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 pfr_table tbl = { 0 };
1360 struct pfr_astats *t = NULL;
1361 struct pfa_entry *e;
1362 int i, numaddrs = 1, outnum;
1363
1364 if (pt == NULL)
1365 return (-1);
1366
1367 strlcpy(tbl.pfrt_name, pt->pfrt_name,
1368 sizeof(tbl.pfrt_name));
1369
1370 for (;;) {
1371 t = reallocf(t, numaddrs * sizeof(struct pfr_astats));
1372 if (t == NULL) {
1373 syslog(LOG_ERR, "pfa_table_addrs(): reallocf(): %s",
1374 strerror(errno));
1375 numaddrs = -1;
1376 goto error;
1377 }
1378
1379 outnum = numaddrs;
1380 if (pfctl_get_astats(pfh, &tbl, t, &outnum, 0) != 0) {
1381 syslog(LOG_ERR, "pfa_table_addrs(): ioctl() on %s: %s",
1382 pt->pfrt_name, strerror(errno));
1383 numaddrs = -1;
1384 break;
1385 }
1386
1387 if (numaddrs >= outnum)
1388 break;
1389
1390 numaddrs = outnum;
1391 }
1392
1393 for (i = 0; i < numaddrs; i++) {
1394 if ((t + i)->pfras_a.pfra_af != AF_INET &&
1395 (t + i)->pfras_a.pfra_af != AF_INET6) {
1396 numaddrs = i;
1397 break;
1398 }
1399
1400 e = (struct pfa_entry *)malloc(sizeof(struct pfa_entry));
1401 if (e == NULL) {
1402 syslog(LOG_ERR, "pfa_table_addrs(): malloc(): %s",
1403 strerror(errno));
1404 numaddrs = -1;
1405 break;
1406 }
1407 e->index = sidx + i;
1408 memcpy(&e->pfas, t + i, sizeof(struct pfr_astats));
1409 TAILQ_INSERT_TAIL(&pfa_table, e, link);
1410 }
1411
1412 free(t);
1413 error:
1414 return (numaddrs);
1415 }
1416
1417 static int
pfa_refresh(void)1418 pfa_refresh(void)
1419 {
1420 struct pfioc_table io;
1421 struct pfr_table *pt = NULL, *it = NULL;
1422 struct pfa_entry *e;
1423 int i, numtbls = 1, cidx, naddrs;
1424
1425 if (started && this_tick <= pf_tick)
1426 return (0);
1427
1428 while (!TAILQ_EMPTY(&pfa_table)) {
1429 e = TAILQ_FIRST(&pfa_table);
1430 TAILQ_REMOVE(&pfa_table, e, link);
1431 free(e);
1432 }
1433
1434 memset(&io, 0, sizeof(io));
1435 io.pfrio_esize = sizeof(struct pfr_table);
1436
1437 for (;;) {
1438 pt = reallocf(pt, numtbls * sizeof(struct pfr_table));
1439 if (pt == NULL) {
1440 syslog(LOG_ERR, "pfa_refresh(): reallocf() %s",
1441 strerror(errno));
1442 return (-1);
1443 }
1444 memset(pt, 0, sizeof(*pt));
1445 io.pfrio_size = numtbls;
1446 io.pfrio_buffer = pt;
1447
1448 if (ioctl(pfctl_fd(pfh), DIOCRGETTABLES, &io)) {
1449 syslog(LOG_ERR, "pfa_refresh(): ioctl(): %s",
1450 strerror(errno));
1451 goto err2;
1452 }
1453
1454 if (numtbls >= io.pfrio_size)
1455 break;
1456
1457 numtbls = io.pfrio_size;
1458 }
1459
1460 cidx = 1;
1461
1462 for (it = pt, i = 0; i < numtbls; it++, i++) {
1463 /*
1464 * Skip the table if not active - ioctl(DIOCRGETASTATS) will
1465 * return ESRCH for this entry anyway.
1466 */
1467 if (!(it->pfrt_flags & PFR_TFLAG_ACTIVE))
1468 continue;
1469
1470 if ((naddrs = pfa_table_addrs(cidx, it)) < 0)
1471 goto err1;
1472
1473 cidx += naddrs;
1474 }
1475
1476 pfa_table_age = time(NULL);
1477 pfa_table_count = cidx;
1478 pf_tick = this_tick;
1479
1480 free(pt);
1481 return (0);
1482 err1:
1483 while (!TAILQ_EMPTY(&pfa_table)) {
1484 e = TAILQ_FIRST(&pfa_table);
1485 TAILQ_REMOVE(&pfa_table, e, link);
1486 free(e);
1487 }
1488
1489 err2:
1490 free(pt);
1491 return (-1);
1492 }
1493
1494 static int
pfl_scan_ruleset(const char * path)1495 pfl_scan_ruleset(const char *path)
1496 {
1497 struct pfctl_rules_info rules;
1498 struct pfctl_rule rule;
1499 char anchor_call[MAXPATHLEN] = "";
1500 struct pfl_entry *e;
1501 u_int32_t nr, i;
1502
1503 if (pfctl_get_rules_info_h(pfh, &rules, PF_PASS, path)) {
1504 syslog(LOG_ERR, "pfl_scan_ruleset: ioctl(DIOCGETRULES): %s",
1505 strerror(errno));
1506 goto err;
1507 }
1508
1509 for (nr = rules.nr, i = 0; i < nr; i++) {
1510 if (pfctl_get_rule_h(pfh, i, rules.ticket, path,
1511 PF_PASS, &rule, anchor_call)) {
1512 syslog(LOG_ERR, "pfl_scan_ruleset: ioctl(DIOCGETRULE):"
1513 " %s", strerror(errno));
1514 goto err;
1515 }
1516
1517 if (rule.label[0][0]) {
1518 e = (struct pfl_entry *)malloc(sizeof(*e));
1519 if (e == NULL)
1520 goto err;
1521
1522 strlcpy(e->name, path, sizeof(e->name));
1523 if (path[0])
1524 strlcat(e->name, "/", sizeof(e->name));
1525 strlcat(e->name, rule.label[0], sizeof(e->name));
1526
1527 e->evals = rule.evaluations;
1528 e->bytes[IN] = rule.bytes[IN];
1529 e->bytes[OUT] = rule.bytes[OUT];
1530 e->pkts[IN] = rule.packets[IN];
1531 e->pkts[OUT] = rule.packets[OUT];
1532 e->index = ++pfl_table_count;
1533
1534 TAILQ_INSERT_TAIL(&pfl_table, e, link);
1535 }
1536 }
1537
1538 return (0);
1539
1540 err:
1541 return (-1);
1542 }
1543
1544 static int
pfl_walk_rulesets(const char * path)1545 pfl_walk_rulesets(const char *path)
1546 {
1547 struct pfioc_ruleset prs;
1548 char newpath[MAXPATHLEN];
1549 u_int32_t nr, i;
1550
1551 if (pfl_scan_ruleset(path))
1552 goto err;
1553
1554 bzero(&prs, sizeof(prs));
1555 strlcpy(prs.path, path, sizeof(prs.path));
1556 if (ioctl(pfctl_fd(pfh), DIOCGETRULESETS, &prs)) {
1557 syslog(LOG_ERR, "pfl_walk_rulesets: ioctl(DIOCGETRULESETS): %s",
1558 strerror(errno));
1559 goto err;
1560 }
1561
1562 for (nr = prs.nr, i = 0; i < nr; i++) {
1563 prs.nr = i;
1564 if (ioctl(pfctl_fd(pfh), DIOCGETRULESET, &prs)) {
1565 syslog(LOG_ERR, "pfl_walk_rulesets: ioctl(DIOCGETRULESET):"
1566 " %s", strerror(errno));
1567 goto err;
1568 }
1569
1570 if (strcmp(prs.name, PF_RESERVED_ANCHOR) == 0)
1571 continue;
1572
1573 strlcpy(newpath, path, sizeof(newpath));
1574 if (path[0])
1575 strlcat(newpath, "/", sizeof(newpath));
1576
1577 strlcat(newpath, prs.name, sizeof(newpath));
1578 if (pfl_walk_rulesets(newpath))
1579 goto err;
1580 }
1581
1582 return (0);
1583
1584 err:
1585 return (-1);
1586 }
1587
1588 static int
pfl_refresh(void)1589 pfl_refresh(void)
1590 {
1591 struct pfl_entry *e;
1592
1593 if (started && this_tick <= pf_tick)
1594 return (0);
1595
1596 while (!TAILQ_EMPTY(&pfl_table)) {
1597 e = TAILQ_FIRST(&pfl_table);
1598 TAILQ_REMOVE(&pfl_table, e, link);
1599 free(e);
1600 }
1601 pfl_table_count = 0;
1602
1603 if (pfl_walk_rulesets(""))
1604 goto err;
1605
1606 pfl_table_age = time(NULL);
1607 pf_tick = this_tick;
1608
1609 return (0);
1610
1611 err:
1612 while (!TAILQ_EMPTY(&pfl_table)) {
1613 e = TAILQ_FIRST(&pfl_table);
1614 TAILQ_REMOVE(&pfl_table, e, link);
1615 free(e);
1616 }
1617 pfl_table_count = 0;
1618
1619 return (-1);
1620 }
1621
1622 /*
1623 * check whether altq support is enabled in kernel
1624 */
1625
1626 static int
altq_is_enabled(int pfdev)1627 altq_is_enabled(int pfdev)
1628 {
1629 struct pfioc_altq pa;
1630
1631 errno = 0;
1632 pa.version = PFIOC_ALTQ_VERSION;
1633 if (ioctl(pfdev, DIOCGETALTQS, &pa)) {
1634 if (errno == ENODEV) {
1635 syslog(LOG_INFO, "No ALTQ support in kernel\n"
1636 "ALTQ related functions disabled\n");
1637 return (0);
1638 } else {
1639 syslog(LOG_ERR, "DIOCGETALTQS returned an error: %s",
1640 strerror(errno));
1641 return (-1);
1642 }
1643 }
1644 return (1);
1645 }
1646
1647 /*
1648 * Implement the bsnmpd module interface
1649 */
1650 static int
pf_init(struct lmodule * mod,int __unused argc,char __unused * argv[])1651 pf_init(struct lmodule *mod, int __unused argc, char __unused *argv[])
1652 {
1653 module = mod;
1654
1655 if ((pfh = pfctl_open(PF_DEVICE)) == NULL) {
1656 syslog(LOG_ERR, "pf_init(): open(): %s\n",
1657 strerror(errno));
1658 return (-1);
1659 }
1660
1661 if ((altq_enabled = altq_is_enabled(pfctl_fd(pfh))) == -1) {
1662 syslog(LOG_ERR, "pf_init(): altq test failed");
1663 return (-1);
1664 }
1665
1666 /* Prepare internal state */
1667 TAILQ_INIT(&pfi_table);
1668 TAILQ_INIT(&pfq_table);
1669 TAILQ_INIT(&pft_table);
1670 TAILQ_INIT(&pfa_table);
1671 TAILQ_INIT(&pfl_table);
1672
1673 pfi_refresh();
1674 if (altq_enabled) {
1675 pfq_refresh();
1676 }
1677
1678 pfs_refresh();
1679 pft_refresh();
1680 pfa_refresh();
1681 pfl_refresh();
1682
1683 started = 1;
1684
1685 return (0);
1686 }
1687
1688 static int
pf_fini(void)1689 pf_fini(void)
1690 {
1691 struct pfi_entry *i1, *i2;
1692 struct pfq_entry *q1, *q2;
1693 struct pft_entry *t1, *t2;
1694 struct pfa_entry *a1, *a2;
1695 struct pfl_entry *l1, *l2;
1696
1697 /* Empty the list of interfaces */
1698 i1 = TAILQ_FIRST(&pfi_table);
1699 while (i1 != NULL) {
1700 i2 = TAILQ_NEXT(i1, link);
1701 free(i1);
1702 i1 = i2;
1703 }
1704
1705 /* List of queues */
1706 q1 = TAILQ_FIRST(&pfq_table);
1707 while (q1 != NULL) {
1708 q2 = TAILQ_NEXT(q1, link);
1709 free(q1);
1710 q1 = q2;
1711 }
1712
1713 /* List of tables */
1714 t1 = TAILQ_FIRST(&pft_table);
1715 while (t1 != NULL) {
1716 t2 = TAILQ_NEXT(t1, link);
1717 free(t1);
1718 t1 = t2;
1719 }
1720
1721 /* List of table addresses */
1722 a1 = TAILQ_FIRST(&pfa_table);
1723 while (a1 != NULL) {
1724 a2 = TAILQ_NEXT(a1, link);
1725 free(a1);
1726 a1 = a2;
1727 }
1728
1729 /* And the list of labeled filter rules */
1730 l1 = TAILQ_FIRST(&pfl_table);
1731 while (l1 != NULL) {
1732 l2 = TAILQ_NEXT(l1, link);
1733 free(l1);
1734 l1 = l2;
1735 }
1736
1737 pfctl_free_status(pfs);
1738 pfs = NULL;
1739
1740 pfctl_close(pfh);
1741
1742 return (0);
1743 }
1744
1745 static void
pf_dump(void)1746 pf_dump(void)
1747 {
1748 pfi_refresh();
1749 if (altq_enabled) {
1750 pfq_refresh();
1751 }
1752 pft_refresh();
1753 pfa_refresh();
1754 pfl_refresh();
1755
1756 syslog(LOG_ERR, "Dump: pfi_table_age = %jd",
1757 (intmax_t)pfi_table_age);
1758 syslog(LOG_ERR, "Dump: pfi_table_count = %d",
1759 pfi_table_count);
1760
1761 syslog(LOG_ERR, "Dump: pfq_table_age = %jd",
1762 (intmax_t)pfq_table_age);
1763 syslog(LOG_ERR, "Dump: pfq_table_count = %d",
1764 pfq_table_count);
1765
1766 syslog(LOG_ERR, "Dump: pft_table_age = %jd",
1767 (intmax_t)pft_table_age);
1768 syslog(LOG_ERR, "Dump: pft_table_count = %d",
1769 pft_table_count);
1770
1771 syslog(LOG_ERR, "Dump: pfa_table_age = %jd",
1772 (intmax_t)pfa_table_age);
1773 syslog(LOG_ERR, "Dump: pfa_table_count = %d",
1774 pfa_table_count);
1775
1776 syslog(LOG_ERR, "Dump: pfl_table_age = %jd",
1777 (intmax_t)pfl_table_age);
1778 syslog(LOG_ERR, "Dump: pfl_table_count = %d",
1779 pfl_table_count);
1780 }
1781
1782 const struct snmp_module config = {
1783 .comment = "This module implements a MIB for the pf packet filter.",
1784 .init = pf_init,
1785 .fini = pf_fini,
1786 .tree = pf_ctree,
1787 .dump = pf_dump,
1788 .tree_size = pf_CTREE_SIZE,
1789 };
1790