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