Because of the small ad hoc changes that were made here and there over the years, the listener config code has become a bit convoluted I think. Here is a little cleanup to:
- have all listener creation functions take listen_opts as param, and call config_listener() when done, which adds the listener(s) to the current config list of listeners. - make the fallback chain between interface(), host_v4() host_v6() and host_dns() obvious when creating an if_listener. - fix a bug where the specified family was ignored if the listener is given as a hostname. Comments? Eric. Index: parse.y =================================================================== RCS file: /cvs/src/usr.sbin/smtpd/parse.y,v retrieving revision 1.189 diff -u -p -r1.189 parse.y --- parse.y 31 Aug 2016 15:24:04 -0000 1.189 +++ parse.y 9 Sep 2016 11:11:54 -0000 @@ -138,15 +138,14 @@ static struct listen_opts { uint32_t options; } listen_opts; -static struct listener *create_sock_listener(struct listen_opts *); -static void create_if_listener(struct listenerlist *, struct listen_opts *); -static void config_listener(struct listener *, struct listen_opts *); - -struct listener *host_v4(const char *, in_port_t); -struct listener *host_v6(const char *, in_port_t); -int host_dns(struct listenerlist *, struct listen_opts *); -int host(struct listenerlist *, struct listen_opts *); -int interface(struct listenerlist *, struct listen_opts *); +static void create_sock_listener(struct listen_opts *); +static void create_if_listener(struct listen_opts *); +static void config_listener(struct listener *, struct listen_opts *); +static int host_v4(struct listen_opts *); +static int host_v6(struct listen_opts *); +static int host_dns(struct listen_opts *); +static int interface(struct listen_opts *); + void set_local(const char *); void set_localaddrs(struct table *); int delaytonum(char *); @@ -695,13 +694,13 @@ socket_listener : SOCKET sock_listen { yyerror("socket listener already configured"); YYERROR; } - conf->sc_sock_listener = create_sock_listener(&listen_opts); + create_sock_listener(&listen_opts); } ; if_listener : STRING if_listen { listen_opts.ifx = $1; - create_if_listener(conf->sc_listeners, &listen_opts); + create_if_listener(&listen_opts); } ; @@ -2005,7 +2004,7 @@ parse_config(struct smtpd *x_conf, const /* If the socket listener was not configured, create a default one. */ if (!conf->sc_sock_listener) { memset(&listen_opts, 0, sizeof listen_opts); - conf->sc_sock_listener = create_sock_listener(&listen_opts); + create_sock_listener(&listen_opts); } /* Free macros and check which have not been used. */ @@ -2109,7 +2108,7 @@ symget(const char *nam) return (NULL); } -static struct listener * +static void create_sock_listener(struct listen_opts *lo) { struct listener *l = xcalloc(1, sizeof(*l), "create_sock_listener"); @@ -2118,13 +2117,12 @@ create_sock_listener(struct listen_opts l->ss.ss_family = AF_LOCAL; l->ss.ss_len = sizeof(struct sockaddr *); l->local = 1; + conf->sc_sock_listener = l; config_listener(l, lo); - - return (l); } static void -create_if_listener(struct listenerlist *ll, struct listen_opts *lo) +create_if_listener(struct listen_opts *lo) { uint16_t flags; @@ -2142,17 +2140,11 @@ create_if_listener(struct listenerlist * if (lo->port) { lo->flags = lo->ssl|lo->auth|flags; lo->port = htons(lo->port); - if (!interface(ll, lo)) - if (host(ll, lo) <= 0) - errx(1, "invalid virtual ip or interface: %s", lo->ifx); } else { if (lo->ssl & F_SMTPS) { lo->port = htons(465); lo->flags = F_SMTPS|lo->auth|flags; - if (!interface(ll, lo)) - if (host(ll, lo) <= 0) - errx(1, "invalid virtual ip or interface: %s", lo->ifx); } if (!lo->ssl || (lo->ssl & F_STARTTLS)) { @@ -2160,11 +2152,19 @@ create_if_listener(struct listenerlist * lo->flags = lo->auth|flags; if (lo->ssl & F_STARTTLS) lo->flags |= F_STARTTLS; - if (!interface(ll, lo)) - if (host(ll, lo) <= 0) - errx(1, "invalid virtual ip or interface: %s", lo->ifx); } } + + if (interface(lo)) + return; + if (host_v4(lo)) + return; + if (host_v6(lo)) + return; + if (host_dns(lo)) + return; + + errx(1, "invalid virtual ip or interface: %s", lo->ifx); } static void @@ -2224,58 +2224,69 @@ config_listener(struct listener *h, str if (lo->ssl & F_TLS_VERIFY) h->flags |= F_TLS_VERIFY; + + if (h != conf->sc_sock_listener) + TAILQ_INSERT_TAIL(conf->sc_listeners, h, entry); } -struct listener * -host_v4(const char *s, in_port_t port) +static int +host_v4(struct listen_opts *lo) { struct in_addr ina; struct sockaddr_in *sain; struct listener *h; + if (lo->family != AF_UNSPEC && lo->family != AF_INET) + return (0); + memset(&ina, 0, sizeof(ina)); - if (inet_pton(AF_INET, s, &ina) != 1) - return (NULL); + if (inet_pton(AF_INET, lo->ifx, &ina) != 1) + return (0); h = xcalloc(1, sizeof(*h), "host_v4"); sain = (struct sockaddr_in *)&h->ss; sain->sin_len = sizeof(struct sockaddr_in); sain->sin_family = AF_INET; sain->sin_addr.s_addr = ina.s_addr; - sain->sin_port = port; + sain->sin_port = lo->port; if (sain->sin_addr.s_addr == htonl(INADDR_LOOPBACK)) h->local = 1; + config_listener(h, lo); - return (h); + return (1); } -struct listener * -host_v6(const char *s, in_port_t port) +static int +host_v6(struct listen_opts *lo) { struct in6_addr ina6; struct sockaddr_in6 *sin6; struct listener *h; + if (lo->family != AF_UNSPEC && lo->family != AF_INET6) + return (0); + memset(&ina6, 0, sizeof(ina6)); - if (inet_pton(AF_INET6, s, &ina6) != 1) - return (NULL); + if (inet_pton(AF_INET6, lo->ifx, &ina6) != 1) + return (0); h = xcalloc(1, sizeof(*h), "host_v6"); sin6 = (struct sockaddr_in6 *)&h->ss; sin6->sin6_len = sizeof(struct sockaddr_in6); sin6->sin6_family = AF_INET6; - sin6->sin6_port = port; + sin6->sin6_port = lo->port; memcpy(&sin6->sin6_addr, &ina6, sizeof(ina6)); if (IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr)) h->local = 1; + config_listener(h, lo); - return (h); + return (1); } -int -host_dns(struct listenerlist *al, struct listen_opts *lo) +static int +host_dns(struct listen_opts *lo) { struct addrinfo hints, *res0, *res; int error, cnt = 0; @@ -2284,7 +2295,7 @@ host_dns(struct listenerlist *al, struct struct listener *h; memset(&hints, 0, sizeof(hints)); - hints.ai_family = PF_UNSPEC; + hints.ai_family = lo->family; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_ADDRCONFIG; error = getaddrinfo(lo->ifx, NULL, &hints, &res0); @@ -2323,7 +2334,6 @@ host_dns(struct listenerlist *al, struct config_listener(h, lo); - TAILQ_INSERT_HEAD(al, h, entry); cnt++; } @@ -2331,28 +2341,8 @@ host_dns(struct listenerlist *al, struct return (cnt); } -int -host(struct listenerlist *al, struct listen_opts *lo) -{ - struct listener *h; - - h = host_v4(lo->ifx, lo->port); - - /* IPv6 address? */ - if (h == NULL) - h = host_v6(lo->ifx, lo->port); - - if (h != NULL) { - config_listener(h, lo); - TAILQ_INSERT_HEAD(al, h, entry); - return (1); - } - - return (host_dns(al, lo)); -} - -int -interface(struct listenerlist *al, struct listen_opts *lo) +static int +interface(struct listen_opts *lo) { struct ifaddrs *ifap, *p; struct sockaddr_in *sain; @@ -2400,7 +2390,6 @@ interface(struct listenerlist *al, struc config_listener(h, lo); ret = 1; - TAILQ_INSERT_HEAD(al, h, entry); } freeifaddrs(ifap);