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