Import snmpd_metrics.
authormartijn <martijn@openbsd.org>
Thu, 1 Sep 2022 14:20:32 +0000 (14:20 +0000)
committermartijn <martijn@openbsd.org>
Thu, 1 Sep 2022 14:20:32 +0000 (14:20 +0000)
This contains snmpd's mib.c (and friends) adjusted for libagentx.
This standalone binary is to be used by snmpd to achieve privilege
separation.

If people need net-snmpd, but want some of the base snmpd metrics they can
start this binary as a normal daemon and connect to net-snmpd's agentx
socket.

Tested, Feedback, and OK sthen@
Release build test, and OK tb@

12 files changed:
libexec/snmpd/Makefile [new file with mode: 0644]
libexec/snmpd/snmpd_metrics/Makefile [new file with mode: 0644]
libexec/snmpd/snmpd_metrics/kroute.c [new file with mode: 0644]
libexec/snmpd/snmpd_metrics/log.c [new file with mode: 0644]
libexec/snmpd/snmpd_metrics/log.h [new file with mode: 0644]
libexec/snmpd/snmpd_metrics/mib.c [new file with mode: 0644]
libexec/snmpd/snmpd_metrics/mib.h [new file with mode: 0644]
libexec/snmpd/snmpd_metrics/pf.c [new file with mode: 0644]
libexec/snmpd/snmpd_metrics/snmpd.h [new file with mode: 0644]
libexec/snmpd/snmpd_metrics/snmpd_metrics.8 [new file with mode: 0644]
libexec/snmpd/snmpd_metrics/timer.c [new file with mode: 0644]
libexec/snmpd/snmpd_metrics/util.c [new file with mode: 0644]

diff --git a/libexec/snmpd/Makefile b/libexec/snmpd/Makefile
new file mode 100644 (file)
index 0000000..06d5c44
--- /dev/null
@@ -0,0 +1,8 @@
+#      from: @(#)Makefile      5.7 (Berkeley) 4/1/91
+#      $OpenBSD: Makefile,v 1.1.1.1 2022/09/01 14:20:32 martijn Exp $
+
+.include <bsd.own.mk>
+
+SUBDIR= snmpd_metrics
+
+.include <bsd.subdir.mk>
diff --git a/libexec/snmpd/snmpd_metrics/Makefile b/libexec/snmpd/snmpd_metrics/Makefile
new file mode 100644 (file)
index 0000000..1b768f7
--- /dev/null
@@ -0,0 +1,17 @@
+#      $OpenBSD: Makefile,v 1.1.1.1 2022/09/01 14:20:34 martijn Exp $
+
+PROG=          snmpd_metrics
+SRCS=          mib.c log.c kroute.c pf.c timer.c util.c
+MAN=           snmpd_metrics.8
+
+CFLAGS+=       -Wall -I${.CURDIR}
+CFLAGS+=       -Wstrict-prototypes -Wmissing-prototypes
+CFLAGS+=       -Wmissing-declarations
+CFLAGS+=       -Wshadow -Wpointer-arith -Wcast-qual
+CFLAGS+=       -Wsign-compare
+
+LDADD=         -lagentx -levent -lkvm
+DPADD=         ${LIBAGENTX} ${LIBEVENT} ${LIBKVM}
+BINDIR=                /usr/libexec/snmpd/
+
+.include <bsd.prog.mk>
diff --git a/libexec/snmpd/snmpd_metrics/kroute.c b/libexec/snmpd/snmpd_metrics/kroute.c
new file mode 100644 (file)
index 0000000..91de8d4
--- /dev/null
@@ -0,0 +1,1699 @@
+/*     $OpenBSD: kroute.c,v 1.1.1.1 2022/09/01 14:20:33 martijn Exp $  */
+
+/*
+ * Copyright (c) 2007, 2008 Reyk Floeter <reyk@openbsd.org>
+ * Copyright (c) 2004 Esben Norby <norby@openbsd.org>
+ * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+#include <sys/tree.h>
+#include <sys/uio.h>
+#include <sys/ioctl.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_types.h>
+#include <net/route.h>
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+#include <arpa/inet.h>
+
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <event.h>
+
+#include "snmpd.h"
+
+struct ktable          **krt;
+u_int                    krt_size;
+
+struct {
+       struct event             ks_ev;
+       u_long                   ks_iflastchange;
+       u_long                   ks_nroutes;    /* 4 billions enough? */
+       int                      ks_fd;
+       int                      ks_ifd;
+       u_short                  ks_nkif;
+} kr_state;
+
+struct kroute_node {
+       RB_ENTRY(kroute_node)    entry;
+       struct kroute            r;
+       struct kroute_node      *next;
+};
+
+struct kroute6_node {
+       RB_ENTRY(kroute6_node)   entry;
+       struct kroute6           r;
+       struct kroute6_node     *next;
+};
+
+struct kif_node {
+       RB_ENTRY(kif_node)       entry;
+       TAILQ_HEAD(, kif_addr)   addrs;
+       TAILQ_HEAD(, kif_arp)    arps;
+       struct kif               k;
+};
+
+int    kroute_compare(struct kroute_node *, struct kroute_node *);
+int    kroute6_compare(struct kroute6_node *, struct kroute6_node *);
+int    kif_compare(struct kif_node *, struct kif_node *);
+
+void                    ktable_init(void);
+int                     ktable_new(u_int, u_int);
+void                    ktable_free(u_int);
+int                     ktable_exists(u_int, u_int *);
+struct ktable          *ktable_get(u_int);
+int                     ktable_update(u_int);
+
+struct kroute_node     *kroute_find(struct ktable *, in_addr_t, u_int8_t,
+                           u_int8_t);
+struct kroute_node     *kroute_matchgw(struct kroute_node *,
+                           struct sockaddr_in *);
+int                     kroute_insert(struct ktable *, struct kroute_node *);
+int                     kroute_remove(struct ktable *, struct kroute_node *);
+void                    kroute_clear(struct ktable *);
+
+struct kroute6_node    *kroute6_find(struct ktable *, const struct in6_addr *,
+                           u_int8_t, u_int8_t);
+struct kroute6_node    *kroute6_matchgw(struct kroute6_node *,
+                           struct sockaddr_in6 *);
+int                     kroute6_insert(struct ktable *, struct kroute6_node *);
+int                     kroute6_remove(struct ktable *, struct kroute6_node *);
+void                    kroute6_clear(struct ktable *);
+
+struct kif_arp         *karp_find(struct sockaddr *, u_short);
+int                     karp_insert(struct kif_node *, struct kif_arp *);
+int                     karp_remove(struct kif_node *, struct kif_arp *);
+
+struct kif_node                *kif_find(u_short);
+struct kif_node                *kif_insert(u_short);
+int                     kif_remove(struct kif_node *);
+void                    kif_clear(void);
+struct kif             *kif_update(u_short, int, struct if_data *,
+                           struct sockaddr_dl *);
+
+int                     ka_compare(struct kif_addr *, struct kif_addr *);
+void                    ka_insert(u_short, struct kif_addr *);
+struct kif_addr                *ka_find(struct sockaddr *);
+int                     ka_remove(struct kif_addr *);
+
+u_int8_t       prefixlen_classful(in_addr_t);
+u_int8_t       mask2prefixlen(in_addr_t);
+in_addr_t      prefixlen2mask(u_int8_t);
+u_int8_t       mask2prefixlen6(struct sockaddr_in6 *);
+struct in6_addr *prefixlen2mask6(u_int8_t);
+void           get_rtaddrs(int, struct sockaddr *, struct sockaddr **);
+void           if_change(u_short, int, struct if_data *, struct sockaddr_dl *);
+void           if_newaddr(u_short, struct sockaddr *, struct sockaddr *,
+                   struct sockaddr *);
+void           if_deladdr(u_short, struct sockaddr *, struct sockaddr *,
+                   struct sockaddr *);
+void           if_announce(void *);
+
+int            fetchtable(struct ktable *);
+int            fetchifs(u_short);
+int            fetcharp(struct ktable *);
+void           dispatch_rtmsg(int, short, void *);
+int            rtmsg_process(char *, int);
+int            dispatch_rtmsg_addr(struct ktable *, struct rt_msghdr *,
+                   struct sockaddr *[RTAX_MAX]);
+
+RB_PROTOTYPE(kroute_tree, kroute_node, entry, kroute_compare)
+RB_GENERATE(kroute_tree, kroute_node, entry, kroute_compare)
+
+RB_PROTOTYPE(kroute6_tree, kroute6_node, entry, kroute6_compare)
+RB_GENERATE(kroute6_tree, kroute6_node, entry, kroute6_compare)
+
+RB_HEAD(kif_tree, kif_node)            kit;
+RB_PROTOTYPE(kif_tree, kif_node, entry, kif_compare)
+RB_GENERATE(kif_tree, kif_node, entry, kif_compare)
+
+RB_HEAD(ka_tree, kif_addr)             kat;
+RB_PROTOTYPE(ka_tree, kif_addr, node, ka_compare)
+RB_GENERATE(ka_tree, kif_addr, node, ka_compare)
+
+void
+kr_init(void)
+{
+       int             opt = 0, rcvbuf, default_rcvbuf;
+       unsigned int    tid = RTABLE_ANY;
+       socklen_t       optlen;
+
+       if ((kr_state.ks_ifd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
+               fatal("kr_init: ioctl socket");
+
+       if ((kr_state.ks_fd = socket(AF_ROUTE, SOCK_RAW, 0)) == -1)
+               fatal("kr_init: route socket");
+
+       /* not interested in my own messages */
+       if (setsockopt(kr_state.ks_fd, SOL_SOCKET, SO_USELOOPBACK,
+           &opt, sizeof(opt)) == -1)
+               log_warn("%s: SO_USELOOPBACK", __func__);       /* not fatal */
+
+       if (snmpd_env->sc_rtfilter && setsockopt(kr_state.ks_fd, AF_ROUTE,
+           ROUTE_MSGFILTER, &snmpd_env->sc_rtfilter,
+           sizeof(snmpd_env->sc_rtfilter)) == -1)
+               log_warn("%s: ROUTE_MSGFILTER", __func__);
+
+       /* grow receive buffer, don't wanna miss messages */
+       optlen = sizeof(default_rcvbuf);
+       if (getsockopt(kr_state.ks_fd, SOL_SOCKET, SO_RCVBUF,
+           &default_rcvbuf, &optlen) == -1)
+               log_warn("%s: SO_RCVBUF", __func__);
+       else
+               for (rcvbuf = MAX_RTSOCK_BUF;
+                   rcvbuf > default_rcvbuf &&
+                   setsockopt(kr_state.ks_fd, SOL_SOCKET, SO_RCVBUF,
+                   &rcvbuf, sizeof(rcvbuf)) == -1 && errno == ENOBUFS;
+                   rcvbuf /= 2)
+                       ;       /* nothing */
+
+       if (setsockopt(kr_state.ks_fd, AF_ROUTE, ROUTE_TABLEFILTER, &tid,
+           sizeof(tid)) == -1)
+               log_warn("%s: ROUTE_TABLEFILTER", __func__);
+
+       RB_INIT(&kit);
+       RB_INIT(&kat);
+
+       if (fetchifs(0) == -1)
+               fatalx("kr_init: fetchifs");
+
+       ktable_init();
+
+       event_set(&kr_state.ks_ev, kr_state.ks_fd, EV_READ | EV_PERSIST,
+           dispatch_rtmsg, NULL);
+       event_add(&kr_state.ks_ev, NULL);
+}
+
+void
+ktable_init(void)
+{
+       u_int            i;
+
+       for (i = 0; i <= RT_TABLEID_MAX; i++)
+               if (ktable_exists(i, NULL))
+                       ktable_update(i);
+}
+
+int
+ktable_new(u_int rtableid, u_int rdomid)
+{
+       struct ktable   **xkrt;
+       struct ktable    *kt;
+       size_t            newsize, oldsize;
+
+       /* resize index table if needed */
+       if (rtableid >= krt_size) {
+               if ((xkrt = reallocarray(krt, rtableid + 1,
+                   sizeof(struct ktable *))) == NULL) {
+                       log_warn("%s: realloc", __func__);
+                       return (-1);
+               }
+               krt = xkrt;
+               oldsize = krt_size * sizeof(struct ktable *);
+               krt_size = rtableid + 1;
+               newsize = krt_size * sizeof(struct ktable *);
+               bzero((char *)krt + oldsize, newsize - oldsize);
+       }
+
+       if (krt[rtableid])
+               fatalx("ktable_new: table already exists");
+
+       /* allocate new element */
+       kt = krt[rtableid] = calloc(1, sizeof(struct ktable));
+       if (kt == NULL) {
+               log_warn("%s: calloc", __func__);
+               return (-1);
+       }
+
+       /* initialize structure ... */
+       RB_INIT(&kt->krt);
+       RB_INIT(&kt->krt6);
+       kt->rtableid = rtableid;
+       kt->rdomain = rdomid;
+
+       /* ... and load it */
+       if (fetchtable(kt) == -1)
+               return (-1);
+       /* load arp information */
+       if (fetcharp(kt) == -1)
+               return (-1);
+
+       log_debug("%s: new ktable for rtableid %d", __func__, rtableid);
+       return (0);
+}
+
+void
+ktable_free(u_int rtableid)
+{
+       struct ktable   *kt;
+
+       if ((kt = ktable_get(rtableid)) == NULL)
+               return;
+
+       log_debug("%s: freeing ktable rtableid %u", __func__, kt->rtableid);
+       kroute_clear(kt);
+       kroute6_clear(kt);
+
+       krt[kt->rtableid] = NULL;
+       free(kt);
+}
+
+struct ktable *
+ktable_get(u_int rtableid)
+{
+       if (rtableid >= krt_size)
+               return (NULL);
+       return (krt[rtableid]);
+}
+
+int
+ktable_update(u_int rtableid)
+{
+       struct ktable   *kt;
+       u_int            rdomid;
+
+       if (!ktable_exists(rtableid, &rdomid))
+               fatalx("ktable_update: table doesn't exist");
+
+       if (rdomid != rtableid) {
+               if (ktable_get(rdomid) == NULL &&
+                   ktable_new(rdomid, rdomid) != 0)
+                       return (-1);
+       }
+
+       kt = ktable_get(rtableid);
+       if (kt == NULL) {
+               if (ktable_new(rtableid, rdomid))
+                       return (-1);
+       }
+       return (0);
+}
+
+int
+ktable_exists(u_int rtableid, u_int *rdomid)
+{
+       size_t                   len;
+       struct rt_tableinfo      info;
+       int                      mib[6];
+
+       mib[0] = CTL_NET;
+       mib[1] = PF_ROUTE;
+       mib[2] = 0;
+       mib[3] = 0;
+       mib[4] = NET_RT_TABLE;
+       mib[5] = rtableid;
+
+       len = sizeof(info);
+       if (sysctl(mib, 6, &info, &len, NULL, 0) == -1) {
+               if (errno == ENOENT)
+                       /* table nonexistent */
+                       return (0);
+               log_warn("%s: sysctl", __func__);
+               /* must return 0 so that the table is considered non-existent */
+               return (0);
+       }
+       if (rdomid)
+               *rdomid = info.rti_domainid;
+       return (1);
+}
+
+void
+kr_shutdown(void)
+{
+       u_int   i;
+
+       for (i = krt_size; i > 0; i--)
+               ktable_free(i - 1);
+       kif_clear();
+}
+
+u_int
+kr_ifnumber(void)
+{
+       return (kr_state.ks_nkif);
+}
+
+u_long
+kr_iflastchange(void)
+{
+       return (kr_state.ks_iflastchange);
+}
+
+int
+kr_updateif(u_int if_index)
+{
+       return (fetchifs(if_index));
+}
+
+u_long
+kr_routenumber(void)
+{
+       return (kr_state.ks_nroutes);
+}
+
+/* rb-tree compare */
+int
+kroute_compare(struct kroute_node *a, struct kroute_node *b)
+{
+       if (ntohl(a->r.prefix.s_addr) < ntohl(b->r.prefix.s_addr))
+               return (-1);
+       if (ntohl(a->r.prefix.s_addr) > ntohl(b->r.prefix.s_addr))
+               return (1);
+       if (a->r.prefixlen < b->r.prefixlen)
+               return (-1);
+       if (a->r.prefixlen > b->r.prefixlen)
+               return (1);
+
+       /* if the priority is RTP_ANY finish on the first address hit */
+       if (a->r.priority == RTP_ANY || b->r.priority == RTP_ANY)
+               return (0);
+       if (a->r.priority < b->r.priority)
+               return (-1);
+       if (a->r.priority > b->r.priority)
+               return (1);
+       return (0);
+}
+
+int
+kroute6_compare(struct kroute6_node *a, struct kroute6_node *b)
+{
+       int i;
+
+       for (i = 0; i < 16; i++) {
+               if (a->r.prefix.s6_addr[i] < b->r.prefix.s6_addr[i])
+                       return (-1);
+               if (a->r.prefix.s6_addr[i] > b->r.prefix.s6_addr[i])
+                       return (1);
+       }
+
+       if (a->r.prefixlen < b->r.prefixlen)
+               return (-1);
+       if (a->r.prefixlen > b->r.prefixlen)
+               return (1);
+
+       /* if the priority is RTP_ANY finish on the first address hit */
+       if (a->r.priority == RTP_ANY || b->r.priority == RTP_ANY)
+               return (0);
+       if (a->r.priority < b->r.priority)
+               return (-1);
+       if (a->r.priority > b->r.priority)
+               return (1);
+       return (0);
+}
+
+int
+kif_compare(struct kif_node *a, struct kif_node *b)
+{
+       return (a->k.if_index - b->k.if_index);
+}
+
+int
+ka_compare(struct kif_addr *a, struct kif_addr *b)
+{
+       if (a->addr.sa.sa_family < b->addr.sa.sa_family)
+               return (-1);
+       if (a->addr.sa.sa_family > b->addr.sa.sa_family)
+               return (1);
+       return (memcmp(&a->addr.sa, &b->addr.sa, a->addr.sa.sa_len));
+}
+
+/* tree management */
+struct kroute_node *
+kroute_find(struct ktable *kt, in_addr_t prefix, u_int8_t prefixlen,
+    u_int8_t prio)
+{
+       struct kroute_node      s;
+       struct kroute_node      *kn, *tmp;
+
+       s.r.prefix.s_addr = prefix;
+       s.r.prefixlen = prefixlen;
+       s.r.priority = prio;
+
+       kn = RB_FIND(kroute_tree, &kt->krt, &s);
+       if (kn && prio == RTP_ANY) {
+               tmp = RB_PREV(kroute_tree, &kt->krt, kn);
+               while (tmp) {
+                       if (kroute_compare(&s, tmp) == 0)
+                               kn = tmp;
+                       else
+                               break;
+                       tmp = RB_PREV(kroute_tree, &kt->krt, kn);
+               }
+       }
+       return (kn);
+}
+
+struct kroute_node *
+kroute_matchgw(struct kroute_node *kr, struct sockaddr_in *sa_in)
+{
+       in_addr_t       nexthop;
+
+       if (sa_in == NULL) {
+               log_warnx("%s: no nexthop defined", __func__);
+               return (NULL);
+       }
+       nexthop = sa_in->sin_addr.s_addr;
+
+       while (kr) {
+               if (kr->r.nexthop.s_addr == nexthop)
+                       return (kr);
+               kr = kr->next;
+       }
+
+       return (NULL);
+}
+
+int
+kroute_insert(struct ktable *kt, struct kroute_node *kr)
+{
+       struct kroute_node      *krm;
+
+       if ((krm = RB_INSERT(kroute_tree, &kt->krt, kr)) != NULL) {
+               /* multipath route, add at end of list */
+               while (krm->next != NULL)
+                       krm = krm->next;
+               krm->next = kr;
+               kr->next = NULL; /* to be sure */
+       }
+
+       kr_state.ks_nroutes++;
+       return (0);
+}
+
+int
+kroute_remove(struct ktable *kt, struct kroute_node *kr)
+{
+       struct kroute_node      *krm;
+
+       if ((krm = RB_FIND(kroute_tree, &kt->krt, kr)) == NULL) {
+               log_warnx("%s: failed to find %s/%u", __func__,
+                   inet_ntoa(kr->r.prefix), kr->r.prefixlen);
+               return (-1);
+       }
+
+       if (krm == kr) {
+               /* head element */
+               if (RB_REMOVE(kroute_tree, &kt->krt, kr) == NULL) {
+                       log_warnx("%s: failed for %s/%u", __func__,
+                           inet_ntoa(kr->r.prefix), kr->r.prefixlen);
+                       return (-1);
+               }
+               if (kr->next != NULL) {
+                       if (RB_INSERT(kroute_tree, &kt->krt, kr->next)
+                           != NULL) {
+                               log_warnx("%s: failed to add %s/%u", __func__,
+                                   inet_ntoa(kr->r.prefix), kr->r.prefixlen);
+                               return (-1);
+                       }
+               }
+       } else {
+               /* somewhere in the list */
+               while (krm->next != kr && krm->next != NULL)
+                       krm = krm->next;
+               if (krm->next == NULL) {
+                       log_warnx("%s: multipath list corrupted for %s/%u",
+                           __func__, inet_ntoa(kr->r.prefix), kr->r.prefixlen);
+                       return (-1);
+               }
+               krm->next = kr->next;
+       }
+
+       kr_state.ks_nroutes--;
+       free(kr);
+       return (0);
+}
+
+void
+kroute_clear(struct ktable *kt)
+{
+       struct kroute_node      *kr;
+
+       while ((kr = RB_MIN(kroute_tree, &kt->krt)) != NULL)
+               kroute_remove(kt, kr);
+}
+
+struct kroute6_node *
+kroute6_find(struct ktable *kt, const struct in6_addr *prefix,
+    u_int8_t prefixlen, u_int8_t prio)
+{
+       struct kroute6_node     s;
+       struct kroute6_node     *kn6, *tmp;
+
+       memcpy(&s.r.prefix, prefix, sizeof(struct in6_addr));
+       s.r.prefixlen = prefixlen;
+       s.r.priority = prio;
+
+       kn6 = RB_FIND(kroute6_tree, &kt->krt6, &s);
+       if (kn6 && prio == RTP_ANY) {
+               tmp = RB_PREV(kroute6_tree, &kt->krt6, kn6);
+               while (tmp) {
+                       if (kroute6_compare(&s, tmp) == 0)
+                               kn6 = tmp;
+                       else
+                               break;
+                       tmp = RB_PREV(kroute6_tree, &kt->krt6, kn6);
+               }
+       }
+       return (kn6);
+}
+
+struct kroute6_node *
+kroute6_matchgw(struct kroute6_node *kr, struct sockaddr_in6 *sa_in6)
+{
+       struct in6_addr nexthop;
+
+       if (sa_in6 == NULL) {
+               log_warnx("%s: no nexthop defined", __func__);
+               return (NULL);
+       }
+       memcpy(&nexthop, &sa_in6->sin6_addr, sizeof(nexthop));
+
+       while (kr) {
+               if (memcmp(&kr->r.nexthop, &nexthop, sizeof(nexthop)) == 0)
+                       return (kr);
+               kr = kr->next;
+       }
+
+       return (NULL);
+}
+
+int
+kroute6_insert(struct ktable *kt, struct kroute6_node *kr)
+{
+       struct kroute6_node     *krm;
+
+       if ((krm = RB_INSERT(kroute6_tree, &kt->krt6, kr)) != NULL) {
+               /* multipath route, add at end of list */
+               while (krm->next != NULL)
+                       krm = krm->next;
+               krm->next = kr;
+               kr->next = NULL; /* to be sure */
+       }
+
+       kr_state.ks_nroutes++;
+       return (0);
+}
+
+int
+kroute6_remove(struct ktable *kt, struct kroute6_node *kr)
+{
+       struct kroute6_node     *krm;
+
+       if ((krm = RB_FIND(kroute6_tree, &kt->krt6, kr)) == NULL) {
+               log_warnx("%s: failed for %s/%u", __func__,
+                   log_in6addr(&kr->r.prefix), kr->r.prefixlen);
+               return (-1);
+       }
+
+       if (krm == kr) {
+               /* head element */
+               if (RB_REMOVE(kroute6_tree, &kt->krt6, kr) == NULL) {
+                       log_warnx("%s: failed for %s/%u", __func__,
+                           log_in6addr(&kr->r.prefix), kr->r.prefixlen);
+                       return (-1);
+               }
+               if (kr->next != NULL) {
+                       if (RB_INSERT(kroute6_tree, &kt->krt6, kr->next) !=
+                           NULL) {
+                               log_warnx("%s: failed to add %s/%u", __func__,
+                                   log_in6addr(&kr->r.prefix),
+                                   kr->r.prefixlen);
+                               return (-1);
+                       }
+               }
+       } else {
+               /* somewhere in the list */
+               while (krm->next != kr && krm->next != NULL)
+                       krm = krm->next;
+               if (krm->next == NULL) {
+                       log_warnx("%s: multipath list corrupted for %s/%u",
+                           __func__, log_in6addr(&kr->r.prefix),
+                           kr->r.prefixlen);
+                       return (-1);
+               }
+               krm->next = kr->next;
+       }
+
+       kr_state.ks_nroutes--;
+       free(kr);
+       return (0);
+}
+
+void
+kroute6_clear(struct ktable *kt)
+{
+       struct kroute6_node     *kr;
+
+       while ((kr = RB_MIN(kroute6_tree, &kt->krt6)) != NULL)
+               kroute6_remove(kt, kr);
+}
+
+static inline int
+karp_compare(struct kif_arp *a, struct kif_arp *b)
+{
+       /* Interface indices are assumed equal */
+       if (ntohl(a->addr.sin.sin_addr.s_addr) >
+           ntohl(b->addr.sin.sin_addr.s_addr))
+               return (1);
+       if (ntohl(a->addr.sin.sin_addr.s_addr) <
+           ntohl(b->addr.sin.sin_addr.s_addr))
+               return (-1);
+       return (0);
+}
+
+static inline struct kif_arp *
+karp_search(struct kif_node *kn, struct kif_arp *ka)
+{
+       struct kif_arp          *pivot;
+
+       TAILQ_FOREACH(pivot, &kn->arps, entry) {
+               switch (karp_compare(ka, pivot)) {
+               case 0: /* found */
+                       return (pivot);
+               case -1: /* ka < pivot, end the search */
+                       return (NULL);
+               }
+       }
+       /* looped through the whole list and didn't find */
+       return (NULL);
+}
+
+struct kif_arp *
+karp_find(struct sockaddr *sa, u_short ifindex)
+{
+       struct kif_node         *kn;
+       struct kif_arp          *ka = NULL, s;
+
+       memcpy(&s.addr.sa, sa, sa->sa_len);
+
+       if (ifindex == 0) {
+               /*
+                * We iterate manually to handle zero ifindex special
+                * case differently from kif_find, in particular we
+                * want to look for the address on all available
+                * interfaces.
+                */
+               RB_FOREACH(kn, kif_tree, &kit) {
+                       if ((ka = karp_search(kn, &s)) != NULL)
+                               break;
+               }
+       } else {
+               if ((kn = kif_find(ifindex)) == NULL)
+                       return (NULL);
+               ka = karp_search(kn, &s);
+       }
+       return (ka);
+}
+
+int
+karp_insert(struct kif_node *kn, struct kif_arp *ka)
+{
+       struct kif_arp          *pivot;
+
+       if (ka->if_index == 0)
+               return (-1);
+       if (!kn && (kn = kif_find(ka->if_index)) == NULL)
+               return (-1);
+       /* Put entry on the list in the ascending lexical order */
+       TAILQ_FOREACH(pivot, &kn->arps, entry) {
+               switch (karp_compare(ka, pivot)) {
+               case 0: /* collision */
+                       return (-1);
+               case -1: /* ka < pivot */
+                       TAILQ_INSERT_BEFORE(pivot, ka, entry);
+                       return (0);
+               }
+       }
+       /* ka is larger than any other element on the list */
+       TAILQ_INSERT_TAIL(&kn->arps, ka, entry);
+       return (0);
+}
+
+int
+karp_remove(struct kif_node *kn, struct kif_arp *ka)
+{
+       if (ka->if_index == 0)
+               return (-1);
+       if (!kn && (kn = kif_find(ka->if_index)) == NULL)
+               return (-1);
+       TAILQ_REMOVE(&kn->arps, ka, entry);
+       free(ka);
+       return (0);
+}
+
+struct kif_arp *
+karp_first(u_short ifindex)
+{
+       struct kif_node         *kn;
+
+       if ((kn = kif_find(ifindex)) == NULL)
+               return (NULL);
+       return (TAILQ_FIRST(&kn->arps));
+}
+
+struct kif_arp *
+karp_getaddr(struct sockaddr *sa, u_short ifindex, int next)
+{
+       struct kif_arp          *ka;
+
+       if ((ka = karp_find(sa, ifindex)) == NULL)
+               return (NULL);
+       return (next ? TAILQ_NEXT(ka, entry) : ka);
+}
+
+struct kif_node *
+kif_find(u_short if_index)
+{
+       struct kif_node s;
+
+       if (if_index == 0)
+               return (RB_MIN(kif_tree, &kit));
+
+       bzero(&s, sizeof(s));
+       s.k.if_index = if_index;
+
+       return (RB_FIND(kif_tree, &kit, &s));
+}
+
+struct kif *
+kr_getif(u_short if_index)
+{
+       struct kif_node *kn;
+
+       kn = kif_find(if_index);
+       if (kn == NULL)
+               return (NULL);
+
+       return (&kn->k);
+}
+
+struct kif *
+kr_getnextif(u_short if_index)
+{
+       struct kif_node *kn;
+
+       if ((kn = kif_find(if_index)) == NULL)
+               return (NULL);
+       if (if_index)
+               kn = RB_NEXT(kif_tree, &kit, kn);
+       if (kn == NULL)
+               return (NULL);
+
+       return (&kn->k);
+}
+
+struct kif_node *
+kif_insert(u_short if_index)
+{
+       struct kif_node *kif;
+
+       if ((kif = calloc(1, sizeof(struct kif_node))) == NULL)
+               return (NULL);
+
+       kif->k.if_index = if_index;
+       TAILQ_INIT(&kif->addrs);
+       TAILQ_INIT(&kif->arps);
+
+       if (RB_INSERT(kif_tree, &kit, kif) != NULL)
+               fatalx("kif_insert: RB_INSERT");
+
+       kr_state.ks_nkif++;
+       kr_state.ks_iflastchange = smi_getticks();
+
+       return (kif);
+}
+
+int
+kif_remove(struct kif_node *kif)
+{
+       struct kif_addr *ka;
+       struct kif_arp  *kr;
+
+       if (RB_REMOVE(kif_tree, &kit, kif) == NULL) {
+               log_warnx("%s: RB_REMOVE failed", __func__);
+               return (-1);
+       }
+
+       while ((ka = TAILQ_FIRST(&kif->addrs)) != NULL) {
+               TAILQ_REMOVE(&kif->addrs, ka, entry);
+               ka_remove(ka);
+       }
+       while ((kr = TAILQ_FIRST(&kif->arps)) != NULL) {
+               karp_remove(kif, kr);
+       }
+       free(kif);
+
+       kr_state.ks_nkif--;
+       kr_state.ks_iflastchange = smi_getticks();
+
+       return (0);
+}
+
+void
+kif_clear(void)
+{
+       struct kif_node *kif;
+
+       while ((kif = RB_MIN(kif_tree, &kit)) != NULL)
+               kif_remove(kif);
+       kr_state.ks_nkif = 0;
+       kr_state.ks_iflastchange = smi_getticks();
+}
+
+struct kif *
+kif_update(u_short if_index, int flags, struct if_data *ifd,
+    struct sockaddr_dl *sdl)
+{
+       struct kif_node         *kif;
+       struct ether_addr       *ea;
+       struct ifreq             ifr;
+
+       if ((kif = kif_find(if_index)) == NULL)
+               if ((kif = kif_insert(if_index)) == NULL)
+                       return (NULL);
+
+       kif->k.if_flags = flags;
+       bcopy(ifd, &kif->k.if_data, sizeof(struct if_data));
+       kif->k.if_ticks = smi_getticks();
+
+       if (sdl && sdl->sdl_family == AF_LINK) {
+               if (sdl->sdl_nlen >= sizeof(kif->k.if_name))
+                       memcpy(kif->k.if_name, sdl->sdl_data,
+                           sizeof(kif->k.if_name) - 1);
+               else if (sdl->sdl_nlen > 0)
+                       memcpy(kif->k.if_name, sdl->sdl_data,
+                           sdl->sdl_nlen);
+               /* string already terminated via calloc() */
+
+               if ((ea = (struct ether_addr *)LLADDR(sdl)) != NULL)
+                       bcopy(&ea->ether_addr_octet, kif->k.if_lladdr,
+                           ETHER_ADDR_LEN);
+       }
+
+       bzero(&ifr, sizeof(ifr));
+       strlcpy(ifr.ifr_name, kif->k.if_name, sizeof(ifr.ifr_name));
+       ifr.ifr_data = (caddr_t)&kif->k.if_descr;
+       if (ioctl(kr_state.ks_ifd, SIOCGIFDESCR, &ifr) == -1)
+               bzero(&kif->k.if_descr, sizeof(kif->k.if_descr));
+
+       return (&kif->k);
+}
+
+void
+ka_insert(u_short if_index, struct kif_addr *ka)
+{
+       if (ka->addr.sa.sa_len == 0)
+               return;
+
+       ka->if_index = if_index;
+       RB_INSERT(ka_tree, &kat, ka);
+}
+
+struct kif_addr        *
+ka_find(struct sockaddr *sa)
+{
+       struct kif_addr         ka;
+
+       if (sa == NULL)
+               return (RB_MIN(ka_tree, &kat));
+       bzero(&ka.addr, sizeof(ka.addr));
+       bcopy(sa, &ka.addr.sa, sa->sa_len);
+       return (RB_FIND(ka_tree, &kat, &ka));
+}
+
+int
+ka_remove(struct kif_addr *ka)
+{
+       RB_REMOVE(ka_tree, &kat, ka);
+       free(ka);
+       return (0);
+}
+
+struct kif_addr *
+kr_getaddr(struct sockaddr *sa)
+{
+       return (ka_find(sa));
+}
+
+struct kif_addr *
+kr_getnextaddr(struct sockaddr *sa)
+{
+       struct kif_addr ka;
+
+       bzero(&ka.addr, sizeof(ka.addr));
+       bcopy(sa, &ka.addr.sa, sa->sa_len);
+       return RB_NFIND(ka_tree, &kat, &ka);
+}
+
+/* misc */
+u_int8_t
+prefixlen_classful(in_addr_t ina)
+{
+       /* it hurt to write this. */
+
+       if (ina >= 0xf0000000U)         /* class E */
+               return (32);
+       else if (ina >= 0xe0000000U)    /* class D */
+               return (4);
+       else if (ina >= 0xc0000000U)    /* class C */
+               return (24);
+       else if (ina >= 0x80000000U)    /* class B */
+               return (16);
+       else                            /* class A */
+               return (8);
+}
+
+u_int8_t
+mask2prefixlen(in_addr_t ina)
+{
+       if (ina == 0)
+               return (0);
+       else
+               return (33 - ffs(ntohl(ina)));
+}
+
+in_addr_t
+prefixlen2mask(u_int8_t prefixlen)
+{
+       if (prefixlen == 0)
+               return (0);
+
+       return (htonl(0xffffffff << (32 - prefixlen)));
+}
+
+u_int8_t
+mask2prefixlen6(struct sockaddr_in6 *sa_in6)
+{
+       unsigned int     l = 0;
+       u_int8_t        *ap, *ep;
+
+       /*
+        * sin6_len is the size of the sockaddr so substract the offset of
+        * the possibly truncated sin6_addr struct.
+        */
+       ap = (u_int8_t *)&sa_in6->sin6_addr;
+       ep = (u_int8_t *)sa_in6 + sa_in6->sin6_len;
+       for (; ap < ep; ap++) {
+               /* this "beauty" is adopted from sbin/route/show.c ... */
+               switch (*ap) {
+               case 0xff:
+                       l += 8;
+                       break;
+               case 0xfe:
+                       l += 7;
+                       goto done;
+               case 0xfc:
+                       l += 6;
+                       goto done;
+               case 0xf8:
+                       l += 5;
+                       goto done;
+               case 0xf0:
+                       l += 4;
+                       goto done;
+               case 0xe0:
+                       l += 3;
+                       goto done;
+               case 0xc0:
+                       l += 2;
+                       goto done;
+               case 0x80:
+                       l += 1;
+                       goto done;
+               case 0x00:
+                       goto done;
+               default:
+                       fatalx("non contiguous inet6 netmask");
+               }
+       }
+
+done:
+       if (l > sizeof(struct in6_addr) * 8)
+               fatalx("inet6 prefixlen out of bound");
+       return (l);
+}
+
+struct in6_addr *
+prefixlen2mask6(u_int8_t prefixlen)
+{
+       static struct in6_addr  mask;
+       int                     i;
+
+       bzero(&mask, sizeof(mask));
+       for (i = 0; i < prefixlen / 8; i++)
+               mask.s6_addr[i] = 0xff;
+       i = prefixlen % 8;
+       if (i)
+               mask.s6_addr[prefixlen / 8] = 0xff00 >> i;
+
+       return (&mask);
+}
+
+#define ROUNDUP(a) \
+       ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
+
+void
+get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info)
+{
+       int     i;
+
+       for (i = 0; i < RTAX_MAX; i++) {
+               if (addrs & (1 << i)) {
+                       rti_info[i] = sa;
+                       sa = (struct sockaddr *)((char *)(sa) +
+                           ROUNDUP(sa->sa_len));
+               } else
+                       rti_info[i] = NULL;
+
+       }
+}
+
+void
+if_change(u_short if_index, int flags, struct if_data *ifd,
+    struct sockaddr_dl *sdl)
+{
+       if (kif_update(if_index, flags, ifd, sdl) == NULL)
+               log_warn("%s: interface %u update failed", __func__, if_index);
+}
+
+void
+if_newaddr(u_short if_index, struct sockaddr *ifa, struct sockaddr *mask,
+    struct sockaddr *brd)
+{
+       struct kif_node *kif;
+       struct kif_addr *ka;
+
+       if (ifa == NULL)
+               return;
+       if ((kif = kif_find(if_index)) == NULL) {
+               log_warnx("%s: corresponding if %u not found", __func__,
+                   if_index);
+               return;
+       }
+       if ((ka = ka_find(ifa)) == NULL) {
+               if ((ka = calloc(1, sizeof(struct kif_addr))) == NULL)
+                       fatal("if_newaddr");
+               bcopy(ifa, &ka->addr.sa, ifa->sa_len);
+               TAILQ_INSERT_TAIL(&kif->addrs, ka, entry);
+               ka_insert(if_index, ka);
+       }
+
+       if (mask)
+               bcopy(mask, &ka->mask.sa, mask->sa_len);
+       else
+               bzero(&ka->mask, sizeof(ka->mask));
+       if (brd)
+               bcopy(brd, &ka->dstbrd.sa, brd->sa_len);
+       else
+               bzero(&ka->dstbrd, sizeof(ka->dstbrd));
+}
+
+void
+if_deladdr(u_short if_index, struct sockaddr *ifa, struct sockaddr *mask,
+    struct sockaddr *brd)
+{
+       struct kif_node *kif;
+       struct kif_addr *ka;
+
+       if (ifa == NULL)
+               return;
+       if ((kif = kif_find(if_index)) == NULL) {
+               log_warnx("%s: corresponding if %u not found", __func__,
+                   if_index);
+               return;
+       }
+       if ((ka = ka_find(ifa)) == NULL)
+               return;
+
+       TAILQ_REMOVE(&kif->addrs, ka, entry);
+       ka_remove(ka);
+}
+
+void
+if_announce(void *msg)
+{
+       struct if_announcemsghdr        *ifan;
+       struct kif_node                 *kif;
+
+       ifan = msg;
+
+       switch (ifan->ifan_what) {
+       case IFAN_ARRIVAL:
+               kif = kif_insert(ifan->ifan_index);
+               strlcpy(kif->k.if_name, ifan->ifan_name,
+                   sizeof(kif->k.if_name));
+               break;
+       case IFAN_DEPARTURE:
+               kif = kif_find(ifan->ifan_index);
+               kif_remove(kif);
+               break;
+       }
+}
+
+int
+fetchtable(struct ktable *kt)
+{
+       int                      mib[7];
+       size_t                   len;
+       char                    *buf;
+       int                      rv;
+
+       mib[0] = CTL_NET;
+       mib[1] = PF_ROUTE;
+       mib[2] = 0;
+       mib[3] = AF_INET;
+       mib[4] = NET_RT_DUMP;
+       mib[5] = 0;
+       mib[6] = kt->rtableid;
+
+       if (sysctl(mib, 7, NULL, &len, NULL, 0) == -1) {
+               if (kt->rtableid != 0 && errno == EINVAL)
+                       /* table nonexistent */
+                       return (0);
+               log_warn("%s: failed to fetch routing table %u size", __func__,
+                   kt->rtableid);
+               return (-1);
+       }
+       if (len == 0)
+               return (0);
+       if ((buf = malloc(len)) == NULL) {
+               log_warn("%s: malloc", __func__);
+               return (-1);
+       }
+       if (sysctl(mib, 7, buf, &len, NULL, 0) == -1) {
+               log_warn("%s: failed to fetch routing table %u", __func__,
+                   kt->rtableid);
+               free(buf);
+               return (-1);
+       }
+
+       rv = rtmsg_process(buf, len);
+       free(buf);
+
+       return (rv);
+}
+
+int
+fetchifs(u_short if_index)
+{
+       size_t                   len;
+       int                      mib[6];
+       char                    *buf;
+       int                      rv;
+
+       mib[0] = CTL_NET;
+       mib[1] = PF_ROUTE;
+       mib[2] = 0;
+       mib[3] = 0;     /* wildcard address family */
+       mib[4] = NET_RT_IFLIST;
+       mib[5] = if_index;
+
+       if (sysctl(mib, 6, NULL, &len, NULL, 0) == -1) {
+               log_warn("%s: failed to fetch address table size for %u",
+                   __func__, if_index);
+               return (-1);
+       }
+       if ((buf = malloc(len)) == NULL) {
+               log_warn("%s: malloc", __func__);
+               return (-1);
+       }
+       if (sysctl(mib, 6, buf, &len, NULL, 0) == -1) {
+               log_warn("%s: failed to fetch address table for %u",
+                   __func__, if_index);
+               free(buf);
+               return (-1);
+       }
+
+       rv = rtmsg_process(buf, len);
+       free(buf);
+
+       return (rv);
+}
+
+int
+fetcharp(struct ktable *kt)
+{
+       size_t                   len;
+       int                      mib[7];
+       char                    *buf;
+       int                      rv;
+
+       mib[0] = CTL_NET;
+       mib[1] = PF_ROUTE;
+       mib[2] = 0;
+       mib[3] = AF_INET;
+       mib[4] = NET_RT_FLAGS;
+       mib[5] = RTF_LLINFO;
+       mib[6] = kt->rtableid;
+
+       if (sysctl(mib, 7, NULL, &len, NULL, 0) == -1) {
+               log_warn("%s: failed to fetch arp table %u size", __func__,
+                   kt->rtableid);
+               return (-1);
+       }
+       /* Empty table? */
+       if (len == 0)
+               return (0);
+       if ((buf = malloc(len)) == NULL) {
+               log_warn("%s: malloc", __func__);
+               return (-1);
+       }
+       if (sysctl(mib, 7, buf, &len, NULL, 0) == -1) {
+               log_warn("%s: failed to fetch arp table %u", __func__,
+                   kt->rtableid);
+               free(buf);
+               return (-1);
+       }
+
+       rv = rtmsg_process(buf, len);
+       free(buf);
+
+       return (rv);
+}
+
+/* ARGSUSED */
+void
+dispatch_rtmsg(int fd, short event, void *arg)
+{
+       char                     buf[RT_BUF_SIZE];
+       ssize_t                  n;
+
+       if ((n = read(fd, &buf, sizeof(buf))) == -1) {
+               log_warn("%s: read error", __func__);
+               return;
+       }
+
+       if (n == 0) {
+               log_warnx("%s: routing socket closed", __func__);
+               return;
+       }
+
+       rtmsg_process(buf, n);
+}
+
+int
+rtmsg_process(char *buf, int len)
+{
+       struct ktable           *kt;
+       struct rt_msghdr        *rtm;
+       struct if_msghdr         ifm;
+       struct ifa_msghdr       *ifam;
+       struct sockaddr         *sa, *rti_info[RTAX_MAX];
+       int                      offset;
+       char                    *next;
+
+       for (offset = 0; offset < len; offset += rtm->rtm_msglen) {
+               next = buf + offset;
+               rtm = (struct rt_msghdr *)next;
+               if (rtm->rtm_version != RTM_VERSION)
+                       continue;
+
+               sa = (struct sockaddr *)(next + rtm->rtm_hdrlen);
+               get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
+
+               switch (rtm->rtm_type) {
+               case RTM_ADD:
+               case RTM_GET:
+               case RTM_CHANGE:
+               case RTM_DELETE:
+               case RTM_RESOLVE:
+                       if (rtm->rtm_errno)              /* failed attempts */
+                               continue;
+
+                       if ((kt = ktable_get(rtm->rtm_tableid)) == NULL)
+                               continue;
+
+                       if (dispatch_rtmsg_addr(kt, rtm, rti_info) == -1)
+                               return (-1);
+                       break;
+               case RTM_IFINFO:
+                       memcpy(&ifm, next, sizeof(ifm));
+                       if_change(ifm.ifm_index, ifm.ifm_flags, &ifm.ifm_data,
+                           (struct sockaddr_dl *)rti_info[RTAX_IFP]);
+                       break;
+               case RTM_DELADDR:
+                       ifam = (struct ifa_msghdr *)rtm;
+                       if ((ifam->ifam_addrs & (RTA_NETMASK | RTA_IFA |
+                           RTA_BRD)) == 0)
+                               break;
+
+                       if_deladdr(ifam->ifam_index, rti_info[RTAX_IFA],
+                           rti_info[RTAX_NETMASK], rti_info[RTAX_BRD]);
+                       break;
+               case RTM_NEWADDR:
+                       ifam = (struct ifa_msghdr *)rtm;
+                       if ((ifam->ifam_addrs & (RTA_NETMASK | RTA_IFA |
+                           RTA_BRD)) == 0)
+                               break;
+
+                       if_newaddr(ifam->ifam_index, rti_info[RTAX_IFA],
+                           rti_info[RTAX_NETMASK], rti_info[RTAX_BRD]);
+                       break;
+               case RTM_IFANNOUNCE:
+                       if_announce(next);
+                       break;
+               case RTM_DESYNC:
+                       kr_shutdown();
+                       if (fetchifs(0) == -1)
+                               fatalx("rtmsg_process: fetchifs");
+                       ktable_init();
+                       break;
+               default:
+                       /* ignore for now */
+                       break;
+               }
+       }
+
+       return (offset);
+}
+
+int
+dispatch_rtmsg_addr(struct ktable *kt, struct rt_msghdr *rtm,
+    struct sockaddr *rti_info[RTAX_MAX])
+{
+       struct sockaddr         *sa, *psa;
+       struct sockaddr_in      *sa_in, *psa_in = NULL;
+       struct sockaddr_in6     *sa_in6, *psa_in6 = NULL;
+       struct sockaddr_dl      *sa_dl;
+       struct kroute_node      *kr;
+       struct kroute6_node     *kr6;
+       struct kif_arp          *ka;
+       int                      flags, mpath = 0;
+       u_int16_t                ifindex;
+       u_int8_t                 prefixlen;
+       u_int8_t                 prio;
+
+       flags = 0;
+       ifindex = 0;
+       prefixlen = 0;
+
+       if ((psa = rti_info[RTAX_DST]) == NULL)
+               return (-1);
+
+       if (rtm->rtm_flags & RTF_STATIC)
+               flags |= F_STATIC;
+       if (rtm->rtm_flags & RTF_BLACKHOLE)
+               flags |= F_BLACKHOLE;
+       if (rtm->rtm_flags & RTF_REJECT)
+               flags |= F_REJECT;
+       if (rtm->rtm_flags & RTF_DYNAMIC)
+               flags |= F_DYNAMIC;
+#ifdef RTF_MPATH
+       if (rtm->rtm_flags & RTF_MPATH)
+               mpath = 1;
+#endif
+
+       prio = rtm->rtm_priority;
+       switch (psa->sa_family) {
+       case AF_INET:
+               psa_in = (struct sockaddr_in *)psa;
+               sa_in = (struct sockaddr_in *)rti_info[RTAX_NETMASK];
+               if (sa_in != NULL) {
+                       if (sa_in->sin_len != 0)
+                               prefixlen = mask2prefixlen(
+                                   sa_in->sin_addr.s_addr);
+               } else if (rtm->rtm_flags & RTF_HOST)
+                       prefixlen = 32;
+               else
+                       prefixlen =
+                           prefixlen_classful(psa_in->sin_addr.s_addr);
+               break;
+       case AF_INET6:
+               psa_in6 = (struct sockaddr_in6 *)psa;
+               sa_in6 = (struct sockaddr_in6 *)rti_info[RTAX_NETMASK];
+               if (sa_in6 != NULL) {
+                       if (sa_in6->sin6_len != 0)
+                               prefixlen = mask2prefixlen6(sa_in6);
+               } else if (rtm->rtm_flags & RTF_HOST)
+                       prefixlen = 128;
+               else
+                       fatalx("in6 net addr without netmask");
+               break;
+       default:
+               return (0);
+       }
+
+       if ((sa = rti_info[RTAX_GATEWAY]) != NULL)
+               switch (sa->sa_family) {
+               case AF_INET:
+               case AF_INET6:
+                       if (rtm->rtm_flags & RTF_CONNECTED) {
+                               flags |= F_CONNECTED;
+                               ifindex = rtm->rtm_index;
+                       }
+                       mpath = 0;      /* link local stuff can't be mpath */
+                       break;
+               case AF_LINK:
+                       /*
+                        * Traditional BSD connected routes have
+                        * a gateway of type AF_LINK.
+                        */
+                       flags |= F_CONNECTED;
+                       ifindex = rtm->rtm_index;
+                       mpath = 0;      /* link local stuff can't be mpath */
+                       break;
+               }
+
+       if (rtm->rtm_type == RTM_DELETE) {
+               if (sa != NULL && sa->sa_family == AF_LINK &&
+                   (rtm->rtm_flags & RTF_HOST) &&
+                   psa->sa_family == AF_INET) {
+                       if ((ka = karp_find(psa, ifindex)) == NULL)
+                               return (0);
+                       if (karp_remove(NULL, ka) == -1)
+                               return (-1);
+                       return (0);
+               } else if (sa == NULL && (rtm->rtm_flags & RTF_HOST) &&
+                   psa->sa_family == AF_INET) {
+                       if ((ka = karp_find(psa, ifindex)) != NULL)
+                               karp_remove(NULL, ka);
+                       /* Continue to the route section below  */
+               }
+               switch (psa->sa_family) {
+               case AF_INET:
+                       sa_in = (struct sockaddr_in *)sa;
+                       if ((kr = kroute_find(kt, psa_in->sin_addr.s_addr,
+                           prefixlen, prio)) == NULL)
+                               return (0);
+
+                       if (mpath)
+                               /* get the correct route */
+                               if ((kr = kroute_matchgw(kr, sa_in)) == NULL) {
+                                       log_warnx("%s[delete]: "
+                                           "mpath route not found", __func__);
+                                       return (0);
+                               }
+
+                       if (kroute_remove(kt, kr) == -1)
+                               return (-1);
+                       break;
+               case AF_INET6:
+                       sa_in6 = (struct sockaddr_in6 *)sa;
+                       if ((kr6 = kroute6_find(kt, &psa_in6->sin6_addr,
+                           prefixlen, prio)) == NULL)
+                               return (0);
+
+                       if (mpath)
+                               /* get the correct route */
+                               if ((kr6 = kroute6_matchgw(kr6, sa_in6)) ==
+                                   NULL) {
+                                       log_warnx("%s[delete]: "
+                                           "IPv6 mpath route not found",
+                                           __func__);
+                                       return (0);
+                               }
+
+                       if (kroute6_remove(kt, kr6) == -1)
+                               return (-1);
+                       break;
+               }
+               return (0);
+       }
+
+       if (sa == NULL && !(flags & F_CONNECTED))
+               return (0);
+
+       /* Add or update an ARP entry */
+       if ((rtm->rtm_flags & RTF_LLINFO) && (rtm->rtm_flags & RTF_HOST) &&
+           sa != NULL && sa->sa_family == AF_LINK &&
+           psa->sa_family == AF_INET) {
+               sa_dl = (struct sockaddr_dl *)sa;
+               /* ignore incomplete entries */
+               if (!sa_dl->sdl_alen)
+                       return (0);
+               /* ignore entries that do not specify an interface */
+               if (ifindex == 0)
+                       return (0);
+               if ((ka = karp_find(psa, ifindex)) != NULL) {
+                       memcpy(&ka->target.sdl, sa_dl, sa_dl->sdl_len);
+                       if (rtm->rtm_flags & RTF_PERMANENT_ARP)
+                               flags |= F_STATIC;
+                       ka->flags = flags;
+               } else {
+                       if ((ka = calloc(1, sizeof(struct kif_arp))) == NULL) {
+                               log_warn("%s: calloc", __func__);
+                               return (-1);
+                       }
+                       memcpy(&ka->addr.sa, psa, psa->sa_len);
+                       memcpy(&ka->target.sdl, sa_dl, sa_dl->sdl_len);
+                       if (rtm->rtm_flags & RTF_PERMANENT_ARP)
+                               flags |= F_STATIC;
+                       ka->flags = flags;
+                       ka->if_index = ifindex;
+                       if (karp_insert(NULL, ka)) {
+                               free(ka);
+                               log_warnx("%s: failed to insert", __func__);
+                               return (-1);
+                       }
+               }
+               return (0);
+       }
+
+       switch (psa->sa_family) {
+       case AF_INET:
+               sa_in = (struct sockaddr_in *)sa;
+               if ((kr = kroute_find(kt, psa_in->sin_addr.s_addr, prefixlen,
+                   prio)) != NULL) {
+                       /* get the correct route */
+                       if (mpath && rtm->rtm_type == RTM_CHANGE &&
+                           (kr = kroute_matchgw(kr, sa_in)) == NULL) {
+                               log_warnx("%s[change]: "
+                                   "mpath route not found", __func__);
+                               return (-1);
+                       } else if (mpath && rtm->rtm_type == RTM_ADD)
+                               goto add4;
+
+                       if (sa_in != NULL)
+                               kr->r.nexthop.s_addr =
+                                   sa_in->sin_addr.s_addr;
+                       else
+                               kr->r.nexthop.s_addr = 0;
+                       kr->r.flags = flags;
+                       kr->r.if_index = ifindex;
+                       kr->r.ticks = smi_getticks();
+               } else {
+add4:
+                       if ((kr = calloc(1,
+                           sizeof(struct kroute_node))) == NULL) {
+                               log_warn("%s: calloc", __func__);
+                               return (-1);
+                       }
+                       kr->r.prefix.s_addr = psa_in->sin_addr.s_addr;
+                       kr->r.prefixlen = prefixlen;
+                       if (sa_in != NULL)
+                               kr->r.nexthop.s_addr = sa_in->sin_addr.s_addr;
+                       else
+                               kr->r.nexthop.s_addr = 0;
+                       kr->r.flags = flags;
+                       kr->r.if_index = ifindex;
+                       kr->r.ticks = smi_getticks();
+                       kr->r.priority = prio;
+
+                       kroute_insert(kt, kr);
+               }
+               break;
+       case AF_INET6:
+               sa_in6 = (struct sockaddr_in6 *)sa;
+               if ((kr6 = kroute6_find(kt, &psa_in6->sin6_addr, prefixlen,
+                   prio)) != NULL) {
+                       /* get the correct route */
+                       if (mpath && rtm->rtm_type == RTM_CHANGE &&
+                           (kr6 = kroute6_matchgw(kr6, sa_in6)) ==
+                           NULL) {
+                               log_warnx("%s[change]: "
+                                   "IPv6 mpath route not found", __func__);
+                               return (-1);
+                       } else if (mpath && rtm->rtm_type == RTM_ADD)
+                               goto add6;
+
+                       if (sa_in6 != NULL)
+                               memcpy(&kr6->r.nexthop,
+                                   &sa_in6->sin6_addr,
+                                   sizeof(struct in6_addr));
+                       else
+                               memcpy(&kr6->r.nexthop,
+                                   &in6addr_any,
+                                   sizeof(struct in6_addr));
+
+                       kr6->r.flags = flags;
+                       kr6->r.if_index = ifindex;
+                       kr6->r.ticks = smi_getticks();
+               } else {
+add6:
+                       if ((kr6 = calloc(1,
+                           sizeof(struct kroute6_node))) == NULL) {
+                               log_warn("%s: calloc", __func__);
+                               return (-1);
+                       }
+                       memcpy(&kr6->r.prefix, &psa_in6->sin6_addr,
+                           sizeof(struct in6_addr));
+                       kr6->r.prefixlen = prefixlen;
+                       if (sa_in6 != NULL)
+                               memcpy(&kr6->r.nexthop, &sa_in6->sin6_addr,
+                                   sizeof(struct in6_addr));
+                       else
+                               memcpy(&kr6->r.nexthop, &in6addr_any,
+                                   sizeof(struct in6_addr));
+                       kr6->r.flags = flags;
+                       kr6->r.if_index = ifindex;
+                       kr6->r.ticks = smi_getticks();
+                       kr6->r.priority = prio;
+
+                       kroute6_insert(kt, kr6);
+               }
+               break;
+       }
+
+       return (0);
+}
+
+struct kroute *
+kroute_first(void)
+{
+       struct kroute_node      *kn;
+       struct ktable           *kt;
+
+       if ((kt = ktable_get(0)) == NULL)
+               return (NULL);
+       kn = RB_MIN(kroute_tree, &kt->krt);
+       return (&kn->r);
+}
+
+struct kroute *
+kroute_getaddr(in_addr_t prefix, u_int8_t prefixlen, u_int8_t prio, int next)
+{
+       struct kroute_node      *kn;
+       struct ktable           *kt;
+
+       if ((kt = ktable_get(0)) == NULL)
+               return (NULL);
+       kn = kroute_find(kt, prefix, prefixlen, prio);
+       if (kn != NULL && next)
+               kn = RB_NEXT(kroute_tree, &kt->krt, kn);
+       if (kn != NULL)
+               return (&kn->r);
+       else
+               return (NULL);
+}
diff --git a/libexec/snmpd/snmpd_metrics/log.c b/libexec/snmpd/snmpd_metrics/log.c
new file mode 100644 (file)
index 0000000..3a322bf
--- /dev/null
@@ -0,0 +1,218 @@
+/*     $OpenBSD: log.c,v 1.1.1.1 2022/09/01 14:20:34 martijn Exp $     */
+
+/*
+ * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <syslog.h>
+#include <errno.h>
+#include <time.h>
+
+static int      debug;
+static int      verbose;
+const char     *log_procname;
+
+void   log_init(int, int);
+void   log_procinit(const char *);
+void   log_setverbose(int);
+int    log_getverbose(void);
+void   log_warn(const char *, ...)
+           __attribute__((__format__ (printf, 1, 2)));
+void   log_warnx(const char *, ...)
+           __attribute__((__format__ (printf, 1, 2)));
+void   log_info(const char *, ...)
+           __attribute__((__format__ (printf, 1, 2)));
+void   log_debug(const char *, ...)
+           __attribute__((__format__ (printf, 1, 2)));
+void   logit(int, const char *, ...)
+           __attribute__((__format__ (printf, 2, 3)));
+void   vlog(int, const char *, va_list)
+           __attribute__((__format__ (printf, 2, 0)));
+__dead void fatal(const char *, ...)
+           __attribute__((__format__ (printf, 1, 2)));
+__dead void fatalx(const char *, ...)
+           __attribute__((__format__ (printf, 1, 2)));
+
+void
+log_init(int n_debug, int facility)
+{
+       extern char     *__progname;
+
+       debug = n_debug;
+       verbose = n_debug;
+       log_procinit(__progname);
+
+       if (!debug)
+               openlog(__progname, LOG_PID | LOG_NDELAY, facility);
+
+       tzset();
+}
+
+void
+log_procinit(const char *procname)
+{
+       if (procname != NULL)
+               log_procname = procname;
+}
+
+void
+log_setverbose(int v)
+{
+       verbose = v;
+}
+
+int
+log_getverbose(void)
+{
+       return (verbose);
+}
+
+void
+logit(int pri, const char *fmt, ...)
+{
+       va_list ap;
+
+       va_start(ap, fmt);
+       vlog(pri, fmt, ap);
+       va_end(ap);
+}
+
+void
+vlog(int pri, const char *fmt, va_list ap)
+{
+       char    *nfmt;
+       int      saved_errno = errno;
+
+       if (debug) {
+               /* best effort in out of mem situations */
+               if (asprintf(&nfmt, "%s\n", fmt) == -1) {
+                       vfprintf(stderr, fmt, ap);
+                       fprintf(stderr, "\n");
+               } else {
+                       vfprintf(stderr, nfmt, ap);
+                       free(nfmt);
+               }
+               fflush(stderr);
+       } else
+               vsyslog(pri, fmt, ap);
+
+       errno = saved_errno;
+}
+
+void
+log_warn(const char *emsg, ...)
+{
+       char            *nfmt;
+       va_list          ap;
+       int              saved_errno = errno;
+
+       /* best effort to even work in out of memory situations */
+       if (emsg == NULL)
+               logit(LOG_ERR, "%s", strerror(saved_errno));
+       else {
+               va_start(ap, emsg);
+
+               if (asprintf(&nfmt, "%s: %s", emsg,
+                   strerror(saved_errno)) == -1) {
+                       /* we tried it... */
+                       vlog(LOG_ERR, emsg, ap);
+                       logit(LOG_ERR, "%s", strerror(saved_errno));
+               } else {
+                       vlog(LOG_ERR, nfmt, ap);
+                       free(nfmt);
+               }
+               va_end(ap);
+       }
+
+       errno = saved_errno;
+}
+
+void
+log_warnx(const char *emsg, ...)
+{
+       va_list  ap;
+
+       va_start(ap, emsg);
+       vlog(LOG_ERR, emsg, ap);
+       va_end(ap);
+}
+
+void
+log_info(const char *emsg, ...)
+{
+       va_list  ap;
+
+       va_start(ap, emsg);
+       vlog(LOG_INFO, emsg, ap);
+       va_end(ap);
+}
+
+void
+log_debug(const char *emsg, ...)
+{
+       va_list  ap;
+
+       if (verbose > 1) {
+               va_start(ap, emsg);
+               vlog(LOG_DEBUG, emsg, ap);
+               va_end(ap);
+       }
+}
+
+static void
+vfatalc(int code, const char *emsg, va_list ap)
+{
+       static char     s[BUFSIZ];
+       const char      *sep;
+
+       if (emsg != NULL) {
+               (void)vsnprintf(s, sizeof(s), emsg, ap);
+               sep = ": ";
+       } else {
+               s[0] = '\0';
+               sep = "";
+       }
+       if (code)
+               logit(LOG_CRIT, "%s: %s%s%s",
+                   log_procname, s, sep, strerror(code));
+       else
+               logit(LOG_CRIT, "%s%s%s", log_procname, sep, s);
+}
+
+void
+fatal(const char *emsg, ...)
+{
+       va_list ap;
+
+       va_start(ap, emsg);
+       vfatalc(errno, emsg, ap);
+       va_end(ap);
+       exit(1);
+}
+
+void
+fatalx(const char *emsg, ...)
+{
+       va_list ap;
+
+       va_start(ap, emsg);
+       vfatalc(0, emsg, ap);
+       va_end(ap);
+       exit(1);
+}
diff --git a/libexec/snmpd/snmpd_metrics/log.h b/libexec/snmpd/snmpd_metrics/log.h
new file mode 100644 (file)
index 0000000..a02fe82
--- /dev/null
@@ -0,0 +1,40 @@
+/*     $OpenBSD: log.h,v 1.1.1.1 2022/09/01 14:20:34 martijn Exp $     */
+
+/*
+ * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdarg.h>
+
+void   log_init(int, int);
+void   log_procinit(const char *);
+void   log_setverbose(int);
+int    log_getverbose(void);
+void   log_warn(const char *, ...)
+           __attribute__((__format__ (printf, 1, 2)));
+void   log_warnx(const char *, ...)
+           __attribute__((__format__ (printf, 1, 2)));
+void   log_info(const char *, ...)
+           __attribute__((__format__ (printf, 1, 2)));
+void   log_debug(const char *, ...)
+           __attribute__((__format__ (printf, 1, 2)));
+void   logit(int, const char *, ...)
+           __attribute__((__format__ (printf, 2, 3)));
+void   vlog(int, const char *, va_list)
+           __attribute__((__format__ (printf, 2, 0)));
+__dead void fatal(const char *, ...)
+           __attribute__((__format__ (printf, 1, 2)));
+__dead void fatalx(const char *, ...)
+           __attribute__((__format__ (printf, 1, 2)));
diff --git a/libexec/snmpd/snmpd_metrics/mib.c b/libexec/snmpd/snmpd_metrics/mib.c
new file mode 100644 (file)
index 0000000..eeedb1e
--- /dev/null
@@ -0,0 +1,4367 @@
+/*     $OpenBSD: mib.c,v 1.1.1.1 2022/09/01 14:20:34 martijn Exp $     */
+
+/*
+ * Copyright (c) 2022 Martijn van Duren <martijn@openbsd.org>
+ * Copyright (c) 2012 Joel Knight <joel@openbsd.org>
+ * Copyright (c) 2007, 2008, 2012 Reyk Floeter <reyk@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <sys/signal.h>
+#include <sys/queue.h>
+#include <sys/proc.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/time.h>
+#include <sys/tree.h>
+#include <sys/utsname.h>
+#include <sys/sysctl.h>
+#include <sys/sensors.h>
+#include <sys/sched.h>
+#include <sys/mount.h>
+#include <sys/ioctl.h>
+#include <sys/disk.h>
+
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <netinet/ip_carp.h>
+#include <netinet/ip_var.h>
+#include <arpa/inet.h>
+#include <net/if.h>
+#include <net/if_types.h>
+#include <net/pfvar.h>
+#include <netinet/ip_ipsp.h>
+#include <net/if_pfsync.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <event.h>
+#include <fcntl.h>
+#include <grp.h>
+#include <pwd.h>
+#include <string.h>
+#include <syslog.h>
+#include <time.h>
+#include <unistd.h>
+#include <pwd.h>
+#include <libgen.h>
+#include <limits.h>
+#include <kvm.h>
+
+#include "log.h"
+#include "snmpd.h"
+#include "mib.h"
+
+struct event            connev;
+const char             *agentxsocket = NULL;
+int                     agentxfd = -1;
+
+void            snmp_connect(struct agentx *, void *, int);
+void            snmp_tryconnect(int, short, void *);
+void            snmp_read(int, short, void *);
+
+struct agentx_context *sac;
+struct snmpd *snmpd_env;
+
+/* HOST-RESOURCES-MIB */
+struct agentx_object *hrSystemProcesses, *hrSystemMaxProcesses;
+struct agentx_index *hrStorageIdx;
+struct agentx_object *hrStorageIndex, *hrStorageType, *hrStorageDescr;
+struct agentx_object *hrStorageAllocationUnits, *hrStorageSize, *hrStorageUsed;
+struct agentx_object *hrStorageAllocationFailures;
+struct agentx_index *hrDeviceIdx;
+struct agentx_object *hrDeviceIndex, *hrDeviceType, *hrDeviceDescr, *hrDeviceID;
+struct agentx_object *hrDeviceStatus, *hrDeviceErrors, *hrProcessorFrwID;
+struct agentx_object *hrProcessorLoad;
+struct agentx_index *hrSWRunIdx;
+struct agentx_object *hrSWRunIndex, *hrSWRunName, *hrSWRunID, *hrSWRunPath;
+struct agentx_object *hrSWRunParameters, *hrSWRunType, *hrSWRunStatus;
+
+void    mib_hrsystemuptime(struct agentx_varbind *);
+void    mib_hrsystemdate(struct agentx_varbind *);
+void    mib_hrsystemprocs(struct agentx_varbind *);
+void    mib_hrmemory(struct agentx_varbind *);
+void    mib_hrstorage(struct agentx_varbind *);
+void    mib_hrdevice(struct agentx_varbind *);
+void    mib_hrprocessor(struct agentx_varbind *);
+void    mib_hrswrun(struct agentx_varbind *);
+
+int     kinfo_proc_comp(const void *, const void *);
+int     kinfo_proc(u_int32_t, struct kinfo_proc **);
+void    kinfo_timer_cb(int, short, void *);
+void    kinfo_proc_free(void);
+int     kinfo_args(struct kinfo_proc *, char **);
+
+/* IF-MIB */
+struct agentx_index *ifIdx;
+struct agentx_object *ifName, *ifInMulticastPkts, *ifInBroadcastPkts;
+struct agentx_object *ifOutMulticastPkts, *ifOutBroadcastPkts;
+struct agentx_object *ifOutBroadcastPkts, *ifHCInOctets, *ifHCInUcastPkts;
+struct agentx_object *ifHCInMulticastPkts, *ifHCInBroadcastPkts, *ifHCOutOctets;
+struct agentx_object *ifHCOutUcastPkts, *ifHCOutMulticastPkts;
+struct agentx_object *ifHCOutBroadcastPkts, *ifLinkUpDownTrapEnable;
+struct agentx_object *ifHighSpeed, *ifPromiscuousMode, *ifConnectorPresent;
+struct agentx_object *ifAlias, *ifCounterDiscontinuityTime;
+struct agentx_index *ifRcvAddressAddress;
+struct agentx_object *ifRcvAddressStatus, *ifRcvAddressType;
+struct agentx_object *ifStackLastChange, *ifNumber, *ifIndex, *ifDescr, *ifType;
+struct agentx_object *ifMtu, *ifSpeed, *ifPhysAddress, *ifAdminStatus;
+struct agentx_object *ifOperStatus, *ifLastChange, *ifInOctets, *ifInUcastPkts;
+struct agentx_object *ifInNUcastPkts, *ifInDiscards, *ifInErrors;
+struct agentx_object *ifInUnknownProtos, *ifOutOctets, *ifOutUcastPkts;
+struct agentx_object *ifOutNUcastPkts, *ifOutDiscards, *ifOutErrors, *ifOutQLen;
+struct agentx_object *ifSpecific;
+
+/* OPENBSD-PF-MIB */
+struct agentx_object *pfRunning, *pfRuntime, *pfDebug, *pfHostid;
+struct agentx_object *pfCntMatch, *pfCntBadOffset, *pfCntFragment, *pfCntShort;
+struct agentx_object *pfCntNormalize, *pfCntMemory, *pfCntTimestamp;
+struct agentx_object *pfCntCongestion, *pfCntIpOption, *pfCntProtoCksum;
+struct agentx_object *pfCntStateMismatch, *pfCntStateInsert, *pfCntStateLimit;
+struct agentx_object *pfCntSrcLimit, *pfCntSynproxy, *pfCntTranslate;
+struct agentx_object *pfCntNoRoute;
+struct agentx_object *pfStateCount, *pfStateSearches, *pfStateInserts;
+struct agentx_object *pfStateRemovals;
+struct agentx_object *pfLogIfName, *pfLogIfIpBytesIn, *pfLogIfIpBytesOut;
+struct agentx_object *pfLogIfIpPktsInPass, *pfLogIfIpPktsInDrop;
+struct agentx_object *pfLogIfIpPktsOutPass, *pfLogIfIpPktsOutDrop;
+struct agentx_object *pfLogIfIp6BytesIn, *pfLogIfIp6BytesOut;
+struct agentx_object *pfLogIfIp6PktsInPass, *pfLogIfIp6PktsInDrop;
+struct agentx_object *pfLogIfIp6PktsOutPass, *pfLogIfIp6PktsOutDrop;
+struct agentx_object *pfSrcTrackCount, *pfSrcTrackSearches, *pfSrcTrackInserts;
+struct agentx_object *pfSrcTrackRemovals;
+struct agentx_object *pfLimitStates, *pfLimitSourceNodes, *pfLimitFragments;
+struct agentx_object *pfLimitMaxTables, *pfLimitMaxTableEntries;
+struct agentx_object *pfTimeoutTcpFirst, *pfTimeoutTcpOpening;
+struct agentx_object *pfTimeoutTcpEstablished, *pfTimeoutTcpClosing;
+struct agentx_object *pfTimeoutTcpFinWait, *pfTimeoutTcpClosed;
+struct agentx_object *pfTimeoutUdpFirst, *pfTimeoutUdpSingle;
+struct agentx_object *pfTimeoutUdpMultiple, *pfTimeoutIcmpFirst;
+struct agentx_object *pfTimeoutIcmpError, *pfTimeoutOtherFirst;
+struct agentx_object *pfTimeoutOtherSingle, *pfTimeoutOtherMultiple;
+struct agentx_object *pfTimeoutFragment, *pfTimeoutInterval, *pfTimeoutInterval;
+struct agentx_object *pfTimeoutAdaptiveStart, *pfTimeoutAdaptiveEnd;
+struct agentx_object *pfTimeoutSrcTrack;
+struct agentx_index *pfIfIdx;
+struct agentx_object *pfIfNumber, *pfIfIndex, *pfIfDescr, *pfIfType, *pfIfRefs;
+struct agentx_object *pfIfRules, *pfIfIn4PassPkts, *pfIfIn4PassBytes;
+struct agentx_object *pfIfIn4BlockPkts, *pfIfIn4BlockBytes, *pfIfOut4PassPkts;
+struct agentx_object *pfIfOut4PassBytes, *pfIfOut4BlockPkts;
+struct agentx_object *pfIfOut4BlockBytes, *pfIfIn6PassPkts, *pfIfIn6PassBytes;
+struct agentx_object *pfIfIn6BlockPkts, *pfIfIn6BlockBytes, *pfIfOut6PassPkts;
+struct agentx_object *pfIfOut6PassBytes, *pfIfOut6BlockPkts;
+struct agentx_object *pfIfOut6BlockBytes;
+struct agentx_index *pfTblIdx;
+struct agentx_object *pfTblNumber, *pfTblIndex, *pfTblName, *pfTblAddresses;
+struct agentx_object *pfTblAnchorRefs, *pfTblRuleRefs, *pfTblEvalsMatch;
+struct agentx_object *pfTblEvalsNoMatch, *pfTblInPassPkts, *pfTblInPassBytes;
+struct agentx_object *pfTblInBlockPkts, *pfTblInBlockBytes, *pfTblInXPassPkts;
+struct agentx_object *pfTblInXPassBytes, *pfTblOutPassPkts, *pfTblOutPassBytes;
+struct agentx_object *pfTblOutBlockPkts, *pfTblOutBlockBytes;
+struct agentx_object *pfTblOutXPassPkts, *pfTblOutXPassBytes;
+struct agentx_object *pfTblStatsCleared, *pfTblInMatchPkts, *pfTblInMatchBytes;
+struct agentx_object *pfTblOutMatchPkts, *pfTblOutMatchBytes;
+struct agentx_index *pfTblAddrTblIdx, *pfTblAddrNetIdx, *pfTblAddrMaskIdx;
+struct agentx_object *pfTblAddrTblIndex, *pfTblAddrNet, *pfTblAddrMask;
+struct agentx_object *pfTblAddrCleared, *pfTblAddrInBlockPkts;
+struct agentx_object *pfTblAddrInBlockBytes, *pfTblAddrInPassPkts;
+struct agentx_object *pfTblAddrInPassBytes, *pfTblAddrOutBlockPkts;
+struct agentx_object *pfTblAddrOutBlockBytes, *pfTblAddrOutPassPkts;
+struct agentx_object *pfTblAddrOutPassBytes, *pfTblAddrInMatchPkts;
+struct agentx_object *pfTblAddrInMatchBytes, *pfTblAddrOutMatchPkts;
+struct agentx_object *pfTblAddrOutMatchBytes;
+struct agentx_index *pfLabelIdx;
+struct agentx_object *pfLabelNumber, *pfLabelIndex, *pfLabelName, *pfLabelEvals;
+struct agentx_object *pfLabelPkts, *pfLabelBytes, *pfLabelInPkts;
+struct agentx_object *pfLabelInBytes, *pfLabelOutPkts, *pfLabelOutBytes;
+struct agentx_object *pfLabelTotalStates;
+struct agentx_object *pfsyncIpPktsRecv, *pfsyncIp6PktsRecv;
+struct agentx_object *pfsyncPktDiscardsForBadInterface;
+struct agentx_object *pfsyncPktDiscardsForBadTtl, *pfsyncPktShorterThanHeader;
+struct agentx_object *pfsyncPktDiscardsForBadVersion;
+struct agentx_object *pfsyncPktDiscardsForBadAction;
+struct agentx_object *pfsyncPktDiscardsForBadLength;
+struct agentx_object *pfsyncPktDiscardsForBadAuth;
+struct agentx_object *pfsyncPktDiscardsForStaleState;
+struct agentx_object *pfsyncPktDiscardsForBadValues;
+struct agentx_object *pfsyncPktDiscardsForBadState;
+struct agentx_object *pfsyncIpPktsSent, *pfsyncIp6PktsSent, *pfsyncNoMemory;
+struct agentx_object *pfsyncOutputErrors;
+
+/* OPENBSD-SENSORS-MIB */
+struct agentx_index *sensorIdx;
+struct agentx_object *sensorNumber, *sensorIndex, *sensorDescr, *sensorType;
+struct agentx_object *sensorDevice, *sensorValue, *sensorUnits, *sensorStatus;
+
+/* OPENBSD-CARP-MIB */
+struct agentx_object *carpAllow, *carpPreempt, *carpLog;
+struct agentx_index *carpIfIdx;
+struct agentx_object *carpIfNumber, *carpIfIndex, *carpIfDescr, *carpIfVhid;
+struct agentx_object *carpIfDev, *carpIfAdvbase, *carpIfAdvskew, *carpIfState;
+struct agentx_index *carpGroupIdx;
+struct agentx_object *carpGroupIndex, *carpGroupName, *carpGroupDemote;
+struct agentx_object *carpIpPktsRecv, *carpIp6PktsRecv;
+struct agentx_object *carpPktDiscardsForBadInterface;
+struct agentx_object *carpPktDiscardsForWrongTtl, *carpPktShorterThanHeader;
+struct agentx_object *carpPktDiscardsForBadChecksum;
+struct agentx_object *carpPktDiscardsForBadVersion, *carpPktDiscardsForTooShort;
+struct agentx_object *carpPktDiscardsForBadAuth, *carpPktDiscardsForBadVhid;
+struct agentx_object *carpPktDiscardsForBadAddressList, *carpIpPktsSent;
+struct agentx_object *carpIp6PktsSent, *carpNoMemory, *carpTransitionsToMaster;
+
+/* OPENBSD-MEM-MIB */
+struct agentx_object *memMIBVersion, *memIfName, *memIfLiveLocks;
+
+/* IP-MIB */
+struct agentx_object *ipForwarding, *ipDefaultTTL, *ipInReceives;
+struct agentx_object *ipInHdrErrors, *ipInAddrErrors, *ipForwDatagrams;
+struct agentx_object *ipInUnknownProtos, *ipInDelivers, *ipOutRequests;
+struct agentx_object *ipOutDiscards, *ipOutNoRoutes, *ipReasmTimeout;
+struct agentx_object *ipReasmReqds, *ipReasmOKs, *ipReasmFails, *ipFragOKs;
+struct agentx_object *ipFragFails, *ipFragCreates, *ipAdEntAddr;
+struct agentx_index *ipAdEntAddrIdx;
+struct agentx_object *ipAdEntAddr, *ipAdEntIfIndex, *ipAdEntNetMask;
+struct agentx_object *ipAdEntBcastAddr, *ipAdEntReasmMaxSize;
+struct agentx_index *ipNetToMediaIfIdx, *ipNetToMediaNetAddressIdx;
+struct agentx_object *ipNetToMediaIfIndex, *ipNetToMediaPhysAddress;
+struct agentx_object *ipNetToMediaNetAddress, *ipNetToMediaType;
+
+/* IP-FORWARD-MIB */
+struct agentx_object *inetCidrRouteNumber;
+struct agentx_index *inetCidrRouteDestTypeIdx, *inetCidrRouteDestIdx;
+struct agentx_index *inetCidrRoutePfxLenIdx, *inetCidrRoutePolicyIdx;
+struct agentx_index *inetCidrRouteNextHopTypeIdx, *inetCidrRouteNextHopIdx;
+struct agentx_object *inetCidrRouteIfIndex, *inetCidrRouteType;
+struct agentx_object *inetCidrRouteProto, *inetCidrRouteAge;
+struct agentx_object *inetCidrRouteNextHopAS, *inetCidrRouteMetric1;
+struct agentx_object *inetCidrRouteMetric2, *inetCidrRouteMetric3;
+struct agentx_object *inetCidrRouteMetric4, *inetCidrRouteMetric5;
+struct agentx_object *inetCidrRouteStatus;
+
+/* UCD-DISKIO-MIB */
+struct agentx_index *diskIOIdx;
+struct agentx_object *diskIOIndex, *diskIODevice, *diskIONRead, *diskIONWritten;
+struct agentx_object *diskIOReads, *diskIOWrites, *diskIONReadX;
+struct agentx_object *diskIONWrittenX;
+
+/* BRIDGE-MIB */
+struct agentx_object *dot1dBaseNumPorts, *dot1dBaseType;
+struct agentx_index *dot1dBasePortIdx;
+struct agentx_object *dot1dBasePort, *dot1dBasePortIfIndex;
+struct agentx_object *dot1dBasePortCircuit, *dot1dBasePortDelayExceededDiscards;
+struct agentx_object *dot1dBasePortMtuExceededDiscards;
+
+/* HOST-RESOURCES-MIB */
+void
+mib_hrsystemuptime(struct agentx_varbind *vb)
+{
+       struct timespec  uptime;
+       long long        ticks;
+
+       if (clock_gettime(CLOCK_BOOTTIME, &uptime) == -1) {
+               log_warn("clock_gettime");
+               agentx_varbind_error(vb);
+               return;
+       }
+       ticks = uptime.tv_sec * 100 + uptime.tv_nsec / 10000000;
+       agentx_varbind_timeticks(vb, ticks);
+}
+
+void
+mib_hrsystemdate(struct agentx_varbind *vb)
+{
+       struct tm       *ptm;
+       u_char           s[11];
+       time_t           now;
+       int              tzoffset;
+       unsigned short   year;
+
+       (void)time(&now);
+       ptm = localtime(&now);
+
+       year = htons(ptm->tm_year + 1900);
+       memcpy(s, &year, 2);
+       s[2] = ptm->tm_mon + 1;
+       s[3] = ptm->tm_mday;
+       s[4] = ptm->tm_hour;
+       s[5] = ptm->tm_min;
+       s[6] = ptm->tm_sec;
+       s[7] = 0;
+
+       tzoffset = ptm->tm_gmtoff;
+       if (tzoffset < 0)
+               s[8] = '-';
+       else
+               s[8] = '+';
+
+       s[9] = abs(tzoffset) / 3600;
+       s[10] = (abs(tzoffset) - (s[9] * 3600)) / 60;
+
+       agentx_varbind_nstring(vb, s, sizeof(s));
+}
+
+void
+mib_hrsystemprocs(struct agentx_varbind *vb)
+{
+       struct agentx_object    *obj;
+       char                     errbuf[_POSIX2_LINE_MAX];
+       int                      val;
+       int                      mib[] = { CTL_KERN, KERN_MAXPROC };
+       kvm_t                   *kd;
+       size_t                   len;
+
+       obj = agentx_varbind_get_object(vb);
+       if (obj == hrSystemProcesses) {
+               if ((kd = kvm_openfiles(NULL, NULL, NULL,
+                   KVM_NO_FILES, errbuf)) == NULL) {
+                       log_warn("kvm_openfiles");
+                       agentx_varbind_error(vb);
+                       return;
+               }
+
+               if (kvm_getprocs(kd, KERN_PROC_ALL, 0,
+                   sizeof(struct kinfo_proc), &val) == NULL) {
+                       log_warn("kvm_getprocs");
+                       kvm_close(kd);
+                       agentx_varbind_error(vb);
+                       return;
+               }
+
+               agentx_varbind_gauge32(vb, val);
+
+               kvm_close(kd);
+       } else if (obj == hrSystemMaxProcesses) {
+               len = sizeof(val);
+               if (sysctl(mib, 2, &val, &len, NULL, 0) == -1) {
+                       log_warn("sysctl");
+                       agentx_varbind_error(vb);
+                       return;
+               }
+
+               agentx_varbind_integer(vb, val);
+       } else
+               fatal("%s: Unexpected object", __func__);
+}
+
+void
+mib_hrmemory(struct agentx_varbind *vb)
+{
+       int                      mib[] = { CTL_HW, HW_PHYSMEM64 };
+       u_int64_t                physmem;
+       size_t                   len = sizeof(physmem);
+
+       if (sysctl(mib, nitems(mib), &physmem, &len, NULL, 0) == -1) {
+               log_warn("sysctl");
+               agentx_varbind_error(vb);
+               return;
+       }
+
+       agentx_varbind_integer(vb, physmem / 1024);
+}
+
+void
+mib_hrstorage(struct agentx_varbind *vb)
+{
+       struct agentx_object            *obj;
+       enum agentx_request_type         req;
+       int32_t                          idx;
+       struct statfs                   *mntbuf, *mnt;
+       int                              mntsize, maxsize;
+       uint64_t                         units, size, used, fail = 0;
+       const char                      *descr = NULL;
+       int                              mib[] = { CTL_HW, 0 };
+       u_int64_t                        physmem, realmem;
+       struct uvmexp                    uvm;
+       size_t                           len;
+       uint32_t                         sop[] = { HRSTORAGEOTHER };
+
+       /* Physical memory, real memory, swap */
+       mib[1] = HW_PHYSMEM64;
+       len = sizeof(physmem);
+       if (sysctl(mib, nitems(mib), &physmem, &len, NULL, 0) == -1) {
+               log_warn("sysctl");
+               agentx_varbind_error(vb);
+               return;
+       }
+       mib[1] = HW_USERMEM64;
+       len = sizeof(realmem);
+       if (sysctl(mib, nitems(mib), &realmem, &len, NULL, 0) == -1) {
+               log_warn("sysctl");
+               agentx_varbind_error(vb);
+               return;
+       }
+       mib[0] = CTL_VM;
+       mib[1] = VM_UVMEXP;
+       len = sizeof(uvm);
+       if (sysctl(mib, nitems(mib), &uvm, &len, NULL, 0) == -1) {
+               log_warn("sysctl");
+               agentx_varbind_error(vb);
+               return;
+       }
+       maxsize = 10;
+
+       /* Disks */
+       if ((mntsize = getmntinfo(&mntbuf, MNT_NOWAIT)) == 0) {
+               log_warn("getmntinfo");
+               agentx_varbind_error(vb);
+               return;
+       }
+       maxsize = 30 + mntsize;
+
+       /*
+        * Get and verify the current row index.
+        *
+        * We use a special mapping here that is inspired by other SNMP
+        * agents: index 1 + 2 for RAM, index 10 for swap, index 31 and
+        * higher for disk storage.
+        */
+       obj = agentx_varbind_get_object(vb);
+       req = agentx_varbind_request(vb);
+       idx = agentx_varbind_get_index_integer(vb, hrStorageIdx);
+       if (req == AGENTX_REQUEST_TYPE_GETNEXT) {
+               if (idx == INT32_MAX) {
+                       agentx_varbind_notfound(vb);
+                       return;
+               }
+               idx++;
+       }
+       if (idx > maxsize) {
+               agentx_varbind_notfound(vb);
+               return;
+       }
+       if (req == AGENTX_REQUEST_TYPE_GET) {
+               if (idx < 1 || (idx > 2 && idx < 10) ||
+                   (idx > 10 && idx < 31)) {
+                       agentx_varbind_notfound(vb);
+                       return;
+               }
+       } else {
+               if (idx < 1)
+                       idx = 1;
+               else if (idx > 2 && idx < 10)
+                       idx = 10;
+               else if (idx > 10 && idx < 31)
+                       idx = 31;
+       }
+
+       switch (idx) {
+       case 1:
+               descr = "Physical memory";
+               units = uvm.pagesize;
+               size = physmem / uvm.pagesize;
+               used = size - uvm.free;
+               memcpy(sop, (uint32_t[]){ HRSTORAGERAM }, sizeof(sop));
+               break;
+       case 2:
+               descr = "Real memory";
+               units = uvm.pagesize;
+               size = realmem / uvm.pagesize;
+               used = size - uvm.free;
+               memcpy(sop, (uint32_t[]){ HRSTORAGERAM }, sizeof(sop));
+               break;
+       case 10:
+               descr = "Swap space";
+               units = uvm.pagesize;
+               size = uvm.swpages;
+               used = uvm.swpginuse;
+               memcpy(sop, (uint32_t[]){ HRSTORAGEVIRTUALMEMORY },
+                   sizeof(sop));
+               break;
+       default:
+               mnt = &mntbuf[idx - 31];
+               descr = mnt->f_mntonname;
+               units = mnt->f_bsize;
+               size = mnt->f_blocks;
+               used = mnt->f_blocks - mnt->f_bfree;
+               memcpy(sop, (uint32_t[]){ HRSTORAGEFIXEDDISK }, sizeof(sop));
+               break;
+       }
+
+       while (size > INT32_MAX) {
+               units *= 2;
+               size /= 2;
+               used /= 2;
+       }
+
+       agentx_varbind_set_index_integer(vb, hrStorageIdx, idx);
+
+       if (obj == hrStorageIndex)
+               agentx_varbind_integer(vb, idx);
+       else if (obj == hrStorageType)
+               agentx_varbind_oid(vb, sop, nitems(sop));
+       else if (obj == hrStorageDescr)
+               agentx_varbind_string(vb, descr);
+       else if (obj == hrStorageAllocationUnits)
+               agentx_varbind_integer(vb, units);
+       else if (obj == hrStorageSize)
+               agentx_varbind_integer(vb, size);
+       else if (obj == hrStorageUsed)
+               agentx_varbind_integer(vb, used);
+       else if (obj == hrStorageAllocationFailures)
+               agentx_varbind_counter32(vb, fail);
+       else
+               fatal("%s: Unexpected object", __func__);
+}
+
+void
+mib_hrdevice(struct agentx_varbind *vb)
+{
+       struct agentx_object            *obj;
+       enum agentx_request_type         req;
+       int32_t                          idx;
+       uint32_t                         fail = 0;
+       int                              status;
+       int                              mib[] = { CTL_HW, HW_MODEL };
+       size_t                           len;
+       char                             descr[BUFSIZ];
+       uint32_t                         sop[] = { HRDEVICEPROCESSOR };
+
+       /* Get and verify the current row index */
+       obj = agentx_varbind_get_object(vb);
+       idx = agentx_varbind_get_index_integer(vb, hrDeviceIdx);
+       req = agentx_varbind_request(vb);
+       if (req == AGENTX_REQUEST_TYPE_GETNEXT) {
+               if (idx == INT32_MAX) {
+                       agentx_varbind_notfound(vb);
+                       return;
+               }
+               idx++;
+               if (idx < 1)
+                       idx = 1;
+       } else if (req == AGENTX_REQUEST_TYPE_GETNEXTINCLUSIVE) {
+               if (idx < 1)
+                       idx = 1;
+       }
+       if (idx < 1 || idx > snmpd_env->sc_ncpu) {
+               agentx_varbind_notfound(vb);
+               return;
+       }
+
+       agentx_varbind_set_index_integer(vb, hrDeviceIdx, idx);
+
+       len = sizeof(descr);
+       if (sysctl(mib, nitems(mib), &descr, &len, NULL, 0) == -1) {
+               log_warn("sysctl");
+               agentx_varbind_error(vb);
+               return;
+       }
+       /* unknown(1), running(2), warning(3), testing(4), down(5) */
+       status = 2;
+
+       if (obj == hrDeviceIndex)
+               agentx_varbind_integer(vb, idx);
+       else if (obj == hrDeviceType)
+               agentx_varbind_oid(vb, sop, nitems(sop));
+       else if (obj == hrDeviceDescr)
+               agentx_varbind_string(vb, descr);
+       else if (obj == hrDeviceID)
+               agentx_varbind_oid(vb, AGENTX_OID(0, 0));
+       else if (obj == hrDeviceStatus)
+               agentx_varbind_integer(vb, status);
+       else if (obj == hrDeviceErrors)
+               agentx_varbind_counter32(vb, fail);
+       else
+               fatal("%s: Unexpected object", __func__);
+}
+
+void
+mib_hrprocessor(struct agentx_varbind *vb)
+{
+       struct agentx_object            *obj;
+       enum agentx_request_type         req;
+       int32_t                          idx;
+       int64_t                         *cptime2, val;
+
+       obj = agentx_varbind_get_object(vb);
+       idx = agentx_varbind_get_index_integer(vb, hrDeviceIdx);
+       req = agentx_varbind_request(vb);
+       if (req == AGENTX_REQUEST_TYPE_GETNEXT) {
+               if (idx == INT32_MAX) {
+                       agentx_varbind_notfound(vb);
+                       return;
+               }
+               idx++;
+               if (idx < 1)
+                       idx = 1;
+       }
+       else if (req == AGENTX_REQUEST_TYPE_GETNEXTINCLUSIVE) {
+               if (idx < 1)
+                       idx = 1;
+       }
+       if (idx < 1 || idx > snmpd_env->sc_ncpu) {
+               agentx_varbind_notfound(vb);
+               return;
+       }
+
+       agentx_varbind_set_index_integer(vb, hrDeviceIdx, idx);
+
+       if (obj == hrProcessorFrwID)
+               agentx_varbind_oid(vb, AGENTX_OID(0, 0));
+       else if (obj == hrProcessorLoad) {
+               /*
+                * The percentage of time that the system was not
+                * idle during the last minute.
+                */
+               if (snmpd_env->sc_cpustates == NULL) {
+                       log_warnx("cpustates not initialized");
+                       agentx_varbind_error(vb);
+                       return;
+               }
+               cptime2 = snmpd_env->sc_cpustates + (CPUSTATES * (idx - 1));
+               val = 100 -
+                   (cptime2[CP_IDLE] > 1000 ? 1000 : (cptime2[CP_IDLE] / 10));
+               agentx_varbind_integer(vb, val);
+       } else
+               fatal("%s: Unexpected object", __func__);
+}
+
+void
+mib_hrswrun(struct agentx_varbind *vb)
+{
+       struct agentx_object            *obj;
+       enum agentx_request_type         req;
+       int32_t                          idx;
+       struct kinfo_proc               *kinfo;
+       char                            *s;
+
+       obj = agentx_varbind_get_object(vb);
+       idx = agentx_varbind_get_index_integer(vb, hrSWRunIdx);
+       req = agentx_varbind_request(vb);
+
+       if (req == AGENTX_REQUEST_TYPE_GETNEXT) {
+               if (idx == INT32_MAX) {
+                       agentx_varbind_notfound(vb);
+                       return;
+               }
+               idx++;
+       }
+       /* Get and verify the current row index */
+       if (kinfo_proc(idx, &kinfo) == -1) {
+               log_warn("kinfo_proc");
+               agentx_varbind_error(vb);
+               return;
+       }
+
+       if (kinfo == NULL) {
+               agentx_varbind_notfound(vb);
+               return;
+       }
+       if (req == AGENTX_REQUEST_TYPE_GET) {
+               if (kinfo->p_pid != idx) {
+                       agentx_varbind_notfound(vb);
+                       return;
+               }
+       }
+       agentx_varbind_set_index_integer(vb, hrSWRunIdx, kinfo->p_pid);
+
+       if (obj == hrSWRunIndex)
+               agentx_varbind_integer(vb, kinfo->p_pid);
+       else if (obj == hrSWRunName || obj == hrSWRunPath)
+               agentx_varbind_string(vb, kinfo->p_comm);
+       else if (obj == hrSWRunID)
+               agentx_varbind_oid(vb, AGENTX_OID(0, 0));
+       else if (obj == hrSWRunParameters) {
+               if (kinfo_args(kinfo, &s) == -1) {
+                       log_warn("kinfo_args");
+                       agentx_varbind_error(vb);
+                       return;
+               }
+
+               agentx_varbind_string(vb, s);
+       } else if (obj == hrSWRunType) {
+               if (kinfo->p_flag & P_SYSTEM) {
+                       /* operatingSystem(2) */
+                       agentx_varbind_integer(vb, 2);
+               } else {
+                       /* application(4) */
+                       agentx_varbind_integer(vb, 4);
+               }
+       } else if (obj == hrSWRunStatus) {
+               switch (kinfo->p_stat) {
+               case SONPROC:
+                       /* running(1) */
+                       agentx_varbind_integer(vb, 1);
+                       break;
+               case SIDL:
+               case SRUN:
+               case SSLEEP:
+                       /* runnable(2) */
+                       agentx_varbind_integer(vb, 2);
+                       break;
+               case SSTOP:
+                       /* notRunnable(3) */
+                       agentx_varbind_integer(vb, 3);
+                       break;
+               case SDEAD:
+               default:
+                       /* invalid(4) */
+                       agentx_varbind_integer(vb, 4);
+                       break;
+               }
+       } else
+               fatal("%s: Unexpected object", __func__);
+}
+
+int
+kinfo_proc_comp(const void *a, const void *b)
+{
+       struct kinfo_proc * const *k1 = a;
+       struct kinfo_proc * const *k2 = b;
+
+       return (((*k1)->p_pid > (*k2)->p_pid) ? 1 : -1);
+}
+
+static struct event      kinfo_timer;
+static struct kinfo_proc *kp = NULL;
+static struct kinfo_proc **klist = NULL;
+static size_t            nkp = 0, nklist = 0;
+
+int
+kinfo_proc(u_int32_t idx, struct kinfo_proc **kinfo)
+{
+       int              mib[] = { CTL_KERN, KERN_PROC,
+                           KERN_PROC_ALL, 0, sizeof(*kp), 0 };
+       size_t           size, count, i;
+       struct timeval   timer;
+
+       if (kp != NULL && klist != NULL)
+               goto cached;
+
+       kinfo_proc_free();
+       for (;;) {
+               size = nkp * sizeof(*kp);
+               mib[5] = nkp;
+               if (sysctl(mib, nitems(mib), kp, &size, NULL, 0) == -1) {
+                       if (errno == ENOMEM) {
+                               kinfo_proc_free();
+                               continue;
+                       }
+
+                       return (-1);
+               }
+
+               count = size / sizeof(*kp);
+               if (count <= nkp)
+                       break;
+
+               kp = malloc(size);
+               if (kp == NULL) {
+                       kinfo_proc_free();
+                       return (-1);
+               }
+               nkp = count;
+       }
+
+       klist = calloc(count, sizeof(*klist));
+       if (klist == NULL) {
+               kinfo_proc_free();
+               return (-1);
+       }
+       nklist = count;
+
+       for (i = 0; i < nklist; i++)
+               klist[i] = &kp[i];
+       qsort(klist, nklist, sizeof(*klist), kinfo_proc_comp);
+
+       evtimer_set(&kinfo_timer, kinfo_timer_cb, NULL);
+       timer.tv_sec = 5;
+       timer.tv_usec = 0;
+       evtimer_add(&kinfo_timer, &timer);
+
+cached:
+       *kinfo = NULL;
+       for (i = 0; i < nklist; i++) {
+               if (klist[i]->p_pid >= (int32_t)idx) {
+                       *kinfo = klist[i];
+                       break;
+               }
+       }
+
+       return (0);
+}
+
+void
+kinfo_timer_cb(int fd, short event, void *arg)
+{
+       kinfo_proc_free();
+}
+
+void
+kinfo_proc_free(void)
+{
+       free(kp);
+       kp = NULL;
+       nkp = 0;
+       free(klist);
+       klist = NULL;
+       nklist = 0;
+}
+
+int
+kinfo_args(struct kinfo_proc *kinfo, char **s)
+{
+       static char              str[128];
+       static char             *buf = NULL;
+       static size_t            buflen = 128;
+
+       int                      mib[] = { CTL_KERN, KERN_PROC_ARGS,
+                                   kinfo->p_pid, KERN_PROC_ARGV };
+       char                    *nbuf, **argv;
+
+       if (buf == NULL) {
+               buf = malloc(buflen);
+               if (buf == NULL)
+                       return (-1);
+       }
+
+       str[0] = '\0';
+       *s = str;
+
+       while (sysctl(mib, nitems(mib), buf, &buflen, NULL, 0) == -1) {
+               if (errno != ENOMEM) {
+                       /* some errors are expected, dont get too upset */
+                       return (0);
+               }
+
+               nbuf = realloc(buf, buflen + 128);
+               if (nbuf == NULL)
+                       return (-1);
+
+               buf = nbuf;
+               buflen += 128;
+       }
+
+       argv = (char **)buf;
+       if (argv[0] == NULL)
+               return (0);
+
+       argv++;
+       while (*argv != NULL) {
+               strlcat(str, *argv, sizeof(str));
+               argv++;
+               if (*argv != NULL)
+                       strlcat(str, " ", sizeof(str));
+       }
+
+       return (0);
+}
+
+/*
+ * Defined in IF-MIB.txt (RFCs 1229, 1573, 2233, 2863)
+ */
+
+void    mib_ifnumber(struct agentx_varbind *);
+struct kif
+       *mib_ifget(u_int);
+void    mib_iftable(struct agentx_varbind *);
+void    mib_ifxtable(struct agentx_varbind *);
+void    mib_ifstacklast(struct agentx_varbind *);
+void    mib_ifrcvtable(struct agentx_varbind *);
+
+static uint8_t ether_zeroaddr[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+void
+mib_ifnumber(struct agentx_varbind *vb)
+{
+       agentx_varbind_integer(vb, kr_ifnumber());
+}
+
+struct kif *
+mib_ifget(u_int idx)
+{
+       struct kif      *kif;
+
+       if ((kif = kr_getif(idx)) == NULL) {
+               /*
+                * It may happen that an interface with a specific index
+                * does not exist or has been removed. Jump to the next
+                * available interface index.
+                */
+               for (kif = kr_getif(0); kif != NULL;
+                   kif = kr_getnextif(kif->if_index))
+                       if (kif->if_index > idx)
+                               break;
+               if (kif == NULL)
+                       return (NULL);
+       }
+       idx = kif->if_index;
+
+       /* Update interface information */
+       kr_updateif(idx);
+       if ((kif = kr_getif(idx)) == NULL) {
+               log_debug("mib_ifxtable: interface %d disappeared?", idx);
+               return (NULL);
+       }
+
+       return (kif);
+}
+
+void
+mib_iftable(struct agentx_varbind *vb)
+{
+       struct agentx_object            *obj;
+       enum agentx_request_type         req;
+       int32_t                          idx = 0;
+       struct kif                      *kif;
+       long long                        i;
+
+       obj = agentx_varbind_get_object(vb);
+       idx = agentx_varbind_get_index_integer(vb, ifIdx);
+       req = agentx_varbind_request(vb);
+       if (req == AGENTX_REQUEST_TYPE_GETNEXT) {
+               if (idx == INT32_MAX) {
+                       agentx_varbind_notfound(vb);
+                       return;
+               }
+               idx++;
+       }
+       if ((kif = mib_ifget(idx)) == NULL) {
+               agentx_varbind_notfound(vb);
+               return;
+       }
+       if (req == AGENTX_REQUEST_TYPE_GET) {
+               if (idx != kif->if_index) {
+                       agentx_varbind_notfound(vb);
+                       return;
+               }
+       }
+       agentx_varbind_set_index_integer(vb, ifIdx, kif->if_index);
+
+       if (obj == ifIndex)
+               agentx_varbind_integer(vb, kif->if_index);
+       else if (obj == ifDescr) {
+               /*
+                * The ifDescr should contain a vendor, product, etc.
+                * but we just use the interface name (like ifName).
+                * The interface name includes the driver name on OpenBSD.
+                */
+               agentx_varbind_string(vb, kif->if_name);
+       } else if (obj == ifType) {
+               if (kif->if_type >= 0xf0) {
+                       /*
+                        * It does not make sense to announce the private
+                        * interface types for CARP, ENC, PFSYNC, etc.
+                        */
+                       agentx_varbind_integer(vb, IFT_OTHER);
+               } else
+                       agentx_varbind_integer(vb, kif->if_type);
+       } else if (obj == ifMtu)
+               agentx_varbind_integer(vb, kif->if_mtu);
+       else if (obj == ifSpeed) {
+               if (kif->if_baudrate > UINT32_MAX) {
+                       /* speed should be obtained from ifHighSpeed instead */
+                       agentx_varbind_gauge32(vb, UINT32_MAX);
+               } else
+                       agentx_varbind_gauge32(vb, kif->if_baudrate);
+       } else if (obj == ifPhysAddress) {
+               if (bcmp(kif->if_lladdr, ether_zeroaddr,
+                   sizeof(kif->if_lladdr)) == 0) {
+                       agentx_varbind_string(vb, "");
+               } else {
+                       agentx_varbind_nstring(vb, kif->if_lladdr,
+                           sizeof(kif->if_lladdr));
+               }
+       } else if (obj == ifAdminStatus) {
+               /* ifAdminStatus up(1), down(2), testing(3) */
+               i = (kif->if_flags & IFF_UP) ? 1 : 2;
+               agentx_varbind_integer(vb, i);
+       } else if (obj == ifOperStatus) {
+               if ((kif->if_flags & IFF_UP) == 0)
+                       i = 2;  /* down(2) */
+               else if (kif->if_link_state == LINK_STATE_UNKNOWN)
+                       i = 4;  /* unknown(4) */
+               else if (LINK_STATE_IS_UP(kif->if_link_state))
+                       i = 1;  /* up(1) */
+               else
+                       i = 7;  /* lowerLayerDown(7) or dormant(5)? */
+               agentx_varbind_integer(vb, i);
+       } else if (obj == ifLastChange)
+               agentx_varbind_timeticks(vb, kif->if_ticks);
+       else if (obj == ifInOctets)
+               agentx_varbind_counter32(vb, (uint32_t)kif->if_ibytes);
+       else if (obj == ifInUcastPkts)
+               agentx_varbind_counter32(vb, (uint32_t)kif->if_ipackets);
+       else if (obj == ifInNUcastPkts)
+               agentx_varbind_counter32(vb, (uint32_t)kif->if_imcasts);
+       else if (obj == ifInDiscards)
+               agentx_varbind_counter32(vb, (uint32_t)kif->if_iqdrops);
+       else if (obj == ifInErrors)
+               agentx_varbind_counter32(vb, (uint32_t)kif->if_ierrors);
+       else if (obj == ifInUnknownProtos)
+               agentx_varbind_counter32(vb, (uint32_t)kif->if_noproto);
+       else if (obj == ifOutOctets)
+               agentx_varbind_counter32(vb, (uint32_t)kif->if_obytes);
+       else if (obj == ifOutUcastPkts)
+               agentx_varbind_counter32(vb, (uint32_t)kif->if_opackets);
+       else if (obj == ifOutNUcastPkts)
+               agentx_varbind_counter32(vb, (uint32_t)kif->if_omcasts);
+       else if (obj == ifOutDiscards)
+               agentx_varbind_counter32(vb, (uint32_t)kif->if_oqdrops);
+       else if (obj == ifOutErrors)
+               agentx_varbind_counter32(vb, (uint32_t)kif->if_oerrors);
+       else if (obj == ifOutQLen)
+               agentx_varbind_gauge32(vb, 0);
+       else if (obj == ifSpecific)
+               agentx_varbind_oid(vb, AGENTX_OID(0, 0));
+       else
+               fatal("%s: Unexpected object", __func__);
+}
+
+void
+mib_ifxtable(struct agentx_varbind *vb)
+{
+       struct agentx_object            *obj;
+       enum agentx_request_type         req;
+       int32_t                          idx = 0;
+       struct kif                      *kif;
+       int                              i = 0;
+
+       obj = agentx_varbind_get_object(vb);
+       idx = agentx_varbind_get_index_integer(vb, ifIdx);
+       req = agentx_varbind_request(vb);
+       if (req == AGENTX_REQUEST_TYPE_GETNEXT) {
+               if (idx == INT32_MAX) {
+                       agentx_varbind_notfound(vb);
+                       return;
+               }
+               idx++;
+       }
+       if ((kif = mib_ifget(idx)) == NULL) {
+               agentx_varbind_notfound(vb);
+               return;
+       }
+       if (req == AGENTX_REQUEST_TYPE_GET) {
+               if (idx != kif->if_index) {
+                       agentx_varbind_notfound(vb);
+                       return;
+               }
+       }
+       agentx_varbind_set_index_integer(vb, ifIdx, kif->if_index);
+
+       if (obj == ifName)
+               agentx_varbind_string(vb, kif->if_name);
+       else if (obj == ifInMulticastPkts)
+               agentx_varbind_counter32(vb, (uint32_t)kif->if_imcasts);
+       else if (obj == ifInBroadcastPkts)
+               agentx_varbind_counter32(vb, 0);
+       else if (obj == ifOutMulticastPkts)
+               agentx_varbind_counter32(vb, (uint32_t)kif->if_omcasts);
+       else if (obj == ifOutBroadcastPkts)
+               agentx_varbind_counter32(vb, 0);
+       else if (obj == ifHCInOctets)
+               agentx_varbind_counter64(vb, (uint64_t)kif->if_ibytes);
+       else if (obj == ifHCInUcastPkts)
+               agentx_varbind_counter64(vb, (uint64_t)kif->if_ipackets);
+       else if (obj == ifHCInMulticastPkts)
+               agentx_varbind_counter64(vb, (uint64_t)kif->if_imcasts);
+       else if (obj == ifHCInBroadcastPkts)
+               agentx_varbind_counter64(vb, 0);
+       else if (obj == ifHCOutOctets)
+               agentx_varbind_counter64(vb, (uint64_t)kif->if_obytes);
+       else if (obj == ifHCOutUcastPkts)
+               agentx_varbind_counter64(vb, (uint64_t)kif->if_opackets);
+       else if (obj == ifHCOutMulticastPkts)
+               agentx_varbind_counter64(vb, (uint64_t)kif->if_omcasts);
+       else if (obj == ifHCOutBroadcastPkts)
+               agentx_varbind_counter64(vb, 0);
+       else if (obj == ifLinkUpDownTrapEnable)
+               agentx_varbind_integer(vb, 0);  /* enabled(1), disabled(2) */
+       else if (obj == ifHighSpeed) {
+               i = kif->if_baudrate >= 1000000 ?
+                   kif->if_baudrate / 1000000 : 0;
+               agentx_varbind_gauge32(vb, i);
+       } else if (obj == ifPromiscuousMode) {
+               /* ifPromiscuousMode: true(1), false(2) */
+               i = kif->if_flags & IFF_PROMISC ? 1 : 2;
+               agentx_varbind_integer(vb, i);
+       } else if (obj == ifConnectorPresent) {
+               /* ifConnectorPresent: false(2), true(1) */
+               i = kif->if_type == IFT_ETHER ? 1 : 2;
+               agentx_varbind_integer(vb, i);
+       } else if (obj == ifAlias)
+               agentx_varbind_string(vb, kif->if_descr);
+       else if (obj == ifCounterDiscontinuityTime)
+               agentx_varbind_timeticks(vb, 0);
+       else
+               fatal("%s: Unexpected object", __func__);
+}
+
+void
+mib_ifstacklast(struct agentx_varbind *vb)
+{
+       agentx_varbind_timeticks(vb, kr_iflastchange());
+}
+
+void
+mib_ifrcvtable(struct agentx_varbind *vb)
+{
+       struct agentx_object            *obj;
+       enum agentx_request_type         req;
+       int32_t                          idx = 0;
+       const uint8_t                   *lladdr;
+       struct kif                      *kif;
+       int                              i = 0, llcmp, impl;
+       size_t                           slen;
+
+       obj = agentx_varbind_get_object(vb);
+       idx = agentx_varbind_get_index_integer(vb, ifIdx);
+       lladdr = (const uint8_t *)agentx_varbind_get_index_string(vb,
+           ifRcvAddressAddress, &slen, &impl);
+       if (lladdr == NULL)
+               lladdr = ether_zeroaddr;
+       req = agentx_varbind_request(vb);
+
+       if ((kif = mib_ifget(idx)) == NULL) {
+               agentx_varbind_notfound(vb);
+               return;
+       }
+       /*
+        * The lladdr of the interface will be encoded in the returned OID
+        * ifRcvAddressX.ifindex.6.x.x.x.x.x.x = val
+        * Thanks to the virtual cloner interfaces, it is an easy 1:1
+        * mapping in OpenBSD; only one lladdr (MAC) address per interface.
+        */
+       if (slen == 6)
+               llcmp = bcmp(lladdr, kif->if_lladdr, sizeof(kif->if_lladdr));
+       if (req == AGENTX_REQUEST_TYPE_GET) {
+               if (idx != kif->if_index || slen != 6 || llcmp != 0) {
+                       agentx_varbind_notfound(vb);
+                       return;
+               }
+       } else if (idx == kif->if_index) {
+               if (req == AGENTX_REQUEST_TYPE_GETNEXT) {
+                       if (slen > 6 || llcmp >= 0)
+                               kif = kr_getnextif(kif->if_index);
+               } else {
+                       if (slen > 6 || llcmp > 0)
+                               kif = kr_getnextif(kif->if_index);
+               }
+               if (kif == NULL) {
+                       agentx_varbind_notfound(vb);
+                       return;
+               }
+       }
+       agentx_varbind_set_index_integer(vb, ifIdx, kif->if_index);
+       agentx_varbind_set_index_nstring(vb, ifRcvAddressAddress,
+           kif->if_lladdr, sizeof(kif->if_lladdr));
+
+       if (obj == ifRcvAddressStatus) {
+               /* ifRcvAddressStatus: RowStatus active(1), notInService(2) */
+               i = kif->if_flags & IFF_UP ? 1 : 2;
+               agentx_varbind_integer(vb, i);
+       } else if (obj == ifRcvAddressType) {
+               /* ifRcvAddressType: other(1), volatile(2), nonVolatile(3) */
+               agentx_varbind_integer(vb, 1);
+       } else
+               fatal("%s: Unexpected object", __func__);
+}
+
+/*
+ * Defined in 
+ * - OPENBSD-PF-MIB.txt
+ * - OPENBSD-SENSORS-MIB.txt
+ * - OPENBSD-CARP-MIB.txt
+ * (http://www.packetmischief.ca/openbsd-snmp-mibs/)
+ */ 
+#define OIDVER_OPENBSD_MEM             1
+
+struct carpif {
+       struct carpreq   carpr;
+       struct kif       kif;
+};
+
+void    mib_pfinfo(struct agentx_varbind *);
+void    mib_pfcounters(struct agentx_varbind *);
+void    mib_pfscounters(struct agentx_varbind *);
+void    mib_pflogif(struct agentx_varbind *);
+void    mib_pfsrctrack(struct agentx_varbind *);
+void    mib_pflimits(struct agentx_varbind *);
+void    mib_pftimeouts(struct agentx_varbind *);
+void    mib_pfifnum(struct agentx_varbind *);
+void    mib_pfiftable(struct agentx_varbind *);
+void    mib_pftablenum(struct agentx_varbind *);
+void    mib_pftables(struct agentx_varbind *);
+void    mib_pftableaddrs(struct agentx_varbind *);
+void    mib_pflabelnum(struct agentx_varbind *);
+void    mib_pflabels(struct agentx_varbind *);
+void    mib_pfsyncstats(struct agentx_varbind *);
+
+void    mib_sensornum(struct agentx_varbind *);
+void    mib_sensors(struct agentx_varbind *);
+const char *mib_sensorunit(struct sensor *);
+char   *mib_sensorvalue(struct sensor *);
+
+void    mib_carpsysctl(struct agentx_varbind *);
+void    mib_carpstats(struct agentx_varbind *);
+void    mib_carpiftable(struct agentx_varbind *);
+void    mib_carpgrouptable(struct agentx_varbind *);
+void    mib_carpifnum(struct agentx_varbind *);
+struct carpif
+       *mib_carpifget(u_int);
+void    mib_memversion(struct agentx_varbind *);
+void    mib_memiftable(struct agentx_varbind *);
+
+void
+mib_pfinfo(struct agentx_varbind *vb)
+{
+       struct agentx_object    *obj;
+       struct pf_status         s;
+       time_t                   runtime = 0;
+       struct timespec          uptime;
+
+       if (pf_get_stats(&s)) {
+               agentx_varbind_error(vb);
+               return;
+       }
+
+       obj = agentx_varbind_get_object(vb);
+       if (obj == pfRunning)
+               agentx_varbind_integer(vb, s.running);
+       else if (obj == pfRuntime) {
+               if (!clock_gettime(CLOCK_BOOTTIME, &uptime))
+                       runtime = uptime.tv_sec - s.since;
+               runtime *= 100;
+               agentx_varbind_timeticks(vb, runtime);
+       } else if (obj == pfDebug)
+               agentx_varbind_integer(vb, s.debug);
+       else if (obj == pfHostid)
+               agentx_varbind_printf(vb, "0x%08x", ntohl(s.hostid));
+       else
+               fatal("%s: Unexpected object", __func__);
+}
+
+void
+mib_pfcounters(struct agentx_varbind *vb)
+{
+       struct agentx_object    *obj;
+       struct pf_status         s;
+
+       if (pf_get_stats(&s)) {
+               agentx_varbind_error(vb);
+               return;
+       }
+
+       obj = agentx_varbind_get_object(vb);
+       if (obj == pfCntMatch)
+               agentx_varbind_counter64(vb, s.counters[PFRES_MATCH]);
+       else if (obj == pfCntBadOffset)
+               agentx_varbind_counter64(vb, s.counters[PFRES_BADOFF]);
+       else if (obj == pfCntFragment)
+               agentx_varbind_counter64(vb, s.counters[PFRES_FRAG]);
+       else if (obj == pfCntShort)
+               agentx_varbind_counter64(vb, s.counters[PFRES_SHORT]);
+       else if (obj == pfCntNormalize)
+               agentx_varbind_counter64(vb, s.counters[PFRES_NORM]);
+       else if (obj == pfCntMemory)
+               agentx_varbind_counter64(vb, s.counters[PFRES_MEMORY]);
+       else if (obj == pfCntTimestamp)
+               agentx_varbind_counter64(vb, s.counters[PFRES_TS]);
+       else if (obj == pfCntCongestion)
+               agentx_varbind_counter64(vb, s.counters[PFRES_CONGEST]);
+       else if (obj == pfCntIpOption)
+               agentx_varbind_counter64(vb, s.counters[PFRES_IPOPTIONS]);
+       else if (obj == pfCntProtoCksum)
+               agentx_varbind_counter64(vb, s.counters[PFRES_PROTCKSUM]);
+       else if (obj == pfCntStateMismatch)
+               agentx_varbind_counter64(vb, s.counters[PFRES_BADSTATE]);
+       else if (obj == pfCntStateInsert)
+               agentx_varbind_counter64(vb, s.counters[PFRES_STATEINS]);
+       else if (obj == pfCntStateLimit)
+               agentx_varbind_counter64(vb, s.counters[PFRES_MAXSTATES]);
+       else if (obj == pfCntSrcLimit)
+               agentx_varbind_counter64(vb, s.counters[PFRES_SRCLIMIT]);
+       else if (obj == pfCntSynproxy)
+               agentx_varbind_counter64(vb, s.counters[PFRES_SYNPROXY]);
+       else if (obj == pfCntTranslate)
+               agentx_varbind_counter64(vb, s.counters[PFRES_TRANSLATE]);
+       else if (obj == pfCntNoRoute)
+               agentx_varbind_counter64(vb, s.counters[PFRES_NOROUTE]);
+       else
+               fatal("%s: Unexpected object", __func__);
+}
+
+void
+mib_pfscounters(struct agentx_varbind *vb)
+{
+       struct agentx_object    *obj;
+       struct pf_status         s;
+
+       if (pf_get_stats(&s)) {
+               agentx_varbind_error(vb);
+               return;
+       }
+
+       obj = agentx_varbind_get_object(vb);
+       if (obj == pfStateCount)
+               agentx_varbind_unsigned32(vb, s.states);
+       else if (obj == pfStateSearches)
+               agentx_varbind_counter64(vb, s.fcounters[FCNT_STATE_SEARCH]);
+       else if (obj == pfStateInserts)
+               agentx_varbind_counter64(vb, s.fcounters[FCNT_STATE_INSERT]);
+       else if (obj == pfStateRemovals)
+               agentx_varbind_counter64(vb, s.fcounters[FCNT_STATE_REMOVALS]);
+       else
+               fatal("%s: Unexpected object", __func__);
+}
+
+void
+mib_pflogif(struct agentx_varbind *vb)
+{
+       struct agentx_object    *obj;
+       struct pf_status         s;
+
+       if (pf_get_stats(&s)) {
+               agentx_varbind_error(vb);
+               return;
+       }
+
+       obj = agentx_varbind_get_object(vb);
+       if (obj == pfLogIfName)
+               agentx_varbind_string(vb, s.ifname);
+       else if (obj == pfLogIfIpBytesIn)
+               agentx_varbind_counter64(vb, s.bcounters[IPV4][IN]);
+       else if (obj == pfLogIfIpBytesOut)
+               agentx_varbind_counter64(vb, s.bcounters[IPV4][OUT]);
+       else if (obj == pfLogIfIpPktsInPass)
+               agentx_varbind_counter64(vb, s.pcounters[IPV4][IN][PF_PASS]);
+       else if (obj == pfLogIfIpPktsInDrop)
+               agentx_varbind_counter64(vb, s.pcounters[IPV4][IN][PF_DROP]);
+       else if (obj == pfLogIfIpPktsOutPass)
+               agentx_varbind_counter64(vb, s.pcounters[IPV4][OUT][PF_PASS]);
+       else if (obj == pfLogIfIpPktsOutDrop)
+               agentx_varbind_counter64(vb, s.pcounters[IPV4][OUT][PF_DROP]);
+       else if (obj == pfLogIfIp6BytesIn)
+               agentx_varbind_counter64(vb, s.bcounters[IPV6][IN]);
+       else if (obj == pfLogIfIp6BytesOut)
+               agentx_varbind_counter64(vb, s.bcounters[IPV6][OUT]);
+       else if (obj == pfLogIfIp6PktsInPass)
+               agentx_varbind_counter64(vb, s.pcounters[IPV6][IN][PF_PASS]);
+       else if (obj == pfLogIfIp6PktsInDrop)
+               agentx_varbind_counter64(vb, s.pcounters[IPV6][IN][PF_DROP]);
+       else if (obj == pfLogIfIp6PktsOutPass)
+               agentx_varbind_counter64(vb, s.pcounters[IPV6][OUT][PF_PASS]);
+       else if (obj == pfLogIfIp6PktsOutDrop)
+               agentx_varbind_counter64(vb, s.pcounters[IPV6][OUT][PF_DROP]);
+       else
+               fatal("%s: Unexpected object", __func__);
+}
+
+void
+mib_pfsrctrack(struct agentx_varbind *vb)
+{
+       struct agentx_object    *obj;
+       struct pf_status         s;
+
+       if (pf_get_stats(&s)) {
+               agentx_varbind_error(vb);
+               return;
+       }
+
+       obj = agentx_varbind_get_object(vb);
+       if (obj == pfSrcTrackCount)
+               agentx_varbind_unsigned32(vb, s.src_nodes);
+       else if (obj == pfSrcTrackSearches)
+               agentx_varbind_counter64(vb, s.scounters[SCNT_SRC_NODE_SEARCH]);
+       else if (obj == pfSrcTrackInserts)
+               agentx_varbind_counter64(vb, s.scounters[SCNT_SRC_NODE_INSERT]);
+       else if (obj == pfSrcTrackRemovals)
+               agentx_varbind_counter64(vb,
+                   s.scounters[SCNT_SRC_NODE_REMOVALS]);
+       else
+               fatal("%s: Unexpected object", __func__);
+}
+
+void
+mib_pflimits(struct agentx_varbind *vb)
+{
+       struct agentx_object    *obj;
+       struct pfioc_limit       pl;
+       extern int               devpf;
+
+       obj = agentx_varbind_get_object(vb);
+       memset(&pl, 0, sizeof(pl));
+       if (obj == pfLimitStates)
+               pl.index = PF_LIMIT_STATES;
+       else if (obj == pfLimitSourceNodes)
+               pl.index = PF_LIMIT_SRC_NODES;
+       else if (obj == pfLimitFragments)
+               pl.index = PF_LIMIT_FRAGS;
+       else if (obj == pfLimitMaxTables)
+               pl.index = PF_LIMIT_TABLES;
+       else if (obj == pfLimitMaxTableEntries)
+               pl.index = PF_LIMIT_TABLE_ENTRIES;
+       else
+               fatal("%s: Unexpected object", __func__);
+
+       if (ioctl(devpf, DIOCGETLIMIT, &pl) == -1) {
+               log_warn("DIOCGETLIMIT");
+               agentx_varbind_error(vb);
+               return;
+       }
+
+       agentx_varbind_unsigned32(vb, pl.limit);
+}
+
+void
+mib_pftimeouts(struct agentx_varbind *vb)
+{
+       struct agentx_object    *obj;
+       struct pfioc_tm          pt;
+       extern int               devpf;
+
+       obj = agentx_varbind_get_object(vb);
+       memset(&pt, 0, sizeof(pt));
+       if (obj == pfTimeoutTcpFirst)
+               pt.timeout = PFTM_TCP_FIRST_PACKET;
+       else if (obj == pfTimeoutTcpOpening)
+               pt.timeout = PFTM_TCP_OPENING;
+       else if (obj == pfTimeoutTcpEstablished)
+               pt.timeout = PFTM_TCP_ESTABLISHED;
+       else if (obj == pfTimeoutTcpClosing)
+               pt.timeout = PFTM_TCP_CLOSING;
+       else if (obj == pfTimeoutTcpFinWait)
+               pt.timeout = PFTM_TCP_FIN_WAIT;
+       else if (obj == pfTimeoutTcpClosed)
+               pt.timeout = PFTM_TCP_CLOSED;
+       else if (obj == pfTimeoutUdpFirst)
+               pt.timeout = PFTM_UDP_FIRST_PACKET;
+       else if (obj == pfTimeoutUdpSingle)
+               pt.timeout = PFTM_UDP_SINGLE;
+       else if (obj == pfTimeoutUdpMultiple)
+               pt.timeout = PFTM_UDP_MULTIPLE;
+       else if (obj == pfTimeoutIcmpFirst)
+               pt.timeout = PFTM_ICMP_FIRST_PACKET;
+       else if (obj == pfTimeoutIcmpError)
+               pt.timeout = PFTM_ICMP_ERROR_REPLY;
+       else if (obj == pfTimeoutOtherFirst)
+               pt.timeout = PFTM_OTHER_FIRST_PACKET;
+       else if (obj == pfTimeoutOtherSingle)
+               pt.timeout = PFTM_OTHER_SINGLE;
+       else if (obj == pfTimeoutOtherMultiple)
+               pt.timeout = PFTM_OTHER_MULTIPLE;
+       else if (obj == pfTimeoutFragment)
+               pt.timeout = PFTM_FRAG;
+       else if (obj == pfTimeoutInterval)
+               pt.timeout = PFTM_INTERVAL;
+       else if (obj == pfTimeoutAdaptiveStart)
+               pt.timeout = PFTM_ADAPTIVE_START;
+       else if (obj == pfTimeoutAdaptiveEnd)
+               pt.timeout = PFTM_ADAPTIVE_END;
+       else if (obj == pfTimeoutSrcTrack)
+               pt.timeout = PFTM_SRC_NODE;
+       else
+               fatal("%s: Unexpected object", __func__);
+               
+       if (ioctl(devpf, DIOCGETTIMEOUT, &pt) == -1) {
+               log_warn("DIOCGETTIMEOUT");
+               agentx_varbind_error(vb);
+               return;
+       }
+
+       agentx_varbind_integer(vb, pt.seconds);
+}
+
+void
+mib_pfifnum(struct agentx_varbind *vb)
+{
+       int      c;
+
+       if ((c = pfi_count()) == -1)
+               agentx_varbind_error(vb);
+       else
+               agentx_varbind_integer(vb, c);
+}
+
+void
+mib_pfiftable(struct agentx_varbind *vb)
+{
+       struct agentx_object            *obj;
+       enum agentx_request_type         req;
+       struct pfi_kif                   pif;
+       int                              idx, iftype;
+
+       obj = agentx_varbind_get_object(vb);
+       idx = agentx_varbind_get_index_integer(vb, pfIfIdx);
+       req = agentx_varbind_request(vb);
+
+       if (req == AGENTX_REQUEST_TYPE_GETNEXT) {
+               if (idx < 1)
+                       idx = 1;
+               else if (idx == INT32_MAX) {
+                       agentx_varbind_notfound(vb);
+                       return;
+               } else
+                       idx++;
+       } else if (req == AGENTX_REQUEST_TYPE_GETNEXTINCLUSIVE) {
+               if (idx < 1)
+                       idx = 1;
+       }
+       if (pfi_get_if(&pif, idx)) {
+               agentx_varbind_notfound(vb);
+               return;
+       }
+       agentx_varbind_set_index_integer(vb, pfIfIdx, idx);
+
+       if (obj == pfIfIndex)
+               agentx_varbind_integer(vb, idx);
+       else if (obj == pfIfDescr)
+               agentx_varbind_string(vb, pif.pfik_name);
+       else if (obj == pfIfType) {
+               iftype = (pif.pfik_ifp == NULL ? PFI_IFTYPE_GROUP
+                   : PFI_IFTYPE_INSTANCE);
+               agentx_varbind_integer(vb, iftype);
+       } else if (obj == pfIfRefs)
+               agentx_varbind_unsigned32(vb, pif.pfik_states);
+       else if (obj == pfIfRules)
+               agentx_varbind_unsigned32(vb, pif.pfik_rules);
+       else if (obj == pfIfIn4PassPkts)
+               agentx_varbind_counter64(vb, pif.pfik_packets[IPV4][IN][PASS]);
+       else if (obj == pfIfIn4PassBytes)
+               agentx_varbind_counter64(vb, pif.pfik_bytes[IPV4][IN][PASS]);
+       else if (obj == pfIfIn4BlockPkts)
+               agentx_varbind_counter64(vb, pif.pfik_packets[IPV4][IN][BLOCK]);
+       else if (obj == pfIfIn4BlockBytes)
+               agentx_varbind_counter64(vb, pif.pfik_bytes[IPV4][IN][BLOCK]);
+       else if (obj == pfIfOut4PassPkts)
+               agentx_varbind_counter64(vb, pif.pfik_packets[IPV4][OUT][PASS]);
+       else if (obj == pfIfOut4PassBytes)
+               agentx_varbind_counter64(vb, pif.pfik_bytes[IPV4][OUT][PASS]);
+       else if (obj == pfIfOut4BlockPkts)
+               agentx_varbind_counter64(vb, pif.pfik_packets[IPV4][OUT][BLOCK]);
+       else if (obj == pfIfOut4BlockBytes)
+               agentx_varbind_counter64(vb, pif.pfik_bytes[IPV4][OUT][BLOCK]);
+       else if (obj == pfIfIn6PassPkts)
+               agentx_varbind_counter64(vb, pif.pfik_packets[IPV6][IN][PASS]);
+       else if (obj == pfIfIn6PassBytes)
+               agentx_varbind_counter64(vb, pif.pfik_bytes[IPV6][IN][PASS]);
+       else if (obj == pfIfIn6BlockPkts)
+               agentx_varbind_counter64(vb, pif.pfik_packets[IPV6][IN][BLOCK]);
+       else if (obj == pfIfIn6BlockBytes)
+               agentx_varbind_counter64(vb, pif.pfik_bytes[IPV6][IN][BLOCK]);
+       else if (obj == pfIfOut6PassPkts)
+               agentx_varbind_counter64(vb, pif.pfik_packets[IPV6][OUT][PASS]);
+       else if (obj == pfIfOut6PassBytes)
+               agentx_varbind_counter64(vb, pif.pfik_bytes[IPV6][OUT][PASS]);
+       else if (obj == pfIfOut6BlockPkts)
+               agentx_varbind_counter64(vb, pif.pfik_packets[IPV6][OUT][BLOCK]);
+       else if (obj == pfIfOut6BlockBytes)
+               agentx_varbind_counter64(vb, pif.pfik_bytes[IPV6][OUT][BLOCK]);
+       else
+               fatal("%s: Unexpected object", __func__);
+}
+
+void
+mib_pftablenum(struct agentx_varbind *vb)
+{
+       int      c;
+
+       if ((c = pft_count()) == -1)
+               agentx_varbind_error(vb);
+       else
+               agentx_varbind_integer(vb, c);
+}
+
+void
+mib_pftables(struct agentx_varbind *vb)
+{
+       struct agentx_object            *obj;
+       enum agentx_request_type         req;
+       struct pfr_tstats                ts;
+       time_t                           tzero;
+       int                              idx;
+
+       obj = agentx_varbind_get_object(vb);
+       idx = agentx_varbind_get_index_integer(vb, pfTblIdx);
+       req = agentx_varbind_request(vb);
+
+       if (req == AGENTX_REQUEST_TYPE_GETNEXT) {
+               if (idx < 1)
+                       idx = 1;
+               else if (idx == INT32_MAX) {
+                       agentx_varbind_notfound(vb);
+                       return;
+               } else
+                       idx++;
+       } else if (req == AGENTX_REQUEST_TYPE_GETNEXTINCLUSIVE) {
+               if (idx < 1)
+                       idx = 1;
+       }
+       if (pft_get_table(&ts, idx)) {
+               agentx_varbind_notfound(vb);
+               return;
+       }
+       agentx_varbind_set_index_integer(vb, pfTblIdx, idx);
+
+       if (obj == pfTblIndex)
+               agentx_varbind_integer(vb, idx);
+       else if (obj == pfTblName)
+               agentx_varbind_string(vb, ts.pfrts_name);
+       else if (obj == pfTblAddresses)
+               agentx_varbind_integer(vb, ts.pfrts_cnt);
+       else if (obj == pfTblAnchorRefs)
+               agentx_varbind_integer(vb, ts.pfrts_refcnt[PFR_REFCNT_ANCHOR]);
+       else if (obj == pfTblRuleRefs)
+               agentx_varbind_integer(vb, ts.pfrts_refcnt[PFR_REFCNT_RULE]);
+       else if (obj == pfTblEvalsMatch)
+               agentx_varbind_counter64(vb, ts.pfrts_match);
+       else if (obj == pfTblEvalsNoMatch)
+               agentx_varbind_counter64(vb, ts.pfrts_nomatch);
+       else if (obj == pfTblInPassPkts)
+               agentx_varbind_counter64(vb, ts.pfrts_packets[IN][PFR_OP_PASS]);
+       else if (obj == pfTblInPassBytes)
+               agentx_varbind_counter64(vb, ts.pfrts_bytes[IN][PFR_OP_PASS]);
+       else if (obj == pfTblInBlockPkts)
+               agentx_varbind_counter64(vb, ts.pfrts_packets[IN][PFR_OP_BLOCK]);
+       else if (obj == pfTblInBlockBytes)
+               agentx_varbind_counter64(vb, ts.pfrts_bytes[IN][PFR_OP_BLOCK]);
+       else if (obj == pfTblInXPassPkts)
+               agentx_varbind_counter64(vb, ts.pfrts_packets[IN][PFR_OP_XPASS]);
+       else if (obj == pfTblInXPassBytes)
+               agentx_varbind_counter64(vb, ts.pfrts_bytes[IN][PFR_OP_XPASS]);
+       else if (obj == pfTblOutPassPkts)
+               agentx_varbind_counter64(vb, ts.pfrts_packets[OUT][PFR_OP_PASS]);
+       else if (obj == pfTblOutPassBytes)
+               agentx_varbind_counter64(vb, ts.pfrts_bytes[OUT][PFR_OP_PASS]);
+       else if (obj == pfTblOutBlockPkts)
+               agentx_varbind_counter64(vb, ts.pfrts_packets[OUT][PFR_OP_BLOCK]);
+       else if (obj == pfTblOutBlockBytes)
+               agentx_varbind_counter64(vb, ts.pfrts_bytes[OUT][PFR_OP_BLOCK]);
+       else if (obj == pfTblOutXPassPkts)
+               agentx_varbind_counter64(vb, ts.pfrts_packets[OUT][PFR_OP_XPASS]);
+       else if (obj == pfTblOutXPassBytes)
+               agentx_varbind_counter64(vb, ts.pfrts_bytes[OUT][PFR_OP_XPASS]);
+       else if (obj == pfTblStatsCleared) {
+               tzero = (time(NULL) - ts.pfrts_tzero) * 100;
+               agentx_varbind_timeticks(vb, tzero);
+       } else if (obj == pfTblInMatchPkts)
+               agentx_varbind_counter64(vb, ts.pfrts_packets[IN][PFR_OP_MATCH]);
+       else if (obj == pfTblInMatchBytes)
+               agentx_varbind_counter64(vb, ts.pfrts_bytes[IN][PFR_OP_MATCH]);
+       else if (obj == pfTblOutMatchPkts)
+               agentx_varbind_counter64(vb, ts.pfrts_packets[OUT][PFR_OP_MATCH]);
+       else if (obj == pfTblOutMatchBytes)
+               agentx_varbind_counter64(vb, ts.pfrts_bytes[OUT][PFR_OP_MATCH]);
+       else
+               fatal("%s: Unexpected object", __func__);
+}
+
+void
+mib_pftableaddrs(struct agentx_varbind *vb)
+{
+       struct agentx_object            *obj;
+       enum agentx_request_type         req;
+       struct pfr_astats                as;
+       int                              tblidx;
+
+       obj = agentx_varbind_get_object(vb);
+       tblidx = agentx_varbind_get_index_integer(vb, pfTblAddrTblIdx);
+       req = agentx_varbind_request(vb);
+
+       /*
+        * XXX No consistent way to differentiate between not found and error
+        * Treat everything as not found.
+        */
+       if (req == AGENTX_REQUEST_TYPE_GET ||
+           req == AGENTX_REQUEST_TYPE_GETNEXTINCLUSIVE) {
+               as.pfras_a.pfra_ip4addr = *agentx_varbind_get_index_ipaddress(
+                   vb, pfTblAddrNetIdx);
+               as.pfras_a.pfra_net = agentx_varbind_get_index_integer(vb,
+                   pfTblAddrMaskIdx);
+
+               if (pfta_get_addr(&as, tblidx)) {
+                       if (req == AGENTX_REQUEST_TYPE_GET) {
+                               agentx_varbind_notfound(vb);
+                               return;
+                       }
+                       req = AGENTX_REQUEST_TYPE_GETNEXT;
+               }
+       }
+       if (req == AGENTX_REQUEST_TYPE_GETNEXT) {
+               if (tblidx < 1)
+                       tblidx = 1;
+               as.pfras_a.pfra_ip4addr = *agentx_varbind_get_index_ipaddress(
+                   vb, pfTblAddrNetIdx);
+               as.pfras_a.pfra_net = agentx_varbind_get_index_integer(vb,
+                   pfTblAddrMaskIdx);
+
+               if (pfta_get_nextaddr(&as, &tblidx)){ 
+                       agentx_varbind_notfound(vb);
+                       return;
+               }
+       }
+       agentx_varbind_set_index_integer(vb, pfTblAddrTblIdx, tblidx);
+       agentx_varbind_set_index_ipaddress(vb, pfTblAddrNetIdx,
+           &as.pfras_a.pfra_ip4addr);
+       agentx_varbind_set_index_integer(vb, pfTblAddrMaskIdx,
+           as.pfras_a.pfra_net);
+
+       if (obj == pfTblAddrTblIndex)
+               agentx_varbind_integer(vb, tblidx);
+       else if (obj == pfTblAddrNet)
+               agentx_varbind_ipaddress(vb, &as.pfras_a.pfra_ip4addr);
+       else if (obj == pfTblAddrMask)
+               agentx_varbind_integer(vb, as.pfras_a.pfra_net);
+       else if (obj == pfTblAddrCleared)
+               agentx_varbind_timeticks(vb, (time(NULL) - as.pfras_tzero) * 100);
+       else if (obj == pfTblAddrInBlockPkts)
+               agentx_varbind_counter64(vb, as.pfras_packets[IN][PFR_OP_BLOCK]);
+       else if (obj == pfTblAddrInBlockBytes)
+               agentx_varbind_counter64(vb, as.pfras_bytes[IN][PFR_OP_BLOCK]);
+       else if (obj == pfTblAddrInPassPkts)
+               agentx_varbind_counter64(vb, as.pfras_packets[IN][PFR_OP_PASS]);
+       else if (obj == pfTblAddrInPassBytes)
+               agentx_varbind_counter64(vb, as.pfras_bytes[IN][PFR_OP_PASS]);
+       else if (obj == pfTblAddrOutBlockPkts)
+               agentx_varbind_counter64(vb, as.pfras_packets[OUT][PFR_OP_BLOCK]);
+       else if (obj == pfTblAddrOutBlockBytes)
+               agentx_varbind_counter64(vb, as.pfras_bytes[OUT][PFR_OP_BLOCK]);
+       else if (obj == pfTblAddrOutPassPkts)
+               agentx_varbind_counter64(vb, as.pfras_packets[OUT][PFR_OP_PASS]);
+       else if (obj == pfTblAddrOutPassBytes)
+               agentx_varbind_counter64(vb, as.pfras_bytes[OUT][PFR_OP_PASS]);
+       else if (obj == pfTblAddrInMatchPkts)
+               agentx_varbind_counter64(vb, as.pfras_packets[IN][PFR_OP_MATCH]);
+       else if (obj == pfTblAddrInMatchBytes)
+               agentx_varbind_counter64(vb, as.pfras_bytes[IN][PFR_OP_MATCH]);
+       else if (obj == pfTblAddrOutMatchPkts)
+               agentx_varbind_counter64(vb, as.pfras_packets[OUT][PFR_OP_MATCH]);
+       else if (obj == pfTblAddrOutMatchBytes)
+               agentx_varbind_counter64(vb, as.pfras_bytes[OUT][PFR_OP_MATCH]);
+       else
+               fatal("%s: Unexpected object", __func__);
+}
+
+void
+mib_pflabelnum(struct agentx_varbind *vb)
+{
+       struct pfioc_rule        pr;
+       u_int32_t                nr, mnr, lnr;
+       extern int               devpf;
+
+       memset(&pr, 0, sizeof(pr));
+       if (ioctl(devpf, DIOCGETRULES, &pr) == -1) {
+               log_warn("DIOCGETRULES");
+               agentx_varbind_error(vb);
+               return;
+       }
+
+       mnr = pr.nr;
+       lnr = 0;
+       for (nr = 0; nr < mnr; ++nr) {
+               pr.nr = nr;
+               if (ioctl(devpf, DIOCGETRULE, &pr) == -1) {
+                       log_warn("DIOCGETRULE");
+                       agentx_varbind_error(vb);
+                       return;
+               }
+
+               if (pr.rule.label[0])
+                       lnr++;
+       }
+
+       agentx_varbind_integer(vb, lnr);
+}
+
+void
+mib_pflabels(struct agentx_varbind *vb)
+{
+       struct agentx_object            *obj;
+       enum agentx_request_type         req;
+       struct pfioc_rule                pr;
+       struct pf_rule                  *r = NULL;
+       u_int32_t                        nr, mnr, lnr;
+       u_int32_t                        idx;
+       extern int                       devpf;
+
+       memset(&pr, 0, sizeof(pr));
+       if (ioctl(devpf, DIOCGETRULES, &pr) == -1) {
+               log_warn("DIOCGETRULES");
+               agentx_varbind_error(vb);
+               return;
+       }
+
+       obj = agentx_varbind_get_object(vb);
+       idx = agentx_varbind_get_index_integer(vb, pfLabelIdx);
+       req = agentx_varbind_request(vb);
+
+       if (idx < 1) {
+               if (req == AGENTX_REQUEST_TYPE_GET) {
+                       agentx_varbind_notfound(vb);
+                       return;
+               }
+               idx = 1;
+       } else if (req == AGENTX_REQUEST_TYPE_GETNEXT) {
+               if (idx == INT32_MAX) {
+                       agentx_varbind_notfound(vb);
+                       return;
+               }
+               idx++;
+       }
+
+       mnr = pr.nr;
+       lnr = 0;
+       for (nr = 0; nr < mnr; ++nr) {
+               pr.nr = nr;
+               if (ioctl(devpf, DIOCGETRULE, &pr) == -1) {
+                       log_warn("DIOCGETRULE");
+                       agentx_varbind_error(vb);
+                       return;
+               }
+
+               if (pr.rule.label[0] && ++lnr == idx) {
+                       r = &pr.rule;
+                       break;
+               }
+       }
+
+       if (r == NULL) {
+               agentx_varbind_notfound(vb);
+               return;
+       }
+       agentx_varbind_set_index_integer(vb, pfLabelIdx, idx);
+
+       if (obj == pfLabelIndex)
+               agentx_varbind_integer(vb, lnr);
+       else if (obj == pfLabelName)
+               agentx_varbind_string(vb, r->label);
+       else if (obj == pfLabelEvals)
+               agentx_varbind_counter64(vb, r->evaluations);
+       else if (obj == pfLabelPkts)
+               agentx_varbind_counter64(vb, r->packets[IN] + r->packets[OUT]);
+       else if (obj == pfLabelBytes)
+               agentx_varbind_counter64(vb, r->bytes[IN] + r->bytes[OUT]);
+       else if (obj == pfLabelInPkts)
+               agentx_varbind_counter64(vb, r->packets[IN]);
+       else if (obj == pfLabelInBytes)
+               agentx_varbind_counter64(vb, r->bytes[IN]);
+       else if (obj == pfLabelOutPkts)
+               agentx_varbind_counter64(vb, r->packets[OUT]);
+       else if (obj == pfLabelOutBytes)
+               agentx_varbind_counter64(vb, r->bytes[OUT]);
+       else if (obj == pfLabelTotalStates)
+               agentx_varbind_counter32(vb, r->states_tot);
+       else
+               fatal("%s: Unexpected object", __func__);
+}
+
+void
+mib_pfsyncstats(struct agentx_varbind *vb)
+{
+       struct agentx_object    *obj;
+       int                      mib[] = { CTL_NET, PF_INET, IPPROTO_PFSYNC,
+                                   PFSYNCCTL_STATS };
+       size_t                   len = sizeof(struct pfsyncstats);
+       struct pfsyncstats       s;
+
+       if (sysctl(mib, 4, &s, &len, NULL, 0) == -1) {
+               log_warn("sysctl");
+               agentx_varbind_error(vb);
+               return;
+       }
+
+       obj = agentx_varbind_get_object(vb);
+       if (obj == pfsyncIpPktsRecv)
+               agentx_varbind_counter64(vb, s.pfsyncs_ipackets);
+       else if (obj == pfsyncIp6PktsRecv)
+               agentx_varbind_counter64(vb, s.pfsyncs_ipackets6);
+       else if (obj == pfsyncPktDiscardsForBadInterface)
+               agentx_varbind_counter64(vb, s.pfsyncs_badif);
+       else if (obj == pfsyncPktDiscardsForBadTtl)
+               agentx_varbind_counter64(vb, s.pfsyncs_badttl);
+       else if (obj == pfsyncPktShorterThanHeader)
+               agentx_varbind_counter64(vb, s.pfsyncs_hdrops);
+       else if (obj == pfsyncPktDiscardsForBadVersion)
+               agentx_varbind_counter64(vb, s.pfsyncs_badver);
+       else if (obj == pfsyncPktDiscardsForBadAction)
+               agentx_varbind_counter64(vb, s.pfsyncs_badact);
+       else if (obj == pfsyncPktDiscardsForBadLength)
+               agentx_varbind_counter64(vb, s.pfsyncs_badlen);
+       else if (obj == pfsyncPktDiscardsForBadAuth)
+               agentx_varbind_counter64(vb, s.pfsyncs_badauth);
+       else if (obj == pfsyncPktDiscardsForStaleState)
+               agentx_varbind_counter64(vb, s.pfsyncs_stale);
+       else if (obj == pfsyncPktDiscardsForBadValues)
+               agentx_varbind_counter64(vb, s.pfsyncs_badval);
+       else if (obj == pfsyncPktDiscardsForBadState)
+               agentx_varbind_counter64(vb, s.pfsyncs_badstate);
+       else if (obj == pfsyncIpPktsSent)
+               agentx_varbind_counter64(vb, s.pfsyncs_opackets);
+       else if (obj == pfsyncIp6PktsSent)
+               agentx_varbind_counter64(vb, s.pfsyncs_opackets6);
+       else if (obj == pfsyncNoMemory)
+               agentx_varbind_counter64(vb, s.pfsyncs_onomem);
+       else if (obj == pfsyncOutputErrors)
+               agentx_varbind_counter64(vb, s.pfsyncs_oerrors);
+       else
+               fatal("%s: Unexpected object", __func__);
+}
+
+/* OPENBSD-SENSORS-MIB */
+void
+mib_sensornum(struct agentx_varbind *vb)
+{
+       struct sensordev         sensordev;
+       size_t                   len = sizeof(sensordev);
+       int                      mib[] = { CTL_HW, HW_SENSORS, 0 };
+       int                      i, c;
+
+       for (i = c = 0; ; i++) {
+               mib[2] = i;
+               if (sysctl(mib, nitems(mib),
+                   &sensordev, &len, NULL, 0) == -1) {
+                       if (errno == ENXIO)
+                               continue;
+                       if (errno == ENOENT)
+                               break;
+                       log_warn("sysctl");
+                       agentx_varbind_error(vb);
+                       return;
+               }
+               c += sensordev.sensors_count;
+       }
+
+       agentx_varbind_integer(vb, c);
+}
+
+void
+mib_sensors(struct agentx_varbind *vb)
+{
+       struct agentx_object            *obj;
+       enum agentx_request_type         req;
+       struct sensordev                 sensordev;
+       size_t                           len = sizeof(sensordev);
+       struct sensor                    sensor;
+       size_t                           slen = sizeof(sensor);
+       char                             desc[32];
+       int                              mib[] =
+           { CTL_HW, HW_SENSORS, 0, 0, 0 };
+       int                              i, j, k;
+       u_int32_t                        idx = 0, n;
+       char                            *s;
+
+       obj = agentx_varbind_get_object(vb);
+       idx = agentx_varbind_get_index_integer(vb, sensorIdx);
+       req = agentx_varbind_request(vb);
+
+       if (req == AGENTX_REQUEST_TYPE_GETNEXT) {
+               if (idx == INT32_MAX) {
+                       agentx_varbind_notfound(vb);
+                       return;
+               }
+               idx++;
+       }
+       if (idx < 1 &&
+           (req == AGENTX_REQUEST_TYPE_GETNEXT ||
+           req == AGENTX_REQUEST_TYPE_GETNEXTINCLUSIVE))
+               idx = 1;
+
+       for (i = 0, n = 1; ; i++) {
+               mib[2] = i;
+               if (sysctl(mib, 3, &sensordev, &len, NULL, 0) == -1) {
+                       if (errno == ENXIO)
+                               continue;
+                       if (errno == ENOENT)
+                               break;
+                       log_warn("sysctl");
+                       agentx_varbind_error(vb);
+                       return;
+               }
+               for (j = 0; j < SENSOR_MAX_TYPES; j++) {
+                       mib[3] = j;
+                       for (k = 0; k < sensordev.maxnumt[j]; k++) {
+                               mib[4] = k;
+                               if (sysctl(mib, 5,
+                                   &sensor, &slen, NULL, 0) == -1) {
+                                       if (errno == ENXIO)
+                                               continue;
+                                       if (errno == ENOENT)
+                                               break;
+                                       log_warn("sysctl");
+                                       agentx_varbind_error(vb);
+                                       return;
+                               }
+                               if (sensor.flags & SENSOR_FINVALID)
+                                       continue;
+                               if (n == idx)
+                                       goto found;
+                               n++;
+                       }
+               }
+       }
+       agentx_varbind_notfound(vb);
+       return;
+
+ found:
+       agentx_varbind_set_index_integer(vb, sensorIdx, idx);
+       if (obj == sensorIndex)
+               agentx_varbind_integer(vb, (int32_t)n);
+       else if (obj == sensorDescr) {
+               if (sensor.desc[0] == '\0') {
+                       snprintf(desc, sizeof(desc), "%s%d",
+                           sensor_type_s[sensor.type],
+                           sensor.numt);
+                       agentx_varbind_string(vb, desc);
+               } else
+                       agentx_varbind_string(vb, sensor.desc);
+       } else if (obj == sensorType)
+               agentx_varbind_integer(vb, sensor.type);
+       else if (obj == sensorDevice)
+               agentx_varbind_string(vb, sensordev.xname);
+       else if (obj == sensorValue) {
+               if ((s = mib_sensorvalue(&sensor)) == NULL) {
+                       log_warn("asprintf");
+                       agentx_varbind_error(vb);
+                       return;
+               }
+               agentx_varbind_string(vb, s);
+               free(s);
+       } else if (obj == sensorUnits)
+               agentx_varbind_string(vb, mib_sensorunit(&sensor));
+       else if (obj == sensorStatus)
+               agentx_varbind_integer(vb, sensor.status);
+       else
+               fatal("%s: Unexpected object", __func__);
+}
+
+#define SENSOR_DRIVE_STATES    (SENSOR_DRIVE_PFAIL + 1)
+static const char * const sensor_drive_s[SENSOR_DRIVE_STATES] = {
+       NULL, "empty", "ready", "powerup", "online", "idle", "active",
+       "rebuild", "powerdown", "fail", "pfail"
+};
+
+static const char * const sensor_unit_s[SENSOR_MAX_TYPES + 1] = {
+       "degC", "RPM", "V DC", "V AC", "Ohm", "W", "A", "Wh", "Ah",
+       "", "", "%", "lx", "", "sec", "%RH", "Hz", "degree", 
+       "m", "Pa", "m/s^2", "m/s", ""
+};
+
+const char *
+mib_sensorunit(struct sensor *s)
+{
+       u_int    idx;
+       idx = s->type > SENSOR_MAX_TYPES ?
+           SENSOR_MAX_TYPES : s->type;
+       return (sensor_unit_s[idx]);
+}
+
+char *
+mib_sensorvalue(struct sensor *s)
+{
+       char    *v;
+       int      ret = -1;
+
+       switch (s->type) {
+       case SENSOR_TEMP:
+               ret = asprintf(&v, "%.2f",
+                   (s->value - 273150000) / 1000000.0);
+               break;
+       case SENSOR_VOLTS_DC:
+       case SENSOR_VOLTS_AC:
+       case SENSOR_WATTS:
+       case SENSOR_AMPS:
+       case SENSOR_WATTHOUR:
+       case SENSOR_AMPHOUR:
+       case SENSOR_LUX:
+       case SENSOR_FREQ:
+       case SENSOR_ACCEL:
+       case SENSOR_VELOCITY:
+       case SENSOR_DISTANCE:
+               ret = asprintf(&v, "%.2f", s->value / 1000000.0);
+               break;
+       case SENSOR_INDICATOR:
+               ret = asprintf(&v, "%s", s->value ? "on" : "off");
+               break;
+       case SENSOR_PERCENT:
+       case SENSOR_HUMIDITY:
+               ret = asprintf(&v, "%.2f", s->value / 1000.0);
+               break;
+       case SENSOR_PRESSURE:
+               ret = asprintf(&v, "%.2f", s->value / 1000.0);
+               break;
+       case SENSOR_TIMEDELTA:
+               ret = asprintf(&v, "%.6f", s->value / 1000000000.0);
+               break;
+       case SENSOR_DRIVE:
+               if (s->value > 0 && s->value < SENSOR_DRIVE_STATES) {
+                       ret = asprintf(&v, "%s", sensor_drive_s[s->value]);
+                       break;
+               }
+               /* FALLTHROUGH */
+       case SENSOR_FANRPM:
+       case SENSOR_OHMS:
+       case SENSOR_INTEGER:
+       default:
+               ret = asprintf(&v, "%lld", s->value);
+               break;
+       }
+
+       if (ret == -1)
+               return (NULL);
+       return (v);
+}
+
+void
+mib_carpsysctl(struct agentx_varbind *vb)
+{
+       struct agentx_object    *obj;
+       size_t                   len;
+       int                      mib[] = { CTL_NET, PF_INET, IPPROTO_CARP, 0 };
+       int                      v;
+
+       obj = agentx_varbind_get_object(vb);
+       if (obj == carpAllow)
+               mib[3] = CARPCTL_ALLOW;
+       else if (obj == carpPreempt)
+               mib[3] = CARPCTL_PREEMPT;
+       else if (obj == carpLog)
+               mib[3] = CARPCTL_LOG;
+       else
+               fatal("%s: Unexpected object", __func__);
+       len = sizeof(v);
+
+       if (sysctl(mib, 4, &v, &len, NULL, 0) == -1) {
+               log_warn("sysctl");
+               agentx_varbind_error(vb);
+               return;
+       }
+
+       agentx_varbind_integer(vb, v);
+}
+
+void
+mib_carpstats(struct agentx_varbind *vb)
+{
+       struct agentx_object    *obj;
+       int                      mib[] = { CTL_NET, PF_INET, IPPROTO_CARP,
+                                   CARPCTL_STATS };
+       size_t                   len;
+       struct                   carpstats stats;
+
+       len = sizeof(stats);
+
+       if (sysctl(mib, 4, &stats, &len, NULL, 0) == -1) {
+               log_warn("sysctl");
+               agentx_varbind_error(vb);
+               return;
+       }
+
+       obj = agentx_varbind_get_object(vb);
+       if (obj == carpIpPktsRecv)
+               agentx_varbind_counter64(vb, stats.carps_ipackets);
+       else if (obj == carpIp6PktsRecv)
+               agentx_varbind_counter64(vb, stats.carps_ipackets6);
+       else if (obj == carpPktDiscardsForBadInterface)
+               agentx_varbind_counter64(vb, stats.carps_badif);
+       else if (obj == carpPktDiscardsForWrongTtl)
+               agentx_varbind_counter64(vb, stats.carps_badttl);
+       else if (obj == carpPktShorterThanHeader)
+               agentx_varbind_counter64(vb, stats.carps_hdrops);
+       else if (obj == carpPktDiscardsForBadChecksum)
+               agentx_varbind_counter64(vb, stats.carps_badsum);
+       else if (obj == carpPktDiscardsForBadVersion)
+               agentx_varbind_counter64(vb, stats.carps_badver);
+       else if (obj == carpPktDiscardsForTooShort)
+               agentx_varbind_counter64(vb, stats.carps_badlen);
+       else if (obj == carpPktDiscardsForBadAuth)
+               agentx_varbind_counter64(vb, stats.carps_badauth);
+       else if (obj == carpPktDiscardsForBadVhid)
+               agentx_varbind_counter64(vb, stats.carps_badvhid);
+       else if (obj == carpPktDiscardsForBadAddressList)
+               agentx_varbind_counter64(vb, stats.carps_badaddrs);
+       else if (obj == carpIpPktsSent)
+               agentx_varbind_counter64(vb, stats.carps_opackets);
+       else if (obj == carpIp6PktsSent)
+               agentx_varbind_counter64(vb, stats.carps_opackets6);
+       else if (obj == carpNoMemory)
+               agentx_varbind_counter64(vb, stats.carps_onomem);
+       else if (obj == carpTransitionsToMaster)
+               agentx_varbind_counter64(vb, stats.carps_preempt);
+       else
+               fatal("%s: Unexpected object", __func__);
+}
+
+void
+mib_carpifnum(struct agentx_varbind *vb)
+{
+       struct kif      *kif;
+       int              c = 0;
+
+       for (kif = kr_getif(0); kif != NULL;
+           kif = kr_getnextif(kif->if_index))
+               if (kif->if_type == IFT_CARP)
+                       c++;
+
+       agentx_varbind_integer(vb, c);
+}
+
+struct carpif *
+mib_carpifget(u_int idx)
+{
+       struct kif      *kif;
+       struct carpif   *cif;
+       int              s;
+       struct ifreq     ifr;
+       struct carpreq   carpr;
+
+       if ((kif = kr_getif(idx)) == NULL || kif->if_type != IFT_CARP) {
+               /*
+                * It may happen that an interface with a specific index
+                * does not exist, has been removed, or is not a carp(4)
+                * interface. Jump to the next available carp(4) interface
+                * index.
+                */
+               for (kif = kr_getif(0); kif != NULL;
+                   kif = kr_getnextif(kif->if_index)) {
+                       if (kif->if_type != IFT_CARP)
+                               continue;
+                       if (kif->if_index > idx)
+                               break;
+
+               }
+               if (kif == NULL)
+                       return (NULL);
+       }
+       idx = kif->if_index;
+
+       /* Update interface information */
+       kr_updateif(idx);
+       if ((kif = kr_getif(idx)) == NULL) {
+               log_debug("mib_carpifget: interface %d disappeared?", idx);
+               return (NULL);
+       }
+
+       if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
+               return (NULL);
+
+       memset(&ifr, 0, sizeof(ifr));
+       strlcpy(ifr.ifr_name, kif->if_name, sizeof(ifr.ifr_name));
+       memset((char *)&carpr, 0, sizeof(carpr));
+       ifr.ifr_data = (caddr_t)&carpr;
+
+       if (ioctl(s, SIOCGVH, (caddr_t)&ifr) == -1) {
+               close(s);
+               return (NULL);
+       }
+
+       cif = calloc(1, sizeof(struct carpif));
+       if (cif != NULL) {
+               memcpy(&cif->carpr, &carpr, sizeof(struct carpreq));
+               memcpy(&cif->kif, kif, sizeof(struct kif));
+       }
+
+       close(s);
+
+       return (cif);
+}
+
+void
+mib_carpiftable(struct agentx_varbind *vb)
+{
+       struct agentx_object            *obj;
+       enum agentx_request_type         req;
+       u_int32_t                        idx;
+       struct carpif                   *cif;
+
+       obj = agentx_varbind_get_object(vb);
+       idx = agentx_varbind_get_index_integer(vb, carpIfIdx);
+       req = agentx_varbind_request(vb);
+
+       if (idx < 1) {
+               if (req == AGENTX_REQUEST_TYPE_GET) {
+                       agentx_varbind_notfound(vb);
+                       return;
+               }
+               idx = 1;
+       } else if (req == AGENTX_REQUEST_TYPE_GETNEXT) {
+               if (idx == INT32_MAX) {
+                       agentx_varbind_notfound(vb);
+                       return;
+               }
+               idx++;
+       }
+
+       /*
+        * XXX No consistent way to differentiate between not found and error
+        * Treat everything as not found.
+        */
+       if ((cif = mib_carpifget(idx)) == NULL) {
+               agentx_varbind_notfound(vb);
+               return;
+       }
+
+       if (req == AGENTX_REQUEST_TYPE_GET && cif->kif.if_index != idx) {
+               agentx_varbind_notfound(vb);
+               return;
+       }
+       agentx_varbind_set_index_integer(vb, carpIfIdx, cif->kif.if_index);
+
+       if (obj == carpIfIndex)
+               agentx_varbind_integer(vb, cif->kif.if_index);
+       else if (obj == carpIfDescr)
+               agentx_varbind_string(vb, cif->kif.if_name);
+       else if (obj == carpIfVhid)
+               agentx_varbind_integer(vb, cif->carpr.carpr_vhids[0]);
+       else if (obj == carpIfDev)
+               agentx_varbind_string(vb, cif->carpr.carpr_carpdev);
+       else if (obj == carpIfAdvbase)
+               agentx_varbind_integer(vb, cif->carpr.carpr_advbase);
+       else if (obj == carpIfAdvskew)
+               agentx_varbind_integer(vb, cif->carpr.carpr_advskews[0]);
+       else if (obj == carpIfState)
+               agentx_varbind_integer(vb, cif->carpr.carpr_states[0]);
+       else
+               fatal("%s: Unexpected object", __func__);
+       free(cif);
+}
+
+static struct ifg_req *
+mib_carpgroupget(u_int idx)
+{
+       struct ifgroupreq        ifgr;
+       struct ifg_req          *ifg = NULL;
+       u_int                    len;
+       int                      s = -1;
+
+       bzero(&ifgr, sizeof(ifgr));
+
+       if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
+               log_warn("socket");
+               return (NULL);
+       }
+
+       if (ioctl(s, SIOCGIFGLIST, (caddr_t)&ifgr) == -1) {
+               log_warn("SIOCGIFGLIST");
+               goto err;
+       }
+       len = ifgr.ifgr_len;
+
+       if (len / sizeof(*ifgr.ifgr_groups) <= idx-1)
+               goto err;
+
+       if ((ifgr.ifgr_groups = calloc(1, len)) == NULL) {
+               log_warn("alloc");
+               goto err;
+       }
+       if (ioctl(s, SIOCGIFGLIST, (caddr_t)&ifgr) == -1) {
+               log_warn("SIOCGIFGLIST");
+               goto err;
+       }
+       close(s);
+
+       if ((ifg = calloc(1, sizeof *ifg)) == NULL) {
+               log_warn("alloc");
+               goto err;
+       }
+
+       memcpy(ifg, &ifgr.ifgr_groups[idx-1], sizeof *ifg);
+       free(ifgr.ifgr_groups);
+       return ifg;
+ err:
+       free(ifgr.ifgr_groups);
+       close(s);
+       return (NULL);
+}
+
+void
+mib_carpgrouptable(struct agentx_varbind *vb)
+{
+       struct agentx_object            *obj;
+       enum agentx_request_type         req;
+       struct ifgroupreq                ifgr;
+       struct ifg_req                  *ifg;
+       uint32_t                         idx;
+       int                              s;
+
+       obj = agentx_varbind_get_object(vb);
+       idx = agentx_varbind_get_index_integer(vb, carpGroupIdx);
+       req = agentx_varbind_request(vb);
+
+       if (idx < 1) {
+               if (req == AGENTX_REQUEST_TYPE_GET) {
+                       agentx_varbind_notfound(vb);
+                       return;
+               }
+               idx = 1;
+       } else if (req == AGENTX_REQUEST_TYPE_GETNEXT) {
+               if (idx == INT32_MAX) {
+                       agentx_varbind_notfound(vb);
+                       return;
+               }
+               idx++;
+       }
+
+       /*
+        * XXX No consistent way to differentiate between not found and error
+        * Treat everything as not found.
+        */
+       if ((ifg = mib_carpgroupget(idx)) == NULL) {
+               agentx_varbind_notfound(vb);
+               return;
+       }
+       agentx_varbind_set_index_integer(vb, carpGroupIdx, idx);
+
+       if (obj == carpGroupName)
+               agentx_varbind_string(vb, ifg->ifgrq_group);
+       else if (obj == carpGroupDemote) {
+               if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
+                       log_warn("socket");
+                       free(ifg);
+                       agentx_varbind_error(vb);
+                       return;
+               }
+
+               bzero(&ifgr, sizeof(ifgr));
+               strlcpy(ifgr.ifgr_name, ifg->ifgrq_group, sizeof(ifgr.ifgr_name));
+               if (ioctl(s, SIOCGIFGATTR, (caddr_t)&ifgr) == -1) {
+                       log_warn("SIOCGIFGATTR");
+                       close(s);
+                       free(ifg);
+                       agentx_varbind_error(vb);
+                       return;
+               }
+
+               close(s);
+               agentx_varbind_integer(vb, ifgr.ifgr_attrib.ifg_carp_demoted);
+       } else
+               fatal("%s: Unexpected object", __func__);
+
+       free(ifg);
+}
+
+void
+mib_memversion(struct agentx_varbind *vb)
+{
+       agentx_varbind_integer(vb, 1);
+}
+
+void
+mib_memiftable(struct agentx_varbind *vb)
+{
+       struct agentx_object            *obj;
+       enum agentx_request_type         req;
+       u_int32_t                        idx = 0;
+       struct kif                      *kif;
+
+       obj = agentx_varbind_get_object(vb);
+       idx = agentx_varbind_get_index_integer(vb, ifIdx);
+       req = agentx_varbind_request(vb);
+       if (req == AGENTX_REQUEST_TYPE_GETNEXT) {
+               if (idx == INT32_MAX) {
+                       agentx_varbind_notfound(vb);
+                       return;
+               }
+               idx++;
+       }
+       if ((kif = mib_ifget(idx)) == NULL) {
+               agentx_varbind_notfound(vb);
+               return;
+       }
+       if (req == AGENTX_REQUEST_TYPE_GET) {
+               if (idx != kif->if_index) {
+                       agentx_varbind_notfound(vb);
+                       return;
+               }
+       }
+       agentx_varbind_set_index_integer(vb, ifIdx, kif->if_index);
+
+       if (obj == memIfName)
+               agentx_varbind_string(vb, kif->if_name);
+       else if (obj == memIfLiveLocks)
+               agentx_varbind_counter64(vb, 0);
+       else
+               fatal("%s: Unexpected object", __func__);
+}
+
+/*
+ * Defined in IP-MIB.txt
+ */
+int mib_getipstat(struct ipstat *);
+void mib_ipstat(struct agentx_varbind *);
+void mib_ipforwarding(struct agentx_varbind *);
+void mib_ipdefaultttl(struct agentx_varbind *);
+void mib_ipinhdrerrs(struct agentx_varbind *);
+void mib_ipinaddrerrs(struct agentx_varbind *);
+void mib_ipforwdgrams(struct agentx_varbind *);
+void mib_ipreasmtimeout(struct agentx_varbind *);
+void mib_ipreasmfails(struct agentx_varbind *);
+void mib_ipfragfails(struct agentx_varbind *);
+void mib_ipaddr(struct agentx_varbind *);
+void mib_physaddr(struct agentx_varbind *);
+
+void
+mib_ipforwarding(struct agentx_varbind *vb)
+{
+       int     mib[] = { CTL_NET, PF_INET, IPPROTO_IP, IPCTL_FORWARDING };
+       int     v;
+       size_t  len = sizeof(v);
+
+       if (sysctl(mib, nitems(mib), &v, &len, NULL, 0) == -1) {
+               log_warn("sysctl");
+               agentx_varbind_error(vb);
+               return;
+       }
+
+       /* ipForwarding: forwarding(1), notForwarding(2) */
+       agentx_varbind_integer(vb, (v == 0) ? 2 : 1);
+}
+
+void
+mib_ipdefaultttl(struct agentx_varbind *vb)
+{
+       int     mib[] = { CTL_NET, PF_INET, IPPROTO_IP, IPCTL_DEFTTL };
+       int     v;
+       size_t  len = sizeof(v);
+
+       if (sysctl(mib, nitems(mib), &v, &len, NULL, 0) == -1) {
+               log_warn("sysctl");
+               agentx_varbind_error(vb);
+               return;
+       }
+
+       agentx_varbind_integer(vb, v);
+}
+
+int
+mib_getipstat(struct ipstat *ipstat)
+{
+       int      mib[] = { CTL_NET, PF_INET, IPPROTO_IP, IPCTL_STATS };
+       size_t   len = sizeof(*ipstat);
+
+       return (sysctl(mib, nitems(mib), ipstat, &len, NULL, 0));
+}
+
+void
+mib_ipstat(struct agentx_varbind *vb)
+{
+       struct agentx_object    *obj;
+       struct ipstat            ipstat;
+
+       if (mib_getipstat(&ipstat) == -1) {
+               log_warn("sysctl");
+               agentx_varbind_error(vb);
+               return;
+       }
+
+       obj = agentx_varbind_get_object(vb);
+       if (obj == ipInReceives)
+               agentx_varbind_counter32(vb, ipstat.ips_total);
+       else if (obj == ipInUnknownProtos)
+               agentx_varbind_counter32(vb, ipstat.ips_noproto);
+       else if (obj == ipInDelivers)
+               agentx_varbind_counter32(vb, ipstat.ips_delivered);
+       else if (obj == ipOutRequests)
+               agentx_varbind_counter32(vb, ipstat.ips_localout);
+       else if (obj == ipOutDiscards)
+               agentx_varbind_counter32(vb, ipstat.ips_odropped);
+       else if (obj == ipOutNoRoutes)
+               agentx_varbind_counter32(vb, ipstat.ips_noroute);
+       else if (obj == ipReasmReqds)
+               agentx_varbind_counter32(vb, ipstat.ips_fragments);
+       else if (obj == ipReasmOKs)
+               agentx_varbind_counter32(vb, ipstat.ips_reassembled);
+       else if (obj == ipFragOKs)
+               agentx_varbind_counter32(vb, ipstat.ips_fragmented);
+       else if (obj == ipFragCreates)
+               agentx_varbind_counter32(vb, ipstat.ips_ofragments);
+       else
+               fatal("%s: Unexpected object", __func__);
+}
+
+void
+mib_ipinhdrerrs(struct agentx_varbind *vb)
+{
+       u_int32_t       errors;
+       struct ipstat   ipstat;
+
+       if (mib_getipstat(&ipstat) == -1) {
+               log_warn("sysctl");
+               agentx_varbind_error(vb);
+               return;
+       }
+
+       errors = ipstat.ips_badsum + ipstat.ips_badvers +
+           ipstat.ips_tooshort + ipstat.ips_toosmall +
+           ipstat.ips_badhlen +  ipstat.ips_badlen +
+           ipstat.ips_badoptions + ipstat.ips_toolong +
+           ipstat.ips_badaddr;
+
+       agentx_varbind_counter32(vb, errors);
+}
+
+void
+mib_ipinaddrerrs(struct agentx_varbind *vb)
+{
+       u_int32_t       errors;
+       struct ipstat   ipstat;
+
+       if (mib_getipstat(&ipstat) == -1) {
+               log_warn("sysctl");
+               agentx_varbind_error(vb);
+               return;
+       }
+
+       errors = ipstat.ips_cantforward + ipstat.ips_badaddr;
+
+       agentx_varbind_counter32(vb, errors);
+}
+
+void
+mib_ipforwdgrams(struct agentx_varbind *vb)
+{
+       u_int32_t       counter;
+       struct ipstat   ipstat;
+
+       if (mib_getipstat(&ipstat) == -1) {
+               log_warn("sysctl");
+               agentx_varbind_error(vb);
+               return;
+       }
+
+       counter = ipstat.ips_forward + ipstat.ips_redirectsent;
+
+       agentx_varbind_counter32(vb, counter);
+}
+
+void
+mib_ipreasmtimeout(struct agentx_varbind *vb)
+{
+       agentx_varbind_integer(vb, IPFRAGTTL);
+}
+
+void
+mib_ipreasmfails(struct agentx_varbind *vb)
+{
+       u_int32_t       counter;
+       struct ipstat   ipstat;
+
+       if (mib_getipstat(&ipstat) == -1) {
+               log_warn("sysctl");
+               agentx_varbind_error(vb);
+               return;
+       }
+
+       counter = ipstat.ips_fragdropped + ipstat.ips_fragtimeout;
+
+       agentx_varbind_counter32(vb, counter);
+}
+
+void
+mib_ipfragfails(struct agentx_varbind *vb)
+{
+       u_int32_t       counter;
+       struct ipstat   ipstat;
+
+       if (mib_getipstat(&ipstat) == -1) {
+               log_warn("sysctl");
+               agentx_varbind_error(vb);
+               return;
+       }
+
+       counter = ipstat.ips_badfrags + ipstat.ips_cantfrag;
+       agentx_varbind_counter32(vb, counter);
+}
+
+void
+mib_ipaddr(struct agentx_varbind *vb)
+{
+       struct agentx_object            *obj;
+       enum agentx_request_type         req;
+       struct sockaddr_in               addr;
+       struct kif_addr                 *ka;
+
+       obj = agentx_varbind_get_object(vb);
+       req = agentx_varbind_request(vb);
+       bzero(&addr, sizeof(addr));
+       addr.sin_family = AF_INET;
+       addr.sin_len = sizeof(addr);
+       addr.sin_addr = *agentx_varbind_get_index_ipaddress(vb, ipAdEntAddrIdx);
+
+       if (req == AGENTX_REQUEST_TYPE_GETNEXT) {
+               if (addr.sin_addr.s_addr == UINT32_MAX) {
+                       agentx_varbind_notfound(vb);
+                       return;
+               }
+               addr.sin_addr.s_addr = htonl(ntohl(addr.sin_addr.s_addr) + 1);
+       }
+       /*
+        * XXX No consistent way to differentiate between not found and error
+        * Treat everything as not found.
+        */
+       ka = kr_getnextaddr((struct sockaddr *)&addr);
+       if (ka == NULL || ka->addr.sa.sa_family != AF_INET) {
+               agentx_varbind_notfound(vb);
+               return;
+       }
+       if (req == AGENTX_REQUEST_TYPE_GET) {
+               if (addr.sin_addr.s_addr !=
+                   ((struct sockaddr_in *)&ka->addr.sa)->sin_addr.s_addr) {
+                       agentx_varbind_notfound(vb);
+                       return;
+               }
+       }
+       agentx_varbind_set_index_ipaddress(vb, ipAdEntAddrIdx,
+           &((struct sockaddr_in *)&ka->addr.sa)->sin_addr);
+
+       if (obj == ipAdEntAddr)
+               agentx_varbind_ipaddress(vb,
+                   &((struct sockaddr_in *)&ka->addr.sa)->sin_addr);
+       else if (obj == ipAdEntIfIndex)
+               agentx_varbind_integer(vb, ka->if_index);
+       else if (obj == ipAdEntNetMask)
+               agentx_varbind_ipaddress(vb, &ka->mask.sin.sin_addr);
+       else if (obj == ipAdEntBcastAddr)
+               agentx_varbind_integer(vb, ka->dstbrd.sa.sa_len ? 1 : 0);
+       else if (obj == ipAdEntReasmMaxSize)
+               agentx_varbind_integer(vb, IP_MAXPACKET);
+       else
+               fatal("%s: Unexpected object", __func__);
+}
+
+void
+mib_physaddr(struct agentx_varbind *vb)
+{
+       struct agentx_object            *obj;
+       enum agentx_request_type         req;
+       struct sockaddr_in               addr;
+       struct kif                      *kif;
+       struct kif_arp                  *ka;
+       u_int32_t                        idx = 0;
+
+       obj = agentx_varbind_get_object(vb);
+       idx = agentx_varbind_get_index_integer(vb, ipNetToMediaIfIdx);
+       req = agentx_varbind_request(vb);
+
+       /* Get the IP address */
+       bzero(&addr, sizeof(addr));
+       addr.sin_family = AF_INET;
+       addr.sin_len = sizeof(addr);
+       addr.sin_addr = *agentx_varbind_get_index_ipaddress(vb,
+           ipNetToMediaNetAddressIdx);
+
+       if (req == AGENTX_REQUEST_TYPE_GET ||
+           req == AGENTX_REQUEST_TYPE_GETNEXTINCLUSIVE) {
+               if ((ka = karp_getaddr((struct sockaddr *)&addr, idx, 0)) == NULL) {
+                       if (req == AGENTX_REQUEST_TYPE_GET) {
+                               agentx_varbind_notfound(vb);
+                               return;
+                       }
+                       req = AGENTX_REQUEST_TYPE_GETNEXT;
+               } else {
+                       if (req == AGENTX_REQUEST_TYPE_GET &&
+                           (idx != ka->if_index ||
+                           addr.sin_addr.s_addr !=
+                           ka->addr.sin.sin_addr.s_addr)) {
+                               agentx_varbind_notfound(vb);
+                               return;
+                       }
+               }
+       }
+       if (req == AGENTX_REQUEST_TYPE_GETNEXT) {
+               if ((kif = kr_getif(idx)) == NULL) {
+                       /* No configured interfaces */
+                       if (idx == 0) {
+                               agentx_varbind_notfound(vb);
+                               return;
+                       }
+                       /*
+                        * It may happen that an interface with a specific index
+                        * does not exist or has been removed.  Jump to the next
+                        * available interface.
+                        */
+                       kif = kr_getif(0);
+ nextif:
+                       for (; kif != NULL; kif = kr_getnextif(kif->if_index))
+                               if (kif->if_index > idx &&
+                                   (ka = karp_first(kif->if_index)) != NULL)
+                                       break;
+                       if (kif == NULL) {
+                               /* No more interfaces with addresses on them */
+                               agentx_varbind_notfound(vb);
+                               return;
+                       }
+               } else {
+                       if (idx == 0 || addr.sin_addr.s_addr == 0)
+                               ka = karp_first(kif->if_index);
+                       else {
+                               /* XXX This only works on a walk. */
+                               ka = karp_getaddr((struct sockaddr *)&addr, idx, 1);
+                       }
+                       if (ka == NULL) {
+                               /* Try next interface */
+                               goto nextif;
+                       }
+               }
+       }
+       agentx_varbind_set_index_integer(vb, ipNetToMediaIfIdx, ka->if_index);
+       agentx_varbind_set_index_ipaddress(vb, ipNetToMediaNetAddressIdx,
+           &ka->addr.sin.sin_addr);
+
+       if (obj == ipNetToMediaIfIndex)
+               agentx_varbind_integer(vb, ka->if_index);
+       else if (obj == ipNetToMediaPhysAddress) {
+               if (bcmp(LLADDR(&ka->target.sdl), ether_zeroaddr,
+                   sizeof(ether_zeroaddr)) == 0)
+                       agentx_varbind_nstring(vb, ether_zeroaddr,
+                           sizeof(ether_zeroaddr));
+               else
+                       agentx_varbind_nstring(vb, LLADDR(&ka->target.sdl),
+                           ka->target.sdl.sdl_alen);
+       } else if (obj == ipNetToMediaNetAddress)
+               agentx_varbind_ipaddress(vb, &ka->addr.sin.sin_addr);
+       else if (obj == ipNetToMediaType) {
+               if (ka->flags & F_STATIC)
+                       agentx_varbind_integer(vb, 4); /* static */
+               else
+                       agentx_varbind_integer(vb, 3); /* dynamic */
+       } else
+               fatal("%s: Unexpected object", __func__);
+}
+
+/*
+ * Defined in IP-FORWARD-MIB.txt (rfc4292)
+ */
+
+void mib_ipfnroutes(struct agentx_varbind *);
+//struct ber_oid *
+//mib_ipfroutetable(struct oid *oid, struct ber_oid *o, struct ber_oid *no);
+void mib_ipfroute(struct agentx_varbind *);
+
+void
+mib_ipfnroutes(struct agentx_varbind *vb)
+{
+       agentx_varbind_gauge32(vb, kr_routenumber());
+}
+
+#define INETADDRESSTYPE_IPV4   1
+void
+mib_ipfroute(struct agentx_varbind *vb)
+{
+       struct agentx_object            *obj;
+       enum agentx_request_type         req;
+       struct kroute                   *kr;
+       const in_addr_t                 *addr, *nhaddr;
+       const uint32_t                  *policy;
+       size_t                           alen, plen, nlen;
+       int                              af;
+       int                              implied;
+       u_int8_t                         prefixlen, prio, type, proto;
+
+
+       obj = agentx_varbind_get_object(vb);
+       req = agentx_varbind_request(vb);
+       af = agentx_varbind_get_index_integer(vb, inetCidrRouteDestTypeIdx);
+       addr = (const in_addr_t *)agentx_varbind_get_index_string(vb,
+           inetCidrRouteDestIdx, &alen, &implied);
+       prefixlen = agentx_varbind_get_index_integer(vb,
+           inetCidrRoutePfxLenIdx);
+       policy = agentx_varbind_get_index_oid(vb, inetCidrRoutePolicyIdx,
+           &plen, &implied);
+       nhaddr = ((const in_addr_t *)agentx_varbind_get_index_string(vb,
+           inetCidrRouteNextHopIdx, &nlen, &implied));
+
+       if (plen >= 2)
+               prio = policy[1];
+       /* Initial 2 sub-identifiers should always be the same for us */
+       if (af < INETADDRESSTYPE_IPV4 ||
+           (af == INETADDRESSTYPE_IPV4 && alen < 4)) {
+               if (req == AGENTX_REQUEST_TYPE_GET) {
+                       agentx_varbind_notfound(vb);
+                       return;
+               }
+               kr = kroute_first();
+       } else if (af > INETADDRESSTYPE_IPV4 ||
+                  (af == INETADDRESSTYPE_IPV4 && alen > 4)) {
+               agentx_varbind_notfound(vb);
+               return;
+       } else {
+               /* XXX This only works when requesting known values. */
+               kr = kroute_getaddr(*addr, prefixlen, prio,
+                   req == AGENTX_REQUEST_TYPE_GETNEXT);
+               if (kr == NULL) {
+                       agentx_varbind_notfound(vb);
+                       return;
+               }
+               if (req == AGENTX_REQUEST_TYPE_GETNEXT)
+                       goto done;
+               if (nlen < 4) {
+                       if (req == AGENTX_REQUEST_TYPE_GET) {
+                               agentx_varbind_notfound(vb);
+                               return;
+                       }
+               } else if (nlen > 4) {
+                       kr = kroute_getaddr(*addr, prefixlen, prio, 1);
+                       if (req == AGENTX_REQUEST_TYPE_GET || kr == NULL) {
+                               agentx_varbind_notfound(vb);
+                               return;
+                       }
+               } else {
+                       if (ntohl(kr->nexthop.s_addr) < ntohl(*nhaddr)) {
+                               if (req == AGENTX_REQUEST_TYPE_GET) {
+                                       agentx_varbind_notfound(vb);
+                                       return;
+                               }
+                       } else if (ntohl(kr->nexthop.s_addr) > ntohl(*nhaddr)) {
+                               kr = kroute_getaddr(*addr, prefixlen, prio, 1);
+                               if (req == AGENTX_REQUEST_TYPE_GET ||
+                                   kr == NULL) {
+                                       agentx_varbind_notfound(vb);
+                                       return;
+                               }
+                       }
+
+               }
+       }
+ done:
+       agentx_varbind_set_index_integer(vb, inetCidrRouteDestTypeIdx,
+           INETADDRESSTYPE_IPV4);
+       agentx_varbind_set_index_nstring(vb, inetCidrRouteDestIdx,
+           (unsigned char *)&kr->prefix.s_addr, 4);
+       agentx_varbind_set_index_integer(vb, inetCidrRoutePfxLenIdx,
+           kr->prefixlen);
+       agentx_varbind_set_index_oid(vb, inetCidrRoutePolicyIdx,
+           AGENTX_OID(0, kr->priority));
+       agentx_varbind_set_index_integer(vb, inetCidrRouteNextHopTypeIdx,
+           INETADDRESSTYPE_IPV4);
+       agentx_varbind_set_index_nstring(vb, inetCidrRouteNextHopIdx,
+           (unsigned char *)&kr->nexthop.s_addr, 4);
+
+       if (obj == inetCidrRouteIfIndex)
+               agentx_varbind_integer(vb, kr->if_index);
+       else if (obj == inetCidrRouteType) {
+               if (kr->flags & F_REJECT)
+                       type = 2;
+               else if (kr->flags & F_BLACKHOLE)
+                       type = 5;
+               else if (kr->flags & F_CONNECTED)
+                       type = 3;
+               else
+                       type = 4;
+               agentx_varbind_integer(vb, type);
+       } else if (obj == inetCidrRouteProto) {
+               switch (kr->priority) {
+               case RTP_CONNECTED:
+                       proto = 2;
+                       break;
+               case RTP_STATIC:
+                       proto = 3;
+                       break;
+               case RTP_OSPF:
+                       proto = 13;
+                       break;
+               case RTP_ISIS:
+                       proto = 9;
+                       break;
+               case RTP_RIP:
+                       proto = 8;
+                       break;
+               case RTP_BGP:
+                       proto = 14;
+                       break;
+               default:
+                       if (kr->flags & F_DYNAMIC)
+                               proto = 4;
+                       else
+                               proto = 1; /* not specified */
+                       break;
+               }
+               agentx_varbind_integer(vb, proto);
+       } else if (obj == inetCidrRouteAge)
+               agentx_varbind_gauge32(vb, 0);
+       else if (obj == inetCidrRouteNextHopAS)
+               agentx_varbind_unsigned32(vb, 0); /* unknown */
+       else if (obj == inetCidrRouteMetric1)
+               agentx_varbind_integer(vb, -1);
+       else if (obj == inetCidrRouteMetric2)
+               agentx_varbind_integer(vb, -1);
+       else if (obj == inetCidrRouteMetric3)
+               agentx_varbind_integer(vb, -1);
+       else if (obj == inetCidrRouteMetric4)
+               agentx_varbind_integer(vb, -1);
+       else if (obj == inetCidrRouteMetric5)
+               agentx_varbind_integer(vb, -1);
+       else if (obj == inetCidrRouteStatus)
+               agentx_varbind_integer(vb, 1);  /* XXX */
+       else
+               fatal("%s: Unexpected object", __func__);
+}
+
+/*
+ * Defined in UCD-DISKIO-MIB.txt.
+ */
+
+void   mib_diskio(struct agentx_varbind *vb);
+
+void
+mib_diskio(struct agentx_varbind *vb)
+{
+       struct agentx_object            *obj;
+       enum agentx_request_type         req;
+       u_int32_t                        idx;
+       int                              mib[] = { CTL_HW, 0 };
+       unsigned int                     diskcount;
+       struct diskstats                *stats;
+       size_t                           len;
+
+       len = sizeof(diskcount);
+       mib[1] = HW_DISKCOUNT;
+       if (sysctl(mib, nitems(mib), &diskcount, &len, NULL, 0) == -1) {
+               log_warn("sysctl");
+               agentx_varbind_error(vb);
+               return;
+       }
+
+       obj = agentx_varbind_get_object(vb);
+       req = agentx_varbind_request(vb);
+       idx = agentx_varbind_get_index_integer(vb, diskIOIdx);
+
+       if (req == AGENTX_REQUEST_TYPE_GETNEXT) {
+               if (idx == INT32_MAX) {
+                       agentx_varbind_notfound(vb);
+                       return;
+               }
+               idx++;
+       }
+       if(idx < 1) {
+               if (req == AGENTX_REQUEST_TYPE_GET) {
+                       agentx_varbind_notfound(vb);
+                       return;
+               }
+               idx = 1;
+       } else if (idx > diskcount) {
+               agentx_varbind_notfound(vb);
+               return;
+       }
+       agentx_varbind_set_index_integer(vb, diskIOIdx, idx);
+
+       stats = calloc(diskcount, sizeof(*stats));
+       if (stats == NULL) {
+               log_warn("malloc");
+               agentx_varbind_error(vb);
+               return;
+       }
+       /* We know len won't overflow, otherwise calloc() would have failed. */
+       len = diskcount * sizeof(*stats);
+       mib[1] = HW_DISKSTATS;
+       if (sysctl(mib, nitems(mib), stats, &len, NULL, 0) == -1) {
+               log_warn("sysctl");
+               free(stats);
+               agentx_varbind_error(vb);
+               return;
+       }
+
+       if (obj == diskIOIndex)
+               agentx_varbind_integer(vb, idx);
+       else if (obj == diskIODevice)
+               agentx_varbind_string(vb, stats[idx - 1].ds_name);
+       else if (obj == diskIONRead)
+               agentx_varbind_counter32(vb, 
+                   (u_int32_t)stats[idx - 1].ds_rbytes);
+       else if (obj == diskIONWritten)
+               agentx_varbind_counter32(vb, 
+                   (u_int32_t)stats[idx - 1].ds_wbytes);
+       else if (obj == diskIOReads)
+               agentx_varbind_counter32(vb, 
+                   (u_int32_t)stats[idx - 1].ds_rxfer);
+       else if (obj == diskIOWrites)
+               agentx_varbind_counter32(vb, 
+                   (u_int32_t)stats[idx - 1].ds_wxfer);
+       else if (obj == diskIONReadX)
+               agentx_varbind_counter64(vb, stats[idx - 1].ds_rbytes);
+       else if (obj == diskIONWrittenX)
+               agentx_varbind_counter64(vb, stats[idx - 1].ds_wbytes);
+       else
+               fatal("%s: Unexpected object", __func__);
+       free(stats);
+}
+
+/*
+ * Defined in BRIDGE-MIB.txt (rfc1493)
+ *
+ * This MIB is required by some NMS to accept the device because
+ * the RFC says that mostly any network device has to provide this MIB... :(
+ */
+
+void    mib_dot1basetype(struct agentx_varbind *);
+void    mib_dot1dtable(struct agentx_varbind *);
+
+void
+mib_dot1basetype(struct agentx_varbind *vb)
+{
+       /* srt (sourceroute + transparent) */
+       agentx_varbind_integer(vb, 4);
+}
+
+void
+mib_dot1dtable(struct agentx_varbind *vb)
+{
+       struct agentx_object            *obj;
+       enum agentx_request_type         req;
+       u_int32_t                        idx = 0;
+       struct kif                      *kif;
+
+       obj = agentx_varbind_get_object(vb);
+       req = agentx_varbind_request(vb);
+       idx = agentx_varbind_get_index_integer(vb, dot1dBasePortIdx);
+
+       if (req == AGENTX_REQUEST_TYPE_GETNEXT) {
+               if (idx == INT32_MAX) {
+                       agentx_varbind_notfound(vb);
+                       return;
+               }
+               idx++;
+       }
+       if ((kif = mib_ifget(idx)) == NULL) {
+               agentx_varbind_notfound(vb);
+               return;
+       }
+       if (req == AGENTX_REQUEST_TYPE_GET) {
+               if (idx != kif->if_index) {
+                       agentx_varbind_notfound(vb);
+                       return;
+               }
+       }
+       agentx_varbind_set_index_integer(vb, dot1dBasePortIdx, kif->if_index);
+
+       if (obj == dot1dBasePort)
+               agentx_varbind_integer(vb, kif->if_index);
+       else if (obj == dot1dBasePortIfIndex)
+               agentx_varbind_integer(vb, kif->if_index);
+       else if (obj == dot1dBasePortCircuit)
+               agentx_varbind_oid(vb, AGENTX_OID(0, 0));
+       else if (obj == dot1dBasePortDelayExceededDiscards)
+               agentx_varbind_counter32(vb, 0);
+       else if (obj == dot1dBasePortMtuExceededDiscards)
+               agentx_varbind_counter32(vb, 0);
+       else
+               fatal("%s: Unexpected object", __func__);
+}
+
+/*
+ * Import all MIBs
+ */
+
+int
+main(int argc, char *argv[])
+{
+       static struct snmpd conf;
+       struct agentx *sa;
+       struct agentx_session *sas;
+       struct agentx_index *indices[6];
+       struct passwd *pw;
+       struct group *gr;
+       char agentxsocketdir[PATH_MAX];
+       int ch;
+       int verbose = 0, daemonize = 1, debug = 0;
+       char *context = NULL;
+       const char *errstr;
+       /* HOST-RESOURCES-MIB */
+       struct agentx_region *host;
+       struct agentx_object *hrSystemUptime, *hrSystemDate, *hrMemorySize;
+       /* IF-MIB */
+       struct agentx_region *ifMIB, *interfaces;
+       /* OPENBSD-PF-MIB */
+       struct agentx_region *pfMIBObjects;
+       /* OPENBSD-SENSOR-MIB */
+       struct agentx_region *sensorsMIBObjects;
+       /* OPENBSD-CARP-MIB */
+       struct agentx_region *carpMIBObjects;
+       /* OPENBSD-MEM-MIB */
+       struct agentx_region *memMIBObjects;
+       /* IP-MIB */
+       struct agentx_region *ip;
+       /* IP-FORWARD-MIB */
+       struct agentx_region *ipForward;
+       /* UCD-DISKIO-MIB */
+       struct agentx_region *ucdDiskIOMIB;
+       /* BRIDGE-MIB */
+       struct agentx_region *dot1dBridge;
+
+       snmpd_env = &conf;
+       log_init(2, LOG_DAEMON);
+
+       agentx_log_fatal = fatalx;
+       agentx_log_warn = log_warnx;
+       agentx_log_info = log_info;
+       agentx_log_debug = log_debug;
+
+       while ((ch = getopt(argc, argv, "C:c:ds:vx:")) != -1) {
+               switch (ch) {
+               case 'C':
+                       if (strcmp(optarg, "filter-routes") == 0) {
+                               conf.sc_rtfilter = 1;
+                       }
+                       break;
+               case 'c':
+                       context = optarg;
+                       break;
+               case 'd':
+                       daemonize = 0;
+                       debug = 1;
+                       break;
+               case 's':
+                       if (optarg[0] != '/')
+                               fatalx("agentx socket path must be absolute");
+                       agentxsocket = optarg;
+                       break;
+               case 'v':
+                       verbose++;
+                       break;
+               case 'x':
+                       /* Undocumented flag for snmpd(8) spawning */
+                       agentxfd = strtonum(optarg, 0, INT_MAX, &errstr);
+                       if (errstr != NULL)
+                               fatalx("invalid agentx fd: %s", errstr);
+                       daemonize = 0;
+                       break;
+               default:
+                       fatalx("usage: snmpd_metrics [-dv] [-C option] "
+                           "[-c context] [-s master]\n");
+               }
+       }
+
+       if (agentxfd != -1 && !debug)
+               /* Initialize syslog logging asap for snmpd */
+               log_init(0, LOG_DAEMON);
+
+       if ((pw = getpwnam("_snmpd")) == NULL)
+               fatal("can't find _snmpd user");
+       if ((gr = getgrnam("_agentx")) == NULL)
+               fatal("can't find _agentx group");
+
+       if (agentxfd != -1 && agentxsocket != NULL)
+               fatalx("-s and -x are mutually exclusive");
+       if (agentxfd == -1 && agentxsocket == NULL)
+               agentxsocket = AGENTX_MASTER_PATH;
+
+       event_init();
+
+       if ((sa = agentx(snmp_connect, NULL)) == NULL)
+               fatal("agentx");
+       if ((sas = agentx_session(sa, NULL, 0, "OpenSNMPd metrics", 0)) == NULL)
+               fatal("agentx_session");
+       if ((sac = agentx_context(sas, context)) == NULL)
+               fatal("agentx_context");
+
+       /* kr_init requires sac */
+       kr_init();
+       pf_init();
+       timer_init();
+
+       if (agentxsocket != NULL) {
+               if (strlcpy(agentxsocketdir, agentxsocket,
+                   sizeof(agentxsocketdir)) >= sizeof(agentxsocketdir)) {
+                       errno = ENAMETOOLONG;
+                       fatal("-s");
+               }
+               if (unveil(dirname(agentxsocketdir), "r") == -1)
+                       fatal("unveil");
+       }
+
+       /* Can't pledge: kvm_getfiles */
+       if (unveil(NULL, NULL) == -1)
+               fatal("unveil");
+
+       if (setgid(gr->gr_gid) == -1)
+               fatal("setgid");
+       if (setuid(pw->pw_uid) == -1)
+               fatal("setuid");
+
+       /* HOST-RESOURCES-MIB */
+       if ((host = agentx_region(sac, AGENTX_OID(HOST), 0)) == NULL)
+               fatal("agentx_region");
+
+       if ((hrSystemUptime = agentx_object(host, AGENTX_OID(HRSYSTEMUPTIME),
+           NULL, 0, 0, mib_hrsystemuptime)) == NULL ||
+           (hrSystemDate = agentx_object(host, AGENTX_OID(HRSYSTEMDATE),
+           NULL, 0, 0, mib_hrsystemdate)) == NULL ||
+           (hrSystemProcesses = agentx_object(host,
+           AGENTX_OID(HRSYSTEMPROCESSES), NULL, 0, 0,
+           mib_hrsystemprocs)) == NULL ||
+           (hrSystemMaxProcesses = agentx_object(host,
+           AGENTX_OID(HRSYSTEMMAXPROCESSES), NULL, 0, 0,
+           mib_hrsystemprocs)) == NULL ||
+           (hrMemorySize = agentx_object(host, AGENTX_OID(HRMEMORYSIZE),
+           NULL, 0, 0, mib_hrmemory)) == NULL)
+               fatal("agentx_object");
+
+       if ((hrStorageIdx = agentx_index_integer_dynamic(host,
+           AGENTX_OID(HRSTORAGEINDEX))) == NULL)
+               fatal("agentx_index_integer_dynamic");
+       if ((hrStorageIndex = agentx_object(host, AGENTX_OID(HRSTORAGEINDEX),
+           &hrStorageIdx, 1, 0, mib_hrstorage)) == NULL ||
+           (hrStorageType = agentx_object(host, AGENTX_OID(HRSTORAGETYPE),
+           &hrStorageIdx, 1, 0, mib_hrstorage)) == NULL ||
+           (hrStorageDescr = agentx_object(host, AGENTX_OID(HRSTORAGEDESCR),
+           &hrStorageIdx, 1, 0, mib_hrstorage)) == NULL ||
+           (hrStorageAllocationUnits = agentx_object(host,
+           AGENTX_OID(HRSTORAGEALLOCATIONUNITS), &hrStorageIdx, 1, 0,
+           mib_hrstorage)) == NULL ||
+           (hrStorageSize = agentx_object(host, AGENTX_OID(HRSTORAGESIZE),
+           &hrStorageIdx, 1, 0, mib_hrstorage)) == NULL ||
+           (hrStorageUsed = agentx_object(host, AGENTX_OID(HRSTORAGEUSED),
+           &hrStorageIdx, 1, 0, mib_hrstorage)) == NULL ||
+           (hrStorageAllocationFailures = agentx_object(host,
+           AGENTX_OID(HRSTORAGEALLOCATIONFAILURES), &hrStorageIdx, 1, 0,
+           mib_hrstorage)) == NULL)
+               fatal("agentx_object");
+
+       if ((hrDeviceIdx = agentx_index_integer_dynamic(host,
+           AGENTX_OID(HRDEVICEINDEX))) == NULL)
+               fatal("agentx_index_integer_dynamic");
+       if ((hrDeviceIndex = agentx_object(host, AGENTX_OID(HRDEVICEINDEX),
+           &hrDeviceIdx, 1, 0, mib_hrdevice)) == NULL ||
+           (hrDeviceType = agentx_object(host, AGENTX_OID(HRDEVICETYPE),
+           &hrDeviceIdx, 1, 0, mib_hrdevice)) == NULL |
+           (hrDeviceDescr = agentx_object(host, AGENTX_OID(HRDEVICEDESCR),
+           &hrDeviceIdx, 1, 0, mib_hrdevice)) == NULL ||
+           (hrDeviceID = agentx_object(host, AGENTX_OID(HRDEVICEID),
+           &hrDeviceIdx, 1, 0, mib_hrdevice)) == NULL ||
+           (hrDeviceStatus = agentx_object(host, AGENTX_OID(HRDEVICESTATUS),
+           &hrDeviceIdx, 1, 0, mib_hrdevice)) == NULL ||
+           (hrDeviceErrors = agentx_object(host, AGENTX_OID(HRDEVICEERRORS),
+           &hrDeviceIdx, 1, 0, mib_hrdevice)) == NULL)
+               fatal("agentx_object");
+       if ((hrProcessorFrwID = agentx_object(host, AGENTX_OID(HRPROCESSORFRWID),
+           &hrDeviceIdx, 1, 0, mib_hrprocessor)) == NULL ||
+           (hrProcessorLoad = agentx_object(host, AGENTX_OID(HRPROCESSORLOAD),
+           &hrDeviceIdx, 1, 0, mib_hrprocessor)) == NULL)
+               fatal("agentx_object");
+       if ((hrSWRunIdx = agentx_index_integer_dynamic(host,
+           AGENTX_OID(HRSWRUNINDEX))) == NULL)
+               fatal("agentx_index_integer_dynamic");
+       if ((hrSWRunIndex = agentx_object(host, AGENTX_OID(HRSWRUNINDEX),
+           &hrSWRunIdx, 1, 0, mib_hrswrun)) == NULL ||
+           (hrSWRunName = agentx_object(host, AGENTX_OID(HRSWRUNNAME),
+           &hrSWRunIdx, 1, 0, mib_hrswrun)) == NULL ||
+           (hrSWRunID = agentx_object(host, AGENTX_OID(HRSWRUNID),
+           &hrSWRunIdx, 1, 0, mib_hrswrun)) == NULL ||
+           (hrSWRunPath = agentx_object(host, AGENTX_OID(HRSWRUNPATH),
+           &hrSWRunIdx, 1, 0, mib_hrswrun)) == NULL ||
+           (hrSWRunParameters = agentx_object(host,
+           AGENTX_OID(HRSWRUNPARAMETERS), &hrSWRunIdx, 1, 0,
+           mib_hrswrun)) == NULL ||
+           (hrSWRunType = agentx_object(host, AGENTX_OID(HRSWRUNTYPE),
+           &hrSWRunIdx, 1, 0, mib_hrswrun)) == NULL ||
+           (hrSWRunStatus = agentx_object(host, AGENTX_OID(HRSWRUNSTATUS),
+           &hrSWRunIdx, 1, 0, mib_hrswrun)) == NULL)
+               fatal("agentx_object");
+
+       /* IF-MIB */
+       if ((ifMIB = agentx_region(sac, AGENTX_OID(IFMIB), 0)) == NULL ||
+           (interfaces = agentx_region(sac,
+           AGENTX_OID(INTERFACES), 0)) == NULL)
+               fatal("agentx_region");
+
+       if ((ifIdx = agentx_index_integer_dynamic(interfaces,
+           AGENTX_OID(IFINDEX))) == NULL)
+               fatal("agentx_index_integer_dynamic");
+       if ((ifName = agentx_object(ifMIB, AGENTX_OID(IFNAME),
+           &ifIdx, 1, 0, mib_ifxtable)) == NULL ||
+           (ifInMulticastPkts = agentx_object(ifMIB,
+           AGENTX_OID(IFINMULTICASTPKTS), &ifIdx, 1, 0,
+           mib_ifxtable)) == NULL ||
+           (ifInBroadcastPkts = agentx_object(ifMIB,
+           AGENTX_OID(IFINBROADCASTPKTS), &ifIdx, 1, 0,
+           mib_ifxtable)) == NULL ||
+           (ifOutMulticastPkts = agentx_object(ifMIB,
+           AGENTX_OID(IFOUTMULTICASTPKTS), &ifIdx, 1, 0,
+           mib_ifxtable)) == NULL ||
+           (ifOutBroadcastPkts = agentx_object(ifMIB,
+           AGENTX_OID(IFOUTBROADCASTPKTS), &ifIdx, 1, 0,
+           mib_ifxtable)) == NULL ||
+           (ifHCInOctets = agentx_object(ifMIB, AGENTX_OID(IFHCINOCTETS),
+           &ifIdx, 1, 0, mib_ifxtable)) == NULL ||
+           (ifHCInUcastPkts = agentx_object(ifMIB, AGENTX_OID(IFHCINUCASTPKTS),
+           &ifIdx, 1, 0, mib_ifxtable)) == NULL ||
+           (ifHCInMulticastPkts = agentx_object(ifMIB,
+           AGENTX_OID(IFHCINMULTICASTPKTS), &ifIdx, 1, 0,
+           mib_ifxtable)) == NULL ||
+           (ifHCInBroadcastPkts = agentx_object(ifMIB,
+           AGENTX_OID(IFHCINBROADCASTPKTS), &ifIdx, 1, 0,
+           mib_ifxtable)) == NULL ||
+           (ifHCOutOctets = agentx_object(ifMIB, AGENTX_OID(IFHCOUTOCTETS),
+           &ifIdx, 1, 0, mib_ifxtable)) == NULL ||
+           (ifHCOutUcastPkts = agentx_object(ifMIB,
+           AGENTX_OID(IFHCOUTUCASTPKTS), &ifIdx, 1, 0,
+           mib_ifxtable)) == NULL ||
+           (ifHCOutMulticastPkts = agentx_object(ifMIB,
+           AGENTX_OID(IFHCOUTMULTICASTPKTS), &ifIdx, 1, 0,
+           mib_ifxtable)) == NULL ||
+           (ifHCOutBroadcastPkts = agentx_object(ifMIB,
+           AGENTX_OID(IFHCOUTBROADCASTPKTS), &ifIdx, 1, 0,
+           mib_ifxtable)) == NULL ||
+           (ifLinkUpDownTrapEnable = agentx_object(ifMIB,
+           AGENTX_OID(IFLINKUPDOWNTRAPENABLE), &ifIdx, 1, 0,
+           mib_ifxtable)) == NULL ||
+           (ifHighSpeed = agentx_object(ifMIB, AGENTX_OID(IFHIGHSPEED),
+           &ifIdx, 1, 0, mib_ifxtable)) == NULL ||
+           (ifPromiscuousMode = agentx_object(ifMIB,
+           AGENTX_OID(IFPROMISCUOUSMODE), &ifIdx, 1, 0,
+           mib_ifxtable)) == NULL ||
+           (ifConnectorPresent = agentx_object(ifMIB,
+           AGENTX_OID(IFCONNECTORPRESENT), &ifIdx, 1, 0,
+           mib_ifxtable)) == NULL ||
+           (ifAlias = agentx_object(ifMIB, AGENTX_OID(IFALIAS),
+           &ifIdx, 1, 0, mib_ifxtable)) == NULL ||
+           (ifCounterDiscontinuityTime = agentx_object(ifMIB,
+           AGENTX_OID(IFCOUNTERDISCONTINUITYTIME), &ifIdx, 1, 0,
+           mib_ifxtable)) == NULL)
+               fatal("agentx_object");
+
+       if ((ifRcvAddressAddress = agentx_index_string_dynamic(ifMIB,
+           AGENTX_OID(IFRCVADDRESSADDRESS))) == NULL)
+               fatal("agentx_index_string_dynamic");
+       indices[0] = ifIdx;
+       indices[1] = ifRcvAddressAddress;
+       if ((ifRcvAddressStatus = agentx_object(ifMIB,
+           AGENTX_OID(IFRCVADDRESSSTATUS), indices, 2, 0,
+           mib_ifrcvtable)) == NULL ||
+           (ifRcvAddressType = agentx_object(ifMIB,
+           AGENTX_OID(IFRCVADDRESSTYPE), indices, 2, 0,
+           mib_ifrcvtable)) == NULL)
+               fatal("agentx_object");
+
+       if ((ifStackLastChange = agentx_object(ifMIB,
+           AGENTX_OID(IFSTACKLASTCHANGE), NULL, 0, 0,
+           mib_ifstacklast)) == NULL)
+               fatal("agentx_object");
+
+       if ((ifNumber = agentx_object(interfaces, AGENTX_OID(IFNUMBER),
+           NULL, 0, 0, mib_ifnumber)) == NULL)
+               fatal("agentx_object");
+
+       if ((ifIndex = agentx_object(interfaces, AGENTX_OID(IFINDEX),
+           &ifIdx, 1, 0, mib_iftable)) == NULL ||
+           (ifDescr = agentx_object(interfaces, AGENTX_OID(IFDESCR),
+           &ifIdx, 1, 0, mib_iftable)) == NULL ||
+           (ifType = agentx_object(interfaces, AGENTX_OID(IFTYPE),
+           &ifIdx, 1, 0, mib_iftable)) == NULL ||
+           (ifMtu = agentx_object(interfaces, AGENTX_OID(IFMTU),
+           &ifIdx, 1, 0, mib_iftable)) == NULL ||
+           (ifSpeed = agentx_object(interfaces, AGENTX_OID(IFSPEED),
+           &ifIdx, 1, 0, mib_iftable)) == NULL ||
+           (ifPhysAddress = agentx_object(interfaces,
+           AGENTX_OID(IFPHYSADDRESS), &ifIdx, 1, 0, mib_iftable)) == NULL ||
+           (ifAdminStatus = agentx_object(interfaces,
+           AGENTX_OID(IFADMINSTATUS), &ifIdx, 1, 0, mib_iftable)) == NULL ||
+           (ifOperStatus = agentx_object(interfaces,
+           AGENTX_OID(IFOPERSTATUS), &ifIdx, 1, 0, mib_iftable)) == NULL ||
+           (ifLastChange = agentx_object(interfaces,
+           AGENTX_OID(IFLASTCHANGE), &ifIdx, 1, 0, mib_iftable)) == NULL ||
+           (ifInOctets = agentx_object(interfaces, AGENTX_OID(IFINOCTETS),
+           &ifIdx, 1, 0, mib_iftable)) == NULL ||
+           (ifInUcastPkts = agentx_object(interfaces,
+           AGENTX_OID(IFINUCASTPKTS), &ifIdx, 1, 0, mib_iftable)) == NULL ||
+           (ifInNUcastPkts = agentx_object(interfaces,
+           AGENTX_OID(IFINNUCASTPKTS), &ifIdx, 1, 0, mib_iftable)) == NULL ||
+           (ifInDiscards = agentx_object(interfaces,
+           AGENTX_OID(IFINDISCARDS), &ifIdx, 1, 0, mib_iftable)) == NULL ||
+           (ifInErrors = agentx_object(interfaces, AGENTX_OID(IFINERRORS),
+           &ifIdx, 1, 0, mib_iftable)) == NULL ||
+           (ifInUnknownProtos = agentx_object(interfaces,
+           AGENTX_OID(IFINUNKNOWNPROTOS), &ifIdx, 1, 0,
+           mib_iftable)) == NULL ||
+           (ifOutOctets = agentx_object(interfaces, AGENTX_OID(IFOUTOCTETS),
+           &ifIdx, 1, 0, mib_iftable)) == NULL ||
+           (ifOutUcastPkts = agentx_object(interfaces,
+           AGENTX_OID(IFOUTUCASTPKTS), &ifIdx, 1, 0, mib_iftable)) == NULL ||
+           (ifOutNUcastPkts = agentx_object(interfaces,
+           AGENTX_OID(IFOUTNUCASTPKTS), &ifIdx, 1, 0, mib_iftable)) == NULL ||
+           (ifOutDiscards = agentx_object(interfaces,
+           AGENTX_OID(IFOUTDISCARDS), &ifIdx, 1, 0, mib_iftable)) == NULL ||
+           (ifOutErrors = agentx_object(interfaces, AGENTX_OID(IFOUTERRORS),
+           &ifIdx, 1, 0, mib_iftable)) == NULL ||
+           (ifOutQLen = agentx_object(interfaces, AGENTX_OID(IFOUTQLEN),
+           &ifIdx, 1, 0, mib_iftable)) == NULL ||
+           (ifSpecific = agentx_object(interfaces, AGENTX_OID(IFSPECIFIC),
+           &ifIdx, 1, 0, mib_iftable)) == NULL)
+               fatal("agentx_object");
+
+       /* OPENBSD-PF-MIB */
+       if ((pfMIBObjects = agentx_region(sac,
+           AGENTX_OID(PFMIBOBJECTS), 0)) == NULL)
+               fatal("agentx_region");
+       if ((pfRunning = agentx_object(pfMIBObjects, AGENTX_OID(PFRUNNING),
+           NULL, 0, 0, mib_pfinfo)) == NULL ||
+           (pfRuntime = agentx_object(pfMIBObjects, AGENTX_OID(PFRUNTIME),
+           NULL, 0, 0, mib_pfinfo)) == NULL ||
+           (pfDebug = agentx_object(pfMIBObjects, AGENTX_OID(PFDEBUG),
+           NULL, 0, 0, mib_pfinfo)) == NULL ||
+           (pfHostid = agentx_object(pfMIBObjects, AGENTX_OID(PFHOSTID),
+           NULL, 0, 0, mib_pfinfo)) == NULL)
+               fatal("agentx_object");
+
+       if ((pfCntMatch = agentx_object(pfMIBObjects, AGENTX_OID(PFCNTMATCH),
+           NULL, 0, 0, mib_pfcounters)) == NULL ||
+           (pfCntBadOffset = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFCNTBADOFFSET), NULL, 0, 0, mib_pfcounters)) == NULL ||
+           (pfCntFragment = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFCNTFRAGMENT), NULL, 0, 0, mib_pfcounters)) == NULL ||
+           (pfCntShort = agentx_object(pfMIBObjects, AGENTX_OID(PFCNTSHORT),
+           NULL, 0, 0, mib_pfcounters)) == NULL ||
+           (pfCntNormalize = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFCNTNORMALIZE), NULL, 0, 0, mib_pfcounters)) == NULL ||
+           (pfCntMemory = agentx_object(pfMIBObjects, AGENTX_OID(PFCNTMEMORY),
+           NULL, 0, 0, mib_pfcounters)) == NULL ||
+           (pfCntTimestamp = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFCNTTIMESTAMP), NULL, 0, 0, mib_pfcounters)) == NULL ||
+           (pfCntCongestion = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFCNTCONGESTION), NULL, 0, 0, mib_pfcounters)) == NULL ||
+           (pfCntIpOption = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFCNTIPOPTION), NULL, 0, 0, mib_pfcounters)) == NULL ||
+           (pfCntProtoCksum = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFCNTPROTOCKSUM), NULL, 0, 0, mib_pfcounters)) == NULL ||
+           (pfCntStateMismatch = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFCNTSTATEMISMATCH), NULL, 0, 0,
+           mib_pfcounters)) == NULL ||
+           (pfCntStateInsert = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFCNTSTATEINSERT), NULL, 0, 0,
+           mib_pfcounters)) == NULL ||
+           (pfCntStateLimit = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFCNTSTATELIMIT), NULL, 0, 0, mib_pfcounters)) == NULL ||
+           (pfCntSrcLimit = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFCNTSRCLIMIT), NULL, 0, 0, mib_pfcounters)) == NULL ||
+           (pfCntSynproxy = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFCNTSYNPROXY), NULL, 0, 0, mib_pfcounters)) == NULL ||
+           (pfCntTranslate = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFCNTTRANSLATE), NULL, 0, 0, mib_pfcounters)) == NULL ||
+           (pfCntNoRoute = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFCNTNOROUTE), NULL, 0, 0, mib_pfcounters)) == NULL)
+               fatal("agentx_object");
+
+       if ((pfStateCount = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFSTATECOUNT), NULL, 0, 0, mib_pfscounters)) == NULL ||
+           (pfStateSearches = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFSTATESEARCHES), NULL, 0, 0,
+           mib_pfscounters)) == NULL ||
+           (pfStateInserts = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFSTATEINSERTS), NULL, 0, 0, mib_pfscounters)) == NULL ||
+           (pfStateRemovals = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFSTATEREMOVALS), NULL, 0, 0, mib_pfscounters)) == NULL)
+               fatal("agentx_object");
+
+       if ((pfLogIfName = agentx_object(pfMIBObjects, AGENTX_OID(PFLOGIFNAME),
+           NULL, 0, 0, mib_pflogif)) == NULL ||
+           (pfLogIfIpBytesIn = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFLOGIFIPBYTESIN), NULL, 0, 0, mib_pflogif)) == NULL ||
+           (pfLogIfIpBytesOut = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFLOGIFIPBYTESOUT), NULL, 0, 0, mib_pflogif)) == NULL ||
+           (pfLogIfIpPktsInPass = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFLOGIFIPPKTSINPASS), NULL, 0, 0,
+           mib_pflogif)) == NULL ||
+           (pfLogIfIpPktsInDrop = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFLOGIFIPPKTSINDROP), NULL, 0, 0,
+           mib_pflogif)) == NULL ||
+           (pfLogIfIpPktsOutPass = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFLOGIFIPPKTSOUTPASS), NULL, 0, 0,
+           mib_pflogif)) == NULL ||
+           (pfLogIfIpPktsOutDrop = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFLOGIFIPPKTSOUTDROP), NULL, 0, 0,
+           mib_pflogif)) == NULL ||
+           (pfLogIfIp6BytesIn = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFLOGIFIP6BYTESIN), NULL, 0, 0, mib_pflogif)) == NULL ||
+           (pfLogIfIp6BytesOut = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFLOGIFIP6BYTESOUT), NULL, 0, 0, mib_pflogif)) == NULL ||
+           (pfLogIfIp6PktsInPass = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFLOGIFIP6PKTSINPASS), NULL, 0, 0,
+           mib_pflogif)) == NULL ||
+           (pfLogIfIp6PktsInDrop = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFLOGIFIP6PKTSINDROP), NULL, 0, 0,
+           mib_pflogif)) == NULL ||
+           (pfLogIfIp6PktsOutPass = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFLOGIFIP6PKTSOUTPASS), NULL, 0, 0,
+           mib_pflogif)) == NULL ||
+           (pfLogIfIp6PktsOutDrop = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFLOGIFIP6PKTSOUTDROP), NULL, 0, 0,
+           mib_pflogif)) == NULL)
+               fatal("agentx_object");
+
+       if ((pfSrcTrackCount = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFSRCTRACKCOUNT), NULL, 0, 0, mib_pfsrctrack)) == NULL ||
+           (pfSrcTrackSearches = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFSRCTRACKSEARCHES), NULL, 0, 0,
+           mib_pfsrctrack)) == NULL ||
+           (pfSrcTrackInserts = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFSRCTRACKINSERTS), NULL, 0, 0,
+           mib_pfsrctrack)) == NULL ||
+           (pfSrcTrackRemovals = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFSRCTRACKREMOVALS), NULL, 0, 0,
+           mib_pfsrctrack)) == NULL)
+               fatal("agentx_object");
+
+       if ((pfLimitStates = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFLIMITSTATES), NULL, 0, 0, mib_pflimits)) == NULL ||
+           (pfLimitSourceNodes = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFLIMITSOURCENODES), NULL, 0, 0,
+           mib_pflimits)) == NULL ||
+           (pfLimitFragments = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFLIMITFRAGMENTS), NULL, 0, 0, mib_pflimits)) == NULL ||
+           (pfLimitMaxTables = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFLIMITMAXTABLES), NULL, 0, 0, mib_pflimits)) == NULL ||
+           (pfLimitMaxTableEntries = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFLIMITMAXTABLEENTRIES), NULL, 0, 0,
+           mib_pflimits)) == NULL)
+               fatal("agentx_object");
+
+       if ((pfTimeoutTcpFirst = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFTIMEOUTTCPFIRST), NULL, 0, 0,
+           mib_pftimeouts)) == NULL ||
+           (pfTimeoutTcpOpening = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFTIMEOUTTCPOPENING), NULL, 0, 0,
+           mib_pftimeouts)) == NULL ||
+           (pfTimeoutTcpEstablished = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFTIMEOUTTCPESTABLISHED), NULL, 0, 0,
+           mib_pftimeouts)) == NULL ||
+           (pfTimeoutTcpClosing = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFTIMEOUTTCPCLOSING), NULL, 0, 0,
+           mib_pftimeouts)) == NULL ||
+           (pfTimeoutTcpFinWait = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFTIMEOUTTCPFINWAIT), NULL, 0, 0,
+           mib_pftimeouts)) == NULL ||
+           (pfTimeoutTcpClosed = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFTIMEOUTTCPCLOSED), NULL, 0, 0,
+           mib_pftimeouts)) == NULL ||
+           (pfTimeoutUdpFirst = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFTIMEOUTUDPFIRST), NULL, 0, 0,
+           mib_pftimeouts)) == NULL ||
+           (pfTimeoutUdpSingle = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFTIMEOUTUDPSINGLE), NULL, 0, 0,
+           mib_pftimeouts)) == NULL ||
+           (pfTimeoutUdpMultiple = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFTIMEOUTUDPMULTIPLE), NULL, 0, 0,
+           mib_pftimeouts)) == NULL ||
+           (pfTimeoutIcmpFirst = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFTIMEOUTICMPFIRST), NULL, 0, 0,
+           mib_pftimeouts)) == NULL ||
+           (pfTimeoutIcmpError = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFTIMEOUTICMPERROR), NULL, 0, 0,
+           mib_pftimeouts)) == NULL ||
+           (pfTimeoutOtherFirst = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFTIMEOUTOTHERFIRST), NULL, 0, 0,
+           mib_pftimeouts)) == NULL ||
+           (pfTimeoutOtherSingle = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFTIMEOUTOTHERSINGLE), NULL, 0, 0,
+           mib_pftimeouts)) == NULL ||
+           (pfTimeoutOtherMultiple = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFTIMEOUTOTHERMULTIPLE), NULL, 0, 0,
+           mib_pftimeouts)) == NULL ||
+           (pfTimeoutFragment = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFTIMEOUTFRAGMENT), NULL, 0, 0,
+           mib_pftimeouts)) == NULL ||
+           (pfTimeoutInterval = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFTIMEOUTINTERVAL), NULL, 0, 0,
+           mib_pftimeouts)) == NULL ||
+           (pfTimeoutAdaptiveStart = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFTIMEOUTADAPTIVESTART), NULL, 0, 0,
+           mib_pftimeouts)) == NULL ||
+           (pfTimeoutAdaptiveEnd = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFTIMEOUTADAPTIVEEND), NULL, 0, 0,
+           mib_pftimeouts)) == NULL ||
+           (pfTimeoutSrcTrack = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFTIMEOUTSRCTRACK), NULL, 0, 0,
+           mib_pftimeouts)) == NULL)
+               fatal("agentx_object");
+
+       if ((pfIfNumber = agentx_object(pfMIBObjects, AGENTX_OID(PFIFNUMBER),
+           NULL, 0, 0, mib_pfifnum)) == NULL)
+               fatal("agentx_object");
+       if ((pfIfIdx = agentx_index_integer_dynamic(pfMIBObjects,
+           AGENTX_OID(PFIFINDEX))) == NULL)
+               fatal("agentx_index_integer_dynamic");
+       if ((pfIfIndex = agentx_object(pfMIBObjects, AGENTX_OID(PFIFINDEX),
+           &pfIfIdx, 1, 0, mib_pfiftable)) == NULL ||
+           (pfIfDescr = agentx_object(pfMIBObjects, AGENTX_OID(PFIFDESCR),
+           &pfIfIdx, 1, 0, mib_pfiftable)) == NULL ||
+           (pfIfType = agentx_object(pfMIBObjects, AGENTX_OID(PFIFTYPE),
+           &pfIfIdx, 1, 0, mib_pfiftable)) == NULL ||
+           (pfIfRefs = agentx_object(pfMIBObjects, AGENTX_OID(PFIFREFS),
+           &pfIfIdx, 1, 0, mib_pfiftable)) == NULL ||
+           (pfIfRules = agentx_object(pfMIBObjects, AGENTX_OID(PFIFRULES),
+           &pfIfIdx, 1, 0, mib_pfiftable)) == NULL ||
+           (pfIfIn4PassPkts = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFIFIN4PASSPKTS), &pfIfIdx, 1, 0,
+           mib_pfiftable)) == NULL ||
+           (pfIfIn4PassBytes = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFIFIN4PASSBYTES), &pfIfIdx, 1, 0,
+           mib_pfiftable)) == NULL ||
+           (pfIfIn4BlockPkts = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFIFIN4BLOCKPKTS), &pfIfIdx, 1, 0,
+           mib_pfiftable)) == NULL ||
+           (pfIfIn4BlockBytes = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFIFIN4BLOCKBYTES), &pfIfIdx, 1, 0,
+           mib_pfiftable)) == NULL ||
+           (pfIfOut4PassPkts = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFIFOUT4PASSPKTS), &pfIfIdx, 1, 0,
+           mib_pfiftable)) == NULL ||
+           (pfIfOut4PassBytes = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFIFOUT4PASSBYTES), &pfIfIdx, 1, 0,
+           mib_pfiftable)) == NULL ||
+           (pfIfOut4BlockPkts = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFIFOUT4BLOCKPKTS), &pfIfIdx, 1, 0,
+           mib_pfiftable)) == NULL ||
+           (pfIfOut4BlockBytes = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFIFOUT4BLOCKBYTES), &pfIfIdx, 1, 0,
+           mib_pfiftable)) == NULL ||
+           (pfIfIn6PassPkts = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFIFIN6PASSPKTS), &pfIfIdx, 1, 0,
+           mib_pfiftable)) == NULL ||
+           (pfIfIn6PassBytes = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFIFIN6PASSBYTES), &pfIfIdx, 1, 0,
+           mib_pfiftable)) == NULL ||
+           (pfIfIn6BlockPkts = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFIFIN6BLOCKPKTS), &pfIfIdx, 1, 0,
+           mib_pfiftable)) == NULL ||
+           (pfIfIn6BlockBytes = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFIFIN6BLOCKBYTES), &pfIfIdx, 1, 0,
+           mib_pfiftable)) == NULL ||
+           (pfIfOut6PassPkts = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFIFOUT6PASSPKTS), &pfIfIdx, 1, 0,
+           mib_pfiftable)) == NULL ||
+           (pfIfOut6PassBytes = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFIFOUT6PASSBYTES), &pfIfIdx, 1, 0,
+           mib_pfiftable)) == NULL ||
+           (pfIfOut6BlockPkts = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFIFOUT6BLOCKPKTS), &pfIfIdx, 1, 0,
+           mib_pfiftable)) == NULL ||
+           (pfIfOut6BlockBytes = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFIFOUT6BLOCKBYTES), &pfIfIdx, 1, 0,
+           mib_pfiftable)) == NULL)
+               fatal("agentx_object");
+
+       if ((pfTblNumber = agentx_object(pfMIBObjects, AGENTX_OID(PFTBLNUMBER),
+           NULL, 0, 0, mib_pftablenum)) == NULL)
+               fatal("agentx_object");
+       if ((pfTblIdx = agentx_index_integer_dynamic(pfMIBObjects,
+           AGENTX_OID(PFTBLINDEX))) == NULL)
+               fatal("agentx_index_integer_dynamic");
+       if ((pfTblIndex = agentx_object(pfMIBObjects, AGENTX_OID(PFTBLINDEX),
+           &pfTblIdx, 1, 0, mib_pftables)) == NULL ||
+           (pfTblName = agentx_object(pfMIBObjects, AGENTX_OID(PFTBLNAME),
+           &pfTblIdx, 1, 0, mib_pftables)) == NULL ||
+           (pfTblAddresses = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFTBLADDRESSES), &pfTblIdx, 1, 0,
+           mib_pftables)) == NULL ||
+           (pfTblAnchorRefs = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFTBLANCHORREFS), &pfTblIdx, 1, 0,
+           mib_pftables)) == NULL ||
+           (pfTblRuleRefs = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFTBLRULEREFS), &pfTblIdx, 1, 0,
+           mib_pftables)) == NULL ||
+           (pfTblEvalsMatch = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFTBLEVALSMATCH), &pfTblIdx, 1, 0,
+           mib_pftables)) == NULL ||
+           (pfTblEvalsNoMatch = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFTBLEVALSNOMATCH), &pfTblIdx, 1, 0,
+           mib_pftables)) == NULL ||
+           (pfTblInPassPkts = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFTBLINPASSPKTS), &pfTblIdx, 1, 0,
+           mib_pftables)) == NULL ||
+           (pfTblInPassBytes = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFTBLINPASSBYTES), &pfTblIdx, 1, 0,
+           mib_pftables)) == NULL ||
+           (pfTblInBlockPkts = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFTBLINBLOCKPKTS), &pfTblIdx, 1, 0,
+           mib_pftables)) == NULL ||
+           (pfTblInBlockBytes = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFTBLINBLOCKBYTES), &pfTblIdx, 1, 0,
+           mib_pftables)) == NULL ||
+           (pfTblInXPassPkts = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFTBLINXPASSPKTS), &pfTblIdx, 1, 0,
+           mib_pftables)) == NULL ||
+           (pfTblInXPassBytes = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFTBLINXPASSBYTES), &pfTblIdx, 1, 0,
+           mib_pftables)) == NULL ||
+           (pfTblOutPassPkts = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFTBLOUTPASSPKTS), &pfTblIdx, 1, 0,
+           mib_pftables)) == NULL ||
+           (pfTblOutPassBytes = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFTBLOUTPASSBYTES), &pfTblIdx, 1, 0,
+           mib_pftables)) == NULL ||
+           (pfTblOutBlockPkts = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFTBLOUTBLOCKPKTS), &pfTblIdx, 1, 0,
+           mib_pftables)) == NULL ||
+           (pfTblOutBlockBytes = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFTBLOUTBLOCKBYTES), &pfTblIdx, 1, 0,
+           mib_pftables)) == NULL ||
+           (pfTblOutXPassPkts = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFTBLOUTXPASSPKTS), &pfTblIdx, 1, 0,
+           mib_pftables)) == NULL ||
+           (pfTblOutXPassBytes = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFTBLOUTXPASSBYTES), &pfTblIdx, 1, 0,
+           mib_pftables)) == NULL ||
+           (pfTblStatsCleared = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFTBLSTATSCLEARED), &pfTblIdx, 1, 0,
+           mib_pftables)) == NULL ||
+           (pfTblInMatchPkts = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFTBLINMATCHPKTS), &pfTblIdx, 1, 0,
+           mib_pftables)) == NULL ||
+           (pfTblInMatchBytes = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFTBLINMATCHBYTES), &pfTblIdx, 1, 0,
+           mib_pftables)) == NULL ||
+           (pfTblOutMatchPkts = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFTBLOUTMATCHPKTS), &pfTblIdx, 1, 0,
+           mib_pftables)) == NULL ||
+           (pfTblOutMatchBytes = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFTBLOUTMATCHBYTES), &pfTblIdx, 1, 0,
+           mib_pftables)) == NULL)
+               fatal("agentx_object");
+
+       if ((pfTblAddrTblIdx = agentx_index_integer_dynamic(pfMIBObjects,
+           AGENTX_OID(PFTBLADDRTBLINDEX))) == NULL ||
+           (pfTblAddrNetIdx = agentx_index_ipaddress_dynamic(pfMIBObjects,
+           AGENTX_OID(PFTBLADDRNET))) == NULL ||
+           (pfTblAddrMaskIdx = agentx_index_integer_dynamic(pfMIBObjects,
+           AGENTX_OID(PFTBLADDRMASK))) == NULL)
+               fatal("agentx_index_integer_dynamic");
+       indices[0] = pfTblAddrTblIdx;
+       indices[1] = pfTblAddrNetIdx;
+       indices[2] = pfTblAddrMaskIdx;
+       if ((pfTblAddrTblIndex = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFTBLADDRTBLINDEX), indices, 3, 0,
+           mib_pftableaddrs)) == NULL ||
+           (pfTblAddrNet = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFTBLADDRNET), indices, 3, 0,
+           mib_pftableaddrs)) == NULL ||
+           (pfTblAddrMask = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFTBLADDRMASK), indices, 3, 0,
+           mib_pftableaddrs)) == NULL ||
+           (pfTblAddrCleared = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFTBLADDRCLEARED), indices, 3, 0,
+           mib_pftableaddrs)) == NULL ||
+           (pfTblAddrInBlockPkts = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFTBLADDRINBLOCKPKTS), indices, 3, 0,
+           mib_pftableaddrs)) == NULL ||
+           (pfTblAddrInBlockBytes = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFTBLADDRINBLOCKBYTES), indices, 3, 0,
+           mib_pftableaddrs)) == NULL ||
+           (pfTblAddrInPassPkts = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFTBLADDRINPASSPKTS), indices, 3, 0,
+           mib_pftableaddrs)) == NULL ||
+           (pfTblAddrInPassBytes = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFTBLADDRINPASSBYTES), indices, 3, 0,
+           mib_pftableaddrs)) == NULL ||
+           (pfTblAddrOutBlockPkts = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFTBLADDROUTBLOCKPKTS), indices, 3, 0,
+           mib_pftableaddrs)) == NULL ||
+           (pfTblAddrOutBlockBytes = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFTBLADDROUTBLOCKBYTES), indices, 3, 0,
+           mib_pftableaddrs)) == NULL ||
+           (pfTblAddrOutPassPkts = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFTBLADDROUTPASSPKTS), indices, 3, 0,
+           mib_pftableaddrs)) == NULL ||
+           (pfTblAddrOutPassBytes = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFTBLADDROUTPASSBYTES), indices, 3, 0,
+           mib_pftableaddrs)) == NULL ||
+           (pfTblAddrInMatchPkts = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFTBLADDRINMATCHPKTS), indices, 3, 0,
+           mib_pftableaddrs)) == NULL ||
+           (pfTblAddrInMatchBytes = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFTBLADDRINMATCHBYTES), indices, 3, 0,
+           mib_pftableaddrs)) == NULL ||
+           (pfTblAddrOutMatchPkts = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFTBLADDROUTMATCHPKTS), indices, 3, 0,
+           mib_pftableaddrs)) == NULL ||
+           (pfTblAddrOutMatchBytes = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFTBLADDROUTMATCHBYTES), indices, 3, 0,
+           mib_pftableaddrs)) == NULL)
+               fatal("agentx_object");
+
+       if ((pfLabelNumber = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFLABELNUMBER), NULL, 0, 0, mib_pflabelnum)) == NULL)
+               fatal("agentx_object");
+       if ((pfLabelIdx = agentx_index_integer_dynamic(pfMIBObjects,
+           AGENTX_OID(PFLABELINDEX))) == NULL)
+               fatal("agentx_index_integer_dynamic");
+       if ((pfLabelIndex = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFLABELINDEX), &pfLabelIdx, 1, 0,
+           mib_pflabels)) == NULL ||
+           (pfLabelName = agentx_object(pfMIBObjects, AGENTX_OID(PFLABELNAME),
+           &pfLabelIdx, 1, 0, mib_pflabels)) == NULL ||
+           (pfLabelEvals = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFLABELEVALS), &pfLabelIdx, 1, 0,
+           mib_pflabels)) == NULL ||
+           (pfLabelPkts = agentx_object(pfMIBObjects, AGENTX_OID(PFLABELPKTS),
+           &pfLabelIdx, 1, 0, mib_pflabels)) == NULL ||
+           (pfLabelBytes = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFLABELBYTES), &pfLabelIdx, 1, 0,
+           mib_pflabels)) == NULL ||
+           (pfLabelInPkts = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFLABELINPKTS), &pfLabelIdx, 1, 0,
+           mib_pflabels)) == NULL ||
+           (pfLabelInBytes = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFLABELINBYTES), &pfLabelIdx, 1, 0,
+           mib_pflabels)) == NULL ||
+           (pfLabelOutPkts = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFLABELOUTPKTS), &pfLabelIdx, 1, 0,
+           mib_pflabels)) == NULL ||
+           (pfLabelOutBytes = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFLABELOUTBYTES), &pfLabelIdx, 1, 0,
+           mib_pflabels)) == NULL ||
+           (pfLabelTotalStates = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFLABELTOTALSTATES), &pfLabelIdx, 1, 0,
+           mib_pflabels)) == NULL)
+               fatal("agentx_object");
+
+       if ((pfsyncIpPktsRecv = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFSYNCIPPKTSRECV), NULL, 0, 0,
+           mib_pfsyncstats)) == NULL ||
+           (pfsyncIp6PktsRecv = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFSYNCIP6PKTSRECV), NULL, 0, 0,
+           mib_pfsyncstats)) == NULL ||
+           (pfsyncPktDiscardsForBadInterface = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFSYNCPKTDISCARDSFORBADINTERFACE), NULL, 0, 0,
+           mib_pfsyncstats)) == NULL ||
+           (pfsyncPktDiscardsForBadTtl = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFSYNCPKTDISCARDSFORBADTTL), NULL, 0, 0,
+           mib_pfsyncstats)) == NULL ||
+           (pfsyncPktShorterThanHeader = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFSYNCPKTSHORTERTHANHEADER), NULL, 0, 0,
+           mib_pfsyncstats)) == NULL ||
+           (pfsyncPktDiscardsForBadVersion = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFSYNCPKTDISCARDSFORBADVERSION), NULL, 0, 0,
+           mib_pfsyncstats)) == NULL ||
+           (pfsyncPktDiscardsForBadAction = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFSYNCPKTDISCARDSFORBADACTION), NULL, 0, 0,
+           mib_pfsyncstats)) == NULL ||
+           (pfsyncPktDiscardsForBadLength = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFSYNCPKTDISCARDSFORBADLENGTH), NULL, 0, 0,
+           mib_pfsyncstats)) == NULL ||
+           (pfsyncPktDiscardsForBadAuth = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFSYNCPKTDISCARDSFORBADAUTH), NULL, 0, 0,
+           mib_pfsyncstats)) == NULL ||
+           (pfsyncPktDiscardsForStaleState = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFSYNCPKTDISCARDSFORSTALESTATE), NULL, 0, 0,
+           mib_pfsyncstats)) == NULL ||
+           (pfsyncPktDiscardsForBadValues = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFSYNCPKTDISCARDSFORBADVALUES), NULL, 0, 0,
+           mib_pfsyncstats)) == NULL ||
+           (pfsyncPktDiscardsForBadState = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFSYNCPKTDISCARDSFORBADSTATE), NULL, 0, 0,
+           mib_pfsyncstats)) == NULL ||
+           (pfsyncIpPktsSent = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFSYNCIPPKTSSENT), NULL, 0, 0,
+           mib_pfsyncstats)) == NULL ||
+           (pfsyncIp6PktsSent = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFSYNCIP6PKTSSENT), NULL, 0, 0,
+           mib_pfsyncstats)) == NULL ||
+           (pfsyncNoMemory = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFSYNCNOMEMORY), NULL, 0, 0,
+           mib_pfsyncstats)) == NULL ||
+           (pfsyncOutputErrors = agentx_object(pfMIBObjects,
+           AGENTX_OID(PFSYNCOUTPUTERRORS), NULL, 0, 0,
+           mib_pfsyncstats)) == NULL)
+               fatal("agentx_object");
+
+       if ((sensorsMIBObjects = agentx_region(sac,
+           AGENTX_OID(SENSORSMIBOBJECTS), 0)) == NULL)
+               fatal("agentx_region");
+       if ((sensorNumber = agentx_object(sensorsMIBObjects,
+           AGENTX_OID(SENSORNUMBER), NULL, 0, 0, mib_sensornum)) == NULL)
+               fatal("agentx_object");
+       if ((sensorIdx = agentx_index_integer_dynamic(sensorsMIBObjects,
+           AGENTX_OID(SENSORINDEX))) == NULL)
+               fatal("agentx_index_integer_dynamic");
+       if ((sensorIndex = agentx_object(sensorsMIBObjects,
+           AGENTX_OID(SENSORINDEX), &sensorIdx, 1, 0, mib_sensors)) == NULL ||
+           (sensorDescr = agentx_object(sensorsMIBObjects,
+           AGENTX_OID(SENSORDESCR), &sensorIdx, 1, 0, mib_sensors)) == NULL ||
+           (sensorType = agentx_object(sensorsMIBObjects,
+           AGENTX_OID(SENSORTYPE), &sensorIdx, 1, 0, mib_sensors)) == NULL ||
+           (sensorDevice = agentx_object(sensorsMIBObjects,
+           AGENTX_OID(SENSORDEVICE), &sensorIdx, 1, 0, mib_sensors)) == NULL ||
+           (sensorValue = agentx_object(sensorsMIBObjects,
+           AGENTX_OID(SENSORVALUE), &sensorIdx, 1, 0, mib_sensors)) == NULL ||
+           (sensorUnits = agentx_object(sensorsMIBObjects,
+           AGENTX_OID(SENSORUNITS), &sensorIdx, 1, 0, mib_sensors)) == NULL ||
+           (sensorStatus = agentx_object(sensorsMIBObjects,
+           AGENTX_OID(SENSORSTATUS), &sensorIdx, 1, 0, mib_sensors)) == NULL)
+               fatal("agentx_object");
+
+       if ((carpMIBObjects = agentx_region(sac,
+           AGENTX_OID(CARPMIBOBJECTS), 0)) == NULL)
+               fatal("agentx_region");
+       if ((carpAllow = agentx_object(carpMIBObjects, AGENTX_OID(CARPALLOW),
+           NULL, 0, 0, mib_carpsysctl)) == NULL ||
+           (carpPreempt = agentx_object(carpMIBObjects,
+           AGENTX_OID(CARPPREEMPT), NULL, 0, 0, mib_carpsysctl)) == NULL ||
+           (carpLog = agentx_object(carpMIBObjects, AGENTX_OID(CARPLOG),
+           NULL, 0, 0, mib_carpsysctl)) == NULL)
+               fatal("agentx_object");
+
+       if ((carpIfNumber = agentx_object(carpMIBObjects,
+           AGENTX_OID(CARPIFNUMBER), NULL, 0, 0, mib_carpifnum)) == NULL)
+               fatal("agentx_object");
+       if ((carpIfIdx = agentx_index_integer_dynamic(carpMIBObjects,
+           AGENTX_OID(CARPIFINDEX))) == NULL)
+               fatal("agentx_index_integer_dynamic");
+       if ((carpIfIndex = agentx_object(carpMIBObjects,
+           AGENTX_OID(CARPIFINDEX), &carpIfIdx, 1, 0,
+           mib_carpiftable)) == NULL ||
+           (carpIfDescr = agentx_object(carpMIBObjects,
+           AGENTX_OID(CARPIFDESCR), &carpIfIdx, 1, 0,
+           mib_carpiftable)) == NULL ||
+           (carpIfVhid = agentx_object(carpMIBObjects, AGENTX_OID(CARPIFVHID),
+           &carpIfIdx, 1, 0, mib_carpiftable)) == NULL ||
+           (carpIfDev = agentx_object(carpMIBObjects, AGENTX_OID(CARPIFDEV),
+           &carpIfIdx, 1, 0, mib_carpiftable)) == NULL ||
+           (carpIfAdvbase = agentx_object(carpMIBObjects,
+           AGENTX_OID(CARPIFADVBASE), &carpIfIdx, 1, 0,
+           mib_carpiftable)) == NULL ||
+           (carpIfAdvskew = agentx_object(carpMIBObjects,
+           AGENTX_OID(CARPIFADVSKEW), &carpIfIdx, 1, 0,
+           mib_carpiftable)) == NULL ||
+           (carpIfState = agentx_object(carpMIBObjects,
+           AGENTX_OID(CARPIFSTATE), &carpIfIdx, 1, 0,
+           mib_carpiftable)) == NULL)
+               fatal("agentx_object");
+
+       if ((carpGroupIdx = agentx_index_integer_dynamic(carpMIBObjects,
+           AGENTX_OID(CARPGROUPINDEX))) == NULL)
+               fatal("agentx_index_integer_dynamic");
+       if ((carpGroupName = agentx_object(carpMIBObjects,
+           AGENTX_OID(CARPGROUPNAME), &carpGroupIdx, 1, 0,
+           mib_carpgrouptable)) == NULL ||
+           (carpGroupDemote = agentx_object(carpMIBObjects,
+           AGENTX_OID(CARPGROUPDEMOTE), &carpGroupIdx, 1, 0,
+           mib_carpgrouptable)) == NULL)
+               fatal("agentx_object");
+
+       if ((carpIpPktsRecv = agentx_object(carpMIBObjects,
+           AGENTX_OID(CARPIPPKTSRECV), NULL, 0, 0, mib_carpstats)) == NULL ||
+           (carpIp6PktsRecv = agentx_object(carpMIBObjects,
+           AGENTX_OID(CARPIP6PKTSRECV), NULL, 0, 0, mib_carpstats)) == NULL ||
+           (carpPktDiscardsForBadInterface = agentx_object(carpMIBObjects,
+           AGENTX_OID(CARPPKTDISCARDSFORBADINTERFACE), NULL, 0, 0,
+           mib_carpstats)) == NULL ||
+           (carpPktDiscardsForWrongTtl = agentx_object(carpMIBObjects,
+           AGENTX_OID(CARPPKTDISCARDSFORWRONGTTL), NULL, 0, 0,
+           mib_carpstats)) == NULL ||
+           (carpPktShorterThanHeader = agentx_object(carpMIBObjects,
+           AGENTX_OID(CARPPKTSHORTERTHANHEADER), NULL, 0, 0,
+           mib_carpstats)) == NULL ||
+           (carpPktDiscardsForBadChecksum = agentx_object(carpMIBObjects,
+           AGENTX_OID(CARPPKTDISCARDSFORBADCHECKSUM), NULL, 0, 0,
+           mib_carpstats)) == NULL ||
+           (carpPktDiscardsForBadVersion = agentx_object(carpMIBObjects,
+           AGENTX_OID(CARPPKTDISCARDSFORBADVERSION), NULL, 0, 0,
+           mib_carpstats)) == NULL ||
+           (carpPktDiscardsForTooShort = agentx_object(carpMIBObjects,
+           AGENTX_OID(CARPPKTDISCARDSFORTOOSHORT), NULL, 0, 0,
+           mib_carpstats)) == NULL ||
+           (carpPktDiscardsForBadAuth = agentx_object(carpMIBObjects,
+           AGENTX_OID(CARPPKTDISCARDSFORBADAUTH), NULL, 0, 0,
+           mib_carpstats)) == NULL ||
+           (carpPktDiscardsForBadVhid = agentx_object(carpMIBObjects,
+           AGENTX_OID(CARPPKTDISCARDSFORBADVHID), NULL, 0, 0,
+           mib_carpstats)) == NULL ||
+           (carpPktDiscardsForBadAddressList = agentx_object(carpMIBObjects,
+           AGENTX_OID(CARPPKTDISCARDSFORBADADDRESSLIST), NULL, 0, 0,
+           mib_carpstats)) == NULL ||
+           (carpIpPktsSent = agentx_object(carpMIBObjects,
+           AGENTX_OID(CARPIPPKTSSENT), NULL, 0, 0,
+           mib_carpstats)) == NULL ||
+           (carpIp6PktsSent = agentx_object(carpMIBObjects,
+           AGENTX_OID(CARPIP6PKTSSENT), NULL, 0, 0,
+           mib_carpstats)) == NULL ||
+           (carpNoMemory = agentx_object(carpMIBObjects,
+           AGENTX_OID(CARPNOMEMORY), NULL, 0, 0,
+           mib_carpstats)) == NULL ||
+           (carpTransitionsToMaster = agentx_object(carpMIBObjects,
+           AGENTX_OID(CARPTRANSITIONSTOMASTER), NULL, 0, 0,
+           mib_carpstats)) == NULL)
+               fatal("agentx_object");
+
+       /* OPENBSD-MEM-MIB */
+       if ((memMIBObjects = agentx_region(sac,
+           AGENTX_OID(MEMMIBOBJECTS), 0)) == NULL)
+               fatal("agentx_region");
+       if ((memMIBVersion = agentx_object(memMIBObjects,
+           AGENTX_OID(MEMMIBVERSION), NULL, 0, 0, mib_memversion)) == NULL)
+               fatal("agentx_object");
+       if ((memIfName = agentx_object(memMIBObjects, AGENTX_OID(MEMIFNAME),
+           &ifIdx, 1, 0, mib_memiftable)) == NULL ||
+           (memIfLiveLocks = agentx_object(memMIBObjects,
+           AGENTX_OID(MEMIFLIVELOCKS), &ifIdx, 1, 0,
+           mib_memiftable)) == NULL)
+               fatal("agentx_object");
+
+       /* IP-MIB */
+       if ((ip = agentx_region(sac, AGENTX_OID(IP), 0)) == NULL)
+               fatal("agentx_region");
+       if ((ipForwarding = agentx_object(ip, AGENTX_OID(IPFORWARDING),
+           NULL, 0, 0, mib_ipforwarding)) == NULL ||
+           (ipDefaultTTL = agentx_object(ip, AGENTX_OID(IPDEFAULTTTL),
+           NULL, 0, 0, mib_ipdefaultttl)) == NULL ||
+           (ipInReceives = agentx_object(ip, AGENTX_OID(IPINRECEIVES),
+           NULL, 0, 0, mib_ipstat)) == NULL ||
+           (ipInHdrErrors = agentx_object(ip, AGENTX_OID(IPINHDRERRORS),
+           NULL, 0, 0, mib_ipinhdrerrs)) == NULL ||
+           (ipInAddrErrors = agentx_object(ip, AGENTX_OID(IPINADDRERRORS),
+           NULL, 0, 0, mib_ipinaddrerrs)) == NULL ||
+           (ipForwDatagrams = agentx_object(ip, AGENTX_OID(IPFORWDATAGRAMS),
+           NULL, 0, 0, mib_ipforwdgrams)) == NULL ||
+           (ipInUnknownProtos = agentx_object(ip,
+           AGENTX_OID(IPINUNKNOWNPROTOS), NULL, 0, 0, mib_ipstat)) == NULL ||
+           (ipInDelivers = agentx_object(ip, AGENTX_OID(IPINDELIVERS),
+           NULL, 0, 0, mib_ipstat)) == NULL ||
+           (ipOutRequests = agentx_object(ip, AGENTX_OID(IPOUTREQUESTS),
+           NULL, 0, 0, mib_ipstat)) == NULL ||
+           (ipOutDiscards = agentx_object(ip, AGENTX_OID(IPOUTDISCARDS),
+           NULL, 0, 0, mib_ipstat)) == NULL ||
+           (ipOutNoRoutes = agentx_object(ip, AGENTX_OID(IPOUTNOROUTES),
+           NULL, 0, 0, mib_ipstat)) == NULL ||
+           (ipReasmTimeout = agentx_object(ip, AGENTX_OID(IPREASMTIMEOUT),
+           NULL, 0, 0, mib_ipreasmtimeout)) == NULL ||
+           (ipReasmReqds = agentx_object(ip, AGENTX_OID(IPREASMREQDS),
+           NULL, 0, 0, mib_ipstat)) == NULL ||
+           (ipReasmOKs = agentx_object(ip, AGENTX_OID(IPREASMOKS),
+           NULL, 0, 0, mib_ipstat)) == NULL ||
+           (ipReasmFails = agentx_object(ip, AGENTX_OID(IPREASMFAILS),
+           NULL, 0, 0, mib_ipreasmfails)) == NULL ||
+           (ipFragOKs = agentx_object(ip, AGENTX_OID(IPFRAGOKS),
+           NULL, 0, 0, mib_ipstat)) == NULL ||
+           (ipFragFails = agentx_object(ip, AGENTX_OID(IPFRAGFAILS),
+           NULL, 0, 0, mib_ipfragfails)) == NULL ||
+           (ipFragCreates = agentx_object(ip, AGENTX_OID(IPFRAGCREATES),
+           NULL, 0, 0, mib_ipstat)) == NULL)
+               fatal("agentx_object");
+
+       if ((ipAdEntAddrIdx = agentx_index_ipaddress_dynamic(ip,
+           AGENTX_OID(IPADENTADDR))) == NULL)
+               fatal("agentx_index_integer_dynamic");
+       if ((ipAdEntAddr = agentx_object(ip, AGENTX_OID(IPADENTADDR),
+           &ipAdEntAddrIdx, 1, 0, mib_ipaddr)) == NULL ||
+           (ipAdEntIfIndex = agentx_object(ip, AGENTX_OID(IPADENTIFINDEX),
+           &ipAdEntAddrIdx, 1, 0, mib_ipaddr)) == NULL ||
+           (ipAdEntNetMask = agentx_object(ip, AGENTX_OID(IPADENTNETMASK),
+           &ipAdEntAddrIdx, 1, 0, mib_ipaddr)) == NULL ||
+           (ipAdEntBcastAddr = agentx_object(ip, AGENTX_OID(IPADENTBCASTADDR),
+           &ipAdEntAddrIdx, 1, 0, mib_ipaddr)) == NULL ||
+           (ipAdEntReasmMaxSize = agentx_object(ip,
+           AGENTX_OID(IPADENTREASMMAXSIZE), &ipAdEntAddrIdx, 1, 0,
+           mib_ipaddr)) == NULL)
+               fatal("agentx_object");
+
+       if ((ipNetToMediaIfIdx = agentx_index_integer_dynamic(ip,
+           AGENTX_OID(IPNETTOMEDIAIFINDEX))) == NULL)
+               fatal("agentx_index_integer_dynamic");
+       if ((ipNetToMediaNetAddressIdx = agentx_index_ipaddress_dynamic(ip,
+           AGENTX_OID(IPNETTOMEDIANETADDRESS))) == NULL)
+               fatal("agentx_index_string_dynamic");
+       indices[0] = ipNetToMediaIfIdx;
+       indices[1] = ipNetToMediaNetAddressIdx;
+       if ((ipNetToMediaIfIndex = agentx_object(ip,
+           AGENTX_OID(IPNETTOMEDIAIFINDEX), indices, 2, 0,
+           mib_physaddr)) == NULL ||
+           (ipNetToMediaPhysAddress = agentx_object(ip,
+           AGENTX_OID(IPNETTOMEDIAPHYSADDRESS), indices, 2, 0,
+           mib_physaddr)) == NULL ||
+           (ipNetToMediaNetAddress = agentx_object(ip,
+           AGENTX_OID(IPNETTOMEDIANETADDRESS), indices, 2, 0,
+           mib_physaddr)) == NULL ||
+           (ipNetToMediaType = agentx_object(ip, AGENTX_OID(IPNETTOMEDIATYPE),
+           indices, 2, 0, mib_physaddr)) == NULL)
+               fatal("agentx_object");
+
+       if ((ipForward = agentx_region(sac, AGENTX_OID(IPFORWARD), 0)) == NULL)
+               fatal("agentx_region");
+       if ((inetCidrRouteNumber = agentx_object(ipForward,
+           AGENTX_OID(INETCIDRROUTENUMBER), NULL, 0, 0,
+           mib_ipfnroutes)) == NULL)
+               fatal("agentx_object");
+       if ((inetCidrRouteDestTypeIdx = agentx_index_integer_dynamic(ipForward,
+           AGENTX_OID(INETCIDRROUTEDESTTYPE))) == NULL ||
+           (inetCidrRouteDestIdx = agentx_index_string_dynamic(ipForward,
+           AGENTX_OID(INETCIDRROUTEDEST))) == NULL ||
+           (inetCidrRoutePfxLenIdx = agentx_index_integer_dynamic(ipForward,
+           AGENTX_OID(INETCIDRROUTEPFXLEN))) == NULL ||
+           (inetCidrRoutePolicyIdx = agentx_index_oid_dynamic(ipForward,
+           AGENTX_OID(INETCIDRROUTEPOLICY))) == NULL ||
+           (inetCidrRouteNextHopTypeIdx = agentx_index_integer_dynamic(
+           ipForward, AGENTX_OID(INETCIDRROUTENEXTHOPTYPE))) == NULL ||
+           (inetCidrRouteNextHopIdx = agentx_index_string_dynamic(ipForward,
+           AGENTX_OID(INETCIDRROUTENEXTHOP))) == NULL)
+               fatal("agentx_index_*_dynamic");
+       indices[0] = inetCidrRouteDestTypeIdx;
+       indices[1] = inetCidrRouteDestIdx;
+       indices[2] = inetCidrRoutePfxLenIdx;
+       indices[3] = inetCidrRoutePolicyIdx;
+       indices[4] = inetCidrRouteNextHopTypeIdx;
+       indices[5] = inetCidrRouteNextHopIdx;
+       if ((inetCidrRouteIfIndex = agentx_object(ipForward,
+           AGENTX_OID(INETCIDRROUTEIFINDEX), indices, 6, 0,
+           mib_ipfroute)) == NULL ||
+           (inetCidrRouteType = agentx_object(ipForward,
+           AGENTX_OID(INETCIDRROUTETYPE), indices, 6, 0,
+           mib_ipfroute)) == NULL ||
+           (inetCidrRouteProto = agentx_object(ipForward,
+           AGENTX_OID(INETCIDRROUTEPROTO), indices, 6, 0,
+           mib_ipfroute)) == NULL ||
+           (inetCidrRouteAge = agentx_object(ipForward,
+           AGENTX_OID(INETCIDRROUTEAGE), indices, 6, 0,
+           mib_ipfroute)) == NULL ||
+           (inetCidrRouteNextHopAS = agentx_object(ipForward,
+           AGENTX_OID(INETCIDRROUTENEXTHOPAS), indices, 6, 0,
+           mib_ipfroute)) == NULL ||
+           (inetCidrRouteMetric1 = agentx_object(ipForward,
+           AGENTX_OID(INETCIDRROUTEMETRIC1), indices, 6, 0,
+           mib_ipfroute)) == NULL ||
+           (inetCidrRouteMetric2 = agentx_object(ipForward,
+           AGENTX_OID(INETCIDRROUTEMETRIC2), indices, 6, 0,
+           mib_ipfroute)) == NULL ||
+           (inetCidrRouteMetric3 = agentx_object(ipForward,
+           AGENTX_OID(INETCIDRROUTEMETRIC3), indices, 6, 0,
+           mib_ipfroute)) == NULL ||
+           (inetCidrRouteMetric4 = agentx_object(ipForward,
+           AGENTX_OID(INETCIDRROUTEMETRIC4), indices, 6, 0,
+           mib_ipfroute)) == NULL ||
+           (inetCidrRouteMetric5 = agentx_object(ipForward,
+           AGENTX_OID(INETCIDRROUTEMETRIC5), indices, 6, 0,
+           mib_ipfroute)) == NULL ||
+           (inetCidrRouteStatus = agentx_object(ipForward,
+           AGENTX_OID(INETCIDRROUTESTATUS), indices, 6, 0,
+           mib_ipfroute)) == NULL)
+               fatal("agentx_object");
+
+       /* UCD-DISKIO-MIB */
+       if ((ucdDiskIOMIB = agentx_region(sac, AGENTX_OID(UCDDISKIOMIB),
+           0)) == NULL)
+               fatal("agentx_region");
+       if ((diskIOIdx = agentx_index_integer_dynamic(ucdDiskIOMIB,
+           AGENTX_OID(DISKIOINDEX))) == NULL)
+               fatal("agentx_index_integer_dynamic");
+       if ((diskIOIndex = agentx_object(ucdDiskIOMIB, AGENTX_OID(DISKIOINDEX),
+           &diskIOIdx, 1, 0, mib_diskio)) == NULL ||
+           (diskIODevice = agentx_object(ucdDiskIOMIB,
+           AGENTX_OID(DISKIODEVICE), &diskIOIdx, 1, 0, mib_diskio)) == NULL ||
+           (diskIONRead = agentx_object(ucdDiskIOMIB, AGENTX_OID(DISKIONREAD),
+           &diskIOIdx, 1, 0, mib_diskio)) == NULL ||
+           (diskIONWritten = agentx_object(ucdDiskIOMIB,
+           AGENTX_OID(DISKIONWRITTEN), &diskIOIdx, 1, 0,
+           mib_diskio)) == NULL ||
+           (diskIOReads = agentx_object(ucdDiskIOMIB,
+           AGENTX_OID(DISKIOREADS), &diskIOIdx, 1, 0, mib_diskio)) == NULL ||
+           (diskIOWrites = agentx_object(ucdDiskIOMIB,
+           AGENTX_OID(DISKIOWRITES), &diskIOIdx, 1, 0, mib_diskio)) == NULL ||
+           (diskIONReadX = agentx_object(ucdDiskIOMIB,
+           AGENTX_OID(DISKIONREADX), &diskIOIdx, 1, 0, mib_diskio)) == NULL ||
+           (diskIONWrittenX = agentx_object(ucdDiskIOMIB,
+           AGENTX_OID(DISKIONWRITTENX), &diskIOIdx, 1, 0,
+           mib_diskio)) == NULL)
+               fatal("agentx_object");
+
+       if ((dot1dBridge = agentx_region(sac, AGENTX_OID(DOT1DBRIDGE),
+           0)) == NULL)
+               fatal("agentx_region");
+       if ((dot1dBaseNumPorts = agentx_object(dot1dBridge,
+           AGENTX_OID(DOT1DBASENUMPORTS), NULL, 0, 0, mib_ifnumber)) == NULL ||
+           (dot1dBaseType = agentx_object(dot1dBridge,
+           AGENTX_OID(DOT1DBASETYPE), NULL, 0, 0, mib_dot1basetype)) == NULL)
+               fatal("agentx_object");
+
+       if ((dot1dBasePortIdx = agentx_index_integer_dynamic(dot1dBridge,
+           AGENTX_OID(DOT1DBASEPORT))) == NULL)
+               fatal("agentx_index_integer_dynamic");
+       if ((dot1dBasePort = agentx_object(dot1dBridge,
+           AGENTX_OID(DOT1DBASEPORT), &dot1dBasePortIdx, 1, 0,
+           mib_dot1dtable)) == NULL ||
+           (dot1dBasePortIfIndex = agentx_object(dot1dBridge,
+           AGENTX_OID(DOT1DBASEPORTIFINDEX), &dot1dBasePortIdx, 1, 0,
+           mib_dot1dtable)) == NULL ||
+           (dot1dBasePortCircuit = agentx_object(dot1dBridge,
+           AGENTX_OID(DOT1DBASEPORTCIRCUIT), &dot1dBasePortIdx, 1, 0,
+           mib_dot1dtable)) == NULL ||
+           (dot1dBasePortDelayExceededDiscards = agentx_object(dot1dBridge,
+           AGENTX_OID(DOT1DBASEPORTDELAYEXCEEDEDDISCARDS), &dot1dBasePortIdx,
+           1, 0, mib_dot1dtable)) == NULL ||
+           (dot1dBasePortMtuExceededDiscards = agentx_object(dot1dBridge,
+           AGENTX_OID(DOT1DBASEPORTMTUEXCEEDEDDISCARDS), &dot1dBasePortIdx,
+           1, 0, mib_dot1dtable)) == NULL)
+               fatal("agentx_object");
+
+       if (daemonize) {
+               log_init(0, LOG_DAEMON);
+               daemon(0, 0);
+       }
+       log_setverbose(verbose);
+
+       event_dispatch();
+}
+
+void
+snmp_connect(struct agentx *sa, void *cookie, int close)
+{
+       static int init = 0;
+
+       if (close) {
+               event_del(&connev);
+               return;
+       }
+
+       if (agentxfd != -1) {
+               /* Exit if snmpd(8) leaves */
+               if (init)
+                       exit(0);
+               agentx_connect(sa, agentxfd);
+               event_set(&connev, agentxfd, EV_READ | EV_PERSIST,
+                   snmp_read, sa);
+               event_add(&connev, NULL);
+               init = 1;
+       } else 
+               snmp_tryconnect(-1, 0, sa);
+}
+
+void
+snmp_tryconnect(int fd, short event, void *cookie)
+{
+       struct timeval timeout = {3, 0};
+       struct agentx *sa = cookie;
+       struct sockaddr_un sun;
+
+       sun.sun_len = sizeof(sun);
+       sun.sun_family = AF_UNIX;
+       strlcpy(sun.sun_path, AGENTX_MASTER_PATH, sizeof(sun.sun_path));
+
+       if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1 ||
+           connect(fd, (struct sockaddr *)&sun, sizeof(sun)) == -1) {
+               if (fd != -1)
+                       close(fd);
+               log_warn("Failed to connect to snmpd");
+               evtimer_set(&connev, snmp_tryconnect, sa);
+               evtimer_add(&connev, &timeout);
+               return;
+       }
+
+       event_set(&connev, fd, EV_READ | EV_PERSIST, snmp_read, sa);
+       event_add(&connev, NULL);
+
+       agentx_connect(sa, fd);
+}
+
+void
+snmp_read(int fd, short event, void *cookie)
+{
+       struct agentx *sa = cookie;
+
+       agentx_read(sa);
+}
+
+u_long
+smi_getticks(void)
+{
+       return agentx_context_uptime(sac);
+}
diff --git a/libexec/snmpd/snmpd_metrics/mib.h b/libexec/snmpd/snmpd_metrics/mib.h
new file mode 100644 (file)
index 0000000..9799547
--- /dev/null
@@ -0,0 +1,896 @@
+/*     $OpenBSD: mib.h,v 1.1.1.1 2022/09/01 14:20:34 martijn Exp $     */
+
+/*
+ * Copyright (c) 2022 Martijn van Duren <martijn@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <agentx.h>
+
+/* HOST-RESOURCES-MIB */
+#define HOST                           AGENTX_MIB2, 25
+#define HRSYSTEM                       HOST, 1
+#define HRSTORAGE                      HOST, 2
+#define HRDEVICE                       HOST, 3
+#define HRSWRUN                                HOST, 4
+#define HRSWRUNPERF                    HOST, 5
+#define HRSWINSTALLED                  HOST, 6
+#define HRMIBADMININFO                 HOST, 7
+#define HRSYSTEMUPTIME                 HRSYSTEM, 1
+#define HRSYSTEMDATE                   HRSYSTEM, 2
+#define HRSYSTEMINITIALLOADDEVICE      HRSYSTEM, 3
+#define HRSYSTEMINITIALLOADPARAMETERS  HRSYSTEM, 4
+#define HRSYSTEMNUMUSERS               HRSYSTEM, 5
+#define HRSYSTEMPROCESSES              HRSYSTEM, 6
+#define HRSYSTEMMAXPROCESSES           HRSYSTEM, 7
+#define HRSTORAGETYPES                 HRSTORAGE, 1
+#define HRMEMORYSIZE                   HRSTORAGE, 2
+#define HRSTORAGETABLE                 HRSTORAGE, 3
+#define HRSTORAGEENTRY                 HRSTORAGETABLE, 1
+#define HRSTORAGEINDEX                 HRSTORAGEENTRY, 1
+#define HRSTORAGETYPE                  HRSTORAGEENTRY, 2
+#define HRSTORAGEDESCR                 HRSTORAGEENTRY, 3
+#define HRSTORAGEALLOCATIONUNITS       HRSTORAGEENTRY, 4
+#define HRSTORAGESIZE                  HRSTORAGEENTRY, 5
+#define HRSTORAGEUSED                  HRSTORAGEENTRY, 6
+#define HRSTORAGEALLOCATIONFAILURES    HRSTORAGEENTRY, 7
+#define HRDEVICETYPES                  HRDEVICE, 1
+#define HRDEVICETABLE                  HRDEVICE, 2
+#define HRDEVICEENTRY                  HRDEVICETABLE, 1
+#define HRDEVICEINDEX                  HRDEVICEENTRY, 1
+#define HRDEVICETYPE                   HRDEVICEENTRY, 2
+#define HRDEVICEDESCR                  HRDEVICEENTRY, 3
+#define HRDEVICEID                     HRDEVICEENTRY, 4
+#define HRDEVICESTATUS                 HRDEVICEENTRY, 5
+#define HRDEVICEERRORS                 HRDEVICEENTRY, 6
+#define HRPROCESSORTABLE               HRDEVICE, 3
+#define HRPROCESSORENTRY               HRPROCESSORTABLE, 1
+#define HRPROCESSORFRWID               HRPROCESSORENTRY, 1
+#define HRPROCESSORLOAD                        HRPROCESSORENTRY, 2
+#define HRNETWORKTABLE                 HRDEVICE, 4
+#define HRNETWORKENTRY                 HRNETWORKTABLE, 1
+#define HRNETWORKIFINDEX               HRNETWORKENTRY, 1
+#define HRPRINTERTABLE                 HRDEVICE, 5
+#define HRPRINTERENTRY                 HRPRINTERTABLE, 1
+#define HRPRINTERSTATUS                        HRPRINTERENTRY, 1
+#define HRPRINTERDETECTEDERRORSTATE    HRPRINTERENTRY, 2
+#define HRDISKSTORAGETABLE             HRDEVICE, 6
+#define HRDISKSTORAGEENTRY             HRDISKSTORAGETABLE, 1
+#define HRDISKSTORAGEACCESS            HRDISKSTORAGEENTRY, 1
+#define HRDISKSTORAGEMEDIA             HRDISKSTORAGEENTRY, 2
+#define HRDISKSTORAGEREMOVEBLE         HRDISKSTORAGEENTRY, 3
+#define HRDISKSTORAGECAPACITY          HRDISKSTORAGEENTRY, 4
+#define HRPARTITIONTABLE               HRDEVICE, 7
+#define HRPARTITIONENTRY               HRPARTITIONTABLE, 1
+#define HRPARTITIONINDEX               HRPARTITIONENTRY, 1
+#define HRPARTITIONLABEL               HRPARTITIONENTRY, 2
+#define HRPARTITIONID                  HRPARTITIONENTRY, 3
+#define HRPARTITIONSIZE                        HRPARTITIONENTRY, 4
+#define HRPARTITIONFSINDEX             HRPARTITIONENTRY, 5
+#define HRFSTYPES                      HRDEVICE, 9
+#define HRFSTABLE                      HRDEVICE, 8
+#define HRFSENTRY                      HRFSTABLE, 1
+#define HRFSINDEX                      HRFSENTRY, 1
+#define HRFSMOUNTPOINT                 HRFSENTRY, 2
+#define HRFSREMOTEMOUNTPOINT           HRFSENTRY, 3
+#define HRFSTYPE                       HRFSENTRY, 4
+#define HRFSACCESS                     HRFSENTRY, 5
+#define HRFSBOOTABLE                   HRFSENTRY, 6
+#define HRFSSTORAGEINDEX               HRFSENTRY, 7
+#define HRFSLASTFULLBACKUPDATE         HRFSENTRY, 8
+#define HRFSLASTPARTIALBACKUPDATE      HRFSENTRY, 9
+#define HRSWOSINDEX                    HRSWRUN, 1
+#define HRSWRUNTABLE                   HRSWRUN, 2
+#define HRSWRUNENTRY                   HRSWRUNTABLE, 1
+#define HRSWRUNINDEX                   HRSWRUNENTRY, 1
+#define HRSWRUNNAME                    HRSWRUNENTRY, 2
+#define HRSWRUNID                      HRSWRUNENTRY, 3
+#define HRSWRUNPATH                    HRSWRUNENTRY, 4
+#define HRSWRUNPARAMETERS              HRSWRUNENTRY, 5
+#define HRSWRUNTYPE                    HRSWRUNENTRY, 6
+#define HRSWRUNSTATUS                  HRSWRUNENTRY, 7
+#define HRSWRUNPERFTABLE               HRSWRUNPERF, 1
+#define HRSWRUNPERFENTRY               HRSWRUNPERFTABLE, 1
+#define HRSWRUNPERFCPU                 HRSWRUNPERFENTRY, 1
+#define HRSWRUNPERFMEM                 HRSWRUNPERFENTRY, 2
+#define HRSWINSTALLEDLASTCHANGE                HRSWINSTALLED, 1
+#define HRSWINSTALLEDLASTUPDATETIME    HRSWINSTALLED, 2
+#define HRSWINSTALLEDTABLE             HRSWINSTALLED, 3
+#define HRSWINSTALLEDENTRY             HRSWINSTALLEDTABLE, 1
+#define HRSWINSTALLEDINDEX             HRSWINSTALLEDENTRY, 1
+#define HRSWINSTALLEDNAME              HRSWINSTALLEDENTRY, 2
+#define HRSWINSTALLEDID                        HRSWINSTALLEDENTRY, 3
+#define HRSWINSTALLEDTYPE              HRSWINSTALLEDENTRY, 4
+#define HRSWINSTALLEDDATE              HRSWINSTALLEDENTRY, 5
+
+/* HOST-RESOURCES-TYPES */
+#define HRSTORAGEOTHER                 HRSTORAGETYPES, 1
+#define HRSTORAGERAM                   HRSTORAGETYPES, 2
+#define HRSTORAGEVIRTUALMEMORY         HRSTORAGETYPES, 3
+#define HRSTORAGEFIXEDDISK             HRSTORAGETYPES, 4
+#define HRSTORAGEREMOVABLEDISK         HRSTORAGETYPES, 5
+#define HRSTORAGEFLOPPYDISK            HRSTORAGETYPES, 6
+#define HRSTORAGECOMPACTDISC           HRSTORAGETYPES, 7
+#define HRSTORAGERAMDISK               HRSTORAGETYPES, 8
+#define HRSTORAGEFLASHMEMORY           HRSTORAGETYPES, 9
+#define HRSTORAGENETWORKDISK           HRSTORAGETYPES, 10
+#define HRDEVICEOTHER                  HRDEVICETYPES, 1
+#define HRDEVICEUNKNOWN                        HRDEVICETYPES, 2
+#define HRDEVICEPROCESSOR              HRDEVICETYPES, 3
+#define HRDEVICENETWORK                        HRDEVICETYPES, 4
+#define HRDEVICEPRINTER                        HRDEVICETYPES, 5
+#define HRDEVICEDISKSTORAGE            HRDEVICETYPES, 6
+#define HRDEVICEVIDEO                  HRDEVICETYPES, 10
+#define HRDEVICEAUDIO                  HRDEVICETYPES, 11
+#define HRDEVICECOPROCESSOR            HRDEVICETYPES, 12
+#define HRDEVICEKEYBOARD               HRDEVICETYPES, 13
+#define HRDEVICEMODEM                  HRDEVICETYPES, 14
+#define HRDEVICEPARALLELPORT           HRDEVICETYPES, 15
+#define HRDEVICEPOINTING               HRDEVICETYPES, 16
+#define HRDEVICESERIALPORT             HRDEVICETYPES, 17
+#define HRDEVICETAPE                   HRDEVICETYPES, 18
+#define HRDEVICECLOCK                  HRDEVICETYPES, 19
+#define HRDEVICEVOLATILEMEMORY         HRDEVICETYPES, 20
+#define HRDEVICENONVOLATILEMEMORY      HRDEVICETYPES, 21
+#define HRFSOTHER                      HRFSTYPES, 1
+#define HRFSUNKNOWN                    HRFSTYPES, 2
+#define HRFSBERKELEYFFS                        HRFSTYPES, 3
+#define HRFSSYS5FS                     HRFSTYPES, 4
+#define HRFSFAT                                HRFSTYPES, 5
+#define HRFSHPFS                       HRFSTYPES, 6
+#define HRFSHFS                                HRFSTYPES, 7
+#define HRFSMFS                                HRFSTYPES, 8
+#define HRFSNTFS                       HRFSTYPES, 9
+#define HRFSVNODE                      HRFSTYPES, 10
+#define HRFSJOURNALED                  HRFSTYPES, 11
+#define HRFSISO9660                    HRFSTYPES, 12
+#define HRFSROCKRIDGE                  HRFSTYPES, 13
+#define HRFSNFS                                HRFSTYPES, 14
+#define HRFSNETWARE                    HRFSTYPES, 15
+#define HRFSAFS                                HRFSTYPES, 16
+#define HRFSDFS                                HRFSTYPES, 17
+#define HRfSAPPLESHARE                 HRFSTYPES, 18
+#define HRFSRFS                                HRFSTYPES, 19
+#define HRFSDGCFS                      HRFSTYPES, 20
+#define HRFSBFS                                HRFSTYPES, 21
+#define HRFSFAT32                      HRFSTYPES, 22
+#define HRFSLINUXEXT2                  HRFSTYPES, 23
+
+/* IF-MIB */
+#define IFMIB                          AGENTX_MIB2, 31
+#define IFMIBOBJECTS                   IFMIB, 1
+#define INTERFACES                     AGENTX_MIB2, 2
+#define IFNUMBER                       INTERFACES, 1
+#define IFTABLELASTCHANGE              IFMIBOBJECTS, 5
+#define IFTABLE                                INTERFACES, 2
+#define IFENTRY                                IFTABLE, 1
+#define IFINDEX                                IFENTRY, 1
+#define IFDESCR                                IFENTRY, 2
+#define IFTYPE                         IFENTRY, 3
+#define IFMTU                          IFENTRY, 4
+#define IFSPEED                                IFENTRY, 5
+#define IFPHYSADDRESS                  IFENTRY, 6
+#define IFADMINSTATUS                  IFENTRY, 7
+#define IFOPERSTATUS                   IFENTRY, 8
+#define IFLASTCHANGE                   IFENTRY, 9
+#define IFINOCTETS                     IFENTRY, 10
+#define IFINUCASTPKTS                  IFENTRY, 11
+#define IFINNUCASTPKTS                 IFENTRY, 12
+#define IFINDISCARDS                   IFENTRY, 13
+#define IFINERRORS                     IFENTRY, 14
+#define IFINUNKNOWNPROTOS              IFENTRY, 15
+#define IFOUTOCTETS                    IFENTRY, 16
+#define IFOUTUCASTPKTS                 IFENTRY, 17
+#define IFOUTNUCASTPKTS                        IFENTRY, 18
+#define IFOUTDISCARDS                  IFENTRY, 19
+#define IFOUTERRORS                    IFENTRY, 20
+#define IFOUTQLEN                      IFENTRY, 21
+#define IFSPECIFIC                     IFENTRY, 22
+#define IFXTABLE                       IFMIBOBJECTS, 1
+#define IFXENTRY                       IFXTABLE, 1
+#define IFNAME                         IFXENTRY, 1
+#define IFINMULTICASTPKTS              IFXENTRY, 2
+#define IFINBROADCASTPKTS              IFXENTRY, 3
+#define IFOUTMULTICASTPKTS             IFXENTRY, 4
+#define IFOUTBROADCASTPKTS             IFXENTRY, 5
+#define IFHCINOCTETS                   IFXENTRY, 6
+#define IFHCINUCASTPKTS                        IFXENTRY, 7
+#define IFHCINMULTICASTPKTS            IFXENTRY, 8
+#define IFHCINBROADCASTPKTS            IFXENTRY, 9
+#define IFHCOUTOCTETS                  IFXENTRY, 10
+#define IFHCOUTUCASTPKTS               IFXENTRY, 11
+#define IFHCOUTMULTICASTPKTS           IFXENTRY, 12
+#define IFHCOUTBROADCASTPKTS           IFXENTRY, 13
+#define IFLINKUPDOWNTRAPENABLE         IFXENTRY, 14
+#define IFHIGHSPEED                    IFXENTRY, 15
+#define IFPROMISCUOUSMODE              IFXENTRY, 16
+#define IFCONNECTORPRESENT             IFXENTRY, 17
+#define IFALIAS                                IFXENTRY, 18
+#define IFCOUNTERDISCONTINUITYTIME     IFXENTRY, 19
+#define IFSTACKTABLE                   IFMIBOBJECTS, 2
+#define IFSTACKENTRY                   IFSTACKTABLE, 1
+#define IFSTACKHIGHERLAYER             IFSTACKENTRY, 1
+#define IFSTACKLOWERLAYER              IFSTACKENTRY, 2
+#define IFSTACKSTATUS                  IFSTACKENTRY, 3
+#define IFRCVADDRESSTABLE              IFMIBOBJECTS, 4
+#define IFRCVADDRESSENTRY              IFRCVADDRESSTABLE, 1
+#define IFRCVADDRESSADDRESS            IFRCVADDRESSENTRY, 1
+#define IFRCVADDRESSSTATUS             IFRCVADDRESSENTRY, 2
+#define IFRCVADDRESSTYPE               IFRCVADDRESSENTRY, 3
+#define IFSTACKLASTCHANGE              IFMIBOBJECTS, 6
+
+/* OPENBSD-BASE-MIB */
+#define OPENBSD                                AGENTX_ENTERPRISES, 30155
+#define PFMIBOBJECTS                   OPENBSD, 1
+#define SENSORSMIBOBJECTS              OPENBSD, 2
+#define RELAYDMIBOBJECTS               OPENBSD, 3
+#define MEMMIBOBJECTS                  OPENBSD, 5
+#define CARPMIBOBJECTS                 OPENBSD, 6
+#define LOCALSYSTEM                    OPENBSD, 23
+#define OPENBSDDEFAULTOBJECTID         LOCALSYSTEM, 1
+#define LOCALTEST                      OPENBSD, 42
+
+/* OPENBSD-PF-MIB */
+#define PFINFO                         PFMIBOBJECTS, 1
+#define PFCOUNTERS                     PFMIBOBJECTS, 2
+#define PFSTATETABLE                   PFMIBOBJECTS, 3
+#define PFLOGINTERFACE                 PFMIBOBJECTS, 4
+#define PFSRCTRACKING                  PFMIBOBJECTS, 5
+#define PFLIMITS                       PFMIBOBJECTS, 6
+#define PFTIMEOUTS                     PFMIBOBJECTS, 7
+#define PFINTERFACES                   PFMIBOBJECTS, 8
+#define PFTABLES                       PFMIBOBJECTS, 9
+#define PFLABELS                       PFMIBOBJECTS, 10
+#define PFSYNCSTATS                    PFMIBOBJECTS, 11
+#define PFRUNNING                      PFINFO, 1
+#define PFRUNTIME                      PFINFO, 2
+#define PFDEBUG                                PFINFO, 3
+#define PFHOSTID                       PFINFO, 4
+#define PFCNTMATCH                     PFCOUNTERS, 1
+#define PFCNTBADOFFSET                 PFCOUNTERS, 2
+#define PFCNTFRAGMENT                  PFCOUNTERS, 3
+#define PFCNTSHORT                     PFCOUNTERS, 4
+#define PFCNTNORMALIZE                 PFCOUNTERS, 5
+#define PFCNTMEMORY                    PFCOUNTERS, 6
+#define PFCNTTIMESTAMP                 PFCOUNTERS, 7
+#define PFCNTCONGESTION                        PFCOUNTERS, 8
+#define PFCNTIPOPTION                  PFCOUNTERS, 9
+#define PFCNTPROTOCKSUM                        PFCOUNTERS, 10
+#define PFCNTSTATEMISMATCH             PFCOUNTERS, 11
+#define PFCNTSTATEINSERT               PFCOUNTERS, 12
+#define PFCNTSTATELIMIT                        PFCOUNTERS, 13
+#define PFCNTSRCLIMIT                  PFCOUNTERS, 14
+#define PFCNTSYNPROXY                  PFCOUNTERS, 15
+#define PFCNTTRANSLATE                 PFCOUNTERS, 16
+#define PFCNTNOROUTE                   PFCOUNTERS, 17
+#define PFSTATECOUNT                   PFSTATETABLE, 1
+#define PFSTATESEARCHES                        PFSTATETABLE, 2
+#define PFSTATEINSERTS                 PFSTATETABLE, 3
+#define PFSTATEREMOVALS                        PFSTATETABLE, 4
+#define PFLOGIFNAME                    PFLOGINTERFACE, 1
+#define PFLOGIFIPBYTESIN               PFLOGINTERFACE, 2
+#define PFLOGIFIPBYTESOUT              PFLOGINTERFACE, 3
+#define PFLOGIFIPPKTSINPASS            PFLOGINTERFACE, 4
+#define PFLOGIFIPPKTSINDROP            PFLOGINTERFACE, 5
+#define PFLOGIFIPPKTSOUTPASS           PFLOGINTERFACE, 6
+#define PFLOGIFIPPKTSOUTDROP           PFLOGINTERFACE, 7
+#define PFLOGIFIP6BYTESIN              PFLOGINTERFACE, 8
+#define PFLOGIFIP6BYTESOUT             PFLOGINTERFACE, 9
+#define PFLOGIFIP6PKTSINPASS           PFLOGINTERFACE, 10
+#define PFLOGIFIP6PKTSINDROP           PFLOGINTERFACE, 11
+#define PFLOGIFIP6PKTSOUTPASS          PFLOGINTERFACE, 12
+#define PFLOGIFIP6PKTSOUTDROP          PFLOGINTERFACE, 13
+#define PFSRCTRACKCOUNT                        PFSRCTRACKING, 1
+#define PFSRCTRACKSEARCHES             PFSRCTRACKING, 2
+#define PFSRCTRACKINSERTS              PFSRCTRACKING, 3
+#define PFSRCTRACKREMOVALS             PFSRCTRACKING, 4
+#define PFLIMITSTATES                  PFLIMITS, 1
+#define PFLIMITSOURCENODES             PFLIMITS, 2
+#define PFLIMITFRAGMENTS               PFLIMITS, 3
+#define PFLIMITMAXTABLES               PFLIMITS, 4
+#define PFLIMITMAXTABLEENTRIES         PFLIMITS, 5
+#define PFTIMEOUTTCPFIRST              PFTIMEOUTS, 1
+#define PFTIMEOUTTCPOPENING            PFTIMEOUTS, 2
+#define PFTIMEOUTTCPESTABLISHED                PFTIMEOUTS, 3
+#define PFTIMEOUTTCPCLOSING            PFTIMEOUTS, 4
+#define PFTIMEOUTTCPFINWAIT            PFTIMEOUTS, 5
+#define PFTIMEOUTTCPCLOSED             PFTIMEOUTS, 6
+#define PFTIMEOUTUDPFIRST              PFTIMEOUTS, 7
+#define PFTIMEOUTUDPSINGLE             PFTIMEOUTS, 8
+#define PFTIMEOUTUDPMULTIPLE           PFTIMEOUTS, 9
+#define PFTIMEOUTICMPFIRST             PFTIMEOUTS, 10
+#define PFTIMEOUTICMPERROR             PFTIMEOUTS, 11
+#define PFTIMEOUTOTHERFIRST            PFTIMEOUTS, 12
+#define PFTIMEOUTOTHERSINGLE           PFTIMEOUTS, 13
+#define PFTIMEOUTOTHERMULTIPLE         PFTIMEOUTS, 14
+#define PFTIMEOUTFRAGMENT              PFTIMEOUTS, 15
+#define PFTIMEOUTINTERVAL              PFTIMEOUTS, 16
+#define PFTIMEOUTADAPTIVESTART         PFTIMEOUTS, 17
+#define PFTIMEOUTADAPTIVEEND           PFTIMEOUTS, 18
+#define PFTIMEOUTSRCTRACK              PFTIMEOUTS, 19
+#define PFIFNUMBER                     PFINTERFACES, 1
+#define PFIFTABLE                      PFINTERFACES, 128
+#define PFIFENTRY                      PFIFTABLE, 1
+#define PFIFINDEX                      PFIFENTRY, 1
+#define PFIFDESCR                      PFIFENTRY, 2
+#define PFIFTYPE                       PFIFENTRY, 3
+#define PFIFREFS                       PFIFENTRY, 4
+#define PFIFRULES                      PFIFENTRY, 5
+#define PFIFIN4PASSPKTS                        PFIFENTRY, 6
+#define PFIFIN4PASSBYTES               PFIFENTRY, 7
+#define PFIFIN4BLOCKPKTS               PFIFENTRY, 8
+#define PFIFIN4BLOCKBYTES              PFIFENTRY, 9
+#define PFIFOUT4PASSPKTS               PFIFENTRY, 10
+#define PFIFOUT4PASSBYTES              PFIFENTRY, 11
+#define PFIFOUT4BLOCKPKTS              PFIFENTRY, 12
+#define PFIFOUT4BLOCKBYTES             PFIFENTRY, 13
+#define PFIFIN6PASSPKTS                        PFIFENTRY, 14
+#define PFIFIN6PASSBYTES               PFIFENTRY, 15
+#define PFIFIN6BLOCKPKTS               PFIFENTRY, 16
+#define PFIFIN6BLOCKBYTES              PFIFENTRY, 17
+#define PFIFOUT6PASSPKTS               PFIFENTRY, 18
+#define PFIFOUT6PASSBYTES              PFIFENTRY, 19
+#define PFIFOUT6BLOCKPKTS              PFIFENTRY, 20
+#define PFIFOUT6BLOCKBYTES             PFIFENTRY, 21
+#define PFTBLNUMBER                    PFTABLES, 1
+#define PFTBLTABLE                     PFTABLES, 128
+#define PFTBLENTRY                     PFTBLTABLE, 1
+#define PFTBLINDEX                     PFTBLENTRY, 1
+#define PFTBLNAME                      PFTBLENTRY, 2
+#define PFTBLADDRESSES                 PFTBLENTRY, 3
+#define PFTBLANCHORREFS                        PFTBLENTRY, 4
+#define PFTBLRULEREFS                  PFTBLENTRY, 5
+#define PFTBLEVALSMATCH                        PFTBLENTRY, 6
+#define PFTBLEVALSNOMATCH              PFTBLENTRY, 7
+#define PFTBLINPASSPKTS                        PFTBLENTRY, 8
+#define PFTBLINPASSBYTES               PFTBLENTRY, 9
+#define PFTBLINBLOCKPKTS               PFTBLENTRY, 10
+#define PFTBLINBLOCKBYTES              PFTBLENTRY, 11
+#define PFTBLINXPASSPKTS               PFTBLENTRY, 12
+#define PFTBLINXPASSBYTES              PFTBLENTRY, 13
+#define PFTBLOUTPASSPKTS               PFTBLENTRY, 14
+#define PFTBLOUTPASSBYTES              PFTBLENTRY, 15
+#define PFTBLOUTBLOCKPKTS              PFTBLENTRY, 16
+#define PFTBLOUTBLOCKBYTES             PFTBLENTRY, 17
+#define PFTBLOUTXPASSPKTS              PFTBLENTRY, 18
+#define PFTBLOUTXPASSBYTES             PFTBLENTRY, 19
+#define PFTBLSTATSCLEARED              PFTBLENTRY, 20
+#define PFTBLINMATCHPKTS               PFTBLENTRY, 21
+#define PFTBLINMATCHBYTES              PFTBLENTRY, 22
+#define PFTBLOUTMATCHPKTS              PFTBLENTRY, 23
+#define PFTBLOUTMATCHBYTES             PFTBLENTRY, 24
+#define PFTBLADDRTABLE                 PFTABLES, 129
+#define PFTBLADDRENTRY                 PFTBLADDRTABLE, 1
+#define PFTBLADDRTBLINDEX              PFTBLADDRENTRY, 1
+#define PFTBLADDRNET                   PFTBLADDRENTRY, 2
+#define PFTBLADDRMASK                  PFTBLADDRENTRY, 3
+#define PFTBLADDRCLEARED               PFTBLADDRENTRY, 4
+#define PFTBLADDRINBLOCKPKTS           PFTBLADDRENTRY, 5
+#define PFTBLADDRINBLOCKBYTES          PFTBLADDRENTRY, 6
+#define PFTBLADDRINPASSPKTS            PFTBLADDRENTRY, 7
+#define PFTBLADDRINPASSBYTES           PFTBLADDRENTRY, 8
+#define PFTBLADDROUTBLOCKPKTS          PFTBLADDRENTRY, 9
+#define PFTBLADDROUTBLOCKBYTES         PFTBLADDRENTRY, 10
+#define PFTBLADDROUTPASSPKTS           PFTBLADDRENTRY, 11
+#define PFTBLADDROUTPASSBYTES          PFTBLADDRENTRY, 12
+#define PFTBLADDRINMATCHPKTS           PFTBLADDRENTRY, 13
+#define PFTBLADDRINMATCHBYTES          PFTBLADDRENTRY, 14
+#define PFTBLADDROUTMATCHPKTS          PFTBLADDRENTRY, 15
+#define PFTBLADDROUTMATCHBYTES         PFTBLADDRENTRY, 16
+#define PFLABELNUMBER                  PFLABELS, 1
+#define PFLABELTABLE                   PFLABELS, 128
+#define PFLABELENTRY                   PFLABELTABLE, 1
+#define PFLABELINDEX                   PFLABELENTRY, 1
+#define PFLABELNAME                    PFLABELENTRY, 2
+#define PFLABELEVALS                   PFLABELENTRY, 3
+#define PFLABELPKTS                    PFLABELENTRY, 4
+#define PFLABELBYTES                   PFLABELENTRY, 5
+#define PFLABELINPKTS                  PFLABELENTRY, 6
+#define PFLABELINBYTES                 PFLABELENTRY, 7
+#define PFLABELOUTPKTS                 PFLABELENTRY, 8
+#define PFLABELOUTBYTES                        PFLABELENTRY, 9
+#define PFLABELTOTALSTATES             PFLABELENTRY, 10
+#define PFSYNCIPPKTSRECV               PFSYNCSTATS, 1
+#define PFSYNCIP6PKTSRECV              PFSYNCSTATS, 2
+#define PFSYNCPKTDISCARDSFORBADINTERFACE PFSYNCSTATS, 3
+#define PFSYNCPKTDISCARDSFORBADTTL     PFSYNCSTATS, 4
+#define PFSYNCPKTSHORTERTHANHEADER     PFSYNCSTATS, 5
+#define PFSYNCPKTDISCARDSFORBADVERSION PFSYNCSTATS, 6
+#define PFSYNCPKTDISCARDSFORBADACTION  PFSYNCSTATS, 7
+#define PFSYNCPKTDISCARDSFORBADLENGTH  PFSYNCSTATS, 8
+#define PFSYNCPKTDISCARDSFORBADAUTH    PFSYNCSTATS, 9
+#define PFSYNCPKTDISCARDSFORSTALESTATE PFSYNCSTATS, 10
+#define PFSYNCPKTDISCARDSFORBADVALUES  PFSYNCSTATS, 11
+#define PFSYNCPKTDISCARDSFORBADSTATE   PFSYNCSTATS, 12
+#define PFSYNCIPPKTSSENT               PFSYNCSTATS, 13
+#define PFSYNCIP6PKTSSENT              PFSYNCSTATS, 14
+#define PFSYNCNOMEMORY                 PFSYNCSTATS, 15
+#define PFSYNCOUTPUTERRORS             PFSYNCSTATS, 16
+
+/* OPENBSD-SENSORS-MIB */
+#define SENSORSMIBOBJECTS              OPENBSD, 2
+#define SENSORS                                SENSORSMIBOBJECTS, 1
+#define SENSORNUMBER                   SENSORS, 1
+#define SENSORTABLE                    SENSORS, 2
+#define SENSORENTRY                    SENSORTABLE, 1
+#define SENSORINDEX                    SENSORENTRY, 1
+#define SENSORDESCR                    SENSORENTRY, 2
+#define SENSORTYPE                     SENSORENTRY, 3
+#define SENSORDEVICE                   SENSORENTRY, 4
+#define SENSORVALUE                    SENSORENTRY, 5
+#define SENSORUNITS                    SENSORENTRY, 6
+#define SENSORSTATUS                   SENSORENTRY, 7
+
+/* OPENBSD-CARP-MIB */
+#define CARPSYSCTL                     CARPMIBOBJECTS, 1
+#define CARPIF                         CARPMIBOBJECTS, 2
+#define CARPSTATS                      CARPMIBOBJECTS, 3
+#define CARPALLOW                      CARPSYSCTL, 1
+#define CARPPREEMPT                    CARPSYSCTL, 2
+#define CARPLOG                                CARPSYSCTL, 3
+#define CARPIFNUMBER                   CARPIF, 1
+#define CARPIFTABLE                    CARPIF, 2
+#define CARPIFENTRY                    CARPIFTABLE, 1
+#define CARPIFINDEX                    CARPIFENTRY, 1
+#define CARPIFDESCR                    CARPIFENTRY, 2
+#define CARPIFVHID                     CARPIFENTRY, 3
+#define CARPIFDEV                      CARPIFENTRY, 4
+#define CARPIFADVBASE                  CARPIFENTRY, 5
+#define CARPIFADVSKEW                  CARPIFENTRY, 6
+#define CARPIFSTATE                    CARPIFENTRY, 7
+#define CARPGROUPTABLE                 CARPMIBOBJECTS, 4
+#define CARPGROUPENTRY                 CARPGROUPTABLE, 1
+#define CARPGROUPINDEX                 CARPGROUPENTRY, 1
+#define CARPGROUPNAME                  CARPGROUPENTRY, 2
+#define CARPGROUPDEMOTE                        CARPGROUPENTRY, 3
+#define CARPIPPKTSRECV                 CARPSTATS, 1
+#define CARPIP6PKTSRECV                        CARPSTATS, 2
+#define CARPPKTDISCARDSFORBADINTERFACE CARPSTATS, 3
+#define CARPPKTDISCARDSFORWRONGTTL     CARPSTATS, 4
+#define CARPPKTSHORTERTHANHEADER       CARPSTATS, 5
+#define CARPPKTDISCARDSFORBADCHECKSUM  CARPSTATS, 6
+#define CARPPKTDISCARDSFORBADVERSION   CARPSTATS, 7
+#define CARPPKTDISCARDSFORTOOSHORT     CARPSTATS, 8
+#define CARPPKTDISCARDSFORBADAUTH      CARPSTATS, 9
+#define CARPPKTDISCARDSFORBADVHID      CARPSTATS, 10
+#define CARPPKTDISCARDSFORBADADDRESSLIST CARPSTATS, 11
+#define CARPIPPKTSSENT                 CARPSTATS, 12
+#define CARPIP6PKTSSENT                        CARPSTATS, 13
+#define CARPNOMEMORY                   CARPSTATS, 14
+#define CARPTRANSITIONSTOMASTER                CARPSTATS, 15
+
+/* OPENBSD-MEM-MIB */
+#define MEMMIBVERSION                  MEMMIBOBJECTS, 1
+#define MEMIFTABLE                     MEMMIBOBJECTS, 2
+#define MEMIFENTRY                     MEMIFTABLE, 1
+#define MEMIFNAME                      MEMIFENTRY, 1
+#define MEMIFLIVELOCKS                 MEMIFENTRY, 2
+
+/* IP-MIB */
+#define IPMIB                          AGENTX_MIB2, 48
+#define IP                             AGENTX_MIB2, 4
+#define IPFORWARDING                   IP, 1
+#define IPDEFAULTTTL                   IP, 2
+#define IPREASMTIMEOUT                 IP, 13
+#define IPV6IPFORWARDING               IP, 25
+#define IPV6IPDEFAULTHOPLIMIT          IP, 26
+#define IPV4INTERFACETABLELASTCHANGE   IP, 27
+#define IPV4INTERFACETABLE             IP, 28
+#define IPV4INTERFACEENTRY             IPV4INTERFACETABLE, 1
+#define IPV4INTERFACEIFINDEX           IPV4INTERFACEENTRY, 1
+#define IPV4INTERFACEREASMMAXSIZE      IPV4INTERFACEENTRY, 2
+#define IPV4INTERFACEENABLESTATUS      IPV4INTERFACEENTRY, 3
+#define IPV4INTERFACERETRANSMITTIME    IPV4INTERFACEENTRY, 4
+#define IPV6INTERFACETABLELASTCHANGE   IP, 29
+#define IPV6INTERFACETABLE             IP, 30
+#define IPV6INTERFACEENTRY             IPV6INTERFACETABLE, 1
+#define IPV6INTERFACEIFINDEX           IPV6INTERFACEENTRY, 1
+#define IPV6INTERFACEREASMMAXSIZE      IPV6INTERFACEENTRY, 2
+#define IPV6INTERFACEIDENTIFIER                IPV6INTERFACEENTRY, 3
+#define IPV6INTERFACEENABLESTATUS      IPV6INTERFACEENTRY, 5
+#define IPV6INTERFACEREACHABLETIME     IPV6INTERFACEENTRY, 6
+#define IPV6INTERFACERETRANSMITTIME    IPV6INTERFACEENTRY, 7
+#define IPV6INTERFACEFORWARDING                IPV6INTERFACEENTRY, 8
+#define IPTRAFFICSTATS                 IP, 31
+#define IPSYSTEMSTATSTABLE             IPTRAFFICSTATS, 1
+#define IPSYSTEMSTATSENTRY             IPSYSTEMSTATSTABLE, 1
+#define IPSYSTEMSTATSIPVERSION         IPSYSTEMSTATSENTRY, 1
+#define IPSYSTEMSTATSINRECEIVES                IPSYSTEMSTATSENTRY, 3
+#define IPSYSTEMSTATSHCINRECEIVES      IPSYSTEMSTATSENTRY, 4
+#define IPSYSTEMSTATSINOCTETS          IPSYSTEMSTATSENTRY, 5
+#define IPSYSTEMSTATSHCINOCTETS                IPSYSTEMSTATSENTRY, 6
+#define IPSYSTEMSTATSINHDRERRORS       IPSYSTEMSTATSENTRY, 7
+#define IPSYSTEMSTATSINNOROUTES                IPSYSTEMSTATSENTRY, 8
+#define IPSYSTEMSTATSINADDRERRORS      IPSYSTEMSTATSENTRY, 9
+#define IPSYSTEMSTATSINUNKNOWNPROTOS   IPSYSTEMSTATSENTRY, 10
+#define IPSYSTEMSTATSINTRUNCATEDPKTS   IPSYSTEMSTATSENTRY, 11
+#define IPSYSTEMSTATSINFORWDATAGRAMS   IPSYSTEMSTATSENTRY, 12
+#define IPSYSTEMSTATSHCINFORWDATAGRAMS IPSYSTEMSTATSENTRY, 13
+#define IPSYSTEMSTATSREASMREQDS                IPSYSTEMSTATSENTRY, 14
+#define IPSYSTEMSTATSREASMOKS          IPSYSTEMSTATSENTRY, 15
+#define IPSYSTEMSTATSREASMFAILS                IPSYSTEMSTATSENTRY, 16
+#define IPSYSTEMSTATSINDISCARDS                IPSYSTEMSTATSENTRY, 17
+#define IPSYSTEMSTATSINDELIVERS                IPSYSTEMSTATSENTRY, 18
+#define IPSYSTEMSTATSHCINDELIVERS      IPSYSTEMSTATSENTRY, 19
+#define IPSYSTEMSTATSOUTREQUESTS       IPSYSTEMSTATSENTRY, 20
+#define IPSYSTEMSTATSHCOUTREQUESTS     IPSYSTEMSTATSENTRY, 21
+#define IPSYSTEMSTATSOUTNOROUTES       IPSYSTEMSTATSENTRY, 22
+#define IPSYSTEMSTATSOUTFORWDATAGRAMS  IPSYSTEMSTATSENTRY, 23
+#define IPSYSTEMSTATSHCOUTfORWDATAGRAMS        IPSYSTEMSTATSENTRY, 24
+#define IPSYSTEMSTATSOUTDISCARDS       IPSYSTEMSTATSENTRY, 25
+#define IPSYSTEMSTATSOUTFRAGREQDS      IPSYSTEMSTATSENTRY, 26
+#define IPSYSTEMSTATSOUTFRAGOKS                IPSYSTEMSTATSENTRY, 27
+#define IPSYSTEMSTATSOUTFRAGFAILS      IPSYSTEMSTATSENTRY, 28
+#define IPSYSTEMSTATSOUTFRAGCREATES    IPSYSTEMSTATSENTRY, 29
+#define IPSYSTEMSTATSOUTTRANSMITS      IPSYSTEMSTATSENTRY, 30
+#define IPSYSTEMSTATSHCOUTTRANSMITS    IPSYSTEMSTATSENTRY, 31
+#define IPSYSTEMSTATSOUTOCTETS         IPSYSTEMSTATSENTRY, 32
+#define IPSYSTEMSTATSHCOUTOCTETS       IPSYSTEMSTATSENTRY, 33
+#define IPSYSTEMSTATSINMCASTPKTS       IPSYSTEMSTATSENTRY, 34
+#define IPSYSTEMSTATSHCINMCASTPKTS     IPSYSTEMSTATSENTRY, 35
+#define IPSYSTEMSTATSINMCASTOCTETS     IPSYSTEMSTATSENTRY, 36
+#define IPSYSTEMSTATSHCINMCASTOCTETS   IPSYSTEMSTATSENTRY, 37
+#define IPSYSTEMSTATSOUTMCASTPKTS      IPSYSTEMSTATSENTRY, 38
+#define IPSYSTEMSTATSHCOUTMCASTPKTS    IPSYSTEMSTATSENTRY, 39
+#define IPSYSTEMSTATSOUTMCASTOCTETS    IPSYSTEMSTATSENTRY, 40
+#define IPSYSTEMSTATSHCOUTMCASTOCTETS  IPSYSTEMSTATSENTRY, 41
+#define IPSYSTEMSTATSINBCASTPKTS       IPSYSTEMSTATSENTRY, 42
+#define IPSYSTEMSTATSHCINBCASTPKTS     IPSYSTEMSTATSENTRY, 43
+#define IPSYSTEMSTATSOUTBCASTPKTS      IPSYSTEMSTATSENTRY, 44
+#define IPSYSTEMSTATSHCOUTBCASTPKTS    IPSYSTEMSTATSENTRY, 45
+#define IPSYSTEMSTATSDISCONTINUITYTIME IPSYSTEMSTATSENTRY, 46
+#define IPSYSTEMSTATSREFRESHRATE       IPSYSTEMSTATSENTRY, 47
+#define IPIFSTATSTABLELASTCHANGE       IPTRAFFICSTATS, 2
+#define IPIFSTATSTABLE                 IPTRAFFICSTATS, 3
+#define IPIFSTATSENTRY                 IPIFSTATSTABLE, 1
+#define IPIFSTATSIPVERSION             IPIFSTATSENTRY, 1
+#define IPIFSTATSIFINDEX               IPIFSTATSENTRY, 2
+#define IPIFSTATSINRECEIVES            IPIFSTATSENTRY, 3
+#define IPIFSTATSHCINRECEIVES          IPIFSTATSENTRY, 4
+#define IPIFSTATSINOCTETS              IPIFSTATSENTRY, 5
+#define IPIFSTATSHCINOCTETS            IPIFSTATSENTRY, 6
+#define IPIFSTATSINHDRERRORS           IPIFSTATSENTRY, 7
+#define IPIFSTATSINNOROUTES            IPIFSTATSENTRY, 8
+#define IPIFSTATSINADDRERRORS          IPIFSTATSENTRY, 9
+#define IPIFSTATSINUNKNOWNPROTOS       IPIFSTATSENTRY, 10
+#define IPIFSTATSINTRUNCATEDPKTS       IPIFSTATSENTRY, 11
+#define IPIFSTATSINFORWDATAGRAMS       IPIFSTATSENTRY, 12
+#define IPIFSTATSHCINFORWDATAGRAMS     IPIFSTATSENTRY, 13
+#define IPIFSTATSREASMREQDS            IPIFSTATSENTRY, 14
+#define IPIFSTATSREASMOKS              IPIFSTATSENTRY, 15
+#define IPIFSTATSREASMFAILS            IPIFSTATSENTRY, 16
+#define IPIFSTATSINDISCARDS            IPIFSTATSENTRY, 17
+#define IPIFSTATSINDELIVERS            IPIFSTATSENTRY, 18
+#define IPIFSTATSHCINDELIVERS          IPIFSTATSENTRY, 19
+#define IPIFSTATSOUTREQUESTS           IPIFSTATSENTRY, 20
+#define IPIFSTATSHCOUTREQUESTS         IPIFSTATSENTRY, 21
+#define IPIFSTATSOUTFORWDATAGRAMS      IPIFSTATSENTRY, 23
+#define IPIFSTATSHCOUTFORWDATAGRAMS    IPIFSTATSENTRY, 24
+#define IPIFSTATSOUTDISCARDS           IPIFSTATSENTRY, 25
+#define iPIFSTATSOUTFRAGREQDS          IPIFSTATSENTRY, 26
+#define IPIFSTATSOUTFRAGOKS            IPIFSTATSENTRY, 27
+#define IPIFSTATSOUTFRAGFAILS          IPIFSTATSENTRY, 28
+#define IPIFSTATSOUTFRAGCREATES                IPIFSTATSENTRY, 29
+#define IPIFSTATSOUTTRANSMITS          IPIFSTATSENTRY, 30
+#define IPIFSTATSHCOUTTRANSMITS                IPIFSTATSENTRY, 31
+#define IPIFSTATSOUTOCTETS             IPIFSTATSENTRY, 32
+#define IPIFSTATSHCOUTOCTETS           IPIFSTATSENTRY, 33
+#define IPIFSTATSINMCASTPKTS           IPIFSTATSENTRY, 34
+#define IPIFSTATSHCINMCASTPKTS         IPIFSTATSENTRY, 35
+#define IPIFSTATSINMCASTOCTETS         IPIFSTATSENTRY, 36
+#define IPIFSTATSHCINMCASTOCTETS       IPIFSTATSENTRY, 37
+#define IPIFSTATSOUTMCASTPKTS          IPIFSTATSENTRY, 38
+#define IPIFSTATSHCOUTMCASTPKTS                IPIFSTATSENTRY, 39
+#define IPIFSTATSOUTMCASTOCTETS                IPIFSTATSENTRY, 40
+#define IPIFSTATSHCOUTMCASTOCTETS      IPIFSTATSENTRY, 41
+#define IPIFSTATSINBCASTPKTS           IPIFSTATSENTRY, 42
+#define IPIFSTATSHCINBCASTPKTS         IPIFSTATSENTRY, 43
+#define IPIFSTATSOUTBCASTPKTS          IPIFSTATSENTRY, 44
+#define IPIFSTATSHCOUTBCASTPKTS                IPIFSTATSENTRY, 45
+#define IPIFSTATSDISCONTINUITYTIME     IPIFSTATSENTRY, 46
+#define IPIFSTATSREFRESHRATE           IPIFSTATSENTRY, 47
+#define IPADDRESSPREFIXTABLE           IP, 32
+#define IPADDRESSPREFIXENTRY           IPADDRESSPREFIXTABLE, 1
+#define IPADDRESSPREFIXIFINDEX         IPADDRESSPREFIXENTRY, 1
+#define IPADDRESSPREFIXTYPE            IPADDRESSPREFIXENTRY, 2
+#define IPADDRESSPREFIXPREFIX          IPADDRESSPREFIXENTRY, 3
+#define IPADDRESSPREFIXLENGTH          IPADDRESSPREFIXENTRY, 4
+#define IPADDRESSPREFIXORIGIN          IPADDRESSPREFIXENTRY, 5
+#define IPADDRESSPREFIXONLINKFLAG      IPADDRESSPREFIXENTRY, 6
+#define IPADDRESSPREFIXAUTONOMOUSFLAG  IPADDRESSPREFIXENTRY, 7
+#define IPADDRESSPREFIXADVPREFERREDLIFETIME IPADDRESSPREFIXENTRY, 8
+#define IPADDRESSPREFIXADVVALIDLIFETIME        IPADDRESSPREFIXENTRY, 9
+#define IPADDRESSSPINLOCK              IP, 33
+#define IPADDRESSTABLE                 IP, 34
+#define IPADDRESSENTRY                 IPADDRESSTABLE, 1
+#define IPADDRESSADDRTYPE              IPADDRESSENTRY, 1
+#define IPADDRESSADDR                  IPADDRESSENTRY, 2
+#define IPADDRESSIFINDEX               IPADDRESSENTRY, 3
+#define IPADDRESSTYPE                  IPADDRESSENTRY, 4
+#define IPADDRESSPREFIX                        IPADDRESSENTRY, 5
+#define IPADDRESSORIGIN                        IPADDRESSENTRY, 6
+#define IPADDRESSSTATUS                        IPADDRESSENTRY, 7
+#define IPADDRESSCREATED               IPADDRESSENTRY, 8
+#define IPADDRESSLASTCHANGED           IPADDRESSENTRY, 9
+#define IPADDRESSROWSTATUS             IPADDRESSENTRY, 10
+#define IPADDRESSSTORAGETYPE           IPADDRESSENTRY, 11
+#define IPNETTOPHYSICALTABLE           IP, 35
+#define IPNETTOPHYSICALENTRY           IPNETTOPHYSICALTABLE, 1
+#define IPNETTOPHYSICALIFINDEX         IPNETTOPHYSICALENTRY, 1
+#define IPNETTOPHYSICALNETADDRESSTYPE  IPNETTOPHYSICALENTRY, 2
+#define IPNETTOPHYSICALNETADDRESS      IPNETTOPHYSICALENTRY, 3
+#define IPNETTOPHYSICALPHYSADDRESS     IPNETTOPHYSICALENTRY, 4
+#define IPNETTOPHYSICALLASTUPDATED     IPNETTOPHYSICALENTRY, 5
+#define IPNETTOPHYSICALTYPE            IPNETTOPHYSICALENTRY, 6
+#define IPNETTOPHYSICALSTATE           IPNETTOPHYSICALENTRY, 7
+#define IPNETTOPHYSICALROWSTATUS       IPNETTOPHYSICALENTRY, 8
+#define IPV6SCOPEZONEINDEXTABLE                IP, 36
+#define IPV6SCOPEZONEINDEXENTRY                IPV6SCOPEZONEINDEXTABLE, 1
+#define IPV6SCOPEZONEINDEXIFINDEX      IPV6SCOPEZONEINDEXENTRY, 1
+#define IPV6SCOPEZONEINDEXLINKLOCAL    IPV6SCOPEZONEINDEXENTRY, 2
+#define IPV6SCOPEZONEINDEX3            IPV6SCOPEZONEINDEXENTRY, 3
+#define IPV6SCOPEZONEINDEXADMINLOCAL   IPV6SCOPEZONEINDEXENTRY, 4
+#define IPV6SCOPEZONEINDEXSITELOCAL    IPV6SCOPEZONEINDEXENTRY, 5
+#define IPV6SCOPEZONEINDEX6            IPV6SCOPEZONEINDEXENTRY, 6
+#define IPV6SCOPEZONEINDEX7            IPV6SCOPEZONEINDEXENTRY, 7
+#define IPV6SCOPEZONEINDEXORGANIZATIONLOCAL IPV6SCOPEZONEINDEXENTRY, 8
+#define IPV6SCOPEZONEINDEX9            IPV6SCOPEZONEINDEXENTRY, 9
+#define IPV6SCOPEZONEINDEXA            IPV6SCOPEZONEINDEXENTRY, 10
+#define IPV6SCOPEZONEINDEXB            IPV6SCOPEZONEINDEXENTRY, 11
+#define IPV6SCOPEZONEINDEXC            IPV6SCOPEZONEINDEXENTRY, 12
+#define IPV6SCOPEZONEINDEXD            IPV6SCOPEZONEINDEXENTRY, 13
+#define IPDEFAULTROUTERTABLE           IP, 37
+#define IPDEFAULTROUTERENTRY           IPDEFAULTROUTERTABLE, 1
+#define IPDEFAULTROUTERADDRESSTYPE     IPDEFAULTROUTERENTRY, 1
+#define IPDEFAULTROUTERADDRESS         IPDEFAULTROUTERENTRY, 2
+#define IPDEFAULTROUTERIFINDEX         IPDEFAULTROUTERENTRY, 3
+#define IPDEFAULTROUTERLIFETIME                IPDEFAULTROUTERENTRY, 4
+#define IPDEFAULTROUTERPREFERENCE      IPDEFAULTROUTERENTRY, 5
+#define IPV6ROUTERADVERTSPINLOCK       IP, 38
+#define IPV6ROUTERADVERTTABLE          IP, 39
+#define IPV6ROUTERADVERTENTRY          IPV6ROUTERADVERTTABLE, 1
+#define IPV6ROUTERADVERTIFINDEX                IPV6ROUTERADVERTENTRY, 1
+#define IPV6ROUTERADVERTSENDADVERTS    IPV6ROUTERADVERTENTRY, 2
+#define IPV6ROUTERADVERTMAXINTERVAL    IPV6ROUTERADVERTENTRY, 3
+#define IPV6ROUTERADVERTMININTERVAL    IPV6ROUTERADVERTENTRY, 4
+#define IPV6ROUTERADVERTMANAGEDFLAG    IPV6ROUTERADVERTENTRY, 5
+#define IPV6ROUTERADVERTOTHERCONFIGFLAG        IPV6ROUTERADVERTENTRY, 6
+#define IPV6ROUTERADVERTLINKMTU                IPV6ROUTERADVERTENTRY, 7
+#define IPV6ROUTERADVERTREACHABLETIME  IPV6ROUTERADVERTENTRY, 8
+#define IPV6ROUTERADVERTRETRANSMITTIME IPV6ROUTERADVERTENTRY, 9
+#define IPV6ROUTERADVERTCURHOPLIMIT    IPV6ROUTERADVERTENTRY, 10
+#define IPV6ROUTERADVERTDEFAULTLIFETIME        IPV6ROUTERADVERTENTRY, 11
+#define IPV6ROUTERADVERTROWSTATUS      IPV6ROUTERADVERTENTRY, 12
+#define ICMP                           AGENTX_MIB2, 5
+#define ICMPSTATSTABLE                 ICMP, 29
+#define ICMPSTATSENTRY                 ICMPSTATSTABLE, 1
+#define ICMPSTATSIPVERSION             ICMPSTATSENTRY, 1
+#define ICMPSTATSINMSGS                        ICMPSTATSENTRY, 2
+#define ICMPSTATSINERRORS              ICMPSTATSENTRY, 3
+#define ICMPSTATSOUTMSGS               ICMPSTATSENTRY, 4
+#define ICMPSTATSOUTERRORS             ICMPSTATSENTRY, 5
+#define ICMPMSGSTATSTABLE              ICMP, 30
+#define ICMPMSGSTATSENTRY              ICMPMSGSTATSTABLE, 1
+#define ICMPMSGSTATSIPVERSION          ICMPMSGSTATSENTRY, 1
+#define ICMPMSGSTATSTYPE               ICMPMSGSTATSENTRY, 2
+#define ICMPMSGSTATSINPKTS             ICMPMSGSTATSENTRY, 3
+#define ICMPMSGSTATSOUTPKTS            ICMPMSGSTATSENTRY, 4
+#define IPINRECEIVES                   IP, 3
+#define IPINHDRERRORS                  IP, 4
+#define IPINADDRERRORS                 IP, 5
+#define IPFORWDATAGRAMS                        IP, 6
+#define IPINUNKNOWNPROTOS              IP, 7
+#define IPINDISCARDS                   IP, 8
+#define IPINDELIVERS                   IP, 9
+#define IPOUTREQUESTS                  IP, 10
+#define IPOUTDISCARDS                  IP, 11
+#define IPOUTNOROUTES                  IP, 12
+#define IPREASMREQDS                   IP, 14
+#define IPREASMOKS                     IP, 15
+#define IPREASMFAILS                   IP, 16
+#define IPFRAGOKS                      IP, 17
+#define IPFRAGFAILS                    IP, 18
+#define IPFRAGCREATES                  IP, 19
+#define IPROUTINGDISCARDS              IP, 23
+#define IPADDRTABLE                    IP, 20
+#define IPADDRENTRY                    IPADDRTABLE, 1
+#define IPADENTADDR                    IPADDRENTRY, 1
+#define IPADENTIFINDEX                 IPADDRENTRY, 2
+#define IPADENTNETMASK                 IPADDRENTRY, 3
+#define IPADENTBCASTADDR               IPADDRENTRY, 4
+#define IPADENTREASMMAXSIZE            IPADDRENTRY, 5
+#define IPNETTOMEDIATABLE              IP, 22
+#define IPNETTOMEDIAENTRY              IPNETTOMEDIATABLE, 1
+#define IPNETTOMEDIAIFINDEX            IPNETTOMEDIAENTRY, 1
+#define IPNETTOMEDIAPHYSADDRESS                IPNETTOMEDIAENTRY, 2
+#define IPNETTOMEDIANETADDRESS         IPNETTOMEDIAENTRY, 3
+#define IPNETTOMEDIATYPE               IPNETTOMEDIAENTRY, 4
+#define ICMPINMSGS                     ICMP, 1
+#define ICMPINERRORS                   ICMP, 2
+#define ICMPINDESTUNREACHS             ICMP, 3
+#define ICMPINTIMEEXCDS                        ICMP, 4
+#define ICMPINPARMPROBS                        ICMP, 5
+#define ICMPINSRCQUENCHS               ICMP, 6
+#define ICMPINREDIRECTS                        ICMP, 7
+#define ICMPINECHOS                    ICMP, 8
+#define ICMPINECHOREPS                 ICMP, 9
+#define ICMPINTIMESTAMPS               ICMP, 10
+#define ICMPINTIMESTAMPREPS            ICMP, 11
+#define ICMPINADDRMASKS                        ICMP, 12
+#define ICMPINADDRMASKREPS             ICMP, 13
+#define ICMPOUTMSGS                    ICMP, 14
+#define ICMPOUTERRORS                  ICMP, 15
+#define ICMPOUTDESTUNREACHS            ICMP, 16
+#define ICMPOUTTIMEEXCDS               ICMP, 17
+#define ICMPOUTPARMPROBS               ICMP, 18
+#define ICMPOUTSRCQUENCHS              ICMP, 19
+#define ICMPOUTREDIRECTS               ICMP, 20
+#define ICMPOUTECHOS                   ICMP, 21
+#define ICMPOUTECHOREPS                        ICMP, 22
+#define ICMPOUTTIMESTAMPS              ICMP, 23
+#define ICMPOUTTIMESTAMPREPS           ICMP, 24
+#define ICMPOUTADDRMASKS               ICMP, 25
+#define ICMPOUTADDRMASKREPS            ICMP, 26
+
+/* IP-FORWARD-MIB */
+#define IPFORWARD                      IP, 24
+#define INETCIDRROUTENUMBER            IPFORWARD, 6
+#define INETCIDRROUTEDISCARDS          IPFORWARD, 8
+#define INETCIDRROUTETABLE             IPFORWARD, 7
+#define INETCIDRROUTEENTRY             INETCIDRROUTETABLE, 1
+#define INETCIDRROUTEDESTTYPE          INETCIDRROUTEENTRY, 1
+#define INETCIDRROUTEDEST              INETCIDRROUTEENTRY, 2
+#define INETCIDRROUTEPFXLEN            INETCIDRROUTEENTRY, 3
+#define INETCIDRROUTEPOLICY            INETCIDRROUTEENTRY, 4
+#define INETCIDRROUTENEXTHOPTYPE       INETCIDRROUTEENTRY, 5
+#define INETCIDRROUTENEXTHOP           INETCIDRROUTEENTRY, 6
+#define INETCIDRROUTEIFINDEX           INETCIDRROUTEENTRY, 7
+#define INETCIDRROUTETYPE              INETCIDRROUTEENTRY, 8
+#define INETCIDRROUTEPROTO             INETCIDRROUTEENTRY, 9
+#define INETCIDRROUTEAGE               INETCIDRROUTEENTRY, 10
+#define INETCIDRROUTENEXTHOPAS         INETCIDRROUTEENTRY, 11
+#define INETCIDRROUTEMETRIC1           INETCIDRROUTEENTRY, 12
+#define INETCIDRROUTEMETRIC2           INETCIDRROUTEENTRY, 13
+#define INETCIDRROUTEMETRIC3           INETCIDRROUTEENTRY, 14
+#define INETCIDRROUTEMETRIC4           INETCIDRROUTEENTRY, 15
+#define INETCIDRROUTEMETRIC5           INETCIDRROUTEENTRY, 16
+#define INETCIDRROUTESTATUS            INETCIDRROUTEENTRY, 17
+/* Deprecated */
+#define IPCIDRROUTENUMBER              IPFORWARD, 3
+#define IPCIDRROUTETABLE               IPFORWARD, 4
+#define IPCIDRROUTEENTRY               IPCIDRROUTETABLE, 1
+#define IPCIDRROUTEDEST                        IPCIDRROUTEENTRY, 1
+#define IPCIDRROUTEMASK                        IPCIDRROUTEENTRY, 2
+#define IPCIDRROUTETOS                 IPCIDRROUTEENTRY, 3
+#define IPCIDRROUTENEXTHOP             IPCIDRROUTEENTRY, 4
+#define IPCIDRROUTEIFINDEX             IPCIDRROUTEENTRY, 5
+#define IPCIDRROUTETYPE                        IPCIDRROUTEENTRY, 6
+#define IPCIDRROUTEPROTO               IPCIDRROUTEENTRY, 7
+#define IPCIDRROUTEAGE                 IPCIDRROUTEENTRY, 8
+#define IPCIDRROUTEINFO                        IPCIDRROUTEENTRY, 9
+#define IPCIDRROUTENEXTHOPAS           IPCIDRROUTEENTRY, 10
+#define IPCIDRROUTEMETRIC1             IPCIDRROUTEENTRY, 11
+#define IPCIDRROUTEMETRIC2             IPCIDRROUTEENTRY, 12
+#define IPCIDRROUTEMETRIC3             IPCIDRROUTEENTRY, 13
+#define IPCIDRROUTEMETRIC4             IPCIDRROUTEENTRY, 14
+#define IPCIDRROUTEMETRIC5             IPCIDRROUTEENTRY, 15
+#define IPCIDRROUTESTATUS              IPCIDRROUTEENTRY, 16
+/* Obsolete */
+#define IPFORWARDNUMBER                        IPFORWARD, 1
+#define IPFORWARDTABLE                 IPFORWARD, 2
+#define IPFORWARDENTRY                 IPFORWARDTABLE, 1
+#define IPFORWARDDEST                  IPFORWARDENTRY, 1
+#define IPFORWARDMASK                  IPFORWARDENTRY, 2
+#define IPFORWARDPOLICY                        IPFORWARDENTRY, 3
+#define IPFORWARDNEXTHOP               IPFORWARDENTRY, 4
+#define IPFORWARDIFINDEX               IPFORWARDENTRY, 5
+#define IPFORWARDTYPE                  IPFORWARDENTRY, 6
+#define IPFORWARDPROTO                 IPFORWARDENTRY, 7
+#define IPFORWARDAGE                   IPFORWARDENTRY, 8
+#define IPFORWARDINFO                  IPFORWARDENTRY, 9
+#define IPFORWARDNEXTHOPAS             IPFORWARDENTRY, 10
+#define IPFORWARDMETRIC1               IPFORWARDENTRY, 11
+#define IPFORWARDMETRIC2               IPFORWARDENTRY, 12
+#define IPFORWARDMETRIC3               IPFORWARDENTRY, 13
+#define IPFORWARDMETRIC4               IPFORWARDENTRY, 13
+#define IPFORWARDMETRIC5               IPFORWARDENTRY, 13
+
+/* UCD-SNMP-MIB */
+#define UCDAVIS                                AGENTX_ENTERPRISES, 2021
+#define UCDEXPERIMENTAL                        UCDAVIS, 13
+
+/* UCD-DISKIO-MIB */
+#define UCDDISKIOMIB                   UCDEXPERIMENTAL, 15
+#define DISKIOTABLE                    UCDDISKIOMIB, 1
+#define DISKIOENTRY                    DISKIOTABLE, 1
+#define DISKIOINDEX                    DISKIOENTRY, 1
+#define DISKIODEVICE                   DISKIOENTRY, 2
+#define DISKIONREAD                    DISKIOENTRY, 3
+#define DISKIONWRITTEN                 DISKIOENTRY, 4
+#define DISKIOREADS                    DISKIOENTRY, 5
+#define DISKIOWRITES                   DISKIOENTRY, 6
+#define DISKIOLA1                      DISKIOENTRY, 9
+#define DISKIOLA5                      DISKIOENTRY, 10
+#define DISKIOLA15                     DISKIOENTRY, 11
+#define DISKIONREADX                   DISKIOENTRY, 12
+#define DISKIONWRITTENX                        DISKIOENTRY, 13
+#define DISKIOBUSYTIME                 DISKIOENTRY, 14
+
+/* BRIDGE-MIB */
+#define DOT1DBRIDGE                    AGENTX_MIB2, 17
+#define DOT1DNOTIFICATIONS             DOT1DBRIDGE, 0
+#define DOT1DBASE                      DOT1DBRIDGE, 1
+#define DOT1DSTP                       DOT1DBRIDGE, 2
+#define DOT1DSR                                DOT1DBRIDGE, 3
+#define DOT1DTP                                DOT1DBRIDGE, 4
+#define DOT1DSTATIC                    DOT1DBRIDGE, 5
+#define DOT1DBASEBRIDGEADDRESS         DOT1DBASE, 1
+#define DOT1DBASENUMPORTS              DOT1DBASE, 2
+#define DOT1DBASETYPE                  DOT1DBASE, 3
+#define DOT1DBASEPORTTABLE             DOT1DBASE, 4
+#define DOT1DBASEPORTENTRY             DOT1DBASEPORTTABLE, 1
+#define DOT1DBASEPORT                  DOT1DBASEPORTENTRY, 1
+#define DOT1DBASEPORTIFINDEX           DOT1DBASEPORTENTRY, 2
+#define DOT1DBASEPORTCIRCUIT           DOT1DBASEPORTENTRY, 3
+#define DOT1DBASEPORTDELAYEXCEEDEDDISCARDS DOT1DBASEPORTENTRY, 4
+#define DOT1DBASEPORTMTUEXCEEDEDDISCARDS DOT1DBASEPORTENTRY, 5
+#define DOT1DSTPPROTOCOLSPECIFICATION  DOT1DSTP, 1
+#define DOT1DSTPPRIORITY               DOT1DSTP, 2
+#define DOT1DSTPTIMESINCETOPOLOGYCHANGE        DOT1DSTP, 3
+#define DOT1DSTPTOPCHANGES             DOT1DSTP, 4
+#define DOT1DSTPDESIGNATEDROOT         DOT1DSTP, 5
+#define DOT1DSTPROOTCOST               DOT1DSTP, 6
+#define DOT1DSTPROOTPORT               DOT1DSTP, 7
+#define DOT1DSTPMAXAGE                 DOT1DSTP, 8
+#define DOT1DSTPHELLOTIME              DOT1DSTP, 9
+#define DOT1DSTPHOLDTIME               DOT1DSTP, 10
+#define DOT1DSTPFORWARDDELAY           DOT1DSTP, 11
+#define DOT1DSTPBRIDGEMAXAGE           DOT1DSTP, 12
+#define DOT1DSTPBRIDGEHELLOTIME                DOT1DSTP, 13
+#define DOT1DSTPBRIDGEFORWARDDELAY     DOT1DSTP, 14
+#define DOT1DSTPPORTTABLE              DOT1DSTP, 15
+#define DOT1DSTPPORTENTRY              DOT1DSTPPORTTABLE, 1
+#define DOT1DSTPPORT                   DOT1DSTPPORTENTRY, 1
+#define DOT1DSTPPORTPRIORITY           DOT1DSTPPORTENTRY, 2
+#define DOT1DSTPPORTSTATE              DOT1DSTPPORTENTRY, 3
+#define DOT1DSTPPORTENABLE             DOT1DSTPPORTENTRY, 4
+#define DOT1DSTPPORTPATHCOST           DOT1DSTPPORTENTRY, 5
+#define DOT1DSTPPORTDESIGNATEDROOT     DOT1DSTPPORTENTRY, 6
+#define DOT1DSTPPORTDESIGNATEDCOST     DOT1DSTPPORTENTRY, 7
+#define DOT1DSTPPORTDESIGNATEDBRIDGE   DOT1DSTPPORTENTRY, 8
+#define DOT1DSTPPORTDESIGNATEDPORT     DOT1DSTPPORTENTRY, 9
+#define DOT1DSTPPORTFORWARDTRANSITIONS DOT1DSTPPORTENTRY, 10
+#define DOT1DSTPPORTPATHCOST32         DOT1DSTPPORTENTRY, 11
+#define DOT1DTPLEARNEDENTRYDISCARDS    DOT1DTP, 1
+#define DOT1DTPAGINGTIME               DOT1DTP, 2
+#define DOT1DTPFDBTABLE                        DOT1DTP, 3
+#define DOT1DTPFDBENTRY                        DOT1DTPFDBTABLE, 1
+#define DOT1DTPFDBADDRESS              DOT1DTPFDBENTRY, 1
+#define DOT1DTPFDBPORT                 DOT1DTPFDBENTRY, 2
+#define DOT1DTPFDBSTATUS               DOT1DTPFDBENTRY, 3
+#define DOT1DTPPORTTABLE               DOT1DTP, 4
+#define DOT1DTPPORTENTRY               DOT1DTPPORTTABLE, 1
+#define DOT1DTPPORT                    DOT1DTPPORTENTRY, 1
+#define DOT1DTPPORTMAXINFO             DOT1DTPPORTENTRY, 2
+#define DOT1DTPPORTINFRAMES            DOT1DTPPORTENTRY, 3
+#define DOT1DTPPORTOUTFRAMES           DOT1DTPPORTENTRY, 4
+#define DOT1DTPPORTINDISCARDS          DOT1DTPPORTENTRY, 5
+#define DOT1DSTATICTABLE               DOT1DSTATIC, 1
+#define DOT1DSTATICENTRY               DOT1DSTATICTABLE, 1
+#define DOT1DSTATICADDRESS             DOT1DSTATICENTRY, 1
+#define DOT1DSTATICRECEIVEPORT         DOT1DSTATICENTRY, 2
+#define DOT1DSTATICALLOWEDTOGOTO       DOT1DSTATICENTRY, 3
+#define DOT1DSTATICSTATUS              DOT1DSTATICENTRY, 4
+#define NEWROOT                                DOT1DNOTIFICATIONS, 1
+#define TOPOLOGYCHANGE                 DOT1DNOTIFICATIONS, 2
diff --git a/libexec/snmpd/snmpd_metrics/pf.c b/libexec/snmpd/snmpd_metrics/pf.c
new file mode 100644 (file)
index 0000000..a4b6096
--- /dev/null
@@ -0,0 +1,501 @@
+/*     $OpenBSD: pf.c,v 1.1.1.1 2022/09/01 14:20:33 martijn Exp $      */
+
+/*
+ * Copyright (c) 2012 Joel Knight <joel@openbsd.org>
+ * Copyright (c) 2002 Cedric Berger
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *    - Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *    - Redistributions in binary form must reproduce the above
+ *      copyright notice, this list of conditions and the following
+ *      disclaimer in the documentation and/or other materials provided
+ *      with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <net/if.h>
+#include <net/pfvar.h>
+
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <event.h>
+
+#include "snmpd.h"
+
+int     devpf = 0;
+
+size_t          buf_esize[PFRB_MAX] = { 0,
+       sizeof(struct pfr_table), sizeof(struct pfr_tstats),
+       sizeof(struct pfr_addr), sizeof(struct pfr_astats),
+       sizeof(struct pfi_kif), sizeof(struct pfioc_trans_e)
+};
+
+void
+pf_init(void)
+{
+       if ((devpf = open("/dev/pf", O_RDONLY)) == -1)
+               fatal("pf_init");
+}
+
+int
+pf_get_stats(struct pf_status *s)
+{
+       extern int       devpf;
+
+       memset(s, 0, sizeof(*s));
+       if (ioctl(devpf, DIOCGETSTATUS, s) == -1) {
+               log_warn("DIOCGETSTATUS");
+               return (-1);
+       }
+
+       return (0);
+}
+
+int
+pfr_get_astats(struct pfr_table *tbl, struct pfr_astats *addr, int *size,
+               int flags)
+{
+       struct pfioc_table       io;
+       extern int               devpf;
+
+       if (tbl == NULL || size == NULL || *size < 0 ||
+           (*size && addr == NULL)) 
+               return (-1);
+
+       bzero(&io, sizeof io);
+       io.pfrio_flags = flags;
+       io.pfrio_table = *tbl;
+       io.pfrio_buffer = addr;
+       io.pfrio_esize = sizeof(*addr);
+       io.pfrio_size = *size;
+       if (ioctl(devpf, DIOCRGETASTATS, &io) == -1) 
+               return (-1);
+       *size = io.pfrio_size;
+       return (0);
+}
+
+int
+pfr_get_tstats(struct pfr_table *filter, struct pfr_tstats *tbl, int *size,
+       int flags)
+{
+       struct pfioc_table       io;
+       extern int               devpf;
+
+       if (size == NULL || *size < 0 || (*size && tbl == NULL))
+               return (-1);
+       bzero(&io, sizeof io);
+       io.pfrio_flags = flags;
+       if (filter != NULL)
+               io.pfrio_table = *filter;
+       io.pfrio_buffer = tbl;
+       io.pfrio_esize = sizeof(*tbl);
+       io.pfrio_size = *size;
+       if (ioctl(devpf, DIOCRGETTSTATS, &io) == -1)
+               return (-1);
+       *size = io.pfrio_size;
+       return (0);
+}
+
+int
+pfr_buf_grow(struct pfr_buffer *b, int minsize)
+{
+       caddr_t  p;
+       size_t   bs;
+
+       if (minsize != 0 && minsize <= b->pfrb_msize)
+               return (0);
+       bs = buf_esize[b->pfrb_type];
+       if (!b->pfrb_msize) {
+               if (minsize < 64)
+                       minsize = 64;
+               b->pfrb_caddr = calloc(bs, minsize);
+               if (b->pfrb_caddr == NULL)
+                       return (-1);
+               b->pfrb_msize = minsize;
+       } else {
+               if (minsize == 0)
+                       minsize = b->pfrb_msize * 2;
+               if (minsize < 0 || (size_t)minsize >= SIZE_MAX / bs) {
+                       /* msize overflow */
+                       return (-1);
+               }
+               p = reallocarray(b->pfrb_caddr, minsize, bs);
+               if (p == NULL)
+                       return (-1);
+               bzero(p + b->pfrb_msize * bs, (minsize - b->pfrb_msize) * bs);
+               b->pfrb_caddr = p;
+               b->pfrb_msize = minsize;
+       }
+       return (0);
+}
+
+const void *
+pfr_buf_next(struct pfr_buffer *b, const void *prev)
+{
+       size_t   bs;
+
+       if (b == NULL)
+               return (NULL);
+       if (b->pfrb_size == 0)
+               return (NULL);
+       if (prev == NULL) 
+               return (b->pfrb_caddr);
+       bs = buf_esize[b->pfrb_type];
+       if ((((const char *)prev)-((char *)b->pfrb_caddr)) / bs >=
+           (size_t)b->pfrb_size-1)
+               return (NULL);
+
+       return (((const char *)prev) + bs);
+}
+
+int
+pfi_get_ifaces(const char *filter, struct pfi_kif *buf, int *size)
+{
+       struct pfioc_iface       io;
+       extern int               devpf;
+
+       if (size == NULL || *size < 0 || (*size && buf == NULL)) {
+               errno = EINVAL;
+               return (-1);
+       }
+       bzero(&io, sizeof io);
+       if (filter != NULL)
+               if (strlcpy(io.pfiio_name, filter, sizeof(io.pfiio_name)) >=
+                   sizeof(io.pfiio_name)) {
+                       errno = EINVAL;
+                       return (-1);
+               }
+       io.pfiio_buffer = buf;
+       io.pfiio_esize = sizeof(*buf);
+       io.pfiio_size = *size;
+       if (ioctl(devpf, DIOCIGETIFACES, &io) == -1)
+               return (-1);
+       *size = io.pfiio_size;
+       return (0);
+}
+
+int
+pfi_get(struct pfr_buffer *b, const char *filter)
+{
+       bzero(b, sizeof(struct pfr_buffer));
+       b->pfrb_type = PFRB_IFACES;
+       for (;;) {
+               pfr_buf_grow(b, b->pfrb_size);
+               b->pfrb_size = b->pfrb_msize;
+               if (pfi_get_ifaces(filter, b->pfrb_caddr, &(b->pfrb_size)))
+                       return (1);
+               if (b->pfrb_size <= b->pfrb_msize)
+                       break;
+       }
+
+       return (0);
+}
+
+int
+pfi_count(void)
+{
+       struct pfr_buffer        b;
+       const struct pfi_kif    *p;
+       int                      c = 0;
+
+       if (pfi_get(&b, NULL)) {
+               free(b.pfrb_caddr);
+               return (-1);
+       }
+
+       PFRB_FOREACH(p, &b)
+               c++;
+
+       free(b.pfrb_caddr);
+       return (c);
+}
+
+int
+pfi_get_if(struct pfi_kif *rp, int idx)
+{
+       struct pfr_buffer        b;
+       const struct pfi_kif    *p;
+       int                      i = 1;
+
+       if (pfi_get(&b, NULL)) {
+               free(b.pfrb_caddr);
+               return (-1);
+       }
+
+       PFRB_FOREACH(p, &b) {
+               if (i == idx)
+                       break;
+               i++;
+       }
+
+       if (p == NULL) {
+               free(b.pfrb_caddr);
+               return (-1);
+       }
+
+       bcopy(p, rp, sizeof(struct pfi_kif));
+       free(b.pfrb_caddr);
+
+       return (0);
+}
+
+int
+pft_get(struct pfr_buffer *b, struct pfr_table *filter)
+{
+       bzero(b, sizeof(struct pfr_buffer));
+       b->pfrb_type = PFRB_TSTATS;
+       
+       for (;;) {
+               pfr_buf_grow(b, b->pfrb_size);
+               b->pfrb_size = b->pfrb_msize;
+               if (pfr_get_tstats(filter, b->pfrb_caddr, &(b->pfrb_size), 0))
+                       return (1);
+               if (b->pfrb_size <= b->pfrb_msize)
+                       break;
+       }
+
+       return (0);
+}
+
+int
+pft_get_table(struct pfr_tstats *rts, int idx)
+{
+       struct pfr_buffer        b;
+       const struct pfr_tstats *ts;
+       int                      i = 1;
+
+       if (pft_get(&b, NULL)) {
+               free(b.pfrb_caddr);
+               return (-1);
+       }
+       PFRB_FOREACH(ts, &b) {
+               if (!(ts->pfrts_flags & PFR_TFLAG_ACTIVE))
+                       continue;
+               if (i == idx)
+                       break;
+               i++;
+       }
+
+       if (ts == NULL) {
+               free(b.pfrb_caddr);
+               return (-1);
+       }
+
+       bcopy(ts, rts, sizeof(struct pfr_tstats));
+       free(b.pfrb_caddr);
+
+       return (0);
+}
+
+int
+pft_count(void)
+{
+       struct pfr_buffer        b;
+       const struct pfr_tstats *ts;
+       int                      c = 0;
+
+       if (pft_get(&b, NULL)) {
+               free(b.pfrb_caddr);
+               return (-1);
+       }
+
+       PFRB_FOREACH(ts, &b) {
+               if (!(ts->pfrts_flags & PFR_TFLAG_ACTIVE))
+                       continue;
+               c++;
+       }
+
+       free(b.pfrb_caddr);
+       return (c);
+}
+
+int
+pfta_get(struct pfr_buffer *b, struct pfr_table *filter)
+{
+       bzero(b, sizeof(struct pfr_buffer));
+       b->pfrb_type = PFRB_ASTATS;
+
+       for (;;) {
+               pfr_buf_grow(b, b->pfrb_size);
+               b->pfrb_size = b->pfrb_msize;
+               if (pfr_get_astats(filter, b->pfrb_caddr, &(b->pfrb_size), 0)) {
+                       return (1);
+               }
+               if (b->pfrb_size <= b->pfrb_msize)
+                       break;
+       }
+       
+       return (0);
+}
+
+int
+pfta_get_addr(struct pfr_astats *ras, int tblidx)
+{
+       struct pfr_buffer        ba;
+       struct pfr_tstats        ts;
+       struct pfr_table         filter;
+       const struct pfr_astats *as;
+
+       if (pft_get_table(&ts, tblidx))
+               return (-1);
+
+       bzero(&filter, sizeof(filter));
+       if (strlcpy(filter.pfrt_name, ts.pfrts_name,
+           sizeof(filter.pfrt_name)) >= sizeof(filter.pfrt_name)) {
+               return (-1);
+       }
+
+       if (pfta_get(&ba, &filter) || ba.pfrb_size == 0) {
+               free(ba.pfrb_caddr);
+               return (-1);
+       }
+
+       PFRB_FOREACH(as, &ba) {
+               if (as->pfras_a.pfra_af != AF_INET)
+                       continue;
+               if ((memcmp(&as->pfras_a.pfra_ip4addr, &ras->pfras_a.pfra_ip4addr,
+                   sizeof(as->pfras_a.pfra_ip4addr)) == 0)
+                   && (as->pfras_a.pfra_net == ras->pfras_a.pfra_net))
+                       break;
+       }
+
+       if (as == NULL) {
+               free(ba.pfrb_caddr);
+               return (-1);
+       }
+
+       bcopy(as, ras, sizeof(struct pfr_astats));
+       free(ba.pfrb_caddr);
+
+       return (0);
+}
+
+int
+pfta_get_nextaddr(struct pfr_astats *ras, int *tblidx)
+{
+       struct pfr_buffer        ba;
+       struct pfr_tstats        ts;
+       struct pfr_table         filter;
+       const struct pfr_astats *as;
+       int                      i, found = 0, cmp;
+
+       ba.pfrb_caddr = NULL;
+
+       for (i = *tblidx; !pft_get_table(&ts, i); i++) {
+               bzero(&filter, sizeof(filter));
+               if (strlcpy(filter.pfrt_name, ts.pfrts_name,
+                   sizeof(filter.pfrt_name)) >= sizeof(filter.pfrt_name))
+                       goto fail;
+
+               if (pfta_get(&ba, &filter) || ba.pfrb_size == 0)
+                       goto fail;
+
+               PFRB_FOREACH(as, &ba) {
+                       if (as->pfras_a.pfra_af != AF_INET)
+                               continue;
+                       if (found)
+                               goto found;
+                       cmp = memcmp(&as->pfras_a.pfra_ip4addr,
+                           &ras->pfras_a.pfra_ip4addr,
+                           sizeof(as->pfras_a.pfra_ip4addr));
+                       if (cmp == 0) {
+                               if (as->pfras_a.pfra_net ==
+                                   ras->pfras_a.pfra_net)
+                                       found = 1;
+                               if (as->pfras_a.pfra_net >
+                                   ras->pfras_a.pfra_net)
+                                       goto found;
+                       } else if (cmp > 0)
+                               goto found;
+               }
+
+               free(ba.pfrb_caddr);
+               ba.pfrb_caddr = NULL;
+       }
+
+
+ fail:
+       free(ba.pfrb_caddr);
+
+       return (-1);
+
+ found:
+       bcopy(as, ras, sizeof(struct pfr_astats));
+       *tblidx = i;
+
+       free(ba.pfrb_caddr);
+
+       return (0);
+}
+
+int
+pfta_get_first(struct pfr_astats *ras)
+{
+       struct pfr_buffer        ba;
+       struct pfr_tstats        ts;
+       struct pfr_table         filter;
+       const struct pfr_astats *as;
+
+       if (pft_get_table(&ts, 1))
+               return (-1);
+
+       bzero(&filter, sizeof(filter));
+       if (strlcpy(filter.pfrt_name, ts.pfrts_name,
+           sizeof(filter.pfrt_name)) >= sizeof(filter.pfrt_name)) {
+               return (-1);
+       }
+
+       if (pfta_get(&ba, &filter) || ba.pfrb_size == 0) {
+               free(ba.pfrb_caddr);
+               return (-1);
+       }
+
+       /* take the first AF_INET addr */
+       PFRB_FOREACH(as, &ba) {
+               if (as->pfras_a.pfra_af != AF_INET)
+                       continue;
+               break;
+       }
+
+       if (as == NULL) {
+               free(ba.pfrb_caddr);
+               return (-1);
+       }
+
+       bcopy(as, ras, sizeof(struct pfr_astats));
+       free(ba.pfrb_caddr);
+
+       return (0);
+}
+
diff --git a/libexec/snmpd/snmpd_metrics/snmpd.h b/libexec/snmpd/snmpd_metrics/snmpd.h
new file mode 100644 (file)
index 0000000..b764c77
--- /dev/null
@@ -0,0 +1,284 @@
+/*     $OpenBSD: snmpd.h,v 1.1.1.1 2022/09/01 14:20:33 martijn Exp $   */
+
+/*
+ * Copyright (c) 2007, 2008, 2012 Reyk Floeter <reyk@openbsd.org>
+ * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef SNMPD_H
+#define SNMPD_H
+
+#include <sys/tree.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+#include <netinet/ip.h>
+#include <arpa/inet.h>
+#include <net/pfvar.h>
+#include <net/route.h>
+
+#include <ber.h>
+#include <stdio.h>
+#include <imsg.h>
+
+#include "log.h"
+
+#ifndef nitems
+#define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))
+#endif
+
+/*
+ * common definitions for snmpd
+ */
+
+#define CONF_FILE              "/etc/snmpd.conf"
+#define SNMPD_SOCKET           "/var/run/snmpd.sock"
+#define SNMPD_USER             "_snmpd"
+#define SNMP_PORT              "161"
+#define SNMPTRAP_PORT          "162"
+
+#define SNMPD_MAXSTRLEN                484
+#define SNMPD_MAXCOMMUNITYLEN  SNMPD_MAXSTRLEN
+#define SNMPD_MAXVARBIND       0x7fffffff
+#define SNMPD_MAXVARBINDLEN    1210
+#define SNMPD_MAXENGINEIDLEN   32
+#define SNMPD_MAXUSERNAMELEN   32
+#define SNMPD_MAXCONTEXNAMELEN 32
+
+#define SNMP_USM_MAXDIGESTLEN  48
+#define SNMP_USM_SALTLEN       8
+#define SNMP_USM_KEYLEN                64
+#define SNMP_CIPHER_KEYLEN     16
+
+#define SMALL_READ_BUF_SIZE    1024
+#define READ_BUF_SIZE          65535
+#define        RT_BUF_SIZE             16384
+#define        MAX_RTSOCK_BUF          (2 * 1024 * 1024)
+
+#define SNMP_ENGINEID_OLD      0x00
+#define SNMP_ENGINEID_NEW      0x80    /* RFC3411 */
+
+#define SNMP_ENGINEID_FMT_IPv4 1
+#define SNMP_ENGINEID_FMT_IPv6 2
+#define SNMP_ENGINEID_FMT_MAC  3
+#define SNMP_ENGINEID_FMT_TEXT 4
+#define SNMP_ENGINEID_FMT_OCT  5
+#define SNMP_ENGINEID_FMT_HH   129
+
+#define PEN_OPENBSD            30155
+
+#if DEBUG
+#define DPRINTF                log_debug
+#else
+#define DPRINTF(x...)  do {} while(0)
+#endif
+
+/*
+ * kroute
+ */
+
+struct kroute_node;
+struct kroute6_node;
+RB_HEAD(kroute_tree, kroute_node);
+RB_HEAD(kroute6_tree, kroute6_node);
+
+struct ktable {
+       struct kroute_tree       krt;
+       struct kroute6_tree      krt6;
+       u_int                    rtableid;
+       u_int                    rdomain;
+};
+
+union kaddr {
+       struct sockaddr         sa;
+       struct sockaddr_in      sin;
+       struct sockaddr_in6     sin6;
+       struct sockaddr_dl      sdl;
+       char                    pad[32];
+};
+
+struct kroute {
+       struct in_addr  prefix;
+       struct in_addr  nexthop;
+       u_long          ticks;
+       u_int16_t       flags;
+       u_short         if_index;
+       u_int8_t        prefixlen;
+       u_int8_t        priority;
+};
+
+struct kroute6 {
+       struct in6_addr prefix;
+       struct in6_addr nexthop;
+       u_long          ticks;
+       u_int16_t       flags;
+       u_short         if_index;
+       u_int8_t        prefixlen;
+       u_int8_t        priority;
+};
+
+struct kif_addr {
+       u_short                  if_index;
+       union kaddr              addr;
+       union kaddr              mask;
+       union kaddr              dstbrd;
+
+       TAILQ_ENTRY(kif_addr)    entry;
+       RB_ENTRY(kif_addr)       node;
+};
+
+struct kif_arp {
+       u_short                  flags;
+       u_short                  if_index;
+       union kaddr              addr;
+       union kaddr              target;
+
+       TAILQ_ENTRY(kif_arp)     entry;
+};
+
+struct kif {
+       char                     if_name[IF_NAMESIZE];
+       char                     if_descr[IFDESCRSIZE];
+       u_int8_t                 if_lladdr[ETHER_ADDR_LEN];
+       struct if_data           if_data;
+       u_long                   if_ticks;
+       int                      if_flags;
+       u_short                  if_index;
+};
+#define        if_mtu          if_data.ifi_mtu
+#define        if_type         if_data.ifi_type
+#define        if_addrlen      if_data.ifi_addrlen
+#define        if_hdrlen       if_data.ifi_hdrlen
+#define        if_metric       if_data.ifi_metric
+#define        if_link_state   if_data.ifi_link_state
+#define        if_baudrate     if_data.ifi_baudrate
+#define        if_ipackets     if_data.ifi_ipackets
+#define        if_ierrors      if_data.ifi_ierrors
+#define        if_opackets     if_data.ifi_opackets
+#define        if_oerrors      if_data.ifi_oerrors
+#define        if_collisions   if_data.ifi_collisions
+#define        if_ibytes       if_data.ifi_ibytes
+#define        if_obytes       if_data.ifi_obytes
+#define        if_imcasts      if_data.ifi_imcasts
+#define        if_omcasts      if_data.ifi_omcasts
+#define        if_iqdrops      if_data.ifi_iqdrops
+#define        if_oqdrops      if_data.ifi_oqdrops
+#define        if_noproto      if_data.ifi_noproto
+#define        if_lastchange   if_data.ifi_lastchange
+#define        if_capabilities if_data.ifi_capabilities
+
+#define F_CONNECTED            0x0001
+#define F_STATIC               0x0002
+#define F_BLACKHOLE            0x0004
+#define F_REJECT               0x0008
+#define F_DYNAMIC              0x0010
+
+/*
+ * pf
+ */
+
+enum { PFRB_TABLES = 1, PFRB_TSTATS, PFRB_ADDRS, PFRB_ASTATS,
+       PFRB_IFACES, PFRB_TRANS, PFRB_MAX };
+
+enum {  IN, OUT };
+enum {  IPV4, IPV6 };
+enum {  PASS, BLOCK };
+
+enum {  PFI_IFTYPE_GROUP, PFI_IFTYPE_INSTANCE };
+
+struct pfr_buffer {
+       int      pfrb_type;     /* type of content, see enum above */
+       int      pfrb_size;     /* number of objects in buffer */
+       int      pfrb_msize;    /* maximum number of objects in buffer */
+       void    *pfrb_caddr;    /* malloc'ated memory area */
+};
+
+#define PFRB_FOREACH(var, buf)                         \
+       for ((var) = pfr_buf_next((buf), NULL);         \
+           (var) != NULL;                              \
+           (var) = pfr_buf_next((buf), (var)))
+
+/*
+ * daemon structures
+ */
+
+struct snmpd {
+       int                      sc_ncpu;
+       int64_t                 *sc_cpustates;
+       int                      sc_rtfilter;
+};
+
+extern struct snmpd *snmpd_env;
+
+/* mib.c */
+u_long   smi_getticks(void);
+
+/* kroute.c */
+void            kr_init(void);
+void            kr_shutdown(void);
+
+u_int           kr_ifnumber(void);
+u_long          kr_iflastchange(void);
+int             kr_updateif(u_int);
+u_long          kr_routenumber(void);
+
+struct kif     *kr_getif(u_short);
+struct kif     *kr_getnextif(u_short);
+struct kif_addr *kr_getaddr(struct sockaddr *);
+struct kif_addr *kr_getnextaddr(struct sockaddr *);
+
+struct kroute  *kroute_first(void);
+struct kroute  *kroute_getaddr(in_addr_t, u_int8_t, u_int8_t, int);
+
+struct kif_arp *karp_first(u_short);
+struct kif_arp *karp_getaddr(struct sockaddr *, u_short, int);
+
+/* pf.c */
+void                    pf_init(void);
+int                     pf_get_stats(struct pf_status *);
+int                     pfr_get_astats(struct pfr_table *, struct pfr_astats *,
+                           int *, int);
+int                     pfr_get_tstats(struct pfr_table *, struct pfr_tstats *,
+                           int *, int);
+int                     pfr_buf_grow(struct pfr_buffer *, int);
+const void             *pfr_buf_next(struct pfr_buffer *, const void *);
+int                     pfi_get_ifaces(const char *, struct pfi_kif *, int *);
+int                     pfi_get(struct pfr_buffer *, const char *);
+int                     pfi_count(void);
+int                     pfi_get_if(struct pfi_kif *, int);
+int                     pft_get(struct pfr_buffer *, struct pfr_table *);
+int                     pft_count(void);
+int                     pft_get_table(struct pfr_tstats *, int);
+int                     pfta_get(struct pfr_buffer *, struct pfr_table *);
+int                     pfta_get_addr(struct pfr_astats *, int);
+int                     pfta_get_nextaddr(struct pfr_astats *, int *);
+int                     pfta_get_first(struct pfr_astats *);
+
+/* timer.c */
+void            timer_init(void);
+
+/* util.c */
+ssize_t         sendtofrom(int, void *, size_t, int, struct sockaddr *,
+           socklen_t, struct sockaddr *, socklen_t);
+ssize_t         recvfromto(int, void *, size_t, int, struct sockaddr *,
+           socklen_t *, struct sockaddr *, socklen_t *);
+const char *log_in6addr(const struct in6_addr *);
+const char *print_host(struct sockaddr_storage *, char *, size_t);
+char   *tohexstr(u_int8_t *, int);
+uint8_t *fromhexstr(uint8_t *, const char *, size_t);
+
+#endif /* SNMPD_H */
diff --git a/libexec/snmpd/snmpd_metrics/snmpd_metrics.8 b/libexec/snmpd/snmpd_metrics/snmpd_metrics.8
new file mode 100644 (file)
index 0000000..dbfb0af
--- /dev/null
@@ -0,0 +1,110 @@
+.\"    $OpenBSD: snmpd_metrics.8,v 1.1.1.1 2022/09/01 14:20:34 martijn Exp $
+.\"
+.\" Copyright (c) 2022 Martijn van Duren <martijn@openbsd.org>
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.Dd $Mdocdate: September 1 2022 $
+.Dt SNMPD_METRICS 8
+.Os
+.Sh NAME
+.Nm snmpd_metrics
+.Nd Export snmpd MIB data.
+.Sh SYNOPSIS
+.Nm
+.Op Fl dv
+.Op Fl C Ar option
+.Op Fl c Ar context
+.Op Fl s Ar path
+.Sh DESCRIPTION
+.Nm
+exports the following
+.Pq partial
+MIBs via an AgentX compatible
+.Pq snmp
+daemon:
+HOST-RESOURCES-MIB, IF-MIB, OPENBSD-PF-MIB, OPENBSD-SENSORS-MIB,
+OPENBSD-CARP-MIB, OPENBSD-MEM-MIB, IP-MIB, IP-FORWARD-MIB,
+UCD-DISKIO-MIB, and BRIDGE-MIB.
+The options are as follows:
+.Bl -tag -width Ds
+.It Fl C Ar option
+Enable MIB-specific options. Currently only
+.Ic filter-routes
+is supported.
+If set ask the kernel to filter route update messages on the routing socket.
+Routing table information will not be available, but CPU use will be
+reduced during bulk updates.
+.It Fl c Ar context
+The SNMPv3 context and can usually be omitted.
+.It Fl d
+Do not daemonize and log to
+.Em stderr .
+.It Fl s Ar path
+Connect to the AgentX master via
+.Ar path .
+It defaults to
+.Pa /var/agentx/master .
+.It Fl v
+Produce more verbose output.
+.El
+.Sh SEE ALSO
+.Xr snmpd 8
+.Xr snmp 1
+.Sh STANDARDS
+.Rs
+.%A P. Grillo
+.%A WeSync.com
+.%D March 2000
+.%R RFC 2790
+.%T Host Resources MIB
+.Re
+.Pp
+.Rs
+.%A K. McCloghrie
+.%A Cisco Systems
+.%A F. Kastenholz
+.%A Argon Networks
+.%D June 2000
+.%R RFC 2863
+.%T The Interfaces Group MIB
+.Re
+.Pp
+.Rs
+.%A S. Routhier, Ed.
+.%D April 2006
+.%R RFC 4293
+.%T Management Information Base for the Internet Protocol (IP)
+.Re
+.Pp
+.Rs
+.%A B. Haberman
+.%A Johns Hopkins University
+.%D April 2006
+.%R RFC 4292
+.%T IP Forwarding Table MIB
+.Re
+.Pp
+.Rs
+.%A K. Norseth, Ed.
+.%A L-3 Communications
+.%A E. Bell, Ed.
+.%A 3Com Europe Limited
+.%D September 2005
+.%R RFC 4188
+.%T Definitions of Managed Objects for Bridges
+.Re
+.Sh AUTHORS
+.An Martijn van Duren Aq Mt martijn@openbsd.org
+.An Joel Knight Aq Mt joel@openbsd.org
+.An Reyk Floeter Aq Mt reyk@openbsd.org
diff --git a/libexec/snmpd/snmpd_metrics/timer.c b/libexec/snmpd/snmpd_metrics/timer.c
new file mode 100644 (file)
index 0000000..e0a70e9
--- /dev/null
@@ -0,0 +1,169 @@
+/*     $OpenBSD: timer.c,v 1.1.1.1 2022/09/01 14:20:33 martijn Exp $   */
+
+/*
+ * Copyright (c) 2008 Reyk Floeter <reyk@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/queue.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/sched.h>
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+
+#include <net/if.h>
+#include <net/if_types.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <netinet/ip_var.h>
+#include <arpa/inet.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <event.h>
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+#include <pwd.h>
+
+#include "snmpd.h"
+#include "mib.h"
+
+void    timer_cpu(int, short, void *);
+int     percentages(int, int64_t *, int64_t *, int64_t *, int64_t *);
+
+static int64_t **cp_time;
+static int64_t **cp_old;
+static int64_t **cp_diff;
+struct event     cpu_ev;
+
+void
+timer_cpu(int fd, short event, void *arg)
+{
+       struct event    *ev = (struct event *)arg;
+       struct timeval   tv = { 60, 0 };        /* every 60 seconds */
+       int              mib[3] = { CTL_KERN, KERN_CPTIME2, 0 }, n;
+       size_t           len;
+       int64_t         *cptime2;
+
+       len = CPUSTATES * sizeof(int64_t);
+       for (n = 0; n < snmpd_env->sc_ncpu; n++) {
+               mib[2] = n;
+               cptime2 = snmpd_env->sc_cpustates + (CPUSTATES * n);
+               if (sysctl(mib, 3, cp_time[n], &len, NULL, 0) == -1)
+                       continue;
+               (void)percentages(CPUSTATES, cptime2, cp_time[n],
+                   cp_old[n], cp_diff[n]);
+#ifdef DEBUG
+               log_debug("timer_cpu: cpu%d %lld%% idle in %llds", n,
+                   (cptime2[CP_IDLE] > 1000 ?
+                   1000 : (cptime2[CP_IDLE] / 10)), (long long) tv.tv_sec);
+#endif
+       }
+
+       evtimer_add(ev, &tv);
+}
+
+void
+timer_init(void)
+{
+       int      mib[] = { CTL_HW, HW_NCPU }, i;
+       size_t   len;
+
+       len = sizeof(snmpd_env->sc_ncpu);
+       if (sysctl(mib, 2, &snmpd_env->sc_ncpu, &len, NULL, 0) == -1)
+               fatal("sysctl");
+
+       snmpd_env->sc_cpustates = calloc(snmpd_env->sc_ncpu,
+           CPUSTATES * sizeof(int64_t));
+       cp_time = calloc(snmpd_env->sc_ncpu, sizeof(int64_t *));
+       cp_old = calloc(snmpd_env->sc_ncpu, sizeof(int64_t *));
+       cp_diff = calloc(snmpd_env->sc_ncpu, sizeof(int64_t *));
+       if (snmpd_env->sc_cpustates == NULL ||
+           cp_time == NULL || cp_old == NULL || cp_diff == NULL)
+               fatal("calloc");
+       for (i = 0; i < snmpd_env->sc_ncpu; i++) {
+               cp_time[i] = calloc(CPUSTATES, sizeof(int64_t));
+               cp_old[i] = calloc(CPUSTATES, sizeof(int64_t));
+               cp_diff[i] = calloc(CPUSTATES, sizeof(int64_t));
+               if (cp_time[i] == NULL || cp_old[i] == NULL ||
+                   cp_diff[i] == NULL)
+                       fatal("calloc");
+       }
+
+       evtimer_set(&cpu_ev, timer_cpu, &cpu_ev);
+       timer_cpu(0, EV_TIMEOUT, &cpu_ev);
+}
+
+/*
+ * percentages() function to calculate CPU utilization.
+ * Source code derived from the top(1) utility:
+ *
+ * Copyright (c) 1984, 1989, William LeFebvre, Rice University
+ * Copyright (c) 1989, 1990, 1992, William LeFebvre, Northwestern University
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR OR HIS EMPLOYER BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+int
+percentages(int cnt, int64_t *out, int64_t *new, int64_t *old, int64_t *diffs)
+{
+       int64_t change, total_change, *dp, half_total;
+       int i;
+
+       /* initialization */
+       total_change = 0;
+       dp = diffs;
+
+       /* calculate changes for each state and the overall change */
+       for (i = 0; i < cnt; i++) {
+               if ((change = *new - *old) < 0) {
+                       /* this only happens when the counter wraps */
+                       change = (*new - *old);
+               }
+               total_change += (*dp++ = change);
+               *old++ = *new++;
+       }
+
+       /* avoid divide by zero potential */
+       if (total_change == 0)
+               total_change = 1;
+
+       /* calculate percentages based on overall change, rounding up */
+       half_total = total_change / 2l;
+       for (i = 0; i < cnt; i++)
+               *out++ = ((*diffs++ * 1000 + half_total) / total_change);
+
+       /* return the total in case the caller wants to use it */
+       return (total_change);
+}
diff --git a/libexec/snmpd/snmpd_metrics/util.c b/libexec/snmpd/snmpd_metrics/util.c
new file mode 100644 (file)
index 0000000..bfb55b4
--- /dev/null
@@ -0,0 +1,229 @@
+/*     $OpenBSD: util.c,v 1.1.1.1 2022/09/01 14:20:33 martijn Exp $    */
+/*
+ * Copyright (c) 2014 Bret Stephen Lambert <blambert@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <sys/socket.h>
+
+#include <net/if.h>
+
+#include <ber.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <netdb.h>
+#include <event.h>
+
+#include "snmpd.h"
+
+ssize_t
+sendtofrom(int s, void *buf, size_t len, int flags, struct sockaddr *to,
+    socklen_t tolen, struct sockaddr *from, socklen_t fromlen)
+{
+       struct iovec             iov;
+       struct msghdr            msg;
+       struct cmsghdr          *cmsg;
+       struct in6_pktinfo      *pkt6;
+       struct sockaddr_in      *in;
+       struct sockaddr_in6     *in6;
+       union {
+               struct cmsghdr  hdr;
+               char            inbuf[CMSG_SPACE(sizeof(struct in_addr))];
+               char            in6buf[CMSG_SPACE(sizeof(struct in6_pktinfo))];
+       } cmsgbuf;
+
+       bzero(&msg, sizeof(msg));
+       bzero(&cmsgbuf, sizeof(cmsgbuf));
+
+       iov.iov_base = buf;
+       iov.iov_len = len;
+       msg.msg_iov = &iov;
+       msg.msg_iovlen = 1;
+       msg.msg_name = to;
+       msg.msg_namelen = tolen;
+       msg.msg_control = &cmsgbuf;
+       msg.msg_controllen = sizeof(cmsgbuf);
+
+       cmsg = CMSG_FIRSTHDR(&msg);
+       switch (to->sa_family) {
+       case AF_INET:
+               msg.msg_controllen = sizeof(cmsgbuf.inbuf);
+               cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
+               cmsg->cmsg_level = IPPROTO_IP;
+               cmsg->cmsg_type = IP_SENDSRCADDR;
+               in = (struct sockaddr_in *)from;
+               memcpy(CMSG_DATA(cmsg), &in->sin_addr, sizeof(struct in_addr));
+               break;
+       case AF_INET6:
+               msg.msg_controllen = sizeof(cmsgbuf.in6buf);
+               cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
+               cmsg->cmsg_level = IPPROTO_IPV6;
+               cmsg->cmsg_type = IPV6_PKTINFO;
+               in6 = (struct sockaddr_in6 *)from;
+               pkt6 = (struct in6_pktinfo *)CMSG_DATA(cmsg);
+               pkt6->ipi6_addr = in6->sin6_addr;
+               break;
+       }
+
+       return sendmsg(s, &msg, flags);
+}
+
+ssize_t
+recvfromto(int s, void *buf, size_t len, int flags, struct sockaddr *from,
+    socklen_t *fromlen, struct sockaddr *to, socklen_t *tolen)
+{
+       struct iovec             iov;
+       struct msghdr            msg;
+       struct cmsghdr          *cmsg;
+       struct in6_pktinfo      *pkt6;
+       struct sockaddr_in      *in;
+       struct sockaddr_in6     *in6;
+       ssize_t                  ret;
+       union {
+               struct cmsghdr hdr;
+               char    buf[CMSG_SPACE(sizeof(struct sockaddr_storage))];
+       } cmsgbuf;
+
+       bzero(&msg, sizeof(msg));
+       bzero(&cmsgbuf.buf, sizeof(cmsgbuf.buf));
+
+       iov.iov_base = buf;
+       iov.iov_len = len;
+       msg.msg_iov = &iov;
+       msg.msg_iovlen = 1;
+       msg.msg_name = from;
+       msg.msg_namelen = *fromlen;
+       msg.msg_control = &cmsgbuf.buf;
+       msg.msg_controllen = sizeof(cmsgbuf.buf);
+
+       if ((ret = recvmsg(s, &msg, flags)) == -1)
+               return (-1);
+
+       *fromlen = from->sa_len;
+       *tolen = 0;
+
+       if (getsockname(s, to, tolen) != 0)
+               *tolen = 0;
+
+       for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
+           cmsg = CMSG_NXTHDR(&msg, cmsg)) {
+               switch (from->sa_family) {
+               case AF_INET:
+                       if (cmsg->cmsg_level == IPPROTO_IP &&
+                           cmsg->cmsg_type == IP_RECVDSTADDR) {
+                               in = (struct sockaddr_in *)to;
+                               in->sin_family = AF_INET;
+                               in->sin_len = *tolen = sizeof(*in);
+                               memcpy(&in->sin_addr, CMSG_DATA(cmsg),
+                                   sizeof(struct in_addr));
+                       }
+                       break;
+               case AF_INET6:
+                       if (cmsg->cmsg_level == IPPROTO_IPV6 &&
+                           cmsg->cmsg_type == IPV6_PKTINFO) {
+                               in6 = (struct sockaddr_in6 *)to;
+                               in6->sin6_family = AF_INET6;
+                               in6->sin6_len = *tolen = sizeof(*in6);
+                               pkt6 = (struct in6_pktinfo *)CMSG_DATA(cmsg);
+                               memcpy(&in6->sin6_addr, &pkt6->ipi6_addr,
+                                   sizeof(struct in6_addr));
+                               if (IN6_IS_ADDR_LINKLOCAL(&in6->sin6_addr))
+                                       in6->sin6_scope_id =
+                                           pkt6->ipi6_ifindex;
+                       }
+                       break;
+               }
+       }
+
+       return (ret);
+}
+
+const char *
+log_in6addr(const struct in6_addr *addr)
+{
+       static char             buf[NI_MAXHOST];
+       struct sockaddr_in6     sa_in6;
+       u_int16_t               tmp16;
+
+       bzero(&sa_in6, sizeof(sa_in6));
+       sa_in6.sin6_len = sizeof(sa_in6);
+       sa_in6.sin6_family = AF_INET6;
+       memcpy(&sa_in6.sin6_addr, addr, sizeof(sa_in6.sin6_addr));
+
+       /* XXX thanks, KAME, for this ugliness... adopted from route/show.c */
+       if (IN6_IS_ADDR_LINKLOCAL(&sa_in6.sin6_addr) ||
+           IN6_IS_ADDR_MC_LINKLOCAL(&sa_in6.sin6_addr)) {
+               memcpy(&tmp16, &sa_in6.sin6_addr.s6_addr[2], sizeof(tmp16));
+               sa_in6.sin6_scope_id = ntohs(tmp16);
+               sa_in6.sin6_addr.s6_addr[2] = 0;
+               sa_in6.sin6_addr.s6_addr[3] = 0;
+       }
+
+       return (print_host((struct sockaddr_storage *)&sa_in6, buf,
+           NI_MAXHOST));
+}
+
+const char *
+print_host(struct sockaddr_storage *ss, char *buf, size_t len)
+{
+       if (getnameinfo((struct sockaddr *)ss, ss->ss_len,
+           buf, len, NULL, 0, NI_NUMERICHOST) != 0) {
+               buf[0] = '\0';
+               return (NULL);
+       }
+       return (buf);
+}
+
+char *
+tohexstr(uint8_t *bstr, int len)
+{
+#define MAXHEXSTRLEN           256
+       static char hstr[2 * MAXHEXSTRLEN + 1];
+       static const char hex[] = "0123456789abcdef";
+       int i;
+
+       if (len > MAXHEXSTRLEN)
+               len = MAXHEXSTRLEN;     /* truncate */
+       for (i = 0; i < len; i++) {
+               hstr[i + i] = hex[bstr[i] >> 4];
+               hstr[i + i + 1] = hex[bstr[i] & 0x0f];
+       }
+       hstr[i + i] = '\0';
+       return hstr;
+}
+
+uint8_t *
+fromhexstr(uint8_t *bstr, const char *hstr, size_t len)
+{
+       size_t i;
+       char hex[3];
+
+       if (len % 2 != 0)
+               return NULL;
+
+       hex[2] = '\0';
+       for (i = 0; i < len; i += 2) {
+               if (!isxdigit(hstr[i]) || !isxdigit(hstr[i + 1]))
+                       return NULL;
+               hex[0] = hstr[i];
+               hex[1] = hstr[i + 1];
+               bstr[i / 2] = strtol(hex, NULL, 16);
+       }
+
+       return bstr;
+}