The following diff adds support for listening multiple addresses (thus
for dual-stack setups).  Multiple "listen on" settings are allowed, the
default is to listen on 0.0.0.0 and :: (currently, only 0.0.0.0).
A single "listen on hostname" line arbitrarily supports up to 16
addresses.

It also tweaks the host*() functions so that addresses are used in the
order where they are resolved*.  This affects bind addresses, but also
"trap receiver" addresses.  So in "trap receiver hostname", if hostname
resolves to both an IPv4 and an IPv6 address, the address that is picked
up respects the order defined by the "family" keyword in resolv.conf.
This *could* break existing setups.

Feedback and oks welcome,

* httpd, relayd and ldapd might also benefit from such a change


Index: control.c
===================================================================
RCS file: /d/cvs/src/usr.sbin/snmpd/control.c,v
retrieving revision 1.39
diff -u -p -r1.39 control.c
--- control.c   2 Sep 2016 13:28:36 -0000       1.39
+++ control.c   9 Nov 2016 23:09:28 -0000
@@ -592,7 +592,7 @@ control_dispatch_agentx(int fd, short ev
                                }
                        }
  dispatch:
-                       snmpe_dispatchmsg(msg);
+                       snmpe_dispatchmsg(msg, fd);
                        break;
                }
 
Index: parse.y
===================================================================
RCS file: /d/cvs/src/usr.sbin/snmpd/parse.y,v
retrieving revision 1.40
diff -u -p -r1.40 parse.y
--- parse.y     9 Nov 2016 20:31:56 -0000       1.40
+++ parse.y     9 Nov 2016 23:31:13 -0000
@@ -198,25 +198,13 @@ yesno             :  STRING                       {
                ;
 
 main           : LISTEN ON STRING              {
-                       struct addresslist       al;
-                       struct address          *h;
-
-                       TAILQ_INIT(&al);
-                       if (host($3, &al, 1, SNMPD_PORT, NULL, NULL, NULL)
-                           <= 0) {
+                       if (host($3, &conf->sc_addresses, 16, SNMPD_PORT, NULL,
+                               NULL, NULL) <= 0) {
                                yyerror("invalid ip address: %s", $3);
                                free($3);
                                YYERROR;
                        }
                        free($3);
-                       h = TAILQ_FIRST(&al);
-                       bcopy(&h->ss, &conf->sc_address.ss, sizeof(*h));
-                       conf->sc_address.port = h->port;
-
-                       while ((h = TAILQ_FIRST(&al)) != NULL) {
-                               TAILQ_REMOVE(&al, h, entry);
-                               free(h);
-                       }
                }
                | READONLY COMMUNITY STRING     {
                        if (strlcpy(conf->sc_rdcommunity, $3,
@@ -989,8 +977,7 @@ parse_config(const char *filename, u_int
 
        conf->sc_flags = flags;
        conf->sc_confpath = filename;
-       conf->sc_address.ss.ss_family = AF_INET;
-       conf->sc_address.port = SNMPD_PORT;
+       TAILQ_INIT(&conf->sc_addresses);
        conf->sc_ps.ps_csock.cs_name = SNMPD_SOCKET;
        TAILQ_INIT(&conf->sc_ps.ps_rcsocks);
        strlcpy(conf->sc_rdcommunity, "public", SNMPD_MAXCOMMUNITYLEN);
@@ -1011,6 +998,22 @@ parse_config(const char *filename, u_int
 
        endservent();
 
+       if (TAILQ_EMPTY(&conf->sc_addresses)) {
+               struct address          *h;
+               h = calloc(1, sizeof(*h));
+               if (h == NULL)
+                       fatal("snmpe: %s", __func__);
+               h->ss.ss_family = AF_INET;
+               h->port = SNMPD_PORT;
+               TAILQ_INSERT_TAIL(&conf->sc_addresses, h, entry);
+               h = calloc(1, sizeof(*h));
+               if (h == NULL)
+                       fatal("snmpe: %s", __func__);
+               h->ss.ss_family = AF_INET6;
+               h->port = SNMPD_PORT;
+               TAILQ_INSERT_TAIL(&conf->sc_addresses, h, entry);
+       }
+
        /* Free macros and check which have not been used. */
        for (sym = TAILQ_FIRST(&symhead); sym != NULL; sym = next) {
                next = TAILQ_NEXT(sym, entry);
@@ -1215,7 +1218,7 @@ host_dns(const char *s, struct addressli
 
                h->sa_srcaddr = src;
 
-               TAILQ_INSERT_HEAD(al, h, entry);
+               TAILQ_INSERT_TAIL(al, h, entry);
                cnt++;
        }
        if (cnt == max && res) {
@@ -1262,7 +1265,7 @@ host(const char *s, struct addresslist *
                }
                h->sa_srcaddr = src;
 
-               TAILQ_INSERT_HEAD(al, h, entry);
+               TAILQ_INSERT_TAIL(al, h, entry);
                return (1);
        }
 
Index: snmpd.h
===================================================================
RCS file: /d/cvs/src/usr.sbin/snmpd/snmpd.h,v
retrieving revision 1.72
diff -u -p -r1.72 snmpd.h
--- snmpd.h     9 Nov 2016 20:31:56 -0000       1.72
+++ snmpd.h     9 Nov 2016 23:09:28 -0000
@@ -518,6 +518,18 @@ struct address {
 };
 TAILQ_HEAD(addresslist, address);
 
+struct sock {
+       int                     fd;
+       TAILQ_ENTRY(sock)       entry;
+};
+TAILQ_HEAD(socklist, sock);
+
+struct evnode {
+       struct event            event;
+       TAILQ_ENTRY(evnode)     entry;
+};
+TAILQ_HEAD(eventlist, evnode);
+
 enum usmauth {
        AUTH_NONE = 0,
        AUTH_MD5,       /* HMAC-MD5-96, RFC3414 */
@@ -556,9 +568,7 @@ struct snmpd {
 #define SNMPD_F_NONAMES                 0x02
 
        const char              *sc_confpath;
-       struct address           sc_address;
-       int                      sc_sock;
-       struct event             sc_ev;
+       struct addresslist       sc_addresses;
        struct timeval           sc_starttime;
        u_int32_t                sc_engine_boots;
 
@@ -652,7 +662,7 @@ struct kif_arp      *karp_getaddr(struct sock
 /* snmpe.c */
 void            snmpe(struct privsep *, struct privsep_proc *);
 void            snmpe_shutdown(void);
-void            snmpe_dispatchmsg(struct snmp_message *);
+void            snmpe_dispatchmsg(struct snmp_message *, int);
 
 /* trap.c */
 void            trap_init(void);
Index: snmpe.c
===================================================================
RCS file: /d/cvs/src/usr.sbin/snmpd/snmpe.c,v
retrieving revision 1.45
diff -u -p -r1.45 snmpe.c
--- snmpe.c     9 Nov 2016 20:31:56 -0000       1.45
+++ snmpe.c     9 Nov 2016 23:09:28 -0000
@@ -53,6 +53,8 @@ int    snmpe_encode(struct snmp_message *)
 void    snmp_msgfree(struct snmp_message *);
 
 struct imsgev  *iev_parent;
+struct socklist         snmpesocks;
+struct eventlist snmpeevents;
 
 static struct privsep_proc procs[] = {
        { "parent",     PROC_PARENT,    snmpe_dispatch_parent }
@@ -62,6 +64,8 @@ void
 snmpe(struct privsep *ps, struct privsep_proc *p)
 {
        struct snmpd    *env = ps->ps_env;
+       struct address  *h;
+       struct sock     *so;
 #ifdef DEBUG
        char             buf[BUFSIZ];
        struct oid      *oid;
@@ -74,9 +78,18 @@ snmpe(struct privsep *ps, struct privsep
        }
 #endif
 
-       /* bind SNMP UDP socket */
-       if ((env->sc_sock = snmpe_bind(&env->sc_address)) == -1)
-               fatalx("snmpe: failed to bind SNMP UDP socket");
+       TAILQ_INIT(&snmpesocks);
+
+       /* bind SNMP UDP sockets */
+       TAILQ_FOREACH(h, &env->sc_addresses, entry) {
+               so = calloc(1, sizeof(*so));
+               if (so == NULL)
+                       fatal("snmpe: %s", __func__);
+               so->fd = snmpe_bind(h);
+               if (so->fd == -1)
+                       fatal("snmpe: failed to bind SNMP UDP socket");
+               TAILQ_INSERT_TAIL(&snmpesocks, so, entry);
+       }
 
        proc_run(ps, p, procs, nitems(procs), snmpe_init, NULL);
 }
@@ -86,16 +99,26 @@ void
 snmpe_init(struct privsep *ps, struct privsep_proc *p, void *arg)
 {
        struct snmpd    *env = ps->ps_env;
+       struct sock     *so;
+       struct evnode   *ev;
 
        kr_init();
        trap_init();
        timer_init();
        usm_generate_keys();
 
+       TAILQ_INIT(&snmpeevents);
+
        /* listen for incoming SNMP UDP messages */
-       event_set(&env->sc_ev, env->sc_sock, EV_READ|EV_PERSIST,
-           snmpe_recvmsg, env);
-       event_add(&env->sc_ev, NULL);
+       TAILQ_FOREACH(so, &snmpesocks, entry) {
+               ev = calloc(1, sizeof(*ev));
+               if (ev == NULL)
+                       fatal("%s", __func__);
+               event_set(&ev->event, so->fd, EV_READ|EV_PERSIST,
+                   snmpe_recvmsg, env);
+               event_add(&ev->event, NULL);
+               TAILQ_INSERT_TAIL(&snmpeevents, ev, entry);
+       }
 }
 
 void
@@ -519,18 +542,18 @@ snmpe_recvmsg(int fd, short sig, void *a
                }
        }
 
-       snmpe_dispatchmsg(msg);
+       snmpe_dispatchmsg(msg, fd);
 }
 
 void
-snmpe_dispatchmsg(struct snmp_message *msg)
+snmpe_dispatchmsg(struct snmp_message *msg, int sock)
 {
        if (snmpe_parsevarbinds(msg) == 1)
                return;
 
        /* not dispatched to subagent; respond directly */
        msg->sm_context = SNMP_C_GETRESP;
-       snmpe_response(snmpd_env->sc_sock, msg);
+       snmpe_response(sock, msg);
 }
 
 void
Index: traphandler.c
===================================================================
RCS file: /d/cvs/src/usr.sbin/snmpd/traphandler.c,v
retrieving revision 1.6
diff -u -p -r1.6 traphandler.c
--- traphandler.c       28 Oct 2016 09:07:08 -0000      1.6
+++ traphandler.c       9 Nov 2016 23:11:55 -0000
@@ -43,9 +43,9 @@
 #include "snmpd.h"
 #include "mib.h"
 
-int     trapsock;
-struct event trapev;
-char    trap_path[PATH_MAX];
+struct socklist                trapsocks;
+struct eventlist       trapevents;
+char                   trap_path[PATH_MAX];
 
 void    traphandler_init(struct privsep *, struct privsep_proc *, void *arg);
 int     traphandler_dispatch_parent(int, struct privsep_proc *, struct imsg *);
@@ -76,10 +76,20 @@ void
 traphandler(struct privsep *ps, struct privsep_proc *p)
 {
        struct snmpd            *env = ps->ps_env;
+       struct address          *h;
+       struct sock             *so;
 
-       if (env->sc_traphandler &&
-           (trapsock = traphandler_bind(&env->sc_address)) == -1)
-               fatal("could not create trap listener socket");
+       TAILQ_INIT(&trapsocks);
+
+       if (env->sc_traphandler) {
+               TAILQ_FOREACH(h, &env->sc_addresses, entry) {
+                       so = calloc(1, sizeof(*so));
+                       so->fd = traphandler_bind(h);
+                       if (so->fd == -1)
+                               fatal("could not create trap listener socket");
+                       TAILQ_INSERT_TAIL(&trapsocks, so, entry);
+               }
+       }
 
        proc_run(ps, p, procs, nitems(procs), traphandler_init, NULL);
 }
@@ -88,20 +98,31 @@ void
 traphandler_init(struct privsep *ps, struct privsep_proc *p, void *arg)
 {
        struct snmpd            *env = ps->ps_env;
+       struct sock             *so;
+       struct evnode           *ev;
+
+       TAILQ_INIT(&trapevents);
 
        if (!env->sc_traphandler)
                return;
 
        /* listen for SNMP trap messages */
-       event_set(&trapev, trapsock, EV_READ|EV_PERSIST, traphandler_recvmsg,
-           ps);
-       event_add(&trapev, NULL);
+       TAILQ_FOREACH(so, &trapsocks, entry) {
+               ev = calloc(1, sizeof (*ev));
+               if (ev == NULL)
+                       fatal("%s", __func__);
+               event_set(&ev->event, so->fd, EV_READ|EV_PERSIST,
+                   traphandler_recvmsg, ps);
+               event_add(&ev->event, NULL);
+               TAILQ_INSERT_TAIL(&trapevents, ev, entry);
+       }
 }
 
 int
 traphandler_bind(struct address *addr)
 {
        int                      s;
+       char                     buf[512];
 
        if ((s = snmpd_socket_af(&addr->ss, htons(SNMPD_TRAPPORT))) == -1)
                return (-1);
@@ -112,6 +133,11 @@ traphandler_bind(struct address *addr)
        if (bind(s, (struct sockaddr *)&addr->ss, addr->ss.ss_len) == -1)
                goto bad;
 
+       if (print_host(&addr->ss, buf, sizeof(buf)) == NULL)
+               goto bad;
+
+       log_info("%s: binding to address %s:%d", __func__, buf, SNMPD_TRAPPORT);
+
        return (s);
  bad:
        close (s);
@@ -121,8 +147,14 @@ traphandler_bind(struct address *addr)
 void
 traphandler_shutdown(void)
 {
-       event_del(&trapev);
-       close(trapsock);
+       struct evnode           *ev;
+       struct sock             *so;
+
+       TAILQ_FOREACH(ev, &trapevents, entry)
+               event_del(&ev->event);
+
+       TAILQ_FOREACH(so, &trapsocks, entry)
+               close(so->fd);
 }
 
 int

-- 
jca | PGP : 0x1524E7EE / 5135 92C1 AD36 5293 2BDF  DDCC 0DFA 74AE 1524 E7EE

Reply via email to