diff options
-rw-r--r-- | usr.sbin/smtpd/dns.c | 20 | ||||
-rw-r--r-- | usr.sbin/smtpd/envelope.c | 9 | ||||
-rw-r--r-- | usr.sbin/smtpd/lka_session.c | 5 | ||||
-rw-r--r-- | usr.sbin/smtpd/mta.c | 37 | ||||
-rw-r--r-- | usr.sbin/smtpd/mta_session.c | 4 | ||||
-rw-r--r-- | usr.sbin/smtpd/parse.y | 13 | ||||
-rw-r--r-- | usr.sbin/smtpd/smtpd.conf.5 | 13 | ||||
-rw-r--r-- | usr.sbin/smtpd/smtpd.h | 10 |
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 *); |