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