]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/bsnmpd/modules/snmp_pf/pf_snmp.c
Merge ^/vendor/lldb/dist up to its last change, and resolve conflicts.
[FreeBSD/FreeBSD.git] / usr.sbin / bsnmpd / modules / snmp_pf / pf_snmp.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2005 Philip Paeps <philip@FreeBSD.org>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  *
28  * $FreeBSD$
29  */
30
31 #define PFIOC_USE_LATEST
32
33 #include <sys/queue.h>
34 #include <bsnmp/snmpmod.h>
35
36 #include <net/pfvar.h>
37 #include <sys/ioctl.h>
38
39 #include <errno.h>
40 #include <fcntl.h>
41 #include <stdint.h>
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <string.h>
45 #include <syslog.h>
46 #include <unistd.h>
47
48 #define SNMPTREE_TYPES
49 #include "pf_oid.h"
50 #include "pf_tree.h"
51
52 struct lmodule *module;
53
54 static int dev = -1;
55 static int started;
56 static uint64_t pf_tick;
57
58 static struct pf_status pfs;
59
60 enum { IN, OUT };
61 enum { IPV4, IPV6 };
62 enum { PASS, BLOCK };
63
64 #define PFI_IFTYPE_GROUP        0
65 #define PFI_IFTYPE_INSTANCE     1
66 #define PFI_IFTYPE_DETACHED     2
67
68 struct pfi_entry {
69         struct pfi_kif  pfi;
70         u_int           index;
71         TAILQ_ENTRY(pfi_entry) link;
72 };
73 TAILQ_HEAD(pfi_table, pfi_entry);
74
75 static struct pfi_table pfi_table;
76 static time_t pfi_table_age;
77 static int pfi_table_count;
78
79 #define PFI_TABLE_MAXAGE        5
80
81 struct pft_entry {
82         struct pfr_tstats pft;
83         u_int           index;
84         TAILQ_ENTRY(pft_entry) link;
85 };
86 TAILQ_HEAD(pft_table, pft_entry);
87
88 static struct pft_table pft_table;
89 static time_t pft_table_age;
90 static int pft_table_count;
91
92 #define PFT_TABLE_MAXAGE        5
93
94 struct pfa_entry {
95         struct pfr_astats pfas;
96         u_int           index;
97         TAILQ_ENTRY(pfa_entry) link;
98 };
99 TAILQ_HEAD(pfa_table, pfa_entry);
100
101 static struct pfa_table pfa_table;
102 static time_t pfa_table_age;
103 static int pfa_table_count;
104
105 #define PFA_TABLE_MAXAGE        5
106
107 struct pfq_entry {
108         struct pf_altq  altq;
109         u_int           index;
110         TAILQ_ENTRY(pfq_entry) link;
111 };
112 TAILQ_HEAD(pfq_table, pfq_entry);
113
114 static struct pfq_table pfq_table;
115 static time_t pfq_table_age;
116 static int pfq_table_count;
117
118 static int altq_enabled = 0;
119
120 #define PFQ_TABLE_MAXAGE        5
121
122 struct pfl_entry {
123         char            name[MAXPATHLEN + PF_RULE_LABEL_SIZE];
124         u_int64_t       evals;
125         u_int64_t       bytes[2];
126         u_int64_t       pkts[2];
127         u_int           index;
128         TAILQ_ENTRY(pfl_entry) link;
129 };
130 TAILQ_HEAD(pfl_table, pfl_entry);
131
132 static struct pfl_table pfl_table;
133 static time_t pfl_table_age;
134 static int pfl_table_count;
135
136 #define PFL_TABLE_MAXAGE        5
137
138 /* Forward declarations */
139 static int pfi_refresh(void);
140 static int pfq_refresh(void);
141 static int pfs_refresh(void);
142 static int pft_refresh(void);
143 static int pfa_refresh(void);
144 static int pfl_refresh(void);
145 static struct pfi_entry * pfi_table_find(u_int idx);
146 static struct pfq_entry * pfq_table_find(u_int idx);
147 static struct pft_entry * pft_table_find(u_int idx);
148 static struct pfa_entry * pfa_table_find(u_int idx);
149 static struct pfl_entry * pfl_table_find(u_int idx);
150
151 static int altq_is_enabled(int pfdevice);
152
153 int
154 pf_status(struct snmp_context __unused *ctx, struct snmp_value *val,
155         u_int sub, u_int __unused vindex, enum snmp_op op)
156 {
157         asn_subid_t     which = val->var.subs[sub - 1];
158         time_t          runtime;
159         unsigned char   str[128];
160
161         if (op == SNMP_OP_SET)
162                 return (SNMP_ERR_NOT_WRITEABLE);
163
164         if (op == SNMP_OP_GET) {
165                 if (pfs_refresh() == -1)
166                         return (SNMP_ERR_GENERR);
167
168                 switch (which) {
169                         case LEAF_pfStatusRunning:
170                             val->v.uint32 = pfs.running;
171                             break;
172                         case LEAF_pfStatusRuntime:
173                             runtime = (pfs.since > 0) ?
174                                 time(NULL) - pfs.since : 0;
175                             val->v.uint32 = runtime * 100;
176                             break;
177                         case LEAF_pfStatusDebug:
178                             val->v.uint32 = pfs.debug;
179                             break;
180                         case LEAF_pfStatusHostId:
181                             sprintf(str, "0x%08x", ntohl(pfs.hostid));
182                             return (string_get(val, str, strlen(str)));
183
184                         default:
185                             return (SNMP_ERR_NOSUCHNAME);
186                 }
187
188                 return (SNMP_ERR_NOERROR);
189         }
190
191         abort();
192 }
193
194 int
195 pf_counter(struct snmp_context __unused *ctx, struct snmp_value *val,
196         u_int sub, u_int __unused vindex, enum snmp_op op)
197 {
198         asn_subid_t     which = val->var.subs[sub - 1];
199
200         if (op == SNMP_OP_SET)
201                 return (SNMP_ERR_NOT_WRITEABLE);
202
203         if (op == SNMP_OP_GET) {
204                 if (pfs_refresh() == -1)
205                         return (SNMP_ERR_GENERR);
206
207                 switch (which) {
208                         case LEAF_pfCounterMatch:
209                                 val->v.counter64 = pfs.counters[PFRES_MATCH];
210                                 break;
211                         case LEAF_pfCounterBadOffset:
212                                 val->v.counter64 = pfs.counters[PFRES_BADOFF];
213                                 break;
214                         case LEAF_pfCounterFragment:
215                                 val->v.counter64 = pfs.counters[PFRES_FRAG];
216                                 break;
217                         case LEAF_pfCounterShort:
218                                 val->v.counter64 = pfs.counters[PFRES_SHORT];
219                                 break;
220                         case LEAF_pfCounterNormalize:
221                                 val->v.counter64 = pfs.counters[PFRES_NORM];
222                                 break;
223                         case LEAF_pfCounterMemDrop:
224                                 val->v.counter64 = pfs.counters[PFRES_MEMORY];
225                                 break;
226
227                         default:
228                                 return (SNMP_ERR_NOSUCHNAME);
229                 }
230
231                 return (SNMP_ERR_NOERROR);
232         }
233
234         abort();
235 }
236
237 int
238 pf_statetable(struct snmp_context __unused *ctx, struct snmp_value *val,
239         u_int sub, u_int __unused vindex, enum snmp_op op)
240 {
241         asn_subid_t     which = val->var.subs[sub - 1];
242
243         if (op == SNMP_OP_SET)
244                 return (SNMP_ERR_NOT_WRITEABLE);
245
246         if (op == SNMP_OP_GET) {
247                 if (pfs_refresh() == -1)
248                         return (SNMP_ERR_GENERR);
249
250                 switch (which) {
251                         case LEAF_pfStateTableCount:
252                                 val->v.uint32 = pfs.states;
253                                 break;
254                         case LEAF_pfStateTableSearches:
255                                 val->v.counter64 =
256                                     pfs.fcounters[FCNT_STATE_SEARCH];
257                                 break;
258                         case LEAF_pfStateTableInserts:
259                                 val->v.counter64 =
260                                     pfs.fcounters[FCNT_STATE_INSERT];
261                                 break;
262                         case LEAF_pfStateTableRemovals:
263                                 val->v.counter64 =
264                                     pfs.fcounters[FCNT_STATE_REMOVALS];
265                                 break;
266
267                         default:
268                                 return (SNMP_ERR_NOSUCHNAME);
269                 }
270
271                 return (SNMP_ERR_NOERROR);
272         }
273
274         abort();
275 }
276
277 int
278 pf_srcnodes(struct snmp_context __unused *ctx, struct snmp_value *val,
279         u_int sub, u_int __unused vindex, enum snmp_op op)
280 {
281         asn_subid_t     which = val->var.subs[sub - 1];
282
283         if (op == SNMP_OP_SET)
284                 return (SNMP_ERR_NOT_WRITEABLE);
285
286         if (op == SNMP_OP_GET) {
287                 if (pfs_refresh() == -1)
288                         return (SNMP_ERR_GENERR);
289
290                 switch (which) {
291                         case LEAF_pfSrcNodesCount:
292                                 val->v.uint32 = pfs.src_nodes;
293                                 break;
294                         case LEAF_pfSrcNodesSearches:
295                                 val->v.counter64 =
296                                     pfs.scounters[SCNT_SRC_NODE_SEARCH];
297                                 break;
298                         case LEAF_pfSrcNodesInserts:
299                                 val->v.counter64 =
300                                     pfs.scounters[SCNT_SRC_NODE_INSERT];
301                                 break;
302                         case LEAF_pfSrcNodesRemovals:
303                                 val->v.counter64 =
304                                     pfs.scounters[SCNT_SRC_NODE_REMOVALS];
305                                 break;
306
307                         default:
308                                 return (SNMP_ERR_NOSUCHNAME);
309                 }
310
311                 return (SNMP_ERR_NOERROR);
312         }
313
314         abort();
315 }
316
317 int
318 pf_limits(struct snmp_context __unused *ctx, struct snmp_value *val,
319         u_int sub, u_int __unused vindex, enum snmp_op op)
320 {
321         asn_subid_t             which = val->var.subs[sub - 1];
322         struct pfioc_limit      pl;
323
324         if (op == SNMP_OP_SET)
325                 return (SNMP_ERR_NOT_WRITEABLE);
326
327         if (op == SNMP_OP_GET) {
328                 bzero(&pl, sizeof(struct pfioc_limit));
329
330                 switch (which) {
331                         case LEAF_pfLimitsStates:
332                                 pl.index = PF_LIMIT_STATES;
333                                 break;
334                         case LEAF_pfLimitsSrcNodes:
335                                 pl.index = PF_LIMIT_SRC_NODES;
336                                 break;
337                         case LEAF_pfLimitsFrags:
338                                 pl.index = PF_LIMIT_FRAGS;
339                                 break;
340
341                         default:
342                                 return (SNMP_ERR_NOSUCHNAME);
343                 }
344
345                 if (ioctl(dev, DIOCGETLIMIT, &pl)) {
346                         syslog(LOG_ERR, "pf_limits(): ioctl(): %s",
347                             strerror(errno));
348                         return (SNMP_ERR_GENERR);
349                 }
350
351                 val->v.uint32 = pl.limit;
352
353                 return (SNMP_ERR_NOERROR);
354         }
355
356         abort();
357 }
358
359 int
360 pf_timeouts(struct snmp_context __unused *ctx, struct snmp_value *val,
361         u_int sub, u_int __unused vindex, enum snmp_op op)
362 {
363         asn_subid_t     which = val->var.subs[sub - 1];
364         struct pfioc_tm pt;
365
366         if (op == SNMP_OP_SET)
367                 return (SNMP_ERR_NOT_WRITEABLE);
368
369         if (op == SNMP_OP_GET) {
370                 bzero(&pt, sizeof(struct pfioc_tm));
371
372                 switch (which) {
373                         case LEAF_pfTimeoutsTcpFirst:
374                                 pt.timeout = PFTM_TCP_FIRST_PACKET;
375                                 break;
376                         case LEAF_pfTimeoutsTcpOpening:
377                                 pt.timeout = PFTM_TCP_OPENING;
378                                 break;
379                         case LEAF_pfTimeoutsTcpEstablished:
380                                 pt.timeout = PFTM_TCP_ESTABLISHED;
381                                 break;
382                         case LEAF_pfTimeoutsTcpClosing:
383                                 pt.timeout = PFTM_TCP_CLOSING;
384                                 break;
385                         case LEAF_pfTimeoutsTcpFinWait:
386                                 pt.timeout = PFTM_TCP_FIN_WAIT;
387                                 break;
388                         case LEAF_pfTimeoutsTcpClosed:
389                                 pt.timeout = PFTM_TCP_CLOSED;
390                                 break;
391                         case LEAF_pfTimeoutsUdpFirst:
392                                 pt.timeout = PFTM_UDP_FIRST_PACKET;
393                                 break;
394                         case LEAF_pfTimeoutsUdpSingle:
395                                 pt.timeout = PFTM_UDP_SINGLE;
396                                 break;
397                         case LEAF_pfTimeoutsUdpMultiple:
398                                 pt.timeout = PFTM_UDP_MULTIPLE;
399                                 break;
400                         case LEAF_pfTimeoutsIcmpFirst:
401                                 pt.timeout = PFTM_ICMP_FIRST_PACKET;
402                                 break;
403                         case LEAF_pfTimeoutsIcmpError:
404                                 pt.timeout = PFTM_ICMP_ERROR_REPLY;
405                                 break;
406                         case LEAF_pfTimeoutsOtherFirst:
407                                 pt.timeout = PFTM_OTHER_FIRST_PACKET;
408                                 break;
409                         case LEAF_pfTimeoutsOtherSingle:
410                                 pt.timeout = PFTM_OTHER_SINGLE;
411                                 break;
412                         case LEAF_pfTimeoutsOtherMultiple:
413                                 pt.timeout = PFTM_OTHER_MULTIPLE;
414                                 break;
415                         case LEAF_pfTimeoutsFragment:
416                                 pt.timeout = PFTM_FRAG;
417                                 break;
418                         case LEAF_pfTimeoutsInterval:
419                                 pt.timeout = PFTM_INTERVAL;
420                                 break;
421                         case LEAF_pfTimeoutsAdaptiveStart:
422                                 pt.timeout = PFTM_ADAPTIVE_START;
423                                 break;
424                         case LEAF_pfTimeoutsAdaptiveEnd:
425                                 pt.timeout = PFTM_ADAPTIVE_END;
426                                 break;
427                         case LEAF_pfTimeoutsSrcNode:
428                                 pt.timeout = PFTM_SRC_NODE;
429                                 break;
430
431                         default:
432                                 return (SNMP_ERR_NOSUCHNAME);
433                 }
434
435                 if (ioctl(dev, DIOCGETTIMEOUT, &pt)) {
436                         syslog(LOG_ERR, "pf_timeouts(): ioctl(): %s",
437                             strerror(errno));
438                         return (SNMP_ERR_GENERR);
439                 }
440
441                 val->v.integer = pt.seconds;
442
443                 return (SNMP_ERR_NOERROR);
444         }
445
446         abort();
447 }
448
449 int
450 pf_logif(struct snmp_context __unused *ctx, struct snmp_value *val,
451         u_int sub, u_int __unused vindex, enum snmp_op op)
452 {
453         asn_subid_t     which = val->var.subs[sub - 1];
454         unsigned char   str[IFNAMSIZ];
455
456         if (op == SNMP_OP_SET)
457                 return (SNMP_ERR_NOT_WRITEABLE);
458
459         if (op == SNMP_OP_GET) {
460                 if (pfs_refresh() == -1)
461                         return (SNMP_ERR_GENERR);
462
463                 switch (which) {
464                         case LEAF_pfLogInterfaceName:
465                                 strlcpy(str, pfs.ifname, sizeof str);
466                                 return (string_get(val, str, strlen(str)));
467                         case LEAF_pfLogInterfaceIp4BytesIn:
468                                 val->v.counter64 = pfs.bcounters[IPV4][IN];
469                                 break;
470                         case LEAF_pfLogInterfaceIp4BytesOut:
471                                 val->v.counter64 = pfs.bcounters[IPV4][OUT];
472                                 break;
473                         case LEAF_pfLogInterfaceIp4PktsInPass:
474                                 val->v.counter64 =
475                                     pfs.pcounters[IPV4][IN][PF_PASS];
476                                 break;
477                         case LEAF_pfLogInterfaceIp4PktsInDrop:
478                                 val->v.counter64 =
479                                     pfs.pcounters[IPV4][IN][PF_DROP];
480                                 break;
481                         case LEAF_pfLogInterfaceIp4PktsOutPass:
482                                 val->v.counter64 =
483                                     pfs.pcounters[IPV4][OUT][PF_PASS];
484                                 break;
485                         case LEAF_pfLogInterfaceIp4PktsOutDrop:
486                                 val->v.counter64 =
487                                     pfs.pcounters[IPV4][OUT][PF_DROP];
488                                 break;
489                         case LEAF_pfLogInterfaceIp6BytesIn:
490                                 val->v.counter64 = pfs.bcounters[IPV6][IN];
491                                 break;
492                         case LEAF_pfLogInterfaceIp6BytesOut:
493                                 val->v.counter64 = pfs.bcounters[IPV6][OUT];
494                                 break;
495                         case LEAF_pfLogInterfaceIp6PktsInPass:
496                                 val->v.counter64 =
497                                     pfs.pcounters[IPV6][IN][PF_PASS];
498                                 break;
499                         case LEAF_pfLogInterfaceIp6PktsInDrop:
500                                 val->v.counter64 =
501                                     pfs.pcounters[IPV6][IN][PF_DROP];
502                                 break;
503                         case LEAF_pfLogInterfaceIp6PktsOutPass:
504                                 val->v.counter64 =
505                                     pfs.pcounters[IPV6][OUT][PF_PASS];
506                                 break;
507                         case LEAF_pfLogInterfaceIp6PktsOutDrop:
508                                 val->v.counter64 =
509                                     pfs.pcounters[IPV6][OUT][PF_DROP];
510                                 break;
511
512                         default:
513                                 return (SNMP_ERR_NOSUCHNAME);
514                 }
515
516                 return (SNMP_ERR_NOERROR);
517         }
518
519         abort();
520 }
521
522 int
523 pf_interfaces(struct snmp_context __unused *ctx, struct snmp_value *val,
524         u_int sub, u_int __unused vindex, enum snmp_op op)
525 {
526         asn_subid_t     which = val->var.subs[sub - 1];
527
528         if (op == SNMP_OP_SET)
529                 return (SNMP_ERR_NOT_WRITEABLE);
530
531         if (op == SNMP_OP_GET) {
532                 if ((time(NULL) - pfi_table_age) > PFI_TABLE_MAXAGE)
533                         if (pfi_refresh() == -1)
534                             return (SNMP_ERR_GENERR);
535
536                 switch (which) {
537                         case LEAF_pfInterfacesIfNumber:
538                                 val->v.uint32 = pfi_table_count;
539                                 break;
540
541                         default:
542                                 return (SNMP_ERR_NOSUCHNAME);
543                 }
544
545                 return (SNMP_ERR_NOERROR);
546         }
547
548         abort();
549 }
550
551 int
552 pf_iftable(struct snmp_context __unused *ctx, struct snmp_value *val,
553         u_int sub, u_int __unused vindex, enum snmp_op op)
554 {
555         asn_subid_t     which = val->var.subs[sub - 1];
556         struct pfi_entry *e = NULL;
557
558         if ((time(NULL) - pfi_table_age) > PFI_TABLE_MAXAGE)
559                 pfi_refresh();
560
561         switch (op) {
562                 case SNMP_OP_SET:
563                         return (SNMP_ERR_NOT_WRITEABLE);
564                 case SNMP_OP_GETNEXT:
565                         if ((e = NEXT_OBJECT_INT(&pfi_table,
566                             &val->var, sub)) == NULL)
567                                 return (SNMP_ERR_NOSUCHNAME);
568                         val->var.len = sub + 1;
569                         val->var.subs[sub] = e->index;
570                         break;
571                 case SNMP_OP_GET:
572                         if (val->var.len - sub != 1)
573                                 return (SNMP_ERR_NOSUCHNAME);
574                         if ((e = pfi_table_find(val->var.subs[sub])) == NULL)
575                                 return (SNMP_ERR_NOSUCHNAME);
576                         break;
577
578                 case SNMP_OP_COMMIT:
579                 case SNMP_OP_ROLLBACK:
580                 default:
581                         abort();
582         }
583
584         switch (which) {
585                 case LEAF_pfInterfacesIfDescr:
586                         return (string_get(val, e->pfi.pfik_name, -1));
587                 case LEAF_pfInterfacesIfType:
588                         val->v.integer = PFI_IFTYPE_INSTANCE;
589                         break;
590                 case LEAF_pfInterfacesIfTZero:
591                         val->v.uint32 =
592                             (time(NULL) - e->pfi.pfik_tzero) * 100;
593                         break;
594                 case LEAF_pfInterfacesIfRefsRule:
595                         val->v.uint32 = e->pfi.pfik_rulerefs;
596                         break;
597                 case LEAF_pfInterfacesIf4BytesInPass:
598                         val->v.counter64 =
599                             e->pfi.pfik_bytes[IPV4][IN][PASS];
600                         break;
601                 case LEAF_pfInterfacesIf4BytesInBlock:
602                         val->v.counter64 =
603                             e->pfi.pfik_bytes[IPV4][IN][BLOCK];
604                         break;
605                 case LEAF_pfInterfacesIf4BytesOutPass:
606                         val->v.counter64 =
607                             e->pfi.pfik_bytes[IPV4][OUT][PASS];
608                         break;
609                 case LEAF_pfInterfacesIf4BytesOutBlock:
610                         val->v.counter64 =
611                             e->pfi.pfik_bytes[IPV4][OUT][BLOCK];
612                         break;
613                 case LEAF_pfInterfacesIf4PktsInPass:
614                         val->v.counter64 =
615                             e->pfi.pfik_packets[IPV4][IN][PASS];
616                         break;
617                 case LEAF_pfInterfacesIf4PktsInBlock:
618                         val->v.counter64 =
619                             e->pfi.pfik_packets[IPV4][IN][BLOCK];
620                         break;
621                 case LEAF_pfInterfacesIf4PktsOutPass:
622                         val->v.counter64 =
623                             e->pfi.pfik_packets[IPV4][OUT][PASS];
624                         break;
625                 case LEAF_pfInterfacesIf4PktsOutBlock:
626                         val->v.counter64 =
627                             e->pfi.pfik_packets[IPV4][OUT][BLOCK];
628                         break;
629                 case LEAF_pfInterfacesIf6BytesInPass:
630                         val->v.counter64 =
631                             e->pfi.pfik_bytes[IPV6][IN][PASS];
632                         break;
633                 case LEAF_pfInterfacesIf6BytesInBlock:
634                         val->v.counter64 =
635                             e->pfi.pfik_bytes[IPV6][IN][BLOCK];
636                         break;
637                 case LEAF_pfInterfacesIf6BytesOutPass:
638                         val->v.counter64 =
639                             e->pfi.pfik_bytes[IPV6][OUT][PASS];
640                         break;
641                 case LEAF_pfInterfacesIf6BytesOutBlock:
642                         val->v.counter64 =
643                             e->pfi.pfik_bytes[IPV6][OUT][BLOCK];
644                         break;
645                 case LEAF_pfInterfacesIf6PktsInPass:
646                         val->v.counter64 =
647                             e->pfi.pfik_packets[IPV6][IN][PASS];
648                         break;
649                 case LEAF_pfInterfacesIf6PktsInBlock:
650                         val->v.counter64 =
651                             e->pfi.pfik_packets[IPV6][IN][BLOCK];
652                         break;
653                 case LEAF_pfInterfacesIf6PktsOutPass:
654                         val->v.counter64 =
655                             e->pfi.pfik_packets[IPV6][OUT][PASS];
656                         break;
657                 case LEAF_pfInterfacesIf6PktsOutBlock:
658                         val->v.counter64 =
659                             e->pfi.pfik_packets[IPV6][OUT][BLOCK];
660                         break;
661
662                 default:
663                         return (SNMP_ERR_NOSUCHNAME);
664         }
665
666         return (SNMP_ERR_NOERROR);
667 }
668
669 int
670 pf_tables(struct snmp_context __unused *ctx, struct snmp_value *val,
671         u_int sub, u_int __unused vindex, enum snmp_op op)
672 {
673         asn_subid_t     which = val->var.subs[sub - 1];
674
675         if (op == SNMP_OP_SET)
676                 return (SNMP_ERR_NOT_WRITEABLE);
677
678         if (op == SNMP_OP_GET) {
679                 if ((time(NULL) - pft_table_age) > PFT_TABLE_MAXAGE)
680                         if (pft_refresh() == -1)
681                             return (SNMP_ERR_GENERR);
682
683                 switch (which) {
684                         case LEAF_pfTablesTblNumber:
685                                 val->v.uint32 = pft_table_count;
686                                 break;
687
688                         default:
689                                 return (SNMP_ERR_NOSUCHNAME);
690                 }
691
692                 return (SNMP_ERR_NOERROR);
693         }
694
695         abort();
696 }
697
698 int
699 pf_tbltable(struct snmp_context __unused *ctx, struct snmp_value *val,
700         u_int sub, u_int __unused vindex, enum snmp_op op)
701 {
702         asn_subid_t     which = val->var.subs[sub - 1];
703         struct pft_entry *e = NULL;
704
705         if ((time(NULL) - pft_table_age) > PFT_TABLE_MAXAGE)
706                 pft_refresh();
707
708         switch (op) {
709                 case SNMP_OP_SET:
710                         return (SNMP_ERR_NOT_WRITEABLE);
711                 case SNMP_OP_GETNEXT:
712                         if ((e = NEXT_OBJECT_INT(&pft_table,
713                             &val->var, sub)) == NULL)
714                                 return (SNMP_ERR_NOSUCHNAME);
715                         val->var.len = sub + 1;
716                         val->var.subs[sub] = e->index;
717                         break;
718                 case SNMP_OP_GET:
719                         if (val->var.len - sub != 1)
720                                 return (SNMP_ERR_NOSUCHNAME);
721                         if ((e = pft_table_find(val->var.subs[sub])) == NULL)
722                                 return (SNMP_ERR_NOSUCHNAME);
723                         break;
724
725                 case SNMP_OP_COMMIT:
726                 case SNMP_OP_ROLLBACK:
727                 default:
728                         abort();
729         }
730
731         switch (which) {
732                 case LEAF_pfTablesTblDescr:
733                         return (string_get(val, e->pft.pfrts_name, -1));
734                 case LEAF_pfTablesTblCount:
735                         val->v.integer = e->pft.pfrts_cnt;
736                         break;
737                 case LEAF_pfTablesTblTZero:
738                         val->v.uint32 =
739                             (time(NULL) - e->pft.pfrts_tzero) * 100;
740                         break;
741                 case LEAF_pfTablesTblRefsAnchor:
742                         val->v.integer =
743                             e->pft.pfrts_refcnt[PFR_REFCNT_ANCHOR];
744                         break;
745                 case LEAF_pfTablesTblRefsRule:
746                         val->v.integer =
747                             e->pft.pfrts_refcnt[PFR_REFCNT_RULE];
748                         break;
749                 case LEAF_pfTablesTblEvalMatch:
750                         val->v.counter64 = e->pft.pfrts_match;
751                         break;
752                 case LEAF_pfTablesTblEvalNoMatch:
753                         val->v.counter64 = e->pft.pfrts_nomatch;
754                         break;
755                 case LEAF_pfTablesTblBytesInPass:
756                         val->v.counter64 =
757                             e->pft.pfrts_bytes[PFR_DIR_IN][PFR_OP_PASS];
758                         break;
759                 case LEAF_pfTablesTblBytesInBlock:
760                         val->v.counter64 =
761                             e->pft.pfrts_bytes[PFR_DIR_IN][PFR_OP_BLOCK];
762                         break;
763                 case LEAF_pfTablesTblBytesInXPass:
764                         val->v.counter64 =
765                             e->pft.pfrts_bytes[PFR_DIR_IN][PFR_OP_XPASS];
766                         break;
767                 case LEAF_pfTablesTblBytesOutPass:
768                         val->v.counter64 =
769                             e->pft.pfrts_bytes[PFR_DIR_OUT][PFR_OP_PASS];
770                         break;
771                 case LEAF_pfTablesTblBytesOutBlock:
772                         val->v.counter64 =
773                             e->pft.pfrts_bytes[PFR_DIR_OUT][PFR_OP_BLOCK];
774                         break;
775                 case LEAF_pfTablesTblBytesOutXPass:
776                         val->v.counter64 =
777                             e->pft.pfrts_bytes[PFR_DIR_OUT][PFR_OP_XPASS];
778                         break;
779                 case LEAF_pfTablesTblPktsInPass:
780                         val->v.counter64 =
781                             e->pft.pfrts_packets[PFR_DIR_IN][PFR_OP_PASS];
782                         break;
783                 case LEAF_pfTablesTblPktsInBlock:
784                         val->v.counter64 =
785                             e->pft.pfrts_packets[PFR_DIR_IN][PFR_OP_BLOCK];
786                         break;
787                 case LEAF_pfTablesTblPktsInXPass:
788                         val->v.counter64 =
789                             e->pft.pfrts_packets[PFR_DIR_IN][PFR_OP_XPASS];
790                         break;
791                 case LEAF_pfTablesTblPktsOutPass:
792                         val->v.counter64 =
793                             e->pft.pfrts_packets[PFR_DIR_OUT][PFR_OP_PASS];
794                         break;
795                 case LEAF_pfTablesTblPktsOutBlock:
796                         val->v.counter64 =
797                             e->pft.pfrts_packets[PFR_DIR_OUT][PFR_OP_BLOCK];
798                         break;
799                 case LEAF_pfTablesTblPktsOutXPass:
800                         val->v.counter64 =
801                             e->pft.pfrts_packets[PFR_DIR_OUT][PFR_OP_XPASS];
802                         break;
803
804                 default:
805                         return (SNMP_ERR_NOSUCHNAME);
806         }
807
808         return (SNMP_ERR_NOERROR);
809 }
810
811 int
812 pf_tbladdr(struct snmp_context __unused *ctx, struct snmp_value __unused *val,
813         u_int __unused sub, u_int __unused vindex, enum snmp_op __unused op)
814 {
815         asn_subid_t     which = val->var.subs[sub - 1];
816         struct pfa_entry *e = NULL;
817
818         if ((time(NULL) - pfa_table_age) > PFA_TABLE_MAXAGE)
819                 pfa_refresh();
820
821         switch (op) {
822                 case SNMP_OP_SET:
823                         return (SNMP_ERR_NOT_WRITEABLE);
824                 case SNMP_OP_GETNEXT:
825                         if ((e = NEXT_OBJECT_INT(&pfa_table,
826                             &val->var, sub)) == NULL)
827                                 return (SNMP_ERR_NOSUCHNAME);
828                         val->var.len = sub + 1;
829                         val->var.subs[sub] = e->index;
830                         break;
831                 case SNMP_OP_GET:
832                         if (val->var.len - sub != 1)
833                                 return (SNMP_ERR_NOSUCHNAME);
834                         if ((e = pfa_table_find(val->var.subs[sub])) == NULL)
835                                 return (SNMP_ERR_NOSUCHNAME);
836                         break;
837
838                 case SNMP_OP_COMMIT:
839                 case SNMP_OP_ROLLBACK:
840                 default:
841                         abort();
842         }
843
844         switch (which) {
845                 case LEAF_pfTablesAddrNetType:
846                         if (e->pfas.pfras_a.pfra_af == AF_INET)
847                                 val->v.integer = pfTablesAddrNetType_ipv4;
848                         else if (e->pfas.pfras_a.pfra_af == AF_INET6)
849                                 val->v.integer = pfTablesAddrNetType_ipv6;
850                         else
851                                 return (SNMP_ERR_GENERR);
852                         break;
853                 case LEAF_pfTablesAddrNet:
854                         if (e->pfas.pfras_a.pfra_af == AF_INET) {
855                                 return (string_get(val,
856                                     (u_char *)&e->pfas.pfras_a.pfra_ip4addr, 4));
857                         } else if (e->pfas.pfras_a.pfra_af == AF_INET6)
858                                 return (string_get(val,
859                                     (u_char *)&e->pfas.pfras_a.pfra_ip6addr, 16));
860                         else
861                                 return (SNMP_ERR_GENERR);
862                         break;
863                 case LEAF_pfTablesAddrPrefix:
864                         val->v.integer = (int32_t) e->pfas.pfras_a.pfra_net;
865                         break;
866                 case LEAF_pfTablesAddrTZero:
867                         val->v.uint32 =
868                             (time(NULL) - e->pfas.pfras_tzero) * 100;
869                         break;
870                 case LEAF_pfTablesAddrBytesInPass:
871                         val->v.counter64 =
872                             e->pfas.pfras_bytes[PFR_DIR_IN][PFR_OP_PASS];
873                         break;
874                 case LEAF_pfTablesAddrBytesInBlock:
875                         val->v.counter64 =
876                             e->pfas.pfras_bytes[PFR_DIR_IN][PFR_OP_BLOCK];
877                         break;
878                 case LEAF_pfTablesAddrBytesOutPass:
879                         val->v.counter64 =
880                             e->pfas.pfras_bytes[PFR_DIR_OUT][PFR_OP_PASS];
881                         break;
882                 case LEAF_pfTablesAddrBytesOutBlock:
883                         val->v.counter64 =
884                             e->pfas.pfras_bytes[PFR_DIR_OUT][PFR_OP_BLOCK];
885                         break;
886                 case LEAF_pfTablesAddrPktsInPass:
887                         val->v.counter64 =
888                             e->pfas.pfras_packets[PFR_DIR_IN][PFR_OP_PASS];
889                         break;
890                 case LEAF_pfTablesAddrPktsInBlock:
891                         val->v.counter64 =
892                             e->pfas.pfras_packets[PFR_DIR_IN][PFR_OP_BLOCK];
893                         break;
894                 case LEAF_pfTablesAddrPktsOutPass:
895                         val->v.counter64 =
896                             e->pfas.pfras_packets[PFR_DIR_OUT][PFR_OP_PASS];
897                         break;
898                 case LEAF_pfTablesAddrPktsOutBlock:
899                         val->v.counter64 =
900                             e->pfas.pfras_packets[PFR_DIR_OUT][PFR_OP_BLOCK];
901                         break;
902                 default:
903                         return (SNMP_ERR_NOSUCHNAME);
904         }
905
906         return (SNMP_ERR_NOERROR);
907 }
908
909 int
910 pf_altq_num(struct snmp_context __unused *ctx, struct snmp_value *val,
911         u_int sub, u_int __unused vindex, enum snmp_op op)
912 {
913         asn_subid_t     which = val->var.subs[sub - 1];
914
915         if (!altq_enabled)
916            return (SNMP_ERR_NOSUCHNAME);
917
918         if (op == SNMP_OP_SET)
919                 return (SNMP_ERR_NOT_WRITEABLE);
920
921         if (op == SNMP_OP_GET) {
922                 if ((time(NULL) - pfq_table_age) > PFQ_TABLE_MAXAGE)
923                         if (pfq_refresh() == -1)
924                             return (SNMP_ERR_GENERR);
925
926                 switch (which) {
927                         case LEAF_pfAltqQueueNumber:
928                                 val->v.uint32 = pfq_table_count;
929                                 break;
930
931                         default:
932                                 return (SNMP_ERR_NOSUCHNAME);
933                 }
934
935                 return (SNMP_ERR_NOERROR);
936         }
937
938         abort();
939         return (SNMP_ERR_GENERR);
940 }
941
942 int
943 pf_altqq(struct snmp_context __unused *ctx, struct snmp_value *val,
944         u_int sub, u_int __unused vindex, enum snmp_op op)
945 {
946         asn_subid_t     which = val->var.subs[sub - 1];
947         struct pfq_entry *e = NULL;
948
949         if (!altq_enabled)
950            return (SNMP_ERR_NOSUCHNAME);
951
952         if ((time(NULL) - pfq_table_age) > PFQ_TABLE_MAXAGE)
953                 pfq_refresh();
954
955         switch (op) {
956                 case SNMP_OP_SET:
957                         return (SNMP_ERR_NOT_WRITEABLE);
958                 case SNMP_OP_GETNEXT:
959                         if ((e = NEXT_OBJECT_INT(&pfq_table,
960                             &val->var, sub)) == NULL)
961                                 return (SNMP_ERR_NOSUCHNAME);
962                         val->var.len = sub + 1;
963                         val->var.subs[sub] = e->index;
964                         break;
965                 case SNMP_OP_GET:
966                         if (val->var.len - sub != 1)
967                                 return (SNMP_ERR_NOSUCHNAME);
968                         if ((e = pfq_table_find(val->var.subs[sub])) == NULL)
969                                 return (SNMP_ERR_NOSUCHNAME);
970                         break;
971
972                 case SNMP_OP_COMMIT:
973                 case SNMP_OP_ROLLBACK:
974                 default:
975                         abort();
976         }
977
978         switch (which) {
979                 case LEAF_pfAltqQueueDescr:
980                         return (string_get(val, e->altq.qname, -1));
981                 case LEAF_pfAltqQueueParent:
982                         return (string_get(val, e->altq.parent, -1));
983                 case LEAF_pfAltqQueueScheduler:
984                         val->v.integer = e->altq.scheduler;
985                         break;
986                 case LEAF_pfAltqQueueBandwidth:
987                         val->v.uint32 = (e->altq.bandwidth > UINT_MAX) ?
988                             UINT_MAX : (u_int32_t)e->altq.bandwidth;
989                         break;
990                 case LEAF_pfAltqQueuePriority:
991                         val->v.integer = e->altq.priority;
992                         break;
993                 case LEAF_pfAltqQueueLimit:
994                         val->v.integer = e->altq.qlimit;
995                         break;
996
997                 default:
998                         return (SNMP_ERR_NOSUCHNAME);
999         }
1000
1001         return (SNMP_ERR_NOERROR);
1002 }
1003
1004 int
1005 pf_labels(struct snmp_context __unused *ctx, struct snmp_value *val,
1006         u_int sub, u_int __unused vindex, enum snmp_op op)
1007 {
1008         asn_subid_t     which = val->var.subs[sub - 1];
1009
1010         if (op == SNMP_OP_SET)
1011                 return (SNMP_ERR_NOT_WRITEABLE);
1012
1013         if (op == SNMP_OP_GET) {
1014                 if ((time(NULL) - pfl_table_age) > PFL_TABLE_MAXAGE)
1015                         if (pfl_refresh() == -1)
1016                                 return (SNMP_ERR_GENERR);
1017
1018                 switch (which) {
1019                         case LEAF_pfLabelsLblNumber:
1020                                 val->v.uint32 = pfl_table_count;
1021                                 break;
1022
1023                         default:
1024                                 return (SNMP_ERR_NOSUCHNAME);
1025                 }
1026
1027                 return (SNMP_ERR_NOERROR);
1028         }
1029
1030         abort();
1031         return (SNMP_ERR_GENERR);
1032 }
1033
1034 int
1035 pf_lbltable(struct snmp_context __unused *ctx, struct snmp_value *val,
1036         u_int sub, u_int __unused vindex, enum snmp_op op)
1037 {
1038         asn_subid_t     which = val->var.subs[sub - 1];
1039         struct pfl_entry *e = NULL;
1040
1041         if ((time(NULL) - pfl_table_age) > PFL_TABLE_MAXAGE)
1042                 pfl_refresh();
1043
1044         switch (op) {
1045                 case SNMP_OP_SET:
1046                         return (SNMP_ERR_NOT_WRITEABLE);
1047                 case SNMP_OP_GETNEXT:
1048                         if ((e = NEXT_OBJECT_INT(&pfl_table,
1049                             &val->var, sub)) == NULL)
1050                                 return (SNMP_ERR_NOSUCHNAME);
1051                         val->var.len = sub + 1;
1052                         val->var.subs[sub] = e->index;
1053                         break;
1054                 case SNMP_OP_GET:
1055                         if (val->var.len - sub != 1)
1056                                 return (SNMP_ERR_NOSUCHNAME);
1057                         if ((e = pfl_table_find(val->var.subs[sub])) == NULL)
1058                                 return (SNMP_ERR_NOSUCHNAME);
1059                         break;
1060
1061                 case SNMP_OP_COMMIT:
1062                 case SNMP_OP_ROLLBACK:
1063                 default:
1064                         abort();
1065         }
1066
1067         switch (which) {
1068                 case LEAF_pfLabelsLblName:
1069                         return (string_get(val, e->name, -1));
1070                 case LEAF_pfLabelsLblEvals:
1071                         val->v.counter64 = e->evals;
1072                         break;
1073                 case LEAF_pfLabelsLblBytesIn:
1074                         val->v.counter64 = e->bytes[IN];
1075                         break;
1076                 case LEAF_pfLabelsLblBytesOut:
1077                         val->v.counter64 = e->bytes[OUT];
1078                         break;
1079                 case LEAF_pfLabelsLblPktsIn:
1080                         val->v.counter64 = e->pkts[IN];
1081                         break;
1082                 case LEAF_pfLabelsLblPktsOut:
1083                         val->v.counter64 = e->pkts[OUT];
1084                         break;
1085                 default:
1086                         return (SNMP_ERR_NOSUCHNAME);
1087         }
1088
1089         return (SNMP_ERR_NOERROR);
1090 }
1091
1092 static struct pfi_entry *
1093 pfi_table_find(u_int idx)
1094 {
1095         struct pfi_entry *e;
1096
1097         TAILQ_FOREACH(e, &pfi_table, link)
1098                 if (e->index == idx)
1099                         return (e);
1100         return (NULL);
1101 }
1102
1103 static struct pfq_entry *
1104 pfq_table_find(u_int idx)
1105 {
1106         struct pfq_entry *e;
1107
1108         TAILQ_FOREACH(e, &pfq_table, link)
1109                 if (e->index == idx)
1110                         return (e);
1111         return (NULL);
1112 }
1113
1114 static struct pft_entry *
1115 pft_table_find(u_int idx)
1116 {
1117         struct pft_entry *e;
1118
1119         TAILQ_FOREACH(e, &pft_table, link)
1120                 if (e->index == idx)
1121                         return (e);
1122         return (NULL);
1123 }
1124
1125 static struct pfa_entry *
1126 pfa_table_find(u_int idx)
1127 {
1128         struct pfa_entry *e;
1129
1130         TAILQ_FOREACH(e, &pfa_table, link)
1131                 if (e->index == idx)
1132                         return (e);
1133         return (NULL);
1134 }
1135
1136 static struct pfl_entry *
1137 pfl_table_find(u_int idx)
1138 {
1139         struct pfl_entry *e;
1140
1141         TAILQ_FOREACH(e, &pfl_table, link)
1142                 if (e->index == idx)
1143                         return (e);
1144
1145         return (NULL);
1146 }
1147
1148 static int
1149 pfi_refresh(void)
1150 {
1151         struct pfioc_iface io;
1152         struct pfi_kif *p = NULL;
1153         struct pfi_entry *e;
1154         int i, numifs = 1;
1155
1156         if (started && this_tick <= pf_tick)
1157                 return (0);
1158
1159         while (!TAILQ_EMPTY(&pfi_table)) {
1160                 e = TAILQ_FIRST(&pfi_table);
1161                 TAILQ_REMOVE(&pfi_table, e, link);
1162                 free(e);
1163         }
1164
1165         bzero(&io, sizeof(io));
1166         io.pfiio_esize = sizeof(struct pfi_kif);
1167
1168         for (;;) {
1169                 p = reallocf(p, numifs * sizeof(struct pfi_kif));
1170                 if (p == NULL) {
1171                         syslog(LOG_ERR, "pfi_refresh(): reallocf() numifs=%d: %s",
1172                             numifs, strerror(errno));
1173                         goto err2;
1174                 }
1175                 io.pfiio_size = numifs;
1176                 io.pfiio_buffer = p;
1177
1178                 if (ioctl(dev, DIOCIGETIFACES, &io)) {
1179                         syslog(LOG_ERR, "pfi_refresh(): ioctl(): %s",
1180                             strerror(errno));
1181                         goto err2;
1182                 }
1183
1184                 if (numifs >= io.pfiio_size)
1185                         break;
1186
1187                 numifs = io.pfiio_size;
1188         }
1189
1190         for (i = 0; i < numifs; i++) {
1191                 e = malloc(sizeof(struct pfi_entry));
1192                 if (e == NULL)
1193                         goto err1;
1194                 e->index = i + 1;
1195                 memcpy(&e->pfi, p+i, sizeof(struct pfi_kif));
1196                 TAILQ_INSERT_TAIL(&pfi_table, e, link);
1197         }
1198
1199         pfi_table_age = time(NULL);
1200         pfi_table_count = numifs;
1201         pf_tick = this_tick;
1202
1203         free(p);
1204         return (0);
1205
1206 err1:
1207         while (!TAILQ_EMPTY(&pfi_table)) {
1208                 e = TAILQ_FIRST(&pfi_table);
1209                 TAILQ_REMOVE(&pfi_table, e, link);
1210                 free(e);
1211         }
1212 err2:
1213         free(p);
1214         return(-1);
1215 }
1216
1217 static int
1218 pfq_refresh(void)
1219 {
1220         struct pfioc_altq pa;
1221         struct pfq_entry *e;
1222         int i, numqs, ticket;
1223
1224         if (started && this_tick <= pf_tick)
1225                 return (0);
1226
1227         while (!TAILQ_EMPTY(&pfq_table)) {
1228                 e = TAILQ_FIRST(&pfq_table);
1229                 TAILQ_REMOVE(&pfq_table, e, link);
1230                 free(e);
1231         }
1232
1233         bzero(&pa, sizeof(pa));
1234         pa.version = PFIOC_ALTQ_VERSION;
1235         if (ioctl(dev, DIOCGETALTQS, &pa)) {
1236                 syslog(LOG_ERR, "pfq_refresh: ioctl(DIOCGETALTQS): %s",
1237                     strerror(errno));
1238                 return (-1);
1239         }
1240
1241         numqs = pa.nr;
1242         ticket = pa.ticket;
1243
1244         for (i = 0; i < numqs; i++) {
1245                 e = malloc(sizeof(struct pfq_entry));
1246                 if (e == NULL) {
1247                         syslog(LOG_ERR, "pfq_refresh(): "
1248                             "malloc(): %s",
1249                             strerror(errno));
1250                         goto err;
1251                 }
1252                 pa.ticket = ticket;
1253                 pa.nr = i;
1254
1255                 if (ioctl(dev, DIOCGETALTQ, &pa)) {
1256                         syslog(LOG_ERR, "pfq_refresh(): "
1257                             "ioctl(DIOCGETALTQ): %s",
1258                             strerror(errno));
1259                         goto err;
1260                 }
1261
1262                 if (pa.altq.qid > 0) {
1263                         memcpy(&e->altq, &pa.altq, sizeof(struct pf_altq));
1264                         e->index = pa.altq.qid;
1265                         pfq_table_count = i;
1266                         INSERT_OBJECT_INT_LINK_INDEX(e, &pfq_table, link, index);
1267                 }
1268         }
1269
1270         pfq_table_age = time(NULL);
1271         pf_tick = this_tick;
1272
1273         return (0);
1274 err:
1275         free(e);
1276         while (!TAILQ_EMPTY(&pfq_table)) {
1277                 e = TAILQ_FIRST(&pfq_table);
1278                 TAILQ_REMOVE(&pfq_table, e, link);
1279                 free(e);
1280         }
1281         return(-1);
1282 }
1283
1284 static int
1285 pfs_refresh(void)
1286 {
1287         if (started && this_tick <= pf_tick)
1288                 return (0);
1289
1290         bzero(&pfs, sizeof(struct pf_status));
1291
1292         if (ioctl(dev, DIOCGETSTATUS, &pfs)) {
1293                 syslog(LOG_ERR, "pfs_refresh(): ioctl(): %s",
1294                     strerror(errno));
1295                 return (-1);
1296         }
1297
1298         pf_tick = this_tick;
1299         return (0);
1300 }
1301
1302 static int
1303 pft_refresh(void)
1304 {
1305         struct pfioc_table io;
1306         struct pfr_tstats *t = NULL;
1307         struct pft_entry *e;
1308         int i, numtbls = 1;
1309
1310         if (started && this_tick <= pf_tick)
1311                 return (0);
1312
1313         while (!TAILQ_EMPTY(&pft_table)) {
1314                 e = TAILQ_FIRST(&pft_table);
1315                 TAILQ_REMOVE(&pft_table, e, link);
1316                 free(e);
1317         }
1318
1319         bzero(&io, sizeof(io));
1320         io.pfrio_esize = sizeof(struct pfr_tstats);
1321
1322         for (;;) {
1323                 t = reallocf(t, numtbls * sizeof(struct pfr_tstats));
1324                 if (t == NULL) {
1325                         syslog(LOG_ERR, "pft_refresh(): reallocf() numtbls=%d: %s",
1326                             numtbls, strerror(errno));
1327                         goto err2;
1328                 }
1329                 io.pfrio_size = numtbls;
1330                 io.pfrio_buffer = t;
1331
1332                 if (ioctl(dev, DIOCRGETTSTATS, &io)) {
1333                         syslog(LOG_ERR, "pft_refresh(): ioctl(): %s",
1334                             strerror(errno));
1335                         goto err2;
1336                 }
1337
1338                 if (numtbls >= io.pfrio_size)
1339                         break;
1340
1341                 numtbls = io.pfrio_size;
1342         }
1343
1344         for (i = 0; i < numtbls; i++) {
1345                 e = malloc(sizeof(struct pft_entry));
1346                 if (e == NULL)
1347                         goto err1;
1348                 e->index = i + 1;
1349                 memcpy(&e->pft, t+i, sizeof(struct pfr_tstats));
1350                 TAILQ_INSERT_TAIL(&pft_table, e, link);
1351         }
1352
1353         pft_table_age = time(NULL);
1354         pft_table_count = numtbls;
1355         pf_tick = this_tick;
1356
1357         free(t);
1358         return (0);
1359 err1:
1360         while (!TAILQ_EMPTY(&pft_table)) {
1361                 e = TAILQ_FIRST(&pft_table);
1362                 TAILQ_REMOVE(&pft_table, e, link);
1363                 free(e);
1364         }
1365 err2:
1366         free(t);
1367         return(-1);
1368 }
1369
1370 static int
1371 pfa_table_addrs(u_int sidx, struct pfr_table *pt)
1372 {
1373         struct pfioc_table io;
1374         struct pfr_astats *t = NULL;
1375         struct pfa_entry *e;
1376         int i, numaddrs = 1;
1377
1378         if (pt == NULL)
1379                 return (-1);
1380
1381         memset(&io, 0, sizeof(io));
1382         strlcpy(io.pfrio_table.pfrt_name, pt->pfrt_name,
1383             sizeof(io.pfrio_table.pfrt_name));
1384
1385         for (;;) {
1386                 t = reallocf(t, numaddrs * sizeof(struct pfr_astats));
1387                 if (t == NULL) {
1388                         syslog(LOG_ERR, "pfa_table_addrs(): reallocf(): %s",
1389                             strerror(errno));
1390                         numaddrs = -1;
1391                         goto error;
1392                 }
1393
1394                 memset(t, 0, sizeof(*t));
1395                 io.pfrio_size = numaddrs;
1396                 io.pfrio_buffer = t;
1397                 io.pfrio_esize = sizeof(struct pfr_astats);
1398
1399                 if (ioctl(dev, DIOCRGETASTATS, &io)) {
1400                         syslog(LOG_ERR, "pfa_table_addrs(): ioctl() on %s: %s",
1401                             pt->pfrt_name, strerror(errno));
1402                         numaddrs = -1;
1403                         break;
1404                 }
1405
1406                 if (numaddrs >= io.pfrio_size)
1407                         break;
1408
1409                 numaddrs = io.pfrio_size;
1410         }
1411
1412         for (i = 0; i < numaddrs; i++) {
1413                 if ((t + i)->pfras_a.pfra_af != AF_INET &&
1414                     (t + i)->pfras_a.pfra_af != AF_INET6) {
1415                         numaddrs = i;
1416                         break;
1417                 }
1418
1419                 e = (struct pfa_entry *)malloc(sizeof(struct pfa_entry));
1420                 if (e == NULL) {
1421                         syslog(LOG_ERR, "pfa_table_addrs(): malloc(): %s",
1422                             strerror(errno));
1423                         numaddrs = -1;
1424                         break;
1425                 }
1426                 e->index = sidx + i;
1427                 memcpy(&e->pfas, t + i, sizeof(struct pfr_astats));
1428                 TAILQ_INSERT_TAIL(&pfa_table, e, link);
1429         }
1430
1431         free(t);
1432 error:
1433         return (numaddrs);
1434 }
1435
1436 static int
1437 pfa_refresh(void)
1438 {
1439         struct pfioc_table io;
1440         struct pfr_table *pt = NULL, *it = NULL;
1441         struct pfa_entry *e;
1442         int i, numtbls = 1, cidx, naddrs;
1443
1444         if (started && this_tick <= pf_tick)
1445                 return (0);
1446
1447         while (!TAILQ_EMPTY(&pfa_table)) {
1448                 e = TAILQ_FIRST(&pfa_table);
1449                 TAILQ_REMOVE(&pfa_table, e, link);
1450                 free(e);
1451         }
1452
1453         memset(&io, 0, sizeof(io));
1454         io.pfrio_esize = sizeof(struct pfr_table);
1455
1456         for (;;) {
1457                 pt = reallocf(pt, numtbls * sizeof(struct pfr_table));
1458                 if (pt == NULL) {
1459                         syslog(LOG_ERR, "pfa_refresh(): reallocf() %s",
1460                             strerror(errno));
1461                         return (-1);
1462                 }
1463                 memset(pt, 0, sizeof(*pt));
1464                 io.pfrio_size = numtbls;
1465                 io.pfrio_buffer = pt;
1466
1467                 if (ioctl(dev, DIOCRGETTABLES, &io)) {
1468                         syslog(LOG_ERR, "pfa_refresh(): ioctl(): %s",
1469                             strerror(errno));
1470                         goto err2;
1471                 }
1472
1473                 if (numtbls >= io.pfrio_size)
1474                         break;
1475
1476                 numtbls = io.pfrio_size;
1477         }
1478
1479         cidx = 1;
1480
1481         for (it = pt, i = 0; i < numtbls; it++, i++) {
1482                 /*
1483                  * Skip the table if not active - ioctl(DIOCRGETASTATS) will
1484                  * return ESRCH for this entry anyway.
1485                  */
1486                 if (!(it->pfrt_flags & PFR_TFLAG_ACTIVE))
1487                         continue;
1488
1489                 if ((naddrs = pfa_table_addrs(cidx, it)) < 0)
1490                         goto err1;
1491
1492                 cidx += naddrs;
1493         }
1494
1495         pfa_table_age = time(NULL);
1496         pfa_table_count = cidx;
1497         pf_tick = this_tick;
1498
1499         free(pt);
1500         return (0);
1501 err1:
1502         while (!TAILQ_EMPTY(&pfa_table)) {
1503                 e = TAILQ_FIRST(&pfa_table);
1504                 TAILQ_REMOVE(&pfa_table, e, link);
1505                 free(e);
1506         }
1507
1508 err2:
1509         free(pt);
1510         return (-1);
1511 }
1512
1513 static int
1514 pfl_scan_ruleset(const char *path)
1515 {
1516         struct pfioc_rule pr;
1517         struct pfl_entry *e;
1518         u_int32_t nr, i;
1519
1520         bzero(&pr, sizeof(pr));
1521         strlcpy(pr.anchor, path, sizeof(pr.anchor));
1522         pr.rule.action = PF_PASS;
1523         if (ioctl(dev, DIOCGETRULES, &pr)) {
1524                 syslog(LOG_ERR, "pfl_scan_ruleset: ioctl(DIOCGETRULES): %s",
1525                     strerror(errno));
1526                 goto err;
1527         }
1528
1529         for (nr = pr.nr, i = 0; i < nr; i++) {
1530                 pr.nr = i;
1531                 if (ioctl(dev, DIOCGETRULE, &pr)) {
1532                         syslog(LOG_ERR, "pfl_scan_ruleset: ioctl(DIOCGETRULE):"
1533                             " %s", strerror(errno));
1534                         goto err;
1535                 }
1536
1537                 if (pr.rule.label[0]) {
1538                         e = (struct pfl_entry *)malloc(sizeof(*e));
1539                         if (e == NULL)
1540                                 goto err;
1541
1542                         strlcpy(e->name, path, sizeof(e->name));
1543                         if (path[0])
1544                                 strlcat(e->name, "/", sizeof(e->name));
1545                         strlcat(e->name, pr.rule.label, sizeof(e->name));
1546
1547                         e->evals = pr.rule.evaluations;
1548                         e->bytes[IN] = pr.rule.bytes[IN];
1549                         e->bytes[OUT] = pr.rule.bytes[OUT];
1550                         e->pkts[IN] = pr.rule.packets[IN];
1551                         e->pkts[OUT] = pr.rule.packets[OUT];
1552                         e->index = ++pfl_table_count;
1553
1554                         TAILQ_INSERT_TAIL(&pfl_table, e, link);
1555                 }
1556         }
1557
1558         return (0);
1559
1560 err:
1561         return (-1);
1562 }
1563
1564 static int
1565 pfl_walk_rulesets(const char *path)
1566 {
1567         struct pfioc_ruleset prs;
1568         char newpath[MAXPATHLEN];
1569         u_int32_t nr, i;
1570
1571         if (pfl_scan_ruleset(path))
1572                 goto err;
1573
1574         bzero(&prs, sizeof(prs));
1575         strlcpy(prs.path, path, sizeof(prs.path));
1576         if (ioctl(dev, DIOCGETRULESETS, &prs)) {
1577                 syslog(LOG_ERR, "pfl_walk_rulesets: ioctl(DIOCGETRULESETS): %s",
1578                     strerror(errno));
1579                 goto err;
1580         }
1581
1582         for (nr = prs.nr, i = 0; i < nr; i++) {
1583                 prs.nr = i;
1584                 if (ioctl(dev, DIOCGETRULESET, &prs)) {
1585                         syslog(LOG_ERR, "pfl_walk_rulesets: ioctl(DIOCGETRULESET):"
1586                             " %s", strerror(errno));
1587                         goto err;
1588                 }
1589
1590                 if (strcmp(prs.name, PF_RESERVED_ANCHOR) == 0)
1591                         continue;
1592
1593                 strlcpy(newpath, path, sizeof(newpath));
1594                 if (path[0])
1595                         strlcat(newpath, "/", sizeof(newpath));
1596
1597                 strlcat(newpath, prs.name, sizeof(newpath));
1598                 if (pfl_walk_rulesets(newpath))
1599                         goto err;
1600         }
1601
1602         return (0);
1603
1604 err:
1605         return (-1);
1606 }
1607
1608 static int
1609 pfl_refresh(void)
1610 {
1611         struct pfl_entry *e;
1612
1613         if (started && this_tick <= pf_tick)
1614                 return (0);
1615
1616         while (!TAILQ_EMPTY(&pfl_table)) {
1617                 e = TAILQ_FIRST(&pfl_table);
1618                 TAILQ_REMOVE(&pfl_table, e, link);
1619                 free(e);
1620         }
1621         pfl_table_count = 0;
1622
1623         if (pfl_walk_rulesets(""))
1624                 goto err;
1625
1626         pfl_table_age = time(NULL);
1627         pf_tick = this_tick;
1628
1629         return (0);
1630
1631 err:
1632         while (!TAILQ_EMPTY(&pfl_table)) {
1633                 e = TAILQ_FIRST(&pfl_table);
1634                 TAILQ_REMOVE(&pfl_table, e, link);
1635                 free(e);
1636         }
1637         pfl_table_count = 0;
1638
1639         return (-1);
1640 }
1641
1642 /*
1643  * check whether altq support is enabled in kernel
1644  */
1645
1646 static int
1647 altq_is_enabled(int pfdev)
1648 {
1649         struct pfioc_altq pa;
1650
1651         errno = 0;
1652         pa.version = PFIOC_ALTQ_VERSION;
1653         if (ioctl(pfdev, DIOCGETALTQS, &pa)) {
1654                 if (errno == ENODEV) {
1655                         syslog(LOG_INFO, "No ALTQ support in kernel\n"
1656                             "ALTQ related functions disabled\n");
1657                         return (0);
1658                 } else
1659                         syslog(LOG_ERR, "DIOCGETALTQS returned an error: %s",
1660                             strerror(errno));
1661                         return (-1);
1662         }
1663         return (1);
1664 }
1665
1666 /*
1667  * Implement the bsnmpd module interface
1668  */
1669 static int
1670 pf_init(struct lmodule *mod, int __unused argc, char __unused *argv[])
1671 {
1672         module = mod;
1673
1674         if ((dev = open("/dev/pf", O_RDONLY)) == -1) {
1675                 syslog(LOG_ERR, "pf_init(): open(): %s\n",
1676                     strerror(errno));
1677                 return (-1);
1678         }
1679
1680         if ((altq_enabled = altq_is_enabled(dev)) == -1) {
1681                 syslog(LOG_ERR, "pf_init(): altq test failed");
1682                 return (-1);
1683         }
1684
1685         /* Prepare internal state */
1686         TAILQ_INIT(&pfi_table);
1687         TAILQ_INIT(&pfq_table);
1688         TAILQ_INIT(&pft_table);
1689         TAILQ_INIT(&pfa_table);
1690         TAILQ_INIT(&pfl_table);
1691
1692         pfi_refresh();
1693         if (altq_enabled) {
1694                 pfq_refresh();
1695         }
1696
1697         pfs_refresh();
1698         pft_refresh();
1699         pfa_refresh();
1700         pfl_refresh();
1701
1702         started = 1;
1703
1704         return (0);
1705 }
1706
1707 static int
1708 pf_fini(void)
1709 {
1710         struct pfi_entry *i1, *i2;
1711         struct pfq_entry *q1, *q2;
1712         struct pft_entry *t1, *t2;
1713         struct pfa_entry *a1, *a2;
1714         struct pfl_entry *l1, *l2;
1715
1716         /* Empty the list of interfaces */
1717         i1 = TAILQ_FIRST(&pfi_table);
1718         while (i1 != NULL) {
1719                 i2 = TAILQ_NEXT(i1, link);
1720                 free(i1);
1721                 i1 = i2;
1722         }
1723
1724         /* List of queues */
1725         q1 = TAILQ_FIRST(&pfq_table);
1726         while (q1 != NULL) {
1727                 q2 = TAILQ_NEXT(q1, link);
1728                 free(q1);
1729                 q1 = q2;
1730         }
1731
1732         /* List of tables */
1733         t1 = TAILQ_FIRST(&pft_table);
1734         while (t1 != NULL) {
1735                 t2 = TAILQ_NEXT(t1, link);
1736                 free(t1);
1737                 t1 = t2;
1738         }
1739
1740         /* List of table addresses */
1741         a1 = TAILQ_FIRST(&pfa_table);
1742         while (a1 != NULL) {
1743                 a2 = TAILQ_NEXT(a1, link);
1744                 free(a1);
1745                 a1 = a2;
1746         }
1747
1748         /* And the list of labeled filter rules */
1749         l1 = TAILQ_FIRST(&pfl_table);
1750         while (l1 != NULL) {
1751                 l2 = TAILQ_NEXT(l1, link);
1752                 free(l1);
1753                 l1 = l2;
1754         }
1755
1756         close(dev);
1757         return (0);
1758 }
1759
1760 static void
1761 pf_dump(void)
1762 {
1763         pfi_refresh();
1764         if (altq_enabled) {
1765                 pfq_refresh();
1766         }
1767         pft_refresh();
1768         pfa_refresh();
1769         pfl_refresh();
1770
1771         syslog(LOG_ERR, "Dump: pfi_table_age = %jd",
1772             (intmax_t)pfi_table_age);
1773         syslog(LOG_ERR, "Dump: pfi_table_count = %d",
1774             pfi_table_count);
1775
1776         syslog(LOG_ERR, "Dump: pfq_table_age = %jd",
1777             (intmax_t)pfq_table_age);
1778         syslog(LOG_ERR, "Dump: pfq_table_count = %d",
1779             pfq_table_count);
1780
1781         syslog(LOG_ERR, "Dump: pft_table_age = %jd",
1782             (intmax_t)pft_table_age);
1783         syslog(LOG_ERR, "Dump: pft_table_count = %d",
1784             pft_table_count);
1785
1786         syslog(LOG_ERR, "Dump: pfa_table_age = %jd",
1787             (intmax_t)pfa_table_age);
1788         syslog(LOG_ERR, "Dump: pfa_table_count = %d",
1789             pfa_table_count);
1790
1791         syslog(LOG_ERR, "Dump: pfl_table_age = %jd",
1792             (intmax_t)pfl_table_age);
1793         syslog(LOG_ERR, "Dump: pfl_table_count = %d",
1794             pfl_table_count);
1795 }
1796
1797 const struct snmp_module config = {
1798         .comment = "This module implements a MIB for the pf packet filter.",
1799         .init =         pf_init,
1800         .fini =         pf_fini,
1801         .tree =         pf_ctree,
1802         .dump =         pf_dump,
1803         .tree_size =    pf_CTREE_SIZE,
1804 };