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