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$ 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 49 struct lmodule *module; 50 51 static int dev = -1; 52 static int started; 53 static uint64_t pf_tick; 54 55 static struct pf_status pfs; 56 57 enum { IN, OUT }; 58 enum { IPV4, IPV6 }; 59 enum { PASS, BLOCK }; 60 61 #define PFI_IFTYPE_GROUP 0 62 #define PFI_IFTYPE_INSTANCE 1 63 #define PFI_IFTYPE_DETACHED 2 64 65 struct pfi_entry { 66 struct pfi_kif pfi; 67 u_int index; 68 TAILQ_ENTRY(pfi_entry) link; 69 }; 70 TAILQ_HEAD(pfi_table, pfi_entry); 71 72 static struct pfi_table pfi_table; 73 static time_t pfi_table_age; 74 static int pfi_table_count; 75 76 #define PFI_TABLE_MAXAGE 5 77 78 struct pft_entry { 79 struct pfr_tstats pft; 80 u_int index; 81 TAILQ_ENTRY(pft_entry) link; 82 }; 83 TAILQ_HEAD(pft_table, pft_entry); 84 85 static struct pft_table pft_table; 86 static time_t pft_table_age; 87 static int pft_table_count; 88 89 #define PFT_TABLE_MAXAGE 5 90 91 struct pfa_entry { 92 struct pfr_astats pfas; 93 u_int index; 94 TAILQ_ENTRY(pfa_entry) link; 95 }; 96 TAILQ_HEAD(pfa_table, pfa_entry); 97 98 static struct pfa_table pfa_table; 99 static time_t pfa_table_age; 100 static int pfa_table_count; 101 102 #define PFA_TABLE_MAXAGE 5 103 104 struct pfq_entry { 105 struct pf_altq altq; 106 u_int index; 107 TAILQ_ENTRY(pfq_entry) link; 108 }; 109 TAILQ_HEAD(pfq_table, pfq_entry); 110 111 static struct pfq_table pfq_table; 112 static time_t pfq_table_age; 113 static int pfq_table_count; 114 115 static int altq_enabled = 0; 116 117 #define PFQ_TABLE_MAXAGE 5 118 119 struct 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 }; 127 TAILQ_HEAD(pfl_table, pfl_entry); 128 129 static struct pfl_table pfl_table; 130 static time_t pfl_table_age; 131 static int pfl_table_count; 132 133 #define PFL_TABLE_MAXAGE 5 134 135 /* Forward declarations */ 136 static int pfi_refresh(void); 137 static int pfq_refresh(void); 138 static int pfs_refresh(void); 139 static int pft_refresh(void); 140 static int pfa_refresh(void); 141 static int pfl_refresh(void); 142 static struct pfi_entry * pfi_table_find(u_int idx); 143 static struct pfq_entry * pfq_table_find(u_int idx); 144 static struct pft_entry * pft_table_find(u_int idx); 145 static struct pfa_entry * pfa_table_find(u_int idx); 146 static struct pfl_entry * pfl_table_find(u_int idx); 147 148 static int altq_is_enabled(int pfdevice); 149 150 int 151 pf_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 191 int 192 pf_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 234 int 235 pf_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 274 int 275 pf_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 314 int 315 pf_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 356 int 357 pf_timeouts(struct snmp_context __unused *ctx, struct snmp_value *val, 358 u_int sub, u_int __unused vindex, enum snmp_op op) 359 { 360 asn_subid_t which = val->var.subs[sub - 1]; 361 struct pfioc_tm pt; 362 363 if (op == SNMP_OP_SET) 364 return (SNMP_ERR_NOT_WRITEABLE); 365 366 if (op == SNMP_OP_GET) { 367 bzero(&pt, sizeof(struct pfioc_tm)); 368 369 switch (which) { 370 case LEAF_pfTimeoutsTcpFirst: 371 pt.timeout = PFTM_TCP_FIRST_PACKET; 372 break; 373 case LEAF_pfTimeoutsTcpOpening: 374 pt.timeout = PFTM_TCP_OPENING; 375 break; 376 case LEAF_pfTimeoutsTcpEstablished: 377 pt.timeout = PFTM_TCP_ESTABLISHED; 378 break; 379 case LEAF_pfTimeoutsTcpClosing: 380 pt.timeout = PFTM_TCP_CLOSING; 381 break; 382 case LEAF_pfTimeoutsTcpFinWait: 383 pt.timeout = PFTM_TCP_FIN_WAIT; 384 break; 385 case LEAF_pfTimeoutsTcpClosed: 386 pt.timeout = PFTM_TCP_CLOSED; 387 break; 388 case LEAF_pfTimeoutsUdpFirst: 389 pt.timeout = PFTM_UDP_FIRST_PACKET; 390 break; 391 case LEAF_pfTimeoutsUdpSingle: 392 pt.timeout = PFTM_UDP_SINGLE; 393 break; 394 case LEAF_pfTimeoutsUdpMultiple: 395 pt.timeout = PFTM_UDP_MULTIPLE; 396 break; 397 case LEAF_pfTimeoutsIcmpFirst: 398 pt.timeout = PFTM_ICMP_FIRST_PACKET; 399 break; 400 case LEAF_pfTimeoutsIcmpError: 401 pt.timeout = PFTM_ICMP_ERROR_REPLY; 402 break; 403 case LEAF_pfTimeoutsOtherFirst: 404 pt.timeout = PFTM_OTHER_FIRST_PACKET; 405 break; 406 case LEAF_pfTimeoutsOtherSingle: 407 pt.timeout = PFTM_OTHER_SINGLE; 408 break; 409 case LEAF_pfTimeoutsOtherMultiple: 410 pt.timeout = PFTM_OTHER_MULTIPLE; 411 break; 412 case LEAF_pfTimeoutsFragment: 413 pt.timeout = PFTM_FRAG; 414 break; 415 case LEAF_pfTimeoutsInterval: 416 pt.timeout = PFTM_INTERVAL; 417 break; 418 case LEAF_pfTimeoutsAdaptiveStart: 419 pt.timeout = PFTM_ADAPTIVE_START; 420 break; 421 case LEAF_pfTimeoutsAdaptiveEnd: 422 pt.timeout = PFTM_ADAPTIVE_END; 423 break; 424 case LEAF_pfTimeoutsSrcNode: 425 pt.timeout = PFTM_SRC_NODE; 426 break; 427 428 default: 429 return (SNMP_ERR_NOSUCHNAME); 430 } 431 432 if (ioctl(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 446 int 447 pf_logif(struct snmp_context __unused *ctx, struct snmp_value *val, 448 u_int sub, u_int __unused vindex, enum snmp_op op) 449 { 450 asn_subid_t which = val->var.subs[sub - 1]; 451 unsigned char str[IFNAMSIZ]; 452 453 if (op == SNMP_OP_SET) 454 return (SNMP_ERR_NOT_WRITEABLE); 455 456 if (op == SNMP_OP_GET) { 457 if (pfs_refresh() == -1) 458 return (SNMP_ERR_GENERR); 459 460 switch (which) { 461 case LEAF_pfLogInterfaceName: 462 strlcpy(str, pfs.ifname, sizeof str); 463 return (string_get(val, str, strlen(str))); 464 case LEAF_pfLogInterfaceIp4BytesIn: 465 val->v.counter64 = pfs.bcounters[IPV4][IN]; 466 break; 467 case LEAF_pfLogInterfaceIp4BytesOut: 468 val->v.counter64 = pfs.bcounters[IPV4][OUT]; 469 break; 470 case LEAF_pfLogInterfaceIp4PktsInPass: 471 val->v.counter64 = 472 pfs.pcounters[IPV4][IN][PF_PASS]; 473 break; 474 case LEAF_pfLogInterfaceIp4PktsInDrop: 475 val->v.counter64 = 476 pfs.pcounters[IPV4][IN][PF_DROP]; 477 break; 478 case LEAF_pfLogInterfaceIp4PktsOutPass: 479 val->v.counter64 = 480 pfs.pcounters[IPV4][OUT][PF_PASS]; 481 break; 482 case LEAF_pfLogInterfaceIp4PktsOutDrop: 483 val->v.counter64 = 484 pfs.pcounters[IPV4][OUT][PF_DROP]; 485 break; 486 case LEAF_pfLogInterfaceIp6BytesIn: 487 val->v.counter64 = pfs.bcounters[IPV6][IN]; 488 break; 489 case LEAF_pfLogInterfaceIp6BytesOut: 490 val->v.counter64 = pfs.bcounters[IPV6][OUT]; 491 break; 492 case LEAF_pfLogInterfaceIp6PktsInPass: 493 val->v.counter64 = 494 pfs.pcounters[IPV6][IN][PF_PASS]; 495 break; 496 case LEAF_pfLogInterfaceIp6PktsInDrop: 497 val->v.counter64 = 498 pfs.pcounters[IPV6][IN][PF_DROP]; 499 break; 500 case LEAF_pfLogInterfaceIp6PktsOutPass: 501 val->v.counter64 = 502 pfs.pcounters[IPV6][OUT][PF_PASS]; 503 break; 504 case LEAF_pfLogInterfaceIp6PktsOutDrop: 505 val->v.counter64 = 506 pfs.pcounters[IPV6][OUT][PF_DROP]; 507 break; 508 509 default: 510 return (SNMP_ERR_NOSUCHNAME); 511 } 512 513 return (SNMP_ERR_NOERROR); 514 } 515 516 abort(); 517 } 518 519 int 520 pf_interfaces(struct snmp_context __unused *ctx, struct snmp_value *val, 521 u_int sub, u_int __unused vindex, enum snmp_op op) 522 { 523 asn_subid_t which = val->var.subs[sub - 1]; 524 525 if (op == SNMP_OP_SET) 526 return (SNMP_ERR_NOT_WRITEABLE); 527 528 if (op == SNMP_OP_GET) { 529 if ((time(NULL) - pfi_table_age) > PFI_TABLE_MAXAGE) 530 if (pfi_refresh() == -1) 531 return (SNMP_ERR_GENERR); 532 533 switch (which) { 534 case LEAF_pfInterfacesIfNumber: 535 val->v.uint32 = pfi_table_count; 536 break; 537 538 default: 539 return (SNMP_ERR_NOSUCHNAME); 540 } 541 542 return (SNMP_ERR_NOERROR); 543 } 544 545 abort(); 546 } 547 548 int 549 pf_iftable(struct snmp_context __unused *ctx, struct snmp_value *val, 550 u_int sub, u_int __unused vindex, enum snmp_op op) 551 { 552 asn_subid_t which = val->var.subs[sub - 1]; 553 struct pfi_entry *e = NULL; 554 555 if ((time(NULL) - pfi_table_age) > PFI_TABLE_MAXAGE) 556 pfi_refresh(); 557 558 switch (op) { 559 case SNMP_OP_SET: 560 return (SNMP_ERR_NOT_WRITEABLE); 561 case SNMP_OP_GETNEXT: 562 if ((e = NEXT_OBJECT_INT(&pfi_table, 563 &val->var, sub)) == NULL) 564 return (SNMP_ERR_NOSUCHNAME); 565 val->var.len = sub + 1; 566 val->var.subs[sub] = e->index; 567 break; 568 case SNMP_OP_GET: 569 if (val->var.len - sub != 1) 570 return (SNMP_ERR_NOSUCHNAME); 571 if ((e = pfi_table_find(val->var.subs[sub])) == NULL) 572 return (SNMP_ERR_NOSUCHNAME); 573 break; 574 575 case SNMP_OP_COMMIT: 576 case SNMP_OP_ROLLBACK: 577 default: 578 abort(); 579 } 580 581 switch (which) { 582 case LEAF_pfInterfacesIfDescr: 583 return (string_get(val, e->pfi.pfik_name, -1)); 584 case LEAF_pfInterfacesIfType: 585 val->v.integer = PFI_IFTYPE_INSTANCE; 586 break; 587 case LEAF_pfInterfacesIfTZero: 588 val->v.uint32 = 589 (time(NULL) - e->pfi.pfik_tzero) * 100; 590 break; 591 case LEAF_pfInterfacesIfRefsRule: 592 val->v.uint32 = e->pfi.pfik_rulerefs; 593 break; 594 case LEAF_pfInterfacesIf4BytesInPass: 595 val->v.counter64 = 596 e->pfi.pfik_bytes[IPV4][IN][PASS]; 597 break; 598 case LEAF_pfInterfacesIf4BytesInBlock: 599 val->v.counter64 = 600 e->pfi.pfik_bytes[IPV4][IN][BLOCK]; 601 break; 602 case LEAF_pfInterfacesIf4BytesOutPass: 603 val->v.counter64 = 604 e->pfi.pfik_bytes[IPV4][OUT][PASS]; 605 break; 606 case LEAF_pfInterfacesIf4BytesOutBlock: 607 val->v.counter64 = 608 e->pfi.pfik_bytes[IPV4][OUT][BLOCK]; 609 break; 610 case LEAF_pfInterfacesIf4PktsInPass: 611 val->v.counter64 = 612 e->pfi.pfik_packets[IPV4][IN][PASS]; 613 break; 614 case LEAF_pfInterfacesIf4PktsInBlock: 615 val->v.counter64 = 616 e->pfi.pfik_packets[IPV4][IN][BLOCK]; 617 break; 618 case LEAF_pfInterfacesIf4PktsOutPass: 619 val->v.counter64 = 620 e->pfi.pfik_packets[IPV4][OUT][PASS]; 621 break; 622 case LEAF_pfInterfacesIf4PktsOutBlock: 623 val->v.counter64 = 624 e->pfi.pfik_packets[IPV4][OUT][BLOCK]; 625 break; 626 case LEAF_pfInterfacesIf6BytesInPass: 627 val->v.counter64 = 628 e->pfi.pfik_bytes[IPV6][IN][PASS]; 629 break; 630 case LEAF_pfInterfacesIf6BytesInBlock: 631 val->v.counter64 = 632 e->pfi.pfik_bytes[IPV6][IN][BLOCK]; 633 break; 634 case LEAF_pfInterfacesIf6BytesOutPass: 635 val->v.counter64 = 636 e->pfi.pfik_bytes[IPV6][OUT][PASS]; 637 break; 638 case LEAF_pfInterfacesIf6BytesOutBlock: 639 val->v.counter64 = 640 e->pfi.pfik_bytes[IPV6][OUT][BLOCK]; 641 break; 642 case LEAF_pfInterfacesIf6PktsInPass: 643 val->v.counter64 = 644 e->pfi.pfik_packets[IPV6][IN][PASS]; 645 break; 646 case LEAF_pfInterfacesIf6PktsInBlock: 647 val->v.counter64 = 648 e->pfi.pfik_packets[IPV6][IN][BLOCK]; 649 break; 650 case LEAF_pfInterfacesIf6PktsOutPass: 651 val->v.counter64 = 652 e->pfi.pfik_packets[IPV6][OUT][PASS]; 653 break; 654 case LEAF_pfInterfacesIf6PktsOutBlock: 655 val->v.counter64 = 656 e->pfi.pfik_packets[IPV6][OUT][BLOCK]; 657 break; 658 659 default: 660 return (SNMP_ERR_NOSUCHNAME); 661 } 662 663 return (SNMP_ERR_NOERROR); 664 } 665 666 int 667 pf_tables(struct snmp_context __unused *ctx, struct snmp_value *val, 668 u_int sub, u_int __unused vindex, enum snmp_op op) 669 { 670 asn_subid_t which = val->var.subs[sub - 1]; 671 672 if (op == SNMP_OP_SET) 673 return (SNMP_ERR_NOT_WRITEABLE); 674 675 if (op == SNMP_OP_GET) { 676 if ((time(NULL) - pft_table_age) > PFT_TABLE_MAXAGE) 677 if (pft_refresh() == -1) 678 return (SNMP_ERR_GENERR); 679 680 switch (which) { 681 case LEAF_pfTablesTblNumber: 682 val->v.uint32 = pft_table_count; 683 break; 684 685 default: 686 return (SNMP_ERR_NOSUCHNAME); 687 } 688 689 return (SNMP_ERR_NOERROR); 690 } 691 692 abort(); 693 } 694 695 int 696 pf_tbltable(struct snmp_context __unused *ctx, struct snmp_value *val, 697 u_int sub, u_int __unused vindex, enum snmp_op op) 698 { 699 asn_subid_t which = val->var.subs[sub - 1]; 700 struct pft_entry *e = NULL; 701 702 if ((time(NULL) - pft_table_age) > PFT_TABLE_MAXAGE) 703 pft_refresh(); 704 705 switch (op) { 706 case SNMP_OP_SET: 707 return (SNMP_ERR_NOT_WRITEABLE); 708 case SNMP_OP_GETNEXT: 709 if ((e = NEXT_OBJECT_INT(&pft_table, 710 &val->var, sub)) == NULL) 711 return (SNMP_ERR_NOSUCHNAME); 712 val->var.len = sub + 1; 713 val->var.subs[sub] = e->index; 714 break; 715 case SNMP_OP_GET: 716 if (val->var.len - sub != 1) 717 return (SNMP_ERR_NOSUCHNAME); 718 if ((e = pft_table_find(val->var.subs[sub])) == NULL) 719 return (SNMP_ERR_NOSUCHNAME); 720 break; 721 722 case SNMP_OP_COMMIT: 723 case SNMP_OP_ROLLBACK: 724 default: 725 abort(); 726 } 727 728 switch (which) { 729 case LEAF_pfTablesTblDescr: 730 return (string_get(val, e->pft.pfrts_name, -1)); 731 case LEAF_pfTablesTblCount: 732 val->v.integer = e->pft.pfrts_cnt; 733 break; 734 case LEAF_pfTablesTblTZero: 735 val->v.uint32 = 736 (time(NULL) - e->pft.pfrts_tzero) * 100; 737 break; 738 case LEAF_pfTablesTblRefsAnchor: 739 val->v.integer = 740 e->pft.pfrts_refcnt[PFR_REFCNT_ANCHOR]; 741 break; 742 case LEAF_pfTablesTblRefsRule: 743 val->v.integer = 744 e->pft.pfrts_refcnt[PFR_REFCNT_RULE]; 745 break; 746 case LEAF_pfTablesTblEvalMatch: 747 val->v.counter64 = e->pft.pfrts_match; 748 break; 749 case LEAF_pfTablesTblEvalNoMatch: 750 val->v.counter64 = e->pft.pfrts_nomatch; 751 break; 752 case LEAF_pfTablesTblBytesInPass: 753 val->v.counter64 = 754 e->pft.pfrts_bytes[PFR_DIR_IN][PFR_OP_PASS]; 755 break; 756 case LEAF_pfTablesTblBytesInBlock: 757 val->v.counter64 = 758 e->pft.pfrts_bytes[PFR_DIR_IN][PFR_OP_BLOCK]; 759 break; 760 case LEAF_pfTablesTblBytesInXPass: 761 val->v.counter64 = 762 e->pft.pfrts_bytes[PFR_DIR_IN][PFR_OP_XPASS]; 763 break; 764 case LEAF_pfTablesTblBytesOutPass: 765 val->v.counter64 = 766 e->pft.pfrts_bytes[PFR_DIR_OUT][PFR_OP_PASS]; 767 break; 768 case LEAF_pfTablesTblBytesOutBlock: 769 val->v.counter64 = 770 e->pft.pfrts_bytes[PFR_DIR_OUT][PFR_OP_BLOCK]; 771 break; 772 case LEAF_pfTablesTblBytesOutXPass: 773 val->v.counter64 = 774 e->pft.pfrts_bytes[PFR_DIR_OUT][PFR_OP_XPASS]; 775 break; 776 case LEAF_pfTablesTblPktsInPass: 777 val->v.counter64 = 778 e->pft.pfrts_packets[PFR_DIR_IN][PFR_OP_PASS]; 779 break; 780 case LEAF_pfTablesTblPktsInBlock: 781 val->v.counter64 = 782 e->pft.pfrts_packets[PFR_DIR_IN][PFR_OP_BLOCK]; 783 break; 784 case LEAF_pfTablesTblPktsInXPass: 785 val->v.counter64 = 786 e->pft.pfrts_packets[PFR_DIR_IN][PFR_OP_XPASS]; 787 break; 788 case LEAF_pfTablesTblPktsOutPass: 789 val->v.counter64 = 790 e->pft.pfrts_packets[PFR_DIR_OUT][PFR_OP_PASS]; 791 break; 792 case LEAF_pfTablesTblPktsOutBlock: 793 val->v.counter64 = 794 e->pft.pfrts_packets[PFR_DIR_OUT][PFR_OP_BLOCK]; 795 break; 796 case LEAF_pfTablesTblPktsOutXPass: 797 val->v.counter64 = 798 e->pft.pfrts_packets[PFR_DIR_OUT][PFR_OP_XPASS]; 799 break; 800 801 default: 802 return (SNMP_ERR_NOSUCHNAME); 803 } 804 805 return (SNMP_ERR_NOERROR); 806 } 807 808 int 809 pf_tbladdr(struct snmp_context __unused *ctx, struct snmp_value __unused *val, 810 u_int __unused sub, u_int __unused vindex, enum snmp_op __unused op) 811 { 812 asn_subid_t which = val->var.subs[sub - 1]; 813 struct pfa_entry *e = NULL; 814 815 if ((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 906 int 907 pf_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 939 int 940 pf_altqq(struct snmp_context __unused *ctx, struct snmp_value *val, 941 u_int sub, u_int __unused vindex, enum snmp_op op) 942 { 943 asn_subid_t which = val->var.subs[sub - 1]; 944 struct pfq_entry *e = NULL; 945 946 if (!altq_enabled) 947 return (SNMP_ERR_NOSUCHNAME); 948 949 if ((time(NULL) - pfq_table_age) > PFQ_TABLE_MAXAGE) 950 pfq_refresh(); 951 952 switch (op) { 953 case SNMP_OP_SET: 954 return (SNMP_ERR_NOT_WRITEABLE); 955 case SNMP_OP_GETNEXT: 956 if ((e = NEXT_OBJECT_INT(&pfq_table, 957 &val->var, sub)) == NULL) 958 return (SNMP_ERR_NOSUCHNAME); 959 val->var.len = sub + 1; 960 val->var.subs[sub] = e->index; 961 break; 962 case SNMP_OP_GET: 963 if (val->var.len - sub != 1) 964 return (SNMP_ERR_NOSUCHNAME); 965 if ((e = pfq_table_find(val->var.subs[sub])) == NULL) 966 return (SNMP_ERR_NOSUCHNAME); 967 break; 968 969 case SNMP_OP_COMMIT: 970 case SNMP_OP_ROLLBACK: 971 default: 972 abort(); 973 } 974 975 switch (which) { 976 case LEAF_pfAltqQueueDescr: 977 return (string_get(val, e->altq.qname, -1)); 978 case LEAF_pfAltqQueueParent: 979 return (string_get(val, e->altq.parent, -1)); 980 case LEAF_pfAltqQueueScheduler: 981 val->v.integer = e->altq.scheduler; 982 break; 983 case LEAF_pfAltqQueueBandwidth: 984 val->v.uint32 = e->altq.bandwidth; 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 1000 int 1001 pf_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 1030 int 1031 pf_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 1088 static struct pfi_entry * 1089 pfi_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 1099 static struct pfq_entry * 1100 pfq_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 1110 static struct pft_entry * 1111 pft_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 1121 static struct pfa_entry * 1122 pfa_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 1132 static struct pfl_entry * 1133 pfl_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 1144 static int 1145 pfi_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 1202 err1: 1203 while (!TAILQ_EMPTY(&pfi_table)) { 1204 e = TAILQ_FIRST(&pfi_table); 1205 TAILQ_REMOVE(&pfi_table, e, link); 1206 free(e); 1207 } 1208 err2: 1209 free(p); 1210 return(-1); 1211 } 1212 1213 static int 1214 pfq_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); 1270 err: 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 1280 static int 1281 pfs_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 1298 static int 1299 pft_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); 1355 err1: 1356 while (!TAILQ_EMPTY(&pft_table)) { 1357 e = TAILQ_FIRST(&pft_table); 1358 TAILQ_REMOVE(&pft_table, e, link); 1359 free(e); 1360 } 1361 err2: 1362 free(t); 1363 return(-1); 1364 } 1365 1366 static int 1367 pfa_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); 1428 error: 1429 return (numaddrs); 1430 } 1431 1432 static int 1433 pfa_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); 1497 err1: 1498 while (!TAILQ_EMPTY(&pfa_table)) { 1499 e = TAILQ_FIRST(&pfa_table); 1500 TAILQ_REMOVE(&pfa_table, e, link); 1501 free(e); 1502 } 1503 1504 err2: 1505 free(pt); 1506 return (-1); 1507 } 1508 1509 static int 1510 pfl_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 1556 err: 1557 return (-1); 1558 } 1559 1560 static int 1561 pfl_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 1600 err: 1601 return (-1); 1602 } 1603 1604 static int 1605 pfl_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 1627 err: 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 1642 static int 1643 altq_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 return (1); 1659 } 1660 1661 /* 1662 * Implement the bsnmpd module interface 1663 */ 1664 static int 1665 pf_init(struct lmodule *mod, int __unused argc, char __unused *argv[]) 1666 { 1667 module = mod; 1668 1669 if ((dev = open("/dev/pf", O_RDONLY)) == -1) { 1670 syslog(LOG_ERR, "pf_init(): open(): %s\n", 1671 strerror(errno)); 1672 return (-1); 1673 } 1674 1675 if ((altq_enabled = altq_is_enabled(dev)) == -1) { 1676 syslog(LOG_ERR, "pf_init(): altq test failed"); 1677 return (-1); 1678 } 1679 1680 /* Prepare internal state */ 1681 TAILQ_INIT(&pfi_table); 1682 TAILQ_INIT(&pfq_table); 1683 TAILQ_INIT(&pft_table); 1684 TAILQ_INIT(&pfa_table); 1685 TAILQ_INIT(&pfl_table); 1686 1687 pfi_refresh(); 1688 if (altq_enabled) { 1689 pfq_refresh(); 1690 } 1691 1692 pfs_refresh(); 1693 pft_refresh(); 1694 pfa_refresh(); 1695 pfl_refresh(); 1696 1697 started = 1; 1698 1699 return (0); 1700 } 1701 1702 static int 1703 pf_fini(void) 1704 { 1705 struct pfi_entry *i1, *i2; 1706 struct pfq_entry *q1, *q2; 1707 struct pft_entry *t1, *t2; 1708 struct pfa_entry *a1, *a2; 1709 struct pfl_entry *l1, *l2; 1710 1711 /* Empty the list of interfaces */ 1712 i1 = TAILQ_FIRST(&pfi_table); 1713 while (i1 != NULL) { 1714 i2 = TAILQ_NEXT(i1, link); 1715 free(i1); 1716 i1 = i2; 1717 } 1718 1719 /* List of queues */ 1720 q1 = TAILQ_FIRST(&pfq_table); 1721 while (q1 != NULL) { 1722 q2 = TAILQ_NEXT(q1, link); 1723 free(q1); 1724 q1 = q2; 1725 } 1726 1727 /* List of tables */ 1728 t1 = TAILQ_FIRST(&pft_table); 1729 while (t1 != NULL) { 1730 t2 = TAILQ_NEXT(t1, link); 1731 free(t1); 1732 t1 = t2; 1733 } 1734 1735 /* List of table addresses */ 1736 a1 = TAILQ_FIRST(&pfa_table); 1737 while (a1 != NULL) { 1738 a2 = TAILQ_NEXT(a1, link); 1739 free(a1); 1740 a1 = a2; 1741 } 1742 1743 /* And the list of labeled filter rules */ 1744 l1 = TAILQ_FIRST(&pfl_table); 1745 while (l1 != NULL) { 1746 l2 = TAILQ_NEXT(l1, link); 1747 free(l1); 1748 l1 = l2; 1749 } 1750 1751 close(dev); 1752 return (0); 1753 } 1754 1755 static void 1756 pf_dump(void) 1757 { 1758 pfi_refresh(); 1759 if (altq_enabled) { 1760 pfq_refresh(); 1761 } 1762 pft_refresh(); 1763 pfa_refresh(); 1764 pfl_refresh(); 1765 1766 syslog(LOG_ERR, "Dump: pfi_table_age = %jd", 1767 (intmax_t)pfi_table_age); 1768 syslog(LOG_ERR, "Dump: pfi_table_count = %d", 1769 pfi_table_count); 1770 1771 syslog(LOG_ERR, "Dump: pfq_table_age = %jd", 1772 (intmax_t)pfq_table_age); 1773 syslog(LOG_ERR, "Dump: pfq_table_count = %d", 1774 pfq_table_count); 1775 1776 syslog(LOG_ERR, "Dump: pft_table_age = %jd", 1777 (intmax_t)pft_table_age); 1778 syslog(LOG_ERR, "Dump: pft_table_count = %d", 1779 pft_table_count); 1780 1781 syslog(LOG_ERR, "Dump: pfa_table_age = %jd", 1782 (intmax_t)pfa_table_age); 1783 syslog(LOG_ERR, "Dump: pfa_table_count = %d", 1784 pfa_table_count); 1785 1786 syslog(LOG_ERR, "Dump: pfl_table_age = %jd", 1787 (intmax_t)pfl_table_age); 1788 syslog(LOG_ERR, "Dump: pfl_table_count = %d", 1789 pfl_table_count); 1790 } 1791 1792 const struct snmp_module config = { 1793 .comment = "This module implements a MIB for the pf packet filter.", 1794 .init = pf_init, 1795 .fini = pf_fini, 1796 .tree = pf_ctree, 1797 .dump = pf_dump, 1798 .tree_size = pf_CTREE_SIZE, 1799 }; 1800