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