Hi On github someone reported an issue[0] regarding localhost MX entries. Currently smtpd will just use the localhost relay. This leads to a loop. Here a patch filtering localhost and localhost addresses for MX requests.
As next step you could implement Null-MX (rfc 7505). Philipp [0] https://github.com/OpenSMTPD/OpenSMTPD/issues/1190 diff --git a/usr.sbin/smtpd/dns.c b/usr.sbin/smtpd/dns.c index f7c6b3df..7389efec 100644 --- a/usr.sbin/smtpd/dns.c +++ b/usr.sbin/smtpd/dns.c @@ -53,6 +53,7 @@ struct dns_lookup { struct dns_session *session; char *host; int preference; + int filter_localhost; }; struct dns_session { @@ -65,7 +66,7 @@ struct dns_session { int refcount; }; -static void dns_lookup_host(struct dns_session *, const char *, int); +static void dns_lookup_host(struct dns_session *, const char *, int, int); static void dns_dispatch_host(struct asr_result *, void *); static void dns_dispatch_mx(struct asr_result *, void *); static void dns_dispatch_mx_preference(struct asr_result *, void *); @@ -139,7 +140,7 @@ dns_imsg(struct mproc *p, struct imsg *imsg) case IMSG_MTA_DNS_HOST: m_get_string(&m, &host); m_end(&m); - dns_lookup_host(s, host, -1); + dns_lookup_host(s, host, -1, 0); return; case IMSG_MTA_DNS_MX: @@ -205,6 +206,28 @@ dns_imsg(struct mproc *p, struct imsg *imsg) } } +static int +is_localhost(struct sockaddr *sa) +{ + struct sockaddr_in6 *ipv6; + struct sockaddr_in *ipv4; + uint32_t addr; + + switch (sa->sa_family) { + case AF_INET6: + // May check also for v6 mapped v4 addresses + ipv6 = (struct sockaddr_in6 *)sa; + return IN6_IS_ADDR_LOOPBACK(&ipv6->sin6_addr); + case AF_INET: + ipv4 = (struct sockaddr_in *)sa; + addr = ntohl(ipv4->sin_addr.s_addr); + return ((addr >> 24) & 0xff) == 127; + default: + log_warnx("warn: unknown family in sockaddr"); + } + return 0; +} + static void dns_dispatch_host(struct asr_result *ar, void *arg) { @@ -215,6 +238,10 @@ dns_dispatch_host(struct asr_result *ar, void *arg) s = lookup->session; for (ai = ar->ar_addrinfo; ai; ai = ai->ai_next) { + if (lookup->filter_localhost && is_localhost(ai->ai_addr)) { + log_warnx("warn: ignore localhost address for host %s", lookup->host); + continue; + } s->mxfound++; m_create(s->p, IMSG_MTA_DNS_HOST, 0, 0, -1); m_add_id(s->p, s->reqid); @@ -280,14 +307,18 @@ dns_dispatch_mx(struct asr_result *ar, void *arg) continue; print_dname(rr.rr.mx.exchange, buf, sizeof(buf)); buf[strlen(buf) - 1] = '\0'; - dns_lookup_host(s, buf, rr.rr.mx.preference); + if (strcasecmp("localhost", buf)==0) { + log_warnx("ignore localhost MX-entry for domain <%s>", lookup->host); + continue; + } + dns_lookup_host(s, buf, rr.rr.mx.preference, 1); found++; } free(ar->ar_data); /* fallback to host if no MX is found. */ if (found == 0) - dns_lookup_host(s, s->name, 0); + dns_lookup_host(s, s->name, 0, 1); } static void @@ -340,7 +371,7 @@ dns_dispatch_mx_preference(struct asr_result *ar, void *arg) } static void -dns_lookup_host(struct dns_session *s, const char *host, int preference) +dns_lookup_host(struct dns_session *s, const char *host, int preference, int filter_localhost) { struct dns_lookup *lookup; struct addrinfo hints; @@ -350,6 +381,7 @@ dns_lookup_host(struct dns_session *s, const char *host, int preference) lookup = xcalloc(1, sizeof *lookup); lookup->preference = preference; + lookup->filter_localhost = filter_localhost; lookup->host = xstrdup(host); lookup->session = s; s->refcount++;