1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 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 29 #define PFIOC_USE_LATEST 30 31 #include <sys/queue.h> 32 #include <bsnmp/snmpmod.h> 33 34 #include <net/pfvar.h> 35 #include <sys/ioctl.h> 36 37 #include <errno.h> 38 #include <fcntl.h> 39 #include <libpfctl.h> 40 #include <stdint.h> 41 #include <stdio.h> 42 #include <stdlib.h> 43 #include <string.h> 44 #include <syslog.h> 45 #include <unistd.h> 46 47 #define SNMPTREE_TYPES 48 #include "pf_oid.h" 49 #include "pf_tree.h" 50 51 struct lmodule *module; 52 53 static struct pfctl_handle *pfh; 54 static int started; 55 static uint64_t pf_tick; 56 57 static struct pfctl_status *pfs; 58 59 enum { IN, OUT }; 60 enum { IPV4, IPV6 }; 61 enum { PASS, BLOCK }; 62 63 #define PFI_IFTYPE_GROUP 0 64 #define PFI_IFTYPE_INSTANCE 1 65 #define PFI_IFTYPE_DETACHED 2 66 67 struct pfi_entry { 68 struct pfi_kif pfi; 69 u_int index; 70 TAILQ_ENTRY(pfi_entry) link; 71 }; 72 TAILQ_HEAD(pfi_table, pfi_entry); 73 74 static struct pfi_table pfi_table; 75 static time_t pfi_table_age; 76 static int pfi_table_count; 77 78 #define PFI_TABLE_MAXAGE 5 79 80 struct pft_entry { 81 struct pfr_tstats pft; 82 u_int index; 83 TAILQ_ENTRY(pft_entry) link; 84 }; 85 TAILQ_HEAD(pft_table, pft_entry); 86 87 static struct pft_table pft_table; 88 static time_t pft_table_age; 89 static int pft_table_count; 90 91 #define PFT_TABLE_MAXAGE 5 92 93 struct pfa_entry { 94 struct pfr_astats pfas; 95 u_int index; 96 TAILQ_ENTRY(pfa_entry) link; 97 }; 98 TAILQ_HEAD(pfa_table, pfa_entry); 99 100 static struct pfa_table pfa_table; 101 static time_t pfa_table_age; 102 static int pfa_table_count; 103 104 #define PFA_TABLE_MAXAGE 5 105 106 struct pfq_entry { 107 struct pf_altq altq; 108 u_int index; 109 TAILQ_ENTRY(pfq_entry) link; 110 }; 111 TAILQ_HEAD(pfq_table, pfq_entry); 112 113 static struct pfq_table pfq_table; 114 static time_t pfq_table_age; 115 static int pfq_table_count; 116 117 static int altq_enabled = 0; 118 119 #define PFQ_TABLE_MAXAGE 5 120 121 struct pfl_entry { 122 char name[MAXPATHLEN + PF_RULE_LABEL_SIZE]; 123 u_int64_t evals; 124 u_int64_t bytes[2]; 125 u_int64_t pkts[2]; 126 u_int index; 127 TAILQ_ENTRY(pfl_entry) link; 128 }; 129 TAILQ_HEAD(pfl_table, pfl_entry); 130 131 static struct pfl_table pfl_table; 132 static time_t pfl_table_age; 133 static int pfl_table_count; 134 135 #define PFL_TABLE_MAXAGE 5 136 137 /* Forward declarations */ 138 static int pfi_refresh(void); 139 static int pfq_refresh(void); 140 static int pfs_refresh(void); 141 static int pft_refresh(void); 142 static int pfa_refresh(void); 143 static int pfl_refresh(void); 144 static struct pfi_entry * pfi_table_find(u_int idx); 145 static struct pfq_entry * pfq_table_find(u_int idx); 146 static struct pft_entry * pft_table_find(u_int idx); 147 static struct pfa_entry * pfa_table_find(u_int idx); 148 static struct pfl_entry * pfl_table_find(u_int idx); 149 150 static int altq_is_enabled(int pfdevice); 151 152 int 153 pf_status(struct snmp_context __unused *ctx, struct snmp_value *val, 154 u_int sub, u_int __unused vindex, enum snmp_op op) 155 { 156 asn_subid_t which = val->var.subs[sub - 1]; 157 time_t runtime; 158 unsigned char str[128]; 159 160 if (op == SNMP_OP_SET) 161 return (SNMP_ERR_NOT_WRITEABLE); 162 163 if (op == SNMP_OP_GET) { 164 if (pfs_refresh() == -1) 165 return (SNMP_ERR_GENERR); 166 167 switch (which) { 168 case LEAF_pfStatusRunning: 169 val->v.uint32 = pfs->running; 170 break; 171 case LEAF_pfStatusRuntime: 172 runtime = (pfs->since > 0) ? 173 time(NULL) - pfs->since : 0; 174 val->v.uint32 = runtime * 100; 175 break; 176 case LEAF_pfStatusDebug: 177 val->v.uint32 = pfs->debug; 178 break; 179 case LEAF_pfStatusHostId: 180 sprintf(str, "0x%08x", ntohl(pfs->hostid)); 181 return (string_get(val, str, strlen(str))); 182 183 default: 184 return (SNMP_ERR_NOSUCHNAME); 185 } 186 187 return (SNMP_ERR_NOERROR); 188 } 189 190 abort(); 191 } 192 193 int 194 pf_counter(struct snmp_context __unused *ctx, struct snmp_value *val, 195 u_int sub, u_int __unused vindex, enum snmp_op op) 196 { 197 asn_subid_t which = val->var.subs[sub - 1]; 198 199 if (op == SNMP_OP_SET) 200 return (SNMP_ERR_NOT_WRITEABLE); 201 202 if (op == SNMP_OP_GET) { 203 if (pfs_refresh() == -1) 204 return (SNMP_ERR_GENERR); 205 206 switch (which) { 207 case LEAF_pfCounterMatch: 208 val->v.counter64 = pfctl_status_counter(pfs, PFRES_MATCH); 209 break; 210 case LEAF_pfCounterBadOffset: 211 val->v.counter64 = pfctl_status_counter(pfs, PFRES_BADOFF); 212 break; 213 case LEAF_pfCounterFragment: 214 val->v.counter64 = pfctl_status_counter(pfs, PFRES_FRAG); 215 break; 216 case LEAF_pfCounterShort: 217 val->v.counter64 = pfctl_status_counter(pfs, PFRES_SHORT); 218 break; 219 case LEAF_pfCounterNormalize: 220 val->v.counter64 = pfctl_status_counter(pfs, PFRES_NORM); 221 break; 222 case LEAF_pfCounterMemDrop: 223 val->v.counter64 = pfctl_status_counter(pfs, PFRES_MEMORY); 224 break; 225 226 default: 227 return (SNMP_ERR_NOSUCHNAME); 228 } 229 230 return (SNMP_ERR_NOERROR); 231 } 232 233 abort(); 234 } 235 236 int 237 pf_statetable(struct snmp_context __unused *ctx, struct snmp_value *val, 238 u_int sub, u_int __unused vindex, enum snmp_op op) 239 { 240 asn_subid_t which = val->var.subs[sub - 1]; 241 242 if (op == SNMP_OP_SET) 243 return (SNMP_ERR_NOT_WRITEABLE); 244 245 if (op == SNMP_OP_GET) { 246 if (pfs_refresh() == -1) 247 return (SNMP_ERR_GENERR); 248 249 switch (which) { 250 case LEAF_pfStateTableCount: 251 val->v.uint32 = pfs->states; 252 break; 253 case LEAF_pfStateTableSearches: 254 val->v.counter64 = 255 pfctl_status_fcounter(pfs, FCNT_STATE_SEARCH); 256 break; 257 case LEAF_pfStateTableInserts: 258 val->v.counter64 = 259 pfctl_status_fcounter(pfs, FCNT_STATE_INSERT); 260 break; 261 case LEAF_pfStateTableRemovals: 262 val->v.counter64 = 263 pfctl_status_fcounter(pfs, FCNT_STATE_REMOVALS); 264 break; 265 266 default: 267 return (SNMP_ERR_NOSUCHNAME); 268 } 269 270 return (SNMP_ERR_NOERROR); 271 } 272 273 abort(); 274 } 275 276 int 277 pf_srcnodes(struct snmp_context __unused *ctx, struct snmp_value *val, 278 u_int sub, u_int __unused vindex, enum snmp_op op) 279 { 280 asn_subid_t which = val->var.subs[sub - 1]; 281 282 if (op == SNMP_OP_SET) 283 return (SNMP_ERR_NOT_WRITEABLE); 284 285 if (op == SNMP_OP_GET) { 286 if (pfs_refresh() == -1) 287 return (SNMP_ERR_GENERR); 288 289 switch (which) { 290 case LEAF_pfSrcNodesCount: 291 val->v.uint32 = pfs->src_nodes; 292 break; 293 case LEAF_pfSrcNodesSearches: 294 val->v.counter64 = 295 pfctl_status_scounter(pfs, SCNT_SRC_NODE_SEARCH); 296 break; 297 case LEAF_pfSrcNodesInserts: 298 val->v.counter64 = 299 pfctl_status_scounter(pfs, SCNT_SRC_NODE_INSERT); 300 break; 301 case LEAF_pfSrcNodesRemovals: 302 val->v.counter64 = 303 pfctl_status_scounter(pfs, SCNT_SRC_NODE_REMOVALS); 304 break; 305 306 default: 307 return (SNMP_ERR_NOSUCHNAME); 308 } 309 310 return (SNMP_ERR_NOERROR); 311 } 312 313 abort(); 314 } 315 316 int 317 pf_limits(struct snmp_context __unused *ctx, struct snmp_value *val, 318 u_int sub, u_int __unused vindex, enum snmp_op op) 319 { 320 asn_subid_t which = val->var.subs[sub - 1]; 321 unsigned int index, limit; 322 323 if (op == SNMP_OP_SET) 324 return (SNMP_ERR_NOT_WRITEABLE); 325 326 if (op == SNMP_OP_GET) { 327 switch (which) { 328 case LEAF_pfLimitsStates: 329 index = PF_LIMIT_STATES; 330 break; 331 case LEAF_pfLimitsSrcNodes: 332 index = PF_LIMIT_SRC_NODES; 333 break; 334 case LEAF_pfLimitsFrags: 335 index = PF_LIMIT_FRAGS; 336 break; 337 338 default: 339 return (SNMP_ERR_NOSUCHNAME); 340 } 341 342 if (pfctl_get_limit(pfh, index, &limit)) { 343 syslog(LOG_ERR, "pf_limits(): ioctl(): %s", 344 strerror(errno)); 345 return (SNMP_ERR_GENERR); 346 } 347 348 val->v.uint32 = limit; 349 350 return (SNMP_ERR_NOERROR); 351 } 352 353 abort(); 354 } 355 356 int 357 pf_timeouts(struct snmp_context __unused *ctx, struct snmp_value *val, 358 u_int sub, u_int __unused vindex, enum snmp_op op) 359 { 360 asn_subid_t which = val->var.subs[sub - 1]; 361 struct pfioc_tm pt; 362 363 if (op == SNMP_OP_SET) 364 return (SNMP_ERR_NOT_WRITEABLE); 365 366 if (op == SNMP_OP_GET) { 367 bzero(&pt, sizeof(struct pfioc_tm)); 368 369 switch (which) { 370 case LEAF_pfTimeoutsTcpFirst: 371 pt.timeout = PFTM_TCP_FIRST_PACKET; 372 break; 373 case LEAF_pfTimeoutsTcpOpening: 374 pt.timeout = PFTM_TCP_OPENING; 375 break; 376 case LEAF_pfTimeoutsTcpEstablished: 377 pt.timeout = PFTM_TCP_ESTABLISHED; 378 break; 379 case LEAF_pfTimeoutsTcpClosing: 380 pt.timeout = PFTM_TCP_CLOSING; 381 break; 382 case LEAF_pfTimeoutsTcpFinWait: 383 pt.timeout = PFTM_TCP_FIN_WAIT; 384 break; 385 case LEAF_pfTimeoutsTcpClosed: 386 pt.timeout = PFTM_TCP_CLOSED; 387 break; 388 case LEAF_pfTimeoutsUdpFirst: 389 pt.timeout = PFTM_UDP_FIRST_PACKET; 390 break; 391 case LEAF_pfTimeoutsUdpSingle: 392 pt.timeout = PFTM_UDP_SINGLE; 393 break; 394 case LEAF_pfTimeoutsUdpMultiple: 395 pt.timeout = PFTM_UDP_MULTIPLE; 396 break; 397 case LEAF_pfTimeoutsIcmpFirst: 398 pt.timeout = PFTM_ICMP_FIRST_PACKET; 399 break; 400 case LEAF_pfTimeoutsIcmpError: 401 pt.timeout = PFTM_ICMP_ERROR_REPLY; 402 break; 403 case LEAF_pfTimeoutsOtherFirst: 404 pt.timeout = PFTM_OTHER_FIRST_PACKET; 405 break; 406 case LEAF_pfTimeoutsOtherSingle: 407 pt.timeout = PFTM_OTHER_SINGLE; 408 break; 409 case LEAF_pfTimeoutsOtherMultiple: 410 pt.timeout = PFTM_OTHER_MULTIPLE; 411 break; 412 case LEAF_pfTimeoutsFragment: 413 pt.timeout = PFTM_FRAG; 414 break; 415 case LEAF_pfTimeoutsInterval: 416 pt.timeout = PFTM_INTERVAL; 417 break; 418 case LEAF_pfTimeoutsAdaptiveStart: 419 pt.timeout = PFTM_ADAPTIVE_START; 420 break; 421 case LEAF_pfTimeoutsAdaptiveEnd: 422 pt.timeout = PFTM_ADAPTIVE_END; 423 break; 424 case LEAF_pfTimeoutsSrcNode: 425 pt.timeout = PFTM_SRC_NODE; 426 break; 427 428 default: 429 return (SNMP_ERR_NOSUCHNAME); 430 } 431 432 if (ioctl(pfctl_fd(pfh), DIOCGETTIMEOUT, &pt)) { 433 syslog(LOG_ERR, "pf_timeouts(): ioctl(): %s", 434 strerror(errno)); 435 return (SNMP_ERR_GENERR); 436 } 437 438 val->v.integer = pt.seconds; 439 440 return (SNMP_ERR_NOERROR); 441 } 442 443 abort(); 444 } 445 446 int 447 pf_logif(struct snmp_context __unused *ctx, struct snmp_value *val, 448 u_int sub, u_int __unused vindex, enum snmp_op op) 449 { 450 asn_subid_t which = val->var.subs[sub - 1]; 451 unsigned char str[IFNAMSIZ]; 452 453 if (op == SNMP_OP_SET) 454 return (SNMP_ERR_NOT_WRITEABLE); 455 456 if (op == SNMP_OP_GET) { 457 if (pfs_refresh() == -1) 458 return (SNMP_ERR_GENERR); 459 460 switch (which) { 461 case LEAF_pfLogInterfaceName: 462 strlcpy(str, pfs->ifname, sizeof str); 463 return (string_get(val, str, strlen(str))); 464 case LEAF_pfLogInterfaceIp4BytesIn: 465 val->v.counter64 = pfs->bcounters[IPV4][IN]; 466 break; 467 case LEAF_pfLogInterfaceIp4BytesOut: 468 val->v.counter64 = pfs->bcounters[IPV4][OUT]; 469 break; 470 case LEAF_pfLogInterfaceIp4PktsInPass: 471 val->v.counter64 = 472 pfs->pcounters[IPV4][IN][PF_PASS]; 473 break; 474 case LEAF_pfLogInterfaceIp4PktsInDrop: 475 val->v.counter64 = 476 pfs->pcounters[IPV4][IN][PF_DROP]; 477 break; 478 case LEAF_pfLogInterfaceIp4PktsOutPass: 479 val->v.counter64 = 480 pfs->pcounters[IPV4][OUT][PF_PASS]; 481 break; 482 case LEAF_pfLogInterfaceIp4PktsOutDrop: 483 val->v.counter64 = 484 pfs->pcounters[IPV4][OUT][PF_DROP]; 485 break; 486 case LEAF_pfLogInterfaceIp6BytesIn: 487 val->v.counter64 = pfs->bcounters[IPV6][IN]; 488 break; 489 case LEAF_pfLogInterfaceIp6BytesOut: 490 val->v.counter64 = pfs->bcounters[IPV6][OUT]; 491 break; 492 case LEAF_pfLogInterfaceIp6PktsInPass: 493 val->v.counter64 = 494 pfs->pcounters[IPV6][IN][PF_PASS]; 495 break; 496 case LEAF_pfLogInterfaceIp6PktsInDrop: 497 val->v.counter64 = 498 pfs->pcounters[IPV6][IN][PF_DROP]; 499 break; 500 case LEAF_pfLogInterfaceIp6PktsOutPass: 501 val->v.counter64 = 502 pfs->pcounters[IPV6][OUT][PF_PASS]; 503 break; 504 case LEAF_pfLogInterfaceIp6PktsOutDrop: 505 val->v.counter64 = 506 pfs->pcounters[IPV6][OUT][PF_DROP]; 507 break; 508 509 default: 510 return (SNMP_ERR_NOSUCHNAME); 511 } 512 513 return (SNMP_ERR_NOERROR); 514 } 515 516 abort(); 517 } 518 519 int 520 pf_interfaces(struct snmp_context __unused *ctx, struct snmp_value *val, 521 u_int sub, u_int __unused vindex, enum snmp_op op) 522 { 523 asn_subid_t which = val->var.subs[sub - 1]; 524 525 if (op == SNMP_OP_SET) 526 return (SNMP_ERR_NOT_WRITEABLE); 527 528 if (op == SNMP_OP_GET) { 529 if ((time(NULL) - pfi_table_age) > PFI_TABLE_MAXAGE) 530 if (pfi_refresh() == -1) 531 return (SNMP_ERR_GENERR); 532 533 switch (which) { 534 case LEAF_pfInterfacesIfNumber: 535 val->v.uint32 = pfi_table_count; 536 break; 537 538 default: 539 return (SNMP_ERR_NOSUCHNAME); 540 } 541 542 return (SNMP_ERR_NOERROR); 543 } 544 545 abort(); 546 } 547 548 int 549 pf_iftable(struct snmp_context __unused *ctx, struct snmp_value *val, 550 u_int sub, u_int __unused vindex, enum snmp_op op) 551 { 552 asn_subid_t which = val->var.subs[sub - 1]; 553 struct pfi_entry *e = NULL; 554 555 if ((time(NULL) - pfi_table_age) > PFI_TABLE_MAXAGE) 556 pfi_refresh(); 557 558 switch (op) { 559 case SNMP_OP_SET: 560 return (SNMP_ERR_NOT_WRITEABLE); 561 case SNMP_OP_GETNEXT: 562 if ((e = NEXT_OBJECT_INT(&pfi_table, 563 &val->var, sub)) == NULL) 564 return (SNMP_ERR_NOSUCHNAME); 565 val->var.len = sub + 1; 566 val->var.subs[sub] = e->index; 567 break; 568 case SNMP_OP_GET: 569 if (val->var.len - sub != 1) 570 return (SNMP_ERR_NOSUCHNAME); 571 if ((e = pfi_table_find(val->var.subs[sub])) == NULL) 572 return (SNMP_ERR_NOSUCHNAME); 573 break; 574 575 case SNMP_OP_COMMIT: 576 case SNMP_OP_ROLLBACK: 577 default: 578 abort(); 579 } 580 581 switch (which) { 582 case LEAF_pfInterfacesIfDescr: 583 return (string_get(val, e->pfi.pfik_name, -1)); 584 case LEAF_pfInterfacesIfType: 585 val->v.integer = PFI_IFTYPE_INSTANCE; 586 break; 587 case LEAF_pfInterfacesIfTZero: 588 val->v.uint32 = 589 (time(NULL) - e->pfi.pfik_tzero) * 100; 590 break; 591 case LEAF_pfInterfacesIfRefsRule: 592 val->v.uint32 = e->pfi.pfik_rulerefs; 593 break; 594 case LEAF_pfInterfacesIf4BytesInPass: 595 val->v.counter64 = 596 e->pfi.pfik_bytes[IPV4][IN][PASS]; 597 break; 598 case LEAF_pfInterfacesIf4BytesInBlock: 599 val->v.counter64 = 600 e->pfi.pfik_bytes[IPV4][IN][BLOCK]; 601 break; 602 case LEAF_pfInterfacesIf4BytesOutPass: 603 val->v.counter64 = 604 e->pfi.pfik_bytes[IPV4][OUT][PASS]; 605 break; 606 case LEAF_pfInterfacesIf4BytesOutBlock: 607 val->v.counter64 = 608 e->pfi.pfik_bytes[IPV4][OUT][BLOCK]; 609 break; 610 case LEAF_pfInterfacesIf4PktsInPass: 611 val->v.counter64 = 612 e->pfi.pfik_packets[IPV4][IN][PASS]; 613 break; 614 case LEAF_pfInterfacesIf4PktsInBlock: 615 val->v.counter64 = 616 e->pfi.pfik_packets[IPV4][IN][BLOCK]; 617 break; 618 case LEAF_pfInterfacesIf4PktsOutPass: 619 val->v.counter64 = 620 e->pfi.pfik_packets[IPV4][OUT][PASS]; 621 break; 622 case LEAF_pfInterfacesIf4PktsOutBlock: 623 val->v.counter64 = 624 e->pfi.pfik_packets[IPV4][OUT][BLOCK]; 625 break; 626 case LEAF_pfInterfacesIf6BytesInPass: 627 val->v.counter64 = 628 e->pfi.pfik_bytes[IPV6][IN][PASS]; 629 break; 630 case LEAF_pfInterfacesIf6BytesInBlock: 631 val->v.counter64 = 632 e->pfi.pfik_bytes[IPV6][IN][BLOCK]; 633 break; 634 case LEAF_pfInterfacesIf6BytesOutPass: 635 val->v.counter64 = 636 e->pfi.pfik_bytes[IPV6][OUT][PASS]; 637 break; 638 case LEAF_pfInterfacesIf6BytesOutBlock: 639 val->v.counter64 = 640 e->pfi.pfik_bytes[IPV6][OUT][BLOCK]; 641 break; 642 case LEAF_pfInterfacesIf6PktsInPass: 643 val->v.counter64 = 644 e->pfi.pfik_packets[IPV6][IN][PASS]; 645 break; 646 case LEAF_pfInterfacesIf6PktsInBlock: 647 val->v.counter64 = 648 e->pfi.pfik_packets[IPV6][IN][BLOCK]; 649 break; 650 case LEAF_pfInterfacesIf6PktsOutPass: 651 val->v.counter64 = 652 e->pfi.pfik_packets[IPV6][OUT][PASS]; 653 break; 654 case LEAF_pfInterfacesIf6PktsOutBlock: 655 val->v.counter64 = 656 e->pfi.pfik_packets[IPV6][OUT][BLOCK]; 657 break; 658 659 default: 660 return (SNMP_ERR_NOSUCHNAME); 661 } 662 663 return (SNMP_ERR_NOERROR); 664 } 665 666 int 667 pf_tables(struct snmp_context __unused *ctx, struct snmp_value *val, 668 u_int sub, u_int __unused vindex, enum snmp_op op) 669 { 670 asn_subid_t which = val->var.subs[sub - 1]; 671 672 if (op == SNMP_OP_SET) 673 return (SNMP_ERR_NOT_WRITEABLE); 674 675 if (op == SNMP_OP_GET) { 676 if ((time(NULL) - pft_table_age) > PFT_TABLE_MAXAGE) 677 if (pft_refresh() == -1) 678 return (SNMP_ERR_GENERR); 679 680 switch (which) { 681 case LEAF_pfTablesTblNumber: 682 val->v.uint32 = pft_table_count; 683 break; 684 685 default: 686 return (SNMP_ERR_NOSUCHNAME); 687 } 688 689 return (SNMP_ERR_NOERROR); 690 } 691 692 abort(); 693 } 694 695 int 696 pf_tbltable(struct snmp_context __unused *ctx, struct snmp_value *val, 697 u_int sub, u_int __unused vindex, enum snmp_op op) 698 { 699 asn_subid_t which = val->var.subs[sub - 1]; 700 struct pft_entry *e = NULL; 701 702 if ((time(NULL) - pft_table_age) > PFT_TABLE_MAXAGE) 703 pft_refresh(); 704 705 switch (op) { 706 case SNMP_OP_SET: 707 return (SNMP_ERR_NOT_WRITEABLE); 708 case SNMP_OP_GETNEXT: 709 if ((e = NEXT_OBJECT_INT(&pft_table, 710 &val->var, sub)) == NULL) 711 return (SNMP_ERR_NOSUCHNAME); 712 val->var.len = sub + 1; 713 val->var.subs[sub] = e->index; 714 break; 715 case SNMP_OP_GET: 716 if (val->var.len - sub != 1) 717 return (SNMP_ERR_NOSUCHNAME); 718 if ((e = pft_table_find(val->var.subs[sub])) == NULL) 719 return (SNMP_ERR_NOSUCHNAME); 720 break; 721 722 case SNMP_OP_COMMIT: 723 case SNMP_OP_ROLLBACK: 724 default: 725 abort(); 726 } 727 728 switch (which) { 729 case LEAF_pfTablesTblDescr: 730 return (string_get(val, e->pft.pfrts_name, -1)); 731 case LEAF_pfTablesTblCount: 732 val->v.integer = e->pft.pfrts_cnt; 733 break; 734 case LEAF_pfTablesTblTZero: 735 val->v.uint32 = 736 (time(NULL) - e->pft.pfrts_tzero) * 100; 737 break; 738 case LEAF_pfTablesTblRefsAnchor: 739 val->v.integer = 740 e->pft.pfrts_refcnt[PFR_REFCNT_ANCHOR]; 741 break; 742 case LEAF_pfTablesTblRefsRule: 743 val->v.integer = 744 e->pft.pfrts_refcnt[PFR_REFCNT_RULE]; 745 break; 746 case LEAF_pfTablesTblEvalMatch: 747 val->v.counter64 = e->pft.pfrts_match; 748 break; 749 case LEAF_pfTablesTblEvalNoMatch: 750 val->v.counter64 = e->pft.pfrts_nomatch; 751 break; 752 case LEAF_pfTablesTblBytesInPass: 753 val->v.counter64 = 754 e->pft.pfrts_bytes[PFR_DIR_IN][PFR_OP_PASS]; 755 break; 756 case LEAF_pfTablesTblBytesInBlock: 757 val->v.counter64 = 758 e->pft.pfrts_bytes[PFR_DIR_IN][PFR_OP_BLOCK]; 759 break; 760 case LEAF_pfTablesTblBytesInXPass: 761 val->v.counter64 = 762 e->pft.pfrts_bytes[PFR_DIR_IN][PFR_OP_XPASS]; 763 break; 764 case LEAF_pfTablesTblBytesOutPass: 765 val->v.counter64 = 766 e->pft.pfrts_bytes[PFR_DIR_OUT][PFR_OP_PASS]; 767 break; 768 case LEAF_pfTablesTblBytesOutBlock: 769 val->v.counter64 = 770 e->pft.pfrts_bytes[PFR_DIR_OUT][PFR_OP_BLOCK]; 771 break; 772 case LEAF_pfTablesTblBytesOutXPass: 773 val->v.counter64 = 774 e->pft.pfrts_bytes[PFR_DIR_OUT][PFR_OP_XPASS]; 775 break; 776 case LEAF_pfTablesTblPktsInPass: 777 val->v.counter64 = 778 e->pft.pfrts_packets[PFR_DIR_IN][PFR_OP_PASS]; 779 break; 780 case LEAF_pfTablesTblPktsInBlock: 781 val->v.counter64 = 782 e->pft.pfrts_packets[PFR_DIR_IN][PFR_OP_BLOCK]; 783 break; 784 case LEAF_pfTablesTblPktsInXPass: 785 val->v.counter64 = 786 e->pft.pfrts_packets[PFR_DIR_IN][PFR_OP_XPASS]; 787 break; 788 case LEAF_pfTablesTblPktsOutPass: 789 val->v.counter64 = 790 e->pft.pfrts_packets[PFR_DIR_OUT][PFR_OP_PASS]; 791 break; 792 case LEAF_pfTablesTblPktsOutBlock: 793 val->v.counter64 = 794 e->pft.pfrts_packets[PFR_DIR_OUT][PFR_OP_BLOCK]; 795 break; 796 case LEAF_pfTablesTblPktsOutXPass: 797 val->v.counter64 = 798 e->pft.pfrts_packets[PFR_DIR_OUT][PFR_OP_XPASS]; 799 break; 800 801 default: 802 return (SNMP_ERR_NOSUCHNAME); 803 } 804 805 return (SNMP_ERR_NOERROR); 806 } 807 808 int 809 pf_tbladdr(struct snmp_context __unused *ctx, struct snmp_value __unused *val, 810 u_int __unused sub, u_int __unused vindex, enum snmp_op __unused op) 811 { 812 asn_subid_t which = val->var.subs[sub - 1]; 813 struct pfa_entry *e = NULL; 814 815 if ((time(NULL) - pfa_table_age) > PFA_TABLE_MAXAGE) 816 pfa_refresh(); 817 818 switch (op) { 819 case SNMP_OP_SET: 820 return (SNMP_ERR_NOT_WRITEABLE); 821 case SNMP_OP_GETNEXT: 822 if ((e = NEXT_OBJECT_INT(&pfa_table, 823 &val->var, sub)) == NULL) 824 return (SNMP_ERR_NOSUCHNAME); 825 val->var.len = sub + 1; 826 val->var.subs[sub] = e->index; 827 break; 828 case SNMP_OP_GET: 829 if (val->var.len - sub != 1) 830 return (SNMP_ERR_NOSUCHNAME); 831 if ((e = pfa_table_find(val->var.subs[sub])) == NULL) 832 return (SNMP_ERR_NOSUCHNAME); 833 break; 834 835 case SNMP_OP_COMMIT: 836 case SNMP_OP_ROLLBACK: 837 default: 838 abort(); 839 } 840 841 switch (which) { 842 case LEAF_pfTablesAddrNetType: 843 if (e->pfas.pfras_a.pfra_af == AF_INET) 844 val->v.integer = pfTablesAddrNetType_ipv4; 845 else if (e->pfas.pfras_a.pfra_af == AF_INET6) 846 val->v.integer = pfTablesAddrNetType_ipv6; 847 else 848 return (SNMP_ERR_GENERR); 849 break; 850 case LEAF_pfTablesAddrNet: 851 if (e->pfas.pfras_a.pfra_af == AF_INET) { 852 return (string_get(val, 853 (u_char *)&e->pfas.pfras_a.pfra_ip4addr, 4)); 854 } else if (e->pfas.pfras_a.pfra_af == AF_INET6) 855 return (string_get(val, 856 (u_char *)&e->pfas.pfras_a.pfra_ip6addr, 16)); 857 else 858 return (SNMP_ERR_GENERR); 859 break; 860 case LEAF_pfTablesAddrPrefix: 861 val->v.integer = (int32_t) e->pfas.pfras_a.pfra_net; 862 break; 863 case LEAF_pfTablesAddrTZero: 864 val->v.uint32 = 865 (time(NULL) - e->pfas.pfras_tzero) * 100; 866 break; 867 case LEAF_pfTablesAddrBytesInPass: 868 val->v.counter64 = 869 e->pfas.pfras_bytes[PFR_DIR_IN][PFR_OP_PASS]; 870 break; 871 case LEAF_pfTablesAddrBytesInBlock: 872 val->v.counter64 = 873 e->pfas.pfras_bytes[PFR_DIR_IN][PFR_OP_BLOCK]; 874 break; 875 case LEAF_pfTablesAddrBytesOutPass: 876 val->v.counter64 = 877 e->pfas.pfras_bytes[PFR_DIR_OUT][PFR_OP_PASS]; 878 break; 879 case LEAF_pfTablesAddrBytesOutBlock: 880 val->v.counter64 = 881 e->pfas.pfras_bytes[PFR_DIR_OUT][PFR_OP_BLOCK]; 882 break; 883 case LEAF_pfTablesAddrPktsInPass: 884 val->v.counter64 = 885 e->pfas.pfras_packets[PFR_DIR_IN][PFR_OP_PASS]; 886 break; 887 case LEAF_pfTablesAddrPktsInBlock: 888 val->v.counter64 = 889 e->pfas.pfras_packets[PFR_DIR_IN][PFR_OP_BLOCK]; 890 break; 891 case LEAF_pfTablesAddrPktsOutPass: 892 val->v.counter64 = 893 e->pfas.pfras_packets[PFR_DIR_OUT][PFR_OP_PASS]; 894 break; 895 case LEAF_pfTablesAddrPktsOutBlock: 896 val->v.counter64 = 897 e->pfas.pfras_packets[PFR_DIR_OUT][PFR_OP_BLOCK]; 898 break; 899 default: 900 return (SNMP_ERR_NOSUCHNAME); 901 } 902 903 return (SNMP_ERR_NOERROR); 904 } 905 906 int 907 pf_altq_num(struct snmp_context __unused *ctx, struct snmp_value *val, 908 u_int sub, u_int __unused vindex, enum snmp_op op) 909 { 910 asn_subid_t which = val->var.subs[sub - 1]; 911 912 if (!altq_enabled) 913 return (SNMP_ERR_NOSUCHNAME); 914 915 if (op == SNMP_OP_SET) 916 return (SNMP_ERR_NOT_WRITEABLE); 917 918 if (op == SNMP_OP_GET) { 919 if ((time(NULL) - pfq_table_age) > PFQ_TABLE_MAXAGE) 920 if (pfq_refresh() == -1) 921 return (SNMP_ERR_GENERR); 922 923 switch (which) { 924 case LEAF_pfAltqQueueNumber: 925 val->v.uint32 = pfq_table_count; 926 break; 927 928 default: 929 return (SNMP_ERR_NOSUCHNAME); 930 } 931 932 return (SNMP_ERR_NOERROR); 933 } 934 935 abort(); 936 return (SNMP_ERR_GENERR); 937 } 938 939 int 940 pf_altqq(struct snmp_context __unused *ctx, struct snmp_value *val, 941 u_int sub, u_int __unused vindex, enum snmp_op op) 942 { 943 asn_subid_t which = val->var.subs[sub - 1]; 944 struct pfq_entry *e = NULL; 945 946 if (!altq_enabled) 947 return (SNMP_ERR_NOSUCHNAME); 948 949 if ((time(NULL) - pfq_table_age) > PFQ_TABLE_MAXAGE) 950 pfq_refresh(); 951 952 switch (op) { 953 case SNMP_OP_SET: 954 return (SNMP_ERR_NOT_WRITEABLE); 955 case SNMP_OP_GETNEXT: 956 if ((e = NEXT_OBJECT_INT(&pfq_table, 957 &val->var, sub)) == NULL) 958 return (SNMP_ERR_NOSUCHNAME); 959 val->var.len = sub + 1; 960 val->var.subs[sub] = e->index; 961 break; 962 case SNMP_OP_GET: 963 if (val->var.len - sub != 1) 964 return (SNMP_ERR_NOSUCHNAME); 965 if ((e = pfq_table_find(val->var.subs[sub])) == NULL) 966 return (SNMP_ERR_NOSUCHNAME); 967 break; 968 969 case SNMP_OP_COMMIT: 970 case SNMP_OP_ROLLBACK: 971 default: 972 abort(); 973 } 974 975 switch (which) { 976 case LEAF_pfAltqQueueDescr: 977 return (string_get(val, e->altq.qname, -1)); 978 case LEAF_pfAltqQueueParent: 979 return (string_get(val, e->altq.parent, -1)); 980 case LEAF_pfAltqQueueScheduler: 981 val->v.integer = e->altq.scheduler; 982 break; 983 case LEAF_pfAltqQueueBandwidth: 984 val->v.uint32 = (e->altq.bandwidth > UINT_MAX) ? 985 UINT_MAX : (u_int32_t)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(pfctl_fd(pfh), 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 pa.version = PFIOC_ALTQ_VERSION; 1232 if (ioctl(pfctl_fd(pfh), 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(pfctl_fd(pfh), 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 pfctl_free_status(pfs); 1288 pfs = pfctl_get_status_h(pfh); 1289 1290 if (pfs == NULL) { 1291 syslog(LOG_ERR, "pfs_refresh(): ioctl(): %s", 1292 strerror(errno)); 1293 return (-1); 1294 } 1295 1296 pf_tick = this_tick; 1297 return (0); 1298 } 1299 1300 static int 1301 pft_refresh(void) 1302 { 1303 struct pfioc_table io; 1304 struct pfr_tstats *t = NULL; 1305 struct pft_entry *e; 1306 int i, numtbls = 1; 1307 1308 if (started && this_tick <= pf_tick) 1309 return (0); 1310 1311 while (!TAILQ_EMPTY(&pft_table)) { 1312 e = TAILQ_FIRST(&pft_table); 1313 TAILQ_REMOVE(&pft_table, e, link); 1314 free(e); 1315 } 1316 1317 bzero(&io, sizeof(io)); 1318 io.pfrio_esize = sizeof(struct pfr_tstats); 1319 1320 for (;;) { 1321 t = reallocf(t, numtbls * sizeof(struct pfr_tstats)); 1322 if (t == NULL) { 1323 syslog(LOG_ERR, "pft_refresh(): reallocf() numtbls=%d: %s", 1324 numtbls, strerror(errno)); 1325 goto err2; 1326 } 1327 io.pfrio_size = numtbls; 1328 io.pfrio_buffer = t; 1329 1330 if (ioctl(pfctl_fd(pfh), DIOCRGETTSTATS, &io)) { 1331 syslog(LOG_ERR, "pft_refresh(): ioctl(): %s", 1332 strerror(errno)); 1333 goto err2; 1334 } 1335 1336 if (numtbls >= io.pfrio_size) 1337 break; 1338 1339 numtbls = io.pfrio_size; 1340 } 1341 1342 for (i = 0; i < numtbls; i++) { 1343 e = malloc(sizeof(struct pft_entry)); 1344 if (e == NULL) 1345 goto err1; 1346 e->index = i + 1; 1347 memcpy(&e->pft, t+i, sizeof(struct pfr_tstats)); 1348 TAILQ_INSERT_TAIL(&pft_table, e, link); 1349 } 1350 1351 pft_table_age = time(NULL); 1352 pft_table_count = numtbls; 1353 pf_tick = this_tick; 1354 1355 free(t); 1356 return (0); 1357 err1: 1358 while (!TAILQ_EMPTY(&pft_table)) { 1359 e = TAILQ_FIRST(&pft_table); 1360 TAILQ_REMOVE(&pft_table, e, link); 1361 free(e); 1362 } 1363 err2: 1364 free(t); 1365 return(-1); 1366 } 1367 1368 static int 1369 pfa_table_addrs(u_int sidx, struct pfr_table *pt) 1370 { 1371 struct pfioc_table io; 1372 struct pfr_astats *t = NULL; 1373 struct pfa_entry *e; 1374 int i, numaddrs = 1; 1375 1376 if (pt == NULL) 1377 return (-1); 1378 1379 memset(&io, 0, sizeof(io)); 1380 strlcpy(io.pfrio_table.pfrt_name, pt->pfrt_name, 1381 sizeof(io.pfrio_table.pfrt_name)); 1382 1383 for (;;) { 1384 t = reallocf(t, numaddrs * sizeof(struct pfr_astats)); 1385 if (t == NULL) { 1386 syslog(LOG_ERR, "pfa_table_addrs(): reallocf(): %s", 1387 strerror(errno)); 1388 numaddrs = -1; 1389 goto error; 1390 } 1391 1392 memset(t, 0, sizeof(*t)); 1393 io.pfrio_size = numaddrs; 1394 io.pfrio_buffer = t; 1395 io.pfrio_esize = sizeof(struct pfr_astats); 1396 1397 if (ioctl(pfctl_fd(pfh), DIOCRGETASTATS, &io)) { 1398 syslog(LOG_ERR, "pfa_table_addrs(): ioctl() on %s: %s", 1399 pt->pfrt_name, strerror(errno)); 1400 numaddrs = -1; 1401 break; 1402 } 1403 1404 if (numaddrs >= io.pfrio_size) 1405 break; 1406 1407 numaddrs = io.pfrio_size; 1408 } 1409 1410 for (i = 0; i < numaddrs; i++) { 1411 if ((t + i)->pfras_a.pfra_af != AF_INET && 1412 (t + i)->pfras_a.pfra_af != AF_INET6) { 1413 numaddrs = i; 1414 break; 1415 } 1416 1417 e = (struct pfa_entry *)malloc(sizeof(struct pfa_entry)); 1418 if (e == NULL) { 1419 syslog(LOG_ERR, "pfa_table_addrs(): malloc(): %s", 1420 strerror(errno)); 1421 numaddrs = -1; 1422 break; 1423 } 1424 e->index = sidx + i; 1425 memcpy(&e->pfas, t + i, sizeof(struct pfr_astats)); 1426 TAILQ_INSERT_TAIL(&pfa_table, e, link); 1427 } 1428 1429 free(t); 1430 error: 1431 return (numaddrs); 1432 } 1433 1434 static int 1435 pfa_refresh(void) 1436 { 1437 struct pfioc_table io; 1438 struct pfr_table *pt = NULL, *it = NULL; 1439 struct pfa_entry *e; 1440 int i, numtbls = 1, cidx, naddrs; 1441 1442 if (started && this_tick <= pf_tick) 1443 return (0); 1444 1445 while (!TAILQ_EMPTY(&pfa_table)) { 1446 e = TAILQ_FIRST(&pfa_table); 1447 TAILQ_REMOVE(&pfa_table, e, link); 1448 free(e); 1449 } 1450 1451 memset(&io, 0, sizeof(io)); 1452 io.pfrio_esize = sizeof(struct pfr_table); 1453 1454 for (;;) { 1455 pt = reallocf(pt, numtbls * sizeof(struct pfr_table)); 1456 if (pt == NULL) { 1457 syslog(LOG_ERR, "pfa_refresh(): reallocf() %s", 1458 strerror(errno)); 1459 return (-1); 1460 } 1461 memset(pt, 0, sizeof(*pt)); 1462 io.pfrio_size = numtbls; 1463 io.pfrio_buffer = pt; 1464 1465 if (ioctl(pfctl_fd(pfh), DIOCRGETTABLES, &io)) { 1466 syslog(LOG_ERR, "pfa_refresh(): ioctl(): %s", 1467 strerror(errno)); 1468 goto err2; 1469 } 1470 1471 if (numtbls >= io.pfrio_size) 1472 break; 1473 1474 numtbls = io.pfrio_size; 1475 } 1476 1477 cidx = 1; 1478 1479 for (it = pt, i = 0; i < numtbls; it++, i++) { 1480 /* 1481 * Skip the table if not active - ioctl(DIOCRGETASTATS) will 1482 * return ESRCH for this entry anyway. 1483 */ 1484 if (!(it->pfrt_flags & PFR_TFLAG_ACTIVE)) 1485 continue; 1486 1487 if ((naddrs = pfa_table_addrs(cidx, it)) < 0) 1488 goto err1; 1489 1490 cidx += naddrs; 1491 } 1492 1493 pfa_table_age = time(NULL); 1494 pfa_table_count = cidx; 1495 pf_tick = this_tick; 1496 1497 free(pt); 1498 return (0); 1499 err1: 1500 while (!TAILQ_EMPTY(&pfa_table)) { 1501 e = TAILQ_FIRST(&pfa_table); 1502 TAILQ_REMOVE(&pfa_table, e, link); 1503 free(e); 1504 } 1505 1506 err2: 1507 free(pt); 1508 return (-1); 1509 } 1510 1511 static int 1512 pfl_scan_ruleset(const char *path) 1513 { 1514 struct pfctl_rules_info rules; 1515 struct pfctl_rule rule; 1516 char anchor_call[MAXPATHLEN] = ""; 1517 struct pfl_entry *e; 1518 u_int32_t nr, i; 1519 1520 if (pfctl_get_rules_info_h(pfh, &rules, PF_PASS, path)) { 1521 syslog(LOG_ERR, "pfl_scan_ruleset: ioctl(DIOCGETRULES): %s", 1522 strerror(errno)); 1523 goto err; 1524 } 1525 1526 for (nr = rules.nr, i = 0; i < nr; i++) { 1527 if (pfctl_get_rule_h(pfh, i, rules.ticket, path, 1528 PF_PASS, &rule, anchor_call)) { 1529 syslog(LOG_ERR, "pfl_scan_ruleset: ioctl(DIOCGETRULE):" 1530 " %s", strerror(errno)); 1531 goto err; 1532 } 1533 1534 if (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, rule.label[0], sizeof(e->name)); 1543 1544 e->evals = rule.evaluations; 1545 e->bytes[IN] = rule.bytes[IN]; 1546 e->bytes[OUT] = rule.bytes[OUT]; 1547 e->pkts[IN] = rule.packets[IN]; 1548 e->pkts[OUT] = 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(pfctl_fd(pfh), 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(pfctl_fd(pfh), 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 pa.version = PFIOC_ALTQ_VERSION; 1650 if (ioctl(pfdev, DIOCGETALTQS, &pa)) { 1651 if (errno == ENODEV) { 1652 syslog(LOG_INFO, "No ALTQ support in kernel\n" 1653 "ALTQ related functions disabled\n"); 1654 return (0); 1655 } else { 1656 syslog(LOG_ERR, "DIOCGETALTQS returned an error: %s", 1657 strerror(errno)); 1658 return (-1); 1659 } 1660 } 1661 return (1); 1662 } 1663 1664 /* 1665 * Implement the bsnmpd module interface 1666 */ 1667 static int 1668 pf_init(struct lmodule *mod, int __unused argc, char __unused *argv[]) 1669 { 1670 module = mod; 1671 1672 if ((pfh = pfctl_open(PF_DEVICE)) == NULL) { 1673 syslog(LOG_ERR, "pf_init(): open(): %s\n", 1674 strerror(errno)); 1675 return (-1); 1676 } 1677 1678 if ((altq_enabled = altq_is_enabled(pfctl_fd(pfh))) == -1) { 1679 syslog(LOG_ERR, "pf_init(): altq test failed"); 1680 return (-1); 1681 } 1682 1683 /* Prepare internal state */ 1684 TAILQ_INIT(&pfi_table); 1685 TAILQ_INIT(&pfq_table); 1686 TAILQ_INIT(&pft_table); 1687 TAILQ_INIT(&pfa_table); 1688 TAILQ_INIT(&pfl_table); 1689 1690 pfi_refresh(); 1691 if (altq_enabled) { 1692 pfq_refresh(); 1693 } 1694 1695 pfs_refresh(); 1696 pft_refresh(); 1697 pfa_refresh(); 1698 pfl_refresh(); 1699 1700 started = 1; 1701 1702 return (0); 1703 } 1704 1705 static int 1706 pf_fini(void) 1707 { 1708 struct pfi_entry *i1, *i2; 1709 struct pfq_entry *q1, *q2; 1710 struct pft_entry *t1, *t2; 1711 struct pfa_entry *a1, *a2; 1712 struct pfl_entry *l1, *l2; 1713 1714 /* Empty the list of interfaces */ 1715 i1 = TAILQ_FIRST(&pfi_table); 1716 while (i1 != NULL) { 1717 i2 = TAILQ_NEXT(i1, link); 1718 free(i1); 1719 i1 = i2; 1720 } 1721 1722 /* List of queues */ 1723 q1 = TAILQ_FIRST(&pfq_table); 1724 while (q1 != NULL) { 1725 q2 = TAILQ_NEXT(q1, link); 1726 free(q1); 1727 q1 = q2; 1728 } 1729 1730 /* List of tables */ 1731 t1 = TAILQ_FIRST(&pft_table); 1732 while (t1 != NULL) { 1733 t2 = TAILQ_NEXT(t1, link); 1734 free(t1); 1735 t1 = t2; 1736 } 1737 1738 /* List of table addresses */ 1739 a1 = TAILQ_FIRST(&pfa_table); 1740 while (a1 != NULL) { 1741 a2 = TAILQ_NEXT(a1, link); 1742 free(a1); 1743 a1 = a2; 1744 } 1745 1746 /* And the list of labeled filter rules */ 1747 l1 = TAILQ_FIRST(&pfl_table); 1748 while (l1 != NULL) { 1749 l2 = TAILQ_NEXT(l1, link); 1750 free(l1); 1751 l1 = l2; 1752 } 1753 1754 pfctl_free_status(pfs); 1755 pfs = NULL; 1756 1757 pfctl_close(pfh); 1758 1759 return (0); 1760 } 1761 1762 static void 1763 pf_dump(void) 1764 { 1765 pfi_refresh(); 1766 if (altq_enabled) { 1767 pfq_refresh(); 1768 } 1769 pft_refresh(); 1770 pfa_refresh(); 1771 pfl_refresh(); 1772 1773 syslog(LOG_ERR, "Dump: pfi_table_age = %jd", 1774 (intmax_t)pfi_table_age); 1775 syslog(LOG_ERR, "Dump: pfi_table_count = %d", 1776 pfi_table_count); 1777 1778 syslog(LOG_ERR, "Dump: pfq_table_age = %jd", 1779 (intmax_t)pfq_table_age); 1780 syslog(LOG_ERR, "Dump: pfq_table_count = %d", 1781 pfq_table_count); 1782 1783 syslog(LOG_ERR, "Dump: pft_table_age = %jd", 1784 (intmax_t)pft_table_age); 1785 syslog(LOG_ERR, "Dump: pft_table_count = %d", 1786 pft_table_count); 1787 1788 syslog(LOG_ERR, "Dump: pfa_table_age = %jd", 1789 (intmax_t)pfa_table_age); 1790 syslog(LOG_ERR, "Dump: pfa_table_count = %d", 1791 pfa_table_count); 1792 1793 syslog(LOG_ERR, "Dump: pfl_table_age = %jd", 1794 (intmax_t)pfl_table_age); 1795 syslog(LOG_ERR, "Dump: pfl_table_count = %d", 1796 pfl_table_count); 1797 } 1798 1799 const struct snmp_module config = { 1800 .comment = "This module implements a MIB for the pf packet filter.", 1801 .init = pf_init, 1802 .fini = pf_fini, 1803 .tree = pf_ctree, 1804 .dump = pf_dump, 1805 .tree_size = pf_CTREE_SIZE, 1806 }; 1807