> Am 17.11.2016 um 14:28 schrieb Jeremie Courreges-Anglas <[email protected]>:
> 
> Reyk Floeter <[email protected]> writes:
> 
>>> On Thu, Nov 10, 2016 at 12:57:13AM +0100, Jeremie Courreges-Anglas wrote:
>>> 
>>> 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.
>>> 
>> 
>> Very useful, thanks!
>> 
>>> 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
>> 
>> Yes, partially.
>> 
>>> 
>> 
>> - See comments inline.
>> 
>> - Should it handle the following case where it currently fails:
>> 
>> listen on 127.0.0.1
>> listen on 0.0.0.0
>> 
>> In comparison, ntpd just ignores it:
>> bind on 0.0.0.0 failed, skipping: Address already in use
> 
> Hmm, having ntpd fail because of a bad address could be hard to spot,
> whereas snmpd is supposed to be queried from other machines.  I tend to
> prefer hard failures but I don't have a strong opinion.  Whatever people
> prefer. :)
> 

you're right 

> [...]
> 
>>> +        struct address        *h;
>>> +        h = calloc(1, sizeof(*h));
>>> +        if (h == NULL)
>>> +            fatal("snmpe: %s", __func__);
>> 
>> I usually don't complain about this style, and it is highly
>> subjective, but I think this h h is just repetition and could be
>> 
>>        if ((h = calloc(1, sizeof(*h))) == NULL)
>>            fatal("snmpe: %s", __func__);
>> 
>> I see that it makes sense to split the if and assignment with very
>> long function calls, but you keep on doing this repetition with very
>> short calls all over the diff.
> 
> ack
> 
> [...]
> 
>> Why do you need two different lists for socks and events?
> 
> No reason,
> 
>> Additionally, the name "sock" might cause namespace issues.
>> 
>> struct listen_sock {
>>    int            s_fd;
>>    struct event        s_ev;
>>    TAILQ_ENTRY(sock)    s_entry;
>> };
>> TAILQ_HEAD(socklist, listen_sock);
> 
> Simpler indeed, thanks.  I used "entry" like in struct addresslist,
> there doesn't seem to be a pattern here.  We could also use "fd" and
> "ev".
> 

I prefer prefixes in structs because it's easier to grep and read, especially 
when using pointers all over the place. non-prefixed struct members are 
artifacts here.

> [...]
> 
>>> +    log_info("%s: binding to address %s:%d", __func__, buf, 
>>> SNMPD_TRAPPORT);
>> 
>> you already did, I think more common is
>> 
>>    log_info("%s: listening on %s:%d", __func__, buf, SNMPD_TRAPPORT);
>> 
>> (should be changed in snmpe_bind() as well)
> 
> Fine.  While here I replaced the function name by the engine name, the
> rationale being that normal messages don't need to reflect internal
> details.  Objections?
> 

right, __func__ is for log_debug and sometimes fatal.

> Here's a diff that includes your suggestions.
> 

looks good. OK.

