Path: blob/main/usr.sbin/bsnmpd/modules/snmp_pf/pf_snmp.c
107769 views
/*-1* SPDX-License-Identifier: BSD-2-Clause2*3* Copyright (c) 2005 Philip Paeps <[email protected]>4* All rights reserved.5*6* Redistribution and use in source and binary forms, with or without7* modification, are permitted provided that the following conditions8* are met:9* 1. Redistributions of source code must retain the above copyright10* notice, this list of conditions and the following disclaimer.11* 2. Redistributions in binary form must reproduce the above copyright12* notice, this list of conditions and the following disclaimer in the13* documentation and/or other materials provided with the distribution.14*15* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND16* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE17* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE18* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE19* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL20* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS21* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)22* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT23* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY24* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF25* SUCH DAMAGE.26*/2728#define PFIOC_USE_LATEST2930#include <sys/queue.h>31#include <bsnmp/snmpmod.h>3233#include <net/pfvar.h>34#include <sys/ioctl.h>3536#include <errno.h>37#include <fcntl.h>38#include <libpfctl.h>39#include <stdint.h>40#include <stdio.h>41#include <stdlib.h>42#include <string.h>43#include <syslog.h>44#include <unistd.h>4546#define SNMPTREE_TYPES47#include "pf_oid.h"48#include "pf_tree.h"4950struct lmodule *module;5152static struct pfctl_handle *pfh;53static int started;54static uint64_t pf_tick;5556static struct pfctl_status *pfs;5758enum { IN, OUT };59enum { IPV4, IPV6 };60enum { PASS, BLOCK };6162#define PFI_IFTYPE_GROUP 063#define PFI_IFTYPE_INSTANCE 164#define PFI_IFTYPE_DETACHED 26566struct pfi_entry {67struct pfi_kif pfi;68u_int index;69TAILQ_ENTRY(pfi_entry) link;70};71TAILQ_HEAD(pfi_table, pfi_entry);7273static struct pfi_table pfi_table;74static time_t pfi_table_age;75static int pfi_table_count;7677#define PFI_TABLE_MAXAGE 57879struct pft_entry {80struct pfr_tstats pft;81u_int index;82TAILQ_ENTRY(pft_entry) link;83};84TAILQ_HEAD(pft_table, pft_entry);8586static struct pft_table pft_table;87static time_t pft_table_age;88static int pft_table_count;8990#define PFT_TABLE_MAXAGE 59192struct pfa_entry {93struct pfr_astats pfas;94u_int index;95TAILQ_ENTRY(pfa_entry) link;96};97TAILQ_HEAD(pfa_table, pfa_entry);9899static struct pfa_table pfa_table;100static time_t pfa_table_age;101static int pfa_table_count;102103#define PFA_TABLE_MAXAGE 5104105struct pfq_entry {106struct pf_altq altq;107u_int index;108TAILQ_ENTRY(pfq_entry) link;109};110TAILQ_HEAD(pfq_table, pfq_entry);111112static struct pfq_table pfq_table;113static time_t pfq_table_age;114static int pfq_table_count;115116static int altq_enabled = 0;117118#define PFQ_TABLE_MAXAGE 5119120struct pfl_entry {121char name[MAXPATHLEN + PF_RULE_LABEL_SIZE];122u_int64_t evals;123u_int64_t bytes[2];124u_int64_t pkts[2];125u_int index;126TAILQ_ENTRY(pfl_entry) link;127};128TAILQ_HEAD(pfl_table, pfl_entry);129130static struct pfl_table pfl_table;131static time_t pfl_table_age;132static int pfl_table_count;133134#define PFL_TABLE_MAXAGE 5135136/* Forward declarations */137static int pfi_refresh(void);138static int pfq_refresh(void);139static int pfs_refresh(void);140static int pft_refresh(void);141static int pfa_refresh(void);142static int pfl_refresh(void);143static struct pfi_entry * pfi_table_find(u_int idx);144static struct pfq_entry * pfq_table_find(u_int idx);145static struct pft_entry * pft_table_find(u_int idx);146static struct pfa_entry * pfa_table_find(u_int idx);147static struct pfl_entry * pfl_table_find(u_int idx);148149static int altq_is_enabled(int pfdevice);150151int152pf_status(struct snmp_context __unused *ctx, struct snmp_value *val,153u_int sub, u_int __unused vindex, enum snmp_op op)154{155asn_subid_t which = val->var.subs[sub - 1];156time_t runtime;157unsigned char str[128];158159if (op == SNMP_OP_SET)160return (SNMP_ERR_NOT_WRITEABLE);161162if (op == SNMP_OP_GET) {163if (pfs_refresh() == -1)164return (SNMP_ERR_GENERR);165166switch (which) {167case LEAF_pfStatusRunning:168val->v.uint32 = pfs->running;169break;170case LEAF_pfStatusRuntime:171runtime = (pfs->since > 0) ?172time(NULL) - pfs->since : 0;173val->v.uint32 = (uint32_t)(runtime * 100);174break;175case LEAF_pfStatusDebug:176val->v.uint32 = pfs->debug;177break;178case LEAF_pfStatusHostId:179sprintf(str, "0x%08x", ntohl(pfs->hostid));180return (string_get(val, str, strlen(str)));181182default:183return (SNMP_ERR_NOSUCHNAME);184}185186return (SNMP_ERR_NOERROR);187}188189abort();190}191192int193pf_counter(struct snmp_context __unused *ctx, struct snmp_value *val,194u_int sub, u_int __unused vindex, enum snmp_op op)195{196asn_subid_t which = val->var.subs[sub - 1];197198if (op == SNMP_OP_SET)199return (SNMP_ERR_NOT_WRITEABLE);200201if (op == SNMP_OP_GET) {202if (pfs_refresh() == -1)203return (SNMP_ERR_GENERR);204205switch (which) {206case LEAF_pfCounterMatch:207val->v.counter64 = pfctl_status_counter(pfs, PFRES_MATCH);208break;209case LEAF_pfCounterBadOffset:210val->v.counter64 = pfctl_status_counter(pfs, PFRES_BADOFF);211break;212case LEAF_pfCounterFragment:213val->v.counter64 = pfctl_status_counter(pfs, PFRES_FRAG);214break;215case LEAF_pfCounterShort:216val->v.counter64 = pfctl_status_counter(pfs, PFRES_SHORT);217break;218case LEAF_pfCounterNormalize:219val->v.counter64 = pfctl_status_counter(pfs, PFRES_NORM);220break;221case LEAF_pfCounterMemDrop:222val->v.counter64 = pfctl_status_counter(pfs, PFRES_MEMORY);223break;224225default:226return (SNMP_ERR_NOSUCHNAME);227}228229return (SNMP_ERR_NOERROR);230}231232abort();233}234235int236pf_statetable(struct snmp_context __unused *ctx, struct snmp_value *val,237u_int sub, u_int __unused vindex, enum snmp_op op)238{239asn_subid_t which = val->var.subs[sub - 1];240241if (op == SNMP_OP_SET)242return (SNMP_ERR_NOT_WRITEABLE);243244if (op == SNMP_OP_GET) {245if (pfs_refresh() == -1)246return (SNMP_ERR_GENERR);247248switch (which) {249case LEAF_pfStateTableCount:250val->v.uint32 = pfs->states;251break;252case LEAF_pfStateTableSearches:253val->v.counter64 =254pfctl_status_fcounter(pfs, FCNT_STATE_SEARCH);255break;256case LEAF_pfStateTableInserts:257val->v.counter64 =258pfctl_status_fcounter(pfs, FCNT_STATE_INSERT);259break;260case LEAF_pfStateTableRemovals:261val->v.counter64 =262pfctl_status_fcounter(pfs, FCNT_STATE_REMOVALS);263break;264265default:266return (SNMP_ERR_NOSUCHNAME);267}268269return (SNMP_ERR_NOERROR);270}271272abort();273}274275int276pf_srcnodes(struct snmp_context __unused *ctx, struct snmp_value *val,277u_int sub, u_int __unused vindex, enum snmp_op op)278{279asn_subid_t which = val->var.subs[sub - 1];280281if (op == SNMP_OP_SET)282return (SNMP_ERR_NOT_WRITEABLE);283284if (op == SNMP_OP_GET) {285if (pfs_refresh() == -1)286return (SNMP_ERR_GENERR);287288switch (which) {289case LEAF_pfSrcNodesCount:290val->v.uint32 = pfs->src_nodes;291break;292case LEAF_pfSrcNodesSearches:293val->v.counter64 =294pfctl_status_scounter(pfs, SCNT_SRC_NODE_SEARCH);295break;296case LEAF_pfSrcNodesInserts:297val->v.counter64 =298pfctl_status_scounter(pfs, SCNT_SRC_NODE_INSERT);299break;300case LEAF_pfSrcNodesRemovals:301val->v.counter64 =302pfctl_status_scounter(pfs, SCNT_SRC_NODE_REMOVALS);303break;304305default:306return (SNMP_ERR_NOSUCHNAME);307}308309return (SNMP_ERR_NOERROR);310}311312abort();313}314315int316pf_limits(struct snmp_context __unused *ctx, struct snmp_value *val,317u_int sub, u_int __unused vindex, enum snmp_op op)318{319asn_subid_t which = val->var.subs[sub - 1];320unsigned int index, limit;321322if (op == SNMP_OP_SET)323return (SNMP_ERR_NOT_WRITEABLE);324325if (op == SNMP_OP_GET) {326switch (which) {327case LEAF_pfLimitsStates:328index = PF_LIMIT_STATES;329break;330case LEAF_pfLimitsSrcNodes:331index = PF_LIMIT_SRC_NODES;332break;333case LEAF_pfLimitsFrags:334index = PF_LIMIT_FRAGS;335break;336337default:338return (SNMP_ERR_NOSUCHNAME);339}340341if (pfctl_get_limit(pfh, index, &limit)) {342syslog(LOG_ERR, "pf_limits(): ioctl(): %s",343strerror(errno));344return (SNMP_ERR_GENERR);345}346347val->v.uint32 = limit;348349return (SNMP_ERR_NOERROR);350}351352abort();353}354355int356pf_timeouts(struct snmp_context __unused *ctx, struct snmp_value *val,357u_int sub, u_int __unused vindex, enum snmp_op op)358{359asn_subid_t which = val->var.subs[sub - 1];360struct pfioc_tm pt;361362if (op == SNMP_OP_SET)363return (SNMP_ERR_NOT_WRITEABLE);364365if (op == SNMP_OP_GET) {366bzero(&pt, sizeof(struct pfioc_tm));367368switch (which) {369case LEAF_pfTimeoutsTcpFirst:370pt.timeout = PFTM_TCP_FIRST_PACKET;371break;372case LEAF_pfTimeoutsTcpOpening:373pt.timeout = PFTM_TCP_OPENING;374break;375case LEAF_pfTimeoutsTcpEstablished:376pt.timeout = PFTM_TCP_ESTABLISHED;377break;378case LEAF_pfTimeoutsTcpClosing:379pt.timeout = PFTM_TCP_CLOSING;380break;381case LEAF_pfTimeoutsTcpFinWait:382pt.timeout = PFTM_TCP_FIN_WAIT;383break;384case LEAF_pfTimeoutsTcpClosed:385pt.timeout = PFTM_TCP_CLOSED;386break;387case LEAF_pfTimeoutsUdpFirst:388pt.timeout = PFTM_UDP_FIRST_PACKET;389break;390case LEAF_pfTimeoutsUdpSingle:391pt.timeout = PFTM_UDP_SINGLE;392break;393case LEAF_pfTimeoutsUdpMultiple:394pt.timeout = PFTM_UDP_MULTIPLE;395break;396case LEAF_pfTimeoutsIcmpFirst:397pt.timeout = PFTM_ICMP_FIRST_PACKET;398break;399case LEAF_pfTimeoutsIcmpError:400pt.timeout = PFTM_ICMP_ERROR_REPLY;401break;402case LEAF_pfTimeoutsOtherFirst:403pt.timeout = PFTM_OTHER_FIRST_PACKET;404break;405case LEAF_pfTimeoutsOtherSingle:406pt.timeout = PFTM_OTHER_SINGLE;407break;408case LEAF_pfTimeoutsOtherMultiple:409pt.timeout = PFTM_OTHER_MULTIPLE;410break;411case LEAF_pfTimeoutsFragment:412pt.timeout = PFTM_FRAG;413break;414case LEAF_pfTimeoutsInterval:415pt.timeout = PFTM_INTERVAL;416break;417case LEAF_pfTimeoutsAdaptiveStart:418pt.timeout = PFTM_ADAPTIVE_START;419break;420case LEAF_pfTimeoutsAdaptiveEnd:421pt.timeout = PFTM_ADAPTIVE_END;422break;423case LEAF_pfTimeoutsSrcNode:424pt.timeout = PFTM_SRC_NODE;425break;426427default:428return (SNMP_ERR_NOSUCHNAME);429}430431if (ioctl(pfctl_fd(pfh), DIOCGETTIMEOUT, &pt)) {432syslog(LOG_ERR, "pf_timeouts(): ioctl(): %s",433strerror(errno));434return (SNMP_ERR_GENERR);435}436437val->v.integer = pt.seconds;438439return (SNMP_ERR_NOERROR);440}441442abort();443}444445int446pf_logif(struct snmp_context __unused *ctx, struct snmp_value *val,447u_int sub, u_int __unused vindex, enum snmp_op op)448{449asn_subid_t which = val->var.subs[sub - 1];450unsigned char str[IFNAMSIZ];451452if (op == SNMP_OP_SET)453return (SNMP_ERR_NOT_WRITEABLE);454455if (op == SNMP_OP_GET) {456if (pfs_refresh() == -1)457return (SNMP_ERR_GENERR);458459switch (which) {460case LEAF_pfLogInterfaceName:461strlcpy(str, pfs->ifname, sizeof str);462return (string_get(val, str, strlen(str)));463case LEAF_pfLogInterfaceIp4BytesIn:464val->v.counter64 = pfs->bcounters[IPV4][IN];465break;466case LEAF_pfLogInterfaceIp4BytesOut:467val->v.counter64 = pfs->bcounters[IPV4][OUT];468break;469case LEAF_pfLogInterfaceIp4PktsInPass:470val->v.counter64 =471pfs->pcounters[IPV4][IN][PF_PASS];472break;473case LEAF_pfLogInterfaceIp4PktsInDrop:474val->v.counter64 =475pfs->pcounters[IPV4][IN][PF_DROP];476break;477case LEAF_pfLogInterfaceIp4PktsOutPass:478val->v.counter64 =479pfs->pcounters[IPV4][OUT][PF_PASS];480break;481case LEAF_pfLogInterfaceIp4PktsOutDrop:482val->v.counter64 =483pfs->pcounters[IPV4][OUT][PF_DROP];484break;485case LEAF_pfLogInterfaceIp6BytesIn:486val->v.counter64 = pfs->bcounters[IPV6][IN];487break;488case LEAF_pfLogInterfaceIp6BytesOut:489val->v.counter64 = pfs->bcounters[IPV6][OUT];490break;491case LEAF_pfLogInterfaceIp6PktsInPass:492val->v.counter64 =493pfs->pcounters[IPV6][IN][PF_PASS];494break;495case LEAF_pfLogInterfaceIp6PktsInDrop:496val->v.counter64 =497pfs->pcounters[IPV6][IN][PF_DROP];498break;499case LEAF_pfLogInterfaceIp6PktsOutPass:500val->v.counter64 =501pfs->pcounters[IPV6][OUT][PF_PASS];502break;503case LEAF_pfLogInterfaceIp6PktsOutDrop:504val->v.counter64 =505pfs->pcounters[IPV6][OUT][PF_DROP];506break;507508default:509return (SNMP_ERR_NOSUCHNAME);510}511512return (SNMP_ERR_NOERROR);513}514515abort();516}517518int519pf_interfaces(struct snmp_context __unused *ctx, struct snmp_value *val,520u_int sub, u_int __unused vindex, enum snmp_op op)521{522asn_subid_t which = val->var.subs[sub - 1];523524if (op == SNMP_OP_SET)525return (SNMP_ERR_NOT_WRITEABLE);526527if (op == SNMP_OP_GET) {528if ((time(NULL) - pfi_table_age) > PFI_TABLE_MAXAGE)529if (pfi_refresh() == -1)530return (SNMP_ERR_GENERR);531532switch (which) {533case LEAF_pfInterfacesIfNumber:534val->v.uint32 = pfi_table_count;535break;536537default:538return (SNMP_ERR_NOSUCHNAME);539}540541return (SNMP_ERR_NOERROR);542}543544abort();545}546547int548pf_iftable(struct snmp_context __unused *ctx, struct snmp_value *val,549u_int sub, u_int __unused vindex, enum snmp_op op)550{551asn_subid_t which = val->var.subs[sub - 1];552struct pfi_entry *e = NULL;553554if ((time(NULL) - pfi_table_age) > PFI_TABLE_MAXAGE)555pfi_refresh();556557switch (op) {558case SNMP_OP_SET:559return (SNMP_ERR_NOT_WRITEABLE);560case SNMP_OP_GETNEXT:561if ((e = NEXT_OBJECT_INT(&pfi_table,562&val->var, sub)) == NULL)563return (SNMP_ERR_NOSUCHNAME);564val->var.len = sub + 1;565val->var.subs[sub] = e->index;566break;567case SNMP_OP_GET:568if (val->var.len - sub != 1)569return (SNMP_ERR_NOSUCHNAME);570if ((e = pfi_table_find(val->var.subs[sub])) == NULL)571return (SNMP_ERR_NOSUCHNAME);572break;573574case SNMP_OP_COMMIT:575case SNMP_OP_ROLLBACK:576default:577abort();578}579580switch (which) {581case LEAF_pfInterfacesIfDescr:582return (string_get(val, e->pfi.pfik_name, -1));583case LEAF_pfInterfacesIfType:584val->v.integer = PFI_IFTYPE_INSTANCE;585break;586case LEAF_pfInterfacesIfTZero:587val->v.uint32 =588(uint32_t)(time(NULL) - e->pfi.pfik_tzero) * 100;589break;590case LEAF_pfInterfacesIfRefsRule:591val->v.uint32 = e->pfi.pfik_rulerefs;592break;593case LEAF_pfInterfacesIf4BytesInPass:594val->v.counter64 =595e->pfi.pfik_bytes[IPV4][IN][PASS];596break;597case LEAF_pfInterfacesIf4BytesInBlock:598val->v.counter64 =599e->pfi.pfik_bytes[IPV4][IN][BLOCK];600break;601case LEAF_pfInterfacesIf4BytesOutPass:602val->v.counter64 =603e->pfi.pfik_bytes[IPV4][OUT][PASS];604break;605case LEAF_pfInterfacesIf4BytesOutBlock:606val->v.counter64 =607e->pfi.pfik_bytes[IPV4][OUT][BLOCK];608break;609case LEAF_pfInterfacesIf4PktsInPass:610val->v.counter64 =611e->pfi.pfik_packets[IPV4][IN][PASS];612break;613case LEAF_pfInterfacesIf4PktsInBlock:614val->v.counter64 =615e->pfi.pfik_packets[IPV4][IN][BLOCK];616break;617case LEAF_pfInterfacesIf4PktsOutPass:618val->v.counter64 =619e->pfi.pfik_packets[IPV4][OUT][PASS];620break;621case LEAF_pfInterfacesIf4PktsOutBlock:622val->v.counter64 =623e->pfi.pfik_packets[IPV4][OUT][BLOCK];624break;625case LEAF_pfInterfacesIf6BytesInPass:626val->v.counter64 =627e->pfi.pfik_bytes[IPV6][IN][PASS];628break;629case LEAF_pfInterfacesIf6BytesInBlock:630val->v.counter64 =631e->pfi.pfik_bytes[IPV6][IN][BLOCK];632break;633case LEAF_pfInterfacesIf6BytesOutPass:634val->v.counter64 =635e->pfi.pfik_bytes[IPV6][OUT][PASS];636break;637case LEAF_pfInterfacesIf6BytesOutBlock:638val->v.counter64 =639e->pfi.pfik_bytes[IPV6][OUT][BLOCK];640break;641case LEAF_pfInterfacesIf6PktsInPass:642val->v.counter64 =643e->pfi.pfik_packets[IPV6][IN][PASS];644break;645case LEAF_pfInterfacesIf6PktsInBlock:646val->v.counter64 =647e->pfi.pfik_packets[IPV6][IN][BLOCK];648break;649case LEAF_pfInterfacesIf6PktsOutPass:650val->v.counter64 =651e->pfi.pfik_packets[IPV6][OUT][PASS];652break;653case LEAF_pfInterfacesIf6PktsOutBlock:654val->v.counter64 =655e->pfi.pfik_packets[IPV6][OUT][BLOCK];656break;657658default:659return (SNMP_ERR_NOSUCHNAME);660}661662return (SNMP_ERR_NOERROR);663}664665int666pf_tables(struct snmp_context __unused *ctx, struct snmp_value *val,667u_int sub, u_int __unused vindex, enum snmp_op op)668{669asn_subid_t which = val->var.subs[sub - 1];670671if (op == SNMP_OP_SET)672return (SNMP_ERR_NOT_WRITEABLE);673674if (op == SNMP_OP_GET) {675if (! started || (time(NULL) - pft_table_age) > PFT_TABLE_MAXAGE)676if (pft_refresh() == -1)677return (SNMP_ERR_GENERR);678679switch (which) {680case LEAF_pfTablesTblNumber:681val->v.uint32 = pft_table_count;682break;683684default:685return (SNMP_ERR_NOSUCHNAME);686}687688return (SNMP_ERR_NOERROR);689}690691abort();692}693694int695pf_tbltable(struct snmp_context __unused *ctx, struct snmp_value *val,696u_int sub, u_int __unused vindex, enum snmp_op op)697{698asn_subid_t which = val->var.subs[sub - 1];699struct pft_entry *e = NULL;700701if ((time(NULL) - pft_table_age) > PFT_TABLE_MAXAGE)702pft_refresh();703704switch (op) {705case SNMP_OP_SET:706return (SNMP_ERR_NOT_WRITEABLE);707case SNMP_OP_GETNEXT:708if ((e = NEXT_OBJECT_INT(&pft_table,709&val->var, sub)) == NULL)710return (SNMP_ERR_NOSUCHNAME);711val->var.len = sub + 1;712val->var.subs[sub] = e->index;713break;714case SNMP_OP_GET:715if (val->var.len - sub != 1)716return (SNMP_ERR_NOSUCHNAME);717if ((e = pft_table_find(val->var.subs[sub])) == NULL)718return (SNMP_ERR_NOSUCHNAME);719break;720721case SNMP_OP_COMMIT:722case SNMP_OP_ROLLBACK:723default:724abort();725}726727switch (which) {728case LEAF_pfTablesTblDescr:729return (string_get(val, e->pft.pfrts_name, -1));730case LEAF_pfTablesTblCount:731val->v.integer = e->pft.pfrts_cnt;732break;733case LEAF_pfTablesTblTZero:734val->v.uint32 =735(uint32_t)(time(NULL) - e->pft.pfrts_tzero) * 100;736break;737case LEAF_pfTablesTblRefsAnchor:738val->v.integer =739e->pft.pfrts_refcnt[PFR_REFCNT_ANCHOR];740break;741case LEAF_pfTablesTblRefsRule:742val->v.integer =743e->pft.pfrts_refcnt[PFR_REFCNT_RULE];744break;745case LEAF_pfTablesTblEvalMatch:746val->v.counter64 = e->pft.pfrts_match;747break;748case LEAF_pfTablesTblEvalNoMatch:749val->v.counter64 = e->pft.pfrts_nomatch;750break;751case LEAF_pfTablesTblBytesInPass:752val->v.counter64 =753e->pft.pfrts_bytes[PFR_DIR_IN][PFR_OP_PASS];754break;755case LEAF_pfTablesTblBytesInBlock:756val->v.counter64 =757e->pft.pfrts_bytes[PFR_DIR_IN][PFR_OP_BLOCK];758break;759case LEAF_pfTablesTblBytesInXPass:760val->v.counter64 =761e->pft.pfrts_bytes[PFR_DIR_IN][PFR_OP_XPASS];762break;763case LEAF_pfTablesTblBytesOutPass:764val->v.counter64 =765e->pft.pfrts_bytes[PFR_DIR_OUT][PFR_OP_PASS];766break;767case LEAF_pfTablesTblBytesOutBlock:768val->v.counter64 =769e->pft.pfrts_bytes[PFR_DIR_OUT][PFR_OP_BLOCK];770break;771case LEAF_pfTablesTblBytesOutXPass:772val->v.counter64 =773e->pft.pfrts_bytes[PFR_DIR_OUT][PFR_OP_XPASS];774break;775case LEAF_pfTablesTblPktsInPass:776val->v.counter64 =777e->pft.pfrts_packets[PFR_DIR_IN][PFR_OP_PASS];778break;779case LEAF_pfTablesTblPktsInBlock:780val->v.counter64 =781e->pft.pfrts_packets[PFR_DIR_IN][PFR_OP_BLOCK];782break;783case LEAF_pfTablesTblPktsInXPass:784val->v.counter64 =785e->pft.pfrts_packets[PFR_DIR_IN][PFR_OP_XPASS];786break;787case LEAF_pfTablesTblPktsOutPass:788val->v.counter64 =789e->pft.pfrts_packets[PFR_DIR_OUT][PFR_OP_PASS];790break;791case LEAF_pfTablesTblPktsOutBlock:792val->v.counter64 =793e->pft.pfrts_packets[PFR_DIR_OUT][PFR_OP_BLOCK];794break;795case LEAF_pfTablesTblPktsOutXPass:796val->v.counter64 =797e->pft.pfrts_packets[PFR_DIR_OUT][PFR_OP_XPASS];798break;799800default:801return (SNMP_ERR_NOSUCHNAME);802}803804return (SNMP_ERR_NOERROR);805}806807int808pf_tbladdr(struct snmp_context __unused *ctx, struct snmp_value __unused *val,809u_int __unused sub, u_int __unused vindex, enum snmp_op __unused op)810{811asn_subid_t which = val->var.subs[sub - 1];812struct pfa_entry *e = NULL;813814if (! started || (time(NULL) - pfa_table_age) > PFA_TABLE_MAXAGE)815pfa_refresh();816817switch (op) {818case SNMP_OP_SET:819return (SNMP_ERR_NOT_WRITEABLE);820case SNMP_OP_GETNEXT:821if ((e = NEXT_OBJECT_INT(&pfa_table,822&val->var, sub)) == NULL)823return (SNMP_ERR_NOSUCHNAME);824val->var.len = sub + 1;825val->var.subs[sub] = e->index;826break;827case SNMP_OP_GET:828if (val->var.len - sub != 1)829return (SNMP_ERR_NOSUCHNAME);830if ((e = pfa_table_find(val->var.subs[sub])) == NULL)831return (SNMP_ERR_NOSUCHNAME);832break;833834case SNMP_OP_COMMIT:835case SNMP_OP_ROLLBACK:836default:837abort();838}839840switch (which) {841case LEAF_pfTablesAddrNetType:842if (e->pfas.pfras_a.pfra_af == AF_INET)843val->v.integer = pfTablesAddrNetType_ipv4;844else if (e->pfas.pfras_a.pfra_af == AF_INET6)845val->v.integer = pfTablesAddrNetType_ipv6;846else847return (SNMP_ERR_GENERR);848break;849case LEAF_pfTablesAddrNet:850if (e->pfas.pfras_a.pfra_af == AF_INET) {851return (string_get(val,852(u_char *)&e->pfas.pfras_a.pfra_ip4addr, 4));853} else if (e->pfas.pfras_a.pfra_af == AF_INET6)854return (string_get(val,855(u_char *)&e->pfas.pfras_a.pfra_ip6addr, 16));856else857return (SNMP_ERR_GENERR);858break;859case LEAF_pfTablesAddrPrefix:860val->v.integer = (int32_t) e->pfas.pfras_a.pfra_net;861break;862case LEAF_pfTablesAddrTZero:863val->v.uint32 =864(uint32_t)(time(NULL) - e->pfas.pfras_tzero) * 100;865break;866case LEAF_pfTablesAddrBytesInPass:867val->v.counter64 =868e->pfas.pfras_bytes[PFR_DIR_IN][PFR_OP_PASS];869break;870case LEAF_pfTablesAddrBytesInBlock:871val->v.counter64 =872e->pfas.pfras_bytes[PFR_DIR_IN][PFR_OP_BLOCK];873break;874case LEAF_pfTablesAddrBytesOutPass:875val->v.counter64 =876e->pfas.pfras_bytes[PFR_DIR_OUT][PFR_OP_PASS];877break;878case LEAF_pfTablesAddrBytesOutBlock:879val->v.counter64 =880e->pfas.pfras_bytes[PFR_DIR_OUT][PFR_OP_BLOCK];881break;882case LEAF_pfTablesAddrPktsInPass:883val->v.counter64 =884e->pfas.pfras_packets[PFR_DIR_IN][PFR_OP_PASS];885break;886case LEAF_pfTablesAddrPktsInBlock:887val->v.counter64 =888e->pfas.pfras_packets[PFR_DIR_IN][PFR_OP_BLOCK];889break;890case LEAF_pfTablesAddrPktsOutPass:891val->v.counter64 =892e->pfas.pfras_packets[PFR_DIR_OUT][PFR_OP_PASS];893break;894case LEAF_pfTablesAddrPktsOutBlock:895val->v.counter64 =896e->pfas.pfras_packets[PFR_DIR_OUT][PFR_OP_BLOCK];897break;898default:899return (SNMP_ERR_NOSUCHNAME);900}901902return (SNMP_ERR_NOERROR);903}904905int906pf_altq_num(struct snmp_context __unused *ctx, struct snmp_value *val,907u_int sub, u_int __unused vindex, enum snmp_op op)908{909asn_subid_t which = val->var.subs[sub - 1];910911if (!altq_enabled)912return (SNMP_ERR_NOSUCHNAME);913914if (op == SNMP_OP_SET)915return (SNMP_ERR_NOT_WRITEABLE);916917if (op == SNMP_OP_GET) {918if ((time(NULL) - pfq_table_age) > PFQ_TABLE_MAXAGE)919if (pfq_refresh() == -1)920return (SNMP_ERR_GENERR);921922switch (which) {923case LEAF_pfAltqQueueNumber:924val->v.uint32 = pfq_table_count;925break;926927default:928return (SNMP_ERR_NOSUCHNAME);929}930931return (SNMP_ERR_NOERROR);932}933934abort();935return (SNMP_ERR_GENERR);936}937938int939pf_altqq(struct snmp_context __unused *ctx, struct snmp_value *val,940u_int sub, u_int __unused vindex, enum snmp_op op)941{942asn_subid_t which = val->var.subs[sub - 1];943struct pfq_entry *e = NULL;944945if (!altq_enabled)946return (SNMP_ERR_NOSUCHNAME);947948if ((time(NULL) - pfq_table_age) > PFQ_TABLE_MAXAGE)949pfq_refresh();950951switch (op) {952case SNMP_OP_SET:953return (SNMP_ERR_NOT_WRITEABLE);954case SNMP_OP_GETNEXT:955if ((e = NEXT_OBJECT_INT(&pfq_table,956&val->var, sub)) == NULL)957return (SNMP_ERR_NOSUCHNAME);958val->var.len = sub + 1;959val->var.subs[sub] = e->index;960break;961case SNMP_OP_GET:962if (val->var.len - sub != 1)963return (SNMP_ERR_NOSUCHNAME);964if ((e = pfq_table_find(val->var.subs[sub])) == NULL)965return (SNMP_ERR_NOSUCHNAME);966break;967968case SNMP_OP_COMMIT:969case SNMP_OP_ROLLBACK:970default:971abort();972}973974switch (which) {975case LEAF_pfAltqQueueDescr:976return (string_get(val, e->altq.qname, -1));977case LEAF_pfAltqQueueParent:978return (string_get(val, e->altq.parent, -1));979case LEAF_pfAltqQueueScheduler:980val->v.integer = e->altq.scheduler;981break;982case LEAF_pfAltqQueueBandwidth:983val->v.uint32 = (e->altq.bandwidth > UINT_MAX) ?984UINT_MAX : (u_int32_t)e->altq.bandwidth;985break;986case LEAF_pfAltqQueuePriority:987val->v.integer = e->altq.priority;988break;989case LEAF_pfAltqQueueLimit:990val->v.integer = e->altq.qlimit;991break;992993default:994return (SNMP_ERR_NOSUCHNAME);995}996997return (SNMP_ERR_NOERROR);998}9991000int1001pf_labels(struct snmp_context __unused *ctx, struct snmp_value *val,1002u_int sub, u_int __unused vindex, enum snmp_op op)1003{1004asn_subid_t which = val->var.subs[sub - 1];10051006if (op == SNMP_OP_SET)1007return (SNMP_ERR_NOT_WRITEABLE);10081009if (op == SNMP_OP_GET) {1010if ((time(NULL) - pfl_table_age) > PFL_TABLE_MAXAGE)1011if (pfl_refresh() == -1)1012return (SNMP_ERR_GENERR);10131014switch (which) {1015case LEAF_pfLabelsLblNumber:1016val->v.uint32 = pfl_table_count;1017break;10181019default:1020return (SNMP_ERR_NOSUCHNAME);1021}10221023return (SNMP_ERR_NOERROR);1024}10251026abort();1027return (SNMP_ERR_GENERR);1028}10291030int1031pf_lbltable(struct snmp_context __unused *ctx, struct snmp_value *val,1032u_int sub, u_int __unused vindex, enum snmp_op op)1033{1034asn_subid_t which = val->var.subs[sub - 1];1035struct pfl_entry *e = NULL;10361037if (! started || (time(NULL) - pfl_table_age) > PFL_TABLE_MAXAGE)1038pfl_refresh();10391040switch (op) {1041case SNMP_OP_SET:1042return (SNMP_ERR_NOT_WRITEABLE);1043case SNMP_OP_GETNEXT:1044if ((e = NEXT_OBJECT_INT(&pfl_table,1045&val->var, sub)) == NULL)1046return (SNMP_ERR_NOSUCHNAME);1047val->var.len = sub + 1;1048val->var.subs[sub] = e->index;1049break;1050case SNMP_OP_GET:1051if (val->var.len - sub != 1)1052return (SNMP_ERR_NOSUCHNAME);1053if ((e = pfl_table_find(val->var.subs[sub])) == NULL)1054return (SNMP_ERR_NOSUCHNAME);1055break;10561057case SNMP_OP_COMMIT:1058case SNMP_OP_ROLLBACK:1059default:1060abort();1061}10621063switch (which) {1064case LEAF_pfLabelsLblName:1065return (string_get(val, e->name, -1));1066case LEAF_pfLabelsLblEvals:1067val->v.counter64 = e->evals;1068break;1069case LEAF_pfLabelsLblBytesIn:1070val->v.counter64 = e->bytes[IN];1071break;1072case LEAF_pfLabelsLblBytesOut:1073val->v.counter64 = e->bytes[OUT];1074break;1075case LEAF_pfLabelsLblPktsIn:1076val->v.counter64 = e->pkts[IN];1077break;1078case LEAF_pfLabelsLblPktsOut:1079val->v.counter64 = e->pkts[OUT];1080break;1081default:1082return (SNMP_ERR_NOSUCHNAME);1083}10841085return (SNMP_ERR_NOERROR);1086}10871088static struct pfi_entry *1089pfi_table_find(u_int idx)1090{1091struct pfi_entry *e;10921093TAILQ_FOREACH(e, &pfi_table, link)1094if (e->index == idx)1095return (e);1096return (NULL);1097}10981099static struct pfq_entry *1100pfq_table_find(u_int idx)1101{1102struct pfq_entry *e;11031104TAILQ_FOREACH(e, &pfq_table, link)1105if (e->index == idx)1106return (e);1107return (NULL);1108}11091110static struct pft_entry *1111pft_table_find(u_int idx)1112{1113struct pft_entry *e;11141115TAILQ_FOREACH(e, &pft_table, link)1116if (e->index == idx)1117return (e);1118return (NULL);1119}11201121static struct pfa_entry *1122pfa_table_find(u_int idx)1123{1124struct pfa_entry *e;11251126TAILQ_FOREACH(e, &pfa_table, link)1127if (e->index == idx)1128return (e);1129return (NULL);1130}11311132static struct pfl_entry *1133pfl_table_find(u_int idx)1134{1135struct pfl_entry *e;11361137TAILQ_FOREACH(e, &pfl_table, link)1138if (e->index == idx)1139return (e);11401141return (NULL);1142}11431144static int1145pfi_refresh(void)1146{1147struct pfioc_iface io;1148struct pfi_kif *p = NULL;1149struct pfi_entry *e;1150int i, numifs = 1;11511152if (started && this_tick <= pf_tick)1153return (0);11541155while (!TAILQ_EMPTY(&pfi_table)) {1156e = TAILQ_FIRST(&pfi_table);1157TAILQ_REMOVE(&pfi_table, e, link);1158free(e);1159}11601161bzero(&io, sizeof(io));1162io.pfiio_esize = sizeof(struct pfi_kif);11631164for (;;) {1165p = reallocf(p, numifs * sizeof(struct pfi_kif));1166if (p == NULL) {1167syslog(LOG_ERR, "pfi_refresh(): reallocf() numifs=%d: %s",1168numifs, strerror(errno));1169goto err2;1170}1171io.pfiio_size = numifs;1172io.pfiio_buffer = p;11731174if (ioctl(pfctl_fd(pfh), DIOCIGETIFACES, &io)) {1175syslog(LOG_ERR, "pfi_refresh(): ioctl(): %s",1176strerror(errno));1177goto err2;1178}11791180if (numifs >= io.pfiio_size)1181break;11821183numifs = io.pfiio_size;1184}11851186for (i = 0; i < numifs; i++) {1187e = malloc(sizeof(struct pfi_entry));1188if (e == NULL)1189goto err1;1190e->index = i + 1;1191memcpy(&e->pfi, p+i, sizeof(struct pfi_kif));1192TAILQ_INSERT_TAIL(&pfi_table, e, link);1193}11941195pfi_table_age = time(NULL);1196pfi_table_count = numifs;1197pf_tick = this_tick;11981199free(p);1200return (0);12011202err1:1203while (!TAILQ_EMPTY(&pfi_table)) {1204e = TAILQ_FIRST(&pfi_table);1205TAILQ_REMOVE(&pfi_table, e, link);1206free(e);1207}1208err2:1209free(p);1210return(-1);1211}12121213static int1214pfq_refresh(void)1215{1216struct pfioc_altq pa;1217struct pfq_entry *e;1218int i, numqs, ticket;12191220if (started && this_tick <= pf_tick)1221return (0);12221223while (!TAILQ_EMPTY(&pfq_table)) {1224e = TAILQ_FIRST(&pfq_table);1225TAILQ_REMOVE(&pfq_table, e, link);1226free(e);1227}12281229bzero(&pa, sizeof(pa));1230pa.version = PFIOC_ALTQ_VERSION;1231if (ioctl(pfctl_fd(pfh), DIOCGETALTQS, &pa)) {1232syslog(LOG_ERR, "pfq_refresh: ioctl(DIOCGETALTQS): %s",1233strerror(errno));1234return (-1);1235}12361237numqs = pa.nr;1238ticket = pa.ticket;12391240for (i = 0; i < numqs; i++) {1241e = malloc(sizeof(struct pfq_entry));1242if (e == NULL) {1243syslog(LOG_ERR, "pfq_refresh(): "1244"malloc(): %s",1245strerror(errno));1246goto err;1247}1248pa.ticket = ticket;1249pa.nr = i;12501251if (ioctl(pfctl_fd(pfh), DIOCGETALTQ, &pa)) {1252syslog(LOG_ERR, "pfq_refresh(): "1253"ioctl(DIOCGETALTQ): %s",1254strerror(errno));1255goto err;1256}12571258if (pa.altq.qid > 0) {1259memcpy(&e->altq, &pa.altq, sizeof(struct pf_altq));1260e->index = pa.altq.qid;1261pfq_table_count = i;1262INSERT_OBJECT_INT_LINK_INDEX(e, &pfq_table, link, index);1263}1264}12651266pfq_table_age = time(NULL);1267pf_tick = this_tick;12681269return (0);1270err:1271free(e);1272while (!TAILQ_EMPTY(&pfq_table)) {1273e = TAILQ_FIRST(&pfq_table);1274TAILQ_REMOVE(&pfq_table, e, link);1275free(e);1276}1277return(-1);1278}12791280static int1281pfs_refresh(void)1282{1283if (started && this_tick <= pf_tick)1284return (0);12851286pfctl_free_status(pfs);1287pfs = pfctl_get_status_h(pfh);12881289if (pfs == NULL) {1290syslog(LOG_ERR, "pfs_refresh(): pfctl_get_status failure");1291return (-1);1292}12931294pf_tick = this_tick;1295return (0);1296}12971298static int1299pft_add_tstats(const struct pfr_tstats *t, void *arg)1300{1301struct pft_entry *e;1302int *index = arg;13031304e = malloc(sizeof(struct pft_entry));1305if (e == NULL)1306return (ENOMEM);13071308e->index = (*index) + 1;1309(*index)++;1310memcpy(&e->pft, t, sizeof(struct pfr_tstats));1311TAILQ_INSERT_TAIL(&pft_table, e, link);13121313return (0);1314}13151316static int1317pft_refresh(void)1318{1319struct pfr_table filter;1320struct pft_entry *e;1321int i, numtbls = 1;13221323while (!TAILQ_EMPTY(&pft_table)) {1324e = TAILQ_FIRST(&pft_table);1325TAILQ_REMOVE(&pft_table, e, link);1326free(e);1327}13281329bzero(&filter, sizeof(filter));13301331if (pfctl_get_tstats(pfh, &filter, pft_add_tstats, &i)) {1332syslog(LOG_ERR, "pft_refresh(): pfctl_get_tstats(): %s",1333strerror(errno));1334goto err1;1335}13361337pft_table_age = time(NULL);1338pft_table_count = numtbls;1339pf_tick = this_tick;13401341return (0);1342err1:1343while (!TAILQ_EMPTY(&pft_table)) {1344e = TAILQ_FIRST(&pft_table);1345TAILQ_REMOVE(&pft_table, e, link);1346free(e);1347}1348return(-1);1349}13501351static int1352pfa_table_addrs(u_int sidx, struct pfr_table *pt)1353{1354struct pfr_table tbl = { 0 };1355struct pfr_astats *t = NULL;1356struct pfa_entry *e;1357int i, numaddrs = 1, outnum;13581359if (pt == NULL)1360return (-1);13611362strlcpy(tbl.pfrt_name, pt->pfrt_name,1363sizeof(tbl.pfrt_name));13641365for (;;) {1366t = reallocf(t, numaddrs * sizeof(struct pfr_astats));1367if (t == NULL) {1368syslog(LOG_ERR, "pfa_table_addrs(): reallocf(): %s",1369strerror(errno));1370numaddrs = -1;1371goto error;1372}13731374outnum = numaddrs;1375if (pfctl_get_astats(pfh, &tbl, t, &outnum, 0) != 0) {1376syslog(LOG_ERR, "pfa_table_addrs(): ioctl() on %s: %s",1377pt->pfrt_name, strerror(errno));1378numaddrs = -1;1379break;1380}13811382if (numaddrs >= outnum)1383break;13841385numaddrs = outnum;1386}13871388for (i = 0; i < numaddrs; i++) {1389if ((t + i)->pfras_a.pfra_af != AF_INET &&1390(t + i)->pfras_a.pfra_af != AF_INET6) {1391numaddrs = i;1392break;1393}13941395e = (struct pfa_entry *)malloc(sizeof(struct pfa_entry));1396if (e == NULL) {1397syslog(LOG_ERR, "pfa_table_addrs(): malloc(): %s",1398strerror(errno));1399numaddrs = -1;1400break;1401}1402e->index = sidx + i;1403memcpy(&e->pfas, t + i, sizeof(struct pfr_astats));1404TAILQ_INSERT_TAIL(&pfa_table, e, link);1405}14061407free(t);1408error:1409return (numaddrs);1410}14111412static int1413pfa_refresh(void)1414{1415struct pfioc_table io;1416struct pfr_table *pt = NULL, *it = NULL;1417struct pfa_entry *e;1418int i, numtbls = 1, cidx, naddrs;14191420while (!TAILQ_EMPTY(&pfa_table)) {1421e = TAILQ_FIRST(&pfa_table);1422TAILQ_REMOVE(&pfa_table, e, link);1423free(e);1424}14251426memset(&io, 0, sizeof(io));1427io.pfrio_esize = sizeof(struct pfr_table);14281429for (;;) {1430pt = reallocf(pt, numtbls * sizeof(struct pfr_table));1431if (pt == NULL) {1432syslog(LOG_ERR, "pfa_refresh(): reallocf() %s",1433strerror(errno));1434return (-1);1435}1436memset(pt, 0, sizeof(*pt));1437io.pfrio_size = numtbls;1438io.pfrio_buffer = pt;14391440if (ioctl(pfctl_fd(pfh), DIOCRGETTABLES, &io)) {1441syslog(LOG_ERR, "pfa_refresh(): ioctl(): %s",1442strerror(errno));1443goto err2;1444}14451446if (numtbls >= io.pfrio_size)1447break;14481449numtbls = io.pfrio_size;1450}14511452cidx = 1;14531454for (it = pt, i = 0; i < numtbls; it++, i++) {1455/*1456* Skip the table if not active - ioctl(DIOCRGETASTATS) will1457* return ESRCH for this entry anyway.1458*/1459if (!(it->pfrt_flags & PFR_TFLAG_ACTIVE))1460continue;14611462if ((naddrs = pfa_table_addrs(cidx, it)) < 0)1463goto err1;14641465cidx += naddrs;1466}14671468pfa_table_age = time(NULL);1469pfa_table_count = cidx;1470pf_tick = this_tick;14711472free(pt);1473return (0);1474err1:1475while (!TAILQ_EMPTY(&pfa_table)) {1476e = TAILQ_FIRST(&pfa_table);1477TAILQ_REMOVE(&pfa_table, e, link);1478free(e);1479}14801481err2:1482free(pt);1483return (-1);1484}14851486static int1487pfl_scan_ruleset(const char *path)1488{1489struct pfctl_rules_info rules;1490struct pfctl_rule rule;1491char anchor_call[MAXPATHLEN] = "";1492struct pfl_entry *e;1493u_int32_t nr, i;14941495if (pfctl_get_rules_info_h(pfh, &rules, PF_PASS, path)) {1496syslog(LOG_ERR, "pfl_scan_ruleset: ioctl(DIOCGETRULES): %s",1497strerror(errno));1498goto err;1499}15001501for (nr = rules.nr, i = 0; i < nr; i++) {1502if (pfctl_get_rule_h(pfh, i, rules.ticket, path,1503PF_PASS, &rule, anchor_call)) {1504syslog(LOG_ERR, "pfl_scan_ruleset: ioctl(DIOCGETRULE):"1505" %s", strerror(errno));1506goto err;1507}15081509if (rule.label[0][0]) {1510e = (struct pfl_entry *)malloc(sizeof(*e));1511if (e == NULL)1512goto err;15131514strlcpy(e->name, path, sizeof(e->name));1515if (path[0])1516strlcat(e->name, "/", sizeof(e->name));1517strlcat(e->name, rule.label[0], sizeof(e->name));15181519e->evals = rule.evaluations;1520e->bytes[IN] = rule.bytes[IN];1521e->bytes[OUT] = rule.bytes[OUT];1522e->pkts[IN] = rule.packets[IN];1523e->pkts[OUT] = rule.packets[OUT];1524e->index = ++pfl_table_count;15251526TAILQ_INSERT_TAIL(&pfl_table, e, link);1527}1528}15291530return (0);15311532err:1533return (-1);1534}15351536static int1537pfl_walk_rulesets(const char *path)1538{1539struct pfioc_ruleset prs;1540char newpath[MAXPATHLEN];1541u_int32_t nr, i;15421543if (pfl_scan_ruleset(path))1544goto err;15451546bzero(&prs, sizeof(prs));1547strlcpy(prs.path, path, sizeof(prs.path));1548if (ioctl(pfctl_fd(pfh), DIOCGETRULESETS, &prs)) {1549syslog(LOG_ERR, "pfl_walk_rulesets: ioctl(DIOCGETRULESETS): %s",1550strerror(errno));1551goto err;1552}15531554for (nr = prs.nr, i = 0; i < nr; i++) {1555prs.nr = i;1556if (ioctl(pfctl_fd(pfh), DIOCGETRULESET, &prs)) {1557syslog(LOG_ERR, "pfl_walk_rulesets: ioctl(DIOCGETRULESET):"1558" %s", strerror(errno));1559goto err;1560}15611562if (strcmp(prs.name, PF_RESERVED_ANCHOR) == 0)1563continue;15641565strlcpy(newpath, path, sizeof(newpath));1566if (path[0])1567strlcat(newpath, "/", sizeof(newpath));15681569strlcat(newpath, prs.name, sizeof(newpath));1570if (pfl_walk_rulesets(newpath))1571goto err;1572}15731574return (0);15751576err:1577return (-1);1578}15791580static int1581pfl_refresh(void)1582{1583struct pfl_entry *e;15841585while (!TAILQ_EMPTY(&pfl_table)) {1586e = TAILQ_FIRST(&pfl_table);1587TAILQ_REMOVE(&pfl_table, e, link);1588free(e);1589}1590pfl_table_count = 0;15911592if (pfl_walk_rulesets(""))1593goto err;15941595pfl_table_age = time(NULL);1596pf_tick = this_tick;15971598return (0);15991600err:1601while (!TAILQ_EMPTY(&pfl_table)) {1602e = TAILQ_FIRST(&pfl_table);1603TAILQ_REMOVE(&pfl_table, e, link);1604free(e);1605}1606pfl_table_count = 0;16071608return (-1);1609}16101611/*1612* check whether altq support is enabled in kernel1613*/16141615static int1616altq_is_enabled(int pfdev)1617{1618struct pfioc_altq pa;16191620errno = 0;1621pa.version = PFIOC_ALTQ_VERSION;1622if (ioctl(pfdev, DIOCGETALTQS, &pa)) {1623if (errno == ENODEV) {1624syslog(LOG_INFO, "No ALTQ support in kernel\n"1625"ALTQ related functions disabled\n");1626return (0);1627} else {1628syslog(LOG_ERR, "DIOCGETALTQS returned an error: %s",1629strerror(errno));1630return (-1);1631}1632}1633return (1);1634}16351636/*1637* Implement the bsnmpd module interface1638*/1639static int1640pf_init(struct lmodule *mod, int __unused argc, char __unused *argv[])1641{1642module = mod;16431644if ((pfh = pfctl_open(PF_DEVICE)) == NULL) {1645syslog(LOG_ERR, "pf_init(): open(): %s\n",1646strerror(errno));1647return (-1);1648}16491650if ((altq_enabled = altq_is_enabled(pfctl_fd(pfh))) == -1) {1651syslog(LOG_ERR, "pf_init(): altq test failed");1652return (-1);1653}16541655/* Prepare internal state */1656TAILQ_INIT(&pfi_table);1657TAILQ_INIT(&pfq_table);1658TAILQ_INIT(&pft_table);1659TAILQ_INIT(&pfa_table);1660TAILQ_INIT(&pfl_table);16611662pfi_refresh();1663if (altq_enabled) {1664pfq_refresh();1665}16661667pfs_refresh();1668pft_refresh();1669pfa_refresh();1670pfl_refresh();16711672started = 1;16731674return (0);1675}16761677static int1678pf_fini(void)1679{1680struct pfi_entry *i1, *i2;1681struct pfq_entry *q1, *q2;1682struct pft_entry *t1, *t2;1683struct pfa_entry *a1, *a2;1684struct pfl_entry *l1, *l2;16851686/* Empty the list of interfaces */1687i1 = TAILQ_FIRST(&pfi_table);1688while (i1 != NULL) {1689i2 = TAILQ_NEXT(i1, link);1690free(i1);1691i1 = i2;1692}16931694/* List of queues */1695q1 = TAILQ_FIRST(&pfq_table);1696while (q1 != NULL) {1697q2 = TAILQ_NEXT(q1, link);1698free(q1);1699q1 = q2;1700}17011702/* List of tables */1703t1 = TAILQ_FIRST(&pft_table);1704while (t1 != NULL) {1705t2 = TAILQ_NEXT(t1, link);1706free(t1);1707t1 = t2;1708}17091710/* List of table addresses */1711a1 = TAILQ_FIRST(&pfa_table);1712while (a1 != NULL) {1713a2 = TAILQ_NEXT(a1, link);1714free(a1);1715a1 = a2;1716}17171718/* And the list of labeled filter rules */1719l1 = TAILQ_FIRST(&pfl_table);1720while (l1 != NULL) {1721l2 = TAILQ_NEXT(l1, link);1722free(l1);1723l1 = l2;1724}17251726pfctl_free_status(pfs);1727pfs = NULL;17281729pfctl_close(pfh);17301731return (0);1732}17331734static void1735pf_dump(void)1736{1737pfi_refresh();1738if (altq_enabled) {1739pfq_refresh();1740}1741pft_refresh();1742pfa_refresh();1743pfl_refresh();17441745syslog(LOG_ERR, "Dump: pfi_table_age = %jd",1746(intmax_t)pfi_table_age);1747syslog(LOG_ERR, "Dump: pfi_table_count = %d",1748pfi_table_count);17491750syslog(LOG_ERR, "Dump: pfq_table_age = %jd",1751(intmax_t)pfq_table_age);1752syslog(LOG_ERR, "Dump: pfq_table_count = %d",1753pfq_table_count);17541755syslog(LOG_ERR, "Dump: pft_table_age = %jd",1756(intmax_t)pft_table_age);1757syslog(LOG_ERR, "Dump: pft_table_count = %d",1758pft_table_count);17591760syslog(LOG_ERR, "Dump: pfa_table_age = %jd",1761(intmax_t)pfa_table_age);1762syslog(LOG_ERR, "Dump: pfa_table_count = %d",1763pfa_table_count);17641765syslog(LOG_ERR, "Dump: pfl_table_age = %jd",1766(intmax_t)pfl_table_age);1767syslog(LOG_ERR, "Dump: pfl_table_count = %d",1768pfl_table_count);1769}17701771const struct snmp_module config = {1772.comment = "This module implements a MIB for the pf packet filter.",1773.init = pf_init,1774.fini = pf_fini,1775.tree = pf_ctree,1776.dump = pf_dump,1777.tree_size = pf_CTREE_SIZE,1778};177917801781