1 /* $OpenBSD: pfctl.c,v 1.278 2008/08/31 20:18:17 jmc Exp $ */ 2 3 /*- 4 * SPDX-License-Identifier: BSD-2-Clause 5 * 6 * Copyright (c) 2001 Daniel Hartmeier 7 * Copyright (c) 2002,2003 Henning Brauer 8 * All rights reserved. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 14 * - Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * - Redistributions in binary form must reproduce the above 17 * copyright notice, this list of conditions and the following 18 * disclaimer in the documentation and/or other materials provided 19 * with the distribution. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 29 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 31 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 32 * POSSIBILITY OF SUCH DAMAGE. 33 * 34 */ 35 36 #include <sys/cdefs.h> 37 #define PFIOC_USE_LATEST 38 39 #include <sys/types.h> 40 #include <sys/ioctl.h> 41 #include <sys/socket.h> 42 #include <sys/stat.h> 43 #include <sys/endian.h> 44 45 #include <net/if.h> 46 #include <netinet/in.h> 47 #include <net/pfvar.h> 48 #include <arpa/inet.h> 49 #include <net/altq/altq.h> 50 51 #include <err.h> 52 #include <errno.h> 53 #include <fcntl.h> 54 #include <libpfctl.h> 55 #include <limits.h> 56 #include <netdb.h> 57 #include <stdint.h> 58 #include <stdio.h> 59 #include <stdlib.h> 60 #include <string.h> 61 #include <unistd.h> 62 #include <stdarg.h> 63 #include <libgen.h> 64 65 #include "pfctl_parser.h" 66 #include "pfctl.h" 67 68 void usage(void); 69 int pfctl_enable(int, int); 70 int pfctl_disable(int, int); 71 void pfctl_clear_stats(struct pfctl_handle *, int); 72 void pfctl_get_skip_ifaces(void); 73 void pfctl_check_skip_ifaces(char *); 74 void pfctl_adjust_skip_ifaces(struct pfctl *); 75 void pfctl_clear_interface_flags(int, int); 76 void pfctl_flush_eth_rules(int, int, char *); 77 int pfctl_flush_rules(int, int, char *); 78 void pfctl_flush_nat(int, int, char *); 79 int pfctl_clear_altq(int, int); 80 void pfctl_clear_src_nodes(int, int); 81 void pfctl_clear_iface_states(int, const char *, int); 82 struct addrinfo * 83 pfctl_addrprefix(char *, struct pf_addr *, int); 84 void pfctl_kill_src_nodes(int, int); 85 void pfctl_net_kill_states(int, const char *, int); 86 void pfctl_gateway_kill_states(int, const char *, int); 87 void pfctl_label_kill_states(int, const char *, int); 88 void pfctl_id_kill_states(int, const char *, int); 89 void pfctl_key_kill_states(int, const char *, int); 90 int pfctl_parse_host(char *, struct pf_rule_addr *); 91 void pfctl_init_options(struct pfctl *); 92 int pfctl_load_options(struct pfctl *); 93 int pfctl_load_limit(struct pfctl *, unsigned int, unsigned int); 94 int pfctl_load_timeout(struct pfctl *, unsigned int, unsigned int); 95 int pfctl_load_debug(struct pfctl *, unsigned int); 96 int pfctl_load_logif(struct pfctl *, char *); 97 int pfctl_load_hostid(struct pfctl *, u_int32_t); 98 int pfctl_load_reassembly(struct pfctl *, u_int32_t); 99 int pfctl_load_syncookies(struct pfctl *, u_int8_t); 100 int pfctl_get_pool(int, struct pfctl_pool *, u_int32_t, u_int32_t, int, 101 const char *, int); 102 void pfctl_print_eth_rule_counters(struct pfctl_eth_rule *, int); 103 void pfctl_print_rule_counters(struct pfctl_rule *, int); 104 int pfctl_show_eth_rules(int, char *, int, enum pfctl_show, char *, int, int); 105 int pfctl_show_rules(int, char *, int, enum pfctl_show, char *, int, int); 106 int pfctl_show_nat(int, const char *, int, char *, int, int); 107 int pfctl_show_src_nodes(int, int); 108 int pfctl_show_states(int, const char *, int); 109 int pfctl_show_status(int, int); 110 int pfctl_show_running(int); 111 int pfctl_show_timeouts(int, int); 112 int pfctl_show_limits(int, int); 113 void pfctl_debug(int, u_int32_t, int); 114 int pfctl_test_altqsupport(int, int); 115 int pfctl_show_anchors(int, int, char *); 116 int pfctl_show_eth_anchors(int, int, char *); 117 int pfctl_ruleset_trans(struct pfctl *, char *, struct pfctl_anchor *, bool); 118 int pfctl_eth_ruleset_trans(struct pfctl *, char *, 119 struct pfctl_eth_anchor *); 120 int pfctl_load_eth_ruleset(struct pfctl *, char *, 121 struct pfctl_eth_ruleset *, int); 122 int pfctl_load_eth_rule(struct pfctl *, char *, struct pfctl_eth_rule *, 123 int); 124 int pfctl_load_ruleset(struct pfctl *, char *, 125 struct pfctl_ruleset *, int, int); 126 int pfctl_load_rule(struct pfctl *, char *, struct pfctl_rule *, int); 127 const char *pfctl_lookup_option(char *, const char * const *); 128 void pfctl_reset(int, int); 129 int pfctl_walk_show(int, struct pfioc_ruleset *, void *); 130 int pfctl_walk_get(int, struct pfioc_ruleset *, void *); 131 int pfctl_walk_anchors(int, int, const char *, 132 int(*)(int, struct pfioc_ruleset *, void *), void *); 133 struct pfr_anchors * 134 pfctl_get_anchors(int, const char *, int); 135 int pfctl_recurse(int, int, const char *, 136 int(*)(int, int, struct pfr_anchoritem *)); 137 int pfctl_call_clearrules(int, int, struct pfr_anchoritem *); 138 int pfctl_call_cleartables(int, int, struct pfr_anchoritem *); 139 int pfctl_call_clearanchors(int, int, struct pfr_anchoritem *); 140 int pfctl_call_showtables(int, int, struct pfr_anchoritem *); 141 142 static struct pfctl_anchor_global pf_anchors; 143 struct pfctl_anchor pf_main_anchor; 144 struct pfctl_eth_anchor pf_eth_main_anchor; 145 static struct pfr_buffer skip_b; 146 147 static const char *clearopt; 148 static char *rulesopt; 149 static const char *showopt; 150 static const char *debugopt; 151 static char *anchoropt; 152 static const char *optiopt = NULL; 153 static const char *pf_device = PF_DEVICE; 154 static char *ifaceopt; 155 static char *tableopt; 156 static const char *tblcmdopt; 157 static int src_node_killers; 158 static char *src_node_kill[2]; 159 static int state_killers; 160 static char *state_kill[2]; 161 int loadopt; 162 int altqsupport; 163 164 int dev = -1; 165 struct pfctl_handle *pfh = NULL; 166 static int first_title = 1; 167 static int labels = 0; 168 static int exit_val = 0; 169 170 #define INDENT(d, o) do { \ 171 if (o) { \ 172 int i; \ 173 for (i=0; i < d; i++) \ 174 printf(" "); \ 175 } \ 176 } while (0); \ 177 178 179 static const struct { 180 const char *name; 181 int index; 182 } pf_limits[] = { 183 { "states", PF_LIMIT_STATES }, 184 { "src-nodes", PF_LIMIT_SRC_NODES }, 185 { "frags", PF_LIMIT_FRAGS }, 186 { "table-entries", PF_LIMIT_TABLE_ENTRIES }, 187 { "anchors", PF_LIMIT_ANCHORS }, 188 { "eth-anchors", PF_LIMIT_ETH_ANCHORS }, 189 { NULL, 0 } 190 }; 191 192 struct pf_hint { 193 const char *name; 194 int timeout; 195 }; 196 static const struct pf_hint pf_hint_normal[] = { 197 { "tcp.first", 2 * 60 }, 198 { "tcp.opening", 30 }, 199 { "tcp.established", 24 * 60 * 60 }, 200 { "tcp.closing", 15 * 60 }, 201 { "tcp.finwait", 45 }, 202 { "tcp.closed", 90 }, 203 { "tcp.tsdiff", 30 }, 204 { NULL, 0 } 205 }; 206 static const struct pf_hint pf_hint_satellite[] = { 207 { "tcp.first", 3 * 60 }, 208 { "tcp.opening", 30 + 5 }, 209 { "tcp.established", 24 * 60 * 60 }, 210 { "tcp.closing", 15 * 60 + 5 }, 211 { "tcp.finwait", 45 + 5 }, 212 { "tcp.closed", 90 + 5 }, 213 { "tcp.tsdiff", 60 }, 214 { NULL, 0 } 215 }; 216 static const struct pf_hint pf_hint_conservative[] = { 217 { "tcp.first", 60 * 60 }, 218 { "tcp.opening", 15 * 60 }, 219 { "tcp.established", 5 * 24 * 60 * 60 }, 220 { "tcp.closing", 60 * 60 }, 221 { "tcp.finwait", 10 * 60 }, 222 { "tcp.closed", 3 * 60 }, 223 { "tcp.tsdiff", 60 }, 224 { NULL, 0 } 225 }; 226 static const struct pf_hint pf_hint_aggressive[] = { 227 { "tcp.first", 30 }, 228 { "tcp.opening", 5 }, 229 { "tcp.established", 5 * 60 * 60 }, 230 { "tcp.closing", 60 }, 231 { "tcp.finwait", 30 }, 232 { "tcp.closed", 30 }, 233 { "tcp.tsdiff", 10 }, 234 { NULL, 0 } 235 }; 236 237 static const struct { 238 const char *name; 239 const struct pf_hint *hint; 240 } pf_hints[] = { 241 { "normal", pf_hint_normal }, 242 { "satellite", pf_hint_satellite }, 243 { "high-latency", pf_hint_satellite }, 244 { "conservative", pf_hint_conservative }, 245 { "aggressive", pf_hint_aggressive }, 246 { NULL, NULL } 247 }; 248 249 static const char * const clearopt_list[] = { 250 "nat", "queue", "rules", "Sources", 251 "states", "info", "Tables", "osfp", "all", 252 "ethernet", "Reset", NULL 253 }; 254 255 static const char * const showopt_list[] = { 256 "ether", "nat", "queue", "rules", "Anchors", "Sources", "states", 257 "info", "Interfaces", "labels", "timeouts", "memory", "Tables", 258 "osfp", "Running", "all", "creatorids", NULL 259 }; 260 261 static const char * const tblcmdopt_list[] = { 262 "kill", "flush", "add", "delete", "load", "replace", "show", 263 "test", "zero", "expire", "reset", NULL 264 }; 265 266 static const char * const debugopt_list[] = { 267 "none", "urgent", "misc", "loud", NULL 268 }; 269 270 static const char * const optiopt_list[] = { 271 "none", "basic", "profile", NULL 272 }; 273 274 void 275 usage(void) 276 { 277 extern char *__progname; 278 279 fprintf(stderr, 280 "usage: %s [-AdeghMmNnOPqRSrvz] [-a anchor] [-D macro=value] [-F modifier]\n" 281 "\t[-f file] [-i interface] [-K host | network]\n" 282 "\t[-k host | network | gateway | label | id] [-o level] [-p device]\n" 283 "\t[-s modifier] [-t table -T command [address ...]] [-x level]\n", 284 __progname); 285 286 exit(1); 287 } 288 289 void 290 pfctl_err(int opts, int eval, const char *fmt, ...) 291 { 292 va_list ap; 293 294 va_start(ap, fmt); 295 296 if ((opts & PF_OPT_IGNFAIL) == 0) 297 verr(eval, fmt, ap); 298 else 299 vwarn(fmt, ap); 300 301 va_end(ap); 302 303 exit_val = eval; 304 } 305 306 void 307 pfctl_errx(int opts, int eval, const char *fmt, ...) 308 { 309 va_list ap; 310 311 va_start(ap, fmt); 312 313 if ((opts & PF_OPT_IGNFAIL) == 0) 314 verrx(eval, fmt, ap); 315 else 316 vwarnx(fmt, ap); 317 318 va_end(ap); 319 320 exit_val = eval; 321 } 322 323 /* 324 * Cache protocol number to name translations. 325 * 326 * Translation is performed a lot e.g., when dumping states and 327 * getprotobynumber is incredibly expensive. 328 * 329 * Note from the getprotobynumber(3) manpage: 330 * <quote> 331 * These functions use a thread-specific data space; if the data is needed 332 * for future use, it should be copied before any subsequent calls overwrite 333 * it. Only the Internet protocols are currently understood. 334 * </quote> 335 * 336 * Consequently we only cache the name and strdup it for safety. 337 * 338 * At the time of writing this comment the last entry in /etc/protocols is: 339 * divert 258 DIVERT # Divert pseudo-protocol [non IANA] 340 */ 341 const char * 342 pfctl_proto2name(int proto) 343 { 344 static const char *pfctl_proto_cache[259]; 345 struct protoent *p; 346 347 if (proto >= nitems(pfctl_proto_cache)) { 348 p = getprotobynumber(proto); 349 if (p == NULL) { 350 return (NULL); 351 } 352 return (p->p_name); 353 } 354 355 if (pfctl_proto_cache[proto] == NULL) { 356 p = getprotobynumber(proto); 357 if (p == NULL) { 358 return (NULL); 359 } 360 pfctl_proto_cache[proto] = strdup(p->p_name); 361 } 362 363 return (pfctl_proto_cache[proto]); 364 } 365 366 int 367 pfctl_enable(int dev, int opts) 368 { 369 int ret; 370 371 if ((ret = pfctl_startstop(pfh, 1)) != 0) { 372 if (ret == EEXIST) 373 errx(1, "pf already enabled"); 374 else if (ret == ESRCH) 375 errx(1, "pfil registeration failed"); 376 else 377 errc(1, ret, "DIOCSTART"); 378 } 379 if ((opts & PF_OPT_QUIET) == 0) 380 fprintf(stderr, "pf enabled\n"); 381 382 if (altqsupport && ioctl(dev, DIOCSTARTALTQ)) 383 if (errno != EEXIST) 384 err(1, "DIOCSTARTALTQ"); 385 386 return (0); 387 } 388 389 int 390 pfctl_disable(int dev, int opts) 391 { 392 int ret; 393 394 if ((ret = pfctl_startstop(pfh, 0)) != 0) { 395 if (ret == ENOENT) 396 errx(1, "pf not enabled"); 397 else 398 errc(1, ret, "DIOCSTOP"); 399 } 400 if ((opts & PF_OPT_QUIET) == 0) 401 fprintf(stderr, "pf disabled\n"); 402 403 if (altqsupport && ioctl(dev, DIOCSTOPALTQ)) 404 if (errno != ENOENT) 405 err(1, "DIOCSTOPALTQ"); 406 407 return (0); 408 } 409 410 void 411 pfctl_clear_stats(struct pfctl_handle *h, int opts) 412 { 413 int ret; 414 if ((ret = pfctl_clear_status(h)) != 0) 415 pfctl_err(opts, 1, "DIOCCLRSTATUS"); 416 if ((opts & PF_OPT_QUIET) == 0) 417 fprintf(stderr, "pf: statistics cleared\n"); 418 } 419 420 void 421 pfctl_get_skip_ifaces(void) 422 { 423 bzero(&skip_b, sizeof(skip_b)); 424 skip_b.pfrb_type = PFRB_IFACES; 425 for (;;) { 426 pfr_buf_grow(&skip_b, skip_b.pfrb_size); 427 skip_b.pfrb_size = skip_b.pfrb_msize; 428 if (pfi_get_ifaces(NULL, skip_b.pfrb_caddr, &skip_b.pfrb_size)) 429 err(1, "pfi_get_ifaces"); 430 if (skip_b.pfrb_size <= skip_b.pfrb_msize) 431 break; 432 } 433 } 434 435 void 436 pfctl_check_skip_ifaces(char *ifname) 437 { 438 struct pfi_kif *p; 439 struct node_host *h = NULL, *n = NULL; 440 441 PFRB_FOREACH(p, &skip_b) { 442 if (!strcmp(ifname, p->pfik_name) && 443 (p->pfik_flags & PFI_IFLAG_SKIP)) 444 p->pfik_flags &= ~PFI_IFLAG_SKIP; 445 if (!strcmp(ifname, p->pfik_name) && p->pfik_group != NULL) { 446 if ((h = ifa_grouplookup(p->pfik_name, 0)) == NULL) 447 continue; 448 449 for (n = h; n != NULL; n = n->next) { 450 if (strncmp(p->pfik_name, ifname, IFNAMSIZ)) 451 continue; 452 453 p->pfik_flags &= ~PFI_IFLAG_SKIP; 454 } 455 } 456 } 457 } 458 459 void 460 pfctl_adjust_skip_ifaces(struct pfctl *pf) 461 { 462 struct pfi_kif *p, *pp; 463 struct node_host *h = NULL, *n = NULL; 464 465 PFRB_FOREACH(p, &skip_b) { 466 if (p->pfik_group == NULL || !(p->pfik_flags & PFI_IFLAG_SKIP)) 467 continue; 468 469 pfctl_set_interface_flags(pf, p->pfik_name, PFI_IFLAG_SKIP, 0); 470 if ((h = ifa_grouplookup(p->pfik_name, 0)) == NULL) 471 continue; 472 473 for (n = h; n != NULL; n = n->next) 474 PFRB_FOREACH(pp, &skip_b) { 475 if (strncmp(pp->pfik_name, n->ifname, IFNAMSIZ)) 476 continue; 477 478 if (!(pp->pfik_flags & PFI_IFLAG_SKIP)) 479 pfctl_set_interface_flags(pf, 480 pp->pfik_name, PFI_IFLAG_SKIP, 1); 481 if (pp->pfik_flags & PFI_IFLAG_SKIP) 482 pp->pfik_flags &= ~PFI_IFLAG_SKIP; 483 } 484 } 485 486 PFRB_FOREACH(p, &skip_b) { 487 if (! (p->pfik_flags & PFI_IFLAG_SKIP)) 488 continue; 489 490 pfctl_set_interface_flags(pf, p->pfik_name, PFI_IFLAG_SKIP, 0); 491 } 492 } 493 494 void 495 pfctl_clear_interface_flags(int dev, int opts) 496 { 497 struct pfioc_iface pi; 498 499 if ((opts & PF_OPT_NOACTION) == 0) { 500 bzero(&pi, sizeof(pi)); 501 pi.pfiio_flags = PFI_IFLAG_SKIP; 502 503 if (ioctl(dev, DIOCCLRIFFLAG, &pi)) 504 err(1, "DIOCCLRIFFLAG"); 505 if ((opts & PF_OPT_QUIET) == 0) 506 fprintf(stderr, "pf: interface flags reset\n"); 507 } 508 } 509 510 void 511 pfctl_flush_eth_rules(int dev, int opts, char *anchorname) 512 { 513 int ret; 514 515 ret = pfctl_clear_eth_rules(dev, anchorname); 516 if (ret != 0) 517 err(1, "pfctl_clear_eth_rules"); 518 519 if ((opts & PF_OPT_QUIET) == 0) 520 fprintf(stderr, "Ethernet rules cleared\n"); 521 } 522 523 int 524 pfctl_flush_rules(int dev, int opts, char *anchorname) 525 { 526 int ret; 527 528 ret = pfctl_clear_rules(dev, anchorname); 529 if (ret != 0) { 530 pfctl_err(opts, 1, "%s", __func__); 531 return (1); 532 } else if ((opts & PF_OPT_QUIET) == 0) 533 fprintf(stderr, "rules cleared\n"); 534 535 return (0); 536 } 537 538 void 539 pfctl_flush_nat(int dev, int opts, char *anchorname) 540 { 541 int ret; 542 543 ret = pfctl_clear_nat(dev, anchorname); 544 if (ret != 0) 545 err(1, "pfctl_clear_nat"); 546 if ((opts & PF_OPT_QUIET) == 0) 547 fprintf(stderr, "nat cleared\n"); 548 } 549 550 int 551 pfctl_clear_altq(int dev, int opts) 552 { 553 struct pfr_buffer t; 554 555 if (!altqsupport) 556 return (-1); 557 memset(&t, 0, sizeof(t)); 558 t.pfrb_type = PFRB_TRANS; 559 if (pfctl_add_trans(&t, PF_RULESET_ALTQ, "") || 560 pfctl_trans(dev, &t, DIOCXBEGIN, 0) || 561 pfctl_trans(dev, &t, DIOCXCOMMIT, 0)) 562 err(1, "pfctl_clear_altq"); 563 if ((opts & PF_OPT_QUIET) == 0) 564 fprintf(stderr, "altq cleared\n"); 565 return (0); 566 } 567 568 void 569 pfctl_clear_src_nodes(int dev, int opts) 570 { 571 if (ioctl(dev, DIOCCLRSRCNODES)) 572 pfctl_err(opts, 1, "DIOCCLRSRCNODES"); 573 if ((opts & PF_OPT_QUIET) == 0) 574 fprintf(stderr, "source tracking entries cleared\n"); 575 } 576 577 void 578 pfctl_clear_iface_states(int dev, const char *iface, int opts) 579 { 580 struct pfctl_kill kill; 581 unsigned int killed; 582 int ret; 583 584 memset(&kill, 0, sizeof(kill)); 585 if (iface != NULL && strlcpy(kill.ifname, iface, 586 sizeof(kill.ifname)) >= sizeof(kill.ifname)) 587 pfctl_errx(opts, 1, "invalid interface: %s", iface); 588 589 if (opts & PF_OPT_KILLMATCH) 590 kill.kill_match = true; 591 592 if ((ret = pfctl_clear_states_h(pfh, &kill, &killed)) != 0) 593 pfctl_err(opts, 1, "DIOCCLRSTATUS"); 594 if ((opts & PF_OPT_QUIET) == 0) 595 fprintf(stderr, "%d states cleared\n", killed); 596 } 597 598 struct addrinfo * 599 pfctl_addrprefix(char *addr, struct pf_addr *mask, int numeric) 600 { 601 char *p; 602 const char *errstr; 603 int prefix, ret_ga, q, r; 604 struct addrinfo hints, *res; 605 606 bzero(&hints, sizeof(hints)); 607 hints.ai_socktype = SOCK_DGRAM; /* dummy */ 608 if (numeric) 609 hints.ai_flags = AI_NUMERICHOST; 610 611 if ((p = strchr(addr, '/')) != NULL) { 612 *p++ = '\0'; 613 /* prefix only with numeric addresses */ 614 hints.ai_flags |= AI_NUMERICHOST; 615 } 616 617 if ((ret_ga = getaddrinfo(addr, NULL, &hints, &res))) { 618 errx(1, "getaddrinfo: %s", gai_strerror(ret_ga)); 619 /* NOTREACHED */ 620 } 621 622 if (p == NULL) 623 return (res); 624 625 prefix = strtonum(p, 0, res->ai_family == AF_INET6 ? 128 : 32, &errstr); 626 if (errstr) 627 errx(1, "prefix is %s: %s", errstr, p); 628 629 q = prefix >> 3; 630 r = prefix & 7; 631 switch (res->ai_family) { 632 case AF_INET: 633 bzero(&mask->v4, sizeof(mask->v4)); 634 mask->v4.s_addr = htonl((u_int32_t) 635 (0xffffffffffULL << (32 - prefix))); 636 break; 637 case AF_INET6: 638 bzero(&mask->v6, sizeof(mask->v6)); 639 if (q > 0) 640 memset((void *)&mask->v6, 0xff, q); 641 if (r > 0) 642 *((u_char *)&mask->v6 + q) = 643 (0xff00 >> r) & 0xff; 644 break; 645 } 646 647 return (res); 648 } 649 650 void 651 pfctl_kill_src_nodes(int dev, int opts) 652 { 653 struct pfioc_src_node_kill psnk; 654 struct addrinfo *res[2], *resp[2]; 655 struct sockaddr last_src, last_dst; 656 int killed, sources, dests; 657 658 killed = sources = dests = 0; 659 660 memset(&psnk, 0, sizeof(psnk)); 661 memset(&psnk.psnk_src.addr.v.a.mask, 0xff, 662 sizeof(psnk.psnk_src.addr.v.a.mask)); 663 memset(&last_src, 0xff, sizeof(last_src)); 664 memset(&last_dst, 0xff, sizeof(last_dst)); 665 666 res[0] = pfctl_addrprefix(src_node_kill[0], 667 &psnk.psnk_src.addr.v.a.mask, (opts & PF_OPT_NODNS)); 668 669 for (resp[0] = res[0]; resp[0]; resp[0] = resp[0]->ai_next) { 670 if (resp[0]->ai_addr == NULL) 671 continue; 672 /* We get lots of duplicates. Catch the easy ones */ 673 if (memcmp(&last_src, resp[0]->ai_addr, sizeof(last_src)) == 0) 674 continue; 675 last_src = *(struct sockaddr *)resp[0]->ai_addr; 676 677 psnk.psnk_af = resp[0]->ai_family; 678 sources++; 679 680 copy_satopfaddr(&psnk.psnk_src.addr.v.a.addr, resp[0]->ai_addr); 681 682 if (src_node_killers > 1) { 683 dests = 0; 684 memset(&psnk.psnk_dst.addr.v.a.mask, 0xff, 685 sizeof(psnk.psnk_dst.addr.v.a.mask)); 686 memset(&last_dst, 0xff, sizeof(last_dst)); 687 res[1] = pfctl_addrprefix(src_node_kill[1], 688 &psnk.psnk_dst.addr.v.a.mask, 689 (opts & PF_OPT_NODNS)); 690 for (resp[1] = res[1]; resp[1]; 691 resp[1] = resp[1]->ai_next) { 692 if (resp[1]->ai_addr == NULL) 693 continue; 694 if (psnk.psnk_af != resp[1]->ai_family) 695 continue; 696 697 if (memcmp(&last_dst, resp[1]->ai_addr, 698 sizeof(last_dst)) == 0) 699 continue; 700 last_dst = *(struct sockaddr *)resp[1]->ai_addr; 701 702 dests++; 703 704 copy_satopfaddr(&psnk.psnk_dst.addr.v.a.addr, 705 resp[1]->ai_addr); 706 if (ioctl(dev, DIOCKILLSRCNODES, &psnk)) 707 err(1, "DIOCKILLSRCNODES"); 708 killed += psnk.psnk_killed; 709 } 710 freeaddrinfo(res[1]); 711 } else { 712 if (ioctl(dev, DIOCKILLSRCNODES, &psnk)) 713 err(1, "DIOCKILLSRCNODES"); 714 killed += psnk.psnk_killed; 715 } 716 } 717 718 freeaddrinfo(res[0]); 719 720 if ((opts & PF_OPT_QUIET) == 0) 721 fprintf(stderr, "killed %d src nodes from %d sources and %d " 722 "destinations\n", killed, sources, dests); 723 } 724 725 void 726 pfctl_net_kill_states(int dev, const char *iface, int opts) 727 { 728 struct pfctl_kill kill; 729 struct addrinfo *res[2], *resp[2]; 730 struct sockaddr last_src, last_dst; 731 unsigned int newkilled; 732 int killed, sources, dests; 733 int ret; 734 735 killed = sources = dests = 0; 736 737 memset(&kill, 0, sizeof(kill)); 738 memset(&kill.src.addr.v.a.mask, 0xff, 739 sizeof(kill.src.addr.v.a.mask)); 740 memset(&last_src, 0xff, sizeof(last_src)); 741 memset(&last_dst, 0xff, sizeof(last_dst)); 742 if (iface != NULL && strlcpy(kill.ifname, iface, 743 sizeof(kill.ifname)) >= sizeof(kill.ifname)) 744 pfctl_errx(opts, 1, "invalid interface: %s", iface); 745 746 if (state_killers == 2 && (strcmp(state_kill[0], "nat") == 0)) { 747 kill.nat = true; 748 state_kill[0] = state_kill[1]; 749 state_killers = 1; 750 } 751 752 res[0] = pfctl_addrprefix(state_kill[0], 753 &kill.src.addr.v.a.mask, (opts & PF_OPT_NODNS)); 754 755 if (opts & PF_OPT_KILLMATCH) 756 kill.kill_match = true; 757 758 for (resp[0] = res[0]; resp[0]; resp[0] = resp[0]->ai_next) { 759 if (resp[0]->ai_addr == NULL) 760 continue; 761 /* We get lots of duplicates. Catch the easy ones */ 762 if (memcmp(&last_src, resp[0]->ai_addr, sizeof(last_src)) == 0) 763 continue; 764 last_src = *(struct sockaddr *)resp[0]->ai_addr; 765 766 kill.af = resp[0]->ai_family; 767 sources++; 768 769 copy_satopfaddr(&kill.src.addr.v.a.addr, resp[0]->ai_addr); 770 771 if (state_killers > 1) { 772 dests = 0; 773 memset(&kill.dst.addr.v.a.mask, 0xff, 774 sizeof(kill.dst.addr.v.a.mask)); 775 memset(&last_dst, 0xff, sizeof(last_dst)); 776 res[1] = pfctl_addrprefix(state_kill[1], 777 &kill.dst.addr.v.a.mask, 778 (opts & PF_OPT_NODNS)); 779 for (resp[1] = res[1]; resp[1]; 780 resp[1] = resp[1]->ai_next) { 781 if (resp[1]->ai_addr == NULL) 782 continue; 783 if (kill.af != resp[1]->ai_family) 784 continue; 785 786 if (memcmp(&last_dst, resp[1]->ai_addr, 787 sizeof(last_dst)) == 0) 788 continue; 789 last_dst = *(struct sockaddr *)resp[1]->ai_addr; 790 791 dests++; 792 793 copy_satopfaddr(&kill.dst.addr.v.a.addr, 794 resp[1]->ai_addr); 795 796 if ((ret = pfctl_kill_states_h(pfh, &kill, &newkilled)) != 0) 797 pfctl_errx(opts, 1, "DIOCKILLSTATES"); 798 killed += newkilled; 799 } 800 freeaddrinfo(res[1]); 801 } else { 802 if ((ret = pfctl_kill_states_h(pfh, &kill, &newkilled)) != 0) 803 pfctl_errx(opts, 1, "DIOCKILLSTATES"); 804 killed += newkilled; 805 } 806 } 807 808 freeaddrinfo(res[0]); 809 810 if ((opts & PF_OPT_QUIET) == 0) 811 fprintf(stderr, "killed %d states from %d sources and %d " 812 "destinations\n", killed, sources, dests); 813 } 814 815 void 816 pfctl_gateway_kill_states(int dev, const char *iface, int opts) 817 { 818 struct pfctl_kill kill; 819 struct addrinfo *res, *resp; 820 struct sockaddr last_src; 821 unsigned int newkilled; 822 int killed = 0; 823 824 if (state_killers != 2 || (strlen(state_kill[1]) == 0)) { 825 warnx("no gateway specified"); 826 usage(); 827 } 828 829 memset(&kill, 0, sizeof(kill)); 830 memset(&kill.rt_addr.addr.v.a.mask, 0xff, 831 sizeof(kill.rt_addr.addr.v.a.mask)); 832 memset(&last_src, 0xff, sizeof(last_src)); 833 if (iface != NULL && strlcpy(kill.ifname, iface, 834 sizeof(kill.ifname)) >= sizeof(kill.ifname)) 835 pfctl_errx(opts, 1, "invalid interface: %s", iface); 836 837 if (opts & PF_OPT_KILLMATCH) 838 kill.kill_match = true; 839 840 res = pfctl_addrprefix(state_kill[1], &kill.rt_addr.addr.v.a.mask, 841 (opts & PF_OPT_NODNS)); 842 843 for (resp = res; resp; resp = resp->ai_next) { 844 if (resp->ai_addr == NULL) 845 continue; 846 /* We get lots of duplicates. Catch the easy ones */ 847 if (memcmp(&last_src, resp->ai_addr, sizeof(last_src)) == 0) 848 continue; 849 last_src = *(struct sockaddr *)resp->ai_addr; 850 851 kill.af = resp->ai_family; 852 853 copy_satopfaddr(&kill.rt_addr.addr.v.a.addr, 854 resp->ai_addr); 855 if (pfctl_kill_states_h(pfh, &kill, &newkilled)) 856 pfctl_errx(opts, 1, "DIOCKILLSTATES"); 857 killed += newkilled; 858 } 859 860 freeaddrinfo(res); 861 862 if ((opts & PF_OPT_QUIET) == 0) 863 fprintf(stderr, "killed %d states\n", killed); 864 } 865 866 void 867 pfctl_label_kill_states(int dev, const char *iface, int opts) 868 { 869 struct pfctl_kill kill; 870 unsigned int killed; 871 int ret; 872 873 if (state_killers != 2 || (strlen(state_kill[1]) == 0)) { 874 warnx("no label specified"); 875 usage(); 876 } 877 memset(&kill, 0, sizeof(kill)); 878 if (iface != NULL && strlcpy(kill.ifname, iface, 879 sizeof(kill.ifname)) >= sizeof(kill.ifname)) 880 pfctl_errx(opts, 1, "invalid interface: %s", iface); 881 882 if (opts & PF_OPT_KILLMATCH) 883 kill.kill_match = true; 884 885 if (strlcpy(kill.label, state_kill[1], sizeof(kill.label)) >= 886 sizeof(kill.label)) 887 errx(1, "label too long: %s", state_kill[1]); 888 889 if ((ret = pfctl_kill_states_h(pfh, &kill, &killed)) != 0) 890 pfctl_errx(opts, 1, "DIOCKILLSTATES"); 891 892 if ((opts & PF_OPT_QUIET) == 0) 893 fprintf(stderr, "killed %d states\n", killed); 894 } 895 896 void 897 pfctl_id_kill_states(int dev, const char *iface, int opts) 898 { 899 struct pfctl_kill kill; 900 unsigned int killed; 901 int ret; 902 903 if (state_killers != 2 || (strlen(state_kill[1]) == 0)) { 904 warnx("no id specified"); 905 usage(); 906 } 907 908 memset(&kill, 0, sizeof(kill)); 909 910 if (opts & PF_OPT_KILLMATCH) 911 kill.kill_match = true; 912 913 if ((sscanf(state_kill[1], "%jx/%x", 914 &kill.cmp.id, &kill.cmp.creatorid)) == 2) { 915 } 916 else if ((sscanf(state_kill[1], "%jx", &kill.cmp.id)) == 1) { 917 kill.cmp.creatorid = 0; 918 } else { 919 warnx("wrong id format specified"); 920 usage(); 921 } 922 if (kill.cmp.id == 0) { 923 warnx("cannot kill id 0"); 924 usage(); 925 } 926 927 if ((ret = pfctl_kill_states_h(pfh, &kill, &killed)) != 0) 928 pfctl_errx(opts, 1, "DIOCKILLSTATES"); 929 930 if ((opts & PF_OPT_QUIET) == 0) 931 fprintf(stderr, "killed %d states\n", killed); 932 } 933 934 void 935 pfctl_key_kill_states(int dev, const char *iface, int opts) 936 { 937 struct pfctl_kill kill; 938 char *s, *token, *tokens[4]; 939 struct protoent *p; 940 u_int i, sidx, didx; 941 int ret, killed; 942 943 if (state_killers != 2 || (strlen(state_kill[1]) == 0)) { 944 warnx("no key specified"); 945 usage(); 946 } 947 memset(&kill, 0, sizeof(kill)); 948 949 if (iface != NULL && 950 strlcpy(kill.ifname, iface, sizeof(kill.ifname)) >= 951 sizeof(kill.ifname)) 952 pfctl_errx(opts, 1, "invalid interface: %s", iface); 953 954 s = strdup(state_kill[1]); 955 if (!s) 956 errx(1, "%s: strdup", __func__); 957 i = 0; 958 while ((token = strsep(&s, " \t")) != NULL) 959 if (*token != '\0') { 960 if (i < 4) 961 tokens[i] = token; 962 i++; 963 } 964 if (i != 4) 965 errx(1, "%s: key must be " 966 "\"protocol host1:port1 direction host2:port2\" format", 967 __func__); 968 969 if ((p = getprotobyname(tokens[0])) == NULL) 970 errx(1, "invalid protocol: %s", tokens[0]); 971 kill.proto = p->p_proto; 972 973 if (strcmp(tokens[2], "->") == 0) { 974 sidx = 1; 975 didx = 3; 976 } else if (strcmp(tokens[2], "<-") == 0) { 977 sidx = 3; 978 didx = 1; 979 } else 980 errx(1, "invalid direction: %s", tokens[2]); 981 982 if (pfctl_parse_host(tokens[sidx], &kill.src) == -1) 983 errx(1, "invalid host: %s", tokens[sidx]); 984 if (pfctl_parse_host(tokens[didx], &kill.dst) == -1) 985 errx(1, "invalid host: %s", tokens[didx]); 986 987 if ((ret = pfctl_kill_states_h(pfh, &kill, &killed)) != 0) 988 pfctl_errx(opts, 1, "DIOCKILLSTATES"); 989 990 if ((opts & PF_OPT_QUIET) == 0) 991 fprintf(stderr, "killed %d states\n", killed); 992 } 993 994 int 995 pfctl_parse_host(char *str, struct pf_rule_addr *addr) 996 { 997 char *s = NULL, *sbs, *sbe; 998 struct addrinfo hints, *ai; 999 1000 s = strdup(str); 1001 if (!s) 1002 errx(1, "pfctl_parse_host: strdup"); 1003 1004 memset(&hints, 0, sizeof(hints)); 1005 hints.ai_socktype = SOCK_DGRAM; /* dummy */ 1006 hints.ai_flags = AI_NUMERICHOST; 1007 1008 if ((sbs = strchr(s, '[')) != NULL && (sbe = strrchr(s, ']')) != NULL) { 1009 hints.ai_family = AF_INET6; 1010 *(sbs++) = *sbe = '\0'; 1011 } else if ((sbs = strchr(s, ':')) != NULL) { 1012 hints.ai_family = AF_INET; 1013 *(sbs++) = '\0'; 1014 } else { 1015 /* Assume that no ':<number>' means port 0 */ 1016 } 1017 1018 if (getaddrinfo(s, sbs, &hints, &ai) != 0) 1019 goto error; 1020 1021 copy_satopfaddr(&addr->addr.v.a.addr, ai->ai_addr); 1022 addr->port[0] = ai->ai_family == AF_INET6 ? 1023 ((struct sockaddr_in6 *)ai->ai_addr)->sin6_port : 1024 ((struct sockaddr_in *)ai->ai_addr)->sin_port; 1025 freeaddrinfo(ai); 1026 free(s); 1027 1028 memset(&addr->addr.v.a.mask, 0xff, sizeof(struct pf_addr)); 1029 addr->port_op = PF_OP_EQ; 1030 addr->addr.type = PF_ADDR_ADDRMASK; 1031 1032 return (0); 1033 1034 error: 1035 free(s); 1036 return (-1); 1037 } 1038 1039 int 1040 pfctl_get_pool(int dev, struct pfctl_pool *pool, u_int32_t nr, 1041 u_int32_t ticket, int r_action, const char *anchorname, int which) 1042 { 1043 struct pfioc_pooladdr pp; 1044 struct pfctl_pooladdr *pa; 1045 u_int32_t pnr, mpnr; 1046 int ret; 1047 1048 memset(&pp, 0, sizeof(pp)); 1049 if ((ret = pfctl_get_addrs(pfh, ticket, nr, r_action, anchorname, &mpnr, which)) != 0) { 1050 warnc(ret, "DIOCGETADDRS"); 1051 return (-1); 1052 } 1053 1054 TAILQ_INIT(&pool->list); 1055 for (pnr = 0; pnr < mpnr; ++pnr) { 1056 if ((ret = pfctl_get_addr(pfh, ticket, nr, r_action, anchorname, pnr, &pp, which)) != 0) { 1057 warnc(ret, "DIOCGETADDR"); 1058 return (-1); 1059 } 1060 pa = calloc(1, sizeof(struct pfctl_pooladdr)); 1061 if (pa == NULL) 1062 err(1, "calloc"); 1063 bcopy(&pp.addr, pa, sizeof(struct pfctl_pooladdr)); 1064 pa->af = pp.af; 1065 TAILQ_INSERT_TAIL(&pool->list, pa, entries); 1066 } 1067 1068 return (0); 1069 } 1070 1071 void 1072 pfctl_move_pool(struct pfctl_pool *src, struct pfctl_pool *dst) 1073 { 1074 struct pfctl_pooladdr *pa; 1075 1076 while ((pa = TAILQ_FIRST(&src->list)) != NULL) { 1077 TAILQ_REMOVE(&src->list, pa, entries); 1078 TAILQ_INSERT_TAIL(&dst->list, pa, entries); 1079 } 1080 } 1081 1082 void 1083 pfctl_clear_pool(struct pfctl_pool *pool) 1084 { 1085 struct pfctl_pooladdr *pa; 1086 1087 while ((pa = TAILQ_FIRST(&pool->list)) != NULL) { 1088 TAILQ_REMOVE(&pool->list, pa, entries); 1089 free(pa); 1090 } 1091 } 1092 1093 void 1094 pfctl_print_eth_rule_counters(struct pfctl_eth_rule *rule, int opts) 1095 { 1096 if (opts & PF_OPT_VERBOSE) { 1097 printf(" [ Evaluations: %-8llu Packets: %-8llu " 1098 "Bytes: %-10llu]\n", 1099 (unsigned long long)rule->evaluations, 1100 (unsigned long long)(rule->packets[0] + 1101 rule->packets[1]), 1102 (unsigned long long)(rule->bytes[0] + 1103 rule->bytes[1])); 1104 } 1105 if (opts & PF_OPT_VERBOSE2) { 1106 char timestr[30]; 1107 1108 if (rule->last_active_timestamp != 0) { 1109 bcopy(ctime(&rule->last_active_timestamp), timestr, 1110 sizeof(timestr)); 1111 *strchr(timestr, '\n') = '\0'; 1112 } else { 1113 snprintf(timestr, sizeof(timestr), "N/A"); 1114 } 1115 printf(" [ Last Active Time: %s ]\n", timestr); 1116 } 1117 } 1118 1119 void 1120 pfctl_print_rule_counters(struct pfctl_rule *rule, int opts) 1121 { 1122 if (opts & PF_OPT_DEBUG) { 1123 const char *t[PF_SKIP_COUNT] = { "i", "d", "f", 1124 "p", "sa", "da", "sp", "dp" }; 1125 int i; 1126 1127 printf(" [ Skip steps: "); 1128 for (i = 0; i < PF_SKIP_COUNT; ++i) { 1129 if (rule->skip[i].nr == rule->nr + 1) 1130 continue; 1131 printf("%s=", t[i]); 1132 if (rule->skip[i].nr == -1) 1133 printf("end "); 1134 else 1135 printf("%u ", rule->skip[i].nr); 1136 } 1137 printf("]\n"); 1138 1139 printf(" [ queue: qname=%s qid=%u pqname=%s pqid=%u ]\n", 1140 rule->qname, rule->qid, rule->pqname, rule->pqid); 1141 } 1142 if (opts & PF_OPT_VERBOSE) { 1143 printf(" [ Evaluations: %-8llu Packets: %-8llu " 1144 "Bytes: %-10llu States: %-6ju]\n", 1145 (unsigned long long)rule->evaluations, 1146 (unsigned long long)(rule->packets[0] + 1147 rule->packets[1]), 1148 (unsigned long long)(rule->bytes[0] + 1149 rule->bytes[1]), (uintmax_t)rule->states_cur); 1150 printf(" [ Source Nodes: %-6ju " 1151 "Limit: %-6ju " 1152 "NAT/RDR: %-6ju " 1153 "Route: %-6ju " 1154 "]\n", 1155 (uintmax_t)rule->src_nodes, 1156 (uintmax_t)rule->src_nodes_type[PF_SN_LIMIT], 1157 (uintmax_t)rule->src_nodes_type[PF_SN_NAT], 1158 (uintmax_t)rule->src_nodes_type[PF_SN_ROUTE]); 1159 if (!(opts & PF_OPT_DEBUG)) 1160 printf(" [ Inserted: uid %u pid %u " 1161 "State Creations: %-6ju]\n", 1162 (unsigned)rule->cuid, (unsigned)rule->cpid, 1163 (uintmax_t)rule->states_tot); 1164 } 1165 if (opts & PF_OPT_VERBOSE2) { 1166 char timestr[30]; 1167 if (rule->last_active_timestamp != 0) { 1168 bcopy(ctime(&rule->last_active_timestamp), timestr, 1169 sizeof(timestr)); 1170 *strchr(timestr, '\n') = '\0'; 1171 } else { 1172 snprintf(timestr, sizeof(timestr), "N/A"); 1173 } 1174 printf(" [ Last Active Time: %s ]\n", timestr); 1175 } 1176 } 1177 1178 void 1179 pfctl_print_title(char *title) 1180 { 1181 if (!first_title) 1182 printf("\n"); 1183 first_title = 0; 1184 printf("%s\n", title); 1185 } 1186 1187 int 1188 pfctl_show_eth_rules(int dev, char *path, int opts, enum pfctl_show format, 1189 char *anchorname, int depth, int wildcard) 1190 { 1191 char anchor_call[MAXPATHLEN]; 1192 struct pfctl_eth_rules_info info; 1193 struct pfctl_eth_rule rule; 1194 int brace; 1195 int dotitle = opts & PF_OPT_SHOWALL; 1196 int len = strlen(path); 1197 int ret; 1198 char *npath, *p; 1199 1200 /* 1201 * Truncate a trailing / and * on an anchorname before searching for 1202 * the ruleset, this is syntactic sugar that doesn't actually make it 1203 * to the kernel. 1204 */ 1205 if ((p = strrchr(anchorname, '/')) != NULL && 1206 p[1] == '*' && p[2] == '\0') { 1207 p[0] = '\0'; 1208 } 1209 1210 if (anchorname[0] == '/') { 1211 if ((npath = calloc(1, MAXPATHLEN)) == NULL) 1212 errx(1, "calloc"); 1213 snprintf(npath, MAXPATHLEN, "%s", anchorname); 1214 } else { 1215 if (path[0]) 1216 snprintf(&path[len], MAXPATHLEN - len, "/%s", anchorname); 1217 else 1218 snprintf(&path[len], MAXPATHLEN - len, "%s", anchorname); 1219 npath = path; 1220 } 1221 1222 /* 1223 * If this anchor was called with a wildcard path, go through 1224 * the rulesets in the anchor rather than the rules. 1225 */ 1226 if (wildcard && (opts & PF_OPT_RECURSE)) { 1227 struct pfctl_eth_rulesets_info ri; 1228 u_int32_t mnr, nr; 1229 1230 if ((ret = pfctl_get_eth_rulesets_info(dev, &ri, npath)) != 0) { 1231 if (ret == EINVAL) { 1232 fprintf(stderr, "Anchor '%s' " 1233 "not found.\n", anchorname); 1234 } else { 1235 warnc(ret, "DIOCGETETHRULESETS"); 1236 return (-1); 1237 } 1238 } 1239 mnr = ri.nr; 1240 1241 pfctl_print_eth_rule_counters(&rule, opts); 1242 for (nr = 0; nr < mnr; ++nr) { 1243 struct pfctl_eth_ruleset_info rs; 1244 1245 if ((ret = pfctl_get_eth_ruleset(dev, npath, nr, &rs)) != 0) 1246 errc(1, ret, "DIOCGETETHRULESET"); 1247 INDENT(depth, !(opts & PF_OPT_VERBOSE)); 1248 printf("anchor \"%s\" all {\n", rs.name); 1249 pfctl_show_eth_rules(dev, npath, opts, 1250 format, rs.name, depth + 1, 0); 1251 INDENT(depth, !(opts & PF_OPT_VERBOSE)); 1252 printf("}\n"); 1253 } 1254 path[len] = '\0'; 1255 return (0); 1256 } 1257 1258 if ((ret = pfctl_get_eth_rules_info(dev, &info, path)) != 0) { 1259 warnc(ret, "DIOCGETETHRULES"); 1260 return (-1); 1261 } 1262 for (int nr = 0; nr < info.nr; nr++) { 1263 brace = 0; 1264 INDENT(depth, !(opts & PF_OPT_VERBOSE)); 1265 if ((ret = pfctl_get_eth_rule(dev, nr, info.ticket, path, &rule, 1266 opts & PF_OPT_CLRRULECTRS, anchor_call)) != 0) { 1267 warnc(ret, "DIOCGETETHRULE"); 1268 return (-1); 1269 } 1270 if (anchor_call[0] && 1271 ((((p = strrchr(anchor_call, '_')) != NULL) && 1272 (p == anchor_call || 1273 *(--p) == '/')) || (opts & PF_OPT_RECURSE))) { 1274 brace++; 1275 int aclen = strlen(anchor_call); 1276 if (anchor_call[aclen - 1] == '*') 1277 anchor_call[aclen - 2] = '\0'; 1278 } 1279 p = &anchor_call[0]; 1280 if (dotitle) { 1281 pfctl_print_title("ETH RULES:"); 1282 dotitle = 0; 1283 } 1284 print_eth_rule(&rule, anchor_call, 1285 opts & (PF_OPT_VERBOSE2 | PF_OPT_DEBUG)); 1286 if (brace) 1287 printf(" {\n"); 1288 else 1289 printf("\n"); 1290 pfctl_print_eth_rule_counters(&rule, opts); 1291 if (brace) { 1292 pfctl_show_eth_rules(dev, path, opts, format, 1293 p, depth + 1, rule.anchor_wildcard); 1294 INDENT(depth, !(opts & PF_OPT_VERBOSE)); 1295 printf("}\n"); 1296 } 1297 } 1298 1299 path[len] = '\0'; 1300 return (0); 1301 } 1302 1303 int 1304 pfctl_show_rules(int dev, char *path, int opts, enum pfctl_show format, 1305 char *anchorname, int depth, int wildcard) 1306 { 1307 struct pfctl_rules_info ri; 1308 struct pfctl_rule rule; 1309 char anchor_call[MAXPATHLEN]; 1310 u_int32_t nr, header = 0; 1311 int rule_numbers = opts & (PF_OPT_VERBOSE2 | PF_OPT_DEBUG); 1312 int numeric = opts & PF_OPT_NUMERIC; 1313 int len = strlen(path), ret = 0; 1314 char *npath, *p; 1315 1316 /* 1317 * Truncate a trailing / and * on an anchorname before searching for 1318 * the ruleset, this is syntactic sugar that doesn't actually make it 1319 * to the kernel. 1320 */ 1321 if ((p = strrchr(anchorname, '/')) != NULL && 1322 p[1] == '*' && p[2] == '\0') { 1323 p[0] = '\0'; 1324 } 1325 1326 if (anchorname[0] == '/') { 1327 if ((npath = calloc(1, MAXPATHLEN)) == NULL) 1328 errx(1, "calloc"); 1329 strlcpy(npath, anchorname, MAXPATHLEN); 1330 } else { 1331 if (path[0]) 1332 snprintf(&path[len], MAXPATHLEN - len, "/%s", anchorname); 1333 else 1334 snprintf(&path[len], MAXPATHLEN - len, "%s", anchorname); 1335 npath = path; 1336 } 1337 1338 /* 1339 * If this anchor was called with a wildcard path, go through 1340 * the rulesets in the anchor rather than the rules. 1341 */ 1342 if (wildcard && (opts & PF_OPT_RECURSE)) { 1343 struct pfioc_ruleset prs; 1344 u_int32_t mnr, nr; 1345 1346 memset(&prs, 0, sizeof(prs)); 1347 if ((ret = pfctl_get_rulesets(pfh, npath, &mnr)) != 0) 1348 errx(1, "%s", pf_strerror(ret)); 1349 1350 for (nr = 0; nr < mnr; ++nr) { 1351 if ((ret = pfctl_get_ruleset(pfh, npath, nr, &prs)) != 0) 1352 errx(1, "%s", pf_strerror(ret)); 1353 INDENT(depth, !(opts & PF_OPT_VERBOSE)); 1354 printf("anchor \"%s\" all {\n", prs.name); 1355 pfctl_show_rules(dev, npath, opts, 1356 format, prs.name, depth + 1, 0); 1357 INDENT(depth, !(opts & PF_OPT_VERBOSE)); 1358 printf("}\n"); 1359 } 1360 path[len] = '\0'; 1361 return (0); 1362 } 1363 1364 if (opts & PF_OPT_SHOWALL) { 1365 ret = pfctl_get_rules_info_h(pfh, &ri, PF_PASS, path); 1366 if (ret != 0) { 1367 warnx("%s", pf_strerror(ret)); 1368 goto error; 1369 } 1370 header++; 1371 } 1372 ret = pfctl_get_rules_info_h(pfh, &ri, PF_SCRUB, path); 1373 if (ret != 0) { 1374 warnx("%s", pf_strerror(ret)); 1375 goto error; 1376 } 1377 if (opts & PF_OPT_SHOWALL) { 1378 if (format == PFCTL_SHOW_RULES && (ri.nr > 0 || header)) 1379 pfctl_print_title("FILTER RULES:"); 1380 else if (format == PFCTL_SHOW_LABELS && labels) 1381 pfctl_print_title("LABEL COUNTERS:"); 1382 } 1383 1384 for (nr = 0; nr < ri.nr; ++nr) { 1385 if ((ret = pfctl_get_clear_rule_h(pfh, nr, ri.ticket, path, PF_SCRUB, 1386 &rule, anchor_call, opts & PF_OPT_CLRRULECTRS)) != 0) { 1387 warnc(ret, "DIOCGETRULENV"); 1388 goto error; 1389 } 1390 1391 if (pfctl_get_pool(dev, &rule.rdr, 1392 nr, ri.ticket, PF_SCRUB, path, PF_RDR) != 0) 1393 goto error; 1394 1395 if (pfctl_get_pool(dev, &rule.nat, 1396 nr, ri.ticket, PF_SCRUB, path, PF_NAT) != 0) 1397 goto error; 1398 1399 if (pfctl_get_pool(dev, &rule.route, 1400 nr, ri.ticket, PF_SCRUB, path, PF_RT) != 0) 1401 goto error; 1402 1403 switch (format) { 1404 case PFCTL_SHOW_LABELS: 1405 break; 1406 case PFCTL_SHOW_RULES: 1407 if (rule.label[0][0] && (opts & PF_OPT_SHOWALL)) 1408 labels = 1; 1409 print_rule(&rule, anchor_call, rule_numbers, numeric); 1410 printf("\n"); 1411 pfctl_print_rule_counters(&rule, opts); 1412 break; 1413 case PFCTL_SHOW_NOTHING: 1414 break; 1415 } 1416 pfctl_clear_pool(&rule.rdr); 1417 pfctl_clear_pool(&rule.nat); 1418 pfctl_clear_pool(&rule.route); 1419 } 1420 ret = pfctl_get_rules_info_h(pfh, &ri, PF_PASS, path); 1421 if (ret != 0) { 1422 warnc(ret, "DIOCGETRULES"); 1423 goto error; 1424 } 1425 for (nr = 0; nr < ri.nr; ++nr) { 1426 if ((ret = pfctl_get_clear_rule_h(pfh, nr, ri.ticket, path, PF_PASS, 1427 &rule, anchor_call, opts & PF_OPT_CLRRULECTRS)) != 0) { 1428 warnc(ret, "DIOCGETRULE"); 1429 goto error; 1430 } 1431 1432 if (pfctl_get_pool(dev, &rule.rdr, 1433 nr, ri.ticket, PF_PASS, path, PF_RDR) != 0) 1434 goto error; 1435 1436 if (pfctl_get_pool(dev, &rule.nat, 1437 nr, ri.ticket, PF_PASS, path, PF_NAT) != 0) 1438 goto error; 1439 1440 if (pfctl_get_pool(dev, &rule.route, 1441 nr, ri.ticket, PF_PASS, path, PF_RT) != 0) 1442 goto error; 1443 1444 switch (format) { 1445 case PFCTL_SHOW_LABELS: { 1446 bool show = false; 1447 int i = 0; 1448 1449 while (rule.label[i][0]) { 1450 printf("%s ", rule.label[i++]); 1451 show = true; 1452 } 1453 1454 if (show) { 1455 printf("%llu %llu %llu %llu" 1456 " %llu %llu %llu %ju\n", 1457 (unsigned long long)rule.evaluations, 1458 (unsigned long long)(rule.packets[0] + 1459 rule.packets[1]), 1460 (unsigned long long)(rule.bytes[0] + 1461 rule.bytes[1]), 1462 (unsigned long long)rule.packets[0], 1463 (unsigned long long)rule.bytes[0], 1464 (unsigned long long)rule.packets[1], 1465 (unsigned long long)rule.bytes[1], 1466 (uintmax_t)rule.states_tot); 1467 } 1468 1469 if (anchor_call[0] && 1470 (((p = strrchr(anchor_call, '/')) ? 1471 p[1] == '_' : anchor_call[0] == '_') || 1472 opts & PF_OPT_RECURSE)) { 1473 pfctl_show_rules(dev, npath, opts, format, 1474 anchor_call, depth, rule.anchor_wildcard); 1475 } 1476 break; 1477 } 1478 case PFCTL_SHOW_RULES: 1479 if (rule.label[0][0] && (opts & PF_OPT_SHOWALL)) 1480 labels = 1; 1481 INDENT(depth, !(opts & PF_OPT_VERBOSE)); 1482 print_rule(&rule, anchor_call, rule_numbers, numeric); 1483 1484 /* 1485 * If this is a 'unnamed' brace notation 1486 * anchor, OR the user has explicitly requested 1487 * recursion, print it recursively. 1488 */ 1489 if (anchor_call[0] && 1490 (((p = strrchr(anchor_call, '/')) ? 1491 p[1] == '_' : anchor_call[0] == '_') || 1492 opts & PF_OPT_RECURSE)) { 1493 printf(" {\n"); 1494 pfctl_print_rule_counters(&rule, opts); 1495 pfctl_show_rules(dev, npath, opts, format, 1496 anchor_call, depth + 1, 1497 rule.anchor_wildcard); 1498 INDENT(depth, !(opts & PF_OPT_VERBOSE)); 1499 printf("}\n"); 1500 } else { 1501 printf("\n"); 1502 pfctl_print_rule_counters(&rule, opts); 1503 } 1504 break; 1505 case PFCTL_SHOW_NOTHING: 1506 break; 1507 } 1508 pfctl_clear_pool(&rule.rdr); 1509 pfctl_clear_pool(&rule.nat); 1510 } 1511 1512 error: 1513 path[len] = '\0'; 1514 return (ret); 1515 } 1516 1517 int 1518 pfctl_show_nat(int dev, const char *path, int opts, char *anchorname, int depth, 1519 int wildcard) 1520 { 1521 struct pfctl_rules_info ri; 1522 struct pfctl_rule rule; 1523 char anchor_call[MAXPATHLEN]; 1524 u_int32_t nr; 1525 static int nattype[3] = { PF_NAT, PF_RDR, PF_BINAT }; 1526 int i, dotitle = opts & PF_OPT_SHOWALL; 1527 int ret; 1528 int len = strlen(path); 1529 char *npath, *p; 1530 1531 /* 1532 * Truncate a trailing / and * on an anchorname before searching for 1533 * the ruleset, this is syntactic sugar that doesn't actually make it 1534 * to the kernel. 1535 */ 1536 if ((p = strrchr(anchorname, '/')) != NULL && 1537 p[1] == '*' && p[2] == '\0') { 1538 p[0] = '\0'; 1539 } 1540 1541 if ((npath = calloc(1, MAXPATHLEN)) == NULL) 1542 errx(1, "calloc"); 1543 1544 if (anchorname[0] == '/') { 1545 snprintf(npath, MAXPATHLEN, "%s", anchorname); 1546 } else { 1547 snprintf(npath, MAXPATHLEN, "%s", path); 1548 if (npath[0]) 1549 snprintf(&npath[len], MAXPATHLEN - len, "/%s", anchorname); 1550 else 1551 snprintf(&npath[len], MAXPATHLEN - len, "%s", anchorname); 1552 } 1553 1554 /* 1555 * If this anchor was called with a wildcard path, go through 1556 * the rulesets in the anchor rather than the rules. 1557 */ 1558 if (wildcard && (opts & PF_OPT_RECURSE)) { 1559 struct pfioc_ruleset prs; 1560 u_int32_t mnr, nr; 1561 memset(&prs, 0, sizeof(prs)); 1562 if ((ret = pfctl_get_rulesets(pfh, npath, &mnr)) != 0) { 1563 if (ret == EINVAL) 1564 fprintf(stderr, "NAT anchor '%s' " 1565 "not found.\n", anchorname); 1566 else 1567 errx(1, "%s", pf_strerror(ret)); 1568 } 1569 1570 for (nr = 0; nr < mnr; ++nr) { 1571 if ((ret = pfctl_get_ruleset(pfh, npath, nr, &prs)) != 0) 1572 errx(1, "%s", pf_strerror(ret)); 1573 INDENT(depth, !(opts & PF_OPT_VERBOSE)); 1574 printf("nat-anchor \"%s\" all {\n", prs.name); 1575 pfctl_show_nat(dev, npath, opts, 1576 prs.name, depth + 1, 0); 1577 INDENT(depth, !(opts & PF_OPT_VERBOSE)); 1578 printf("}\n"); 1579 } 1580 npath[len] = '\0'; 1581 return (0); 1582 } 1583 1584 for (i = 0; i < 3; i++) { 1585 ret = pfctl_get_rules_info_h(pfh, &ri, nattype[i], npath); 1586 if (ret != 0) { 1587 warnc(ret, "DIOCGETRULES"); 1588 return (-1); 1589 } 1590 for (nr = 0; nr < ri.nr; ++nr) { 1591 INDENT(depth, !(opts & PF_OPT_VERBOSE)); 1592 1593 if ((ret = pfctl_get_rule_h(pfh, nr, ri.ticket, npath, 1594 nattype[i], &rule, anchor_call)) != 0) { 1595 warnc(ret, "DIOCGETRULE"); 1596 return (-1); 1597 } 1598 if (pfctl_get_pool(dev, &rule.rdr, nr, 1599 ri.ticket, nattype[i], npath, PF_RDR) != 0) 1600 return (-1); 1601 if (pfctl_get_pool(dev, &rule.nat, nr, 1602 ri.ticket, nattype[i], npath, PF_NAT) != 0) 1603 return (-1); 1604 if (pfctl_get_pool(dev, &rule.route, nr, 1605 ri.ticket, nattype[i], npath, PF_RT) != 0) 1606 return (-1); 1607 1608 if (dotitle) { 1609 pfctl_print_title("TRANSLATION RULES:"); 1610 dotitle = 0; 1611 } 1612 print_rule(&rule, anchor_call, 1613 opts & PF_OPT_VERBOSE2, opts & PF_OPT_NUMERIC); 1614 if (anchor_call[0] && 1615 (((p = strrchr(anchor_call, '/')) ? 1616 p[1] == '_' : anchor_call[0] == '_') || 1617 opts & PF_OPT_RECURSE)) { 1618 printf(" {\n"); 1619 pfctl_print_rule_counters(&rule, opts); 1620 pfctl_show_nat(dev, npath, opts, anchor_call, 1621 depth + 1, rule.anchor_wildcard); 1622 INDENT(depth, !(opts & PF_OPT_VERBOSE)); 1623 printf("}\n"); 1624 } else { 1625 printf("\n"); 1626 pfctl_print_rule_counters(&rule, opts); 1627 } 1628 } 1629 } 1630 return (0); 1631 } 1632 1633 static int 1634 pfctl_print_src_node(struct pfctl_src_node *sn, void *arg) 1635 { 1636 int *opts = (int *)arg; 1637 1638 if (*opts & PF_OPT_SHOWALL) { 1639 pfctl_print_title("SOURCE TRACKING NODES:"); 1640 *opts &= ~PF_OPT_SHOWALL; 1641 } 1642 1643 print_src_node(sn, *opts); 1644 1645 return (0); 1646 } 1647 1648 int 1649 pfctl_show_src_nodes(int dev, int opts) 1650 { 1651 int error; 1652 1653 error = pfctl_get_srcnodes(pfh, pfctl_print_src_node, &opts); 1654 1655 return (error); 1656 } 1657 1658 struct pfctl_show_state_arg { 1659 int opts; 1660 int dotitle; 1661 const char *iface; 1662 }; 1663 1664 static int 1665 pfctl_show_state(struct pfctl_state *s, void *arg) 1666 { 1667 struct pfctl_show_state_arg *a = (struct pfctl_show_state_arg *)arg; 1668 1669 if (a->dotitle) { 1670 pfctl_print_title("STATES:"); 1671 a->dotitle = 0; 1672 } 1673 print_state(s, a->opts); 1674 1675 return (0); 1676 } 1677 1678 int 1679 pfctl_show_states(int dev, const char *iface, int opts) 1680 { 1681 struct pfctl_show_state_arg arg; 1682 struct pfctl_state_filter filter = {}; 1683 1684 if (iface != NULL) 1685 strlcpy(filter.ifname, iface, IFNAMSIZ); 1686 1687 arg.opts = opts; 1688 arg.dotitle = opts & PF_OPT_SHOWALL; 1689 arg.iface = iface; 1690 1691 if (pfctl_get_filtered_states_iter(&filter, pfctl_show_state, &arg)) 1692 return (-1); 1693 1694 return (0); 1695 } 1696 1697 int 1698 pfctl_show_status(int dev, int opts) 1699 { 1700 struct pfctl_status *status; 1701 struct pfctl_syncookies cookies; 1702 int ret; 1703 1704 if ((status = pfctl_get_status_h(pfh)) == NULL) { 1705 warn("DIOCGETSTATUS"); 1706 return (-1); 1707 } 1708 if ((ret = pfctl_get_syncookies(dev, &cookies)) != 0) { 1709 pfctl_free_status(status); 1710 warnc(ret, "DIOCGETSYNCOOKIES"); 1711 return (-1); 1712 } 1713 if (opts & PF_OPT_SHOWALL) 1714 pfctl_print_title("INFO:"); 1715 print_status(status, &cookies, opts); 1716 pfctl_free_status(status); 1717 return (0); 1718 } 1719 1720 int 1721 pfctl_show_running(int dev) 1722 { 1723 struct pfctl_status *status; 1724 int running; 1725 1726 if ((status = pfctl_get_status_h(pfh)) == NULL) { 1727 warn("DIOCGETSTATUS"); 1728 return (-1); 1729 } 1730 1731 running = status->running; 1732 1733 print_running(status); 1734 pfctl_free_status(status); 1735 return (!running); 1736 } 1737 1738 int 1739 pfctl_show_timeouts(int dev, int opts) 1740 { 1741 uint32_t seconds; 1742 int i; 1743 int ret; 1744 1745 if (opts & PF_OPT_SHOWALL) 1746 pfctl_print_title("TIMEOUTS:"); 1747 for (i = 0; pf_timeouts[i].name; i++) { 1748 if ((ret = pfctl_get_timeout(pfh, pf_timeouts[i].timeout, &seconds)) != 0) 1749 errc(1, ret, "DIOCGETTIMEOUT"); 1750 printf("%-20s %10d", pf_timeouts[i].name, seconds); 1751 if (pf_timeouts[i].timeout >= PFTM_ADAPTIVE_START && 1752 pf_timeouts[i].timeout <= PFTM_ADAPTIVE_END) 1753 printf(" states"); 1754 else 1755 printf("s"); 1756 printf("\n"); 1757 } 1758 return (0); 1759 1760 } 1761 1762 int 1763 pfctl_show_limits(int dev, int opts) 1764 { 1765 unsigned int limit; 1766 int i; 1767 int ret; 1768 1769 if (opts & PF_OPT_SHOWALL) 1770 pfctl_print_title("LIMITS:"); 1771 for (i = 0; pf_limits[i].name; i++) { 1772 if ((ret = pfctl_get_limit(pfh, pf_limits[i].index, &limit)) != 0) 1773 errc(1, ret, "DIOCGETLIMIT"); 1774 printf("%-13s ", pf_limits[i].name); 1775 if (limit == UINT_MAX) 1776 printf("unlimited\n"); 1777 else 1778 printf("hard limit %8u\n", limit); 1779 } 1780 return (0); 1781 } 1782 1783 void 1784 pfctl_show_creators(int opts) 1785 { 1786 int ret; 1787 uint32_t creators[16]; 1788 size_t count = nitems(creators); 1789 1790 ret = pfctl_get_creatorids(pfh, creators, &count); 1791 if (ret != 0) 1792 errx(ret, "Failed to retrieve creators"); 1793 1794 printf("Creator IDs:\n"); 1795 for (size_t i = 0; i < count; i++) 1796 printf("%08x\n", creators[i]); 1797 } 1798 1799 /* callbacks for rule/nat/rdr/addr */ 1800 int 1801 pfctl_add_pool(struct pfctl *pf, struct pfctl_pool *p, int which) 1802 { 1803 struct pfctl_pooladdr *pa; 1804 int ret; 1805 1806 TAILQ_FOREACH(pa, &p->list, entries) { 1807 memcpy(&pf->paddr.addr, pa, sizeof(struct pfctl_pooladdr)); 1808 pf->paddr.af = pa->af; 1809 if ((pf->opts & PF_OPT_NOACTION) == 0) { 1810 if ((ret = pfctl_add_addr(pf->h, &pf->paddr, which)) != 0) 1811 errc(1, ret, "DIOCADDADDR"); 1812 } 1813 } 1814 return (0); 1815 } 1816 1817 void 1818 pfctl_init_rule(struct pfctl_rule *r) 1819 { 1820 memset(r, 0, sizeof(struct pfctl_rule)); 1821 TAILQ_INIT(&(r->rdr.list)); 1822 TAILQ_INIT(&(r->nat.list)); 1823 TAILQ_INIT(&(r->route.list)); 1824 } 1825 1826 int 1827 pfctl_append_rule(struct pfctl *pf, struct pfctl_rule *r, 1828 const char *anchor_call) 1829 { 1830 u_int8_t rs_num; 1831 struct pfctl_rule *rule; 1832 struct pfctl_ruleset *rs; 1833 char *p; 1834 1835 rs_num = pf_get_ruleset_number(r->action); 1836 if (rs_num == PF_RULESET_MAX) 1837 errx(1, "Invalid rule type %d", r->action); 1838 1839 rs = &pf->anchor->ruleset; 1840 1841 if (anchor_call[0] && r->anchor == NULL) { 1842 /* 1843 * Don't make non-brace anchors part of the main anchor pool. 1844 */ 1845 if ((r->anchor = calloc(1, sizeof(*r->anchor))) == NULL) 1846 err(1, "pfctl_append_rule: calloc"); 1847 1848 pf_init_ruleset(&r->anchor->ruleset); 1849 r->anchor->ruleset.anchor = r->anchor; 1850 if (strlcpy(r->anchor->path, anchor_call, 1851 sizeof(rule->anchor->path)) >= sizeof(rule->anchor->path)) 1852 errx(1, "pfctl_append_rule: strlcpy"); 1853 if ((p = strrchr(anchor_call, '/')) != NULL) { 1854 if (!strlen(p)) 1855 err(1, "pfctl_append_rule: bad anchor name %s", 1856 anchor_call); 1857 } else 1858 p = (char *)anchor_call; 1859 if (strlcpy(r->anchor->name, p, 1860 sizeof(rule->anchor->name)) >= sizeof(rule->anchor->name)) 1861 errx(1, "pfctl_append_rule: strlcpy"); 1862 } 1863 1864 if ((rule = calloc(1, sizeof(*rule))) == NULL) 1865 err(1, "calloc"); 1866 bcopy(r, rule, sizeof(*rule)); 1867 TAILQ_INIT(&rule->rdr.list); 1868 pfctl_move_pool(&r->rdr, &rule->rdr); 1869 TAILQ_INIT(&rule->nat.list); 1870 pfctl_move_pool(&r->nat, &rule->nat); 1871 TAILQ_INIT(&rule->route.list); 1872 pfctl_move_pool(&r->route, &rule->route); 1873 1874 TAILQ_INSERT_TAIL(rs->rules[rs_num].active.ptr, rule, entries); 1875 return (0); 1876 } 1877 1878 int 1879 pfctl_append_eth_rule(struct pfctl *pf, struct pfctl_eth_rule *r, 1880 const char *anchor_call) 1881 { 1882 struct pfctl_eth_rule *rule; 1883 struct pfctl_eth_ruleset *rs; 1884 char *p; 1885 1886 rs = &pf->eanchor->ruleset; 1887 1888 if (anchor_call[0] && r->anchor == NULL) { 1889 /* 1890 * Don't make non-brace anchors part of the main anchor pool. 1891 */ 1892 if ((r->anchor = calloc(1, sizeof(*r->anchor))) == NULL) 1893 err(1, "pfctl_append_rule: calloc"); 1894 1895 pf_init_eth_ruleset(&r->anchor->ruleset); 1896 r->anchor->ruleset.anchor = r->anchor; 1897 if (strlcpy(r->anchor->path, anchor_call, 1898 sizeof(rule->anchor->path)) >= sizeof(rule->anchor->path)) 1899 errx(1, "pfctl_append_rule: strlcpy"); 1900 if ((p = strrchr(anchor_call, '/')) != NULL) { 1901 if (!strlen(p)) 1902 err(1, "pfctl_append_eth_rule: bad anchor name %s", 1903 anchor_call); 1904 } else 1905 p = (char *)anchor_call; 1906 if (strlcpy(r->anchor->name, p, 1907 sizeof(rule->anchor->name)) >= sizeof(rule->anchor->name)) 1908 errx(1, "pfctl_append_eth_rule: strlcpy"); 1909 } 1910 1911 if ((rule = calloc(1, sizeof(*rule))) == NULL) 1912 err(1, "calloc"); 1913 bcopy(r, rule, sizeof(*rule)); 1914 1915 TAILQ_INSERT_TAIL(&rs->rules, rule, entries); 1916 return (0); 1917 } 1918 1919 int 1920 pfctl_eth_ruleset_trans(struct pfctl *pf, char *path, 1921 struct pfctl_eth_anchor *a) 1922 { 1923 int osize = pf->trans->pfrb_size; 1924 1925 if ((pf->loadopt & PFCTL_FLAG_ETH) != 0) { 1926 if (pfctl_add_trans(pf->trans, PF_RULESET_ETH, path)) 1927 return (1); 1928 } 1929 if (pfctl_trans(pf->dev, pf->trans, DIOCXBEGIN, osize)) 1930 return (5); 1931 1932 return (0); 1933 } 1934 1935 int 1936 pfctl_ruleset_trans(struct pfctl *pf, char *path, struct pfctl_anchor *a, bool do_eth) 1937 { 1938 int osize = pf->trans->pfrb_size; 1939 1940 if ((pf->loadopt & PFCTL_FLAG_ETH) != 0 && do_eth) { 1941 if (pfctl_add_trans(pf->trans, PF_RULESET_ETH, path)) 1942 return (1); 1943 } 1944 if ((pf->loadopt & PFCTL_FLAG_NAT) != 0) { 1945 if (pfctl_add_trans(pf->trans, PF_RULESET_NAT, path) || 1946 pfctl_add_trans(pf->trans, PF_RULESET_BINAT, path) || 1947 pfctl_add_trans(pf->trans, PF_RULESET_RDR, path)) 1948 return (1); 1949 } 1950 if (a == pf->astack[0] && ((altqsupport && 1951 (pf->loadopt & PFCTL_FLAG_ALTQ) != 0))) { 1952 if (pfctl_add_trans(pf->trans, PF_RULESET_ALTQ, path)) 1953 return (2); 1954 } 1955 if ((pf->loadopt & PFCTL_FLAG_FILTER) != 0) { 1956 if (pfctl_add_trans(pf->trans, PF_RULESET_SCRUB, path) || 1957 pfctl_add_trans(pf->trans, PF_RULESET_FILTER, path)) 1958 return (3); 1959 } 1960 if (pf->loadopt & PFCTL_FLAG_TABLE) 1961 if (pfctl_add_trans(pf->trans, PF_RULESET_TABLE, path)) 1962 return (4); 1963 if (pfctl_trans(pf->dev, pf->trans, DIOCXBEGIN, osize)) 1964 return (5); 1965 1966 return (0); 1967 } 1968 1969 int 1970 pfctl_load_eth_ruleset(struct pfctl *pf, char *path, 1971 struct pfctl_eth_ruleset *rs, int depth) 1972 { 1973 struct pfctl_eth_rule *r; 1974 int error, len = strlen(path); 1975 int brace = 0; 1976 1977 pf->eanchor = rs->anchor; 1978 if (path[0]) 1979 snprintf(&path[len], MAXPATHLEN - len, "/%s", pf->eanchor->name); 1980 else 1981 snprintf(&path[len], MAXPATHLEN - len, "%s", pf->eanchor->name); 1982 1983 if (depth) { 1984 if (TAILQ_FIRST(&rs->rules) != NULL) { 1985 brace++; 1986 if (pf->opts & PF_OPT_VERBOSE) 1987 printf(" {\n"); 1988 if ((pf->opts & PF_OPT_NOACTION) == 0 && 1989 (error = pfctl_eth_ruleset_trans(pf, 1990 path, rs->anchor))) { 1991 printf("pfctl_load_eth_rulesets: " 1992 "pfctl_eth_ruleset_trans %d\n", error); 1993 goto error; 1994 } 1995 } else if (pf->opts & PF_OPT_VERBOSE) 1996 printf("\n"); 1997 } 1998 1999 while ((r = TAILQ_FIRST(&rs->rules)) != NULL) { 2000 TAILQ_REMOVE(&rs->rules, r, entries); 2001 2002 error = pfctl_load_eth_rule(pf, path, r, depth); 2003 if (error) 2004 return (error); 2005 2006 if (r->anchor) { 2007 if ((error = pfctl_load_eth_ruleset(pf, path, 2008 &r->anchor->ruleset, depth + 1))) 2009 return (error); 2010 } else if (pf->opts & PF_OPT_VERBOSE) 2011 printf("\n"); 2012 free(r); 2013 } 2014 if (brace && pf->opts & PF_OPT_VERBOSE) { 2015 INDENT(depth - 1, (pf->opts & PF_OPT_VERBOSE)); 2016 printf("}\n"); 2017 } 2018 path[len] = '\0'; 2019 2020 return (0); 2021 error: 2022 path[len] = '\0'; 2023 return (error); 2024 } 2025 2026 int 2027 pfctl_load_eth_rule(struct pfctl *pf, char *path, struct pfctl_eth_rule *r, 2028 int depth) 2029 { 2030 char *name; 2031 char anchor[PF_ANCHOR_NAME_SIZE]; 2032 int len = strlen(path); 2033 int ret; 2034 2035 if (strlcpy(anchor, path, sizeof(anchor)) >= sizeof(anchor)) 2036 errx(1, "pfctl_load_eth_rule: strlcpy"); 2037 2038 if (r->anchor) { 2039 if (r->anchor->match) { 2040 if (path[0]) 2041 snprintf(&path[len], MAXPATHLEN - len, 2042 "/%s", r->anchor->name); 2043 else 2044 snprintf(&path[len], MAXPATHLEN - len, 2045 "%s", r->anchor->name); 2046 name = r->anchor->name; 2047 } else 2048 name = r->anchor->path; 2049 } else 2050 name = ""; 2051 2052 if ((pf->opts & PF_OPT_NOACTION) == 0) 2053 if ((ret = pfctl_add_eth_rule(pf->dev, r, anchor, name, 2054 pf->eth_ticket)) != 0) 2055 errc(1, ret, "DIOCADDETHRULENV"); 2056 2057 if (pf->opts & PF_OPT_VERBOSE) { 2058 INDENT(depth, !(pf->opts & PF_OPT_VERBOSE2)); 2059 print_eth_rule(r, r->anchor ? r->anchor->name : "", 2060 pf->opts & (PF_OPT_VERBOSE2 | PF_OPT_DEBUG)); 2061 } 2062 2063 path[len] = '\0'; 2064 2065 return (0); 2066 } 2067 2068 int 2069 pfctl_load_ruleset(struct pfctl *pf, char *path, struct pfctl_ruleset *rs, 2070 int rs_num, int depth) 2071 { 2072 struct pfctl_rule *r; 2073 int error, len = strlen(path); 2074 int brace = 0; 2075 2076 pf->anchor = rs->anchor; 2077 2078 if (path[0]) 2079 snprintf(&path[len], MAXPATHLEN - len, "/%s", pf->anchor->name); 2080 else 2081 snprintf(&path[len], MAXPATHLEN - len, "%s", pf->anchor->name); 2082 2083 if (depth) { 2084 if (TAILQ_FIRST(rs->rules[rs_num].active.ptr) != NULL) { 2085 brace++; 2086 if (pf->opts & PF_OPT_VERBOSE) 2087 printf(" {\n"); 2088 if ((pf->opts & PF_OPT_NOACTION) == 0 && 2089 (error = pfctl_ruleset_trans(pf, 2090 path, rs->anchor, false))) { 2091 printf("%s: " 2092 "pfctl_ruleset_trans %d\n", __func__, error); 2093 goto error; 2094 } 2095 } else if (pf->opts & PF_OPT_VERBOSE) 2096 printf("\n"); 2097 } 2098 2099 if (pf->optimize && rs_num == PF_RULESET_FILTER) 2100 pfctl_optimize_ruleset(pf, rs); 2101 2102 while ((r = TAILQ_FIRST(rs->rules[rs_num].active.ptr)) != NULL) { 2103 TAILQ_REMOVE(rs->rules[rs_num].active.ptr, r, entries); 2104 2105 for (int i = 0; i < PF_RULE_MAX_LABEL_COUNT; i++) 2106 expand_label(r->label[i], PF_RULE_LABEL_SIZE, r); 2107 expand_label(r->tagname, PF_TAG_NAME_SIZE, r); 2108 expand_label(r->match_tagname, PF_TAG_NAME_SIZE, r); 2109 2110 if ((error = pfctl_load_rule(pf, path, r, depth))) 2111 goto error; 2112 if (r->anchor) { 2113 if ((error = pfctl_load_ruleset(pf, path, 2114 &r->anchor->ruleset, rs_num, depth + 1))) 2115 goto error; 2116 } else if (pf->opts & PF_OPT_VERBOSE) 2117 printf("\n"); 2118 free(r); 2119 } 2120 if (brace && pf->opts & PF_OPT_VERBOSE) { 2121 INDENT(depth - 1, (pf->opts & PF_OPT_VERBOSE)); 2122 printf("}\n"); 2123 } 2124 path[len] = '\0'; 2125 return (0); 2126 2127 error: 2128 path[len] = '\0'; 2129 return (error); 2130 2131 } 2132 2133 int 2134 pfctl_load_rule(struct pfctl *pf, char *path, struct pfctl_rule *r, int depth) 2135 { 2136 u_int8_t rs_num = pf_get_ruleset_number(r->action); 2137 char *name; 2138 u_int32_t ticket; 2139 char anchor[PF_ANCHOR_NAME_SIZE]; 2140 int len = strlen(path); 2141 int error; 2142 bool was_present; 2143 2144 /* set up anchor before adding to path for anchor_call */ 2145 if ((pf->opts & PF_OPT_NOACTION) == 0) 2146 ticket = pfctl_get_ticket(pf->trans, rs_num, path); 2147 if (strlcpy(anchor, path, sizeof(anchor)) >= sizeof(anchor)) 2148 errx(1, "pfctl_load_rule: strlcpy"); 2149 2150 if (r->anchor) { 2151 if (r->anchor->match) { 2152 if (path[0]) 2153 snprintf(&path[len], MAXPATHLEN - len, 2154 "/%s", r->anchor->name); 2155 else 2156 snprintf(&path[len], MAXPATHLEN - len, 2157 "%s", r->anchor->name); 2158 name = r->anchor->name; 2159 } else 2160 name = r->anchor->path; 2161 } else 2162 name = ""; 2163 2164 was_present = false; 2165 if ((pf->opts & PF_OPT_NOACTION) == 0) { 2166 if ((pf->opts & PF_OPT_NOACTION) == 0) { 2167 if ((error = pfctl_begin_addrs(pf->h, 2168 &pf->paddr.ticket)) != 0) 2169 errc(1, error, "DIOCBEGINADDRS"); 2170 } 2171 2172 if (pfctl_add_pool(pf, &r->rdr, PF_RDR)) 2173 return (1); 2174 if (pfctl_add_pool(pf, &r->nat, PF_NAT)) 2175 return (1); 2176 if (pfctl_add_pool(pf, &r->route, PF_RT)) 2177 return (1); 2178 error = pfctl_add_rule_h(pf->h, r, anchor, name, ticket, 2179 pf->paddr.ticket); 2180 switch (error) { 2181 case 0: 2182 /* things worked, do nothing */ 2183 break; 2184 case EEXIST: 2185 /* an identical rule is already present */ 2186 was_present = true; 2187 break; 2188 default: 2189 errc(1, error, "DIOCADDRULE"); 2190 } 2191 } 2192 2193 if (pf->opts & PF_OPT_VERBOSE) { 2194 INDENT(depth, !(pf->opts & PF_OPT_VERBOSE2)); 2195 print_rule(r, name, 2196 pf->opts & PF_OPT_VERBOSE2, 2197 pf->opts & PF_OPT_NUMERIC); 2198 if (was_present) 2199 printf(" -- rule was already present"); 2200 } 2201 path[len] = '\0'; 2202 pfctl_clear_pool(&r->rdr); 2203 pfctl_clear_pool(&r->nat); 2204 return (0); 2205 } 2206 2207 int 2208 pfctl_add_altq(struct pfctl *pf, struct pf_altq *a) 2209 { 2210 if (altqsupport && 2211 (loadopt & PFCTL_FLAG_ALTQ) != 0) { 2212 memcpy(&pf->paltq->altq, a, sizeof(struct pf_altq)); 2213 if ((pf->opts & PF_OPT_NOACTION) == 0) { 2214 if (ioctl(pf->dev, DIOCADDALTQ, pf->paltq)) { 2215 if (errno == ENXIO) 2216 errx(1, "qtype not configured"); 2217 else if (errno == ENODEV) 2218 errx(1, "%s: driver does not support " 2219 "altq", a->ifname); 2220 else 2221 err(1, "DIOCADDALTQ"); 2222 } 2223 } 2224 pfaltq_store(&pf->paltq->altq); 2225 } 2226 return (0); 2227 } 2228 2229 int 2230 pfctl_rules(int dev, char *filename, int opts, int optimize, 2231 char *anchorname, struct pfr_buffer *trans) 2232 { 2233 #define ERR(...) do { warn(__VA_ARGS__); goto _error; } while(0) 2234 #define ERRX(...) do { warnx(__VA_ARGS__); goto _error; } while(0) 2235 2236 struct pfr_buffer *t, buf; 2237 struct pfioc_altq pa; 2238 struct pfctl pf; 2239 struct pfctl_ruleset *rs; 2240 struct pfctl_eth_ruleset *ethrs; 2241 struct pfr_table trs; 2242 char *path = NULL; 2243 int osize; 2244 2245 RB_INIT(&pf_anchors); 2246 memset(&pf_main_anchor, 0, sizeof(pf_main_anchor)); 2247 pf_init_ruleset(&pf_main_anchor.ruleset); 2248 pf_main_anchor.ruleset.anchor = &pf_main_anchor; 2249 2250 memset(&pf_eth_main_anchor, 0, sizeof(pf_eth_main_anchor)); 2251 pf_init_eth_ruleset(&pf_eth_main_anchor.ruleset); 2252 pf_eth_main_anchor.ruleset.anchor = &pf_eth_main_anchor; 2253 2254 if (trans == NULL) { 2255 bzero(&buf, sizeof(buf)); 2256 buf.pfrb_type = PFRB_TRANS; 2257 t = &buf; 2258 osize = 0; 2259 } else { 2260 t = trans; 2261 osize = t->pfrb_size; 2262 } 2263 2264 memset(&pa, 0, sizeof(pa)); 2265 pa.version = PFIOC_ALTQ_VERSION; 2266 memset(&pf, 0, sizeof(pf)); 2267 memset(&trs, 0, sizeof(trs)); 2268 if ((path = calloc(1, MAXPATHLEN)) == NULL) 2269 ERRX("%s: calloc", __func__); 2270 if (strlcpy(trs.pfrt_anchor, anchorname, 2271 sizeof(trs.pfrt_anchor)) >= sizeof(trs.pfrt_anchor)) 2272 ERRX("%s: strlcpy", __func__); 2273 pf.dev = dev; 2274 pf.h = pfh; 2275 pf.opts = opts; 2276 pf.optimize = optimize; 2277 pf.loadopt = loadopt; 2278 2279 /* non-brace anchor, create without resolving the path */ 2280 if ((pf.anchor = calloc(1, sizeof(*pf.anchor))) == NULL) 2281 ERRX("%s: calloc", __func__); 2282 rs = &pf.anchor->ruleset; 2283 pf_init_ruleset(rs); 2284 rs->anchor = pf.anchor; 2285 if (strlcpy(pf.anchor->path, anchorname, 2286 sizeof(pf.anchor->path)) >= sizeof(pf.anchor->path)) 2287 errx(1, "%s: strlcpy", __func__); 2288 if (strlcpy(pf.anchor->name, anchorname, 2289 sizeof(pf.anchor->name)) >= sizeof(pf.anchor->name)) 2290 errx(1, "%s: strlcpy", __func__); 2291 2292 2293 pf.astack[0] = pf.anchor; 2294 pf.asd = 0; 2295 if (anchorname[0]) 2296 pf.loadopt &= ~PFCTL_FLAG_ALTQ; 2297 pf.paltq = &pa; 2298 pf.trans = t; 2299 pfctl_init_options(&pf); 2300 2301 /* Set up ethernet anchor */ 2302 if ((pf.eanchor = calloc(1, sizeof(*pf.eanchor))) == NULL) 2303 ERRX("%s: calloc", __func__); 2304 2305 if (strlcpy(pf.eanchor->path, anchorname, 2306 sizeof(pf.eanchor->path)) >= sizeof(pf.eanchor->path)) 2307 errx(1, "%s: strlcpy", __func__); 2308 if (strlcpy(pf.eanchor->name, anchorname, 2309 sizeof(pf.eanchor->name)) >= sizeof(pf.eanchor->name)) 2310 errx(1, "%s: strlcpy", __func__); 2311 2312 ethrs = &pf.eanchor->ruleset; 2313 pf_init_eth_ruleset(ethrs); 2314 ethrs->anchor = pf.eanchor; 2315 pf.eastack[0] = pf.eanchor; 2316 2317 if ((opts & PF_OPT_NOACTION) == 0) { 2318 /* 2319 * XXX For the time being we need to open transactions for 2320 * the main ruleset before parsing, because tables are still 2321 * loaded at parse time. 2322 */ 2323 if (pfctl_ruleset_trans(&pf, anchorname, pf.anchor, true)) 2324 ERRX("%s", __func__); 2325 if (pf.loadopt & PFCTL_FLAG_ETH) 2326 pf.eth_ticket = pfctl_get_ticket(t, PF_RULESET_ETH, anchorname); 2327 if (altqsupport && (pf.loadopt & PFCTL_FLAG_ALTQ)) 2328 pa.ticket = 2329 pfctl_get_ticket(t, PF_RULESET_ALTQ, anchorname); 2330 if (pf.loadopt & PFCTL_FLAG_TABLE) 2331 pf.astack[0]->ruleset.tticket = 2332 pfctl_get_ticket(t, PF_RULESET_TABLE, anchorname); 2333 } 2334 2335 if (parse_config(filename, &pf) < 0) { 2336 if ((opts & PF_OPT_NOACTION) == 0) 2337 ERRX("Syntax error in config file: " 2338 "pf rules not loaded"); 2339 else 2340 goto _error; 2341 } 2342 if (loadopt & PFCTL_FLAG_OPTION) 2343 pfctl_adjust_skip_ifaces(&pf); 2344 2345 if ((pf.loadopt & PFCTL_FLAG_FILTER && 2346 (pfctl_load_ruleset(&pf, path, rs, PF_RULESET_SCRUB, 0))) || 2347 (pf.loadopt & PFCTL_FLAG_ETH && 2348 (pfctl_load_eth_ruleset(&pf, path, ethrs, 0))) || 2349 (pf.loadopt & PFCTL_FLAG_NAT && 2350 (pfctl_load_ruleset(&pf, path, rs, PF_RULESET_NAT, 0) || 2351 pfctl_load_ruleset(&pf, path, rs, PF_RULESET_RDR, 0) || 2352 pfctl_load_ruleset(&pf, path, rs, PF_RULESET_BINAT, 0))) || 2353 (pf.loadopt & PFCTL_FLAG_FILTER && 2354 pfctl_load_ruleset(&pf, path, rs, PF_RULESET_FILTER, 0))) { 2355 if ((opts & PF_OPT_NOACTION) == 0) 2356 ERRX("Unable to load rules into kernel"); 2357 else 2358 goto _error; 2359 } 2360 2361 if ((altqsupport && (pf.loadopt & PFCTL_FLAG_ALTQ) != 0)) 2362 if (check_commit_altq(dev, opts) != 0) 2363 ERRX("errors in altq config"); 2364 2365 if (trans == NULL) { 2366 /* process "load anchor" directives */ 2367 if (pfctl_load_anchors(dev, &pf, t) == -1) 2368 ERRX("load anchors"); 2369 2370 if ((opts & PF_OPT_NOACTION) == 0) { 2371 if (!anchorname[0] && pfctl_load_options(&pf)) 2372 goto _error; 2373 if (pfctl_trans(dev, t, DIOCXCOMMIT, osize)) 2374 ERR("DIOCXCOMMIT"); 2375 } 2376 } 2377 free(path); 2378 return (0); 2379 2380 _error: 2381 if (trans == NULL) { /* main ruleset */ 2382 if ((opts & PF_OPT_NOACTION) == 0) 2383 if (pfctl_trans(dev, t, DIOCXROLLBACK, osize)) 2384 err(1, "DIOCXROLLBACK"); 2385 exit(1); 2386 } else { /* sub ruleset */ 2387 free(path); 2388 return (-1); 2389 } 2390 2391 #undef ERR 2392 #undef ERRX 2393 } 2394 2395 FILE * 2396 pfctl_fopen(const char *name, const char *mode) 2397 { 2398 struct stat st; 2399 FILE *fp; 2400 2401 fp = fopen(name, mode); 2402 if (fp == NULL) 2403 return (NULL); 2404 if (fstat(fileno(fp), &st)) { 2405 fclose(fp); 2406 return (NULL); 2407 } 2408 if (S_ISDIR(st.st_mode)) { 2409 fclose(fp); 2410 errno = EISDIR; 2411 return (NULL); 2412 } 2413 return (fp); 2414 } 2415 2416 void 2417 pfctl_init_options(struct pfctl *pf) 2418 { 2419 2420 pf->timeout[PFTM_TCP_FIRST_PACKET] = PFTM_TCP_FIRST_PACKET_VAL; 2421 pf->timeout[PFTM_TCP_OPENING] = PFTM_TCP_OPENING_VAL; 2422 pf->timeout[PFTM_TCP_ESTABLISHED] = PFTM_TCP_ESTABLISHED_VAL; 2423 pf->timeout[PFTM_TCP_CLOSING] = PFTM_TCP_CLOSING_VAL; 2424 pf->timeout[PFTM_TCP_FIN_WAIT] = PFTM_TCP_FIN_WAIT_VAL; 2425 pf->timeout[PFTM_TCP_CLOSED] = PFTM_TCP_CLOSED_VAL; 2426 pf->timeout[PFTM_SCTP_FIRST_PACKET] = PFTM_TCP_FIRST_PACKET_VAL; 2427 pf->timeout[PFTM_SCTP_OPENING] = PFTM_TCP_OPENING_VAL; 2428 pf->timeout[PFTM_SCTP_ESTABLISHED] = PFTM_TCP_ESTABLISHED_VAL; 2429 pf->timeout[PFTM_SCTP_CLOSING] = PFTM_TCP_CLOSING_VAL; 2430 pf->timeout[PFTM_SCTP_CLOSED] = PFTM_TCP_CLOSED_VAL; 2431 pf->timeout[PFTM_UDP_FIRST_PACKET] = PFTM_UDP_FIRST_PACKET_VAL; 2432 pf->timeout[PFTM_UDP_SINGLE] = PFTM_UDP_SINGLE_VAL; 2433 pf->timeout[PFTM_UDP_MULTIPLE] = PFTM_UDP_MULTIPLE_VAL; 2434 pf->timeout[PFTM_ICMP_FIRST_PACKET] = PFTM_ICMP_FIRST_PACKET_VAL; 2435 pf->timeout[PFTM_ICMP_ERROR_REPLY] = PFTM_ICMP_ERROR_REPLY_VAL; 2436 pf->timeout[PFTM_OTHER_FIRST_PACKET] = PFTM_OTHER_FIRST_PACKET_VAL; 2437 pf->timeout[PFTM_OTHER_SINGLE] = PFTM_OTHER_SINGLE_VAL; 2438 pf->timeout[PFTM_OTHER_MULTIPLE] = PFTM_OTHER_MULTIPLE_VAL; 2439 pf->timeout[PFTM_FRAG] = PFTM_FRAG_VAL; 2440 pf->timeout[PFTM_INTERVAL] = PFTM_INTERVAL_VAL; 2441 pf->timeout[PFTM_SRC_NODE] = PFTM_SRC_NODE_VAL; 2442 pf->timeout[PFTM_TS_DIFF] = PFTM_TS_DIFF_VAL; 2443 pf->timeout[PFTM_ADAPTIVE_START] = PFSTATE_ADAPT_START; 2444 pf->timeout[PFTM_ADAPTIVE_END] = PFSTATE_ADAPT_END; 2445 2446 pf->limit[PF_LIMIT_STATES] = PFSTATE_HIWAT; 2447 pf->limit[PF_LIMIT_FRAGS] = PFFRAG_FRENT_HIWAT; 2448 pf->limit[PF_LIMIT_SRC_NODES] = PFSNODE_HIWAT; 2449 pf->limit[PF_LIMIT_TABLE_ENTRIES] = PFR_KENTRY_HIWAT; 2450 2451 pf->debug = PF_DEBUG_URGENT; 2452 pf->reassemble = 0; 2453 2454 pf->syncookies = false; 2455 pf->syncookieswat[0] = PF_SYNCOOKIES_LOWATPCT; 2456 pf->syncookieswat[1] = PF_SYNCOOKIES_HIWATPCT; 2457 } 2458 2459 int 2460 pfctl_load_options(struct pfctl *pf) 2461 { 2462 int i, error = 0; 2463 2464 if ((loadopt & PFCTL_FLAG_OPTION) == 0) 2465 return (0); 2466 2467 /* load limits */ 2468 for (i = 0; i < PF_LIMIT_MAX; i++) { 2469 if ((pf->opts & PF_OPT_MERGE) && !pf->limit_set[i]) 2470 continue; 2471 if (pfctl_load_limit(pf, i, pf->limit[i])) 2472 error = 1; 2473 } 2474 2475 /* 2476 * If we've set the states limit, but haven't explicitly set adaptive 2477 * timeouts, do it now with a start of 60% and end of 120%. 2478 */ 2479 if (pf->limit_set[PF_LIMIT_STATES] && 2480 !pf->timeout_set[PFTM_ADAPTIVE_START] && 2481 !pf->timeout_set[PFTM_ADAPTIVE_END]) { 2482 pf->timeout[PFTM_ADAPTIVE_START] = 2483 (pf->limit[PF_LIMIT_STATES] / 10) * 6; 2484 pf->timeout_set[PFTM_ADAPTIVE_START] = 1; 2485 pf->timeout[PFTM_ADAPTIVE_END] = 2486 (pf->limit[PF_LIMIT_STATES] / 10) * 12; 2487 pf->timeout_set[PFTM_ADAPTIVE_END] = 1; 2488 } 2489 2490 /* load timeouts */ 2491 for (i = 0; i < PFTM_MAX; i++) { 2492 if ((pf->opts & PF_OPT_MERGE) && !pf->timeout_set[i]) 2493 continue; 2494 if (pfctl_load_timeout(pf, i, pf->timeout[i])) 2495 error = 1; 2496 } 2497 2498 /* load debug */ 2499 if (!(pf->opts & PF_OPT_MERGE) || pf->debug_set) 2500 if (pfctl_load_debug(pf, pf->debug)) 2501 error = 1; 2502 2503 /* load logif */ 2504 if (!(pf->opts & PF_OPT_MERGE) || pf->ifname_set) 2505 if (pfctl_load_logif(pf, pf->ifname)) 2506 error = 1; 2507 2508 /* load hostid */ 2509 if (!(pf->opts & PF_OPT_MERGE) || pf->hostid_set) 2510 if (pfctl_load_hostid(pf, pf->hostid)) 2511 error = 1; 2512 2513 /* load reassembly settings */ 2514 if (!(pf->opts & PF_OPT_MERGE) || pf->reass_set) 2515 if (pfctl_load_reassembly(pf, pf->reassemble)) 2516 error = 1; 2517 2518 /* load keepcounters */ 2519 if (pfctl_set_keepcounters(pf->dev, pf->keep_counters)) 2520 error = 1; 2521 2522 /* load syncookies settings */ 2523 if (pfctl_load_syncookies(pf, pf->syncookies)) 2524 error = 1; 2525 2526 return (error); 2527 } 2528 2529 int 2530 pfctl_apply_limit(struct pfctl *pf, const char *opt, unsigned int limit) 2531 { 2532 int i; 2533 2534 2535 for (i = 0; pf_limits[i].name; i++) { 2536 if (strcasecmp(opt, pf_limits[i].name) == 0) { 2537 pf->limit[pf_limits[i].index] = limit; 2538 pf->limit_set[pf_limits[i].index] = 1; 2539 break; 2540 } 2541 } 2542 if (pf_limits[i].name == NULL) { 2543 warnx("Bad pool name."); 2544 return (1); 2545 } 2546 2547 if (pf->opts & PF_OPT_VERBOSE) 2548 printf("set limit %s %d\n", opt, limit); 2549 2550 return (0); 2551 } 2552 2553 int 2554 pfctl_load_limit(struct pfctl *pf, unsigned int index, unsigned int limit) 2555 { 2556 if (pfctl_set_limit(pf->h, index, limit)) { 2557 if (errno == EBUSY) 2558 warnx("Current pool size exceeds requested %s limit %u", 2559 pf_limits[index].name, limit); 2560 else 2561 warnx("Cannot set %s limit to %u", 2562 pf_limits[index].name, limit); 2563 return (1); 2564 } 2565 return (0); 2566 } 2567 2568 int 2569 pfctl_apply_timeout(struct pfctl *pf, const char *opt, int seconds, int quiet) 2570 { 2571 int i; 2572 2573 if ((loadopt & PFCTL_FLAG_OPTION) == 0) 2574 return (0); 2575 2576 for (i = 0; pf_timeouts[i].name; i++) { 2577 if (strcasecmp(opt, pf_timeouts[i].name) == 0) { 2578 pf->timeout[pf_timeouts[i].timeout] = seconds; 2579 pf->timeout_set[pf_timeouts[i].timeout] = 1; 2580 break; 2581 } 2582 } 2583 2584 if (pf_timeouts[i].name == NULL) { 2585 warnx("Bad timeout name."); 2586 return (1); 2587 } 2588 2589 2590 if (pf->opts & PF_OPT_VERBOSE && ! quiet) 2591 printf("set timeout %s %d\n", opt, seconds); 2592 2593 return (0); 2594 } 2595 2596 int 2597 pfctl_load_timeout(struct pfctl *pf, unsigned int timeout, unsigned int seconds) 2598 { 2599 if (pfctl_set_timeout(pf->h, timeout, seconds)) { 2600 warnx("DIOCSETTIMEOUT"); 2601 return (1); 2602 } 2603 return (0); 2604 } 2605 2606 int 2607 pfctl_set_reassembly(struct pfctl *pf, int on, int nodf) 2608 { 2609 if ((loadopt & PFCTL_FLAG_OPTION) == 0) 2610 return (0); 2611 2612 pf->reass_set = 1; 2613 if (on) { 2614 pf->reassemble = PF_REASS_ENABLED; 2615 if (nodf) 2616 pf->reassemble |= PF_REASS_NODF; 2617 } else { 2618 pf->reassemble = 0; 2619 } 2620 2621 if (pf->opts & PF_OPT_VERBOSE) 2622 printf("set reassemble %s %s\n", on ? "yes" : "no", 2623 nodf ? "no-df" : ""); 2624 2625 return (0); 2626 } 2627 2628 int 2629 pfctl_set_optimization(struct pfctl *pf, const char *opt) 2630 { 2631 const struct pf_hint *hint; 2632 int i, r; 2633 2634 if ((loadopt & PFCTL_FLAG_OPTION) == 0) 2635 return (0); 2636 2637 for (i = 0; pf_hints[i].name; i++) 2638 if (strcasecmp(opt, pf_hints[i].name) == 0) 2639 break; 2640 2641 hint = pf_hints[i].hint; 2642 if (hint == NULL) { 2643 warnx("invalid state timeouts optimization"); 2644 return (1); 2645 } 2646 2647 for (i = 0; hint[i].name; i++) 2648 if ((r = pfctl_apply_timeout(pf, hint[i].name, 2649 hint[i].timeout, 1))) 2650 return (r); 2651 2652 if (pf->opts & PF_OPT_VERBOSE) 2653 printf("set optimization %s\n", opt); 2654 2655 return (0); 2656 } 2657 2658 int 2659 pfctl_set_logif(struct pfctl *pf, char *ifname) 2660 { 2661 2662 if ((loadopt & PFCTL_FLAG_OPTION) == 0) 2663 return (0); 2664 2665 if (!strcmp(ifname, "none")) { 2666 free(pf->ifname); 2667 pf->ifname = NULL; 2668 } else { 2669 pf->ifname = strdup(ifname); 2670 if (!pf->ifname) 2671 errx(1, "pfctl_set_logif: strdup"); 2672 } 2673 pf->ifname_set = 1; 2674 2675 if (pf->opts & PF_OPT_VERBOSE) 2676 printf("set loginterface %s\n", ifname); 2677 2678 return (0); 2679 } 2680 2681 int 2682 pfctl_load_logif(struct pfctl *pf, char *ifname) 2683 { 2684 if (ifname != NULL && strlen(ifname) >= IFNAMSIZ) { 2685 warnx("pfctl_load_logif: strlcpy"); 2686 return (1); 2687 } 2688 return (pfctl_set_statusif(pfh, ifname ? ifname : "")); 2689 } 2690 2691 void 2692 pfctl_set_hostid(struct pfctl *pf, u_int32_t hostid) 2693 { 2694 if ((loadopt & PFCTL_FLAG_OPTION) == 0) 2695 return; 2696 2697 HTONL(hostid); 2698 2699 pf->hostid = hostid; 2700 pf->hostid_set = 1; 2701 2702 if (pf->opts & PF_OPT_VERBOSE) 2703 printf("set hostid 0x%08x\n", ntohl(hostid)); 2704 } 2705 2706 int 2707 pfctl_load_hostid(struct pfctl *pf, u_int32_t hostid) 2708 { 2709 if (ioctl(dev, DIOCSETHOSTID, &hostid)) { 2710 warnx("DIOCSETHOSTID"); 2711 return (1); 2712 } 2713 return (0); 2714 } 2715 2716 int 2717 pfctl_load_reassembly(struct pfctl *pf, u_int32_t reassembly) 2718 { 2719 if (ioctl(dev, DIOCSETREASS, &reassembly)) { 2720 warnx("DIOCSETREASS"); 2721 return (1); 2722 } 2723 return (0); 2724 } 2725 2726 int 2727 pfctl_load_syncookies(struct pfctl *pf, u_int8_t val) 2728 { 2729 struct pfctl_syncookies cookies; 2730 2731 bzero(&cookies, sizeof(cookies)); 2732 2733 cookies.mode = val; 2734 cookies.lowwater = pf->syncookieswat[0]; 2735 cookies.highwater = pf->syncookieswat[1]; 2736 2737 if (pfctl_set_syncookies(dev, &cookies)) { 2738 warnx("DIOCSETSYNCOOKIES"); 2739 return (1); 2740 } 2741 return (0); 2742 } 2743 2744 int 2745 pfctl_cfg_syncookies(struct pfctl *pf, uint8_t val, struct pfctl_watermarks *w) 2746 { 2747 if (val != PF_SYNCOOKIES_ADAPTIVE && w != NULL) { 2748 warnx("syncookies start/end only apply to adaptive"); 2749 return (1); 2750 } 2751 if (val == PF_SYNCOOKIES_ADAPTIVE && w != NULL) { 2752 if (!w->hi) 2753 w->hi = PF_SYNCOOKIES_HIWATPCT; 2754 if (!w->lo) 2755 w->lo = w->hi / 2; 2756 if (w->lo >= w->hi) { 2757 warnx("start must be higher than end"); 2758 return (1); 2759 } 2760 pf->syncookieswat[0] = w->lo; 2761 pf->syncookieswat[1] = w->hi; 2762 pf->syncookieswat_set = 1; 2763 } 2764 2765 if (pf->opts & PF_OPT_VERBOSE) { 2766 if (val == PF_SYNCOOKIES_NEVER) 2767 printf("set syncookies never\n"); 2768 else if (val == PF_SYNCOOKIES_ALWAYS) 2769 printf("set syncookies always\n"); 2770 else if (val == PF_SYNCOOKIES_ADAPTIVE) { 2771 if (pf->syncookieswat_set) 2772 printf("set syncookies adaptive (start %u%%, " 2773 "end %u%%)\n", pf->syncookieswat[1], 2774 pf->syncookieswat[0]); 2775 else 2776 printf("set syncookies adaptive\n"); 2777 } else { /* cannot happen */ 2778 warnx("king bula ate all syncookies"); 2779 return (1); 2780 } 2781 } 2782 2783 pf->syncookies = val; 2784 return (0); 2785 } 2786 2787 int 2788 pfctl_do_set_debug(struct pfctl *pf, char *d) 2789 { 2790 u_int32_t level; 2791 int ret; 2792 2793 if ((loadopt & PFCTL_FLAG_OPTION) == 0) 2794 return (0); 2795 2796 if (!strcmp(d, "none")) 2797 pf->debug = PF_DEBUG_NONE; 2798 else if (!strcmp(d, "urgent")) 2799 pf->debug = PF_DEBUG_URGENT; 2800 else if (!strcmp(d, "misc")) 2801 pf->debug = PF_DEBUG_MISC; 2802 else if (!strcmp(d, "loud")) 2803 pf->debug = PF_DEBUG_NOISY; 2804 else { 2805 warnx("unknown debug level \"%s\"", d); 2806 return (-1); 2807 } 2808 2809 pf->debug_set = 1; 2810 level = pf->debug; 2811 2812 if ((pf->opts & PF_OPT_NOACTION) == 0) 2813 if ((ret = pfctl_set_debug(pfh, level)) != 0) 2814 errc(1, ret, "DIOCSETDEBUG"); 2815 2816 if (pf->opts & PF_OPT_VERBOSE) 2817 printf("set debug %s\n", d); 2818 2819 return (0); 2820 } 2821 2822 int 2823 pfctl_load_debug(struct pfctl *pf, unsigned int level) 2824 { 2825 if (pfctl_set_debug(pf->h, level)) { 2826 warnx("DIOCSETDEBUG"); 2827 return (1); 2828 } 2829 return (0); 2830 } 2831 2832 int 2833 pfctl_set_interface_flags(struct pfctl *pf, char *ifname, int flags, int how) 2834 { 2835 struct pfioc_iface pi; 2836 struct node_host *h = NULL, *n = NULL; 2837 2838 if ((loadopt & PFCTL_FLAG_OPTION) == 0) 2839 return (0); 2840 2841 bzero(&pi, sizeof(pi)); 2842 2843 pi.pfiio_flags = flags; 2844 2845 /* Make sure our cache matches the kernel. If we set or clear the flag 2846 * for a group this applies to all members. */ 2847 h = ifa_grouplookup(ifname, 0); 2848 for (n = h; n != NULL; n = n->next) 2849 pfctl_set_interface_flags(pf, n->ifname, flags, how); 2850 2851 if (strlcpy(pi.pfiio_name, ifname, sizeof(pi.pfiio_name)) >= 2852 sizeof(pi.pfiio_name)) 2853 errx(1, "pfctl_set_interface_flags: strlcpy"); 2854 2855 if ((pf->opts & PF_OPT_NOACTION) == 0) { 2856 if (how == 0) { 2857 if (ioctl(pf->dev, DIOCCLRIFFLAG, &pi)) 2858 pfctl_err(pf->opts, 1, "DIOCCLRIFFLAG"); 2859 } else { 2860 if (ioctl(pf->dev, DIOCSETIFFLAG, &pi)) 2861 err(1, "DIOCSETIFFLAG"); 2862 pfctl_check_skip_ifaces(ifname); 2863 } 2864 } 2865 return (0); 2866 } 2867 2868 void 2869 pfctl_debug(int dev, u_int32_t level, int opts) 2870 { 2871 int ret; 2872 2873 if ((ret = pfctl_set_debug(pfh, level)) != 0) 2874 errc(1, ret, "DIOCSETDEBUG"); 2875 if ((opts & PF_OPT_QUIET) == 0) { 2876 fprintf(stderr, "debug level set to '"); 2877 switch (level) { 2878 case PF_DEBUG_NONE: 2879 fprintf(stderr, "none"); 2880 break; 2881 case PF_DEBUG_URGENT: 2882 fprintf(stderr, "urgent"); 2883 break; 2884 case PF_DEBUG_MISC: 2885 fprintf(stderr, "misc"); 2886 break; 2887 case PF_DEBUG_NOISY: 2888 fprintf(stderr, "loud"); 2889 break; 2890 default: 2891 fprintf(stderr, "<invalid>"); 2892 break; 2893 } 2894 fprintf(stderr, "'\n"); 2895 } 2896 } 2897 2898 int 2899 pfctl_test_altqsupport(int dev, int opts) 2900 { 2901 struct pfioc_altq pa; 2902 2903 pa.version = PFIOC_ALTQ_VERSION; 2904 if (ioctl(dev, DIOCGETALTQS, &pa)) { 2905 if (errno == ENODEV) { 2906 if (opts & PF_OPT_VERBOSE) 2907 fprintf(stderr, "No ALTQ support in kernel\n" 2908 "ALTQ related functions disabled\n"); 2909 return (0); 2910 } else 2911 err(1, "DIOCGETALTQS"); 2912 } 2913 return (1); 2914 } 2915 2916 int 2917 pfctl_walk_show(int opts, struct pfioc_ruleset *pr, void *warg) 2918 { 2919 if (pr->path[0]) { 2920 if (pr->path[0] != '_' || (opts & PF_OPT_VERBOSE)) 2921 printf(" %s/%s\n", pr->path, pr->name); 2922 } else if (pr->name[0] != '_' || (opts & PF_OPT_VERBOSE)) 2923 printf(" %s\n", pr->name); 2924 2925 return (0); 2926 } 2927 2928 int 2929 pfctl_walk_get(int opts, struct pfioc_ruleset *pr, void *warg) 2930 { 2931 struct pfr_anchoritem *pfra; 2932 struct pfr_anchors *anchors; 2933 int e; 2934 2935 anchors = (struct pfr_anchors *)warg; 2936 2937 pfra = malloc(sizeof(*pfra)); 2938 if (pfra == NULL) 2939 err(1, "%s", __func__); 2940 2941 if (pr->path[0]) 2942 e = asprintf(&pfra->pfra_anchorname, "%s/%s", pr->path, 2943 pr->name); 2944 else 2945 e = asprintf(&pfra->pfra_anchorname, "%s", pr->name); 2946 2947 if (e == -1) 2948 err(1, "%s", __func__); 2949 2950 SLIST_INSERT_HEAD(anchors, pfra, pfra_sle); 2951 2952 return (0); 2953 } 2954 2955 int 2956 pfctl_walk_anchors(int dev, int opts, const char *anchor, 2957 int(walkf)(int, struct pfioc_ruleset *, void *), void *warg) 2958 { 2959 struct pfioc_ruleset pr; 2960 u_int32_t mnr, nr; 2961 int ret; 2962 2963 memset(&pr, 0, sizeof(pr)); 2964 if ((ret = pfctl_get_rulesets(pfh, anchor, &mnr)) != 0) 2965 errx(1, "%s", pf_strerror(ret)); 2966 for (nr = 0; nr < mnr; ++nr) { 2967 char sub[MAXPATHLEN]; 2968 2969 if ((ret = pfctl_get_ruleset(pfh, anchor, nr, &pr)) != 0) 2970 errc(1, ret, "DIOCGETRULESET"); 2971 if (!strcmp(pr.name, PF_RESERVED_ANCHOR)) 2972 continue; 2973 sub[0] = '\0'; 2974 if (walkf(opts, &pr, warg)) 2975 return (-1); 2976 2977 if (pr.path[0]) 2978 snprintf(sub, sizeof(sub), "%s/%s", pr.path, pr.name); 2979 else 2980 snprintf(sub, sizeof(sub), "%s", pr.name); 2981 if (pfctl_walk_anchors(dev, opts, sub, walkf, warg)) 2982 return (-1); 2983 } 2984 return (0); 2985 } 2986 2987 int 2988 pfctl_show_anchors(int dev, int opts, char *anchor) 2989 { 2990 return ( 2991 pfctl_walk_anchors(dev, opts, anchor, pfctl_walk_show, NULL)); 2992 } 2993 2994 struct pfr_anchors * 2995 pfctl_get_anchors(int dev, const char *anchor, int opts) 2996 { 2997 struct pfioc_ruleset pr; 2998 static struct pfr_anchors anchors; 2999 char anchorbuf[PATH_MAX]; 3000 char *n; 3001 3002 SLIST_INIT(&anchors); 3003 3004 memset(&pr, 0, sizeof(pr)); 3005 if (*anchor != '\0') { 3006 strlcpy(anchorbuf, anchor, sizeof(anchorbuf)); 3007 n = dirname(anchorbuf); 3008 if (n[0] != '.' && n[1] != '\0') 3009 strlcpy(pr.path, n, sizeof(pr.path)); 3010 strlcpy(anchorbuf, anchor, sizeof(anchorbuf)); 3011 n = basename(anchorbuf); 3012 if (n != NULL) 3013 strlcpy(pr.name, n, sizeof(pr.name)); 3014 } 3015 3016 /* insert a root anchor first. */ 3017 pfctl_walk_get(opts, &pr, &anchors); 3018 3019 if (pfctl_walk_anchors(dev, opts, anchor, pfctl_walk_get, &anchors)) 3020 errx(1, "%s failed to retrieve list of anchors, can't continue", 3021 __func__); 3022 3023 return (&anchors); 3024 } 3025 3026 int 3027 pfctl_call_cleartables(int dev, int opts, struct pfr_anchoritem *pfra) 3028 { 3029 /* 3030 * PF_OPT_QUIET makes pfctl_clear_tables() to stop printing number of 3031 * tables cleared for given anchor. 3032 */ 3033 opts |= PF_OPT_QUIET; 3034 return ((pfctl_do_clear_tables(pfra->pfra_anchorname, opts) == -1) ? 3035 1 : 0); 3036 } 3037 3038 int 3039 pfctl_call_clearrules(int dev, int opts, struct pfr_anchoritem *pfra) 3040 { 3041 /* 3042 * PF_OPT_QUIET makes pfctl_clear_rules() to stop printing a 'rules 3043 * cleared' message for every anchor it deletes. 3044 */ 3045 opts |= PF_OPT_QUIET; 3046 return (pfctl_flush_rules(dev, opts, pfra->pfra_anchorname)); 3047 } 3048 3049 int 3050 pfctl_call_clearanchors(int dev, int opts, struct pfr_anchoritem *pfra) 3051 { 3052 int rv = 0; 3053 3054 rv |= pfctl_call_cleartables(dev, opts, pfra); 3055 rv |= pfctl_call_clearrules(dev, opts, pfra); 3056 3057 return (rv); 3058 } 3059 3060 int 3061 pfctl_call_showtables(int dev, int opts, struct pfr_anchoritem *pfra) 3062 { 3063 pfctl_show_tables(pfra->pfra_anchorname, opts); 3064 return (0); 3065 } 3066 3067 int 3068 pfctl_recurse(int dev, int opts, const char *anchorname, 3069 int(*walkf)(int, int, struct pfr_anchoritem *)) 3070 { 3071 int rv = 0; 3072 struct pfr_anchors *anchors; 3073 struct pfr_anchoritem *pfra, *pfra_save; 3074 3075 anchors = pfctl_get_anchors(dev, anchorname, opts); 3076 /* 3077 * While traversing the list, pfctl_clear_*() must always return 3078 * so that failures on one anchor do not prevent clearing others. 3079 */ 3080 opts |= PF_OPT_IGNFAIL; 3081 if ((opts & PF_OPT_CALLSHOW) == 0) 3082 printf("Removing:\n"); 3083 SLIST_FOREACH_SAFE(pfra, anchors, pfra_sle, pfra_save) { 3084 if ((opts & PF_OPT_CALLSHOW) == 0) 3085 printf(" %s\n", 3086 (*pfra->pfra_anchorname == '\0') ? "/" : 3087 pfra->pfra_anchorname); 3088 rv |= walkf(dev, opts, pfra); 3089 SLIST_REMOVE(anchors, pfra, pfr_anchoritem, pfra_sle); 3090 free(pfra->pfra_anchorname); 3091 free(pfra); 3092 } 3093 3094 return (rv); 3095 } 3096 3097 int 3098 pfctl_show_eth_anchors(int dev, int opts, char *anchorname) 3099 { 3100 struct pfctl_eth_rulesets_info ri; 3101 struct pfctl_eth_ruleset_info rs; 3102 int ret; 3103 3104 if ((ret = pfctl_get_eth_rulesets_info(dev, &ri, anchorname)) != 0) { 3105 if (ret == ENOENT) 3106 fprintf(stderr, "Anchor '%s' not found.\n", 3107 anchorname); 3108 else 3109 errc(1, ret, "DIOCGETETHRULESETS"); 3110 return (-1); 3111 } 3112 3113 for (int nr = 0; nr < ri.nr; nr++) { 3114 char sub[MAXPATHLEN]; 3115 3116 if ((ret = pfctl_get_eth_ruleset(dev, anchorname, nr, &rs)) != 0) 3117 errc(1, ret, "DIOCGETETHRULESET"); 3118 3119 if (!strcmp(rs.name, PF_RESERVED_ANCHOR)) 3120 continue; 3121 sub[0] = 0; 3122 if (rs.path[0]) { 3123 strlcat(sub, rs.path, sizeof(sub)); 3124 strlcat(sub, "/", sizeof(sub)); 3125 } 3126 strlcat(sub, rs.name, sizeof(sub)); 3127 if (sub[0] != '_' || (opts & PF_OPT_VERBOSE)) 3128 printf(" %s\n", sub); 3129 if ((opts & PF_OPT_VERBOSE) && pfctl_show_eth_anchors(dev, opts, sub)) 3130 return (-1); 3131 } 3132 return (0); 3133 } 3134 3135 const char * 3136 pfctl_lookup_option(char *cmd, const char * const *list) 3137 { 3138 if (cmd != NULL && *cmd) 3139 for (; *list; list++) 3140 if (!strncmp(cmd, *list, strlen(cmd))) 3141 return (*list); 3142 return (NULL); 3143 } 3144 3145 void 3146 pfctl_reset(int dev, int opts) 3147 { 3148 struct pfctl pf; 3149 struct pfr_buffer t; 3150 int i; 3151 3152 memset(&pf, 0, sizeof(pf)); 3153 pf.dev = dev; 3154 pf.h = pfh; 3155 pfctl_init_options(&pf); 3156 3157 /* Force reset upon pfctl_load_options() */ 3158 pf.debug_set = 1; 3159 pf.reass_set = 1; 3160 pf.syncookieswat_set = 1; 3161 pf.ifname = strdup("none"); 3162 if (pf.ifname == NULL) 3163 err(1, "%s: strdup", __func__); 3164 pf.ifname_set = 1; 3165 3166 memset(&t, 0, sizeof(t)); 3167 t.pfrb_type = PFRB_TRANS; 3168 if (pfctl_trans(dev, &t, DIOCXBEGIN, 0)) 3169 err(1, "%s: DIOCXBEGIN", __func__); 3170 3171 for (i = 0; pf_limits[i].name; i++) 3172 pf.limit_set[pf_limits[i].index] = 1; 3173 3174 for (i = 0; pf_timeouts[i].name; i++) 3175 pf.timeout_set[pf_timeouts[i].timeout] = 1; 3176 3177 pfctl_load_options(&pf); 3178 3179 if (pfctl_trans(dev, &t, DIOCXCOMMIT, 0)) 3180 err(1, "%s: DIOCXCOMMIT", __func__); 3181 3182 pfctl_clear_interface_flags(dev, opts); 3183 } 3184 3185 int 3186 main(int argc, char *argv[]) 3187 { 3188 int ch; 3189 int mode = O_RDONLY; 3190 int opts = 0; 3191 int optimize = PF_OPTIMIZE_BASIC; 3192 char anchorname[MAXPATHLEN]; 3193 char *path; 3194 3195 if (argc < 2) 3196 usage(); 3197 3198 while ((ch = getopt(argc, argv, 3199 "a:AdD:eqf:F:ghi:k:K:mMnNOo:Pp:rRs:St:T:vx:z")) != -1) { 3200 switch (ch) { 3201 case 'a': 3202 anchoropt = optarg; 3203 break; 3204 case 'd': 3205 opts |= PF_OPT_DISABLE; 3206 mode = O_RDWR; 3207 break; 3208 case 'D': 3209 if (pfctl_cmdline_symset(optarg) < 0) 3210 warnx("could not parse macro definition %s", 3211 optarg); 3212 break; 3213 case 'e': 3214 opts |= PF_OPT_ENABLE; 3215 mode = O_RDWR; 3216 break; 3217 case 'q': 3218 opts |= PF_OPT_QUIET; 3219 break; 3220 case 'F': 3221 clearopt = pfctl_lookup_option(optarg, clearopt_list); 3222 if (clearopt == NULL) { 3223 warnx("Unknown flush modifier '%s'", optarg); 3224 usage(); 3225 } 3226 mode = O_RDWR; 3227 break; 3228 case 'i': 3229 ifaceopt = optarg; 3230 break; 3231 case 'k': 3232 if (state_killers >= 2) { 3233 warnx("can only specify -k twice"); 3234 usage(); 3235 /* NOTREACHED */ 3236 } 3237 state_kill[state_killers++] = optarg; 3238 mode = O_RDWR; 3239 break; 3240 case 'K': 3241 if (src_node_killers >= 2) { 3242 warnx("can only specify -K twice"); 3243 usage(); 3244 /* NOTREACHED */ 3245 } 3246 src_node_kill[src_node_killers++] = optarg; 3247 mode = O_RDWR; 3248 break; 3249 case 'm': 3250 opts |= PF_OPT_MERGE; 3251 break; 3252 case 'M': 3253 opts |= PF_OPT_KILLMATCH; 3254 break; 3255 case 'n': 3256 opts |= PF_OPT_NOACTION; 3257 break; 3258 case 'N': 3259 loadopt |= PFCTL_FLAG_NAT; 3260 break; 3261 case 'r': 3262 opts |= PF_OPT_USEDNS; 3263 break; 3264 case 'f': 3265 rulesopt = optarg; 3266 mode = O_RDWR; 3267 break; 3268 case 'g': 3269 opts |= PF_OPT_DEBUG; 3270 break; 3271 case 'A': 3272 loadopt |= PFCTL_FLAG_ALTQ; 3273 break; 3274 case 'R': 3275 loadopt |= PFCTL_FLAG_FILTER; 3276 break; 3277 case 'o': 3278 optiopt = pfctl_lookup_option(optarg, optiopt_list); 3279 if (optiopt == NULL) { 3280 warnx("Unknown optimization '%s'", optarg); 3281 usage(); 3282 } 3283 opts |= PF_OPT_OPTIMIZE; 3284 break; 3285 case 'O': 3286 loadopt |= PFCTL_FLAG_OPTION; 3287 break; 3288 case 'p': 3289 pf_device = optarg; 3290 break; 3291 case 'P': 3292 opts |= PF_OPT_NUMERIC; 3293 break; 3294 case 's': 3295 showopt = pfctl_lookup_option(optarg, showopt_list); 3296 if (showopt == NULL) { 3297 warnx("Unknown show modifier '%s'", optarg); 3298 usage(); 3299 } 3300 break; 3301 case 'S': 3302 opts |= PF_OPT_NODNS; 3303 break; 3304 case 't': 3305 tableopt = optarg; 3306 break; 3307 case 'T': 3308 tblcmdopt = pfctl_lookup_option(optarg, tblcmdopt_list); 3309 if (tblcmdopt == NULL) { 3310 warnx("Unknown table command '%s'", optarg); 3311 usage(); 3312 } 3313 break; 3314 case 'v': 3315 if (opts & PF_OPT_VERBOSE) 3316 opts |= PF_OPT_VERBOSE2; 3317 opts |= PF_OPT_VERBOSE; 3318 break; 3319 case 'x': 3320 debugopt = pfctl_lookup_option(optarg, debugopt_list); 3321 if (debugopt == NULL) { 3322 warnx("Unknown debug level '%s'", optarg); 3323 usage(); 3324 } 3325 mode = O_RDWR; 3326 break; 3327 case 'z': 3328 opts |= PF_OPT_CLRRULECTRS; 3329 mode = O_RDWR; 3330 break; 3331 case 'h': 3332 /* FALLTHROUGH */ 3333 default: 3334 usage(); 3335 /* NOTREACHED */ 3336 } 3337 } 3338 3339 if ((opts & PF_OPT_NODNS) && (opts & PF_OPT_USEDNS)) 3340 errx(1, "-N and -r are mutually exclusive"); 3341 3342 if ((tblcmdopt == NULL) ^ (tableopt == NULL)) 3343 usage(); 3344 3345 if (tblcmdopt != NULL) { 3346 argc -= optind; 3347 argv += optind; 3348 ch = *tblcmdopt; 3349 if (ch == 'l') { 3350 loadopt |= PFCTL_FLAG_TABLE; 3351 tblcmdopt = NULL; 3352 } else 3353 mode = strchr("st", ch) ? O_RDONLY : O_RDWR; 3354 } else if (argc != optind) { 3355 warnx("unknown command line argument: %s ...", argv[optind]); 3356 usage(); 3357 /* NOTREACHED */ 3358 } 3359 if (loadopt == 0) 3360 loadopt = ~0; 3361 3362 memset(anchorname, 0, sizeof(anchorname)); 3363 if (anchoropt != NULL) { 3364 int len = strlen(anchoropt); 3365 3366 if (anchoropt[0] == '\0') 3367 errx(1, "anchor name must not be empty"); 3368 if (mode == O_RDONLY && showopt == NULL && tblcmdopt == NULL) { 3369 warnx("anchors apply to -f, -F, -s, and -T only"); 3370 usage(); 3371 } 3372 if (mode == O_RDWR && tblcmdopt == NULL && 3373 (anchoropt[0] == '_' || strstr(anchoropt, "/_") != NULL)) 3374 errx(1, "anchor names beginning with '_' cannot " 3375 "be modified from the command line"); 3376 3377 if (len >= 1 && anchoropt[len - 1] == '*') { 3378 if (len >= 2 && anchoropt[len - 2] == '/') 3379 anchoropt[len - 2] = '\0'; 3380 else 3381 anchoropt[len - 1] = '\0'; 3382 opts |= PF_OPT_RECURSE; 3383 } 3384 if (strlcpy(anchorname, anchoropt, 3385 sizeof(anchorname)) >= sizeof(anchorname)) 3386 errx(1, "anchor name '%s' too long", 3387 anchoropt); 3388 loadopt &= PFCTL_FLAG_FILTER|PFCTL_FLAG_NAT|PFCTL_FLAG_TABLE|PFCTL_FLAG_ETH; 3389 } 3390 3391 if ((opts & PF_OPT_NOACTION) == 0) { 3392 dev = open(pf_device, mode); 3393 if (dev == -1) 3394 err(1, "%s", pf_device); 3395 altqsupport = pfctl_test_altqsupport(dev, opts); 3396 } else { 3397 dev = open(pf_device, O_RDONLY); 3398 if (dev >= 0) 3399 opts |= PF_OPT_DUMMYACTION; 3400 /* turn off options */ 3401 opts &= ~ (PF_OPT_DISABLE | PF_OPT_ENABLE); 3402 clearopt = showopt = debugopt = NULL; 3403 #if !defined(ENABLE_ALTQ) 3404 altqsupport = 0; 3405 #else 3406 altqsupport = 1; 3407 #endif 3408 } 3409 pfh = pfctl_open(pf_device); 3410 if (pfh == NULL) 3411 err(1, "Failed to open netlink"); 3412 3413 if (opts & PF_OPT_DISABLE) 3414 if (pfctl_disable(dev, opts)) 3415 exit_val = 1; 3416 3417 if ((path = calloc(1, MAXPATHLEN)) == NULL) 3418 errx(1, "%s: calloc", __func__); 3419 3420 if (showopt != NULL) { 3421 switch (*showopt) { 3422 case 'A': 3423 pfctl_show_anchors(dev, opts, anchorname); 3424 if (opts & PF_OPT_VERBOSE2) 3425 printf("Ethernet:\n"); 3426 pfctl_show_eth_anchors(dev, opts, anchorname); 3427 break; 3428 case 'r': 3429 pfctl_load_fingerprints(dev, opts); 3430 pfctl_show_rules(dev, path, opts, PFCTL_SHOW_RULES, 3431 anchorname, 0, 0); 3432 break; 3433 case 'l': 3434 pfctl_load_fingerprints(dev, opts); 3435 pfctl_show_rules(dev, path, opts, PFCTL_SHOW_LABELS, 3436 anchorname, 0, 0); 3437 break; 3438 case 'n': 3439 pfctl_load_fingerprints(dev, opts); 3440 pfctl_show_nat(dev, path, opts, anchorname, 0, 0); 3441 break; 3442 case 'q': 3443 pfctl_show_altq(dev, ifaceopt, opts, 3444 opts & PF_OPT_VERBOSE2); 3445 break; 3446 case 's': 3447 pfctl_show_states(dev, ifaceopt, opts); 3448 break; 3449 case 'S': 3450 pfctl_show_src_nodes(dev, opts); 3451 break; 3452 case 'i': 3453 pfctl_show_status(dev, opts); 3454 break; 3455 case 'R': 3456 exit_val = pfctl_show_running(dev); 3457 break; 3458 case 't': 3459 pfctl_show_timeouts(dev, opts); 3460 break; 3461 case 'm': 3462 pfctl_show_limits(dev, opts); 3463 break; 3464 case 'e': 3465 pfctl_show_eth_rules(dev, path, opts, 0, anchorname, 0, 3466 0); 3467 break; 3468 case 'a': 3469 opts |= PF_OPT_SHOWALL; 3470 pfctl_load_fingerprints(dev, opts); 3471 3472 pfctl_show_eth_rules(dev, path, opts, 0, anchorname, 0, 3473 0); 3474 3475 pfctl_show_nat(dev, path, opts, anchorname, 0, 0); 3476 pfctl_show_rules(dev, path, opts, PFCTL_SHOW_RULES, 3477 anchorname, 0, 0); 3478 pfctl_show_altq(dev, ifaceopt, opts, 0); 3479 pfctl_show_states(dev, ifaceopt, opts); 3480 pfctl_show_src_nodes(dev, opts); 3481 pfctl_show_status(dev, opts); 3482 pfctl_show_rules(dev, path, opts, PFCTL_SHOW_LABELS, 3483 anchorname, 0, 0); 3484 pfctl_show_timeouts(dev, opts); 3485 pfctl_show_limits(dev, opts); 3486 pfctl_show_tables(anchorname, opts); 3487 pfctl_show_fingerprints(opts); 3488 break; 3489 case 'T': 3490 if (opts & PF_OPT_RECURSE) { 3491 opts |= PF_OPT_CALLSHOW; 3492 pfctl_recurse(dev, opts, anchorname, 3493 pfctl_call_showtables); 3494 } else 3495 pfctl_show_tables(anchorname, opts); 3496 break; 3497 case 'o': 3498 pfctl_load_fingerprints(dev, opts); 3499 pfctl_show_fingerprints(opts); 3500 break; 3501 case 'I': 3502 pfctl_show_ifaces(ifaceopt, opts); 3503 break; 3504 case 'c': 3505 pfctl_show_creators(opts); 3506 break; 3507 } 3508 } 3509 3510 if ((opts & PF_OPT_CLRRULECTRS) && showopt == NULL) { 3511 pfctl_show_eth_rules(dev, path, opts, PFCTL_SHOW_NOTHING, 3512 anchorname, 0, 0); 3513 pfctl_show_rules(dev, path, opts, PFCTL_SHOW_NOTHING, 3514 anchorname, 0, 0); 3515 } 3516 3517 if (clearopt != NULL) { 3518 switch (*clearopt) { 3519 case 'e': 3520 pfctl_flush_eth_rules(dev, opts, anchorname); 3521 break; 3522 case 'r': 3523 if (opts & PF_OPT_RECURSE) 3524 pfctl_recurse(dev, opts, anchorname, 3525 pfctl_call_clearrules); 3526 else 3527 pfctl_flush_rules(dev, opts, anchorname); 3528 break; 3529 case 'n': 3530 pfctl_flush_nat(dev, opts, anchorname); 3531 break; 3532 case 'q': 3533 pfctl_clear_altq(dev, opts); 3534 break; 3535 case 's': 3536 pfctl_clear_iface_states(dev, ifaceopt, opts); 3537 break; 3538 case 'S': 3539 pfctl_clear_src_nodes(dev, opts); 3540 break; 3541 case 'i': 3542 pfctl_clear_stats(pfh, opts); 3543 break; 3544 case 'a': 3545 if (ifaceopt) { 3546 warnx("don't specify an interface with -Fall"); 3547 usage(); 3548 /* NOTREACHED */ 3549 } 3550 pfctl_flush_eth_rules(dev, opts, anchorname); 3551 pfctl_flush_rules(dev, opts, anchorname); 3552 pfctl_flush_nat(dev, opts, anchorname); 3553 if (opts & PF_OPT_RECURSE) 3554 pfctl_recurse(dev, opts, anchorname, 3555 pfctl_call_clearanchors); 3556 else { 3557 pfctl_do_clear_tables(anchorname, opts); 3558 pfctl_flush_rules(dev, opts, anchorname); 3559 } 3560 if (!*anchorname) { 3561 pfctl_clear_altq(dev, opts); 3562 pfctl_clear_iface_states(dev, ifaceopt, opts); 3563 pfctl_clear_src_nodes(dev, opts); 3564 pfctl_clear_stats(pfh, opts); 3565 pfctl_clear_fingerprints(dev, opts); 3566 pfctl_reset(dev, opts); 3567 } 3568 break; 3569 case 'o': 3570 pfctl_clear_fingerprints(dev, opts); 3571 break; 3572 case 'T': 3573 if ((opts & PF_OPT_RECURSE) == 0) 3574 pfctl_do_clear_tables(anchorname, opts); 3575 else 3576 pfctl_recurse(dev, opts, anchorname, 3577 pfctl_call_cleartables); 3578 break; 3579 case 'R': 3580 pfctl_reset(dev, opts); 3581 break; 3582 } 3583 } 3584 if (state_killers) { 3585 if (!strcmp(state_kill[0], "label")) 3586 pfctl_label_kill_states(dev, ifaceopt, opts); 3587 else if (!strcmp(state_kill[0], "id")) 3588 pfctl_id_kill_states(dev, ifaceopt, opts); 3589 else if (!strcmp(state_kill[0], "gateway")) 3590 pfctl_gateway_kill_states(dev, ifaceopt, opts); 3591 else if (!strcmp(state_kill[0], "key")) 3592 pfctl_key_kill_states(dev, ifaceopt, opts); 3593 else 3594 pfctl_net_kill_states(dev, ifaceopt, opts); 3595 } 3596 3597 if (src_node_killers) 3598 pfctl_kill_src_nodes(dev, opts); 3599 3600 if (tblcmdopt != NULL) { 3601 exit_val = pfctl_table(argc, argv, tableopt, 3602 tblcmdopt, rulesopt, anchorname, opts); 3603 rulesopt = NULL; 3604 } 3605 if (optiopt != NULL) { 3606 switch (*optiopt) { 3607 case 'n': 3608 optimize = 0; 3609 break; 3610 case 'b': 3611 optimize |= PF_OPTIMIZE_BASIC; 3612 break; 3613 case 'o': 3614 case 'p': 3615 optimize |= PF_OPTIMIZE_PROFILE; 3616 break; 3617 } 3618 } 3619 3620 if ((rulesopt != NULL) && (loadopt & PFCTL_FLAG_OPTION) && 3621 !anchorname[0] && !(opts & PF_OPT_NOACTION)) 3622 pfctl_get_skip_ifaces(); 3623 3624 if (rulesopt != NULL && !(opts & PF_OPT_MERGE) && 3625 !anchorname[0] && (loadopt & PFCTL_FLAG_OPTION)) 3626 if (pfctl_file_fingerprints(dev, opts, PF_OSFP_FILE)) 3627 exit_val = 1; 3628 3629 if (rulesopt != NULL) { 3630 if (pfctl_rules(dev, rulesopt, opts, optimize, 3631 anchorname, NULL)) 3632 exit_val = 1; 3633 } 3634 3635 if (opts & PF_OPT_ENABLE) 3636 if (pfctl_enable(dev, opts)) 3637 exit_val = 1; 3638 3639 if (debugopt != NULL) { 3640 switch (*debugopt) { 3641 case 'n': 3642 pfctl_debug(dev, PF_DEBUG_NONE, opts); 3643 break; 3644 case 'u': 3645 pfctl_debug(dev, PF_DEBUG_URGENT, opts); 3646 break; 3647 case 'm': 3648 pfctl_debug(dev, PF_DEBUG_MISC, opts); 3649 break; 3650 case 'l': 3651 pfctl_debug(dev, PF_DEBUG_NOISY, opts); 3652 break; 3653 } 3654 } 3655 3656 exit(exit_val); 3657 } 3658 3659 char * 3660 pf_strerror(int errnum) 3661 { 3662 switch (errnum) { 3663 case ESRCH: 3664 return "Table does not exist."; 3665 case EINVAL: 3666 case ENOENT: 3667 return "Anchor does not exist."; 3668 default: 3669 return strerror(errnum); 3670 } 3671 } 3672