Found some minor issues.
Please disregard for now.

On Tue, 2020-12-01 at 17:12 +0100, Martijn van Duren wrote:
> Hello tech@,
> 
> Long story short: the traphandler process in snmpd annoys me a great
> deal and is in the way for overhauling the transport mapping section
> of snmpe, which is needed for implementing new agentx master support.
> 
> The current traphandler process is also a joke, since all it does is
> receive a message, does a minimal parsing validation and then pass
> then entire buffer to the parent process, which forks the actual
> handlers. This means that the current pledgeset is also way too wide
> for what traphandler does.
> 
> Since snmpe already does a similar packet parsing I see no reason to
> keep this initial verification in the traphandler process. The diff
> below drops the traphandler process and moves the receiving of the
> packets to snmpe, which then forwards the pdu (instead of the
> current whole packet) to the parent. I also extended the checking, so
> it should be a little more resilient to malformed packets.
> 
> While here I also didn't like the fact that listening on a trap-port
> always implies that snmp itself is also listening. This diff adds the
> trap keyword (for udp) on the listen on line, so that we can setup a
> traphandler-only setup. This gives the added bonus that we can now
> also choose the port we listen on for traps. Adding a listen trap
> statement requires a trap handle and vice versa.
> 
> It's not the pretties code, but it's a stopgap that allows me to move
> forward without creating even larger diffs and without (hopefully)
> breaking existing setups (apart from the keyword change).
> 
> OK?
> 
> martijn@
> 
> Index: parse.y
> ===================================================================
> RCS file: /cvs/src/usr.sbin/snmpd/parse.y,v
> retrieving revision 1.62
> diff -u -p -r1.62 parse.y
> --- parse.y     30 Oct 2020 07:43:48 -0000      1.62
> +++ parse.y     1 Dec 2020 16:12:20 -0000
> @@ -94,11 +94,9 @@ char         *symget(const char *);
>  struct snmpd                   *conf = NULL;
>  static int                      errors = 0;
>  static struct usmuser          *user = NULL;
> -static char                    *snmpd_port = SNMPD_PORT;
>  
>  int             host(const char *, const char *, int,
>                     struct sockaddr_storage *, int);
> -int             listen_add(struct sockaddr_storage *, int);
>  
>  typedef struct {
>         union {
> @@ -284,13 +282,16 @@ listenproto       : UDP listen_udp
>  listen_udp     : STRING port                   {
>                         struct sockaddr_storage ss[16];
>                         int nhosts, i;
> +                       char *port = $2;
>  
> -                       nhosts = host($1, $2, SOCK_DGRAM, ss, nitems(ss));
> +                       if (port == NULL)
> +                               port = SNMPD_PORT;
> +
> +                       nhosts = host($1, port, SOCK_DGRAM, ss, nitems(ss));
>                         if (nhosts < 1) {
>                                 yyerror("invalid address: %s", $1);
>                                 free($1);
> -                               if ($2 != snmpd_port)
> -                                       free($2);
> +                               free($2);
>                                 YYERROR;
>                         }
>                         if (nhosts > (int)nitems(ss))
> @@ -298,10 +299,38 @@ listen_udp        : STRING port                   {
>                                     $1, $2, nitems(ss));
>  
>                         free($1);
> -                       if ($2 != snmpd_port)
> +                       free($2);
> +                       for (i = 0; i < nhosts; i++) {
> +                               if (listen_add(&(ss[i]), SOCK_DGRAM, 0) == 
> -1) {
> +                                       yyerror("calloc");
> +                                       YYERROR;
> +                               }
> +                       }
> +               }
> +               | STRING port TRAP              {
> +                       struct sockaddr_storage ss[16];
> +                       int nhosts, i;
> +                       char *port = $2;
> +
> +                       if (port == NULL)
> +                               port = SNMPD_TRAPPORT;
> +
> +                       nhosts = host($1, port, SOCK_DGRAM, ss, nitems(ss));
> +                       if (nhosts < 1) {
> +                               yyerror("invalid address: %s", $1);
> +                               free($1);
>                                 free($2);
> +                               YYERROR;
> +                       }
> +                       if (nhosts > (int)nitems(ss))
> +                               log_warn("%s:%s resolves to more than %zu 
> hosts",
> +                                   $1, $2, nitems(ss));
> +
> +                       free($1);
> +                       free($2);
>                         for (i = 0; i < nhosts; i++) {
> -                               if (listen_add(&(ss[i]), SOCK_DGRAM) == -1) {
> +                               if (listen_add(&(ss[i]), SOCK_DGRAM,
> +                                   ADDRESS_FLAG_TRAP) == -1) {
>                                         yyerror("calloc");
>                                         YYERROR;
>                                 }
> @@ -311,13 +340,16 @@ listen_udp        : STRING port                   {
>  listen_tcp     : STRING port                   {
>                         struct sockaddr_storage ss[16];
>                         int nhosts, i;
> +                       char *port = $2;
> +
> +                       if (port == NULL)
> +                               port = SNMPD_PORT;
>  
> -                       nhosts = host($1, $2, SOCK_STREAM, ss, nitems(ss));
> +                       nhosts = host($1, port, SOCK_STREAM, ss, nitems(ss));
>                         if (nhosts < 1) {
>                                 yyerror("invalid address: %s", $1);
>                                 free($1);
> -                               if ($2 != snmpd_port)
> -                                       free($2);
> +                               free($2);
>                                 YYERROR;
>                         }
>                         if (nhosts > (int)nitems(ss))
> @@ -325,10 +357,10 @@ listen_tcp        : STRING port                   {
>                                     $1, $2, nitems(ss));
>  
>                         free($1);
> -                       if ($2 != snmpd_port)
> -                               free($2);
> +                       free($2);
>                         for (i = 0; i < nhosts; i++) {
> -                               if (listen_add(&(ss[i]), SOCK_STREAM) == -1) {
> +                               if (listen_add(&(ss[i]), SOCK_STREAM,
> +                                   0) == -1) {
>                                         yyerror("calloc");
>                                         YYERROR;
>                                 }
> @@ -336,7 +368,7 @@ listen_tcp  : STRING port                   {
>                 }
>  
>  port           : /* empty */                   {
> -                       $$ = snmpd_port;
> +                       $$ = NULL;
>                 }
>                 | PORT STRING                   {
>                         $$ = $2;
> @@ -1079,7 +1111,7 @@ parse_config(const char *filename, u_int
>  {
>         struct sockaddr_storage ss;
>         struct sym      *sym, *next;
> -       struct address  *h;
> +       struct address  *h, *htmp;
>         int found;
>  
>         if ((conf = calloc(1, sizeof(*conf))) == NULL) {
> @@ -1108,15 +1140,28 @@ parse_config(const char *filename, u_int
>  
>         endservent();
>  
> +       found = 0;
> +       TAILQ_FOREACH_SAFE(h, &conf->sc_addresses, entry, htmp) {
> +               if (h->flags & ADDRESS_FLAG_TRAP) {
> +                       if (!conf->sc_traphandler) {
> +                               if (!found)
> +                                       fatalx("No trap handle configured");
> +                       }
> +                       found = 1;
> +               }
> +       }
> +       if (conf->sc_traphandler && !found)
> +               fatalx("Trap handle configured without trap listener");
> +
>         /* Setup default listen addresses */
>         if (TAILQ_EMPTY(&conf->sc_addresses)) {
>                 if (host("0.0.0.0", SNMPD_PORT, SOCK_DGRAM, &ss, 1) != 1)
>                         fatal("Unexpected resolving of 0.0.0.0");
> -               if (listen_add(&ss, SOCK_DGRAM) == -1)
> +               if (listen_add(&ss, SOCK_DGRAM, 0) == -1)
>                         fatal("calloc");
>                 if (host("::", SNMPD_PORT, SOCK_DGRAM, &ss, 1) != 1)
>                         fatal("Unexpected resolving of ::");
> -               if (listen_add(&ss, SOCK_DGRAM) == -1)
> +               if (listen_add(&ss, SOCK_DGRAM, 0) == -1)
>                         fatal("calloc");
>         }
>         if (conf->sc_traphandler) {
> @@ -1258,7 +1303,7 @@ host(const char *s, const char *port, in
>  }
>  
>  int
> -listen_add(struct sockaddr_storage *ss, int type)
> +listen_add(struct sockaddr_storage *ss, int type, int flags)
>  {
>         struct sockaddr_in *sin;
>         struct sockaddr_in6 *sin6;
> @@ -1275,6 +1320,7 @@ listen_add(struct sockaddr_storage *ss, 
>                 h->port = ntohs(sin6->sin6_port);
>         }
>         h->type = type;
> +       h->flags = flags;
>         TAILQ_INSERT_TAIL(&(conf->sc_addresses), h, entry);
>  
>         return 0;
> Index: snmpd.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/snmpd/snmpd.c,v
> retrieving revision 1.42
> diff -u -p -r1.42 snmpd.c
> --- snmpd.c     6 Sep 2020 15:51:28 -0000       1.42
> +++ snmpd.c     1 Dec 2020 16:12:20 -0000
> @@ -51,9 +51,7 @@ int    check_child(pid_t, const char *);
>  struct snmpd   *snmpd_env;
>  
>  static struct privsep_proc procs[] = {
> -       { "snmpe", PROC_SNMPE, snmpd_dispatch_snmpe, snmpe, snmpe_shutdown },
> -       { "traphandler", PROC_TRAP, snmpd_dispatch_traphandler, traphandler,
> -           traphandler_shutdown }
> +       { "snmpe", PROC_SNMPE, snmpd_dispatch_snmpe, snmpe, snmpe_shutdown }
>  };
>  
>  void
> @@ -300,6 +298,8 @@ int
>  snmpd_dispatch_snmpe(int fd, struct privsep_proc *p, struct imsg *imsg)
>  {
>         switch (imsg->hdr.type) {
> +       case IMSG_ALERT:
> +               return (traphandler_priv_recvmsg(p, imsg));
>         case IMSG_CTL_RELOAD:
>                 /* XXX notyet */
>         default:
> Index: snmpd.conf.5
> ===================================================================
> RCS file: /cvs/src/usr.sbin/snmpd/snmpd.conf.5,v
> retrieving revision 1.45
> diff -u -p -r1.45 snmpd.conf.5
> --- snmpd.conf.5        24 Oct 2020 14:52:11 -0000      1.45
> +++ snmpd.conf.5        1 Dec 2020 16:12:20 -0000
> @@ -95,13 +95,33 @@ Routing table information will not be av
>  reduced during bulk updates.
>  The default is
>  .Ic no .
> -.It Ic listen on Oo Ic tcp | udp Oc Ar address Op Ic port Ar port
> +.It Ic listen on Oo Ic tcp | udp Oc Ar address Oo Ic port Ar port Oc Op Ic 
> trap
>  Specify the local address
>  .Xr snmpd 8
>  should listen on for incoming SNMP messages.
>  Multiple
>  .Ic listen on
> -statements are supported, the default is UDP.
> +statements are supported, the default is
> +.Ic udp .
> +The default
> +.Ar port
> +is 161.
> +.Pp
> +The
> +.Ic trap
> +keyword disables support for get and set queries and enables support for
> +receiving traps.
> +Currently only
> +.Ic udp
> +listeners support
> +.Ic trap .
> +At least one
> +.Ic trap handle
> +directive must be set.
> +The default
> +.Ic trap
> +.Ar port
> +port is 162.
>  .It Ic read-only community Ar string
>  Specify the name of the read-only community.
>  The default value is
> @@ -193,9 +213,11 @@ 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 be accepted on all
> -.Ic listen on
> -UDP addresses.
> +Setting
> +.Ic trap handle
> +requires that at least one
> +.Ic listen on trap
> +command is set.
>  .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.90
> diff -u -p -r1.90 snmpd.h
> --- snmpd.h     6 Sep 2020 15:51:28 -0000       1.90
> +++ snmpd.h     1 Dec 2020 16:12:20 -0000
> @@ -110,7 +110,6 @@ struct imsgev {
>  enum privsep_procid {
>         PROC_PARENT,    /* Parent process and application interface */
>         PROC_SNMPE,     /* SNMP engine */
> -       PROC_TRAP,      /* SNMP trap receiver */
>         PROC_MAX
>  };
>  
> @@ -386,6 +385,7 @@ struct snmp_message {
>         int                      sm_sock_tcp;
>         struct event             sm_sockev;
>         char                     sm_host[HOST_NAME_MAX+1];
> +       int                      sm_addressflags;
>  
>         struct sockaddr_storage  sm_local_ss;
>         socklen_t                sm_local_slen;
> @@ -483,11 +483,15 @@ struct address {
>         in_port_t                port;
>         int                      type;
>         int                      fd;
> +       int                      flags;
>         struct event             ev;
>         struct event             evt;
>  
>         TAILQ_ENTRY(address)     entry;
>  };
> +
> +#define ADDRESS_FLAG_TRAP 0x01
> +
>  TAILQ_HEAD(addresslist, address);
>  
>  struct trap_address {
> @@ -588,6 +592,7 @@ extern struct snmpd *snmpd_env;
>  /* parse.y */
>  struct snmpd   *parse_config(const char *, u_int);
>  int             cmdline_symset(char *);
> +int             listen_add(struct sockaddr_storage *, int, int);
>  
>  /* log.c */
>  void   log_init(int, int);
> @@ -761,9 +766,8 @@ struct imsgev *
>  int     proc_flush_imsg(struct privsep *, enum privsep_procid, int);
>  
>  /* traphandler.c */
> -void    traphandler(struct privsep *, struct privsep_proc *);
> -void    traphandler_shutdown(void);
> -int     snmpd_dispatch_traphandler(int, struct privsep_proc *, struct imsg 
> *);
> +int     traphandler_parse(struct snmp_message *);
> +int     traphandler_priv_recvmsg(struct privsep_proc *, struct imsg *);
>  void    trapcmd_free(struct trapcmd *);
>  int     trapcmd_add(struct trapcmd *);
>  struct trapcmd *
> Index: snmpe.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/snmpd/snmpe.c,v
> retrieving revision 1.67
> diff -u -p -r1.67 snmpe.c
> --- snmpe.c     6 Sep 2020 17:29:35 -0000       1.67
> +++ snmpe.c     1 Dec 2020 16:12:20 -0000
> @@ -108,7 +108,7 @@ snmpe_init(struct privsep *ps, struct pr
>                         evtimer_set(&h->evt, snmpe_acceptcb, h);
>                 } else {
>                         event_set(&h->ev, h->fd, EV_READ|EV_PERSIST,
> -                           snmpe_recvmsg, env);
> +                           snmpe_recvmsg, h);
>                 }
>                 event_add(&h->ev, NULL);
>         }
> @@ -271,6 +271,12 @@ snmpe_parse(struct snmp_message *msg)
>         if (class != BER_CLASS_CONTEXT)
>                 goto parsefail;
>  
> +       if (msg->sm_addressflags & ADDRESS_FLAG_TRAP &&
> +           type != SNMP_C_TRAP && type != SNMP_C_TRAPV2) {
> +               msg->sm_errstr = "invalid request on trap port";
> +               goto fail;
> +       }
> +
>         switch (type) {
>         case SNMP_C_GETBULKREQ:
>                 if (msg->sm_version == SNMP_V1) {
> @@ -320,7 +326,18 @@ snmpe_parse(struct snmp_message *msg)
>                 goto parsefail;
>  
>         case SNMP_C_TRAP:
> +               if (msg->sm_version != SNMP_V1) {
> +                       stats->snmp_inbadversions++;
> +                       msg->sm_errstr = "SNMPv1-trap on new protocol";
> +                       goto fail;
> +               }
>         case SNMP_C_TRAPV2:
> +               if (type == SNMP_C_TRAPV2 &&
> +                   msg->sm_version != SNMP_V2 && msg->sm_version != SNMP_V3) 
> {
> +                       stats->snmp_inbadversions++;
> +                       msg->sm_errstr = "SNMPv2-trap on wrong protocol";
> +                       goto fail;
> +               }
>                 if (msg->sm_version != SNMP_V3 &&
>                     strcmp(env->sc_trcommunity, msg->sm_community) != 0) {
>                         stats->snmp_inbadcommunitynames++;
> @@ -328,8 +345,13 @@ snmpe_parse(struct snmp_message *msg)
>                         goto fail;
>                 }
>                 stats->snmp_intraps++;
> -               msg->sm_errstr = "received trap";
> -               goto fail;
> +               if ((msg->sm_addressflags & ADDRESS_FLAG_TRAP) == 0) {
> +                       msg->sm_errstr = "received trap";
> +                       goto fail;
> +               }
> +               if (traphandler_parse(msg) == -1)
> +                       goto fail;
> +               return (0);
>  
>         default:
>                 msg->sm_errstr = "invalid context";
> @@ -662,8 +684,8 @@ snmpe_writecb(int fd, short type, void *
>  void
>  snmpe_recvmsg(int fd, short sig, void *arg)
>  {
> -       struct snmpd            *env = arg;
> -       struct snmp_stats       *stats = &env->sc_stats;
> +       struct address          *h = arg;
> +       struct snmp_stats       *stats = &(snmpd_env->sc_stats);
>         ssize_t                  len;
>         struct snmp_message     *msg;
>  
> @@ -672,6 +694,7 @@ snmpe_recvmsg(int fd, short sig, void *a
>  
>         msg->sm_sock = fd;
>         msg->sm_slen = sizeof(msg->sm_ss);
> +       msg->sm_addressflags = h->flags;
>         if ((len = recvfromto(fd, msg->sm_data, sizeof(msg->sm_data), 0,
>             (struct sockaddr *)&msg->sm_ss, &msg->sm_slen,
>             (struct sockaddr *)&msg->sm_local_ss, &msg->sm_local_slen)) < 1) {
> Index: traphandler.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/snmpd/traphandler.c,v
> retrieving revision 1.18
> diff -u -p -r1.18 traphandler.c
> --- traphandler.c       6 Sep 2020 15:51:28 -0000       1.18
> +++ traphandler.c       1 Dec 2020 16:12:20 -0000
> @@ -42,16 +42,10 @@
>  #include "snmpd.h"
>  #include "mib.h"
>  
> -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 
> *);
> -int     traphandler_bind(struct address *);
> -void    traphandler_recvmsg(int, short, void *);
> +int     traphandler_extract(struct snmp_message *, struct ber_element *,
> +           u_int *, struct ber_oid *, struct ber_element **);
>  int     traphandler_priv_recvmsg(struct privsep_proc *, struct imsg *);
>  int     traphandler_fork_handler(struct privsep_proc *, struct imsg *);
> -int     traphandler_parse(char *, size_t, struct ber_element **,
> -           struct ber_element **, u_int *, struct ber_oid *);
>  void    traphandler_v1translate(struct ber_oid *, u_int, u_int);
>  
>  int     trapcmd_cmp(struct trapcmd *, struct trapcmd *);
> @@ -65,208 +59,105 @@ RB_GENERATE(trapcmd_tree, trapcmd, cmd_e
>  
>  struct trapcmd_tree trapcmd_tree = RB_INITIALIZER(&trapcmd_tree);
>  
> -static struct privsep_proc procs[] = {
> -       { "parent",     PROC_PARENT,    traphandler_dispatch_parent }
> -};
> -
> -void
> -traphandler(struct privsep *ps, struct privsep_proc *p)
> -{
> -       struct snmpd            *env = ps->ps_env;
> -       struct address          *h;
> -
> -       if (env->sc_traphandler) {
> -               TAILQ_FOREACH(h, &env->sc_addresses, entry) {
> -                       if (h->type != SOCK_DGRAM)
> -                               continue;
> -                       if ((h->fd = traphandler_bind(h)) == -1)
> -                               fatal("could not create trap listener 
> socket");
> -               }
> -       }
> -
> -       proc_run(ps, p, procs, nitems(procs), traphandler_init, NULL);
> -}
> -
> -void
> -traphandler_init(struct privsep *ps, struct privsep_proc *p, void *arg)
> -{
> -       struct snmpd            *env = ps->ps_env;
> -       struct address          *h;
> -
> -       if (pledge("stdio id proc recvfd exec", NULL) == -1)
> -               fatal("pledge");
> -
> -       if (!env->sc_traphandler)
> -               return;
> -
> -       /* listen for SNMP trap messages */
> -       TAILQ_FOREACH(h, &env->sc_addresses, entry) {
> -               event_set(&h->ev, h->fd, EV_READ|EV_PERSIST,
> -                   traphandler_recvmsg, ps);
> -               event_add(&h->ev, NULL);
> -       }
> -}
> -
> -int
> -traphandler_bind(struct address *addr)
> -{
> -       int                      s;
> -       char                     buf[512];
> -       struct sockaddr_in      *sin;
> -       struct sockaddr_in6     *sin6;
> -
> -       if (addr->ss.ss_family == AF_INET) {
> -               sin = (struct sockaddr_in *)&(addr->ss);
> -               sin->sin_port = htons(162);
> -       } else {
> -               sin6 = (struct sockaddr_in6 *)&(addr->ss);
> -               sin6->sin6_port = htons(162);
> -       }
> -       if ((s = snmpd_socket_af(&addr->ss, SOCK_DGRAM)) == -1)
> -               return (-1);
> -
> -       if (fcntl(s, F_SETFL, O_NONBLOCK) == -1)
> -               goto bad;
> -
> -       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:%s", buf, SNMPD_TRAPPORT);
> -
> -       return (s);
> - bad:
> -       close (s);
> -       return (-1);
> -}
> -
> -void
> -traphandler_shutdown(void)
> -{
> -       struct address          *h;
> -
> -       TAILQ_FOREACH(h, &snmpd_env->sc_addresses, entry) {
> -               event_del(&h->ev);
> -               close(h->fd);
> -       }
> -}
> -
> -int
> -traphandler_dispatch_parent(int fd, struct privsep_proc *p, struct imsg 
> *imsg)
> -{
> -       switch (imsg->hdr.type) {
> -       default:
> -               break;
> -       }
> -
> -       return (-1);
> -}
> -
> -int
> -snmpd_dispatch_traphandler(int fd, struct privsep_proc *p, struct imsg *imsg)
> -{
> -       switch (imsg->hdr.type) {
> -       case IMSG_ALERT:
> -               return (traphandler_priv_recvmsg(p, imsg));
> -       default:
> -               break;
> -       }
> -
> -       return (-1);
> -}
> -
> -void
> -traphandler_recvmsg(int fd, short events, void *arg)
> -{
> -       struct privsep          *ps = arg;
> -       char                     buf[8196];
> -       struct iovec             iov[2];
> -       struct sockaddr_storage  ss;
> -       socklen_t                slen;
> -       ssize_t                  n;
> -       struct ber_element      *req, *iter;
> -       struct ber_oid           trapoid;
> -       u_int                    uptime;
> -
> -       slen = sizeof(ss);
> -       if ((n = recvfrom(fd, buf, sizeof(buf), 0, (struct sockaddr *)&ss,
> -           &slen)) == -1)
> -               return;
> -
> -       if (traphandler_parse(buf, n, &req, &iter, &uptime, &trapoid) == -1)
> -               goto done;
> -
> -       iov[0].iov_base = &ss;
> -       iov[0].iov_len = ss.ss_len;
> -       iov[1].iov_base = buf;
> -       iov[1].iov_len = n;
> -
> -       /* Forward it to the parent process */
> -       if (proc_composev(ps, PROC_PARENT, IMSG_ALERT, iov, 2) == -1)
> -               goto done;
> -
> - done:
> -       if (req != NULL)
> -               ober_free_elements(req);
> -       return;
> -}
> -
>  /*
> - * Validate received message
> + * Validate received message let parent create a handler process.
>   */
>  int
> -traphandler_parse(char *buf, size_t n, struct ber_element **req,
> -    struct ber_element **vbinds, u_int *uptime, struct ber_oid *trapoid)
> +traphandler_parse(struct snmp_message *msg)
>  {
>         struct ber               ber;
> -       struct ber_element      *elm;
> -       u_int                    vers, gtype, etype;
> +       struct ber_oid           oid;
> +       struct ber_element      *vb;
> +       struct iovec             iov[2];
> +       u_int                    uptime;
> +       ssize_t                  len;
> +       char                    *pdu;
> +
> +       if (traphandler_extract(msg, msg->sm_pdu, &uptime, &oid, &vb) == -1)
> +               return -1;
>  
>         bzero(&ber, sizeof(ber));
>         ober_set_application(&ber, smi_application);
> -       ober_set_readbuf(&ber, buf, n);
>  
> -       if ((*req = ober_read_elements(&ber, NULL)) == NULL)
> -               goto done;
> +       if ((len = ober_write_elements(&ber, msg->sm_pdu)) == -1) {
> +               /* ober_write_elements can only return ENOMEM on error */
> +               msg->sm_errstr = "failed to handle trap: Cannot allocate 
> memory";
> +               ober_free(&ber);
> +               return -1;
> +       }
> +       ober_get_writebuf(&ber, (void **)&pdu);
> +
> +       iov[0].iov_base = &(msg->sm_ss);
> +       iov[0].iov_len = msg->sm_ss.ss_len;
> +       iov[1].iov_base = pdu;
> +       iov[1].iov_len = (size_t)len;
> +
> +       if (proc_composev(&(snmpd_env->sc_ps), PROC_PARENT, IMSG_ALERT, iov,
> +           2) == -1) {
> +               ober_free(&ber);
> +               /* We need a better error reporting system, no errno for now 
> */
> +               msg->sm_errstr = "Failed to handle trap";
> +               return -1;
> +       }
>  
> -       if (ober_scanf_elements(*req, "{dSe", &vers, &elm) == -1)
> -               goto done;
> +       ober_free(&ber);
> +       return (0);
> +}
>  
> -       switch (vers) {
> -       case SNMP_V1:
> -               if (ober_scanf_elements(elm, "{oSddde",
> -                   trapoid, &gtype, &etype, uptime, &elm) == -1)
> -                       goto done;
> -               traphandler_v1translate(trapoid, gtype, etype);
> -               if (elm->be_type != BER_TYPE_SEQUENCE)
> -                       goto done;
> -               *vbinds = elm->be_sub;
> +int
> +traphandler_extract(struct snmp_message *msg, struct ber_element *pdu,
> +    u_int *uptime, struct ber_oid *trapoid, struct ber_element **vb0)
> +{
> +       struct ber_oid           oid;
> +       u_int                    class, gtype, etype;
> +       unsigned int             type;
> +       struct ber_element      *vb, *tmp;
> +       /* OK to set stats twice, they only count in the snmpe process */
> +       struct snmp_stats       *stats = &(snmpd_env->sc_stats);
> +       char *buf;
> +
> +       if (ober_scanf_elements(pdu, "t", &class, &type) != 0) {
> +               msg->sm_errstr = "Invalid trap format";
> +               stats->snmp_inasnparseerrs++;
> +               return -1;
> +       }
> +
> +       switch (type) {
> +       case SNMP_C_TRAP:
> +               if (ober_scanf_elements(pdu, "{oSddd{e", trapoid, &gtype, 
> &etype,
> +                   &uptime, vb0) == -1) {
> +                       msg->sm_errstr = "Invalid trap format";
> +                       stats->snmp_inasnparseerrs++;
> +                       return -1;
> +               }
>                 break;
> -
> -       case SNMP_V2:
> -               if (ober_scanf_elements(elm, "{SSS{e}}", &elm) == -1 ||
> -                   ober_scanf_elements(elm, "{Sd}{So}",
> -                   uptime, trapoid) == -1)
> -                       goto done;
> -               *vbinds = elm->be_next->be_next;
> +       case SNMP_C_TRAPV2:
> +               if (ober_scanf_elements(pdu, "{SSS{e", &vb) == -1 ||
> +                   ober_scanf_elements(vb, "{Sd}{So}",
> +                   &uptime, trapoid) == -1) {
> +                       msg->sm_errstr = "Invalid trapv2 format";
> +                       stats->snmp_inasnparseerrs++;
> +                       return -1;
> +               }
> +               *vb0 = vb->be_next->be_next;
>                 break;
> -
>         default:
> -               log_warnx("unsupported SNMP trap version '%d'", vers);
> -               goto done;
> +               msg->sm_errstr = "invalid pdu type";
> +               stats->snmp_inasnparseerrs++;
> +               return -1;
>         }
>  
> -       ober_free(&ber);
> -       return (0);
> +       for (vb = *vb0; vb != NULL; vb = vb->be_next) {
> +               if (ober_scanf_elements(vb, "{oe}", &oid, &tmp) == -1 ||
> +                   (buf = smi_print_element(tmp)) == NULL) {
> +                       msg->sm_errstr = "invalid varbind in trap";
> +                       stats->snmp_inasnparseerrs++;
> +                       return -1;
> +               }
> +               free(buf);
> +       }
>  
> - done:
> -       ober_free(&ber);
> -       if (*req)
> -               ober_free_elements(*req);
> -       *req = NULL;
> -       return (-1);
> +       return 0;
>  }
>  
>  void
> @@ -312,7 +203,8 @@ traphandler_fork_handler(struct privsep_
>         struct sockaddr         *sa;
>         char                    *buf;
>         ssize_t                  n;
> -       struct ber_element      *req, *iter;
> +       struct ber               ber;
> +       struct ber_element      *iter, *pdu;
>         struct trapcmd          *cmd;
>         struct ber_oid           trapoid;
>         u_int                    uptime;
> @@ -339,15 +231,21 @@ traphandler_fork_handler(struct privsep_
>         n -= sa->sa_len;
>         buf = (char *)imsg->data + sa->sa_len;
>  
> -       if (traphandler_parse(buf, n, &req, &iter, &uptime, &trapoid) == -1)
> +       bzero(&ber, sizeof(ber));
> +       ober_set_application(&ber, smi_application);
> +       ober_set_readbuf(&ber, buf, n);
> +       if ((pdu = ober_read_elements(&ber, NULL)) == NULL)
> +               fatal("traphandler_fork_handler: ober_read_elements");
> +
> +       if (traphandler_extract(NULL, pdu, &uptime, &trapoid, &iter) == -1)
>                 fatalx("couldn't parse SNMP trap message");
>  
>         smi_oid2string(&trapoid, oidbuf, sizeof(oidbuf), 0);
>         if ((cmd = trapcmd_lookup(&trapoid)) != NULL)
>                 trapcmd_exec(cmd, sa, iter, oidbuf, uptime);
>  
> -       if (req != NULL)
> -               ober_free_elements(req);
> +       ober_free_elements(pdu);
> +       ober_free(&ber);
>  
>         exit(0);
>  }
> 
> 


Reply via email to