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