> 
> 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    17 Nov 2016 13:07:10 -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,8 @@ 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);
> +    TAILQ_INIT(&conf->sc_sockets);
>    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 +999,20 @@ parse_config(const char *filename, u_int
> 
>    endservent();
> 
> +    if (TAILQ_EMPTY(&conf->sc_addresses)) {
> +        struct address        *h;
> +        if ((h = calloc(1, sizeof(*h))) == NULL)
> +            fatal("snmpe: %s", __func__);
> +        h->ss.ss_family = AF_INET;
> +        h->port = SNMPD_PORT;
> +        TAILQ_INSERT_TAIL(&conf->sc_addresses, h, entry);
> +        if ((h = calloc(1, sizeof(*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 +1217,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 +1264,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    17 Nov 2016 13:06:54 -0000
> @@ -518,6 +518,13 @@ struct address {
> };
> TAILQ_HEAD(addresslist, address);
> 
> +struct listen_sock {
> +    int                s_fd;
> +    struct event            s_ev;
> +    TAILQ_ENTRY(listen_sock)    entry;
> +};
> +TAILQ_HEAD(socklist, listen_sock);
> +
> enum usmauth {
>    AUTH_NONE = 0,
>    AUTH_MD5,    /* HMAC-MD5-96, RFC3414 */
> @@ -556,9 +563,8 @@ 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 socklist         sc_sockets;
>    struct timeval         sc_starttime;
>    u_int32_t         sc_engine_boots;
> 
> @@ -652,7 +658,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    17 Nov 2016 13:08:13 -0000
> @@ -61,7 +61,9 @@ static struct privsep_proc procs[] = {
> void
> snmpe(struct privsep *ps, struct privsep_proc *p)
> {
> -    struct snmpd    *env = ps->ps_env;
> +    struct snmpd        *env = ps->ps_env;
> +    struct address        *h;
> +    struct listen_sock    *so;
> #ifdef DEBUG
>    char         buf[BUFSIZ];
>    struct oid    *oid;
> @@ -74,9 +76,13 @@ 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_FOREACH(h, &env->sc_addresses, entry) {
> +        if ((so = calloc(1, sizeof(*so))) == NULL)
> +            fatal("snmpe: %s", __func__);
> +        if ((so->s_fd = snmpe_bind(h)) == -1)
> +            fatal("snmpe: failed to bind SNMP UDP socket");
> +        TAILQ_INSERT_TAIL(&env->sc_sockets, so, entry);
> +    }
> 
>    proc_run(ps, p, procs, nitems(procs), snmpe_init, NULL);
> }
> @@ -85,7 +91,8 @@ snmpe(struct privsep *ps, struct privsep
> void
> snmpe_init(struct privsep *ps, struct privsep_proc *p, void *arg)
> {
> -    struct snmpd    *env = ps->ps_env;
> +    struct snmpd        *env = ps->ps_env;
> +    struct listen_sock    *so;
> 
>    kr_init();
>    trap_init();
> @@ -93,9 +100,11 @@ snmpe_init(struct privsep *ps, struct pr
>    usm_generate_keys();
> 
>    /* 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, &env->sc_sockets, entry) {
> +        event_set(&so->s_ev, so->s_fd, EV_READ|EV_PERSIST,
> +            snmpe_recvmsg, env);
> +        event_add(&so->s_ev, NULL);
> +    }
> }
> 
> void
> @@ -156,7 +165,7 @@ snmpe_bind(struct address *addr)
>    if (print_host(&addr->ss, buf, sizeof(buf)) == NULL)
>        goto bad;
> 
> -    log_info("snmpe_bind: binding to address %s:%d", buf, addr->port);
> +    log_info("snmpe: listening on %s:%d", buf, addr->port);
> 
>    return (s);
> 
> @@ -519,18 +528,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    17 Nov 2016 13:08:37 -0000
> @@ -43,8 +43,6 @@
> #include "snmpd.h"
> #include "mib.h"
> 
> -int     trapsock;
> -struct event trapev;
> char     trap_path[PATH_MAX];
> 
> void     traphandler_init(struct privsep *, struct privsep_proc *, void *arg);
> @@ -76,10 +74,18 @@ void
> traphandler(struct privsep *ps, struct privsep_proc *p)
> {
>    struct snmpd        *env = ps->ps_env;
> +    struct address        *h;
> +    struct listen_sock    *so;
> 
> -    if (env->sc_traphandler &&
> -        (trapsock = traphandler_bind(&env->sc_address)) == -1)
> -        fatal("could not create trap listener socket");
> +    if (env->sc_traphandler) {
> +        TAILQ_FOREACH(h, &env->sc_addresses, entry) {
> +            if ((so = calloc(1, sizeof(*so))) == NULL)
> +                fatal("%s", __func__);
> +            if ((so->s_fd = traphandler_bind(h)) == -1)
> +                fatal("could not create trap listener socket");
> +            TAILQ_INSERT_TAIL(&env->sc_sockets, so, entry);
> +        }
> +    }
> 
>    proc_run(ps, p, procs, nitems(procs), traphandler_init, NULL);
> }
> @@ -88,20 +94,24 @@ void
> traphandler_init(struct privsep *ps, struct privsep_proc *p, void *arg)
> {
>    struct snmpd        *env = ps->ps_env;
> +    struct listen_sock    *so;
> 
>    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, &env->sc_sockets, entry) {
> +        event_set(&so->s_ev, so->s_fd, EV_READ|EV_PERSIST,
> +            traphandler_recvmsg, ps);
> +        event_add(&so->s_ev, NULL);
> +    }
> }
> 
> 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 +122,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("traphandler: listening on %s:%d", buf, SNMPD_TRAPPORT);
> +
>    return (s);
>  bad:
>    close (s);
> @@ -121,8 +136,12 @@ traphandler_bind(struct address *addr)
> void
> traphandler_shutdown(void)
> {
> -    event_del(&trapev);
> -    close(trapsock);
> +    struct listen_sock    *so;
> +
> +    TAILQ_FOREACH(so, &snmpd_env->sc_sockets, entry) {
> +        event_del(&so->s_ev);
> +        close(so->s_fd);
> +    }
> }
> 
> int
> 
> 
> -- 
> jca | PGP : 0x1524E7EE / 5135 92C1 AD36 5293 2BDF  DDCC 0DFA 74AE 1524 E7EE

Reply via email to