diff options
author | Eric Faurot <eric@cvs.openbsd.org> | 2012-08-21 20:19:47 +0000 |
---|---|---|
committer | Eric Faurot <eric@cvs.openbsd.org> | 2012-08-21 20:19:47 +0000 |
commit | 567cbc2bb44ed7a2c477b0787d4ccd50e8ebecf2 (patch) | |
tree | 8e02dd4f4d744ae5e98f189efaab025969f857a8 /usr.sbin | |
parent | aeaaf85fa9a03d459d328e8f93992b1f1d1043b4 (diff) |
Allow smtpd to work as a backup MX, relaying only to MXs with higher
priority in the DNS record. For example:
accept for domain "foo.org" relay backup "mx3.foo.org"
will relay mails for "foo.org" using only hosts with higher priority
(i.e. lower value) than "mx3.foo.org", which is supposed to be the
current server.
If the specified backup MX is not found in the DNS record, relaying
works as normal.
ok gilles@
Diffstat (limited to 'usr.sbin')
-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 *); |