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