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