]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/bsnmpd/modules/snmp_pf/pf_snmp.c
This commit was generated by cvs2svn to compensate for changes in r169808,
[FreeBSD/FreeBSD.git] / usr.sbin / bsnmpd / modules / snmp_pf / pf_snmp.c
1 /*-
2  * Copyright (c) 2005 Philip Paeps <philip@FreeBSD.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  * $FreeBSD$
27  */
28
29 #include <bsnmp/snmpmod.h>
30
31 #include <net/pfvar.h>
32 #include <sys/ioctl.h>
33
34 #include <errno.h>
35 #include <fcntl.h>
36 #include <stdint.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <syslog.h>
41 #include <unistd.h>
42
43 #include "pf_oid.h"
44 #include "pf_tree.h"
45
46 struct lmodule *module;
47
48 static int dev = -1;
49 static int started;
50 static uint64_t pf_tick;
51
52 static struct pf_status pfs;
53
54 enum { IN, OUT };
55 enum { IPV4, IPV6 };
56 enum { PASS, BLOCK };
57
58 #define PFI_IFTYPE_GROUP        0
59 #define PFI_IFTYPE_INSTANCE     1
60 #define PFI_IFTYPE_DETACHED     2
61
62 struct pfi_entry {
63         struct pfi_if   pfi;
64         u_int           index;
65         TAILQ_ENTRY(pfi_entry) link;
66 };
67 TAILQ_HEAD(pfi_table, pfi_entry);
68
69 static struct pfi_table pfi_table;
70 static time_t pfi_table_age;
71 static int pfi_table_count;
72
73 #define PFI_TABLE_MAXAGE        5
74
75 struct pft_entry {
76         struct pfr_tstats pft;
77         u_int           index;
78         TAILQ_ENTRY(pft_entry) link;
79 };
80 TAILQ_HEAD(pft_table, pft_entry);
81
82 static struct pft_table pft_table;
83 static time_t pft_table_age;
84 static int pft_table_count;
85
86 #define PFT_TABLE_MAXAGE        5
87
88 struct pfq_entry {
89         struct pf_altq  altq;
90         u_int           index;
91         TAILQ_ENTRY(pfq_entry) link;
92 };
93 TAILQ_HEAD(pfq_table, pfq_entry);
94
95 static struct pfq_table pfq_table;
96 static time_t pfq_table_age;
97 static int pfq_table_count;
98
99 static int altq_enabled = 0;
100
101 #define PFQ_TABLE_MAXAGE        5
102
103 /* Forward declarations */
104 static int pfi_refresh(void);
105 static int pfq_refresh(void);
106 static int pfs_refresh(void);
107 static int pft_refresh(void);
108 static struct pfi_entry * pfi_table_find(u_int idx);
109 static struct pfq_entry * pfq_table_find(u_int idx);
110 static struct pft_entry * pft_table_find(u_int idx);
111
112 static int altq_is_enabled(int pfdevice);
113
114 int
115 pf_status(struct snmp_context __unused *ctx, struct snmp_value *val,
116         u_int sub, u_int __unused vindex, enum snmp_op op)
117 {
118         asn_subid_t     which = val->var.subs[sub - 1];
119         time_t          runtime;
120         unsigned char   str[128];
121
122         if (op == SNMP_OP_SET)
123                 return (SNMP_ERR_NOT_WRITEABLE);
124
125         if (op == SNMP_OP_GET) {
126                 if (pfs_refresh() == -1)
127                         return (SNMP_ERR_GENERR);
128
129                 switch (which) {
130                         case LEAF_pfStatusRunning:
131                             val->v.uint32 = pfs.running;
132                             break;
133                         case LEAF_pfStatusRuntime:
134                             runtime = (pfs.since > 0) ?
135                                 time(NULL) - pfs.since : 0;
136                             val->v.uint32 = runtime * 100;
137                             break;
138                         case LEAF_pfStatusDebug:
139                             val->v.uint32 = pfs.debug;
140                             break;
141                         case LEAF_pfStatusHostId:
142                             sprintf(str, "0x%08x", ntohl(pfs.hostid));
143                             return (string_get(val, str, strlen(str)));
144
145                         default:
146                             return (SNMP_ERR_NOSUCHNAME);
147                 }
148
149                 return (SNMP_ERR_NOERROR);
150         }
151
152         abort();
153 }
154
155 int
156 pf_counter(struct snmp_context __unused *ctx, struct snmp_value *val,
157         u_int sub, u_int __unused vindex, enum snmp_op op)
158 {
159         asn_subid_t     which = val->var.subs[sub - 1];
160
161         if (op == SNMP_OP_SET)
162                 return (SNMP_ERR_NOT_WRITEABLE);
163
164         if (op == SNMP_OP_GET) {
165                 if (pfs_refresh() == -1)
166                         return (SNMP_ERR_GENERR);
167
168                 switch (which) {
169                         case LEAF_pfCounterMatch:
170                                 val->v.counter64 = pfs.counters[PFRES_MATCH];
171                                 break;
172                         case LEAF_pfCounterBadOffset:
173                                 val->v.counter64 = pfs.counters[PFRES_BADOFF];
174                                 break;
175                         case LEAF_pfCounterFragment:
176                                 val->v.counter64 = pfs.counters[PFRES_FRAG];
177                                 break;
178                         case LEAF_pfCounterShort:
179                                 val->v.counter64 = pfs.counters[PFRES_SHORT];
180                                 break;
181                         case LEAF_pfCounterNormalize:
182                                 val->v.counter64 = pfs.counters[PFRES_NORM];
183                                 break;
184                         case LEAF_pfCounterMemDrop:
185                                 val->v.counter64 = pfs.counters[PFRES_MEMORY];
186                                 break;
187
188                         default:
189                                 return (SNMP_ERR_NOSUCHNAME);
190                 }
191
192                 return (SNMP_ERR_NOERROR);
193         }
194
195         abort();
196 }
197
198 int
199 pf_statetable(struct snmp_context __unused *ctx, struct snmp_value *val,
200         u_int sub, u_int __unused vindex, enum snmp_op op)
201 {
202         asn_subid_t     which = val->var.subs[sub - 1];
203
204         if (op == SNMP_OP_SET)
205                 return (SNMP_ERR_NOT_WRITEABLE);
206
207         if (op == SNMP_OP_GET) {
208                 if (pfs_refresh() == -1)
209                         return (SNMP_ERR_GENERR);
210
211                 switch (which) {
212                         case LEAF_pfStateTableCount:
213                                 val->v.uint32 = pfs.states;
214                                 break;
215                         case LEAF_pfStateTableSearches:
216                                 val->v.counter64 =
217                                     pfs.fcounters[FCNT_STATE_SEARCH];
218                                 break;
219                         case LEAF_pfStateTableInserts:
220                                 val->v.counter64 =
221                                     pfs.fcounters[FCNT_STATE_INSERT];
222                                 break;
223                         case LEAF_pfStateTableRemovals:
224                                 val->v.counter64 =
225                                     pfs.fcounters[FCNT_STATE_REMOVALS];
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
239 pf_srcnodes(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_pfSrcNodesCount:
253                                 val->v.uint32 = pfs.src_nodes;
254                                 break;
255                         case LEAF_pfSrcNodesSearches:
256                                 val->v.counter64 =
257                                     pfs.scounters[SCNT_SRC_NODE_SEARCH];
258                                 break;
259                         case LEAF_pfSrcNodesInserts:
260                                 val->v.counter64 =
261                                     pfs.scounters[SCNT_SRC_NODE_INSERT];
262                                 break;
263                         case LEAF_pfSrcNodesRemovals:
264                                 val->v.counter64 =
265                                     pfs.scounters[SCNT_SRC_NODE_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
279 pf_limits(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         struct pfioc_limit      pl;
284
285         if (op == SNMP_OP_SET)
286                 return (SNMP_ERR_NOT_WRITEABLE);
287
288         if (op == SNMP_OP_GET) {
289                 bzero(&pl, sizeof(struct pfioc_limit));
290
291                 switch (which) {
292                         case LEAF_pfLimitsStates:
293                                 pl.index = PF_LIMIT_STATES;
294                                 break;
295                         case LEAF_pfLimitsSrcNodes:
296                                 pl.index = PF_LIMIT_SRC_NODES;
297                                 break;
298                         case LEAF_pfLimitsFrags:
299                                 pl.index = PF_LIMIT_FRAGS;
300                                 break;
301
302                         default:
303                                 return (SNMP_ERR_NOSUCHNAME);
304                 }
305
306                 if (ioctl(dev, DIOCGETLIMIT, &pl)) {
307                         syslog(LOG_ERR, "pf_limits(): ioctl(): %s",
308                             strerror(errno));
309                         return (SNMP_ERR_GENERR);
310                 }
311
312                 val->v.uint32 = pl.limit;
313
314                 return (SNMP_ERR_NOERROR);
315         }
316
317         abort();
318 }
319
320 int
321 pf_timeouts(struct snmp_context __unused *ctx, struct snmp_value *val,
322         u_int sub, u_int __unused vindex, enum snmp_op op)
323 {
324         asn_subid_t     which = val->var.subs[sub - 1];
325         struct pfioc_tm pt;
326
327         if (op == SNMP_OP_SET)
328                 return (SNMP_ERR_NOT_WRITEABLE);
329
330         if (op == SNMP_OP_GET) {
331                 bzero(&pt, sizeof(struct pfioc_tm));
332
333                 switch (which) {
334                         case LEAF_pfTimeoutsTcpFirst:
335                                 pt.timeout = PFTM_TCP_FIRST_PACKET;
336                                 break;
337                         case LEAF_pfTimeoutsTcpOpening:
338                                 pt.timeout = PFTM_TCP_OPENING;
339                                 break;
340                         case LEAF_pfTimeoutsTcpEstablished:
341                                 pt.timeout = PFTM_TCP_ESTABLISHED;
342                                 break;
343                         case LEAF_pfTimeoutsTcpClosing:
344                                 pt.timeout = PFTM_TCP_CLOSING;
345                                 break;
346                         case LEAF_pfTimeoutsTcpFinWait:
347                                 pt.timeout = PFTM_TCP_FIN_WAIT;
348                                 break;
349                         case LEAF_pfTimeoutsTcpClosed:
350                                 pt.timeout = PFTM_TCP_CLOSED;
351                                 break;
352                         case LEAF_pfTimeoutsUdpFirst:
353                                 pt.timeout = PFTM_UDP_FIRST_PACKET;
354                                 break;
355                         case LEAF_pfTimeoutsUdpSingle:
356                                 pt.timeout = PFTM_UDP_SINGLE;
357                                 break;
358                         case LEAF_pfTimeoutsUdpMultiple:
359                                 pt.timeout = PFTM_UDP_MULTIPLE;
360                                 break;
361                         case LEAF_pfTimeoutsIcmpFirst:
362                                 pt.timeout = PFTM_ICMP_FIRST_PACKET;
363                                 break;
364                         case LEAF_pfTimeoutsIcmpError:
365                                 pt.timeout = PFTM_ICMP_ERROR_REPLY;
366                                 break;
367                         case LEAF_pfTimeoutsOtherFirst:
368                                 pt.timeout = PFTM_OTHER_FIRST_PACKET;
369                                 break;
370                         case LEAF_pfTimeoutsOtherSingle:
371                                 pt.timeout = PFTM_OTHER_SINGLE;
372                                 break;
373                         case LEAF_pfTimeoutsOtherMultiple:
374                                 pt.timeout = PFTM_OTHER_MULTIPLE;
375                                 break;
376                         case LEAF_pfTimeoutsFragment:
377                                 pt.timeout = PFTM_FRAG;
378                                 break;
379                         case LEAF_pfTimeoutsInterval:
380                                 pt.timeout = PFTM_INTERVAL;
381                                 break;
382                         case LEAF_pfTimeoutsAdaptiveStart:
383                                 pt.timeout = PFTM_ADAPTIVE_START;
384                                 break;
385                         case LEAF_pfTimeoutsAdaptiveEnd:
386                                 pt.timeout = PFTM_ADAPTIVE_END;
387                                 break;
388                         case LEAF_pfTimeoutsSrcNode:
389                                 pt.timeout = PFTM_SRC_NODE;
390                                 break;
391
392                         default:
393                                 return (SNMP_ERR_NOSUCHNAME);
394                 }
395
396                 if (ioctl(dev, DIOCGETTIMEOUT, &pt)) {
397                         syslog(LOG_ERR, "pf_timeouts(): ioctl(): %s",
398                             strerror(errno));
399                         return (SNMP_ERR_GENERR);
400                 }
401
402                 val->v.integer = pt.seconds;
403
404                 return (SNMP_ERR_NOERROR);
405         }
406
407         abort();
408 }
409
410 int
411 pf_logif(struct snmp_context __unused *ctx, struct snmp_value *val,
412         u_int sub, u_int __unused vindex, enum snmp_op op)
413 {
414         asn_subid_t     which = val->var.subs[sub - 1];
415         unsigned char   str[IFNAMSIZ];
416
417         if (op == SNMP_OP_SET)
418                 return (SNMP_ERR_NOT_WRITEABLE);
419
420         if (op == SNMP_OP_GET) {
421                 if (pfs_refresh() == -1)
422                         return (SNMP_ERR_GENERR);
423
424                 switch (which) {
425                         case LEAF_pfLogInterfaceName:
426                                 strlcpy(str, pfs.ifname, sizeof str);
427                                 return (string_get(val, str, strlen(str)));
428                         case LEAF_pfLogInterfaceIp4BytesIn:
429                                 val->v.counter64 = pfs.bcounters[IPV4][IN];
430                                 break;
431                         case LEAF_pfLogInterfaceIp4BytesOut:
432                                 val->v.counter64 = pfs.bcounters[IPV4][OUT];
433                                 break;
434                         case LEAF_pfLogInterfaceIp4PktsInPass:
435                                 val->v.counter64 =
436                                     pfs.pcounters[IPV4][IN][PF_PASS];
437                                 break;
438                         case LEAF_pfLogInterfaceIp4PktsInDrop:
439                                 val->v.counter64 =
440                                     pfs.pcounters[IPV4][IN][PF_DROP];
441                                 break;
442                         case LEAF_pfLogInterfaceIp4PktsOutPass:
443                                 val->v.counter64 =
444                                     pfs.pcounters[IPV4][OUT][PF_PASS];
445                                 break;
446                         case LEAF_pfLogInterfaceIp4PktsOutDrop:
447                                 val->v.counter64 =
448                                     pfs.pcounters[IPV4][OUT][PF_DROP];
449                                 break;
450                         case LEAF_pfLogInterfaceIp6BytesIn:
451                                 val->v.counter64 = pfs.bcounters[IPV6][IN];
452                                 break;
453                         case LEAF_pfLogInterfaceIp6BytesOut:
454                                 val->v.counter64 = pfs.bcounters[IPV6][OUT];
455                                 break;
456                         case LEAF_pfLogInterfaceIp6PktsInPass:
457                                 val->v.counter64 =
458                                     pfs.pcounters[IPV6][IN][PF_PASS];
459                                 break;
460                         case LEAF_pfLogInterfaceIp6PktsInDrop:
461                                 val->v.counter64 =
462                                     pfs.pcounters[IPV6][IN][PF_DROP];
463                                 break;
464                         case LEAF_pfLogInterfaceIp6PktsOutPass:
465                                 val->v.counter64 =
466                                     pfs.pcounters[IPV6][OUT][PF_PASS];
467                                 break;
468                         case LEAF_pfLogInterfaceIp6PktsOutDrop:
469                                 val->v.counter64 =
470                                     pfs.pcounters[IPV6][OUT][PF_DROP];
471                                 break;
472
473                         default:
474                                 return (SNMP_ERR_NOSUCHNAME);
475                 }
476
477                 return (SNMP_ERR_NOERROR);
478         }
479
480         abort();
481 }
482
483 int
484 pf_interfaces(struct snmp_context __unused *ctx, struct snmp_value *val,
485         u_int sub, u_int __unused vindex, enum snmp_op op)
486 {
487         asn_subid_t     which = val->var.subs[sub - 1];
488
489         if (op == SNMP_OP_SET)
490                 return (SNMP_ERR_NOT_WRITEABLE);
491
492         if (op == SNMP_OP_GET) {
493                 if ((time(NULL) - pfi_table_age) > PFI_TABLE_MAXAGE)
494                         if (pfi_refresh() == -1)
495                             return (SNMP_ERR_GENERR);
496
497                 switch (which) {
498                         case LEAF_pfInterfacesIfNumber:
499                                 val->v.uint32 = pfi_table_count;
500                                 break;
501
502                         default:
503                                 return (SNMP_ERR_NOSUCHNAME);
504                 }
505
506                 return (SNMP_ERR_NOERROR);
507         }
508
509         abort();
510 }
511
512 int
513 pf_iftable(struct snmp_context __unused *ctx, struct snmp_value *val,
514         u_int sub, u_int __unused vindex, enum snmp_op op)
515 {
516         asn_subid_t     which = val->var.subs[sub - 1];
517         struct pfi_entry *e = NULL;
518
519         switch (op) {
520                 case SNMP_OP_SET:
521                         return (SNMP_ERR_NOT_WRITEABLE);
522                 case SNMP_OP_GETNEXT:
523                         if ((e = NEXT_OBJECT_INT(&pfi_table,
524                             &val->var, sub)) == NULL)
525                                 return (SNMP_ERR_NOSUCHNAME);
526                         val->var.len = sub + 1;
527                         val->var.subs[sub] = e->index;
528                         break;
529                 case SNMP_OP_GET:
530                         if (val->var.len - sub != 1)
531                                 return (SNMP_ERR_NOSUCHNAME);
532                         if ((e = pfi_table_find(val->var.subs[sub])) == NULL)
533                                 return (SNMP_ERR_NOSUCHNAME);
534                         break;
535
536                 case SNMP_OP_COMMIT:
537                 case SNMP_OP_ROLLBACK:
538                 default:
539                         abort();
540         }
541
542         if ((time(NULL) - pfi_table_age) > PFI_TABLE_MAXAGE)
543                 pfi_refresh();
544
545         switch (which) {
546                 case LEAF_pfInterfacesIfDescr:
547                         return (string_get(val, e->pfi.pfif_name, -1));
548                 case LEAF_pfInterfacesIfType:
549                         val->v.integer = PFI_IFTYPE_INSTANCE;
550                         break;
551                 case LEAF_pfInterfacesIfTZero:
552                         val->v.uint32 =
553                             (time(NULL) - e->pfi.pfif_tzero) * 100;
554                         break;
555                 case LEAF_pfInterfacesIfRefsState:
556                         val->v.uint32 = e->pfi.pfif_states;
557                         break;
558                 case LEAF_pfInterfacesIfRefsRule:
559                         val->v.uint32 = e->pfi.pfif_rules;
560                         break;
561                 case LEAF_pfInterfacesIf4BytesInPass:
562                         val->v.counter64 =
563                             e->pfi.pfif_bytes[IPV4][IN][PASS];
564                         break;
565                 case LEAF_pfInterfacesIf4BytesInBlock:
566                         val->v.counter64 =
567                             e->pfi.pfif_bytes[IPV4][IN][BLOCK];
568                         break;
569                 case LEAF_pfInterfacesIf4BytesOutPass:
570                         val->v.counter64 =
571                             e->pfi.pfif_bytes[IPV4][OUT][PASS];
572                         break;
573                 case LEAF_pfInterfacesIf4BytesOutBlock:
574                         val->v.counter64 =
575                             e->pfi.pfif_bytes[IPV4][OUT][BLOCK];
576                         break;
577                 case LEAF_pfInterfacesIf4PktsInPass:
578                         val->v.counter64 =
579                             e->pfi.pfif_packets[IPV4][IN][PASS];
580                         break;
581                 case LEAF_pfInterfacesIf4PktsInBlock:
582                         val->v.counter64 =
583                             e->pfi.pfif_packets[IPV4][IN][BLOCK];
584                         break;
585                 case LEAF_pfInterfacesIf4PktsOutPass:
586                         val->v.counter64 =
587                             e->pfi.pfif_packets[IPV4][OUT][PASS];
588                         break;
589                 case LEAF_pfInterfacesIf4PktsOutBlock:
590                         val->v.counter64 =
591                             e->pfi.pfif_packets[IPV4][OUT][BLOCK];
592                         break;
593                 case LEAF_pfInterfacesIf6BytesInPass:
594                         val->v.counter64 =
595                             e->pfi.pfif_bytes[IPV6][IN][PASS];
596                         break;
597                 case LEAF_pfInterfacesIf6BytesInBlock:
598                         val->v.counter64 =
599                             e->pfi.pfif_bytes[IPV6][IN][BLOCK];
600                         break;
601                 case LEAF_pfInterfacesIf6BytesOutPass:
602                         val->v.counter64 =
603                             e->pfi.pfif_bytes[IPV6][OUT][PASS];
604                         break;
605                 case LEAF_pfInterfacesIf6BytesOutBlock:
606                         val->v.counter64 =
607                             e->pfi.pfif_bytes[IPV6][OUT][BLOCK];
608                         break;
609                 case LEAF_pfInterfacesIf6PktsInPass:
610                         val->v.counter64 =
611                             e->pfi.pfif_packets[IPV6][IN][PASS];
612                         break;
613                 case LEAF_pfInterfacesIf6PktsInBlock:
614                         val->v.counter64 =
615                             e->pfi.pfif_packets[IPV6][IN][BLOCK];
616                         break;
617                 case LEAF_pfInterfacesIf6PktsOutPass:
618                         val->v.counter64 =
619                             e->pfi.pfif_packets[IPV6][OUT][PASS];
620                         break;
621                 case LEAF_pfInterfacesIf6PktsOutBlock:
622                         val->v.counter64 = 
623                             e->pfi.pfif_packets[IPV6][OUT][BLOCK];
624                         break;
625
626                 default:
627                         return (SNMP_ERR_NOSUCHNAME);
628         }
629
630         return (SNMP_ERR_NOERROR);
631 }
632
633 int
634 pf_tables(struct snmp_context __unused *ctx, struct snmp_value *val,
635         u_int sub, u_int __unused vindex, enum snmp_op op)
636 {
637         asn_subid_t     which = val->var.subs[sub - 1];
638
639         if (op == SNMP_OP_SET)
640                 return (SNMP_ERR_NOT_WRITEABLE);
641
642         if (op == SNMP_OP_GET) {
643                 if ((time(NULL) - pft_table_age) > PFT_TABLE_MAXAGE)
644                         if (pft_refresh() == -1)
645                             return (SNMP_ERR_GENERR);
646
647                 switch (which) {
648                         case LEAF_pfTablesTblNumber:
649                                 val->v.uint32 = pft_table_count;
650                                 break;
651
652                         default:
653                                 return (SNMP_ERR_NOSUCHNAME);
654                 }
655
656                 return (SNMP_ERR_NOERROR);
657         }
658
659         abort();
660 }
661
662 int
663 pf_tbltable(struct snmp_context __unused *ctx, struct snmp_value *val,
664         u_int sub, u_int __unused vindex, enum snmp_op op)
665 {
666         asn_subid_t     which = val->var.subs[sub - 1];
667         struct pft_entry *e = NULL;
668
669         switch (op) {
670                 case SNMP_OP_SET:
671                         return (SNMP_ERR_NOT_WRITEABLE);
672                 case SNMP_OP_GETNEXT:
673                         if ((e = NEXT_OBJECT_INT(&pft_table,
674                             &val->var, sub)) == NULL)
675                                 return (SNMP_ERR_NOSUCHNAME);
676                         val->var.len = sub + 1;
677                         val->var.subs[sub] = e->index;
678                         break;
679                 case SNMP_OP_GET:
680                         if (val->var.len - sub != 1)
681                                 return (SNMP_ERR_NOSUCHNAME);
682                         if ((e = pft_table_find(val->var.subs[sub])) == NULL)
683                                 return (SNMP_ERR_NOSUCHNAME);
684                         break;
685
686                 case SNMP_OP_COMMIT:
687                 case SNMP_OP_ROLLBACK:
688                 default:
689                         abort();
690         }
691
692         if ((time(NULL) - pft_table_age) > PFT_TABLE_MAXAGE)
693                 pft_refresh();
694
695         switch (which) {
696                 case LEAF_pfTablesTblDescr:
697                         return (string_get(val, e->pft.pfrts_name, -1));
698                 case LEAF_pfTablesTblCount:
699                         val->v.integer = e->pft.pfrts_cnt;
700                         break;
701                 case LEAF_pfTablesTblTZero:
702                         val->v.uint32 =
703                             (time(NULL) - e->pft.pfrts_tzero) * 100;
704                         break;
705                 case LEAF_pfTablesTblRefsAnchor:
706                         val->v.integer =
707                             e->pft.pfrts_refcnt[PFR_REFCNT_ANCHOR];
708                         break;
709                 case LEAF_pfTablesTblRefsRule:
710                         val->v.integer =
711                             e->pft.pfrts_refcnt[PFR_REFCNT_RULE];
712                         break;
713                 case LEAF_pfTablesTblEvalMatch:
714                         val->v.counter64 = e->pft.pfrts_match;
715                         break;
716                 case LEAF_pfTablesTblEvalNoMatch:
717                         val->v.counter64 = e->pft.pfrts_nomatch;
718                         break;
719                 case LEAF_pfTablesTblBytesInPass:
720                         val->v.counter64 =
721                             e->pft.pfrts_bytes[PFR_DIR_IN][PFR_OP_PASS];
722                         break;
723                 case LEAF_pfTablesTblBytesInBlock:
724                         val->v.counter64 =
725                             e->pft.pfrts_bytes[PFR_DIR_IN][PFR_OP_BLOCK];
726                         break;
727                 case LEAF_pfTablesTblBytesInXPass:
728                         val->v.counter64 =
729                             e->pft.pfrts_bytes[PFR_DIR_IN][PFR_OP_XPASS];
730                         break;
731                 case LEAF_pfTablesTblBytesOutPass:
732                         val->v.counter64 =
733                             e->pft.pfrts_bytes[PFR_DIR_OUT][PFR_OP_PASS];
734                         break;
735                 case LEAF_pfTablesTblBytesOutBlock:
736                         val->v.counter64 =
737                             e->pft.pfrts_bytes[PFR_DIR_OUT][PFR_OP_BLOCK];
738                         break;
739                 case LEAF_pfTablesTblBytesOutXPass:
740                         val->v.counter64 =
741                             e->pft.pfrts_bytes[PFR_DIR_OUT][PFR_OP_XPASS];
742                         break;
743                 case LEAF_pfTablesTblPktsInPass:
744                         val->v.counter64 =
745                             e->pft.pfrts_packets[PFR_DIR_IN][PFR_OP_PASS];
746                         break;
747                 case LEAF_pfTablesTblPktsInBlock:
748                         val->v.counter64 =
749                             e->pft.pfrts_packets[PFR_DIR_IN][PFR_OP_BLOCK];
750                         break;
751                 case LEAF_pfTablesTblPktsInXPass:
752                         val->v.counter64 =
753                             e->pft.pfrts_packets[PFR_DIR_IN][PFR_OP_XPASS];
754                         break;
755                 case LEAF_pfTablesTblPktsOutPass:
756                         val->v.counter64 =
757                             e->pft.pfrts_packets[PFR_DIR_OUT][PFR_OP_PASS];
758                         break;
759                 case LEAF_pfTablesTblPktsOutBlock:
760                         val->v.counter64 =
761                             e->pft.pfrts_packets[PFR_DIR_OUT][PFR_OP_BLOCK];
762                         break;
763                 case LEAF_pfTablesTblPktsOutXPass:
764                         val->v.counter64 =
765                             e->pft.pfrts_packets[PFR_DIR_OUT][PFR_OP_XPASS];
766                         break;
767
768                 default:
769                         return (SNMP_ERR_NOSUCHNAME);
770         }
771
772         return (SNMP_ERR_NOERROR);
773 }
774
775 int
776 pf_tbladdr(struct snmp_context __unused *ctx, struct snmp_value __unused *val,
777         u_int __unused sub, u_int __unused vindex, enum snmp_op __unused op)
778 {
779         return (SNMP_ERR_GENERR);
780 }
781
782 int
783 pf_altq(struct snmp_context __unused *ctx, struct snmp_value *val,
784         u_int sub, u_int __unused vindex, enum snmp_op op)
785 {
786         asn_subid_t     which = val->var.subs[sub - 1];
787
788         if (!altq_enabled) {
789            return (SNMP_ERR_NOERROR);
790         }
791
792         if (op == SNMP_OP_SET)
793                 return (SNMP_ERR_NOT_WRITEABLE);
794
795         if (op == SNMP_OP_GET) {
796                 if ((time(NULL) - pfq_table_age) > PFQ_TABLE_MAXAGE)
797                         if (pfq_refresh() == -1)
798                             return (SNMP_ERR_GENERR);
799
800                 switch (which) {
801                         case LEAF_pfAltqQueueNumber:
802                                 val->v.uint32 = pfq_table_count;
803                                 break;
804
805                         default:
806                                 return (SNMP_ERR_NOSUCHNAME);
807                 }
808
809                 return (SNMP_ERR_NOERROR);
810         }
811
812         abort();
813         return (SNMP_ERR_GENERR);
814 }       
815
816 int
817 pf_altqq(struct snmp_context __unused *ctx, struct snmp_value *val,
818         u_int sub, u_int __unused vindex, enum snmp_op op)
819 {
820         asn_subid_t     which = val->var.subs[sub - 1];
821         struct pfq_entry *e = NULL;
822
823         if (!altq_enabled) {
824            return (SNMP_ERR_NOERROR);
825         }
826
827         switch (op) {
828                 case SNMP_OP_SET:
829                         return (SNMP_ERR_NOT_WRITEABLE);
830                 case SNMP_OP_GETNEXT:
831                         if ((e = NEXT_OBJECT_INT(&pfq_table,
832                             &val->var, sub)) == NULL)
833                                 return (SNMP_ERR_NOSUCHNAME);
834                         val->var.len = sub + 1;
835                         val->var.subs[sub] = e->index;
836                         break;
837                 case SNMP_OP_GET:
838                         if (val->var.len - sub != 1)
839                                 return (SNMP_ERR_NOSUCHNAME);
840                         if ((e = pfq_table_find(val->var.subs[sub])) == NULL)
841                                 return (SNMP_ERR_NOSUCHNAME);
842                         break;
843
844                 case SNMP_OP_COMMIT:
845                 case SNMP_OP_ROLLBACK:
846                 default:
847                         abort();
848         }
849
850         if ((time(NULL) - pfq_table_age) > PFQ_TABLE_MAXAGE)
851                 pfq_refresh();
852
853         switch (which) {
854                 case LEAF_pfAltqQueueDescr:
855                         return (string_get(val, e->altq.qname, -1));
856                 case LEAF_pfAltqQueueParent:
857                         return (string_get(val, e->altq.parent, -1));
858                 case LEAF_pfAltqQueueScheduler:
859                         val->v.integer = e->altq.scheduler;
860                         break;
861                 case LEAF_pfAltqQueueBandwidth:
862                         val->v.uint32 = e->altq.bandwidth;
863                         break;
864                 case LEAF_pfAltqQueuePriority:
865                         val->v.integer = e->altq.priority;
866                         break;
867                 case LEAF_pfAltqQueueLimit:
868                         val->v.integer = e->altq.qlimit;
869                         break;
870                 
871                 default:
872                         return (SNMP_ERR_NOSUCHNAME);
873         }
874
875         return (SNMP_ERR_NOERROR);
876 }       
877
878 static struct pfi_entry *
879 pfi_table_find(u_int idx)
880 {
881         struct pfi_entry *e;
882
883         TAILQ_FOREACH(e, &pfi_table, link)
884                 if (e->index == idx)
885                         return (e);
886         return (NULL);
887 }
888
889 static struct pfq_entry *
890 pfq_table_find(u_int idx)
891 {
892         struct pfq_entry *e;
893         TAILQ_FOREACH(e, &pfq_table, link)
894                 if (e->index == idx)
895                         return (e);
896         return (NULL);
897 }
898
899 static struct pft_entry *
900 pft_table_find(u_int idx)
901 {
902         struct pft_entry *e;
903
904         TAILQ_FOREACH(e, &pft_table, link)
905                 if (e->index == idx)
906                         return (e);
907         return (NULL);
908 }
909
910 static int
911 pfi_refresh(void)
912 {
913         struct pfioc_iface io;
914         struct pfi_if *p = NULL;
915         struct pfi_entry *e;
916         int i, numifs = 1;
917
918         if (started && this_tick <= pf_tick)
919                 return (0);
920
921         while (!TAILQ_EMPTY(&pfi_table)) {
922                 e = TAILQ_FIRST(&pfi_table);
923                 TAILQ_REMOVE(&pfi_table, e, link);
924                 free(e);
925         }
926
927         bzero(&io, sizeof(io));
928         io.pfiio_flags = PFI_FLAG_INSTANCE;
929         io.pfiio_esize = sizeof(struct pfi_if);
930
931         for (;;) {
932                 p = reallocf(p, numifs * sizeof(struct pfi_if));
933                 if (p == NULL) {
934                         syslog(LOG_ERR, "pfi_refresh(): reallocf() numifs=%d: %s",
935                             numifs, strerror(errno));
936                         goto err2;
937                 }
938                 io.pfiio_size = numifs;
939                 io.pfiio_buffer = p;
940
941                 if (ioctl(dev, DIOCIGETIFACES, &io)) {
942                         syslog(LOG_ERR, "pfi_refresh(): ioctl(): %s",
943                             strerror(errno));
944                         goto err2;
945                 }
946
947                 if (numifs >= io.pfiio_size)
948                         break;
949
950                 numifs = io.pfiio_size;
951         }
952
953         for (i = 0; i < numifs; i++) {
954                 e = malloc(sizeof(struct pfi_entry));
955                 if (e == NULL)
956                         goto err1;
957                 e->index = i + 1;
958                 memcpy(&e->pfi, p+i, sizeof(struct pfi_if));
959                 TAILQ_INSERT_TAIL(&pfi_table, e, link);
960         }
961
962         pfi_table_age = time(NULL);
963         pfi_table_count = numifs;
964         pf_tick = this_tick;
965
966         free(p);
967         return (0);
968
969 err1:
970         while (!TAILQ_EMPTY(&pfi_table)) {
971                 e = TAILQ_FIRST(&pfi_table);
972                 TAILQ_REMOVE(&pfi_table, e, link);
973                 free(e);
974         }
975 err2:
976         free(p);
977         return(-1);
978 }
979
980 static int
981 pfq_refresh(void)
982 {
983         struct pfioc_altq pa;
984         struct pfq_entry *e;
985         int i, numqs, ticket;
986
987         if (started && this_tick <= pf_tick)
988                 return (0);
989
990         while (!TAILQ_EMPTY(&pfq_table)) {
991                 e = TAILQ_FIRST(&pfq_table);
992                 TAILQ_REMOVE(&pfq_table, e, link);
993                 free(e);
994         }
995
996         bzero(&pa, sizeof(pa));
997         
998         if (ioctl(dev, DIOCGETALTQS, &pa)) {
999                 syslog(LOG_ERR, "pfq_refresh: ioctl(DIOCGETALTQS): %s",
1000                     strerror(errno));
1001                 return (-1);
1002         }
1003
1004         numqs = pa.nr;
1005         ticket = pa.ticket;
1006
1007         for (i = 0; i < numqs; i++) {
1008                 e = malloc(sizeof(struct pfq_entry));
1009                 if (e == NULL) {
1010                         syslog(LOG_ERR, "pfq_refresh(): "
1011                             "malloc(): %s",
1012                             strerror(errno));
1013                         goto err;
1014                 }
1015                 pa.ticket = ticket;
1016                 pa.nr = i;
1017
1018                 if (ioctl(dev, DIOCGETALTQ, &pa)) {
1019                         syslog(LOG_ERR, "pfq_refresh(): "
1020                             "ioctl(DIOCGETALTQ): %s",
1021                             strerror(errno));
1022                         goto err;
1023                 }
1024
1025                 if (pa.altq.qid > 0) {
1026                         memcpy(&e->altq, &pa.altq, sizeof(struct pf_altq));
1027                         e->index = pa.altq.qid;
1028                         pfq_table_count = i;
1029                         TAILQ_INSERT_TAIL(&pfq_table, e, link);
1030                 }
1031         }
1032         
1033         pfq_table_age = time(NULL);
1034         pf_tick = this_tick;
1035
1036         return (0);
1037 err:
1038         free(e);
1039         while (!TAILQ_EMPTY(&pfq_table)) {
1040                 e = TAILQ_FIRST(&pfq_table);
1041                 TAILQ_REMOVE(&pfq_table, e, link);
1042                 free(e);
1043         }
1044         return(-1);
1045 }
1046
1047 static int
1048 pfs_refresh(void)
1049 {
1050         if (started && this_tick <= pf_tick)
1051                 return (0);
1052
1053         bzero(&pfs, sizeof(struct pf_status));
1054
1055         if (ioctl(dev, DIOCGETSTATUS, &pfs)) {
1056                 syslog(LOG_ERR, "pfs_refresh(): ioctl(): %s",
1057                     strerror(errno));
1058                 return (-1);
1059         }
1060
1061         pf_tick = this_tick;
1062         return (0);
1063 }
1064
1065 static int
1066 pft_refresh(void)
1067 {
1068         struct pfioc_table io;
1069         struct pfr_tstats *t = NULL;
1070         struct pft_entry *e;
1071         int i, numtbls = 1;
1072
1073         if (started && this_tick <= pf_tick)
1074                 return (0);
1075
1076         while (!TAILQ_EMPTY(&pft_table)) {
1077                 e = TAILQ_FIRST(&pft_table);
1078                 TAILQ_REMOVE(&pft_table, e, link);
1079                 free(e);
1080         }
1081
1082         bzero(&io, sizeof(io));
1083         io.pfrio_esize = sizeof(struct pfr_tstats);
1084
1085         for (;;) {
1086                 t = reallocf(t, numtbls * sizeof(struct pfr_tstats));
1087                 if (t == NULL) {
1088                         syslog(LOG_ERR, "pft_refresh(): reallocf() numtbls=%d: %s",
1089                             numtbls, strerror(errno));
1090                         goto err2;
1091                 }
1092                 io.pfrio_size = numtbls;
1093                 io.pfrio_buffer = t;
1094
1095                 if (ioctl(dev, DIOCRGETTSTATS, &io)) {
1096                         syslog(LOG_ERR, "pft_refresh(): ioctl(): %s",
1097                             strerror(errno));
1098                         goto err2;
1099                 }
1100
1101                 if (numtbls >= io.pfrio_size)
1102                         break;
1103
1104                 numtbls = io.pfrio_size;
1105         }
1106
1107         for (i = 0; i < numtbls; i++) {
1108                 e = malloc(sizeof(struct pfr_tstats));
1109                 if (e == NULL)
1110                         goto err1;
1111                 e->index = i + 1;
1112                 memcpy(&e->pft, t+i, sizeof(struct pfr_tstats));
1113                 TAILQ_INSERT_TAIL(&pft_table, e, link);
1114         }
1115
1116         pft_table_age = time(NULL);
1117         pft_table_count = numtbls;
1118         pf_tick = this_tick;
1119
1120         free(t);
1121         return (0);
1122 err1:
1123         while (!TAILQ_EMPTY(&pft_table)) {
1124                 e = TAILQ_FIRST(&pft_table);
1125                 TAILQ_REMOVE(&pft_table, e, link);
1126                 free(e);
1127         }
1128 err2:
1129         free(t);
1130         return(-1);
1131 }
1132
1133 /*
1134  * check whether altq support is enabled in kernel
1135  */
1136
1137 static int
1138 altq_is_enabled(int pfdev)
1139 {
1140         struct pfioc_altq pa;
1141
1142         errno = 0;
1143         if (ioctl(pfdev, DIOCGETALTQS, &pa)) {
1144                 if (errno == ENODEV) {
1145                         syslog(LOG_INFO, "No ALTQ support in kernel\n"
1146                             "ALTQ related functions disabled\n");
1147                         return (0);
1148                 } else  
1149                         syslog(LOG_ERR, "DIOCGETALTQS returned an error: %s",
1150                             strerror(errno));
1151                         return (-1);
1152         }
1153         return (1);
1154 }
1155
1156 /*
1157  * Implement the bsnmpd module interface
1158  */
1159 static int
1160 pf_init(struct lmodule *mod, int __unused argc, char __unused *argv[])
1161 {
1162         module = mod;
1163
1164         if ((dev = open("/dev/pf", O_RDONLY)) == -1) {
1165                 syslog(LOG_ERR, "pf_init(): open(): %s\n",
1166                     strerror(errno));
1167                 return (-1);
1168         }
1169
1170         if ((altq_enabled = altq_is_enabled(dev)) == -1) {
1171                 syslog(LOG_ERR, "pf_init(): altq test failed");
1172                 return (-1);
1173         }
1174         
1175         /* Prepare internal state */
1176         TAILQ_INIT(&pfi_table);
1177         TAILQ_INIT(&pfq_table);
1178         TAILQ_INIT(&pft_table);
1179
1180         pfi_refresh();
1181         if (altq_enabled) {
1182                 pfq_refresh();
1183         }
1184
1185         pfs_refresh();
1186         pft_refresh();
1187
1188         started = 1;
1189
1190         return (0);
1191 }
1192
1193 static int
1194 pf_fini(void)
1195 {
1196         struct pfi_entry *i1, *i2;
1197         struct pfq_entry *q1, *q2;
1198         struct pft_entry *t1, *t2;
1199
1200         /* Empty the list of interfaces */
1201         i1 = TAILQ_FIRST(&pfi_table);
1202         while (i1 != NULL) {
1203                 i2 = TAILQ_NEXT(i1, link);
1204                 free(i1);
1205                 i1 = i2;
1206         }
1207
1208         /* List of queues */
1209         q1 = TAILQ_FIRST(&pfq_table);
1210         while (q1 != NULL) {
1211                 q2 = TAILQ_NEXT(q1, link);
1212                 free(q1);
1213                 q1 = q2;
1214         }
1215
1216         /* And the list of tables */
1217         t1 = TAILQ_FIRST(&pft_table);
1218         while (t1 != NULL) {
1219                 t2 = TAILQ_NEXT(t1, link);
1220                 free(t1);
1221                 t1 = t2;
1222         }
1223
1224         close(dev);
1225         return (0);
1226 }
1227
1228 static void
1229 pf_dump(void)
1230 {
1231         pfi_refresh();
1232         if (altq_enabled) {
1233                 pfq_refresh();
1234         }
1235         pft_refresh();
1236
1237         syslog(LOG_ERR, "Dump: pfi_table_age = %jd",
1238             (intmax_t)pfi_table_age);
1239         syslog(LOG_ERR, "Dump: pfi_table_count = %d",
1240             pfi_table_count);
1241         
1242         syslog(LOG_ERR, "Dump: pfq_table_age = %jd",
1243             (intmax_t)pfq_table_age);
1244         syslog(LOG_ERR, "Dump: pfq_table_count = %d",
1245             pfq_table_count);
1246
1247         syslog(LOG_ERR, "Dump: pft_table_age = %jd",
1248             (intmax_t)pft_table_age);
1249
1250         syslog(LOG_ERR, "Dump: pft_table_count = %d",
1251             pft_table_count);
1252 }
1253
1254 const struct snmp_module config = {
1255         .comment = "This module implements a MIB for the pf packet filter.",
1256         .init =         pf_init,
1257         .fini =         pf_fini,
1258         .tree =         pf_ctree,
1259         .dump =         pf_dump,
1260         .tree_size =    pf_CTREE_SIZE,
1261 };