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