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_pfInterfacesIfRefsState: 590 val->v.uint32 = e->pfi.pfik_states; 591 break; 592 case LEAF_pfInterfacesIfRefsRule: 593 val->v.uint32 = e->pfi.pfik_rules; 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