Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/usr.sbin/bsnmpd/modules/snmp_pf/pf_snmp.c
107769 views
1
/*-
2
* SPDX-License-Identifier: BSD-2-Clause
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
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
153
pf_status(struct snmp_context __unused *ctx, struct snmp_value *val,
154
u_int sub, u_int __unused vindex, enum snmp_op op)
155
{
156
asn_subid_t which = val->var.subs[sub - 1];
157
time_t runtime;
158
unsigned char str[128];
159
160
if (op == SNMP_OP_SET)
161
return (SNMP_ERR_NOT_WRITEABLE);
162
163
if (op == SNMP_OP_GET) {
164
if (pfs_refresh() == -1)
165
return (SNMP_ERR_GENERR);
166
167
switch (which) {
168
case LEAF_pfStatusRunning:
169
val->v.uint32 = pfs->running;
170
break;
171
case LEAF_pfStatusRuntime:
172
runtime = (pfs->since > 0) ?
173
time(NULL) - pfs->since : 0;
174
val->v.uint32 = (uint32_t)(runtime * 100);
175
break;
176
case LEAF_pfStatusDebug:
177
val->v.uint32 = pfs->debug;
178
break;
179
case LEAF_pfStatusHostId:
180
sprintf(str, "0x%08x", ntohl(pfs->hostid));
181
return (string_get(val, str, strlen(str)));
182
183
default:
184
return (SNMP_ERR_NOSUCHNAME);
185
}
186
187
return (SNMP_ERR_NOERROR);
188
}
189
190
abort();
191
}
192
193
int
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
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
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
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
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
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
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
549
pf_iftable(struct snmp_context __unused *ctx, struct snmp_value *val,
550
u_int sub, u_int __unused vindex, enum snmp_op op)
551
{
552
asn_subid_t which = val->var.subs[sub - 1];
553
struct pfi_entry *e = NULL;
554
555
if ((time(NULL) - pfi_table_age) > PFI_TABLE_MAXAGE)
556
pfi_refresh();
557
558
switch (op) {
559
case SNMP_OP_SET:
560
return (SNMP_ERR_NOT_WRITEABLE);
561
case SNMP_OP_GETNEXT:
562
if ((e = NEXT_OBJECT_INT(&pfi_table,
563
&val->var, sub)) == NULL)
564
return (SNMP_ERR_NOSUCHNAME);
565
val->var.len = sub + 1;
566
val->var.subs[sub] = e->index;
567
break;
568
case SNMP_OP_GET:
569
if (val->var.len - sub != 1)
570
return (SNMP_ERR_NOSUCHNAME);
571
if ((e = pfi_table_find(val->var.subs[sub])) == NULL)
572
return (SNMP_ERR_NOSUCHNAME);
573
break;
574
575
case SNMP_OP_COMMIT:
576
case SNMP_OP_ROLLBACK:
577
default:
578
abort();
579
}
580
581
switch (which) {
582
case LEAF_pfInterfacesIfDescr:
583
return (string_get(val, e->pfi.pfik_name, -1));
584
case LEAF_pfInterfacesIfType:
585
val->v.integer = PFI_IFTYPE_INSTANCE;
586
break;
587
case LEAF_pfInterfacesIfTZero:
588
val->v.uint32 =
589
(uint32_t)(time(NULL) - e->pfi.pfik_tzero) * 100;
590
break;
591
case LEAF_pfInterfacesIfRefsRule:
592
val->v.uint32 = e->pfi.pfik_rulerefs;
593
break;
594
case LEAF_pfInterfacesIf4BytesInPass:
595
val->v.counter64 =
596
e->pfi.pfik_bytes[IPV4][IN][PASS];
597
break;
598
case LEAF_pfInterfacesIf4BytesInBlock:
599
val->v.counter64 =
600
e->pfi.pfik_bytes[IPV4][IN][BLOCK];
601
break;
602
case LEAF_pfInterfacesIf4BytesOutPass:
603
val->v.counter64 =
604
e->pfi.pfik_bytes[IPV4][OUT][PASS];
605
break;
606
case LEAF_pfInterfacesIf4BytesOutBlock:
607
val->v.counter64 =
608
e->pfi.pfik_bytes[IPV4][OUT][BLOCK];
609
break;
610
case LEAF_pfInterfacesIf4PktsInPass:
611
val->v.counter64 =
612
e->pfi.pfik_packets[IPV4][IN][PASS];
613
break;
614
case LEAF_pfInterfacesIf4PktsInBlock:
615
val->v.counter64 =
616
e->pfi.pfik_packets[IPV4][IN][BLOCK];
617
break;
618
case LEAF_pfInterfacesIf4PktsOutPass:
619
val->v.counter64 =
620
e->pfi.pfik_packets[IPV4][OUT][PASS];
621
break;
622
case LEAF_pfInterfacesIf4PktsOutBlock:
623
val->v.counter64 =
624
e->pfi.pfik_packets[IPV4][OUT][BLOCK];
625
break;
626
case LEAF_pfInterfacesIf6BytesInPass:
627
val->v.counter64 =
628
e->pfi.pfik_bytes[IPV6][IN][PASS];
629
break;
630
case LEAF_pfInterfacesIf6BytesInBlock:
631
val->v.counter64 =
632
e->pfi.pfik_bytes[IPV6][IN][BLOCK];
633
break;
634
case LEAF_pfInterfacesIf6BytesOutPass:
635
val->v.counter64 =
636
e->pfi.pfik_bytes[IPV6][OUT][PASS];
637
break;
638
case LEAF_pfInterfacesIf6BytesOutBlock:
639
val->v.counter64 =
640
e->pfi.pfik_bytes[IPV6][OUT][BLOCK];
641
break;
642
case LEAF_pfInterfacesIf6PktsInPass:
643
val->v.counter64 =
644
e->pfi.pfik_packets[IPV6][IN][PASS];
645
break;
646
case LEAF_pfInterfacesIf6PktsInBlock:
647
val->v.counter64 =
648
e->pfi.pfik_packets[IPV6][IN][BLOCK];
649
break;
650
case LEAF_pfInterfacesIf6PktsOutPass:
651
val->v.counter64 =
652
e->pfi.pfik_packets[IPV6][OUT][PASS];
653
break;
654
case LEAF_pfInterfacesIf6PktsOutBlock:
655
val->v.counter64 =
656
e->pfi.pfik_packets[IPV6][OUT][BLOCK];
657
break;
658
659
default:
660
return (SNMP_ERR_NOSUCHNAME);
661
}
662
663
return (SNMP_ERR_NOERROR);
664
}
665
666
int
667
pf_tables(struct snmp_context __unused *ctx, struct snmp_value *val,
668
u_int sub, u_int __unused vindex, enum snmp_op op)
669
{
670
asn_subid_t which = val->var.subs[sub - 1];
671
672
if (op == SNMP_OP_SET)
673
return (SNMP_ERR_NOT_WRITEABLE);
674
675
if (op == SNMP_OP_GET) {
676
if (! started || (time(NULL) - pft_table_age) > PFT_TABLE_MAXAGE)
677
if (pft_refresh() == -1)
678
return (SNMP_ERR_GENERR);
679
680
switch (which) {
681
case LEAF_pfTablesTblNumber:
682
val->v.uint32 = pft_table_count;
683
break;
684
685
default:
686
return (SNMP_ERR_NOSUCHNAME);
687
}
688
689
return (SNMP_ERR_NOERROR);
690
}
691
692
abort();
693
}
694
695
int
696
pf_tbltable(struct snmp_context __unused *ctx, struct snmp_value *val,
697
u_int sub, u_int __unused vindex, enum snmp_op op)
698
{
699
asn_subid_t which = val->var.subs[sub - 1];
700
struct pft_entry *e = NULL;
701
702
if ((time(NULL) - pft_table_age) > PFT_TABLE_MAXAGE)
703
pft_refresh();
704
705
switch (op) {
706
case SNMP_OP_SET:
707
return (SNMP_ERR_NOT_WRITEABLE);
708
case SNMP_OP_GETNEXT:
709
if ((e = NEXT_OBJECT_INT(&pft_table,
710
&val->var, sub)) == NULL)
711
return (SNMP_ERR_NOSUCHNAME);
712
val->var.len = sub + 1;
713
val->var.subs[sub] = e->index;
714
break;
715
case SNMP_OP_GET:
716
if (val->var.len - sub != 1)
717
return (SNMP_ERR_NOSUCHNAME);
718
if ((e = pft_table_find(val->var.subs[sub])) == NULL)
719
return (SNMP_ERR_NOSUCHNAME);
720
break;
721
722
case SNMP_OP_COMMIT:
723
case SNMP_OP_ROLLBACK:
724
default:
725
abort();
726
}
727
728
switch (which) {
729
case LEAF_pfTablesTblDescr:
730
return (string_get(val, e->pft.pfrts_name, -1));
731
case LEAF_pfTablesTblCount:
732
val->v.integer = e->pft.pfrts_cnt;
733
break;
734
case LEAF_pfTablesTblTZero:
735
val->v.uint32 =
736
(uint32_t)(time(NULL) - e->pft.pfrts_tzero) * 100;
737
break;
738
case LEAF_pfTablesTblRefsAnchor:
739
val->v.integer =
740
e->pft.pfrts_refcnt[PFR_REFCNT_ANCHOR];
741
break;
742
case LEAF_pfTablesTblRefsRule:
743
val->v.integer =
744
e->pft.pfrts_refcnt[PFR_REFCNT_RULE];
745
break;
746
case LEAF_pfTablesTblEvalMatch:
747
val->v.counter64 = e->pft.pfrts_match;
748
break;
749
case LEAF_pfTablesTblEvalNoMatch:
750
val->v.counter64 = e->pft.pfrts_nomatch;
751
break;
752
case LEAF_pfTablesTblBytesInPass:
753
val->v.counter64 =
754
e->pft.pfrts_bytes[PFR_DIR_IN][PFR_OP_PASS];
755
break;
756
case LEAF_pfTablesTblBytesInBlock:
757
val->v.counter64 =
758
e->pft.pfrts_bytes[PFR_DIR_IN][PFR_OP_BLOCK];
759
break;
760
case LEAF_pfTablesTblBytesInXPass:
761
val->v.counter64 =
762
e->pft.pfrts_bytes[PFR_DIR_IN][PFR_OP_XPASS];
763
break;
764
case LEAF_pfTablesTblBytesOutPass:
765
val->v.counter64 =
766
e->pft.pfrts_bytes[PFR_DIR_OUT][PFR_OP_PASS];
767
break;
768
case LEAF_pfTablesTblBytesOutBlock:
769
val->v.counter64 =
770
e->pft.pfrts_bytes[PFR_DIR_OUT][PFR_OP_BLOCK];
771
break;
772
case LEAF_pfTablesTblBytesOutXPass:
773
val->v.counter64 =
774
e->pft.pfrts_bytes[PFR_DIR_OUT][PFR_OP_XPASS];
775
break;
776
case LEAF_pfTablesTblPktsInPass:
777
val->v.counter64 =
778
e->pft.pfrts_packets[PFR_DIR_IN][PFR_OP_PASS];
779
break;
780
case LEAF_pfTablesTblPktsInBlock:
781
val->v.counter64 =
782
e->pft.pfrts_packets[PFR_DIR_IN][PFR_OP_BLOCK];
783
break;
784
case LEAF_pfTablesTblPktsInXPass:
785
val->v.counter64 =
786
e->pft.pfrts_packets[PFR_DIR_IN][PFR_OP_XPASS];
787
break;
788
case LEAF_pfTablesTblPktsOutPass:
789
val->v.counter64 =
790
e->pft.pfrts_packets[PFR_DIR_OUT][PFR_OP_PASS];
791
break;
792
case LEAF_pfTablesTblPktsOutBlock:
793
val->v.counter64 =
794
e->pft.pfrts_packets[PFR_DIR_OUT][PFR_OP_BLOCK];
795
break;
796
case LEAF_pfTablesTblPktsOutXPass:
797
val->v.counter64 =
798
e->pft.pfrts_packets[PFR_DIR_OUT][PFR_OP_XPASS];
799
break;
800
801
default:
802
return (SNMP_ERR_NOSUCHNAME);
803
}
804
805
return (SNMP_ERR_NOERROR);
806
}
807
808
int
809
pf_tbladdr(struct snmp_context __unused *ctx, struct snmp_value __unused *val,
810
u_int __unused sub, u_int __unused vindex, enum snmp_op __unused op)
811
{
812
asn_subid_t which = val->var.subs[sub - 1];
813
struct pfa_entry *e = NULL;
814
815
if (! started || (time(NULL) - pfa_table_age) > PFA_TABLE_MAXAGE)
816
pfa_refresh();
817
818
switch (op) {
819
case SNMP_OP_SET:
820
return (SNMP_ERR_NOT_WRITEABLE);
821
case SNMP_OP_GETNEXT:
822
if ((e = NEXT_OBJECT_INT(&pfa_table,
823
&val->var, sub)) == NULL)
824
return (SNMP_ERR_NOSUCHNAME);
825
val->var.len = sub + 1;
826
val->var.subs[sub] = e->index;
827
break;
828
case SNMP_OP_GET:
829
if (val->var.len - sub != 1)
830
return (SNMP_ERR_NOSUCHNAME);
831
if ((e = pfa_table_find(val->var.subs[sub])) == NULL)
832
return (SNMP_ERR_NOSUCHNAME);
833
break;
834
835
case SNMP_OP_COMMIT:
836
case SNMP_OP_ROLLBACK:
837
default:
838
abort();
839
}
840
841
switch (which) {
842
case LEAF_pfTablesAddrNetType:
843
if (e->pfas.pfras_a.pfra_af == AF_INET)
844
val->v.integer = pfTablesAddrNetType_ipv4;
845
else if (e->pfas.pfras_a.pfra_af == AF_INET6)
846
val->v.integer = pfTablesAddrNetType_ipv6;
847
else
848
return (SNMP_ERR_GENERR);
849
break;
850
case LEAF_pfTablesAddrNet:
851
if (e->pfas.pfras_a.pfra_af == AF_INET) {
852
return (string_get(val,
853
(u_char *)&e->pfas.pfras_a.pfra_ip4addr, 4));
854
} else if (e->pfas.pfras_a.pfra_af == AF_INET6)
855
return (string_get(val,
856
(u_char *)&e->pfas.pfras_a.pfra_ip6addr, 16));
857
else
858
return (SNMP_ERR_GENERR);
859
break;
860
case LEAF_pfTablesAddrPrefix:
861
val->v.integer = (int32_t) e->pfas.pfras_a.pfra_net;
862
break;
863
case LEAF_pfTablesAddrTZero:
864
val->v.uint32 =
865
(uint32_t)(time(NULL) - e->pfas.pfras_tzero) * 100;
866
break;
867
case LEAF_pfTablesAddrBytesInPass:
868
val->v.counter64 =
869
e->pfas.pfras_bytes[PFR_DIR_IN][PFR_OP_PASS];
870
break;
871
case LEAF_pfTablesAddrBytesInBlock:
872
val->v.counter64 =
873
e->pfas.pfras_bytes[PFR_DIR_IN][PFR_OP_BLOCK];
874
break;
875
case LEAF_pfTablesAddrBytesOutPass:
876
val->v.counter64 =
877
e->pfas.pfras_bytes[PFR_DIR_OUT][PFR_OP_PASS];
878
break;
879
case LEAF_pfTablesAddrBytesOutBlock:
880
val->v.counter64 =
881
e->pfas.pfras_bytes[PFR_DIR_OUT][PFR_OP_BLOCK];
882
break;
883
case LEAF_pfTablesAddrPktsInPass:
884
val->v.counter64 =
885
e->pfas.pfras_packets[PFR_DIR_IN][PFR_OP_PASS];
886
break;
887
case LEAF_pfTablesAddrPktsInBlock:
888
val->v.counter64 =
889
e->pfas.pfras_packets[PFR_DIR_IN][PFR_OP_BLOCK];
890
break;
891
case LEAF_pfTablesAddrPktsOutPass:
892
val->v.counter64 =
893
e->pfas.pfras_packets[PFR_DIR_OUT][PFR_OP_PASS];
894
break;
895
case LEAF_pfTablesAddrPktsOutBlock:
896
val->v.counter64 =
897
e->pfas.pfras_packets[PFR_DIR_OUT][PFR_OP_BLOCK];
898
break;
899
default:
900
return (SNMP_ERR_NOSUCHNAME);
901
}
902
903
return (SNMP_ERR_NOERROR);
904
}
905
906
int
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
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
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
1032
pf_lbltable(struct snmp_context __unused *ctx, struct snmp_value *val,
1033
u_int sub, u_int __unused vindex, enum snmp_op op)
1034
{
1035
asn_subid_t which = val->var.subs[sub - 1];
1036
struct pfl_entry *e = NULL;
1037
1038
if (! started || (time(NULL) - pfl_table_age) > PFL_TABLE_MAXAGE)
1039
pfl_refresh();
1040
1041
switch (op) {
1042
case SNMP_OP_SET:
1043
return (SNMP_ERR_NOT_WRITEABLE);
1044
case SNMP_OP_GETNEXT:
1045
if ((e = NEXT_OBJECT_INT(&pfl_table,
1046
&val->var, sub)) == NULL)
1047
return (SNMP_ERR_NOSUCHNAME);
1048
val->var.len = sub + 1;
1049
val->var.subs[sub] = e->index;
1050
break;
1051
case SNMP_OP_GET:
1052
if (val->var.len - sub != 1)
1053
return (SNMP_ERR_NOSUCHNAME);
1054
if ((e = pfl_table_find(val->var.subs[sub])) == NULL)
1055
return (SNMP_ERR_NOSUCHNAME);
1056
break;
1057
1058
case SNMP_OP_COMMIT:
1059
case SNMP_OP_ROLLBACK:
1060
default:
1061
abort();
1062
}
1063
1064
switch (which) {
1065
case LEAF_pfLabelsLblName:
1066
return (string_get(val, e->name, -1));
1067
case LEAF_pfLabelsLblEvals:
1068
val->v.counter64 = e->evals;
1069
break;
1070
case LEAF_pfLabelsLblBytesIn:
1071
val->v.counter64 = e->bytes[IN];
1072
break;
1073
case LEAF_pfLabelsLblBytesOut:
1074
val->v.counter64 = e->bytes[OUT];
1075
break;
1076
case LEAF_pfLabelsLblPktsIn:
1077
val->v.counter64 = e->pkts[IN];
1078
break;
1079
case LEAF_pfLabelsLblPktsOut:
1080
val->v.counter64 = e->pkts[OUT];
1081
break;
1082
default:
1083
return (SNMP_ERR_NOSUCHNAME);
1084
}
1085
1086
return (SNMP_ERR_NOERROR);
1087
}
1088
1089
static struct pfi_entry *
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 *
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 *
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 *
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 *
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
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
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
1282
pfs_refresh(void)
1283
{
1284
if (started && this_tick <= pf_tick)
1285
return (0);
1286
1287
pfctl_free_status(pfs);
1288
pfs = pfctl_get_status_h(pfh);
1289
1290
if (pfs == NULL) {
1291
syslog(LOG_ERR, "pfs_refresh(): pfctl_get_status failure");
1292
return (-1);
1293
}
1294
1295
pf_tick = this_tick;
1296
return (0);
1297
}
1298
1299
static int
1300
pft_add_tstats(const struct pfr_tstats *t, void *arg)
1301
{
1302
struct pft_entry *e;
1303
int *index = arg;
1304
1305
e = malloc(sizeof(struct pft_entry));
1306
if (e == NULL)
1307
return (ENOMEM);
1308
1309
e->index = (*index) + 1;
1310
(*index)++;
1311
memcpy(&e->pft, t, sizeof(struct pfr_tstats));
1312
TAILQ_INSERT_TAIL(&pft_table, e, link);
1313
1314
return (0);
1315
}
1316
1317
static int
1318
pft_refresh(void)
1319
{
1320
struct pfr_table filter;
1321
struct pft_entry *e;
1322
int i, numtbls = 1;
1323
1324
while (!TAILQ_EMPTY(&pft_table)) {
1325
e = TAILQ_FIRST(&pft_table);
1326
TAILQ_REMOVE(&pft_table, e, link);
1327
free(e);
1328
}
1329
1330
bzero(&filter, sizeof(filter));
1331
1332
if (pfctl_get_tstats(pfh, &filter, pft_add_tstats, &i)) {
1333
syslog(LOG_ERR, "pft_refresh(): pfctl_get_tstats(): %s",
1334
strerror(errno));
1335
goto err1;
1336
}
1337
1338
pft_table_age = time(NULL);
1339
pft_table_count = numtbls;
1340
pf_tick = this_tick;
1341
1342
return (0);
1343
err1:
1344
while (!TAILQ_EMPTY(&pft_table)) {
1345
e = TAILQ_FIRST(&pft_table);
1346
TAILQ_REMOVE(&pft_table, e, link);
1347
free(e);
1348
}
1349
return(-1);
1350
}
1351
1352
static int
1353
pfa_table_addrs(u_int sidx, struct pfr_table *pt)
1354
{
1355
struct pfr_table tbl = { 0 };
1356
struct pfr_astats *t = NULL;
1357
struct pfa_entry *e;
1358
int i, numaddrs = 1, outnum;
1359
1360
if (pt == NULL)
1361
return (-1);
1362
1363
strlcpy(tbl.pfrt_name, pt->pfrt_name,
1364
sizeof(tbl.pfrt_name));
1365
1366
for (;;) {
1367
t = reallocf(t, numaddrs * sizeof(struct pfr_astats));
1368
if (t == NULL) {
1369
syslog(LOG_ERR, "pfa_table_addrs(): reallocf(): %s",
1370
strerror(errno));
1371
numaddrs = -1;
1372
goto error;
1373
}
1374
1375
outnum = numaddrs;
1376
if (pfctl_get_astats(pfh, &tbl, t, &outnum, 0) != 0) {
1377
syslog(LOG_ERR, "pfa_table_addrs(): ioctl() on %s: %s",
1378
pt->pfrt_name, strerror(errno));
1379
numaddrs = -1;
1380
break;
1381
}
1382
1383
if (numaddrs >= outnum)
1384
break;
1385
1386
numaddrs = outnum;
1387
}
1388
1389
for (i = 0; i < numaddrs; i++) {
1390
if ((t + i)->pfras_a.pfra_af != AF_INET &&
1391
(t + i)->pfras_a.pfra_af != AF_INET6) {
1392
numaddrs = i;
1393
break;
1394
}
1395
1396
e = (struct pfa_entry *)malloc(sizeof(struct pfa_entry));
1397
if (e == NULL) {
1398
syslog(LOG_ERR, "pfa_table_addrs(): malloc(): %s",
1399
strerror(errno));
1400
numaddrs = -1;
1401
break;
1402
}
1403
e->index = sidx + i;
1404
memcpy(&e->pfas, t + i, sizeof(struct pfr_astats));
1405
TAILQ_INSERT_TAIL(&pfa_table, e, link);
1406
}
1407
1408
free(t);
1409
error:
1410
return (numaddrs);
1411
}
1412
1413
static int
1414
pfa_refresh(void)
1415
{
1416
struct pfioc_table io;
1417
struct pfr_table *pt = NULL, *it = NULL;
1418
struct pfa_entry *e;
1419
int i, numtbls = 1, cidx, naddrs;
1420
1421
while (!TAILQ_EMPTY(&pfa_table)) {
1422
e = TAILQ_FIRST(&pfa_table);
1423
TAILQ_REMOVE(&pfa_table, e, link);
1424
free(e);
1425
}
1426
1427
memset(&io, 0, sizeof(io));
1428
io.pfrio_esize = sizeof(struct pfr_table);
1429
1430
for (;;) {
1431
pt = reallocf(pt, numtbls * sizeof(struct pfr_table));
1432
if (pt == NULL) {
1433
syslog(LOG_ERR, "pfa_refresh(): reallocf() %s",
1434
strerror(errno));
1435
return (-1);
1436
}
1437
memset(pt, 0, sizeof(*pt));
1438
io.pfrio_size = numtbls;
1439
io.pfrio_buffer = pt;
1440
1441
if (ioctl(pfctl_fd(pfh), DIOCRGETTABLES, &io)) {
1442
syslog(LOG_ERR, "pfa_refresh(): ioctl(): %s",
1443
strerror(errno));
1444
goto err2;
1445
}
1446
1447
if (numtbls >= io.pfrio_size)
1448
break;
1449
1450
numtbls = io.pfrio_size;
1451
}
1452
1453
cidx = 1;
1454
1455
for (it = pt, i = 0; i < numtbls; it++, i++) {
1456
/*
1457
* Skip the table if not active - ioctl(DIOCRGETASTATS) will
1458
* return ESRCH for this entry anyway.
1459
*/
1460
if (!(it->pfrt_flags & PFR_TFLAG_ACTIVE))
1461
continue;
1462
1463
if ((naddrs = pfa_table_addrs(cidx, it)) < 0)
1464
goto err1;
1465
1466
cidx += naddrs;
1467
}
1468
1469
pfa_table_age = time(NULL);
1470
pfa_table_count = cidx;
1471
pf_tick = this_tick;
1472
1473
free(pt);
1474
return (0);
1475
err1:
1476
while (!TAILQ_EMPTY(&pfa_table)) {
1477
e = TAILQ_FIRST(&pfa_table);
1478
TAILQ_REMOVE(&pfa_table, e, link);
1479
free(e);
1480
}
1481
1482
err2:
1483
free(pt);
1484
return (-1);
1485
}
1486
1487
static int
1488
pfl_scan_ruleset(const char *path)
1489
{
1490
struct pfctl_rules_info rules;
1491
struct pfctl_rule rule;
1492
char anchor_call[MAXPATHLEN] = "";
1493
struct pfl_entry *e;
1494
u_int32_t nr, i;
1495
1496
if (pfctl_get_rules_info_h(pfh, &rules, PF_PASS, path)) {
1497
syslog(LOG_ERR, "pfl_scan_ruleset: ioctl(DIOCGETRULES): %s",
1498
strerror(errno));
1499
goto err;
1500
}
1501
1502
for (nr = rules.nr, i = 0; i < nr; i++) {
1503
if (pfctl_get_rule_h(pfh, i, rules.ticket, path,
1504
PF_PASS, &rule, anchor_call)) {
1505
syslog(LOG_ERR, "pfl_scan_ruleset: ioctl(DIOCGETRULE):"
1506
" %s", strerror(errno));
1507
goto err;
1508
}
1509
1510
if (rule.label[0][0]) {
1511
e = (struct pfl_entry *)malloc(sizeof(*e));
1512
if (e == NULL)
1513
goto err;
1514
1515
strlcpy(e->name, path, sizeof(e->name));
1516
if (path[0])
1517
strlcat(e->name, "/", sizeof(e->name));
1518
strlcat(e->name, rule.label[0], sizeof(e->name));
1519
1520
e->evals = rule.evaluations;
1521
e->bytes[IN] = rule.bytes[IN];
1522
e->bytes[OUT] = rule.bytes[OUT];
1523
e->pkts[IN] = rule.packets[IN];
1524
e->pkts[OUT] = rule.packets[OUT];
1525
e->index = ++pfl_table_count;
1526
1527
TAILQ_INSERT_TAIL(&pfl_table, e, link);
1528
}
1529
}
1530
1531
return (0);
1532
1533
err:
1534
return (-1);
1535
}
1536
1537
static int
1538
pfl_walk_rulesets(const char *path)
1539
{
1540
struct pfioc_ruleset prs;
1541
char newpath[MAXPATHLEN];
1542
u_int32_t nr, i;
1543
1544
if (pfl_scan_ruleset(path))
1545
goto err;
1546
1547
bzero(&prs, sizeof(prs));
1548
strlcpy(prs.path, path, sizeof(prs.path));
1549
if (ioctl(pfctl_fd(pfh), DIOCGETRULESETS, &prs)) {
1550
syslog(LOG_ERR, "pfl_walk_rulesets: ioctl(DIOCGETRULESETS): %s",
1551
strerror(errno));
1552
goto err;
1553
}
1554
1555
for (nr = prs.nr, i = 0; i < nr; i++) {
1556
prs.nr = i;
1557
if (ioctl(pfctl_fd(pfh), DIOCGETRULESET, &prs)) {
1558
syslog(LOG_ERR, "pfl_walk_rulesets: ioctl(DIOCGETRULESET):"
1559
" %s", strerror(errno));
1560
goto err;
1561
}
1562
1563
if (strcmp(prs.name, PF_RESERVED_ANCHOR) == 0)
1564
continue;
1565
1566
strlcpy(newpath, path, sizeof(newpath));
1567
if (path[0])
1568
strlcat(newpath, "/", sizeof(newpath));
1569
1570
strlcat(newpath, prs.name, sizeof(newpath));
1571
if (pfl_walk_rulesets(newpath))
1572
goto err;
1573
}
1574
1575
return (0);
1576
1577
err:
1578
return (-1);
1579
}
1580
1581
static int
1582
pfl_refresh(void)
1583
{
1584
struct pfl_entry *e;
1585
1586
while (!TAILQ_EMPTY(&pfl_table)) {
1587
e = TAILQ_FIRST(&pfl_table);
1588
TAILQ_REMOVE(&pfl_table, e, link);
1589
free(e);
1590
}
1591
pfl_table_count = 0;
1592
1593
if (pfl_walk_rulesets(""))
1594
goto err;
1595
1596
pfl_table_age = time(NULL);
1597
pf_tick = this_tick;
1598
1599
return (0);
1600
1601
err:
1602
while (!TAILQ_EMPTY(&pfl_table)) {
1603
e = TAILQ_FIRST(&pfl_table);
1604
TAILQ_REMOVE(&pfl_table, e, link);
1605
free(e);
1606
}
1607
pfl_table_count = 0;
1608
1609
return (-1);
1610
}
1611
1612
/*
1613
* check whether altq support is enabled in kernel
1614
*/
1615
1616
static int
1617
altq_is_enabled(int pfdev)
1618
{
1619
struct pfioc_altq pa;
1620
1621
errno = 0;
1622
pa.version = PFIOC_ALTQ_VERSION;
1623
if (ioctl(pfdev, DIOCGETALTQS, &pa)) {
1624
if (errno == ENODEV) {
1625
syslog(LOG_INFO, "No ALTQ support in kernel\n"
1626
"ALTQ related functions disabled\n");
1627
return (0);
1628
} else {
1629
syslog(LOG_ERR, "DIOCGETALTQS returned an error: %s",
1630
strerror(errno));
1631
return (-1);
1632
}
1633
}
1634
return (1);
1635
}
1636
1637
/*
1638
* Implement the bsnmpd module interface
1639
*/
1640
static int
1641
pf_init(struct lmodule *mod, int __unused argc, char __unused *argv[])
1642
{
1643
module = mod;
1644
1645
if ((pfh = pfctl_open(PF_DEVICE)) == NULL) {
1646
syslog(LOG_ERR, "pf_init(): open(): %s\n",
1647
strerror(errno));
1648
return (-1);
1649
}
1650
1651
if ((altq_enabled = altq_is_enabled(pfctl_fd(pfh))) == -1) {
1652
syslog(LOG_ERR, "pf_init(): altq test failed");
1653
return (-1);
1654
}
1655
1656
/* Prepare internal state */
1657
TAILQ_INIT(&pfi_table);
1658
TAILQ_INIT(&pfq_table);
1659
TAILQ_INIT(&pft_table);
1660
TAILQ_INIT(&pfa_table);
1661
TAILQ_INIT(&pfl_table);
1662
1663
pfi_refresh();
1664
if (altq_enabled) {
1665
pfq_refresh();
1666
}
1667
1668
pfs_refresh();
1669
pft_refresh();
1670
pfa_refresh();
1671
pfl_refresh();
1672
1673
started = 1;
1674
1675
return (0);
1676
}
1677
1678
static int
1679
pf_fini(void)
1680
{
1681
struct pfi_entry *i1, *i2;
1682
struct pfq_entry *q1, *q2;
1683
struct pft_entry *t1, *t2;
1684
struct pfa_entry *a1, *a2;
1685
struct pfl_entry *l1, *l2;
1686
1687
/* Empty the list of interfaces */
1688
i1 = TAILQ_FIRST(&pfi_table);
1689
while (i1 != NULL) {
1690
i2 = TAILQ_NEXT(i1, link);
1691
free(i1);
1692
i1 = i2;
1693
}
1694
1695
/* List of queues */
1696
q1 = TAILQ_FIRST(&pfq_table);
1697
while (q1 != NULL) {
1698
q2 = TAILQ_NEXT(q1, link);
1699
free(q1);
1700
q1 = q2;
1701
}
1702
1703
/* List of tables */
1704
t1 = TAILQ_FIRST(&pft_table);
1705
while (t1 != NULL) {
1706
t2 = TAILQ_NEXT(t1, link);
1707
free(t1);
1708
t1 = t2;
1709
}
1710
1711
/* List of table addresses */
1712
a1 = TAILQ_FIRST(&pfa_table);
1713
while (a1 != NULL) {
1714
a2 = TAILQ_NEXT(a1, link);
1715
free(a1);
1716
a1 = a2;
1717
}
1718
1719
/* And the list of labeled filter rules */
1720
l1 = TAILQ_FIRST(&pfl_table);
1721
while (l1 != NULL) {
1722
l2 = TAILQ_NEXT(l1, link);
1723
free(l1);
1724
l1 = l2;
1725
}
1726
1727
pfctl_free_status(pfs);
1728
pfs = NULL;
1729
1730
pfctl_close(pfh);
1731
1732
return (0);
1733
}
1734
1735
static void
1736
pf_dump(void)
1737
{
1738
pfi_refresh();
1739
if (altq_enabled) {
1740
pfq_refresh();
1741
}
1742
pft_refresh();
1743
pfa_refresh();
1744
pfl_refresh();
1745
1746
syslog(LOG_ERR, "Dump: pfi_table_age = %jd",
1747
(intmax_t)pfi_table_age);
1748
syslog(LOG_ERR, "Dump: pfi_table_count = %d",
1749
pfi_table_count);
1750
1751
syslog(LOG_ERR, "Dump: pfq_table_age = %jd",
1752
(intmax_t)pfq_table_age);
1753
syslog(LOG_ERR, "Dump: pfq_table_count = %d",
1754
pfq_table_count);
1755
1756
syslog(LOG_ERR, "Dump: pft_table_age = %jd",
1757
(intmax_t)pft_table_age);
1758
syslog(LOG_ERR, "Dump: pft_table_count = %d",
1759
pft_table_count);
1760
1761
syslog(LOG_ERR, "Dump: pfa_table_age = %jd",
1762
(intmax_t)pfa_table_age);
1763
syslog(LOG_ERR, "Dump: pfa_table_count = %d",
1764
pfa_table_count);
1765
1766
syslog(LOG_ERR, "Dump: pfl_table_age = %jd",
1767
(intmax_t)pfl_table_age);
1768
syslog(LOG_ERR, "Dump: pfl_table_count = %d",
1769
pfl_table_count);
1770
}
1771
1772
const struct snmp_module config = {
1773
.comment = "This module implements a MIB for the pf packet filter.",
1774
.init = pf_init,
1775
.fini = pf_fini,
1776
.tree = pf_ctree,
1777
.dump = pf_dump,
1778
.tree_size = pf_CTREE_SIZE,
1779
};
1780
1781