2 * Copyright (c) 2005 Philip Paeps <philip@FreeBSD.org>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 #include <sys/queue.h>
30 #include <bsnmp/snmpmod.h>
32 #include <net/pfvar.h>
33 #include <sys/ioctl.h>
47 struct lmodule *module;
51 static uint64_t pf_tick;
53 static struct pf_status pfs;
59 #define PFI_IFTYPE_GROUP 0
60 #define PFI_IFTYPE_INSTANCE 1
61 #define PFI_IFTYPE_DETACHED 2
66 TAILQ_ENTRY(pfi_entry) link;
68 TAILQ_HEAD(pfi_table, pfi_entry);
70 static struct pfi_table pfi_table;
71 static time_t pfi_table_age;
72 static int pfi_table_count;
74 #define PFI_TABLE_MAXAGE 5
77 struct pfr_tstats pft;
79 TAILQ_ENTRY(pft_entry) link;
81 TAILQ_HEAD(pft_table, pft_entry);
83 static struct pft_table pft_table;
84 static time_t pft_table_age;
85 static int pft_table_count;
87 #define PFT_TABLE_MAXAGE 5
90 struct pfr_astats pfas;
92 TAILQ_ENTRY(pfa_entry) link;
94 TAILQ_HEAD(pfa_table, pfa_entry);
96 static struct pfa_table pfa_table;
97 static time_t pfa_table_age;
98 static int pfa_table_count;
100 #define PFA_TABLE_MAXAGE 5
105 TAILQ_ENTRY(pfq_entry) link;
107 TAILQ_HEAD(pfq_table, pfq_entry);
109 static struct pfq_table pfq_table;
110 static time_t pfq_table_age;
111 static int pfq_table_count;
113 static int altq_enabled = 0;
115 #define PFQ_TABLE_MAXAGE 5
118 char name[MAXPATHLEN + PF_RULE_LABEL_SIZE];
123 TAILQ_ENTRY(pfl_entry) link;
125 TAILQ_HEAD(pfl_table, pfl_entry);
127 static struct pfl_table pfl_table;
128 static time_t pfl_table_age;
129 static int pfl_table_count;
131 #define PFL_TABLE_MAXAGE 5
133 /* Forward declarations */
134 static int pfi_refresh(void);
135 static int pfq_refresh(void);
136 static int pfs_refresh(void);
137 static int pft_refresh(void);
138 static int pfa_refresh(void);
139 static int pfl_refresh(void);
140 static struct pfi_entry * pfi_table_find(u_int idx);
141 static struct pfq_entry * pfq_table_find(u_int idx);
142 static struct pft_entry * pft_table_find(u_int idx);
143 static struct pfa_entry * pfa_table_find(u_int idx);
144 static struct pfl_entry * pfl_table_find(u_int idx);
146 static int altq_is_enabled(int pfdevice);
149 pf_status(struct snmp_context __unused *ctx, struct snmp_value *val,
150 u_int sub, u_int __unused vindex, enum snmp_op op)
152 asn_subid_t which = val->var.subs[sub - 1];
154 unsigned char str[128];
156 if (op == SNMP_OP_SET)
157 return (SNMP_ERR_NOT_WRITEABLE);
159 if (op == SNMP_OP_GET) {
160 if (pfs_refresh() == -1)
161 return (SNMP_ERR_GENERR);
164 case LEAF_pfStatusRunning:
165 val->v.uint32 = pfs.running;
167 case LEAF_pfStatusRuntime:
168 runtime = (pfs.since > 0) ?
169 time(NULL) - pfs.since : 0;
170 val->v.uint32 = runtime * 100;
172 case LEAF_pfStatusDebug:
173 val->v.uint32 = pfs.debug;
175 case LEAF_pfStatusHostId:
176 sprintf(str, "0x%08x", ntohl(pfs.hostid));
177 return (string_get(val, str, strlen(str)));
180 return (SNMP_ERR_NOSUCHNAME);
183 return (SNMP_ERR_NOERROR);
190 pf_counter(struct snmp_context __unused *ctx, struct snmp_value *val,
191 u_int sub, u_int __unused vindex, enum snmp_op op)
193 asn_subid_t which = val->var.subs[sub - 1];
195 if (op == SNMP_OP_SET)
196 return (SNMP_ERR_NOT_WRITEABLE);
198 if (op == SNMP_OP_GET) {
199 if (pfs_refresh() == -1)
200 return (SNMP_ERR_GENERR);
203 case LEAF_pfCounterMatch:
204 val->v.counter64 = pfs.counters[PFRES_MATCH];
206 case LEAF_pfCounterBadOffset:
207 val->v.counter64 = pfs.counters[PFRES_BADOFF];
209 case LEAF_pfCounterFragment:
210 val->v.counter64 = pfs.counters[PFRES_FRAG];
212 case LEAF_pfCounterShort:
213 val->v.counter64 = pfs.counters[PFRES_SHORT];
215 case LEAF_pfCounterNormalize:
216 val->v.counter64 = pfs.counters[PFRES_NORM];
218 case LEAF_pfCounterMemDrop:
219 val->v.counter64 = pfs.counters[PFRES_MEMORY];
223 return (SNMP_ERR_NOSUCHNAME);
226 return (SNMP_ERR_NOERROR);
233 pf_statetable(struct snmp_context __unused *ctx, struct snmp_value *val,
234 u_int sub, u_int __unused vindex, enum snmp_op op)
236 asn_subid_t which = val->var.subs[sub - 1];
238 if (op == SNMP_OP_SET)
239 return (SNMP_ERR_NOT_WRITEABLE);
241 if (op == SNMP_OP_GET) {
242 if (pfs_refresh() == -1)
243 return (SNMP_ERR_GENERR);
246 case LEAF_pfStateTableCount:
247 val->v.uint32 = pfs.states;
249 case LEAF_pfStateTableSearches:
251 pfs.fcounters[FCNT_STATE_SEARCH];
253 case LEAF_pfStateTableInserts:
255 pfs.fcounters[FCNT_STATE_INSERT];
257 case LEAF_pfStateTableRemovals:
259 pfs.fcounters[FCNT_STATE_REMOVALS];
263 return (SNMP_ERR_NOSUCHNAME);
266 return (SNMP_ERR_NOERROR);
273 pf_srcnodes(struct snmp_context __unused *ctx, struct snmp_value *val,
274 u_int sub, u_int __unused vindex, enum snmp_op op)
276 asn_subid_t which = val->var.subs[sub - 1];
278 if (op == SNMP_OP_SET)
279 return (SNMP_ERR_NOT_WRITEABLE);
281 if (op == SNMP_OP_GET) {
282 if (pfs_refresh() == -1)
283 return (SNMP_ERR_GENERR);
286 case LEAF_pfSrcNodesCount:
287 val->v.uint32 = pfs.src_nodes;
289 case LEAF_pfSrcNodesSearches:
291 pfs.scounters[SCNT_SRC_NODE_SEARCH];
293 case LEAF_pfSrcNodesInserts:
295 pfs.scounters[SCNT_SRC_NODE_INSERT];
297 case LEAF_pfSrcNodesRemovals:
299 pfs.scounters[SCNT_SRC_NODE_REMOVALS];
303 return (SNMP_ERR_NOSUCHNAME);
306 return (SNMP_ERR_NOERROR);
313 pf_limits(struct snmp_context __unused *ctx, struct snmp_value *val,
314 u_int sub, u_int __unused vindex, enum snmp_op op)
316 asn_subid_t which = val->var.subs[sub - 1];
317 struct pfioc_limit pl;
319 if (op == SNMP_OP_SET)
320 return (SNMP_ERR_NOT_WRITEABLE);
322 if (op == SNMP_OP_GET) {
323 bzero(&pl, sizeof(struct pfioc_limit));
326 case LEAF_pfLimitsStates:
327 pl.index = PF_LIMIT_STATES;
329 case LEAF_pfLimitsSrcNodes:
330 pl.index = PF_LIMIT_SRC_NODES;
332 case LEAF_pfLimitsFrags:
333 pl.index = PF_LIMIT_FRAGS;
337 return (SNMP_ERR_NOSUCHNAME);
340 if (ioctl(dev, DIOCGETLIMIT, &pl)) {
341 syslog(LOG_ERR, "pf_limits(): ioctl(): %s",
343 return (SNMP_ERR_GENERR);
346 val->v.uint32 = pl.limit;
348 return (SNMP_ERR_NOERROR);
355 pf_timeouts(struct snmp_context __unused *ctx, struct snmp_value *val,
356 u_int sub, u_int __unused vindex, enum snmp_op op)
358 asn_subid_t which = val->var.subs[sub - 1];
361 if (op == SNMP_OP_SET)
362 return (SNMP_ERR_NOT_WRITEABLE);
364 if (op == SNMP_OP_GET) {
365 bzero(&pt, sizeof(struct pfioc_tm));
368 case LEAF_pfTimeoutsTcpFirst:
369 pt.timeout = PFTM_TCP_FIRST_PACKET;
371 case LEAF_pfTimeoutsTcpOpening:
372 pt.timeout = PFTM_TCP_OPENING;
374 case LEAF_pfTimeoutsTcpEstablished:
375 pt.timeout = PFTM_TCP_ESTABLISHED;
377 case LEAF_pfTimeoutsTcpClosing:
378 pt.timeout = PFTM_TCP_CLOSING;
380 case LEAF_pfTimeoutsTcpFinWait:
381 pt.timeout = PFTM_TCP_FIN_WAIT;
383 case LEAF_pfTimeoutsTcpClosed:
384 pt.timeout = PFTM_TCP_CLOSED;
386 case LEAF_pfTimeoutsUdpFirst:
387 pt.timeout = PFTM_UDP_FIRST_PACKET;
389 case LEAF_pfTimeoutsUdpSingle:
390 pt.timeout = PFTM_UDP_SINGLE;
392 case LEAF_pfTimeoutsUdpMultiple:
393 pt.timeout = PFTM_UDP_MULTIPLE;
395 case LEAF_pfTimeoutsIcmpFirst:
396 pt.timeout = PFTM_ICMP_FIRST_PACKET;
398 case LEAF_pfTimeoutsIcmpError:
399 pt.timeout = PFTM_ICMP_ERROR_REPLY;
401 case LEAF_pfTimeoutsOtherFirst:
402 pt.timeout = PFTM_OTHER_FIRST_PACKET;
404 case LEAF_pfTimeoutsOtherSingle:
405 pt.timeout = PFTM_OTHER_SINGLE;
407 case LEAF_pfTimeoutsOtherMultiple:
408 pt.timeout = PFTM_OTHER_MULTIPLE;
410 case LEAF_pfTimeoutsFragment:
411 pt.timeout = PFTM_FRAG;
413 case LEAF_pfTimeoutsInterval:
414 pt.timeout = PFTM_INTERVAL;
416 case LEAF_pfTimeoutsAdaptiveStart:
417 pt.timeout = PFTM_ADAPTIVE_START;
419 case LEAF_pfTimeoutsAdaptiveEnd:
420 pt.timeout = PFTM_ADAPTIVE_END;
422 case LEAF_pfTimeoutsSrcNode:
423 pt.timeout = PFTM_SRC_NODE;
427 return (SNMP_ERR_NOSUCHNAME);
430 if (ioctl(dev, DIOCGETTIMEOUT, &pt)) {
431 syslog(LOG_ERR, "pf_timeouts(): ioctl(): %s",
433 return (SNMP_ERR_GENERR);
436 val->v.integer = pt.seconds;
438 return (SNMP_ERR_NOERROR);
445 pf_logif(struct snmp_context __unused *ctx, struct snmp_value *val,
446 u_int sub, u_int __unused vindex, enum snmp_op op)
448 asn_subid_t which = val->var.subs[sub - 1];
449 unsigned char str[IFNAMSIZ];
451 if (op == SNMP_OP_SET)
452 return (SNMP_ERR_NOT_WRITEABLE);
454 if (op == SNMP_OP_GET) {
455 if (pfs_refresh() == -1)
456 return (SNMP_ERR_GENERR);
459 case LEAF_pfLogInterfaceName:
460 strlcpy(str, pfs.ifname, sizeof str);
461 return (string_get(val, str, strlen(str)));
462 case LEAF_pfLogInterfaceIp4BytesIn:
463 val->v.counter64 = pfs.bcounters[IPV4][IN];
465 case LEAF_pfLogInterfaceIp4BytesOut:
466 val->v.counter64 = pfs.bcounters[IPV4][OUT];
468 case LEAF_pfLogInterfaceIp4PktsInPass:
470 pfs.pcounters[IPV4][IN][PF_PASS];
472 case LEAF_pfLogInterfaceIp4PktsInDrop:
474 pfs.pcounters[IPV4][IN][PF_DROP];
476 case LEAF_pfLogInterfaceIp4PktsOutPass:
478 pfs.pcounters[IPV4][OUT][PF_PASS];
480 case LEAF_pfLogInterfaceIp4PktsOutDrop:
482 pfs.pcounters[IPV4][OUT][PF_DROP];
484 case LEAF_pfLogInterfaceIp6BytesIn:
485 val->v.counter64 = pfs.bcounters[IPV6][IN];
487 case LEAF_pfLogInterfaceIp6BytesOut:
488 val->v.counter64 = pfs.bcounters[IPV6][OUT];
490 case LEAF_pfLogInterfaceIp6PktsInPass:
492 pfs.pcounters[IPV6][IN][PF_PASS];
494 case LEAF_pfLogInterfaceIp6PktsInDrop:
496 pfs.pcounters[IPV6][IN][PF_DROP];
498 case LEAF_pfLogInterfaceIp6PktsOutPass:
500 pfs.pcounters[IPV6][OUT][PF_PASS];
502 case LEAF_pfLogInterfaceIp6PktsOutDrop:
504 pfs.pcounters[IPV6][OUT][PF_DROP];
508 return (SNMP_ERR_NOSUCHNAME);
511 return (SNMP_ERR_NOERROR);
518 pf_interfaces(struct snmp_context __unused *ctx, struct snmp_value *val,
519 u_int sub, u_int __unused vindex, enum snmp_op op)
521 asn_subid_t which = val->var.subs[sub - 1];
523 if (op == SNMP_OP_SET)
524 return (SNMP_ERR_NOT_WRITEABLE);
526 if (op == SNMP_OP_GET) {
527 if ((time(NULL) - pfi_table_age) > PFI_TABLE_MAXAGE)
528 if (pfi_refresh() == -1)
529 return (SNMP_ERR_GENERR);
532 case LEAF_pfInterfacesIfNumber:
533 val->v.uint32 = pfi_table_count;
537 return (SNMP_ERR_NOSUCHNAME);
540 return (SNMP_ERR_NOERROR);
547 pf_iftable(struct snmp_context __unused *ctx, struct snmp_value *val,
548 u_int sub, u_int __unused vindex, enum snmp_op op)
550 asn_subid_t which = val->var.subs[sub - 1];
551 struct pfi_entry *e = NULL;
553 if ((time(NULL) - pfi_table_age) > PFI_TABLE_MAXAGE)
558 return (SNMP_ERR_NOT_WRITEABLE);
559 case SNMP_OP_GETNEXT:
560 if ((e = NEXT_OBJECT_INT(&pfi_table,
561 &val->var, sub)) == NULL)
562 return (SNMP_ERR_NOSUCHNAME);
563 val->var.len = sub + 1;
564 val->var.subs[sub] = e->index;
567 if (val->var.len - sub != 1)
568 return (SNMP_ERR_NOSUCHNAME);
569 if ((e = pfi_table_find(val->var.subs[sub])) == NULL)
570 return (SNMP_ERR_NOSUCHNAME);
574 case SNMP_OP_ROLLBACK:
580 case LEAF_pfInterfacesIfDescr:
581 return (string_get(val, e->pfi.pfik_name, -1));
582 case LEAF_pfInterfacesIfType:
583 val->v.integer = PFI_IFTYPE_INSTANCE;
585 case LEAF_pfInterfacesIfTZero:
587 (time(NULL) - e->pfi.pfik_tzero) * 100;
589 case LEAF_pfInterfacesIfRefsState:
590 val->v.uint32 = e->pfi.pfik_states;
592 case LEAF_pfInterfacesIfRefsRule:
593 val->v.uint32 = e->pfi.pfik_rules;
595 case LEAF_pfInterfacesIf4BytesInPass:
597 e->pfi.pfik_bytes[IPV4][IN][PASS];
599 case LEAF_pfInterfacesIf4BytesInBlock:
601 e->pfi.pfik_bytes[IPV4][IN][BLOCK];
603 case LEAF_pfInterfacesIf4BytesOutPass:
605 e->pfi.pfik_bytes[IPV4][OUT][PASS];
607 case LEAF_pfInterfacesIf4BytesOutBlock:
609 e->pfi.pfik_bytes[IPV4][OUT][BLOCK];
611 case LEAF_pfInterfacesIf4PktsInPass:
613 e->pfi.pfik_packets[IPV4][IN][PASS];
615 case LEAF_pfInterfacesIf4PktsInBlock:
617 e->pfi.pfik_packets[IPV4][IN][BLOCK];
619 case LEAF_pfInterfacesIf4PktsOutPass:
621 e->pfi.pfik_packets[IPV4][OUT][PASS];
623 case LEAF_pfInterfacesIf4PktsOutBlock:
625 e->pfi.pfik_packets[IPV4][OUT][BLOCK];
627 case LEAF_pfInterfacesIf6BytesInPass:
629 e->pfi.pfik_bytes[IPV6][IN][PASS];
631 case LEAF_pfInterfacesIf6BytesInBlock:
633 e->pfi.pfik_bytes[IPV6][IN][BLOCK];
635 case LEAF_pfInterfacesIf6BytesOutPass:
637 e->pfi.pfik_bytes[IPV6][OUT][PASS];
639 case LEAF_pfInterfacesIf6BytesOutBlock:
641 e->pfi.pfik_bytes[IPV6][OUT][BLOCK];
643 case LEAF_pfInterfacesIf6PktsInPass:
645 e->pfi.pfik_packets[IPV6][IN][PASS];
647 case LEAF_pfInterfacesIf6PktsInBlock:
649 e->pfi.pfik_packets[IPV6][IN][BLOCK];
651 case LEAF_pfInterfacesIf6PktsOutPass:
653 e->pfi.pfik_packets[IPV6][OUT][PASS];
655 case LEAF_pfInterfacesIf6PktsOutBlock:
657 e->pfi.pfik_packets[IPV6][OUT][BLOCK];
661 return (SNMP_ERR_NOSUCHNAME);
664 return (SNMP_ERR_NOERROR);
668 pf_tables(struct snmp_context __unused *ctx, struct snmp_value *val,
669 u_int sub, u_int __unused vindex, enum snmp_op op)
671 asn_subid_t which = val->var.subs[sub - 1];
673 if (op == SNMP_OP_SET)
674 return (SNMP_ERR_NOT_WRITEABLE);
676 if (op == SNMP_OP_GET) {
677 if ((time(NULL) - pft_table_age) > PFT_TABLE_MAXAGE)
678 if (pft_refresh() == -1)
679 return (SNMP_ERR_GENERR);
682 case LEAF_pfTablesTblNumber:
683 val->v.uint32 = pft_table_count;
687 return (SNMP_ERR_NOSUCHNAME);
690 return (SNMP_ERR_NOERROR);
697 pf_tbltable(struct snmp_context __unused *ctx, struct snmp_value *val,
698 u_int sub, u_int __unused vindex, enum snmp_op op)
700 asn_subid_t which = val->var.subs[sub - 1];
701 struct pft_entry *e = NULL;
703 if ((time(NULL) - pft_table_age) > PFT_TABLE_MAXAGE)
708 return (SNMP_ERR_NOT_WRITEABLE);
709 case SNMP_OP_GETNEXT:
710 if ((e = NEXT_OBJECT_INT(&pft_table,
711 &val->var, sub)) == NULL)
712 return (SNMP_ERR_NOSUCHNAME);
713 val->var.len = sub + 1;
714 val->var.subs[sub] = e->index;
717 if (val->var.len - sub != 1)
718 return (SNMP_ERR_NOSUCHNAME);
719 if ((e = pft_table_find(val->var.subs[sub])) == NULL)
720 return (SNMP_ERR_NOSUCHNAME);
724 case SNMP_OP_ROLLBACK:
730 case LEAF_pfTablesTblDescr:
731 return (string_get(val, e->pft.pfrts_name, -1));
732 case LEAF_pfTablesTblCount:
733 val->v.integer = e->pft.pfrts_cnt;
735 case LEAF_pfTablesTblTZero:
737 (time(NULL) - e->pft.pfrts_tzero) * 100;
739 case LEAF_pfTablesTblRefsAnchor:
741 e->pft.pfrts_refcnt[PFR_REFCNT_ANCHOR];
743 case LEAF_pfTablesTblRefsRule:
745 e->pft.pfrts_refcnt[PFR_REFCNT_RULE];
747 case LEAF_pfTablesTblEvalMatch:
748 val->v.counter64 = e->pft.pfrts_match;
750 case LEAF_pfTablesTblEvalNoMatch:
751 val->v.counter64 = e->pft.pfrts_nomatch;
753 case LEAF_pfTablesTblBytesInPass:
755 e->pft.pfrts_bytes[PFR_DIR_IN][PFR_OP_PASS];
757 case LEAF_pfTablesTblBytesInBlock:
759 e->pft.pfrts_bytes[PFR_DIR_IN][PFR_OP_BLOCK];
761 case LEAF_pfTablesTblBytesInXPass:
763 e->pft.pfrts_bytes[PFR_DIR_IN][PFR_OP_XPASS];
765 case LEAF_pfTablesTblBytesOutPass:
767 e->pft.pfrts_bytes[PFR_DIR_OUT][PFR_OP_PASS];
769 case LEAF_pfTablesTblBytesOutBlock:
771 e->pft.pfrts_bytes[PFR_DIR_OUT][PFR_OP_BLOCK];
773 case LEAF_pfTablesTblBytesOutXPass:
775 e->pft.pfrts_bytes[PFR_DIR_OUT][PFR_OP_XPASS];
777 case LEAF_pfTablesTblPktsInPass:
779 e->pft.pfrts_packets[PFR_DIR_IN][PFR_OP_PASS];
781 case LEAF_pfTablesTblPktsInBlock:
783 e->pft.pfrts_packets[PFR_DIR_IN][PFR_OP_BLOCK];
785 case LEAF_pfTablesTblPktsInXPass:
787 e->pft.pfrts_packets[PFR_DIR_IN][PFR_OP_XPASS];
789 case LEAF_pfTablesTblPktsOutPass:
791 e->pft.pfrts_packets[PFR_DIR_OUT][PFR_OP_PASS];
793 case LEAF_pfTablesTblPktsOutBlock:
795 e->pft.pfrts_packets[PFR_DIR_OUT][PFR_OP_BLOCK];
797 case LEAF_pfTablesTblPktsOutXPass:
799 e->pft.pfrts_packets[PFR_DIR_OUT][PFR_OP_XPASS];
803 return (SNMP_ERR_NOSUCHNAME);
806 return (SNMP_ERR_NOERROR);
810 pf_tbladdr(struct snmp_context __unused *ctx, struct snmp_value __unused *val,
811 u_int __unused sub, u_int __unused vindex, enum snmp_op __unused op)
813 asn_subid_t which = val->var.subs[sub - 1];
814 struct pfa_entry *e = NULL;
816 if ((time(NULL) - pfa_table_age) > PFA_TABLE_MAXAGE)
821 return (SNMP_ERR_NOT_WRITEABLE);
822 case SNMP_OP_GETNEXT:
823 if ((e = NEXT_OBJECT_INT(&pfa_table,
824 &val->var, sub)) == NULL)
825 return (SNMP_ERR_NOSUCHNAME);
826 val->var.len = sub + 1;
827 val->var.subs[sub] = e->index;
830 if (val->var.len - sub != 1)
831 return (SNMP_ERR_NOSUCHNAME);
832 if ((e = pfa_table_find(val->var.subs[sub])) == NULL)
833 return (SNMP_ERR_NOSUCHNAME);
837 case SNMP_OP_ROLLBACK:
843 case LEAF_pfTablesAddrNetType:
844 if (e->pfas.pfras_a.pfra_af == AF_INET)
845 val->v.integer = pfTablesAddrNetType_ipv4;
846 else if (e->pfas.pfras_a.pfra_af == AF_INET6)
847 val->v.integer = pfTablesAddrNetType_ipv6;
849 return (SNMP_ERR_GENERR);
851 case LEAF_pfTablesAddrNet:
852 if (e->pfas.pfras_a.pfra_af == AF_INET) {
853 return (string_get(val,
854 (u_char *)&e->pfas.pfras_a.pfra_ip4addr, 4));
855 } else if (e->pfas.pfras_a.pfra_af == AF_INET6)
856 return (string_get(val,
857 (u_char *)&e->pfas.pfras_a.pfra_ip6addr, 16));
859 return (SNMP_ERR_GENERR);
861 case LEAF_pfTablesAddrPrefix:
862 val->v.integer = (int32_t) e->pfas.pfras_a.pfra_net;
864 case LEAF_pfTablesAddrTZero:
866 (time(NULL) - e->pfas.pfras_tzero) * 100;
868 case LEAF_pfTablesAddrBytesInPass:
870 e->pfas.pfras_bytes[PFR_DIR_IN][PFR_OP_PASS];
872 case LEAF_pfTablesAddrBytesInBlock:
874 e->pfas.pfras_bytes[PFR_DIR_IN][PFR_OP_BLOCK];
876 case LEAF_pfTablesAddrBytesOutPass:
878 e->pfas.pfras_bytes[PFR_DIR_OUT][PFR_OP_PASS];
880 case LEAF_pfTablesAddrBytesOutBlock:
882 e->pfas.pfras_bytes[PFR_DIR_OUT][PFR_OP_BLOCK];
884 case LEAF_pfTablesAddrPktsInPass:
886 e->pfas.pfras_packets[PFR_DIR_IN][PFR_OP_PASS];
888 case LEAF_pfTablesAddrPktsInBlock:
890 e->pfas.pfras_packets[PFR_DIR_IN][PFR_OP_BLOCK];
892 case LEAF_pfTablesAddrPktsOutPass:
894 e->pfas.pfras_packets[PFR_DIR_OUT][PFR_OP_PASS];
896 case LEAF_pfTablesAddrPktsOutBlock:
898 e->pfas.pfras_packets[PFR_DIR_OUT][PFR_OP_BLOCK];
901 return (SNMP_ERR_NOSUCHNAME);
904 return (SNMP_ERR_NOERROR);
908 pf_altq(struct snmp_context __unused *ctx, struct snmp_value *val,
909 u_int sub, u_int __unused vindex, enum snmp_op op)
911 asn_subid_t which = val->var.subs[sub - 1];
914 return (SNMP_ERR_NOSUCHNAME);
916 if (op == SNMP_OP_SET)
917 return (SNMP_ERR_NOT_WRITEABLE);
919 if (op == SNMP_OP_GET) {
920 if ((time(NULL) - pfq_table_age) > PFQ_TABLE_MAXAGE)
921 if (pfq_refresh() == -1)
922 return (SNMP_ERR_GENERR);
925 case LEAF_pfAltqQueueNumber:
926 val->v.uint32 = pfq_table_count;
930 return (SNMP_ERR_NOSUCHNAME);
933 return (SNMP_ERR_NOERROR);
937 return (SNMP_ERR_GENERR);
941 pf_altqq(struct snmp_context __unused *ctx, struct snmp_value *val,
942 u_int sub, u_int __unused vindex, enum snmp_op op)
944 asn_subid_t which = val->var.subs[sub - 1];
945 struct pfq_entry *e = NULL;
948 return (SNMP_ERR_NOSUCHNAME);
950 if ((time(NULL) - pfq_table_age) > PFQ_TABLE_MAXAGE)
955 return (SNMP_ERR_NOT_WRITEABLE);
956 case SNMP_OP_GETNEXT:
957 if ((e = NEXT_OBJECT_INT(&pfq_table,
958 &val->var, sub)) == NULL)
959 return (SNMP_ERR_NOSUCHNAME);
960 val->var.len = sub + 1;
961 val->var.subs[sub] = e->index;
964 if (val->var.len - sub != 1)
965 return (SNMP_ERR_NOSUCHNAME);
966 if ((e = pfq_table_find(val->var.subs[sub])) == NULL)
967 return (SNMP_ERR_NOSUCHNAME);
971 case SNMP_OP_ROLLBACK:
977 case LEAF_pfAltqQueueDescr:
978 return (string_get(val, e->altq.qname, -1));
979 case LEAF_pfAltqQueueParent:
980 return (string_get(val, e->altq.parent, -1));
981 case LEAF_pfAltqQueueScheduler:
982 val->v.integer = e->altq.scheduler;
984 case LEAF_pfAltqQueueBandwidth:
985 val->v.uint32 = e->altq.bandwidth;
987 case LEAF_pfAltqQueuePriority:
988 val->v.integer = e->altq.priority;
990 case LEAF_pfAltqQueueLimit:
991 val->v.integer = e->altq.qlimit;
995 return (SNMP_ERR_NOSUCHNAME);
998 return (SNMP_ERR_NOERROR);
1002 pf_labels(struct snmp_context __unused *ctx, struct snmp_value *val,
1003 u_int sub, u_int __unused vindex, enum snmp_op op)
1005 asn_subid_t which = val->var.subs[sub - 1];
1007 if (op == SNMP_OP_SET)
1008 return (SNMP_ERR_NOT_WRITEABLE);
1010 if (op == SNMP_OP_GET) {
1011 if ((time(NULL) - pfl_table_age) > PFL_TABLE_MAXAGE)
1012 if (pfl_refresh() == -1)
1013 return (SNMP_ERR_GENERR);
1016 case LEAF_pfLabelsLblNumber:
1017 val->v.uint32 = pfl_table_count;
1021 return (SNMP_ERR_NOSUCHNAME);
1024 return (SNMP_ERR_NOERROR);
1028 return (SNMP_ERR_GENERR);
1032 pf_lbltable(struct snmp_context __unused *ctx, struct snmp_value *val,
1033 u_int sub, u_int __unused vindex, enum snmp_op op)
1035 asn_subid_t which = val->var.subs[sub - 1];
1036 struct pfl_entry *e = NULL;
1038 if ((time(NULL) - pfl_table_age) > PFL_TABLE_MAXAGE)
1043 return (SNMP_ERR_NOT_WRITEABLE);
1044 case SNMP_OP_GETNEXT:
1045 if ((e = NEXT_OBJECT_INT(&pfl_table,
1046 &val->var, sub)) == NULL)
1047 return (SNMP_ERR_NOSUCHNAME);
1048 val->var.len = sub + 1;
1049 val->var.subs[sub] = e->index;
1052 if (val->var.len - sub != 1)
1053 return (SNMP_ERR_NOSUCHNAME);
1054 if ((e = pfl_table_find(val->var.subs[sub])) == NULL)
1055 return (SNMP_ERR_NOSUCHNAME);
1058 case SNMP_OP_COMMIT:
1059 case SNMP_OP_ROLLBACK:
1065 case LEAF_pfLabelsLblName:
1066 return (string_get(val, e->name, -1));
1067 case LEAF_pfLabelsLblEvals:
1068 val->v.counter64 = e->evals;
1070 case LEAF_pfLabelsLblBytesIn:
1071 val->v.counter64 = e->bytes[IN];
1073 case LEAF_pfLabelsLblBytesOut:
1074 val->v.counter64 = e->bytes[OUT];
1076 case LEAF_pfLabelsLblPktsIn:
1077 val->v.counter64 = e->pkts[IN];
1079 case LEAF_pfLabelsLblPktsOut:
1080 val->v.counter64 = e->pkts[OUT];
1083 return (SNMP_ERR_NOSUCHNAME);
1086 return (SNMP_ERR_NOERROR);
1089 static struct pfi_entry *
1090 pfi_table_find(u_int idx)
1092 struct pfi_entry *e;
1094 TAILQ_FOREACH(e, &pfi_table, link)
1095 if (e->index == idx)
1100 static struct pfq_entry *
1101 pfq_table_find(u_int idx)
1103 struct pfq_entry *e;
1105 TAILQ_FOREACH(e, &pfq_table, link)
1106 if (e->index == idx)
1111 static struct pft_entry *
1112 pft_table_find(u_int idx)
1114 struct pft_entry *e;
1116 TAILQ_FOREACH(e, &pft_table, link)
1117 if (e->index == idx)
1122 static struct pfa_entry *
1123 pfa_table_find(u_int idx)
1125 struct pfa_entry *e;
1127 TAILQ_FOREACH(e, &pfa_table, link)
1128 if (e->index == idx)
1133 static struct pfl_entry *
1134 pfl_table_find(u_int idx)
1136 struct pfl_entry *e;
1138 TAILQ_FOREACH(e, &pfl_table, link)
1139 if (e->index == idx)
1148 struct pfioc_iface io;
1149 struct pfi_kif *p = NULL;
1150 struct pfi_entry *e;
1153 if (started && this_tick <= pf_tick)
1156 while (!TAILQ_EMPTY(&pfi_table)) {
1157 e = TAILQ_FIRST(&pfi_table);
1158 TAILQ_REMOVE(&pfi_table, e, link);
1162 bzero(&io, sizeof(io));
1163 io.pfiio_esize = sizeof(struct pfi_kif);
1166 p = reallocf(p, numifs * sizeof(struct pfi_kif));
1168 syslog(LOG_ERR, "pfi_refresh(): reallocf() numifs=%d: %s",
1169 numifs, strerror(errno));
1172 io.pfiio_size = numifs;
1173 io.pfiio_buffer = p;
1175 if (ioctl(dev, DIOCIGETIFACES, &io)) {
1176 syslog(LOG_ERR, "pfi_refresh(): ioctl(): %s",
1181 if (numifs >= io.pfiio_size)
1184 numifs = io.pfiio_size;
1187 for (i = 0; i < numifs; i++) {
1188 e = malloc(sizeof(struct pfi_entry));
1192 memcpy(&e->pfi, p+i, sizeof(struct pfi_kif));
1193 TAILQ_INSERT_TAIL(&pfi_table, e, link);
1196 pfi_table_age = time(NULL);
1197 pfi_table_count = numifs;
1198 pf_tick = this_tick;
1204 while (!TAILQ_EMPTY(&pfi_table)) {
1205 e = TAILQ_FIRST(&pfi_table);
1206 TAILQ_REMOVE(&pfi_table, e, link);
1217 struct pfioc_altq pa;
1218 struct pfq_entry *e;
1219 int i, numqs, ticket;
1221 if (started && this_tick <= pf_tick)
1224 while (!TAILQ_EMPTY(&pfq_table)) {
1225 e = TAILQ_FIRST(&pfq_table);
1226 TAILQ_REMOVE(&pfq_table, e, link);
1230 bzero(&pa, sizeof(pa));
1232 if (ioctl(dev, DIOCGETALTQS, &pa)) {
1233 syslog(LOG_ERR, "pfq_refresh: ioctl(DIOCGETALTQS): %s",
1241 for (i = 0; i < numqs; i++) {
1242 e = malloc(sizeof(struct pfq_entry));
1244 syslog(LOG_ERR, "pfq_refresh(): "
1252 if (ioctl(dev, DIOCGETALTQ, &pa)) {
1253 syslog(LOG_ERR, "pfq_refresh(): "
1254 "ioctl(DIOCGETALTQ): %s",
1259 if (pa.altq.qid > 0) {
1260 memcpy(&e->altq, &pa.altq, sizeof(struct pf_altq));
1261 e->index = pa.altq.qid;
1262 pfq_table_count = i;
1263 INSERT_OBJECT_INT_LINK_INDEX(e, &pfq_table, link, index);
1267 pfq_table_age = time(NULL);
1268 pf_tick = this_tick;
1273 while (!TAILQ_EMPTY(&pfq_table)) {
1274 e = TAILQ_FIRST(&pfq_table);
1275 TAILQ_REMOVE(&pfq_table, e, link);
1284 if (started && this_tick <= pf_tick)
1287 bzero(&pfs, sizeof(struct pf_status));
1289 if (ioctl(dev, DIOCGETSTATUS, &pfs)) {
1290 syslog(LOG_ERR, "pfs_refresh(): ioctl(): %s",
1295 pf_tick = this_tick;
1302 struct pfioc_table io;
1303 struct pfr_tstats *t = NULL;
1304 struct pft_entry *e;
1307 if (started && this_tick <= pf_tick)
1310 while (!TAILQ_EMPTY(&pft_table)) {
1311 e = TAILQ_FIRST(&pft_table);
1312 TAILQ_REMOVE(&pft_table, e, link);
1316 bzero(&io, sizeof(io));
1317 io.pfrio_esize = sizeof(struct pfr_tstats);
1320 t = reallocf(t, numtbls * sizeof(struct pfr_tstats));
1322 syslog(LOG_ERR, "pft_refresh(): reallocf() numtbls=%d: %s",
1323 numtbls, strerror(errno));
1326 io.pfrio_size = numtbls;
1327 io.pfrio_buffer = t;
1329 if (ioctl(dev, DIOCRGETTSTATS, &io)) {
1330 syslog(LOG_ERR, "pft_refresh(): ioctl(): %s",
1335 if (numtbls >= io.pfrio_size)
1338 numtbls = io.pfrio_size;
1341 for (i = 0; i < numtbls; i++) {
1342 e = malloc(sizeof(struct pft_entry));
1346 memcpy(&e->pft, t+i, sizeof(struct pfr_tstats));
1347 TAILQ_INSERT_TAIL(&pft_table, e, link);
1350 pft_table_age = time(NULL);
1351 pft_table_count = numtbls;
1352 pf_tick = this_tick;
1357 while (!TAILQ_EMPTY(&pft_table)) {
1358 e = TAILQ_FIRST(&pft_table);
1359 TAILQ_REMOVE(&pft_table, e, link);
1368 pfa_table_addrs(u_int sidx, struct pfr_table *pt)
1370 struct pfioc_table io;
1371 struct pfr_astats *t = NULL;
1372 struct pfa_entry *e;
1373 int i, numaddrs = 1;
1378 memset(&io, 0, sizeof(io));
1379 strlcpy(io.pfrio_table.pfrt_name, pt->pfrt_name,
1380 sizeof(io.pfrio_table.pfrt_name));
1383 t = reallocf(t, numaddrs * sizeof(struct pfr_astats));
1385 syslog(LOG_ERR, "pfa_table_addrs(): reallocf(): %s",
1391 memset(t, 0, sizeof(*t));
1392 io.pfrio_size = numaddrs;
1393 io.pfrio_buffer = t;
1394 io.pfrio_esize = sizeof(struct pfr_astats);
1396 if (ioctl(dev, DIOCRGETASTATS, &io)) {
1397 syslog(LOG_ERR, "pfa_table_addrs(): ioctl() on %s: %s",
1398 pt->pfrt_name, strerror(errno));
1403 if (numaddrs >= io.pfrio_size)
1406 numaddrs = io.pfrio_size;
1409 for (i = 0; i < numaddrs; i++) {
1410 if ((t + i)->pfras_a.pfra_af != AF_INET &&
1411 (t + i)->pfras_a.pfra_af != AF_INET6) {
1416 e = (struct pfa_entry *)malloc(sizeof(struct pfa_entry));
1418 syslog(LOG_ERR, "pfa_table_addrs(): malloc(): %s",
1423 e->index = sidx + i;
1424 memcpy(&e->pfas, t + i, sizeof(struct pfr_astats));
1425 TAILQ_INSERT_TAIL(&pfa_table, e, link);
1436 struct pfioc_table io;
1437 struct pfr_table *pt = NULL, *it = NULL;
1438 struct pfa_entry *e;
1439 int i, numtbls = 1, cidx, naddrs;
1441 if (started && this_tick <= pf_tick)
1444 while (!TAILQ_EMPTY(&pfa_table)) {
1445 e = TAILQ_FIRST(&pfa_table);
1446 TAILQ_REMOVE(&pfa_table, e, link);
1450 memset(&io, 0, sizeof(io));
1451 io.pfrio_esize = sizeof(struct pfr_table);
1454 pt = reallocf(pt, numtbls * sizeof(struct pfr_table));
1456 syslog(LOG_ERR, "pfa_refresh(): reallocf() %s",
1460 memset(pt, 0, sizeof(*pt));
1461 io.pfrio_size = numtbls;
1462 io.pfrio_buffer = pt;
1464 if (ioctl(dev, DIOCRGETTABLES, &io)) {
1465 syslog(LOG_ERR, "pfa_refresh(): ioctl(): %s",
1470 if (numtbls >= io.pfrio_size)
1473 numtbls = io.pfrio_size;
1478 for (it = pt, i = 0; i < numtbls; it++, i++) {
1480 * Skip the table if not active - ioctl(DIOCRGETASTATS) will
1481 * return ESRCH for this entry anyway.
1483 if (!(it->pfrt_flags & PFR_TFLAG_ACTIVE))
1486 if ((naddrs = pfa_table_addrs(cidx, it)) < 0)
1492 pfa_table_age = time(NULL);
1493 pfa_table_count = cidx;
1494 pf_tick = this_tick;
1499 while (!TAILQ_EMPTY(&pfa_table)) {
1500 e = TAILQ_FIRST(&pfa_table);
1501 TAILQ_REMOVE(&pfa_table, e, link);
1511 pfl_scan_ruleset(const char *path)
1513 struct pfioc_rule pr;
1514 struct pfl_entry *e;
1517 bzero(&pr, sizeof(pr));
1518 strlcpy(pr.anchor, path, sizeof(pr.anchor));
1519 pr.rule.action = PF_PASS;
1520 if (ioctl(dev, DIOCGETRULES, &pr)) {
1521 syslog(LOG_ERR, "pfl_scan_ruleset: ioctl(DIOCGETRULES): %s",
1526 for (nr = pr.nr, i = 0; i < nr; i++) {
1528 if (ioctl(dev, DIOCGETRULE, &pr)) {
1529 syslog(LOG_ERR, "pfl_scan_ruleset: ioctl(DIOCGETRULE):"
1530 " %s", strerror(errno));
1534 if (pr.rule.label[0]) {
1535 e = (struct pfl_entry *)malloc(sizeof(*e));
1539 strlcpy(e->name, path, sizeof(e->name));
1541 strlcat(e->name, "/", sizeof(e->name));
1542 strlcat(e->name, pr.rule.label, sizeof(e->name));
1544 e->evals = pr.rule.evaluations;
1545 e->bytes[IN] = pr.rule.bytes[IN];
1546 e->bytes[OUT] = pr.rule.bytes[OUT];
1547 e->pkts[IN] = pr.rule.packets[IN];
1548 e->pkts[OUT] = pr.rule.packets[OUT];
1549 e->index = ++pfl_table_count;
1551 TAILQ_INSERT_TAIL(&pfl_table, e, link);
1562 pfl_walk_rulesets(const char *path)
1564 struct pfioc_ruleset prs;
1565 char newpath[MAXPATHLEN];
1568 if (pfl_scan_ruleset(path))
1571 bzero(&prs, sizeof(prs));
1572 strlcpy(prs.path, path, sizeof(prs.path));
1573 if (ioctl(dev, DIOCGETRULESETS, &prs)) {
1574 syslog(LOG_ERR, "pfl_walk_rulesets: ioctl(DIOCGETRULESETS): %s",
1579 for (nr = prs.nr, i = 0; i < nr; i++) {
1581 if (ioctl(dev, DIOCGETRULESET, &prs)) {
1582 syslog(LOG_ERR, "pfl_walk_rulesets: ioctl(DIOCGETRULESET):"
1583 " %s", strerror(errno));
1587 if (strcmp(prs.name, PF_RESERVED_ANCHOR) == 0)
1590 strlcpy(newpath, path, sizeof(newpath));
1592 strlcat(newpath, "/", sizeof(newpath));
1594 strlcat(newpath, prs.name, sizeof(newpath));
1595 if (pfl_walk_rulesets(newpath))
1608 struct pfl_entry *e;
1610 if (started && this_tick <= pf_tick)
1613 while (!TAILQ_EMPTY(&pfl_table)) {
1614 e = TAILQ_FIRST(&pfl_table);
1615 TAILQ_REMOVE(&pfl_table, e, link);
1618 pfl_table_count = 0;
1620 if (pfl_walk_rulesets(""))
1623 pfl_table_age = time(NULL);
1624 pf_tick = this_tick;
1629 while (!TAILQ_EMPTY(&pfl_table)) {
1630 e = TAILQ_FIRST(&pfl_table);
1631 TAILQ_REMOVE(&pfl_table, e, link);
1634 pfl_table_count = 0;
1640 * check whether altq support is enabled in kernel
1644 altq_is_enabled(int pfdev)
1646 struct pfioc_altq pa;
1649 if (ioctl(pfdev, DIOCGETALTQS, &pa)) {
1650 if (errno == ENODEV) {
1651 syslog(LOG_INFO, "No ALTQ support in kernel\n"
1652 "ALTQ related functions disabled\n");
1655 syslog(LOG_ERR, "DIOCGETALTQS returned an error: %s",
1663 * Implement the bsnmpd module interface
1666 pf_init(struct lmodule *mod, int __unused argc, char __unused *argv[])
1670 if ((dev = open("/dev/pf", O_RDONLY)) == -1) {
1671 syslog(LOG_ERR, "pf_init(): open(): %s\n",
1676 if ((altq_enabled = altq_is_enabled(dev)) == -1) {
1677 syslog(LOG_ERR, "pf_init(): altq test failed");
1681 /* Prepare internal state */
1682 TAILQ_INIT(&pfi_table);
1683 TAILQ_INIT(&pfq_table);
1684 TAILQ_INIT(&pft_table);
1685 TAILQ_INIT(&pfa_table);
1686 TAILQ_INIT(&pfl_table);
1706 struct pfi_entry *i1, *i2;
1707 struct pfq_entry *q1, *q2;
1708 struct pft_entry *t1, *t2;
1709 struct pfa_entry *a1, *a2;
1710 struct pfl_entry *l1, *l2;
1712 /* Empty the list of interfaces */
1713 i1 = TAILQ_FIRST(&pfi_table);
1714 while (i1 != NULL) {
1715 i2 = TAILQ_NEXT(i1, link);
1720 /* List of queues */
1721 q1 = TAILQ_FIRST(&pfq_table);
1722 while (q1 != NULL) {
1723 q2 = TAILQ_NEXT(q1, link);
1728 /* List of tables */
1729 t1 = TAILQ_FIRST(&pft_table);
1730 while (t1 != NULL) {
1731 t2 = TAILQ_NEXT(t1, link);
1736 /* List of table addresses */
1737 a1 = TAILQ_FIRST(&pfa_table);
1738 while (a1 != NULL) {
1739 a2 = TAILQ_NEXT(a1, link);
1744 /* And the list of labeled filter rules */
1745 l1 = TAILQ_FIRST(&pfl_table);
1746 while (l1 != NULL) {
1747 l2 = TAILQ_NEXT(l1, link);
1767 syslog(LOG_ERR, "Dump: pfi_table_age = %jd",
1768 (intmax_t)pfi_table_age);
1769 syslog(LOG_ERR, "Dump: pfi_table_count = %d",
1772 syslog(LOG_ERR, "Dump: pfq_table_age = %jd",
1773 (intmax_t)pfq_table_age);
1774 syslog(LOG_ERR, "Dump: pfq_table_count = %d",
1777 syslog(LOG_ERR, "Dump: pft_table_age = %jd",
1778 (intmax_t)pft_table_age);
1779 syslog(LOG_ERR, "Dump: pft_table_count = %d",
1782 syslog(LOG_ERR, "Dump: pfa_table_age = %jd",
1783 (intmax_t)pfa_table_age);
1784 syslog(LOG_ERR, "Dump: pfa_table_count = %d",
1787 syslog(LOG_ERR, "Dump: pfl_table_age = %jd",
1788 (intmax_t)pfl_table_age);
1789 syslog(LOG_ERR, "Dump: pfl_table_count = %d",
1793 const struct snmp_module config = {
1794 .comment = "This module implements a MIB for the pf packet filter.",
1799 .tree_size = pf_CTREE_SIZE,