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