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