]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - usr.sbin/bsnmpd/modules/snmp_pf/pf_snmp.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.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_pfInterfacesIfRefsState:
590                         val->v.uint32 = e->pfi.pfik_states;
591                         break;
592                 case LEAF_pfInterfacesIfRefsRule:
593                         val->v.uint32 = e->pfi.pfik_rules;
594                         break;
595                 case LEAF_pfInterfacesIf4BytesInPass:
596                         val->v.counter64 =
597                             e->pfi.pfik_bytes[IPV4][IN][PASS];
598                         break;
599                 case LEAF_pfInterfacesIf4BytesInBlock:
600                         val->v.counter64 =
601                             e->pfi.pfik_bytes[IPV4][IN][BLOCK];
602                         break;
603                 case LEAF_pfInterfacesIf4BytesOutPass:
604                         val->v.counter64 =
605                             e->pfi.pfik_bytes[IPV4][OUT][PASS];
606                         break;
607                 case LEAF_pfInterfacesIf4BytesOutBlock:
608                         val->v.counter64 =
609                             e->pfi.pfik_bytes[IPV4][OUT][BLOCK];
610                         break;
611                 case LEAF_pfInterfacesIf4PktsInPass:
612                         val->v.counter64 =
613                             e->pfi.pfik_packets[IPV4][IN][PASS];
614                         break;
615                 case LEAF_pfInterfacesIf4PktsInBlock:
616                         val->v.counter64 =
617                             e->pfi.pfik_packets[IPV4][IN][BLOCK];
618                         break;
619                 case LEAF_pfInterfacesIf4PktsOutPass:
620                         val->v.counter64 =
621                             e->pfi.pfik_packets[IPV4][OUT][PASS];
622                         break;
623                 case LEAF_pfInterfacesIf4PktsOutBlock:
624                         val->v.counter64 =
625                             e->pfi.pfik_packets[IPV4][OUT][BLOCK];
626                         break;
627                 case LEAF_pfInterfacesIf6BytesInPass:
628                         val->v.counter64 =
629                             e->pfi.pfik_bytes[IPV6][IN][PASS];
630                         break;
631                 case LEAF_pfInterfacesIf6BytesInBlock:
632                         val->v.counter64 =
633                             e->pfi.pfik_bytes[IPV6][IN][BLOCK];
634                         break;
635                 case LEAF_pfInterfacesIf6BytesOutPass:
636                         val->v.counter64 =
637                             e->pfi.pfik_bytes[IPV6][OUT][PASS];
638                         break;
639                 case LEAF_pfInterfacesIf6BytesOutBlock:
640                         val->v.counter64 =
641                             e->pfi.pfik_bytes[IPV6][OUT][BLOCK];
642                         break;
643                 case LEAF_pfInterfacesIf6PktsInPass:
644                         val->v.counter64 =
645                             e->pfi.pfik_packets[IPV6][IN][PASS];
646                         break;
647                 case LEAF_pfInterfacesIf6PktsInBlock:
648                         val->v.counter64 =
649                             e->pfi.pfik_packets[IPV6][IN][BLOCK];
650                         break;
651                 case LEAF_pfInterfacesIf6PktsOutPass:
652                         val->v.counter64 =
653                             e->pfi.pfik_packets[IPV6][OUT][PASS];
654                         break;
655                 case LEAF_pfInterfacesIf6PktsOutBlock:
656                         val->v.counter64 = 
657                             e->pfi.pfik_packets[IPV6][OUT][BLOCK];
658                         break;
659
660                 default:
661                         return (SNMP_ERR_NOSUCHNAME);
662         }
663
664         return (SNMP_ERR_NOERROR);
665 }
666
667 int
668 pf_tables(struct snmp_context __unused *ctx, struct snmp_value *val,
669         u_int sub, u_int __unused vindex, enum snmp_op op)
670 {
671         asn_subid_t     which = val->var.subs[sub - 1];
672
673         if (op == SNMP_OP_SET)
674                 return (SNMP_ERR_NOT_WRITEABLE);
675
676         if (op == SNMP_OP_GET) {
677                 if ((time(NULL) - pft_table_age) > PFT_TABLE_MAXAGE)
678                         if (pft_refresh() == -1)
679                             return (SNMP_ERR_GENERR);
680
681                 switch (which) {
682                         case LEAF_pfTablesTblNumber:
683                                 val->v.uint32 = pft_table_count;
684                                 break;
685
686                         default:
687                                 return (SNMP_ERR_NOSUCHNAME);
688                 }
689
690                 return (SNMP_ERR_NOERROR);
691         }
692
693         abort();
694 }
695
696 int
697 pf_tbltable(struct snmp_context __unused *ctx, struct snmp_value *val,
698         u_int sub, u_int __unused vindex, enum snmp_op op)
699 {
700         asn_subid_t     which = val->var.subs[sub - 1];
701         struct pft_entry *e = NULL;
702
703         if ((time(NULL) - pft_table_age) > PFT_TABLE_MAXAGE)
704                 pft_refresh();
705
706         switch (op) {
707                 case SNMP_OP_SET:
708                         return (SNMP_ERR_NOT_WRITEABLE);
709                 case SNMP_OP_GETNEXT:
710                         if ((e = NEXT_OBJECT_INT(&pft_table,
711                             &val->var, sub)) == NULL)
712                                 return (SNMP_ERR_NOSUCHNAME);
713                         val->var.len = sub + 1;
714                         val->var.subs[sub] = e->index;
715                         break;
716                 case SNMP_OP_GET:
717                         if (val->var.len - sub != 1)
718                                 return (SNMP_ERR_NOSUCHNAME);
719                         if ((e = pft_table_find(val->var.subs[sub])) == NULL)
720                                 return (SNMP_ERR_NOSUCHNAME);
721                         break;
722
723                 case SNMP_OP_COMMIT:
724                 case SNMP_OP_ROLLBACK:
725                 default:
726                         abort();
727         }
728
729         switch (which) {
730                 case LEAF_pfTablesTblDescr:
731                         return (string_get(val, e->pft.pfrts_name, -1));
732                 case LEAF_pfTablesTblCount:
733                         val->v.integer = e->pft.pfrts_cnt;
734                         break;
735                 case LEAF_pfTablesTblTZero:
736                         val->v.uint32 =
737                             (time(NULL) - e->pft.pfrts_tzero) * 100;
738                         break;
739                 case LEAF_pfTablesTblRefsAnchor:
740                         val->v.integer =
741                             e->pft.pfrts_refcnt[PFR_REFCNT_ANCHOR];
742                         break;
743                 case LEAF_pfTablesTblRefsRule:
744                         val->v.integer =
745                             e->pft.pfrts_refcnt[PFR_REFCNT_RULE];
746                         break;
747                 case LEAF_pfTablesTblEvalMatch:
748                         val->v.counter64 = e->pft.pfrts_match;
749                         break;
750                 case LEAF_pfTablesTblEvalNoMatch:
751                         val->v.counter64 = e->pft.pfrts_nomatch;
752                         break;
753                 case LEAF_pfTablesTblBytesInPass:
754                         val->v.counter64 =
755                             e->pft.pfrts_bytes[PFR_DIR_IN][PFR_OP_PASS];
756                         break;
757                 case LEAF_pfTablesTblBytesInBlock:
758                         val->v.counter64 =
759                             e->pft.pfrts_bytes[PFR_DIR_IN][PFR_OP_BLOCK];
760                         break;
761                 case LEAF_pfTablesTblBytesInXPass:
762                         val->v.counter64 =
763                             e->pft.pfrts_bytes[PFR_DIR_IN][PFR_OP_XPASS];
764                         break;
765                 case LEAF_pfTablesTblBytesOutPass:
766                         val->v.counter64 =
767                             e->pft.pfrts_bytes[PFR_DIR_OUT][PFR_OP_PASS];
768                         break;
769                 case LEAF_pfTablesTblBytesOutBlock:
770                         val->v.counter64 =
771                             e->pft.pfrts_bytes[PFR_DIR_OUT][PFR_OP_BLOCK];
772                         break;
773                 case LEAF_pfTablesTblBytesOutXPass:
774                         val->v.counter64 =
775                             e->pft.pfrts_bytes[PFR_DIR_OUT][PFR_OP_XPASS];
776                         break;
777                 case LEAF_pfTablesTblPktsInPass:
778                         val->v.counter64 =
779                             e->pft.pfrts_packets[PFR_DIR_IN][PFR_OP_PASS];
780                         break;
781                 case LEAF_pfTablesTblPktsInBlock:
782                         val->v.counter64 =
783                             e->pft.pfrts_packets[PFR_DIR_IN][PFR_OP_BLOCK];
784                         break;
785                 case LEAF_pfTablesTblPktsInXPass:
786                         val->v.counter64 =
787                             e->pft.pfrts_packets[PFR_DIR_IN][PFR_OP_XPASS];
788                         break;
789                 case LEAF_pfTablesTblPktsOutPass:
790                         val->v.counter64 =
791                             e->pft.pfrts_packets[PFR_DIR_OUT][PFR_OP_PASS];
792                         break;
793                 case LEAF_pfTablesTblPktsOutBlock:
794                         val->v.counter64 =
795                             e->pft.pfrts_packets[PFR_DIR_OUT][PFR_OP_BLOCK];
796                         break;
797                 case LEAF_pfTablesTblPktsOutXPass:
798                         val->v.counter64 =
799                             e->pft.pfrts_packets[PFR_DIR_OUT][PFR_OP_XPASS];
800                         break;
801
802                 default:
803                         return (SNMP_ERR_NOSUCHNAME);
804         }
805
806         return (SNMP_ERR_NOERROR);
807 }
808
809 int
810 pf_tbladdr(struct snmp_context __unused *ctx, struct snmp_value __unused *val,
811         u_int __unused sub, u_int __unused vindex, enum snmp_op __unused op)
812 {
813         asn_subid_t     which = val->var.subs[sub - 1];
814         struct pfa_entry *e = NULL;
815
816         if ((time(NULL) - pfa_table_age) > PFA_TABLE_MAXAGE)
817                 pfa_refresh();
818
819         switch (op) {
820                 case SNMP_OP_SET:
821                         return (SNMP_ERR_NOT_WRITEABLE);
822                 case SNMP_OP_GETNEXT:
823                         if ((e = NEXT_OBJECT_INT(&pfa_table,
824                             &val->var, sub)) == NULL)
825                                 return (SNMP_ERR_NOSUCHNAME);
826                         val->var.len = sub + 1;
827                         val->var.subs[sub] = e->index;
828                         break;
829                 case SNMP_OP_GET:
830                         if (val->var.len - sub != 1)
831                                 return (SNMP_ERR_NOSUCHNAME);
832                         if ((e = pfa_table_find(val->var.subs[sub])) == NULL)
833                                 return (SNMP_ERR_NOSUCHNAME);
834                         break;
835
836                 case SNMP_OP_COMMIT:
837                 case SNMP_OP_ROLLBACK:
838                 default:
839                         abort();
840         }
841
842         switch (which) {
843                 case LEAF_pfTablesAddrNetType:
844                         if (e->pfas.pfras_a.pfra_af == AF_INET)
845                                 val->v.integer = pfTablesAddrNetType_ipv4;
846                         else if (e->pfas.pfras_a.pfra_af == AF_INET6)
847                                 val->v.integer = pfTablesAddrNetType_ipv6;
848                         else
849                                 return (SNMP_ERR_GENERR);
850                         break;
851                 case LEAF_pfTablesAddrNet:
852                         if (e->pfas.pfras_a.pfra_af == AF_INET) {
853                                 return (string_get(val,
854                                     (u_char *)&e->pfas.pfras_a.pfra_ip4addr, 4));
855                         } else if (e->pfas.pfras_a.pfra_af == AF_INET6)
856                                 return (string_get(val,
857                                     (u_char *)&e->pfas.pfras_a.pfra_ip6addr, 16));
858                         else
859                                 return (SNMP_ERR_GENERR);
860                         break;
861                 case LEAF_pfTablesAddrPrefix:
862                         val->v.integer = (int32_t) e->pfas.pfras_a.pfra_net;
863                         break;
864                 case LEAF_pfTablesAddrTZero:
865                         val->v.uint32 =
866                             (time(NULL) - e->pfas.pfras_tzero) * 100;
867                         break;
868                 case LEAF_pfTablesAddrBytesInPass:
869                         val->v.counter64 =
870                             e->pfas.pfras_bytes[PFR_DIR_IN][PFR_OP_PASS];
871                         break;
872                 case LEAF_pfTablesAddrBytesInBlock:
873                         val->v.counter64 =
874                             e->pfas.pfras_bytes[PFR_DIR_IN][PFR_OP_BLOCK];
875                         break;
876                 case LEAF_pfTablesAddrBytesOutPass:
877                         val->v.counter64 =
878                             e->pfas.pfras_bytes[PFR_DIR_OUT][PFR_OP_PASS];
879                         break;
880                 case LEAF_pfTablesAddrBytesOutBlock:
881                         val->v.counter64 =
882                             e->pfas.pfras_bytes[PFR_DIR_OUT][PFR_OP_BLOCK];
883                         break;
884                 case LEAF_pfTablesAddrPktsInPass:
885                         val->v.counter64 =
886                             e->pfas.pfras_packets[PFR_DIR_IN][PFR_OP_PASS];
887                         break;
888                 case LEAF_pfTablesAddrPktsInBlock:
889                         val->v.counter64 =
890                             e->pfas.pfras_packets[PFR_DIR_IN][PFR_OP_BLOCK];
891                         break;
892                 case LEAF_pfTablesAddrPktsOutPass:
893                         val->v.counter64 =
894                             e->pfas.pfras_packets[PFR_DIR_OUT][PFR_OP_PASS];
895                         break;
896                 case LEAF_pfTablesAddrPktsOutBlock:
897                         val->v.counter64 =
898                             e->pfas.pfras_packets[PFR_DIR_OUT][PFR_OP_BLOCK];
899                         break;
900                 default:
901                         return (SNMP_ERR_NOSUCHNAME);
902         }
903
904         return (SNMP_ERR_NOERROR);
905 }
906
907 int
908 pf_altq(struct snmp_context __unused *ctx, struct snmp_value *val,
909         u_int sub, u_int __unused vindex, enum snmp_op op)
910 {
911         asn_subid_t     which = val->var.subs[sub - 1];
912
913         if (!altq_enabled)
914            return (SNMP_ERR_NOSUCHNAME);
915
916         if (op == SNMP_OP_SET)
917                 return (SNMP_ERR_NOT_WRITEABLE);
918
919         if (op == SNMP_OP_GET) {
920                 if ((time(NULL) - pfq_table_age) > PFQ_TABLE_MAXAGE)
921                         if (pfq_refresh() == -1)
922                             return (SNMP_ERR_GENERR);
923
924                 switch (which) {
925                         case LEAF_pfAltqQueueNumber:
926                                 val->v.uint32 = pfq_table_count;
927                                 break;
928
929                         default:
930                                 return (SNMP_ERR_NOSUCHNAME);
931                 }
932
933                 return (SNMP_ERR_NOERROR);
934         }
935
936         abort();
937         return (SNMP_ERR_GENERR);
938 }       
939
940 int
941 pf_altqq(struct snmp_context __unused *ctx, struct snmp_value *val,
942         u_int sub, u_int __unused vindex, enum snmp_op op)
943 {
944         asn_subid_t     which = val->var.subs[sub - 1];
945         struct pfq_entry *e = NULL;
946
947         if (!altq_enabled)
948            return (SNMP_ERR_NOSUCHNAME);
949
950         if ((time(NULL) - pfq_table_age) > PFQ_TABLE_MAXAGE)
951                 pfq_refresh();
952
953         switch (op) {
954                 case SNMP_OP_SET:
955                         return (SNMP_ERR_NOT_WRITEABLE);
956                 case SNMP_OP_GETNEXT:
957                         if ((e = NEXT_OBJECT_INT(&pfq_table,
958                             &val->var, sub)) == NULL)
959                                 return (SNMP_ERR_NOSUCHNAME);
960                         val->var.len = sub + 1;
961                         val->var.subs[sub] = e->index;
962                         break;
963                 case SNMP_OP_GET:
964                         if (val->var.len - sub != 1)
965                                 return (SNMP_ERR_NOSUCHNAME);
966                         if ((e = pfq_table_find(val->var.subs[sub])) == NULL)
967                                 return (SNMP_ERR_NOSUCHNAME);
968                         break;
969
970                 case SNMP_OP_COMMIT:
971                 case SNMP_OP_ROLLBACK:
972                 default:
973                         abort();
974         }
975
976         switch (which) {
977                 case LEAF_pfAltqQueueDescr:
978                         return (string_get(val, e->altq.qname, -1));
979                 case LEAF_pfAltqQueueParent:
980                         return (string_get(val, e->altq.parent, -1));
981                 case LEAF_pfAltqQueueScheduler:
982                         val->v.integer = e->altq.scheduler;
983                         break;
984                 case LEAF_pfAltqQueueBandwidth:
985                         val->v.uint32 = e->altq.bandwidth;
986                         break;
987                 case LEAF_pfAltqQueuePriority:
988                         val->v.integer = e->altq.priority;
989                         break;
990                 case LEAF_pfAltqQueueLimit:
991                         val->v.integer = e->altq.qlimit;
992                         break;
993                 
994                 default:
995                         return (SNMP_ERR_NOSUCHNAME);
996         }
997
998         return (SNMP_ERR_NOERROR);
999 }
1000
1001 int
1002 pf_labels(struct snmp_context __unused *ctx, struct snmp_value *val,
1003         u_int sub, u_int __unused vindex, enum snmp_op op)
1004 {
1005         asn_subid_t     which = val->var.subs[sub - 1];
1006
1007         if (op == SNMP_OP_SET)
1008                 return (SNMP_ERR_NOT_WRITEABLE);
1009
1010         if (op == SNMP_OP_GET) {
1011                 if ((time(NULL) - pfl_table_age) > PFL_TABLE_MAXAGE)
1012                         if (pfl_refresh() == -1)
1013                                 return (SNMP_ERR_GENERR);
1014
1015                 switch (which) {
1016                         case LEAF_pfLabelsLblNumber:
1017                                 val->v.uint32 = pfl_table_count;
1018                                 break;
1019
1020                         default:
1021                                 return (SNMP_ERR_NOSUCHNAME);
1022                 }
1023
1024                 return (SNMP_ERR_NOERROR);
1025         }
1026
1027         abort();
1028         return (SNMP_ERR_GENERR);
1029 }
1030
1031 int
1032 pf_lbltable(struct snmp_context __unused *ctx, struct snmp_value *val,
1033         u_int sub, u_int __unused vindex, enum snmp_op op)
1034 {
1035         asn_subid_t     which = val->var.subs[sub - 1];
1036         struct pfl_entry *e = NULL;
1037
1038         if ((time(NULL) - pfl_table_age) > PFL_TABLE_MAXAGE)
1039                 pfl_refresh();
1040
1041         switch (op) {
1042                 case SNMP_OP_SET:
1043                         return (SNMP_ERR_NOT_WRITEABLE);
1044                 case SNMP_OP_GETNEXT:
1045                         if ((e = NEXT_OBJECT_INT(&pfl_table,
1046                             &val->var, sub)) == NULL)
1047                                 return (SNMP_ERR_NOSUCHNAME);
1048                         val->var.len = sub + 1;
1049                         val->var.subs[sub] = e->index;
1050                         break;
1051                 case SNMP_OP_GET:
1052                         if (val->var.len - sub != 1)
1053                                 return (SNMP_ERR_NOSUCHNAME);
1054                         if ((e = pfl_table_find(val->var.subs[sub])) == NULL)
1055                                 return (SNMP_ERR_NOSUCHNAME);
1056                         break;
1057
1058                 case SNMP_OP_COMMIT:
1059                 case SNMP_OP_ROLLBACK:
1060                 default:
1061                         abort();
1062         }
1063
1064         switch (which) {
1065                 case LEAF_pfLabelsLblName:
1066                         return (string_get(val, e->name, -1));
1067                 case LEAF_pfLabelsLblEvals:
1068                         val->v.counter64 = e->evals;
1069                         break;
1070                 case LEAF_pfLabelsLblBytesIn:
1071                         val->v.counter64 = e->bytes[IN];
1072                         break;
1073                 case LEAF_pfLabelsLblBytesOut:
1074                         val->v.counter64 = e->bytes[OUT];
1075                         break;
1076                 case LEAF_pfLabelsLblPktsIn:
1077                         val->v.counter64 = e->pkts[IN];
1078                         break;
1079                 case LEAF_pfLabelsLblPktsOut:
1080                         val->v.counter64 = e->pkts[OUT];
1081                         break;
1082                 default:
1083                         return (SNMP_ERR_NOSUCHNAME);
1084         }
1085
1086         return (SNMP_ERR_NOERROR);
1087 }
1088
1089 static struct pfi_entry *
1090 pfi_table_find(u_int idx)
1091 {
1092         struct pfi_entry *e;
1093
1094         TAILQ_FOREACH(e, &pfi_table, link)
1095                 if (e->index == idx)
1096                         return (e);
1097         return (NULL);
1098 }
1099
1100 static struct pfq_entry *
1101 pfq_table_find(u_int idx)
1102 {
1103         struct pfq_entry *e;
1104
1105         TAILQ_FOREACH(e, &pfq_table, link)
1106                 if (e->index == idx)
1107                         return (e);
1108         return (NULL);
1109 }
1110
1111 static struct pft_entry *
1112 pft_table_find(u_int idx)
1113 {
1114         struct pft_entry *e;
1115
1116         TAILQ_FOREACH(e, &pft_table, link)
1117                 if (e->index == idx)
1118                         return (e);
1119         return (NULL);
1120 }
1121
1122 static struct pfa_entry *
1123 pfa_table_find(u_int idx)
1124 {
1125         struct pfa_entry *e;
1126
1127         TAILQ_FOREACH(e, &pfa_table, link)
1128                 if (e->index == idx)
1129                         return (e);
1130         return (NULL);
1131 }
1132
1133 static struct pfl_entry *
1134 pfl_table_find(u_int idx)
1135 {
1136         struct pfl_entry *e;
1137
1138         TAILQ_FOREACH(e, &pfl_table, link)
1139                 if (e->index == idx)
1140                         return (e);
1141
1142         return (NULL);
1143 }
1144
1145 static int
1146 pfi_refresh(void)
1147 {
1148         struct pfioc_iface io;
1149         struct pfi_kif *p = NULL;
1150         struct pfi_entry *e;
1151         int i, numifs = 1;
1152
1153         if (started && this_tick <= pf_tick)
1154                 return (0);
1155
1156         while (!TAILQ_EMPTY(&pfi_table)) {
1157                 e = TAILQ_FIRST(&pfi_table);
1158                 TAILQ_REMOVE(&pfi_table, e, link);
1159                 free(e);
1160         }
1161
1162         bzero(&io, sizeof(io));
1163         io.pfiio_esize = sizeof(struct pfi_kif);
1164
1165         for (;;) {
1166                 p = reallocf(p, numifs * sizeof(struct pfi_kif));
1167                 if (p == NULL) {
1168                         syslog(LOG_ERR, "pfi_refresh(): reallocf() numifs=%d: %s",
1169                             numifs, strerror(errno));
1170                         goto err2;
1171                 }
1172                 io.pfiio_size = numifs;
1173                 io.pfiio_buffer = p;
1174
1175                 if (ioctl(dev, DIOCIGETIFACES, &io)) {
1176                         syslog(LOG_ERR, "pfi_refresh(): ioctl(): %s",
1177                             strerror(errno));
1178                         goto err2;
1179                 }
1180
1181                 if (numifs >= io.pfiio_size)
1182                         break;
1183
1184                 numifs = io.pfiio_size;
1185         }
1186
1187         for (i = 0; i < numifs; i++) {
1188                 e = malloc(sizeof(struct pfi_entry));
1189                 if (e == NULL)
1190                         goto err1;
1191                 e->index = i + 1;
1192                 memcpy(&e->pfi, p+i, sizeof(struct pfi_kif));
1193                 TAILQ_INSERT_TAIL(&pfi_table, e, link);
1194         }
1195
1196         pfi_table_age = time(NULL);
1197         pfi_table_count = numifs;
1198         pf_tick = this_tick;
1199
1200         free(p);
1201         return (0);
1202
1203 err1:
1204         while (!TAILQ_EMPTY(&pfi_table)) {
1205                 e = TAILQ_FIRST(&pfi_table);
1206                 TAILQ_REMOVE(&pfi_table, e, link);
1207                 free(e);
1208         }
1209 err2:
1210         free(p);
1211         return(-1);
1212 }
1213
1214 static int
1215 pfq_refresh(void)
1216 {
1217         struct pfioc_altq pa;
1218         struct pfq_entry *e;
1219         int i, numqs, ticket;
1220
1221         if (started && this_tick <= pf_tick)
1222                 return (0);
1223
1224         while (!TAILQ_EMPTY(&pfq_table)) {
1225                 e = TAILQ_FIRST(&pfq_table);
1226                 TAILQ_REMOVE(&pfq_table, e, link);
1227                 free(e);
1228         }
1229
1230         bzero(&pa, sizeof(pa));
1231         
1232         if (ioctl(dev, DIOCGETALTQS, &pa)) {
1233                 syslog(LOG_ERR, "pfq_refresh: ioctl(DIOCGETALTQS): %s",
1234                     strerror(errno));
1235                 return (-1);
1236         }
1237
1238         numqs = pa.nr;
1239         ticket = pa.ticket;
1240
1241         for (i = 0; i < numqs; i++) {
1242                 e = malloc(sizeof(struct pfq_entry));
1243                 if (e == NULL) {
1244                         syslog(LOG_ERR, "pfq_refresh(): "
1245                             "malloc(): %s",
1246                             strerror(errno));
1247                         goto err;
1248                 }
1249                 pa.ticket = ticket;
1250                 pa.nr = i;
1251
1252                 if (ioctl(dev, DIOCGETALTQ, &pa)) {
1253                         syslog(LOG_ERR, "pfq_refresh(): "
1254                             "ioctl(DIOCGETALTQ): %s",
1255                             strerror(errno));
1256                         goto err;
1257                 }
1258
1259                 if (pa.altq.qid > 0) {
1260                         memcpy(&e->altq, &pa.altq, sizeof(struct pf_altq));
1261                         e->index = pa.altq.qid;
1262                         pfq_table_count = i;
1263                         INSERT_OBJECT_INT_LINK_INDEX(e, &pfq_table, link, index);
1264                 }
1265         }
1266         
1267         pfq_table_age = time(NULL);
1268         pf_tick = this_tick;
1269
1270         return (0);
1271 err:
1272         free(e);
1273         while (!TAILQ_EMPTY(&pfq_table)) {
1274                 e = TAILQ_FIRST(&pfq_table);
1275                 TAILQ_REMOVE(&pfq_table, e, link);
1276                 free(e);
1277         }
1278         return(-1);
1279 }
1280
1281 static int
1282 pfs_refresh(void)
1283 {
1284         if (started && this_tick <= pf_tick)
1285                 return (0);
1286
1287         bzero(&pfs, sizeof(struct pf_status));
1288
1289         if (ioctl(dev, DIOCGETSTATUS, &pfs)) {
1290                 syslog(LOG_ERR, "pfs_refresh(): ioctl(): %s",
1291                     strerror(errno));
1292                 return (-1);
1293         }
1294
1295         pf_tick = this_tick;
1296         return (0);
1297 }
1298
1299 static int
1300 pft_refresh(void)
1301 {
1302         struct pfioc_table io;
1303         struct pfr_tstats *t = NULL;
1304         struct pft_entry *e;
1305         int i, numtbls = 1;
1306
1307         if (started && this_tick <= pf_tick)
1308                 return (0);
1309
1310         while (!TAILQ_EMPTY(&pft_table)) {
1311                 e = TAILQ_FIRST(&pft_table);
1312                 TAILQ_REMOVE(&pft_table, e, link);
1313                 free(e);
1314         }
1315
1316         bzero(&io, sizeof(io));
1317         io.pfrio_esize = sizeof(struct pfr_tstats);
1318
1319         for (;;) {
1320                 t = reallocf(t, numtbls * sizeof(struct pfr_tstats));
1321                 if (t == NULL) {
1322                         syslog(LOG_ERR, "pft_refresh(): reallocf() numtbls=%d: %s",
1323                             numtbls, strerror(errno));
1324                         goto err2;
1325                 }
1326                 io.pfrio_size = numtbls;
1327                 io.pfrio_buffer = t;
1328
1329                 if (ioctl(dev, DIOCRGETTSTATS, &io)) {
1330                         syslog(LOG_ERR, "pft_refresh(): ioctl(): %s",
1331                             strerror(errno));
1332                         goto err2;
1333                 }
1334
1335                 if (numtbls >= io.pfrio_size)
1336                         break;
1337
1338                 numtbls = io.pfrio_size;
1339         }
1340
1341         for (i = 0; i < numtbls; i++) {
1342                 e = malloc(sizeof(struct pft_entry));
1343                 if (e == NULL)
1344                         goto err1;
1345                 e->index = i + 1;
1346                 memcpy(&e->pft, t+i, sizeof(struct pfr_tstats));
1347                 TAILQ_INSERT_TAIL(&pft_table, e, link);
1348         }
1349
1350         pft_table_age = time(NULL);
1351         pft_table_count = numtbls;
1352         pf_tick = this_tick;
1353
1354         free(t);
1355         return (0);
1356 err1:
1357         while (!TAILQ_EMPTY(&pft_table)) {
1358                 e = TAILQ_FIRST(&pft_table);
1359                 TAILQ_REMOVE(&pft_table, e, link);
1360                 free(e);
1361         }
1362 err2:
1363         free(t);
1364         return(-1);
1365 }
1366
1367 static int
1368 pfa_table_addrs(u_int sidx, struct pfr_table *pt)
1369 {
1370         struct pfioc_table io;
1371         struct pfr_astats *t = NULL;
1372         struct pfa_entry *e;
1373         int i, numaddrs = 1;
1374
1375         if (pt == NULL)
1376                 return (-1);
1377
1378         memset(&io, 0, sizeof(io));
1379         strlcpy(io.pfrio_table.pfrt_name, pt->pfrt_name,
1380             sizeof(io.pfrio_table.pfrt_name));
1381
1382         for (;;) {
1383                 t = reallocf(t, numaddrs * sizeof(struct pfr_astats));
1384                 if (t == NULL) {
1385                         syslog(LOG_ERR, "pfa_table_addrs(): reallocf(): %s",
1386                             strerror(errno));
1387                         numaddrs = -1;
1388                         goto error;
1389                 }
1390
1391                 memset(t, 0, sizeof(*t));
1392                 io.pfrio_size = numaddrs;
1393                 io.pfrio_buffer = t;
1394                 io.pfrio_esize = sizeof(struct pfr_astats);
1395
1396                 if (ioctl(dev, DIOCRGETASTATS, &io)) {
1397                         syslog(LOG_ERR, "pfa_table_addrs(): ioctl() on %s: %s",
1398                             pt->pfrt_name, strerror(errno));
1399                         numaddrs = -1;
1400                         break;
1401                 }
1402
1403                 if (numaddrs >= io.pfrio_size)
1404                         break;
1405
1406                 numaddrs = io.pfrio_size;
1407         }
1408
1409         for (i = 0; i < numaddrs; i++) {
1410                 if ((t + i)->pfras_a.pfra_af != AF_INET &&
1411                     (t + i)->pfras_a.pfra_af != AF_INET6) {
1412                         numaddrs = i;
1413                         break;
1414                 }
1415
1416                 e = (struct pfa_entry *)malloc(sizeof(struct pfa_entry));
1417                 if (e == NULL) {
1418                         syslog(LOG_ERR, "pfa_table_addrs(): malloc(): %s",
1419                             strerror(errno));
1420                         numaddrs = -1;
1421                         break;
1422                 }
1423                 e->index = sidx + i;
1424                 memcpy(&e->pfas, t + i, sizeof(struct pfr_astats));
1425                 TAILQ_INSERT_TAIL(&pfa_table, e, link);
1426         }
1427
1428         free(t);
1429 error:
1430         return (numaddrs);
1431 }
1432
1433 static int
1434 pfa_refresh(void)
1435 {
1436         struct pfioc_table io;
1437         struct pfr_table *pt = NULL, *it = NULL;
1438         struct pfa_entry *e;
1439         int i, numtbls = 1, cidx, naddrs;
1440
1441         if (started && this_tick <= pf_tick)
1442                 return (0);
1443
1444         while (!TAILQ_EMPTY(&pfa_table)) {
1445                 e = TAILQ_FIRST(&pfa_table);
1446                 TAILQ_REMOVE(&pfa_table, e, link);
1447                 free(e);
1448         }
1449
1450         memset(&io, 0, sizeof(io));
1451         io.pfrio_esize = sizeof(struct pfr_table);
1452
1453         for (;;) {
1454                 pt = reallocf(pt, numtbls * sizeof(struct pfr_table));
1455                 if (pt == NULL) {
1456                         syslog(LOG_ERR, "pfa_refresh(): reallocf() %s",
1457                             strerror(errno));
1458                         return (-1);
1459                 }
1460                 memset(pt, 0, sizeof(*pt));
1461                 io.pfrio_size = numtbls;
1462                 io.pfrio_buffer = pt;
1463
1464                 if (ioctl(dev, DIOCRGETTABLES, &io)) {
1465                         syslog(LOG_ERR, "pfa_refresh(): ioctl(): %s",
1466                             strerror(errno));
1467                         goto err2;
1468                 }
1469
1470                 if (numtbls >= io.pfrio_size)
1471                         break;
1472
1473                 numtbls = io.pfrio_size;
1474         }
1475
1476         cidx = 1;
1477
1478         for (it = pt, i = 0; i < numtbls; it++, i++) {
1479                 /*
1480                  * Skip the table if not active - ioctl(DIOCRGETASTATS) will
1481                  * return ESRCH for this entry anyway.
1482                  */
1483                 if (!(it->pfrt_flags & PFR_TFLAG_ACTIVE))
1484                         continue;
1485
1486                 if ((naddrs = pfa_table_addrs(cidx, it)) < 0)
1487                         goto err1;
1488
1489                 cidx += naddrs;
1490         }
1491
1492         pfa_table_age = time(NULL);
1493         pfa_table_count = cidx;
1494         pf_tick = this_tick;
1495
1496         free(pt);
1497         return (0);
1498 err1:
1499         while (!TAILQ_EMPTY(&pfa_table)) {
1500                 e = TAILQ_FIRST(&pfa_table);
1501                 TAILQ_REMOVE(&pfa_table, e, link);
1502                 free(e);
1503         }
1504
1505 err2:
1506         free(pt);
1507         return (-1);
1508 }
1509
1510 static int
1511 pfl_scan_ruleset(const char *path)
1512 {
1513         struct pfioc_rule pr;
1514         struct pfl_entry *e;
1515         u_int32_t nr, i;
1516
1517         bzero(&pr, sizeof(pr));
1518         strlcpy(pr.anchor, path, sizeof(pr.anchor));
1519         pr.rule.action = PF_PASS;
1520         if (ioctl(dev, DIOCGETRULES, &pr)) {
1521                 syslog(LOG_ERR, "pfl_scan_ruleset: ioctl(DIOCGETRULES): %s",
1522                     strerror(errno));
1523                 goto err;
1524         }
1525
1526         for (nr = pr.nr, i = 0; i < nr; i++) {
1527                 pr.nr = i;
1528                 if (ioctl(dev, DIOCGETRULE, &pr)) {
1529                         syslog(LOG_ERR, "pfl_scan_ruleset: ioctl(DIOCGETRULE):"
1530                             " %s", strerror(errno));
1531                         goto err;
1532                 }
1533
1534                 if (pr.rule.label[0]) {
1535                         e = (struct pfl_entry *)malloc(sizeof(*e));
1536                         if (e == NULL)
1537                                 goto err;
1538
1539                         strlcpy(e->name, path, sizeof(e->name));
1540                         if (path[0])
1541                                 strlcat(e->name, "/", sizeof(e->name));
1542                         strlcat(e->name, pr.rule.label, sizeof(e->name));
1543
1544                         e->evals = pr.rule.evaluations;
1545                         e->bytes[IN] = pr.rule.bytes[IN];
1546                         e->bytes[OUT] = pr.rule.bytes[OUT];
1547                         e->pkts[IN] = pr.rule.packets[IN];
1548                         e->pkts[OUT] = pr.rule.packets[OUT];
1549                         e->index = ++pfl_table_count;
1550
1551                         TAILQ_INSERT_TAIL(&pfl_table, e, link);
1552                 }
1553         }
1554
1555         return (0);
1556
1557 err:
1558         return (-1);
1559 }
1560
1561 static int
1562 pfl_walk_rulesets(const char *path)
1563 {
1564         struct pfioc_ruleset prs;
1565         char newpath[MAXPATHLEN];
1566         u_int32_t nr, i;
1567
1568         if (pfl_scan_ruleset(path))
1569                 goto err;
1570
1571         bzero(&prs, sizeof(prs));
1572         strlcpy(prs.path, path, sizeof(prs.path));
1573         if (ioctl(dev, DIOCGETRULESETS, &prs)) {
1574                 syslog(LOG_ERR, "pfl_walk_rulesets: ioctl(DIOCGETRULESETS): %s",
1575                     strerror(errno));
1576                 goto err;
1577         }
1578
1579         for (nr = prs.nr, i = 0; i < nr; i++) {
1580                 prs.nr = i;
1581                 if (ioctl(dev, DIOCGETRULESET, &prs)) {
1582                         syslog(LOG_ERR, "pfl_walk_rulesets: ioctl(DIOCGETRULESET):"
1583                             " %s", strerror(errno));
1584                         goto err;
1585                 }
1586
1587                 if (strcmp(prs.name, PF_RESERVED_ANCHOR) == 0)
1588                         continue;
1589
1590                 strlcpy(newpath, path, sizeof(newpath));
1591                 if (path[0])
1592                         strlcat(newpath, "/", sizeof(newpath));
1593
1594                 strlcat(newpath, prs.name, sizeof(newpath));
1595                 if (pfl_walk_rulesets(newpath))
1596                         goto err;
1597         }
1598
1599         return (0);
1600
1601 err:
1602         return (-1);
1603 }
1604
1605 static int
1606 pfl_refresh(void)
1607 {
1608         struct pfl_entry *e;
1609
1610         if (started && this_tick <= pf_tick)
1611                 return (0);
1612
1613         while (!TAILQ_EMPTY(&pfl_table)) {
1614                 e = TAILQ_FIRST(&pfl_table);
1615                 TAILQ_REMOVE(&pfl_table, e, link);
1616                 free(e);
1617         }
1618         pfl_table_count = 0;
1619
1620         if (pfl_walk_rulesets(""))
1621                 goto err;
1622
1623         pfl_table_age = time(NULL);
1624         pf_tick = this_tick;
1625
1626         return (0);
1627
1628 err:
1629         while (!TAILQ_EMPTY(&pfl_table)) {
1630                 e = TAILQ_FIRST(&pfl_table);
1631                 TAILQ_REMOVE(&pfl_table, e, link);
1632                 free(e);
1633         }
1634         pfl_table_count = 0;
1635
1636         return (-1);
1637 }
1638
1639 /*
1640  * check whether altq support is enabled in kernel
1641  */
1642
1643 static int
1644 altq_is_enabled(int pfdev)
1645 {
1646         struct pfioc_altq pa;
1647
1648         errno = 0;
1649         if (ioctl(pfdev, DIOCGETALTQS, &pa)) {
1650                 if (errno == ENODEV) {
1651                         syslog(LOG_INFO, "No ALTQ support in kernel\n"
1652                             "ALTQ related functions disabled\n");
1653                         return (0);
1654                 } else  
1655                         syslog(LOG_ERR, "DIOCGETALTQS returned an error: %s",
1656                             strerror(errno));
1657                         return (-1);
1658         }
1659         return (1);
1660 }
1661
1662 /*
1663  * Implement the bsnmpd module interface
1664  */
1665 static int
1666 pf_init(struct lmodule *mod, int __unused argc, char __unused *argv[])
1667 {
1668         module = mod;
1669
1670         if ((dev = open("/dev/pf", O_RDONLY)) == -1) {
1671                 syslog(LOG_ERR, "pf_init(): open(): %s\n",
1672                     strerror(errno));
1673                 return (-1);
1674         }
1675
1676         if ((altq_enabled = altq_is_enabled(dev)) == -1) {
1677                 syslog(LOG_ERR, "pf_init(): altq test failed");
1678                 return (-1);
1679         }
1680         
1681         /* Prepare internal state */
1682         TAILQ_INIT(&pfi_table);
1683         TAILQ_INIT(&pfq_table);
1684         TAILQ_INIT(&pft_table);
1685         TAILQ_INIT(&pfa_table);
1686         TAILQ_INIT(&pfl_table);
1687
1688         pfi_refresh();
1689         if (altq_enabled) {
1690                 pfq_refresh();
1691         }
1692
1693         pfs_refresh();
1694         pft_refresh();
1695         pfa_refresh();
1696         pfl_refresh();
1697
1698         started = 1;
1699
1700         return (0);
1701 }
1702
1703 static int
1704 pf_fini(void)
1705 {
1706         struct pfi_entry *i1, *i2;
1707         struct pfq_entry *q1, *q2;
1708         struct pft_entry *t1, *t2;
1709         struct pfa_entry *a1, *a2;
1710         struct pfl_entry *l1, *l2;
1711
1712         /* Empty the list of interfaces */
1713         i1 = TAILQ_FIRST(&pfi_table);
1714         while (i1 != NULL) {
1715                 i2 = TAILQ_NEXT(i1, link);
1716                 free(i1);
1717                 i1 = i2;
1718         }
1719
1720         /* List of queues */
1721         q1 = TAILQ_FIRST(&pfq_table);
1722         while (q1 != NULL) {
1723                 q2 = TAILQ_NEXT(q1, link);
1724                 free(q1);
1725                 q1 = q2;
1726         }
1727
1728         /* List of tables */
1729         t1 = TAILQ_FIRST(&pft_table);
1730         while (t1 != NULL) {
1731                 t2 = TAILQ_NEXT(t1, link);
1732                 free(t1);
1733                 t1 = t2;
1734         }
1735
1736         /* List of table addresses */
1737         a1 = TAILQ_FIRST(&pfa_table);
1738         while (a1 != NULL) {
1739                 a2 = TAILQ_NEXT(a1, link);
1740                 free(a1);
1741                 a1 = a2;
1742         }
1743
1744         /* And the list of labeled filter rules */
1745         l1 = TAILQ_FIRST(&pfl_table);
1746         while (l1 != NULL) {
1747                 l2 = TAILQ_NEXT(l1, link);
1748                 free(l1);
1749                 l1 = l2;
1750         }
1751
1752         close(dev);
1753         return (0);
1754 }
1755
1756 static void
1757 pf_dump(void)
1758 {
1759         pfi_refresh();
1760         if (altq_enabled) {
1761                 pfq_refresh();
1762         }
1763         pft_refresh();
1764         pfa_refresh();
1765         pfl_refresh();
1766
1767         syslog(LOG_ERR, "Dump: pfi_table_age = %jd",
1768             (intmax_t)pfi_table_age);
1769         syslog(LOG_ERR, "Dump: pfi_table_count = %d",
1770             pfi_table_count);
1771         
1772         syslog(LOG_ERR, "Dump: pfq_table_age = %jd",
1773             (intmax_t)pfq_table_age);
1774         syslog(LOG_ERR, "Dump: pfq_table_count = %d",
1775             pfq_table_count);
1776
1777         syslog(LOG_ERR, "Dump: pft_table_age = %jd",
1778             (intmax_t)pft_table_age);
1779         syslog(LOG_ERR, "Dump: pft_table_count = %d",
1780             pft_table_count);
1781
1782         syslog(LOG_ERR, "Dump: pfa_table_age = %jd",
1783             (intmax_t)pfa_table_age);
1784         syslog(LOG_ERR, "Dump: pfa_table_count = %d",
1785             pfa_table_count);
1786
1787         syslog(LOG_ERR, "Dump: pfl_table_age = %jd",
1788             (intmax_t)pfl_table_age);
1789         syslog(LOG_ERR, "Dump: pfl_table_count = %d",
1790             pfl_table_count);
1791 }
1792
1793 const struct snmp_module config = {
1794         .comment = "This module implements a MIB for the pf packet filter.",
1795         .init =         pf_init,
1796         .fini =         pf_fini,
1797         .tree =         pf_ctree,
1798         .dump =         pf_dump,
1799         .tree_size =    pf_CTREE_SIZE,
1800 };