> On 19.07.2017, at 10:16, Marco Pfatschbacher <[email protected]> wrote:
> 
> This adds TCP support to snmpd.
> I've added a tcp option to the "listen on" statement.
> The trap receiver will continue to bind to UDP addresses only.
> 
> Tested against net-snmp, which has TCP support.
> 

Nice!

Are you also planning to add tcp support in snmpctl?

And it would also be nice to get tls (over TCP) later, there is an RFC for that,
but the tcp implementation can already be done with tls in mind.

I will give it a try, see comments below.

Reyk

> Index: parse.y
> ===================================================================
> RCS file: /cvs/src/usr.sbin/snmpd/parse.y,v
> retrieving revision 1.43
> diff -u -p -p -u -r1.43 parse.y
> --- parse.y   5 Jan 2017 13:53:10 -0000       1.43
> +++ parse.y   19 Jul 2017 07:53:45 -0000
> @@ -99,9 +99,9 @@ struct address      *host_v4(const char *);
> struct address        *host_v6(const char *);
> int            host_dns(const char *, struct addresslist *,
>                   int, in_port_t, struct ber_oid *, char *,
> -                 struct address *);
> +                 struct address *, int);
> int            host(const char *, struct addresslist *,
> -                 int, in_port_t, struct ber_oid *, char *, char *);
> +                 int, in_port_t, struct ber_oid *, char *, char *, int);
> 
> typedef struct {
>       union {
> @@ -128,12 +128,12 @@ typedef struct {
> %token        SYSTEM CONTACT DESCR LOCATION NAME OBJECTID SERVICES RTFILTER
> %token        READONLY READWRITE OCTETSTRING INTEGER COMMUNITY TRAP RECEIVER
> %token        SECLEVEL NONE AUTH ENC USER AUTHKEY ENCKEY ERROR DISABLED
> -%token       SOCKET RESTRICTED AGENTX HANDLE DEFAULT SRCADDR
> +%token       SOCKET RESTRICTED AGENTX HANDLE DEFAULT SRCADDR TCP UDP
> %token        <v.string>      STRING
> %token  <v.number>    NUMBER
> %type <v.string>      hostcmn
> %type <v.string>      srcaddr
> -%type        <v.number>      optwrite yesno seclevel socktype
> +%type        <v.number>      optwrite yesno seclevel socktype proto
> %type <v.data>        objtype cmd
> %type <v.oid>         oid hostoid trapoid
> %type <v.auth>        auth
> @@ -197,9 +197,9 @@ yesno             :  STRING                       {
>               }
>               ;
> 
> -main         : LISTEN ON STRING              {
> +main         : LISTEN ON STRING proto        {
>                       if (host($3, &conf->sc_addresses, 16, SNMPD_PORT, NULL,
> -                         NULL, NULL) <= 0) {
> +                         NULL, NULL, $4) <= 0) {
>                               yyerror("invalid ip address: %s", $3);
>                               free($3);
>                               YYERROR;
> @@ -442,7 +442,7 @@ srcaddr           : /* empty */                           
> { $$ = NULL; }
> 
> hostdef               : STRING hostoid hostcmn srcaddr        {
>                       if (host($1, hlist, 1,
> -                         SNMPD_TRAPPORT, $2, $3, $4) <= 0) {
> +                         SNMPD_TRAPPORT, $2, $3, $4, 0) <= 0) {
>                               yyerror("invalid host: %s", $1);
>                               free($1);
>                               YYERROR;
> @@ -524,6 +524,11 @@ socktype : RESTRICTED            { $$ = SOCK_TYPE_
>               | /* nothing */         { $$ = 0; }
>               ;
> 
> +proto                : /* empty */                   { $$ = IPPROTO_UDP; }
> +             | TCP                           { $$ = IPPROTO_TCP; }
> +             | UDP                           { $$ = IPPROTO_UDP; }
> +             ;
> +
> cmd           : STRING                {
>                       struct           trapcmd *cmd;
>                       size_t           span, limit;
> @@ -634,7 +639,9 @@ lookup(char *s)
>               { "source-address",     SRCADDR },
>               { "string",             OCTETSTRING },
>               { "system",             SYSTEM },
> +             { "tcp",                TCP },
>               { "trap",               TRAP },
> +             { "udp",                UDP },
>               { "user",               USER }
>       };
>       const struct keywords   *p;
> @@ -999,18 +1006,26 @@ parse_config(const char *filename, u_int
> 
>       endservent();
> 
> +     /* Setup default listen addresses */
>       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);
> +             host("0.0.0.0", &conf->sc_addresses, 1, SNMPD_PORT,
> +                 NULL, NULL, NULL, IPPROTO_UDP);
> +             host("::", &conf->sc_addresses, 1, SNMPD_PORT,
> +                 NULL, NULL, NULL, IPPROTO_UDP);

smart!

> +     }
> +     if (conf->sc_traphandler) {
> +             struct address  *h;
> +             int found = 0;

Could you declare these variables in parse_config()'s scope?

> +             TAILQ_FOREACH(h, &conf->sc_addresses, entry) {
> +                     if (h->ipproto == IPPROTO_UDP)
> +                             found = 1;
> +             }
> +             if (!found) {
> +                     fprintf(stderr, "trap handler needs at least one "
> +                         "udp listen address\n");
> +                     free(conf);
> +                     return (NULL);


Please use log_warnx() here.

(The fprintf for unused macros is an artifact.)



> +             }
>       }
> 
>       /* Free macros and check which have not been used. */
> @@ -1162,7 +1177,8 @@ host_v6(const char *s)
> 
> int
> host_dns(const char *s, struct addresslist *al, int max,
> -     in_port_t port, struct ber_oid *oid, char *cmn, struct address *src)
> +    in_port_t port, struct ber_oid *oid, char *cmn,
> +    struct address *src, int ipproto)
> {
>       struct addrinfo          hints, *res0, *res;
>       int                      error, cnt = 0;
> @@ -1193,6 +1209,7 @@ host_dns(const char *s, struct addressli
>                       fatal(__func__);
> 
>               h->port = port;
> +             h->ipproto = ipproto;
>               if (oid != NULL) {
>                       if ((h->sa_oid = calloc(1, sizeof(*oid))) == NULL)
>                               fatal(__func__);
> @@ -1235,7 +1252,7 @@ host_dns(const char *s, struct addressli
> 
> int
> host(const char *s, struct addresslist *al, int max,
> -    in_port_t port, struct ber_oid *oid, char *cmn, char *srcaddr)
> +    in_port_t port, struct ber_oid *oid, char *cmn, char *srcaddr, int 
> ipproto)
> {
>       struct address  *h, *src = NULL;
> 
> @@ -1259,6 +1276,7 @@ host(const char *s, struct addresslist *
>               h->port = port;
>               h->sa_oid = oid;
>               h->sa_community = cmn;
> +             h->ipproto = ipproto;
>               if (src != NULL && h->ss.ss_family != src->ss.ss_family) {
>                       log_warnx("host and source-address family mismatch");
>                       return (-1);
> @@ -1269,5 +1287,5 @@ host(const char *s, struct addresslist *
>               return (1);
>       }
> 
> -     return (host_dns(s, al, max, port, oid, cmn, src));
> +     return (host_dns(s, al, max, port, oid, cmn, src, ipproto));
> }
> Index: snmpd.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/snmpd/snmpd.c,v
> retrieving revision 1.36
> diff -u -p -p -u -r1.36 snmpd.c
> --- snmpd.c   4 Apr 2017 02:37:15 -0000       1.36
> +++ snmpd.c   19 Jul 2017 07:53:45 -0000
> @@ -310,7 +310,7 @@ snmpd_dispatch_snmpe(int fd, struct priv
> }
> 
> int
> -snmpd_socket_af(struct sockaddr_storage *ss, in_port_t port)
> +snmpd_socket_af(struct sockaddr_storage *ss, in_port_t port, int ipproto)
> {
>       int      s;
> 
> @@ -329,7 +329,11 @@ snmpd_socket_af(struct sockaddr_storage 
>               return (-1);
>       }
> 
> -     s = socket(ss->ss_family, SOCK_DGRAM, IPPROTO_UDP);
> +     if (ipproto == IPPROTO_TCP)
> +             s = socket(ss->ss_family, SOCK_STREAM, 0);
> +     else
> +             s = socket(ss->ss_family, SOCK_DGRAM, IPPROTO_UDP);
> +

This should also set SOCK_NONBLOCK|SOCK_CLOEXEC, see below.

>       return (s);
> }
> 
> Index: snmpd.conf.5
> ===================================================================
> RCS file: /cvs/src/usr.sbin/snmpd/snmpd.conf.5,v
> retrieving revision 1.35
> diff -u -p -p -u -r1.35 snmpd.conf.5
> --- snmpd.conf.5      9 Nov 2016 20:31:56 -0000       1.35
> +++ snmpd.conf.5      19 Jul 2017 07:53:45 -0000
> @@ -86,7 +86,7 @@ Routing table information will not be av
> reduced during bulk updates.
> The default is
> .Ic no .
> -.It Ic listen on Ar address
> +.It Ic listen on Ar address Op Ic tcp | udp

It should mention that the default is UDP.

> Specify the local address
> .Xr snmpd 8
> should listen on for incoming SNMP messages.
> @@ -198,6 +198,9 @@ the resolved hostname of the host sendin
> the IP address of the host sending the trap,
> and any variable bindings contained in the trap
> (the OID followed by the value, separated by a single space).
> +Traps will will be accepted on all
> +.Ic listen on
> +UDP addresses.
> .It Xo
> .Ic trap receiver Ar string
> .Op Ic oid Ar oid-string
> Index: snmpd.h
> ===================================================================
> RCS file: /cvs/src/usr.sbin/snmpd/snmpd.h,v
> retrieving revision 1.75
> diff -u -p -p -u -r1.75 snmpd.h
> --- snmpd.h   21 Apr 2017 13:50:23 -0000      1.75
> +++ snmpd.h   19 Jul 2017 07:53:45 -0000
> @@ -403,6 +403,8 @@ struct pfr_buffer {
> struct snmp_message {
>       int                      sm_sock;
>       struct sockaddr_storage  sm_ss;
> +     int                      sm_sock_tcp;
> +     struct event             sm_sockev;
>       socklen_t                sm_slen;
>       char                     sm_host[HOST_NAME_MAX+1];
> 
> @@ -509,6 +511,7 @@ struct snmp_stats {
> struct address {
>       struct sockaddr_storage  ss;
>       in_port_t                port;
> +     int                      ipproto;
> 
>       TAILQ_ENTRY(address)     entry;
> 
> @@ -521,6 +524,7 @@ TAILQ_HEAD(addresslist, address);
> 
> struct listen_sock {
>       int                             s_fd;
> +     int                             s_ipproto;
>       struct event                    s_ev;
>       TAILQ_ENTRY(listen_sock)        entry;
> };
> @@ -739,7 +743,7 @@ char              *smi_print_element(struct ber_elem
> void           timer_init(void);
> 
> /* snmpd.c */
> -int           snmpd_socket_af(struct sockaddr_storage *, in_port_t);
> +int           snmpd_socket_af(struct sockaddr_storage *, in_port_t, int);
> u_long                 snmpd_engine_time(void);
> char          *tohexstr(u_int8_t *, int);
> 
> Index: snmpe.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/snmpd/snmpe.c,v
> retrieving revision 1.47
> diff -u -p -p -u -r1.47 snmpe.c
> --- snmpe.c   21 Apr 2017 13:50:23 -0000      1.47
> +++ snmpe.c   19 Jul 2017 07:53:45 -0000
> @@ -49,10 +49,16 @@ void       snmpe_sig_handler(int sig, short, 
> int    snmpe_dispatch_parent(int, struct privsep_proc *, struct imsg *);
> int    snmpe_bind(struct address *);
> void   snmpe_recvmsg(int fd, short, void *);
> +void  snmpe_readcb(int fd, short, void *);
> +void  snmpe_writecb(int fd, short, void *);
> +void  snmpe_accept_cb(int fd, short, void *);
> +void  snmpe_prepare_read_event(struct snmp_message *, int);
> int    snmpe_encode(struct snmp_message *);
> void   snmp_msgfree(struct snmp_message *);
> 
> struct imsgev *iev_parent;
> +struct timeval       snmpe_tcp_timeout;
> +#define SNMPE_TCP_TIMEOUT 10
> 
> static struct privsep_proc procs[] = {
>       { "parent",     PROC_PARENT,    snmpe_dispatch_parent }
> @@ -76,11 +82,13 @@ snmpe(struct privsep *ps, struct privsep
>       }
> #endif
> 
> +     /* bind SNMP UDP/TCP sockets */
>       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");
> +                     fatal("snmpe: failed to bind SNMP socket");
> +             so->s_ipproto = h->ipproto;
>               TAILQ_INSERT_TAIL(&env->sc_sockets, so, entry);
>       }
> 
> @@ -99,10 +107,20 @@ snmpe_init(struct privsep *ps, struct pr
>       timer_init();
>       usm_generate_keys();
> 
> -     /* listen for incoming SNMP UDP messages */
> +     timerclear(&snmpe_tcp_timeout);
> +     snmpe_tcp_timeout.tv_sec = SNMPE_TCP_TIMEOUT;

The comment says UDP but the variables are for TCP?

> +
> +     /* listen for incoming SNMP UDP/TCP messages */
>       TAILQ_FOREACH(so, &env->sc_sockets, entry) {
> -             event_set(&so->s_ev, so->s_fd, EV_READ|EV_PERSIST,
> -                 snmpe_recvmsg, env);
> +             if (so->s_ipproto == IPPROTO_TCP) {
> +                     if (listen(so->s_fd, 5) < 0)
> +                             fatalx("snmpe: failed to listen on socket");
> +                     event_set(&so->s_ev, so->s_fd, EV_READ|EV_PERSIST,
> +                         snmpe_accept_cb, env);
> +             } else {
> +                     event_set(&so->s_ev, so->s_fd, EV_READ|EV_PERSIST,
> +                         snmpe_recvmsg, env);
> +             }
>               event_add(&so->s_ev, NULL);
>       }
> }
> @@ -110,6 +128,12 @@ snmpe_init(struct privsep *ps, struct pr
> void
> snmpe_shutdown(void)
> {
> +     struct listen_sock *so;
> +
> +     TAILQ_FOREACH(so, &snmpd_env->sc_sockets, entry) {
> +             event_del(&so->s_ev);
> +             close(so->s_fd);
> +     }
>       kr_shutdown();
> }
> 
> @@ -130,32 +154,43 @@ snmpe_bind(struct address *addr)
>       char     buf[512];
>       int      val, s;
> 
> -     if ((s = snmpd_socket_af(&addr->ss, htons(addr->port))) == -1)
> +     if ((s = snmpd_socket_af(&addr->ss, htons(addr->port),
> +         addr->ipproto)) == -1)
>               return (-1);
> 
>       /*
>        * Socket options
>        */
> -     if (fcntl(s, F_SETFL, O_NONBLOCK) == -1)
> -             goto bad;

So are you using blocking listening TCP sockets?

> -
> -     switch (addr->ss.ss_family) {
> -     case AF_INET:
> -             val = 1;
> -             if (setsockopt(s, IPPROTO_IP, IP_RECVDSTADDR,
> -                 &val, sizeof(int)) == -1) {
> -                     log_warn("%s: failed to set IPv4 packet info",
> -                         __func__);
> -                     goto bad;
> -             }
> -             break;
> -     case AF_INET6:
> +     if (addr->ipproto == IPPROTO_TCP) {
> +             if (fcntl(s, F_SETFD, 1) == -1)
> +                     fatal("fcntl(%d, F_SETFD)", s);

Not needed ("deprecated") if you use SOCK_CLOEXEC in socket().

>               val = 1;
> -             if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVPKTINFO,
> -                 &val, sizeof(int)) == -1) {
> -                     log_warn("%s: failed to set IPv6 packet info",
> -                         __func__);
> +             if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
> +                 &val, sizeof(val)) == -1)
> +                     fatal("setsockopt: %s", strerror(errno));
> +     } else {
> +             /* UDP */
> +             if (fcntl(s, F_SETFL, O_NONBLOCK) == -1)
>                       goto bad;

Not needed ("deprecated") if you use SOCK_NONBLOCK in socket().

> +
> +             switch (addr->ss.ss_family) {
> +             case AF_INET:
> +                     val = 1;
> +                     if (setsockopt(s, IPPROTO_IP, IP_RECVDSTADDR,
> +                         &val, sizeof(int)) == -1) {
> +                             log_warn("%s: failed to set IPv4 packet info",
> +                                 __func__);
> +                             goto bad;
> +                     }
> +                     break;
> +             case AF_INET6:
> +                     val = 1;
> +                     if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVPKTINFO,
> +                         &val, sizeof(int)) == -1) {
> +                             log_warn("%s: failed to set IPv6 packet info",
> +                                 __func__);
> +                             goto bad;
> +                     }
>               }
>       }
> 
> @@ -165,7 +200,8 @@ snmpe_bind(struct address *addr)
>       if (print_host(&addr->ss, buf, sizeof(buf)) == NULL)
>               goto bad;
> 
> -     log_info("snmpe: listening on %s:%d", buf, addr->port);
> +     log_info("snmpe: listening on %s %s:%d",
> +         (addr->ipproto == IPPROTO_TCP) ? "tcp" : "udp", buf, addr->port);
> 
>       return (s);
> 
> @@ -479,6 +515,131 @@ snmpe_parsevarbinds(struct snmp_message 
> }
> 
> void
> +snmpe_accept_cb(int fd, short type, void *arg)
> +{
> +     int afd;
> +     socklen_t addrlen;
> +     struct sockaddr addr;
> +     struct snmp_message     *msg = NULL;
> +
> +     if ((afd = accept(fd, &addr, &addrlen)) < 0) {
> +             log_warnx("%s: accept: %s", __func__, strerror(errno));
> +             return;
> +     }
> +     if (fcntl(afd, F_SETFL, O_NONBLOCK) < 0) {
> +             log_warnx("%s: fcntl: %s", __func__, strerror(errno));
> +             goto fail;
> +     }

Better use accept4() with SOCK_NONBLOCK|SOCK_CLOEXEC.

As the listening socket should be non-blocking, you will also have
to check for a few error cases here.

Basically, ignore the error if errno is EWOULDBLOCK, EINTR or 
ECONNABORTED and keep on accepting new connections.

We also have fd accounting in a few daemons to pause accept when
we're out of fds (ENFILE or EMFILE), but this can be implemented in
a separate commit.

> +     if ((msg = calloc(1, sizeof(*msg))) == NULL)
> +             goto fail;
> +
> +     snmpe_prepare_read_event(msg, afd);
> +     return;
> +fail:
> +     free(msg);
> +     close(afd);
> +     return;
> +}
> +
> +void
> +snmpe_prepare_read_event(struct snmp_message *msg, int fd) {

yuck! The function_name_is_too_long and the { is on the wrong line.

> +     msg->sm_sock = fd;
> +     msg->sm_sock_tcp = 1;
> +     msg->sm_ber.fd = -1;
> +     event_set(&msg->sm_sockev, fd, EV_READ|EV_PERSIST,

best practice is to avoid EV_PERSIST and to always re-schedule when
needed. This prevents us from having stale events.

> +         snmpe_readcb, msg);
> +     event_add(&msg->sm_sockev, &snmpe_tcp_timeout);
> +}
> +
> +void
> +snmpe_readcb(int fd, short type, void *arg)
> +{
> +     struct snmp_stats       *stats = &snmpd_env->sc_stats;
> +     struct snmp_message *msg = arg;
> +     ssize_t len;
> +
> +     if (type == EV_TIMEOUT) {
> +             snmp_msgfree(msg);
> +             close(fd);
> +             return;
> +     }
> +     len = read(fd, msg->sm_data + msg->sm_datalen,
> +         sizeof(msg->sm_data) - msg->sm_datalen);
> +     if (len == 0) {

How are you handling error cases len == -1?

And it is non-blocking I/O so you have to check for EINTR and EAGAIN.

> +             event_del(&msg->sm_sockev);
> +             close(fd);
> +             snmp_msgfree(msg);
> +             return;
> +     }
> +
> +     msg->sm_datalen = (size_t)len;
> +     msg->sm_ber.fd = -1;
> +     ber_set_application(&msg->sm_ber, smi_application);
> +     ber_set_readbuf(&msg->sm_ber, msg->sm_data, msg->sm_datalen);
> +     msg->sm_req = ber_read_elements(&msg->sm_ber, NULL);
> +     if (msg->sm_req == NULL)
> +             return; /* short read; try again */

So you basically keep on retrying if anything goes wrong?

Will your persist event continue to fire if len returned -1 on read error?

> +
> +     event_del(&msg->sm_sockev);
> +     if (snmpe_parse(msg) == -1) {
> +             if (msg->sm_usmerr != 0 && MSG_REPORT(msg)) {
> +                     usm_make_report(msg);
> +                     snmpe_response(msg);
> +                     return;
> +             } else {
> +                     snmp_msgfree(msg);
> +                     return;
> +             }
> +     }
> +     stats->snmp_inpkts++;
> +
> +     snmpe_dispatchmsg(msg);
> +}
> +
> +void
> +snmpe_writecb(int fd, short type, void *arg)
> +{
> +     struct snmp_stats       *stats = &snmpd_env->sc_stats;
> +     struct snmp_message *msg = arg;
> +     ssize_t len;
> +     struct ber *ber = &msg->sm_ber;
> +
> +     if (type == EV_TIMEOUT)
> +             goto fail;
> +
> +     len = ber->br_wend - ber->br_wbuf; // XXX might be wrong on reuse

// XXX?

> +     ber->br_wptr = ber->br_wbuf;
> +
> +     log_debug("%s: write fd %d len %zd", __func__, fd, len);
> +
> +     len = write(fd, ber->br_wptr, len);
> +     if (len == -1)
> +             goto fail;
> +
> +     ber->br_wptr += len;
> +
> +     if (ber->br_wptr < ber->br_wend)
> +             return;
> +
> +     stats->snmp_outpkts++;
> +     event_del(&msg->sm_sockev);
> +     snmp_msgfree(msg);
> +
> +     /* socket can be reused; wait for another message */
> +     if ((msg = calloc(1, sizeof(*msg))) == NULL) {
> +             close(fd);
> +             return;
> +     }
> +     snmpe_prepare_read_event(msg, fd);
> +     return;
> +
> +fail:
> +     event_del(&msg->sm_sockev);
> +     close(fd);
> +     snmp_msgfree(msg);
> +}
> +
> +void
> snmpe_recvmsg(int fd, short sig, void *arg)
> {
>       struct snmpd            *env = arg;
> @@ -535,10 +696,11 @@ snmpe_recvmsg(int fd, short sig, void *a
> void
> snmpe_dispatchmsg(struct snmp_message *msg)
> {
> +     /* dispatched to subagent */
>       if (snmpe_parsevarbinds(msg) == 1)
>               return;
> 
> -     /* not dispatched to subagent; respond directly */
> +     /* respond directly */
>       msg->sm_context = SNMP_C_GETRESP;
>       snmpe_response(msg);
> }
> @@ -581,11 +743,18 @@ snmpe_response(struct snmp_message *msg)
>               goto done;
> 
>       usm_finalize_digest(msg, ptr, len);
> -     len = sendtofrom(msg->sm_sock, ptr, len, 0,
> -         (struct sockaddr *)&msg->sm_ss, msg->sm_slen,
> -         (struct sockaddr *)&msg->sm_local_ss, msg->sm_local_slen);
> -     if (len != -1)
> -             stats->snmp_outpkts++;
> +     if (msg->sm_sock_tcp) {
> +             event_set(&msg->sm_sockev, msg->sm_sock, EV_WRITE|EV_PERSIST,

see above.

> +                 snmpe_writecb, msg);
> +             event_add(&msg->sm_sockev, &snmpe_tcp_timeout);
> +             return;
> +     } else {
> +             len = sendtofrom(msg->sm_sock, ptr, len, 0,
> +                 (struct sockaddr *)&msg->sm_ss, msg->sm_slen,
> +                 (struct sockaddr *)&msg->sm_local_ss, msg->sm_local_slen);
> +             if (len != -1)
> +                     stats->snmp_outpkts++;
> +     }
> 
>  done:
>       snmp_msgfree(msg);
> Index: trap.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/snmpd/trap.c,v
> retrieving revision 1.29
> diff -u -p -p -u -r1.29 trap.c
> --- trap.c    21 Apr 2017 13:46:15 -0000      1.29
> +++ trap.c    19 Jul 2017 07:53:45 -0000
> @@ -196,7 +196,8 @@ trap_send(struct ber_oid *oid, struct be
>                               continue;
>               }
> 
> -             if ((s = snmpd_socket_af(&tr->ss, htons(tr->port))) == -1) {
> +             if ((s = snmpd_socket_af(&tr->ss, htons(tr->port),
> +                 IPPROTO_UDP)) == -1) {
>                       ret = -1;
>                       goto done;
>               }
> Index: traphandler.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/snmpd/traphandler.c,v
> retrieving revision 1.8
> diff -u -p -p -u -r1.8 traphandler.c
> --- traphandler.c     9 Jan 2017 14:49:22 -0000       1.8
> +++ traphandler.c     19 Jul 2017 07:53:45 -0000
> @@ -79,6 +79,8 @@ traphandler(struct privsep *ps, struct p
> 
>       if (env->sc_traphandler) {
>               TAILQ_FOREACH(h, &env->sc_addresses, entry) {
> +                     if (h->ipproto != IPPROTO_UDP)
> +                             continue;
>                       if ((so = calloc(1, sizeof(*so))) == NULL)
>                               fatal("%s", __func__);
>                       if ((so->s_fd = traphandler_bind(h)) == -1)
> @@ -113,7 +115,8 @@ traphandler_bind(struct address *addr)
>       int                      s;
>       char                     buf[512];
> 
> -     if ((s = snmpd_socket_af(&addr->ss, htons(SNMPD_TRAPPORT))) == -1)
> +     if ((s = snmpd_socket_af(&addr->ss, htons(SNMPD_TRAPPORT),
> +         IPPROTO_UDP)) == -1)
>               return (-1);
> 
>       if (fcntl(s, F_SETFL, O_NONBLOCK) == -1)
> 

Reply via email to