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