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