Jeremie Courreges-Anglas <[email protected]> writes:
> 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,
ping
> * 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