summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--usr.sbin/smtpd/dns.c20
-rw-r--r--usr.sbin/smtpd/envelope.c9
-rw-r--r--usr.sbin/smtpd/lka_session.c5
-rw-r--r--usr.sbin/smtpd/mta.c37
-rw-r--r--usr.sbin/smtpd/mta_session.c4
-rw-r--r--usr.sbin/smtpd/parse.y13
-rw-r--r--usr.sbin/smtpd/smtpd.conf.513
-rw-r--r--usr.sbin/smtpd/smtpd.h10
8 files changed, 82 insertions, 29 deletions
diff --git a/usr.sbin/smtpd/dns.c b/usr.sbin/smtpd/dns.c
index 94e17990357..5228e61238f 100644
--- a/usr.sbin/smtpd/dns.c
+++ b/usr.sbin/smtpd/dns.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: dns.c,v 1.55 2012/08/21 15:14:40 eric Exp $ */
+/* $OpenBSD: dns.c,v 1.56 2012/08/21 20:19:46 eric Exp $ */
/*
* Copyright (c) 2008 Gilles Chehade <gilles@openbsd.org>
@@ -51,7 +51,7 @@ struct dnssession {
struct dns query;
struct event ev;
struct async *as;
-
+ int preference;
size_t mxfound;
TAILQ_HEAD(, mx) mx;
};
@@ -88,12 +88,14 @@ dns_query_host(char *host, int port, uint64_t id)
}
void
-dns_query_mx(char *host, int port, uint64_t id)
+dns_query_mx(char *host, char *backup, int port, uint64_t id)
{
struct dns query;
bzero(&query, sizeof(query));
strlcpy(query.host, host, sizeof(query.host));
+ if (backup)
+ strlcpy(query.backup, backup, sizeof(query.backup));
query.port = port;
query.id = id;
@@ -287,7 +289,10 @@ next:
while (s->as == NULL) {
mx = TAILQ_FIRST(&s->mx);
- if (mx == NULL) {
+ if (mx == NULL || (s->preference != -1
+ && s->preference <= mx->preference)) {
+ if (mx)
+ log_debug("dns: ignoring mx with lower preference");
if (s->mxfound)
query->error = DNS_OK;
dns_reply(query, IMSG_DNS_HOST_END);
@@ -355,6 +360,7 @@ dnssession_init(struct dns *query)
s->id = query->id;
s->query = *query;
+ s->preference = -1;
TAILQ_INIT(&s->mx);
@@ -397,4 +403,10 @@ dnssession_mx_insert(struct dnssession *s, const char *host, int preference)
}
TAILQ_INSERT_TAIL(&s->mx, mx, entry);
+
+ if (s->preference == -1 && s->query.backup[0]
+ && !strcasecmp(host, s->query.backup)) {
+ log_debug("dns: found our backup preference");
+ s->preference = preference;
+ }
}
diff --git a/usr.sbin/smtpd/envelope.c b/usr.sbin/smtpd/envelope.c
index fcff47361d9..fa0c55ce1b6 100644
--- a/usr.sbin/smtpd/envelope.c
+++ b/usr.sbin/smtpd/envelope.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: envelope.c,v 1.8 2012/08/19 14:16:58 chl Exp $ */
+/* $OpenBSD: envelope.c,v 1.9 2012/08/21 20:19:46 eric Exp $ */
/*
* Copyright (c) 2011 Gilles Chehade <gilles@openbsd.org>
@@ -628,6 +628,8 @@ ascii_load_mta_relay_flags(uint8_t *dest, char *buf)
*dest |= F_STARTTLS;
else if (strcasecmp(flag, "auth") == 0)
*dest |= F_AUTH;
+ else if (strcasecmp(flag, "backup") == 0)
+ *dest |= F_BACKUP;
else
return 0;
}
@@ -748,6 +750,11 @@ ascii_dump_mta_relay_flags(uint8_t flags, char *buf, size_t len)
cpylen = strlcat(buf, " ", len);
cpylen = strlcat(buf, "auth", len);
}
+ if (flags & F_BACKUP) {
+ if (buf[0] != '\0')
+ cpylen = strlcat(buf, " ", len);
+ cpylen = strlcat(buf, "backup", len);
+ }
}
return cpylen < len ? 1 : 0;
diff --git a/usr.sbin/smtpd/lka_session.c b/usr.sbin/smtpd/lka_session.c
index 3037c15cbce..6b75d5bbe16 100644
--- a/usr.sbin/smtpd/lka_session.c
+++ b/usr.sbin/smtpd/lka_session.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: lka_session.c,v 1.21 2012/08/19 14:16:58 chl Exp $ */
+/* $OpenBSD: lka_session.c,v 1.22 2012/08/21 20:19:46 eric Exp $ */
/*
* Copyright (c) 2011 Gilles Chehade <gilles@openbsd.org>
@@ -401,8 +401,7 @@ lka_session_deliver(struct lka_session *lks, struct envelope *ep)
}
}
else if (new_ep->type == D_MTA) {
- if (ep->rule.r_action == A_RELAYVIA)
- new_ep->agent.mta.relay = ep->rule.r_value.relayhost;
+ new_ep->agent.mta.relay = ep->rule.r_value.relayhost;
if (ep->rule.r_as) {
if (ep->rule.r_as->user[0]) {
strlcpy(new_ep->sender.user,
diff --git a/usr.sbin/smtpd/mta.c b/usr.sbin/smtpd/mta.c
index 46ab4dea573..346de9e375b 100644
--- a/usr.sbin/smtpd/mta.c
+++ b/usr.sbin/smtpd/mta.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: mta.c,v 1.135 2012/08/21 13:13:17 eric Exp $ */
+/* $OpenBSD: mta.c,v 1.136 2012/08/21 20:19:46 eric Exp $ */
/*
* Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org>
@@ -344,42 +344,50 @@ const char *
mta_route_to_text(struct mta_route *route)
{
static char buf[1024];
- const char *coma = "";
+ const char *sep = "";
buf[0] = '\0';
snprintf(buf, sizeof buf, "route:%s[", route->hostname);
if (route->flags & ROUTE_STARTTLS) {
- coma = ",";
+ sep = ",";
strlcat(buf, "starttls", sizeof buf);
}
if (route->flags & ROUTE_SMTPS) {
- strlcat(buf, coma, sizeof buf);
- coma = ",";
+ strlcat(buf, sep, sizeof buf);
+ sep = ",";
strlcat(buf, "smtps", sizeof buf);
}
if (route->flags & ROUTE_AUTH) {
- strlcat(buf, coma, sizeof buf);
- coma = ",";
+ strlcat(buf, sep, sizeof buf);
+ sep = ",";
strlcat(buf, "auth=", sizeof buf);
strlcat(buf, route->auth, sizeof buf);
}
if (route->cert) {
- strlcat(buf, coma, sizeof buf);
- coma = ",";
+ strlcat(buf, sep, sizeof buf);
+ sep = ",";
strlcat(buf, "cert=", sizeof buf);
strlcat(buf, route->cert, sizeof buf);
}
if (route->flags & ROUTE_MX) {
- strlcat(buf, coma, sizeof buf);
- coma = ",";
+ strlcat(buf, sep, sizeof buf);
+ sep = ",";
strlcat(buf, "mx", sizeof buf);
}
+
+ if (route->flags & ROUTE_BACKUP) {
+ strlcat(buf, sep, sizeof buf);
+ sep = ",";
+ strlcat(buf, "backup=", sizeof buf);
+ strlcat(buf, route->backupname, sizeof buf);
+ }
+
strlcat(buf, "]", sizeof buf);
return (buf);
@@ -394,7 +402,10 @@ mta_route_for(struct envelope *e)
bzero(&key, sizeof key);
key.flags = e->agent.mta.relay.flags;
- if (e->agent.mta.relay.hostname[0]) {
+ if (e->agent.mta.relay.flags & ROUTE_BACKUP) {
+ key.hostname = e->dest.domain;
+ key.backupname = e->agent.mta.relay.hostname;
+ } else if (e->agent.mta.relay.hostname[0]) {
key.hostname = e->agent.mta.relay.hostname;
key.flags |= ROUTE_MX;
} else
@@ -413,6 +424,8 @@ mta_route_for(struct envelope *e)
route->id = generate_uid();
route->flags = key.flags;
route->hostname = xstrdup(key.hostname, "mta: hostname");
+ route->backupname = key.backupname ?
+ xstrdup(key.backupname, "mta: backupname") : NULL;
route->port = key.port;
route->cert = key.cert ? xstrdup(key.cert, "mta: cert") : NULL;
route->auth = key.auth ? xstrdup(key.auth, "mta: auth") : NULL;
diff --git a/usr.sbin/smtpd/mta_session.c b/usr.sbin/smtpd/mta_session.c
index 612671fff40..db7f15a31a8 100644
--- a/usr.sbin/smtpd/mta_session.c
+++ b/usr.sbin/smtpd/mta_session.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: mta_session.c,v 1.12 2012/08/21 20:07:07 eric Exp $ */
+/* $OpenBSD: mta_session.c,v 1.13 2012/08/21 20:19:46 eric Exp $ */
/*
* Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org>
@@ -317,7 +317,7 @@ mta_enter_state(struct mta_session *s, int newstate)
if (s->flags & MTA_FORCE_MX) /* XXX */
dns_query_host(s->route->hostname, s->route->port, s->id);
else
- dns_query_mx(s->route->hostname, 0, s->id);
+ dns_query_mx(s->route->hostname, s->route->backupname, 0, s->id);
break;
case MTA_CONNECT:
diff --git a/usr.sbin/smtpd/parse.y b/usr.sbin/smtpd/parse.y
index 1a2e6c11165..aee31596a91 100644
--- a/usr.sbin/smtpd/parse.y
+++ b/usr.sbin/smtpd/parse.y
@@ -1,4 +1,4 @@
-/* $OpenBSD: parse.y,v 1.90 2012/08/19 14:16:58 chl Exp $ */
+/* $OpenBSD: parse.y,v 1.91 2012/08/21 20:19:46 eric Exp $ */
/*
* Copyright (c) 2008 Gilles Chehade <gilles@openbsd.org>
@@ -124,7 +124,7 @@ typedef struct {
%token AS QUEUE INTERVAL SIZE LISTEN ON ALL PORT EXPIRE
%token MAP HASH LIST SINGLE SSL SMTPS CERTIFICATE
%token DB PLAIN DOMAIN SOURCE
-%token RELAY VIA DELIVER TO MAILDIR MBOX HOSTNAME
+%token RELAY BACKUP VIA DELIVER TO MAILDIR MBOX HOSTNAME
%token ACCEPT REJECT INCLUDE ERROR MDA FROM FOR
%token ARROW ENABLE AUTH TLS LOCAL VIRTUAL TAG ALIAS FILTER
%token <v.string> STRING
@@ -887,6 +887,14 @@ action : DELIVER TO MAILDIR user {
rule->r_action = A_RELAY;
rule->r_as = $2;
}
+ | RELAY BACKUP STRING relay_as {
+ rule->r_action = A_RELAY;
+ rule->r_as = $4;
+ rule->r_value.relayhost.flags |= F_BACKUP;
+ strlcpy(rule->r_value.relayhost.hostname, $3,
+ sizeof (rule->r_value.relayhost.hostname));
+ free($3);
+ }
| RELAY VIA STRING certname credentials relay_as {
rule->r_action = A_RELAYVIA;
rule->r_as = $6;
@@ -1093,6 +1101,7 @@ lookup(char *s)
{ "all", ALL },
{ "as", AS },
{ "auth", AUTH },
+ { "backup", BACKUP },
{ "certificate", CERTIFICATE },
{ "db", DB },
{ "deliver", DELIVER },
diff --git a/usr.sbin/smtpd/smtpd.conf.5 b/usr.sbin/smtpd/smtpd.conf.5
index 0d699a80d54..0dd3e96a73b 100644
--- a/usr.sbin/smtpd/smtpd.conf.5
+++ b/usr.sbin/smtpd/smtpd.conf.5
@@ -1,4 +1,4 @@
-.\" $OpenBSD: smtpd.conf.5,v 1.57 2012/07/16 06:00:04 jmc Exp $
+.\" $OpenBSD: smtpd.conf.5,v 1.58 2012/08/21 20:19:46 eric Exp $
.\"
.\" Copyright (c) 2008 Janne Johansson <jj@openbsd.org>
.\" Copyright (c) 2009 Jacek Masiulaniec <jacekm@dobremiasto.net>
@@ -16,7 +16,7 @@
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
.\"
-.Dd $Mdocdate: July 16 2012 $
+.Dd $Mdocdate: August 21 2012 $
.Dt SMTPD.CONF 5
.Os
.Sh NAME
@@ -300,12 +300,21 @@ This parameter may use conversion specifiers that are expanded before use
(see above).
.It Xo
.Ic relay
+.Op Ic backup Ar mx
.Op Ic as Ar address
.Xc
Mail is relayed.
The routing decision is based on the DNS system.
.Pp
If the
+.Ic backup
+parameter is specified, the current server will act as a backup server
+for the target domain. Accepted mails are only relayed through
+servers with lower preference value in the MX record for the
+domain than the one specified in
+.Ar mx .
+.Pp
+If the
.Ic as
parameter is specified,
.Xr smtpd 8
diff --git a/usr.sbin/smtpd/smtpd.h b/usr.sbin/smtpd/smtpd.h
index a30c5269b1f..0bcc8edc7f5 100644
--- a/usr.sbin/smtpd/smtpd.h
+++ b/usr.sbin/smtpd/smtpd.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: smtpd.h,v 1.328 2012/08/21 13:13:17 eric Exp $ */
+/* $OpenBSD: smtpd.h,v 1.329 2012/08/21 20:19:46 eric Exp $ */
/*
* Copyright (c) 2008 Gilles Chehade <gilles@openbsd.org>
@@ -79,6 +79,8 @@
#define F_AUTH 0x04
#define F_SSL (F_SMTPS|F_STARTTLS)
+#define F_BACKUP 0x10 /* XXX */
+
#define F_SCERT 0x01
#define F_CCERT 0x02
@@ -88,6 +90,7 @@
#define ROUTE_SSL (ROUTE_STARTTLS | ROUTE_SMTPS)
#define ROUTE_AUTH 0x04
#define ROUTE_MX 0x08
+#define ROUTE_BACKUP 0x10 /* XXX */
typedef uint32_t objid_t;
@@ -653,12 +656,12 @@ enum dns_status {
struct dns {
uint64_t id;
char host[MAXHOSTNAMELEN];
+ char backup[MAXHOSTNAMELEN];
int port;
int error;
int type;
struct imsgev *asker;
struct sockaddr_storage ss;
- struct dns *next;
};
struct secret {
@@ -733,6 +736,7 @@ struct mta_route {
uint8_t flags;
char *hostname;
+ char *backupname;
uint16_t port;
char *cert;
char *auth;
@@ -954,7 +958,7 @@ struct delivery_backend *delivery_backend_lookup(enum action_type);
/* dns.c */
void dns_query_host(char *, int, uint64_t);
-void dns_query_mx(char *, int, uint64_t);
+void dns_query_mx(char *, char *, int, uint64_t);
void dns_query_ptr(struct sockaddr_storage *, uint64_t);
void dns_async(struct imsgev *, int, struct dns *);