1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 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 29 #define PFIOC_USE_LATEST 30 31 #include <sys/queue.h> 32 #include <bsnmp/snmpmod.h> 33 34 #include <net/pfvar.h> 35 #include <sys/ioctl.h> 36 37 #include <errno.h> 38 #include <fcntl.h> 39 #include <libpfctl.h> 40 #include <stdint.h> 41 #include <stdio.h> 42 #include <stdlib.h> 43 #include <string.h> 44 #include <syslog.h> 45 #include <unistd.h> 46 47 #define SNMPTREE_TYPES 48 #include "pf_oid.h" 49 #include "pf_tree.h" 50 51 struct lmodule *module; 52 53 static int dev = -1; 54 static int started; 55 static uint64_t pf_tick; 56 57 static struct pf_status pfs; 58 59 enum { IN, OUT }; 60 enum { IPV4, IPV6 }; 61 enum { PASS, BLOCK }; 62 63 #define PFI_IFTYPE_GROUP 0 64 #define PFI_IFTYPE_INSTANCE 1 65 #define PFI_IFTYPE_DETACHED 2 66 67 struct pfi_entry { 68 struct pfi_kif pfi; 69 u_int index; 70 TAILQ_ENTRY(pfi_entry) link; 71 }; 72 TAILQ_HEAD(pfi_table, pfi_entry); 73 74 static struct pfi_table pfi_table; 75 static time_t pfi_table_age; 76 static int pfi_table_count; 77 78 #define PFI_TABLE_MAXAGE 5 79 80 struct pft_entry { 81 struct pfr_tstats pft; 82 u_int index; 83 TAILQ_ENTRY(pft_entry) link; 84 }; 85 TAILQ_HEAD(pft_table, pft_entry); 86 87 static struct pft_table pft_table; 88 static time_t pft_table_age; 89 static int pft_table_count; 90 91 #define PFT_TABLE_MAXAGE 5 92 93 struct pfa_entry { 94 struct pfr_astats pfas; 95 u_int index; 96 TAILQ_ENTRY(pfa_entry) link; 97 }; 98 TAILQ_HEAD(pfa_table, pfa_entry); 99 100 static struct pfa_table pfa_table; 101 static time_t pfa_table_age; 102 static int pfa_table_count; 103 104 #define PFA_TABLE_MAXAGE 5 105 106 struct pfq_entry { 107 struct pf_altq altq; 108 u_int index; 109 TAILQ_ENTRY(pfq_entry) link; 110 }; 111 TAILQ_HEAD(pfq_table, pfq_entry); 112 113 static struct pfq_table pfq_table; 114 static time_t pfq_table_age; 115 static int pfq_table_count; 116 117 static int altq_enabled = 0; 118 119 #define PFQ_TABLE_MAXAGE 5 120 121 struct pfl_entry { 122 char name[MAXPATHLEN + PF_RULE_LABEL_SIZE]; 123 u_int64_t evals; 124 u_int64_t bytes[2]; 125 u_int64_t pkts[2]; 126 u_int index; 127 TAILQ_ENTRY(pfl_entry) link; 128 }; 129 TAILQ_HEAD(pfl_table, pfl_entry); 130 131 static struct pfl_table pfl_table; 132 static time_t pfl_table_age; 133 static int pfl_table_count; 134 135 #define PFL_TABLE_MAXAGE 5 136 137 /* Forward declarations */ 138 static int pfi_refresh(void); 139 static int pfq_refresh(void); 140 static int pfs_refresh(void); 141 static int pft_refresh(void); 142 static int pfa_refresh(void); 143 static int pfl_refresh(void); 144 static struct pfi_entry * pfi_table_find(u_int idx); 145 static struct pfq_entry * pfq_table_find(u_int idx); 146 static struct pft_entry * pft_table_find(u_int idx); 147 static struct pfa_entry * pfa_table_find(u_int idx); 148 static struct pfl_entry * pfl_table_find(u_int idx); 149 150 static int altq_is_enabled(int pfdevice); 151 152 int 153 pf_status(struct snmp_context __unused *ctx, struct snmp_value *val, 154 u_int sub, u_int __unused vindex, enum snmp_op op) 155 { 156 asn_subid_t which = val->var.subs[sub - 1]; 157 time_t runtime; 158 unsigned char str[128]; 159 160 if (op == SNMP_OP_SET) 161 return (SNMP_ERR_NOT_WRITEABLE); 162 163 if (op == SNMP_OP_GET) { 164 if (pfs_refresh() == -1) 165 return (SNMP_ERR_GENERR); 166 167 switch (which) { 168 case LEAF_pfStatusRunning: 169 val->v.uint32 = pfs.running; 170 break; 171 case LEAF_pfStatusRuntime: 172 runtime = (pfs.since > 0) ? 173 time(NULL) - pfs.since : 0; 174 val->v.uint32 = runtime * 100; 175 break; 176 case LEAF_pfStatusDebug: 177 val->v.uint32 = pfs.debug; 178 break; 179 case LEAF_pfStatusHostId: 180 sprintf(str, "0x%08x", ntohl(pfs.hostid)); 181 return (string_get(val, str, strlen(str))); 182 183 default: 184 return (SNMP_ERR_NOSUCHNAME); 185 } 186 187 return (SNMP_ERR_NOERROR); 188 } 189 190 abort(); 191 } 192 193 int 194 pf_counter(struct snmp_context __unused *ctx, struct snmp_value *val, 195 u_int sub, u_int __unused vindex, enum snmp_op op) 196 { 197 asn_subid_t which = val->var.subs[sub - 1]; 198 199 if (op == SNMP_OP_SET) 200 return (SNMP_ERR_NOT_WRITEABLE); 201 202 if (op == SNMP_OP_GET) { 203 if (pfs_refresh() == -1) 204 return (SNMP_ERR_GENERR); 205 206 switch (which) { 207 case LEAF_pfCounterMatch: 208 val->v.counter64 = pfs.counters[PFRES_MATCH]; 209 break; 210 case LEAF_pfCounterBadOffset: 211 val->v.counter64 = pfs.counters[PFRES_BADOFF]; 212 break; 213 case LEAF_pfCounterFragment: 214 val->v.counter64 = pfs.counters[PFRES_FRAG]; 215 break; 216 case LEAF_pfCounterShort: 217 val->v.counter64 = pfs.counters[PFRES_SHORT]; 218 break; 219 case LEAF_pfCounterNormalize: 220 val->v.counter64 = pfs.counters[PFRES_NORM]; 221 break; 222 case LEAF_pfCounterMemDrop: 223 val->v.counter64 = pfs.counters[PFRES_MEMORY]; 224 break; 225 226 default: 227 return (SNMP_ERR_NOSUCHNAME); 228 } 229 230 return (SNMP_ERR_NOERROR); 231 } 232 233 abort(); 234 } 235 236 int 237 pf_statetable(struct snmp_context __unused *ctx, struct snmp_value *val, 238 u_int sub, u_int __unused vindex, enum snmp_op op) 239 { 240 asn_subid_t which = val->var.subs[sub - 1]; 241 242 if (op == SNMP_OP_SET) 243 return (SNMP_ERR_NOT_WRITEABLE); 244 245 if (op == SNMP_OP_GET) { 246 if (pfs_refresh() == -1) 247 return (SNMP_ERR_GENERR); 248 249 switch (which) { 250 case LEAF_pfStateTableCount: 251 val->v.uint32 = pfs.states; 252 break; 253 case LEAF_pfStateTableSearches: 254 val->v.counter64 = 255 pfs.fcounters[FCNT_STATE_SEARCH]; 256 break; 257 case LEAF_pfStateTableInserts: 258 val->v.counter64 = 259 pfs.fcounters[FCNT_STATE_INSERT]; 260 break; 261 case LEAF_pfStateTableRemovals: 262 val->v.counter64 = 263 pfs.fcounters[FCNT_STATE_REMOVALS]; 264 break; 265 266 default: 267 return (SNMP_ERR_NOSUCHNAME); 268 } 269 270 return (SNMP_ERR_NOERROR); 271 } 272 273 abort(); 274 } 275 276 int 277 pf_srcnodes(struct snmp_context __unused *ctx, struct snmp_value *val, 278 u_int sub, u_int __unused vindex, enum snmp_op op) 279 { 280 asn_subid_t which = val->var.subs[sub - 1]; 281 282 if (op == SNMP_OP_SET) 283 return (SNMP_ERR_NOT_WRITEABLE); 284 285 if (op == SNMP_OP_GET) { 286 if (pfs_refresh() == -1) 287 return (SNMP_ERR_GENERR); 288 289 switch (which) { 290 case LEAF_pfSrcNodesCount: 291 val->v.uint32 = pfs.src_nodes; 292 break; 293 case LEAF_pfSrcNodesSearches: 294 val->v.counter64 = 295 pfs.scounters[SCNT_SRC_NODE_SEARCH]; 296 break; 297 case LEAF_pfSrcNodesInserts: 298 val->v.counter64 = 299 pfs.scounters[SCNT_SRC_NODE_INSERT]; 300 break; 301 case LEAF_pfSrcNodesRemovals: 302 val->v.counter64 = 303 pfs.scounters[SCNT_SRC_NODE_REMOVALS]; 304 break; 305 306 default: 307 return (SNMP_ERR_NOSUCHNAME); 308 } 309 310 return (SNMP_ERR_NOERROR); 311 } 312 313 abort(); 314 } 315 316 int 317 pf_limits(struct snmp_context __unused *ctx, struct snmp_value *val, 318 u_int sub, u_int __unused vindex, enum snmp_op op) 319 { 320 asn_subid_t which = val->var.subs[sub - 1]; 321 struct pfioc_limit pl; 322 323 if (op == SNMP_OP_SET) 324 return (SNMP_ERR_NOT_WRITEABLE); 325 326 if (op == SNMP_OP_GET) { 327 bzero(&pl, sizeof(struct pfioc_limit)); 328 329 switch (which) { 330 case LEAF_pfLimitsStates: 331 pl.index = PF_LIMIT_STATES; 332 break; 333 case LEAF_pfLimitsSrcNodes: 334 pl.index = PF_LIMIT_SRC_NODES; 335 break; 336 case LEAF_pfLimitsFrags: 337 pl.index = PF_LIMIT_FRAGS; 338 break; 339 340 default: 341 return (SNMP_ERR_NOSUCHNAME); 342 } 343 344 if (ioctl(dev, DIOCGETLIMIT, &pl)) { 345 syslog(LOG_ERR, "pf_limits(): ioctl(): %s", 346 strerror(errno)); 347 return (SNMP_ERR_GENERR); 348 } 349 350 val->v.uint32 = pl.limit; 351 352 return (SNMP_ERR_NOERROR); 353 } 354 355 abort(); 356 } 357 358 int 359 pf_timeouts(struct snmp_context __unused *ctx, struct snmp_value *val, 360 u_int sub, u_int __unused vindex, enum snmp_op op) 361 { 362 asn_subid_t which = val->var.subs[sub - 1]; 363 struct pfioc_tm pt; 364 365 if (op == SNMP_OP_SET) 366 return (SNMP_ERR_NOT_WRITEABLE); 367 368 if (op == SNMP_OP_GET) { 369 bzero(&pt, sizeof(struct pfioc_tm)); 370 371 switch (which) { 372 case LEAF_pfTimeoutsTcpFirst: 373 pt.timeout = PFTM_TCP_FIRST_PACKET; 374 break; 375 case LEAF_pfTimeoutsTcpOpening: 376 pt.timeout = PFTM_TCP_OPENING; 377 break; 378 case LEAF_pfTimeoutsTcpEstablished: 379 pt.timeout = PFTM_TCP_ESTABLISHED; 380 break; 381 case LEAF_pfTimeoutsTcpClosing: 382 pt.timeout = PFTM_TCP_CLOSING; 383 break; 384 case LEAF_pfTimeoutsTcpFinWait: 385 pt.timeout = PFTM_TCP_FIN_WAIT; 386 break; 387 case LEAF_pfTimeoutsTcpClosed: 388 pt.timeout = PFTM_TCP_CLOSED; 389 break; 390 case LEAF_pfTimeoutsUdpFirst: 391 pt.timeout = PFTM_UDP_FIRST_PACKET; 392 break; 393 case LEAF_pfTimeoutsUdpSingle: 394 pt.timeout = PFTM_UDP_SINGLE; 395 break; 396 case LEAF_pfTimeoutsUdpMultiple: 397 pt.timeout = PFTM_UDP_MULTIPLE; 398 break; 399 case LEAF_pfTimeoutsIcmpFirst: 400 pt.timeout = PFTM_ICMP_FIRST_PACKET; 401 break; 402 case LEAF_pfTimeoutsIcmpError: 403 pt.timeout = PFTM_ICMP_ERROR_REPLY; 404 break; 405 case LEAF_pfTimeoutsOtherFirst: 406 pt.timeout = PFTM_OTHER_FIRST_PACKET; 407 break; 408 case LEAF_pfTimeoutsOtherSingle: 409 pt.timeout = PFTM_OTHER_SINGLE; 410 break; 411 case LEAF_pfTimeoutsOtherMultiple: 412 pt.timeout = PFTM_OTHER_MULTIPLE; 413 break; 414 case LEAF_pfTimeoutsFragment: 415 pt.timeout = PFTM_FRAG; 416 break; 417 case LEAF_pfTimeoutsInterval: 418 pt.timeout = PFTM_INTERVAL; 419 break; 420 case LEAF_pfTimeoutsAdaptiveStart: 421 pt.timeout = PFTM_ADAPTIVE_START; 422 break; 423 case LEAF_pfTimeoutsAdaptiveEnd: 424 pt.timeout = PFTM_ADAPTIVE_END; 425 break; 426 case LEAF_pfTimeoutsSrcNode: 427 pt.timeout = PFTM_SRC_NODE; 428 break; 429 430 default: 431 return (SNMP_ERR_NOSUCHNAME); 432 } 433 434 if (ioctl(dev, DIOCGETTIMEOUT, &pt)) { 435 syslog(LOG_ERR, "pf_timeouts(): ioctl(): %s", 436 strerror(errno)); 437 return (SNMP_ERR_GENERR); 438 } 439 440 val->v.integer = pt.seconds; 441 442 return (SNMP_ERR_NOERROR); 443 } 444 445 abort(); 446 } 447 448 int 449 pf_logif(struct snmp_context __unused *ctx, struct snmp_value *val, 450 u_int sub, u_int __unused vindex, enum snmp_op op) 451 { 452 asn_subid_t which = val->var.subs[sub - 1]; 453 unsigned char str[IFNAMSIZ]; 454 455 if (op == SNMP_OP_SET) 456 return (SNMP_ERR_NOT_WRITEABLE); 457 458 if (op == SNMP_OP_GET) { 459 if (pfs_refresh() == -1) 460 return (SNMP_ERR_GENERR); 461 462 switch (which) { 463 case LEAF_pfLogInterfaceName: 464 strlcpy(str, pfs.ifname, sizeof str); 465 return (string_get(val, str, strlen(str))); 466 case LEAF_pfLogInterfaceIp4BytesIn: 467 val->v.counter64 = pfs.bcounters[IPV4][IN]; 468 break; 469 case LEAF_pfLogInterfaceIp4BytesOut: 470 val->v.counter64 = pfs.bcounters[IPV4][OUT]; 471 break; 472 case LEAF_pfLogInterfaceIp4PktsInPass: 473 val->v.counter64 = 474 pfs.pcounters[IPV4][IN][PF_PASS]; 475 break; 476 case LEAF_pfLogInterfaceIp4PktsInDrop: 477 val->v.counter64 = 478 pfs.pcounters[IPV4][IN][PF_DROP]; 479 break; 480 case LEAF_pfLogInterfaceIp4PktsOutPass: 481 val->v.counter64 = 482 pfs.pcounters[IPV4][OUT][PF_PASS]; 483 break; 484 case LEAF_pfLogInterfaceIp4PktsOutDrop: 485 val->v.counter64 = 486 pfs.pcounters[IPV4][OUT][PF_DROP]; 487 break; 488 case LEAF_pfLogInterfaceIp6BytesIn: 489 val->v.counter64 = pfs.bcounters[IPV6][IN]; 490 break; 491 case LEAF_pfLogInterfaceIp6BytesOut: 492 val->v.counter64 = pfs.bcounters[IPV6][OUT]; 493 break; 494 case LEAF_pfLogInterfaceIp6PktsInPass: 495 val->v.counter64 = 496 pfs.pcounters[IPV6][IN][PF_PASS]; 497 break; 498 case LEAF_pfLogInterfaceIp6PktsInDrop: 499 val->v.counter64 = 500 pfs.pcounters[IPV6][IN][PF_DROP]; 501 break; 502 case LEAF_pfLogInterfaceIp6PktsOutPass: 503 val->v.counter64 = 504 pfs.pcounters[IPV6][OUT][PF_PASS]; 505 break; 506 case LEAF_pfLogInterfaceIp6PktsOutDrop: 507 val->v.counter64 = 508 pfs.pcounters[IPV6][OUT][PF_DROP]; 509 break; 510 511 default: 512 return (SNMP_ERR_NOSUCHNAME); 513 } 514 515 return (SNMP_ERR_NOERROR); 516 } 517 518 abort(); 519 } 520 521 int 522 pf_interfaces(struct snmp_context __unused *ctx, struct snmp_value *val, 523 u_int sub, u_int __unused vindex, enum snmp_op op) 524 { 525 asn_subid_t which = val->var.subs[sub - 1]; 526 527 if (op == SNMP_OP_SET) 528 return (SNMP_ERR_NOT_WRITEABLE); 529 530 if (op == SNMP_OP_GET) { 531 if ((time(NULL) - pfi_table_age) > PFI_TABLE_MAXAGE) 532 if (pfi_refresh() == -1) 533 return (SNMP_ERR_GENERR); 534 535 switch (which) { 536 case LEAF_pfInterfacesIfNumber: 537 val->v.uint32 = pfi_table_count; 538 break; 539 540 default: 541 return (SNMP_ERR_NOSUCHNAME); 542 } 543 544 return (SNMP_ERR_NOERROR); 545 } 546 547 abort(); 548 } 549 550 int 551 pf_iftable(struct snmp_context __unused *ctx, struct snmp_value *val, 552 u_int sub, u_int __unused vindex, enum snmp_op op) 553 { 554 asn_subid_t which = val->var.subs[sub - 1]; 555 struct pfi_entry *e = NULL; 556 557 if ((time(NULL) - pfi_table_age) > PFI_TABLE_MAXAGE) 558 pfi_refresh(); 559 560 switch (op) { 561 case SNMP_OP_SET: 562 return (SNMP_ERR_NOT_WRITEABLE); 563 case SNMP_OP_GETNEXT: 564 if ((e = NEXT_OBJECT_INT(&pfi_table, 565 &val->var, sub)) == NULL) 566 return (SNMP_ERR_NOSUCHNAME); 567 val->var.len = sub + 1; 568 val->var.subs[sub] = e->index; 569 break; 570 case SNMP_OP_GET: 571 if (val->var.len - sub != 1) 572 return (SNMP_ERR_NOSUCHNAME); 573 if ((e = pfi_table_find(val->var.subs[sub])) == NULL) 574 return (SNMP_ERR_NOSUCHNAME); 575 break; 576 577 case SNMP_OP_COMMIT: 578 case SNMP_OP_ROLLBACK: 579 default: 580 abort(); 581 } 582 583 switch (which) { 584 case LEAF_pfInterfacesIfDescr: 585 return (string_get(val, e->pfi.pfik_name, -1)); 586 case LEAF_pfInterfacesIfType: 587 val->v.integer = PFI_IFTYPE_INSTANCE; 588 break; 589 case LEAF_pfInterfacesIfTZero: 590 val->v.uint32 = 591 (time(NULL) - e->pfi.pfik_tzero) * 100; 592 break; 593 case LEAF_pfInterfacesIfRefsRule: 594 val->v.uint32 = e->pfi.pfik_rulerefs; 595 break; 596 case LEAF_pfInterfacesIf4BytesInPass: 597 val->v.counter64 = 598 e->pfi.pfik_bytes[IPV4][IN][PASS]; 599 break; 600 case LEAF_pfInterfacesIf4BytesInBlock: 601 val->v.counter64 = 602 e->pfi.pfik_bytes[IPV4][IN][BLOCK]; 603 break; 604 case LEAF_pfInterfacesIf4BytesOutPass: 605 val->v.counter64 = 606 e->pfi.pfik_bytes[IPV4][OUT][PASS]; 607 break; 608 case LEAF_pfInterfacesIf4BytesOutBlock: 609 val->v.counter64 = 610 e->pfi.pfik_bytes[IPV4][OUT][BLOCK]; 611 break; 612 case LEAF_pfInterfacesIf4PktsInPass: 613 val->v.counter64 = 614 e->pfi.pfik_packets[IPV4][IN][PASS]; 615 break; 616 case LEAF_pfInterfacesIf4PktsInBlock: 617 val->v.counter64 = 618 e->pfi.pfik_packets[IPV4][IN][BLOCK]; 619 break; 620 case LEAF_pfInterfacesIf4PktsOutPass: 621 val->v.counter64 = 622 e->pfi.pfik_packets[IPV4][OUT][PASS]; 623 break; 624 case LEAF_pfInterfacesIf4PktsOutBlock: 625 val->v.counter64 = 626 e->pfi.pfik_packets[IPV4][OUT][BLOCK]; 627 break; 628 case LEAF_pfInterfacesIf6BytesInPass: 629 val->v.counter64 = 630 e->pfi.pfik_bytes[IPV6][IN][PASS]; 631 break; 632 case LEAF_pfInterfacesIf6BytesInBlock: 633 val->v.counter64 = 634 e->pfi.pfik_bytes[IPV6][IN][BLOCK]; 635 break; 636 case LEAF_pfInterfacesIf6BytesOutPass: 637 val->v.counter64 = 638 e->pfi.pfik_bytes[IPV6][OUT][PASS]; 639 break; 640 case LEAF_pfInterfacesIf6BytesOutBlock: 641 val->v.counter64 = 642 e->pfi.pfik_bytes[IPV6][OUT][BLOCK]; 643 break; 644 case LEAF_pfInterfacesIf6PktsInPass: 645 val->v.counter64 = 646 e->pfi.pfik_packets[IPV6][IN][PASS]; 647 break; 648 case LEAF_pfInterfacesIf6PktsInBlock: 649 val->v.counter64 = 650 e->pfi.pfik_packets[IPV6][IN][BLOCK]; 651 break; 652 case LEAF_pfInterfacesIf6PktsOutPass: 653 val->v.counter64 = 654 e->pfi.pfik_packets[IPV6][OUT][PASS]; 655 break; 656 case LEAF_pfInterfacesIf6PktsOutBlock: 657 val->v.counter64 = 658 e->pfi.pfik_packets[IPV6][OUT][BLOCK]; 659 break; 660 661 default: 662 return (SNMP_ERR_NOSUCHNAME); 663 } 664 665 return (SNMP_ERR_NOERROR); 666 } 667 668 int 669 pf_tables(struct snmp_context __unused *ctx, struct snmp_value *val, 670 u_int sub, u_int __unused vindex, enum snmp_op op) 671 { 672 asn_subid_t which = val->var.subs[sub - 1]; 673 674 if (op == SNMP_OP_SET) 675 return (SNMP_ERR_NOT_WRITEABLE); 676 677 if (op == SNMP_OP_GET) { 678 if ((time(NULL) - pft_table_age) > PFT_TABLE_MAXAGE) 679 if (pft_refresh() == -1) 680 return (SNMP_ERR_GENERR); 681 682 switch (which) { 683 case LEAF_pfTablesTblNumber: 684 val->v.uint32 = pft_table_count; 685 break; 686 687 default: 688 return (SNMP_ERR_NOSUCHNAME); 689 } 690 691 return (SNMP_ERR_NOERROR); 692 } 693 694 abort(); 695 } 696 697 int 698 pf_tbltable(struct snmp_context __unused *ctx, struct snmp_value *val, 699 u_int sub, u_int __unused vindex, enum snmp_op op) 700 { 701 asn_subid_t which = val->var.subs[sub - 1]; 702 struct pft_entry *e = NULL; 703 704 if ((time(NULL) - pft_table_age) > PFT_TABLE_MAXAGE) 705 pft_refresh(); 706 707 switch (op) { 708 case SNMP_OP_SET: 709 return (SNMP_ERR_NOT_WRITEABLE); 710 case SNMP_OP_GETNEXT: 711 if ((e = NEXT_OBJECT_INT(&pft_table, 712 &val->var, sub)) == NULL) 713 return (SNMP_ERR_NOSUCHNAME); 714 val->var.len = sub + 1; 715 val->var.subs[sub] = e->index; 716 break; 717 case SNMP_OP_GET: 718 if (val->var.len - sub != 1) 719 return (SNMP_ERR_NOSUCHNAME); 720 if ((e = pft_table_find(val->var.subs[sub])) == NULL) 721 return (SNMP_ERR_NOSUCHNAME); 722 break; 723 724 case SNMP_OP_COMMIT: 725 case SNMP_OP_ROLLBACK: 726 default: 727 abort(); 728 } 729 730 switch (which) { 731 case LEAF_pfTablesTblDescr: 732 return (string_get(val, e->pft.pfrts_name, -1)); 733 case LEAF_pfTablesTblCount: 734 val->v.integer = e->pft.pfrts_cnt; 735 break; 736 case LEAF_pfTablesTblTZero: 737 val->v.uint32 = 738 (time(NULL) - e->pft.pfrts_tzero) * 100; 739 break; 740 case LEAF_pfTablesTblRefsAnchor: 741 val->v.integer = 742 e->pft.pfrts_refcnt[PFR_REFCNT_ANCHOR]; 743 break; 744 case LEAF_pfTablesTblRefsRule: 745 val->v.integer = 746 e->pft.pfrts_refcnt[PFR_REFCNT_RULE]; 747 break; 748 case LEAF_pfTablesTblEvalMatch: 749 val->v.counter64 = e->pft.pfrts_match; 750 break; 751 case LEAF_pfTablesTblEvalNoMatch: 752 val->v.counter64 = e->pft.pfrts_nomatch; 753 break; 754 case LEAF_pfTablesTblBytesInPass: 755 val->v.counter64 = 756 e->pft.pfrts_bytes[PFR_DIR_IN][PFR_OP_PASS]; 757 break; 758 case LEAF_pfTablesTblBytesInBlock: 759 val->v.counter64 = 760 e->pft.pfrts_bytes[PFR_DIR_IN][PFR_OP_BLOCK]; 761 break; 762 case LEAF_pfTablesTblBytesInXPass: 763 val->v.counter64 = 764 e->pft.pfrts_bytes[PFR_DIR_IN][PFR_OP_XPASS]; 765 break; 766 case LEAF_pfTablesTblBytesOutPass: 767 val->v.counter64 = 768 e->pft.pfrts_bytes[PFR_DIR_OUT][PFR_OP_PASS]; 769 break; 770 case LEAF_pfTablesTblBytesOutBlock: 771 val->v.counter64 = 772 e->pft.pfrts_bytes[PFR_DIR_OUT][PFR_OP_BLOCK]; 773 break; 774 case LEAF_pfTablesTblBytesOutXPass: 775 val->v.counter64 = 776 e->pft.pfrts_bytes[PFR_DIR_OUT][PFR_OP_XPASS]; 777 break; 778 case LEAF_pfTablesTblPktsInPass: 779 val->v.counter64 = 780 e->pft.pfrts_packets[PFR_DIR_IN][PFR_OP_PASS]; 781 break; 782 case LEAF_pfTablesTblPktsInBlock: 783 val->v.counter64 = 784 e->pft.pfrts_packets[PFR_DIR_IN][PFR_OP_BLOCK]; 785 break; 786 case LEAF_pfTablesTblPktsInXPass: 787 val->v.counter64 = 788 e->pft.pfrts_packets[PFR_DIR_IN][PFR_OP_XPASS]; 789 break; 790 case LEAF_pfTablesTblPktsOutPass: 791 val->v.counter64 = 792 e->pft.pfrts_packets[PFR_DIR_OUT][PFR_OP_PASS]; 793 break; 794 case LEAF_pfTablesTblPktsOutBlock: 795 val->v.counter64 = 796 e->pft.pfrts_packets[PFR_DIR_OUT][PFR_OP_BLOCK]; 797 break; 798 case LEAF_pfTablesTblPktsOutXPass: 799 val->v.counter64 = 800 e->pft.pfrts_packets[PFR_DIR_OUT][PFR_OP_XPASS]; 801 break; 802 803 default: 804 return (SNMP_ERR_NOSUCHNAME); 805 } 806 807 return (SNMP_ERR_NOERROR); 808 } 809 810 int 811 pf_tbladdr(struct snmp_context __unused *ctx, struct snmp_value __unused *val, 812 u_int __unused sub, u_int __unused vindex, enum snmp_op __unused op) 813 { 814 asn_subid_t which = val->var.subs[sub - 1]; 815 struct pfa_entry *e = NULL; 816 817 if ((time(NULL) - pfa_table_age) > PFA_TABLE_MAXAGE) 818 pfa_refresh(); 819 820 switch (op) { 821 case SNMP_OP_SET: 822 return (SNMP_ERR_NOT_WRITEABLE); 823 case SNMP_OP_GETNEXT: 824 if ((e = NEXT_OBJECT_INT(&pfa_table, 825 &val->var, sub)) == NULL) 826 return (SNMP_ERR_NOSUCHNAME); 827 val->var.len = sub + 1; 828 val->var.subs[sub] = e->index; 829 break; 830 case SNMP_OP_GET: 831 if (val->var.len - sub != 1) 832 return (SNMP_ERR_NOSUCHNAME); 833 if ((e = pfa_table_find(val->var.subs[sub])) == NULL) 834 return (SNMP_ERR_NOSUCHNAME); 835 break; 836 837 case SNMP_OP_COMMIT: 838 case SNMP_OP_ROLLBACK: 839 default: 840 abort(); 841 } 842 843 switch (which) { 844 case LEAF_pfTablesAddrNetType: 845 if (e->pfas.pfras_a.pfra_af == AF_INET) 846 val->v.integer = pfTablesAddrNetType_ipv4; 847 else if (e->pfas.pfras_a.pfra_af == AF_INET6) 848 val->v.integer = pfTablesAddrNetType_ipv6; 849 else 850 return (SNMP_ERR_GENERR); 851 break; 852 case LEAF_pfTablesAddrNet: 853 if (e->pfas.pfras_a.pfra_af == AF_INET) { 854 return (string_get(val, 855 (u_char *)&e->pfas.pfras_a.pfra_ip4addr, 4)); 856 } else if (e->pfas.pfras_a.pfra_af == AF_INET6) 857 return (string_get(val, 858 (u_char *)&e->pfas.pfras_a.pfra_ip6addr, 16)); 859 else 860 return (SNMP_ERR_GENERR); 861 break; 862 case LEAF_pfTablesAddrPrefix: 863 val->v.integer = (int32_t) e->pfas.pfras_a.pfra_net; 864 break; 865 case LEAF_pfTablesAddrTZero: 866 val->v.uint32 = 867 (time(NULL) - e->pfas.pfras_tzero) * 100; 868 break; 869 case LEAF_pfTablesAddrBytesInPass: 870 val->v.counter64 = 871 e->pfas.pfras_bytes[PFR_DIR_IN][PFR_OP_PASS]; 872 break; 873 case LEAF_pfTablesAddrBytesInBlock: 874 val->v.counter64 = 875 e->pfas.pfras_bytes[PFR_DIR_IN][PFR_OP_BLOCK]; 876 break; 877 case LEAF_pfTablesAddrBytesOutPass: 878 val->v.counter64 = 879 e->pfas.pfras_bytes[PFR_DIR_OUT][PFR_OP_PASS]; 880 break; 881 case LEAF_pfTablesAddrBytesOutBlock: 882 val->v.counter64 = 883 e->pfas.pfras_bytes[PFR_DIR_OUT][PFR_OP_BLOCK]; 884 break; 885 case LEAF_pfTablesAddrPktsInPass: 886 val->v.counter64 = 887 e->pfas.pfras_packets[PFR_DIR_IN][PFR_OP_PASS]; 888 break; 889 case LEAF_pfTablesAddrPktsInBlock: 890 val->v.counter64 = 891 e->pfas.pfras_packets[PFR_DIR_IN][PFR_OP_BLOCK]; 892 break; 893 case LEAF_pfTablesAddrPktsOutPass: 894 val->v.counter64 = 895 e->pfas.pfras_packets[PFR_DIR_OUT][PFR_OP_PASS]; 896 break; 897 case LEAF_pfTablesAddrPktsOutBlock: 898 val->v.counter64 = 899 e->pfas.pfras_packets[PFR_DIR_OUT][PFR_OP_BLOCK]; 900 break; 901 default: 902 return (SNMP_ERR_NOSUCHNAME); 903 } 904 905 return (SNMP_ERR_NOERROR); 906 } 907 908 int 909 pf_altq_num(struct snmp_context __unused *ctx, struct snmp_value *val, 910 u_int sub, u_int __unused vindex, enum snmp_op op) 911 { 912 asn_subid_t which = val->var.subs[sub - 1]; 913 914 if (!altq_enabled) 915 return (SNMP_ERR_NOSUCHNAME); 916 917 if (op == SNMP_OP_SET) 918 return (SNMP_ERR_NOT_WRITEABLE); 919 920 if (op == SNMP_OP_GET) { 921 if ((time(NULL) - pfq_table_age) > PFQ_TABLE_MAXAGE) 922 if (pfq_refresh() == -1) 923 return (SNMP_ERR_GENERR); 924 925 switch (which) { 926 case LEAF_pfAltqQueueNumber: 927 val->v.uint32 = pfq_table_count; 928 break; 929 930 default: 931 return (SNMP_ERR_NOSUCHNAME); 932 } 933 934 return (SNMP_ERR_NOERROR); 935 } 936 937 abort(); 938 return (SNMP_ERR_GENERR); 939 } 940 941 int 942 pf_altqq(struct snmp_context __unused *ctx, struct snmp_value *val, 943 u_int sub, u_int __unused vindex, enum snmp_op op) 944 { 945 asn_subid_t which = val->var.subs[sub - 1]; 946 struct pfq_entry *e = NULL; 947 948 if (!altq_enabled) 949 return (SNMP_ERR_NOSUCHNAME); 950 951 if ((time(NULL) - pfq_table_age) > PFQ_TABLE_MAXAGE) 952 pfq_refresh(); 953 954 switch (op) { 955 case SNMP_OP_SET: 956 return (SNMP_ERR_NOT_WRITEABLE); 957 case SNMP_OP_GETNEXT: 958 if ((e = NEXT_OBJECT_INT(&pfq_table, 959 &val->var, sub)) == NULL) 960 return (SNMP_ERR_NOSUCHNAME); 961 val->var.len = sub + 1; 962 val->var.subs[sub] = e->index; 963 break; 964 case SNMP_OP_GET: 965 if (val->var.len - sub != 1) 966 return (SNMP_ERR_NOSUCHNAME); 967 if ((e = pfq_table_find(val->var.subs[sub])) == NULL) 968 return (SNMP_ERR_NOSUCHNAME); 969 break; 970 971 case SNMP_OP_COMMIT: 972 case SNMP_OP_ROLLBACK: 973 default: 974 abort(); 975 } 976 977 switch (which) { 978 case LEAF_pfAltqQueueDescr: 979 return (string_get(val, e->altq.qname, -1)); 980 case LEAF_pfAltqQueueParent: 981 return (string_get(val, e->altq.parent, -1)); 982 case LEAF_pfAltqQueueScheduler: 983 val->v.integer = e->altq.scheduler; 984 break; 985 case LEAF_pfAltqQueueBandwidth: 986 val->v.uint32 = (e->altq.bandwidth > UINT_MAX) ? 987 UINT_MAX : (u_int32_t)e->altq.bandwidth; 988 break; 989 case LEAF_pfAltqQueuePriority: 990 val->v.integer = e->altq.priority; 991 break; 992 case LEAF_pfAltqQueueLimit: 993 val->v.integer = e->altq.qlimit; 994 break; 995 996 default: 997 return (SNMP_ERR_NOSUCHNAME); 998 } 999 1000 return (SNMP_ERR_NOERROR); 1001 } 1002 1003 int 1004 pf_labels(struct snmp_context __unused *ctx, struct snmp_value *val, 1005 u_int sub, u_int __unused vindex, enum snmp_op op) 1006 { 1007 asn_subid_t which = val->var.subs[sub - 1]; 1008 1009 if (op == SNMP_OP_SET) 1010 return (SNMP_ERR_NOT_WRITEABLE); 1011 1012 if (op == SNMP_OP_GET) { 1013 if ((time(NULL) - pfl_table_age) > PFL_TABLE_MAXAGE) 1014 if (pfl_refresh() == -1) 1015 return (SNMP_ERR_GENERR); 1016 1017 switch (which) { 1018 case LEAF_pfLabelsLblNumber: 1019 val->v.uint32 = pfl_table_count; 1020 break; 1021 1022 default: 1023 return (SNMP_ERR_NOSUCHNAME); 1024 } 1025 1026 return (SNMP_ERR_NOERROR); 1027 } 1028 1029 abort(); 1030 return (SNMP_ERR_GENERR); 1031 } 1032 1033 int 1034 pf_lbltable(struct snmp_context __unused *ctx, struct snmp_value *val, 1035 u_int sub, u_int __unused vindex, enum snmp_op op) 1036 { 1037 asn_subid_t which = val->var.subs[sub - 1]; 1038 struct pfl_entry *e = NULL; 1039 1040 if ((time(NULL) - pfl_table_age) > PFL_TABLE_MAXAGE) 1041 pfl_refresh(); 1042 1043 switch (op) { 1044 case SNMP_OP_SET: 1045 return (SNMP_ERR_NOT_WRITEABLE); 1046 case SNMP_OP_GETNEXT: 1047 if ((e = NEXT_OBJECT_INT(&pfl_table, 1048 &val->var, sub)) == NULL) 1049 return (SNMP_ERR_NOSUCHNAME); 1050 val->var.len = sub + 1; 1051 val->var.subs[sub] = e->index; 1052 break; 1053 case SNMP_OP_GET: 1054 if (val->var.len - sub != 1) 1055 return (SNMP_ERR_NOSUCHNAME); 1056 if ((e = pfl_table_find(val->var.subs[sub])) == NULL) 1057 return (SNMP_ERR_NOSUCHNAME); 1058 break; 1059 1060 case SNMP_OP_COMMIT: 1061 case SNMP_OP_ROLLBACK: 1062 default: 1063 abort(); 1064 } 1065 1066 switch (which) { 1067 case LEAF_pfLabelsLblName: 1068 return (string_get(val, e->name, -1)); 1069 case LEAF_pfLabelsLblEvals: 1070 val->v.counter64 = e->evals; 1071 break; 1072 case LEAF_pfLabelsLblBytesIn: 1073 val->v.counter64 = e->bytes[IN]; 1074 break; 1075 case LEAF_pfLabelsLblBytesOut: 1076 val->v.counter64 = e->bytes[OUT]; 1077 break; 1078 case LEAF_pfLabelsLblPktsIn: 1079 val->v.counter64 = e->pkts[IN]; 1080 break; 1081 case LEAF_pfLabelsLblPktsOut: 1082 val->v.counter64 = e->pkts[OUT]; 1083 break; 1084 default: 1085 return (SNMP_ERR_NOSUCHNAME); 1086 } 1087 1088 return (SNMP_ERR_NOERROR); 1089 } 1090 1091 static struct pfi_entry * 1092 pfi_table_find(u_int idx) 1093 { 1094 struct pfi_entry *e; 1095 1096 TAILQ_FOREACH(e, &pfi_table, link) 1097 if (e->index == idx) 1098 return (e); 1099 return (NULL); 1100 } 1101 1102 static struct pfq_entry * 1103 pfq_table_find(u_int idx) 1104 { 1105 struct pfq_entry *e; 1106 1107 TAILQ_FOREACH(e, &pfq_table, link) 1108 if (e->index == idx) 1109 return (e); 1110 return (NULL); 1111 } 1112 1113 static struct pft_entry * 1114 pft_table_find(u_int idx) 1115 { 1116 struct pft_entry *e; 1117 1118 TAILQ_FOREACH(e, &pft_table, link) 1119 if (e->index == idx) 1120 return (e); 1121 return (NULL); 1122 } 1123 1124 static struct pfa_entry * 1125 pfa_table_find(u_int idx) 1126 { 1127 struct pfa_entry *e; 1128 1129 TAILQ_FOREACH(e, &pfa_table, link) 1130 if (e->index == idx) 1131 return (e); 1132 return (NULL); 1133 } 1134 1135 static struct pfl_entry * 1136 pfl_table_find(u_int idx) 1137 { 1138 struct pfl_entry *e; 1139 1140 TAILQ_FOREACH(e, &pfl_table, link) 1141 if (e->index == idx) 1142 return (e); 1143 1144 return (NULL); 1145 } 1146 1147 static int 1148 pfi_refresh(void) 1149 { 1150 struct pfioc_iface io; 1151 struct pfi_kif *p = NULL; 1152 struct pfi_entry *e; 1153 int i, numifs = 1; 1154 1155 if (started && this_tick <= pf_tick) 1156 return (0); 1157 1158 while (!TAILQ_EMPTY(&pfi_table)) { 1159 e = TAILQ_FIRST(&pfi_table); 1160 TAILQ_REMOVE(&pfi_table, e, link); 1161 free(e); 1162 } 1163 1164 bzero(&io, sizeof(io)); 1165 io.pfiio_esize = sizeof(struct pfi_kif); 1166 1167 for (;;) { 1168 p = reallocf(p, numifs * sizeof(struct pfi_kif)); 1169 if (p == NULL) { 1170 syslog(LOG_ERR, "pfi_refresh(): reallocf() numifs=%d: %s", 1171 numifs, strerror(errno)); 1172 goto err2; 1173 } 1174 io.pfiio_size = numifs; 1175 io.pfiio_buffer = p; 1176 1177 if (ioctl(dev, DIOCIGETIFACES, &io)) { 1178 syslog(LOG_ERR, "pfi_refresh(): ioctl(): %s", 1179 strerror(errno)); 1180 goto err2; 1181 } 1182 1183 if (numifs >= io.pfiio_size) 1184 break; 1185 1186 numifs = io.pfiio_size; 1187 } 1188 1189 for (i = 0; i < numifs; i++) { 1190 e = malloc(sizeof(struct pfi_entry)); 1191 if (e == NULL) 1192 goto err1; 1193 e->index = i + 1; 1194 memcpy(&e->pfi, p+i, sizeof(struct pfi_kif)); 1195 TAILQ_INSERT_TAIL(&pfi_table, e, link); 1196 } 1197 1198 pfi_table_age = time(NULL); 1199 pfi_table_count = numifs; 1200 pf_tick = this_tick; 1201 1202 free(p); 1203 return (0); 1204 1205 err1: 1206 while (!TAILQ_EMPTY(&pfi_table)) { 1207 e = TAILQ_FIRST(&pfi_table); 1208 TAILQ_REMOVE(&pfi_table, e, link); 1209 free(e); 1210 } 1211 err2: 1212 free(p); 1213 return(-1); 1214 } 1215 1216 static int 1217 pfq_refresh(void) 1218 { 1219 struct pfioc_altq pa; 1220 struct pfq_entry *e; 1221 int i, numqs, ticket; 1222 1223 if (started && this_tick <= pf_tick) 1224 return (0); 1225 1226 while (!TAILQ_EMPTY(&pfq_table)) { 1227 e = TAILQ_FIRST(&pfq_table); 1228 TAILQ_REMOVE(&pfq_table, e, link); 1229 free(e); 1230 } 1231 1232 bzero(&pa, sizeof(pa)); 1233 pa.version = PFIOC_ALTQ_VERSION; 1234 if (ioctl(dev, DIOCGETALTQS, &pa)) { 1235 syslog(LOG_ERR, "pfq_refresh: ioctl(DIOCGETALTQS): %s", 1236 strerror(errno)); 1237 return (-1); 1238 } 1239 1240 numqs = pa.nr; 1241 ticket = pa.ticket; 1242 1243 for (i = 0; i < numqs; i++) { 1244 e = malloc(sizeof(struct pfq_entry)); 1245 if (e == NULL) { 1246 syslog(LOG_ERR, "pfq_refresh(): " 1247 "malloc(): %s", 1248 strerror(errno)); 1249 goto err; 1250 } 1251 pa.ticket = ticket; 1252 pa.nr = i; 1253 1254 if (ioctl(dev, DIOCGETALTQ, &pa)) { 1255 syslog(LOG_ERR, "pfq_refresh(): " 1256 "ioctl(DIOCGETALTQ): %s", 1257 strerror(errno)); 1258 goto err; 1259 } 1260 1261 if (pa.altq.qid > 0) { 1262 memcpy(&e->altq, &pa.altq, sizeof(struct pf_altq)); 1263 e->index = pa.altq.qid; 1264 pfq_table_count = i; 1265 INSERT_OBJECT_INT_LINK_INDEX(e, &pfq_table, link, index); 1266 } 1267 } 1268 1269 pfq_table_age = time(NULL); 1270 pf_tick = this_tick; 1271 1272 return (0); 1273 err: 1274 free(e); 1275 while (!TAILQ_EMPTY(&pfq_table)) { 1276 e = TAILQ_FIRST(&pfq_table); 1277 TAILQ_REMOVE(&pfq_table, e, link); 1278 free(e); 1279 } 1280 return(-1); 1281 } 1282 1283 static int 1284 pfs_refresh(void) 1285 { 1286 if (started && this_tick <= pf_tick) 1287 return (0); 1288 1289 bzero(&pfs, sizeof(struct pf_status)); 1290 1291 if (ioctl(dev, DIOCGETSTATUS, &pfs)) { 1292 syslog(LOG_ERR, "pfs_refresh(): ioctl(): %s", 1293 strerror(errno)); 1294 return (-1); 1295 } 1296 1297 pf_tick = this_tick; 1298 return (0); 1299 } 1300 1301 static int 1302 pft_refresh(void) 1303 { 1304 struct pfioc_table io; 1305 struct pfr_tstats *t = NULL; 1306 struct pft_entry *e; 1307 int i, numtbls = 1; 1308 1309 if (started && this_tick <= pf_tick) 1310 return (0); 1311 1312 while (!TAILQ_EMPTY(&pft_table)) { 1313 e = TAILQ_FIRST(&pft_table); 1314 TAILQ_REMOVE(&pft_table, e, link); 1315 free(e); 1316 } 1317 1318 bzero(&io, sizeof(io)); 1319 io.pfrio_esize = sizeof(struct pfr_tstats); 1320 1321 for (;;) { 1322 t = reallocf(t, numtbls * sizeof(struct pfr_tstats)); 1323 if (t == NULL) { 1324 syslog(LOG_ERR, "pft_refresh(): reallocf() numtbls=%d: %s", 1325 numtbls, strerror(errno)); 1326 goto err2; 1327 } 1328 io.pfrio_size = numtbls; 1329 io.pfrio_buffer = t; 1330 1331 if (ioctl(dev, DIOCRGETTSTATS, &io)) { 1332 syslog(LOG_ERR, "pft_refresh(): ioctl(): %s", 1333 strerror(errno)); 1334 goto err2; 1335 } 1336 1337 if (numtbls >= io.pfrio_size) 1338 break; 1339 1340 numtbls = io.pfrio_size; 1341 } 1342 1343 for (i = 0; i < numtbls; i++) { 1344 e = malloc(sizeof(struct pft_entry)); 1345 if (e == NULL) 1346 goto err1; 1347 e->index = i + 1; 1348 memcpy(&e->pft, t+i, sizeof(struct pfr_tstats)); 1349 TAILQ_INSERT_TAIL(&pft_table, e, link); 1350 } 1351 1352 pft_table_age = time(NULL); 1353 pft_table_count = numtbls; 1354 pf_tick = this_tick; 1355 1356 free(t); 1357 return (0); 1358 err1: 1359 while (!TAILQ_EMPTY(&pft_table)) { 1360 e = TAILQ_FIRST(&pft_table); 1361 TAILQ_REMOVE(&pft_table, e, link); 1362 free(e); 1363 } 1364 err2: 1365 free(t); 1366 return(-1); 1367 } 1368 1369 static int 1370 pfa_table_addrs(u_int sidx, struct pfr_table *pt) 1371 { 1372 struct pfioc_table io; 1373 struct pfr_astats *t = NULL; 1374 struct pfa_entry *e; 1375 int i, numaddrs = 1; 1376 1377 if (pt == NULL) 1378 return (-1); 1379 1380 memset(&io, 0, sizeof(io)); 1381 strlcpy(io.pfrio_table.pfrt_name, pt->pfrt_name, 1382 sizeof(io.pfrio_table.pfrt_name)); 1383 1384 for (;;) { 1385 t = reallocf(t, numaddrs * sizeof(struct pfr_astats)); 1386 if (t == NULL) { 1387 syslog(LOG_ERR, "pfa_table_addrs(): reallocf(): %s", 1388 strerror(errno)); 1389 numaddrs = -1; 1390 goto error; 1391 } 1392 1393 memset(t, 0, sizeof(*t)); 1394 io.pfrio_size = numaddrs; 1395 io.pfrio_buffer = t; 1396 io.pfrio_esize = sizeof(struct pfr_astats); 1397 1398 if (ioctl(dev, DIOCRGETASTATS, &io)) { 1399 syslog(LOG_ERR, "pfa_table_addrs(): ioctl() on %s: %s", 1400 pt->pfrt_name, strerror(errno)); 1401 numaddrs = -1; 1402 break; 1403 } 1404 1405 if (numaddrs >= io.pfrio_size) 1406 break; 1407 1408 numaddrs = io.pfrio_size; 1409 } 1410 1411 for (i = 0; i < numaddrs; i++) { 1412 if ((t + i)->pfras_a.pfra_af != AF_INET && 1413 (t + i)->pfras_a.pfra_af != AF_INET6) { 1414 numaddrs = i; 1415 break; 1416 } 1417 1418 e = (struct pfa_entry *)malloc(sizeof(struct pfa_entry)); 1419 if (e == NULL) { 1420 syslog(LOG_ERR, "pfa_table_addrs(): malloc(): %s", 1421 strerror(errno)); 1422 numaddrs = -1; 1423 break; 1424 } 1425 e->index = sidx + i; 1426 memcpy(&e->pfas, t + i, sizeof(struct pfr_astats)); 1427 TAILQ_INSERT_TAIL(&pfa_table, e, link); 1428 } 1429 1430 free(t); 1431 error: 1432 return (numaddrs); 1433 } 1434 1435 static int 1436 pfa_refresh(void) 1437 { 1438 struct pfioc_table io; 1439 struct pfr_table *pt = NULL, *it = NULL; 1440 struct pfa_entry *e; 1441 int i, numtbls = 1, cidx, naddrs; 1442 1443 if (started && this_tick <= pf_tick) 1444 return (0); 1445 1446 while (!TAILQ_EMPTY(&pfa_table)) { 1447 e = TAILQ_FIRST(&pfa_table); 1448 TAILQ_REMOVE(&pfa_table, e, link); 1449 free(e); 1450 } 1451 1452 memset(&io, 0, sizeof(io)); 1453 io.pfrio_esize = sizeof(struct pfr_table); 1454 1455 for (;;) { 1456 pt = reallocf(pt, numtbls * sizeof(struct pfr_table)); 1457 if (pt == NULL) { 1458 syslog(LOG_ERR, "pfa_refresh(): reallocf() %s", 1459 strerror(errno)); 1460 return (-1); 1461 } 1462 memset(pt, 0, sizeof(*pt)); 1463 io.pfrio_size = numtbls; 1464 io.pfrio_buffer = pt; 1465 1466 if (ioctl(dev, DIOCRGETTABLES, &io)) { 1467 syslog(LOG_ERR, "pfa_refresh(): ioctl(): %s", 1468 strerror(errno)); 1469 goto err2; 1470 } 1471 1472 if (numtbls >= io.pfrio_size) 1473 break; 1474 1475 numtbls = io.pfrio_size; 1476 } 1477 1478 cidx = 1; 1479 1480 for (it = pt, i = 0; i < numtbls; it++, i++) { 1481 /* 1482 * Skip the table if not active - ioctl(DIOCRGETASTATS) will 1483 * return ESRCH for this entry anyway. 1484 */ 1485 if (!(it->pfrt_flags & PFR_TFLAG_ACTIVE)) 1486 continue; 1487 1488 if ((naddrs = pfa_table_addrs(cidx, it)) < 0) 1489 goto err1; 1490 1491 cidx += naddrs; 1492 } 1493 1494 pfa_table_age = time(NULL); 1495 pfa_table_count = cidx; 1496 pf_tick = this_tick; 1497 1498 free(pt); 1499 return (0); 1500 err1: 1501 while (!TAILQ_EMPTY(&pfa_table)) { 1502 e = TAILQ_FIRST(&pfa_table); 1503 TAILQ_REMOVE(&pfa_table, e, link); 1504 free(e); 1505 } 1506 1507 err2: 1508 free(pt); 1509 return (-1); 1510 } 1511 1512 static int 1513 pfl_scan_ruleset(const char *path) 1514 { 1515 struct pfioc_rule pr; 1516 struct pfctl_rule rule; 1517 struct pfl_entry *e; 1518 u_int32_t nr, i; 1519 1520 bzero(&pr, sizeof(pr)); 1521 strlcpy(pr.anchor, path, sizeof(pr.anchor)); 1522 pr.rule.action = PF_PASS; 1523 if (ioctl(dev, DIOCGETRULES, &pr)) { 1524 syslog(LOG_ERR, "pfl_scan_ruleset: ioctl(DIOCGETRULES): %s", 1525 strerror(errno)); 1526 goto err; 1527 } 1528 1529 for (nr = pr.nr, i = 0; i < nr; i++) { 1530 pr.nr = i; 1531 if (pfctl_get_rule(dev, pr.nr, pr.ticket, pr.anchor, 1532 PF_PASS, &rule, pr.anchor_call)) { 1533 syslog(LOG_ERR, "pfl_scan_ruleset: ioctl(DIOCGETRULE):" 1534 " %s", strerror(errno)); 1535 goto err; 1536 } 1537 1538 if (rule.label[0]) { 1539 e = (struct pfl_entry *)malloc(sizeof(*e)); 1540 if (e == NULL) 1541 goto err; 1542 1543 strlcpy(e->name, path, sizeof(e->name)); 1544 if (path[0]) 1545 strlcat(e->name, "/", sizeof(e->name)); 1546 strlcat(e->name, rule.label[0], sizeof(e->name)); 1547 1548 e->evals = rule.evaluations; 1549 e->bytes[IN] = rule.bytes[IN]; 1550 e->bytes[OUT] = rule.bytes[OUT]; 1551 e->pkts[IN] = rule.packets[IN]; 1552 e->pkts[OUT] = rule.packets[OUT]; 1553 e->index = ++pfl_table_count; 1554 1555 TAILQ_INSERT_TAIL(&pfl_table, e, link); 1556 } 1557 } 1558 1559 return (0); 1560 1561 err: 1562 return (-1); 1563 } 1564 1565 static int 1566 pfl_walk_rulesets(const char *path) 1567 { 1568 struct pfioc_ruleset prs; 1569 char newpath[MAXPATHLEN]; 1570 u_int32_t nr, i; 1571 1572 if (pfl_scan_ruleset(path)) 1573 goto err; 1574 1575 bzero(&prs, sizeof(prs)); 1576 strlcpy(prs.path, path, sizeof(prs.path)); 1577 if (ioctl(dev, DIOCGETRULESETS, &prs)) { 1578 syslog(LOG_ERR, "pfl_walk_rulesets: ioctl(DIOCGETRULESETS): %s", 1579 strerror(errno)); 1580 goto err; 1581 } 1582 1583 for (nr = prs.nr, i = 0; i < nr; i++) { 1584 prs.nr = i; 1585 if (ioctl(dev, DIOCGETRULESET, &prs)) { 1586 syslog(LOG_ERR, "pfl_walk_rulesets: ioctl(DIOCGETRULESET):" 1587 " %s", strerror(errno)); 1588 goto err; 1589 } 1590 1591 if (strcmp(prs.name, PF_RESERVED_ANCHOR) == 0) 1592 continue; 1593 1594 strlcpy(newpath, path, sizeof(newpath)); 1595 if (path[0]) 1596 strlcat(newpath, "/", sizeof(newpath)); 1597 1598 strlcat(newpath, prs.name, sizeof(newpath)); 1599 if (pfl_walk_rulesets(newpath)) 1600 goto err; 1601 } 1602 1603 return (0); 1604 1605 err: 1606 return (-1); 1607 } 1608 1609 static int 1610 pfl_refresh(void) 1611 { 1612 struct pfl_entry *e; 1613 1614 if (started && this_tick <= pf_tick) 1615 return (0); 1616 1617 while (!TAILQ_EMPTY(&pfl_table)) { 1618 e = TAILQ_FIRST(&pfl_table); 1619 TAILQ_REMOVE(&pfl_table, e, link); 1620 free(e); 1621 } 1622 pfl_table_count = 0; 1623 1624 if (pfl_walk_rulesets("")) 1625 goto err; 1626 1627 pfl_table_age = time(NULL); 1628 pf_tick = this_tick; 1629 1630 return (0); 1631 1632 err: 1633 while (!TAILQ_EMPTY(&pfl_table)) { 1634 e = TAILQ_FIRST(&pfl_table); 1635 TAILQ_REMOVE(&pfl_table, e, link); 1636 free(e); 1637 } 1638 pfl_table_count = 0; 1639 1640 return (-1); 1641 } 1642 1643 /* 1644 * check whether altq support is enabled in kernel 1645 */ 1646 1647 static int 1648 altq_is_enabled(int pfdev) 1649 { 1650 struct pfioc_altq pa; 1651 1652 errno = 0; 1653 pa.version = PFIOC_ALTQ_VERSION; 1654 if (ioctl(pfdev, DIOCGETALTQS, &pa)) { 1655 if (errno == ENODEV) { 1656 syslog(LOG_INFO, "No ALTQ support in kernel\n" 1657 "ALTQ related functions disabled\n"); 1658 return (0); 1659 } else { 1660 syslog(LOG_ERR, "DIOCGETALTQS returned an error: %s", 1661 strerror(errno)); 1662 return (-1); 1663 } 1664 } 1665 return (1); 1666 } 1667 1668 /* 1669 * Implement the bsnmpd module interface 1670 */ 1671 static int 1672 pf_init(struct lmodule *mod, int __unused argc, char __unused *argv[]) 1673 { 1674 module = mod; 1675 1676 if ((dev = open("/dev/pf", O_RDONLY)) == -1) { 1677 syslog(LOG_ERR, "pf_init(): open(): %s\n", 1678 strerror(errno)); 1679 return (-1); 1680 } 1681 1682 if ((altq_enabled = altq_is_enabled(dev)) == -1) { 1683 syslog(LOG_ERR, "pf_init(): altq test failed"); 1684 return (-1); 1685 } 1686 1687 /* Prepare internal state */ 1688 TAILQ_INIT(&pfi_table); 1689 TAILQ_INIT(&pfq_table); 1690 TAILQ_INIT(&pft_table); 1691 TAILQ_INIT(&pfa_table); 1692 TAILQ_INIT(&pfl_table); 1693 1694 pfi_refresh(); 1695 if (altq_enabled) { 1696 pfq_refresh(); 1697 } 1698 1699 pfs_refresh(); 1700 pft_refresh(); 1701 pfa_refresh(); 1702 pfl_refresh(); 1703 1704 started = 1; 1705 1706 return (0); 1707 } 1708 1709 static int 1710 pf_fini(void) 1711 { 1712 struct pfi_entry *i1, *i2; 1713 struct pfq_entry *q1, *q2; 1714 struct pft_entry *t1, *t2; 1715 struct pfa_entry *a1, *a2; 1716 struct pfl_entry *l1, *l2; 1717 1718 /* Empty the list of interfaces */ 1719 i1 = TAILQ_FIRST(&pfi_table); 1720 while (i1 != NULL) { 1721 i2 = TAILQ_NEXT(i1, link); 1722 free(i1); 1723 i1 = i2; 1724 } 1725 1726 /* List of queues */ 1727 q1 = TAILQ_FIRST(&pfq_table); 1728 while (q1 != NULL) { 1729 q2 = TAILQ_NEXT(q1, link); 1730 free(q1); 1731 q1 = q2; 1732 } 1733 1734 /* List of tables */ 1735 t1 = TAILQ_FIRST(&pft_table); 1736 while (t1 != NULL) { 1737 t2 = TAILQ_NEXT(t1, link); 1738 free(t1); 1739 t1 = t2; 1740 } 1741 1742 /* List of table addresses */ 1743 a1 = TAILQ_FIRST(&pfa_table); 1744 while (a1 != NULL) { 1745 a2 = TAILQ_NEXT(a1, link); 1746 free(a1); 1747 a1 = a2; 1748 } 1749 1750 /* And the list of labeled filter rules */ 1751 l1 = TAILQ_FIRST(&pfl_table); 1752 while (l1 != NULL) { 1753 l2 = TAILQ_NEXT(l1, link); 1754 free(l1); 1755 l1 = l2; 1756 } 1757 1758 close(dev); 1759 return (0); 1760 } 1761 1762 static void 1763 pf_dump(void) 1764 { 1765 pfi_refresh(); 1766 if (altq_enabled) { 1767 pfq_refresh(); 1768 } 1769 pft_refresh(); 1770 pfa_refresh(); 1771 pfl_refresh(); 1772 1773 syslog(LOG_ERR, "Dump: pfi_table_age = %jd", 1774 (intmax_t)pfi_table_age); 1775 syslog(LOG_ERR, "Dump: pfi_table_count = %d", 1776 pfi_table_count); 1777 1778 syslog(LOG_ERR, "Dump: pfq_table_age = %jd", 1779 (intmax_t)pfq_table_age); 1780 syslog(LOG_ERR, "Dump: pfq_table_count = %d", 1781 pfq_table_count); 1782 1783 syslog(LOG_ERR, "Dump: pft_table_age = %jd", 1784 (intmax_t)pft_table_age); 1785 syslog(LOG_ERR, "Dump: pft_table_count = %d", 1786 pft_table_count); 1787 1788 syslog(LOG_ERR, "Dump: pfa_table_age = %jd", 1789 (intmax_t)pfa_table_age); 1790 syslog(LOG_ERR, "Dump: pfa_table_count = %d", 1791 pfa_table_count); 1792 1793 syslog(LOG_ERR, "Dump: pfl_table_age = %jd", 1794 (intmax_t)pfl_table_age); 1795 syslog(LOG_ERR, "Dump: pfl_table_count = %d", 1796 pfl_table_count); 1797 } 1798 1799 const struct snmp_module config = { 1800 .comment = "This module implements a MIB for the pf packet filter.", 1801 .init = pf_init, 1802 .fini = pf_fini, 1803 .tree = pf_ctree, 1804 .dump = pf_dump, 1805 .tree_size = pf_CTREE_SIZE, 1806 }; 1807