summaryrefslogtreecommitdiff
path: root/libexec/snmpd
diff options
context:
space:
mode:
authorMartijn van Duren <martijn@cvs.openbsd.org>2022-09-01 14:20:35 +0000
committerMartijn van Duren <martijn@cvs.openbsd.org>2022-09-01 14:20:35 +0000
commit8db8864edf38c306c78bbac3c1f9bba63ab7493c (patch)
tree5a03b77ded42b7a11c7cd6f97e4c1d02aebe2fab /libexec/snmpd
parentb2c776ff569070b35f800e3a41cc03c5233dfbfc (diff)
Import snmpd_metrics.
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@
Diffstat (limited to 'libexec/snmpd')
-rw-r--r--libexec/snmpd/Makefile8
-rw-r--r--libexec/snmpd/snmpd_metrics/Makefile17
-rw-r--r--libexec/snmpd/snmpd_metrics/kroute.c1699
-rw-r--r--libexec/snmpd/snmpd_metrics/log.c218
-rw-r--r--libexec/snmpd/snmpd_metrics/log.h40
-rw-r--r--libexec/snmpd/snmpd_metrics/mib.c4367
-rw-r--r--libexec/snmpd/snmpd_metrics/mib.h896
-rw-r--r--libexec/snmpd/snmpd_metrics/pf.c501
-rw-r--r--libexec/snmpd/snmpd_metrics/snmpd.h284
-rw-r--r--libexec/snmpd/snmpd_metrics/snmpd_metrics.8110
-rw-r--r--libexec/snmpd/snmpd_metrics/timer.c169
-rw-r--r--libexec/snmpd/snmpd_metrics/util.c229
12 files changed, 8538 insertions, 0 deletions
diff --git a/libexec/snmpd/Makefile b/libexec/snmpd/Makefile
new file mode 100644
index 00000000000..06d5c442cc6
--- /dev/null
+++ b/libexec/snmpd/Makefile
@@ -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
index 00000000000..1b768f72e62
--- /dev/null
+++ b/libexec/snmpd/snmpd_metrics/Makefile
@@ -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
index 00000000000..91de8d431f7
--- /dev/null
+++ b/libexec/snmpd/snmpd_metrics/kroute.c
@@ -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
index 00000000000..3a322bf1ec0
--- /dev/null
+++ b/libexec/snmpd/snmpd_metrics/log.c
@@ -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
index 00000000000..a02fe82c1f1
--- /dev/null
+++ b/libexec/snmpd/snmpd_metrics/log.h
@@ -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
index 00000000000..eeedb1e0714
--- /dev/null
+++ b/libexec/snmpd/snmpd_metrics/mib.c
@@ -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
index 00000000000..97995472164
--- /dev/null
+++ b/libexec/snmpd/snmpd_metrics/mib.h
@@ -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
index 00000000000..a4b60962e32
--- /dev/null
+++ b/libexec/snmpd/snmpd_metrics/pf.c
@@ -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
index 00000000000..b764c778e7b
--- /dev/null
+++ b/libexec/snmpd/snmpd_metrics/snmpd.h
@@ -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
index 00000000000..dbfb0af4e7f
--- /dev/null
+++ b/libexec/snmpd/snmpd_metrics/snmpd_metrics.8
@@ -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
index 00000000000..e0a70e9f642
--- /dev/null
+++ b/libexec/snmpd/snmpd_metrics/timer.c
@@ -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
index 00000000000..bfb55b45718
--- /dev/null
+++ b/libexec/snmpd/snmpd_metrics/util.c
@@ -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;
+}