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