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 __FBSDID("$FreeBSD$"); 38 39 #define PFIOC_USE_LATEST 40 41 #include <sys/types.h> 42 #include <sys/ioctl.h> 43 #include <sys/nv.h> 44 #include <sys/socket.h> 45 #include <sys/stat.h> 46 #include <sys/endian.h> 47 48 #include <net/if.h> 49 #include <netinet/in.h> 50 #include <net/pfvar.h> 51 #include <arpa/inet.h> 52 #include <net/altq/altq.h> 53 #include <sys/sysctl.h> 54 55 #include <err.h> 56 #include <errno.h> 57 #include <fcntl.h> 58 #include <libpfctl.h> 59 #include <limits.h> 60 #include <netdb.h> 61 #include <stdint.h> 62 #include <stdio.h> 63 #include <stdlib.h> 64 #include <string.h> 65 #include <unistd.h> 66 67 #include "pfctl_parser.h" 68 #include "pfctl.h" 69 70 void usage(void); 71 int pfctl_enable(int, int); 72 int pfctl_disable(int, int); 73 int pfctl_clear_stats(int, int); 74 int pfctl_get_skip_ifaces(void); 75 int pfctl_check_skip_ifaces(char *); 76 int pfctl_adjust_skip_ifaces(struct pfctl *); 77 int pfctl_clear_interface_flags(int, int); 78 int pfctl_clear_rules(int, int, char *); 79 int pfctl_clear_nat(int, int, char *); 80 int pfctl_clear_altq(int, int); 81 int pfctl_clear_src_nodes(int, int); 82 int pfctl_clear_iface_states(int, const char *, int); 83 void pfctl_addrprefix(char *, struct pf_addr *); 84 int pfctl_kill_src_nodes(int, const char *, int); 85 int pfctl_net_kill_states(int, const char *, int); 86 int pfctl_gateway_kill_states(int, const char *, int); 87 int pfctl_label_kill_states(int, const char *, int); 88 int pfctl_id_kill_states(int, const char *, int); 89 void pfctl_init_options(struct pfctl *); 90 int pfctl_load_options(struct pfctl *); 91 int pfctl_load_limit(struct pfctl *, unsigned int, unsigned int); 92 int pfctl_load_timeout(struct pfctl *, unsigned int, unsigned int); 93 int pfctl_load_debug(struct pfctl *, unsigned int); 94 int pfctl_load_logif(struct pfctl *, char *); 95 int pfctl_load_hostid(struct pfctl *, u_int32_t); 96 int pfctl_get_pool(int, struct pfctl_pool *, u_int32_t, u_int32_t, int, 97 char *); 98 void pfctl_print_rule_counters(struct pfctl_rule *, int); 99 int pfctl_show_rules(int, char *, int, enum pfctl_show, char *, int); 100 int pfctl_show_nat(int, int, char *); 101 int pfctl_show_src_nodes(int, int); 102 int pfctl_show_states(int, const char *, int); 103 int pfctl_show_status(int, int); 104 int pfctl_show_running(int); 105 int pfctl_show_timeouts(int, int); 106 int pfctl_show_limits(int, int); 107 void pfctl_debug(int, u_int32_t, int); 108 int pfctl_test_altqsupport(int, int); 109 int pfctl_show_anchors(int, int, char *); 110 int pfctl_ruleset_trans(struct pfctl *, char *, struct pfctl_anchor *); 111 int pfctl_load_ruleset(struct pfctl *, char *, 112 struct pfctl_ruleset *, int, int); 113 int pfctl_load_rule(struct pfctl *, char *, struct pfctl_rule *, int); 114 const char *pfctl_lookup_option(char *, const char * const *); 115 116 static struct pfctl_anchor_global pf_anchors; 117 static struct pfctl_anchor pf_main_anchor; 118 static struct pfr_buffer skip_b; 119 120 static const char *clearopt; 121 static char *rulesopt; 122 static const char *showopt; 123 static const char *debugopt; 124 static char *anchoropt; 125 static const char *optiopt = NULL; 126 static const char *pf_device = "/dev/pf"; 127 static char *ifaceopt; 128 static char *tableopt; 129 static const char *tblcmdopt; 130 static int src_node_killers; 131 static char *src_node_kill[2]; 132 static int state_killers; 133 static char *state_kill[2]; 134 int loadopt; 135 int altqsupport; 136 137 int dev = -1; 138 static int first_title = 1; 139 static int labels = 0; 140 141 #define INDENT(d, o) do { \ 142 if (o) { \ 143 int i; \ 144 for (i=0; i < d; i++) \ 145 printf(" "); \ 146 } \ 147 } while (0); \ 148 149 150 static const struct { 151 const char *name; 152 int index; 153 } pf_limits[] = { 154 { "states", PF_LIMIT_STATES }, 155 { "src-nodes", PF_LIMIT_SRC_NODES }, 156 { "frags", PF_LIMIT_FRAGS }, 157 { "table-entries", PF_LIMIT_TABLE_ENTRIES }, 158 { NULL, 0 } 159 }; 160 161 struct pf_hint { 162 const char *name; 163 int timeout; 164 }; 165 static const struct pf_hint pf_hint_normal[] = { 166 { "tcp.first", 2 * 60 }, 167 { "tcp.opening", 30 }, 168 { "tcp.established", 24 * 60 * 60 }, 169 { "tcp.closing", 15 * 60 }, 170 { "tcp.finwait", 45 }, 171 { "tcp.closed", 90 }, 172 { "tcp.tsdiff", 30 }, 173 { NULL, 0 } 174 }; 175 static const struct pf_hint pf_hint_satellite[] = { 176 { "tcp.first", 3 * 60 }, 177 { "tcp.opening", 30 + 5 }, 178 { "tcp.established", 24 * 60 * 60 }, 179 { "tcp.closing", 15 * 60 + 5 }, 180 { "tcp.finwait", 45 + 5 }, 181 { "tcp.closed", 90 + 5 }, 182 { "tcp.tsdiff", 60 }, 183 { NULL, 0 } 184 }; 185 static const struct pf_hint pf_hint_conservative[] = { 186 { "tcp.first", 60 * 60 }, 187 { "tcp.opening", 15 * 60 }, 188 { "tcp.established", 5 * 24 * 60 * 60 }, 189 { "tcp.closing", 60 * 60 }, 190 { "tcp.finwait", 10 * 60 }, 191 { "tcp.closed", 3 * 60 }, 192 { "tcp.tsdiff", 60 }, 193 { NULL, 0 } 194 }; 195 static const struct pf_hint pf_hint_aggressive[] = { 196 { "tcp.first", 30 }, 197 { "tcp.opening", 5 }, 198 { "tcp.established", 5 * 60 * 60 }, 199 { "tcp.closing", 60 }, 200 { "tcp.finwait", 30 }, 201 { "tcp.closed", 30 }, 202 { "tcp.tsdiff", 10 }, 203 { NULL, 0 } 204 }; 205 206 static const struct { 207 const char *name; 208 const struct pf_hint *hint; 209 } pf_hints[] = { 210 { "normal", pf_hint_normal }, 211 { "satellite", pf_hint_satellite }, 212 { "high-latency", pf_hint_satellite }, 213 { "conservative", pf_hint_conservative }, 214 { "aggressive", pf_hint_aggressive }, 215 { NULL, NULL } 216 }; 217 218 static const char * const clearopt_list[] = { 219 "nat", "queue", "rules", "Sources", 220 "states", "info", "Tables", "osfp", "all", NULL 221 }; 222 223 static const char * const showopt_list[] = { 224 "nat", "queue", "rules", "Anchors", "Sources", "states", "info", 225 "Interfaces", "labels", "timeouts", "memory", "Tables", "osfp", 226 "Running", "all", NULL 227 }; 228 229 static const char * const tblcmdopt_list[] = { 230 "kill", "flush", "add", "delete", "load", "replace", "show", 231 "test", "zero", "expire", NULL 232 }; 233 234 static const char * const debugopt_list[] = { 235 "none", "urgent", "misc", "loud", NULL 236 }; 237 238 static const char * const optiopt_list[] = { 239 "none", "basic", "profile", NULL 240 }; 241 242 void 243 usage(void) 244 { 245 extern char *__progname; 246 247 fprintf(stderr, 248 "usage: %s [-AdeghMmNnOPqRrvz] [-a anchor] [-D macro=value] [-F modifier]\n" 249 "\t[-f file] [-i interface] [-K host | network]\n" 250 "\t[-k host | network | gateway | label | id] [-o level] [-p device]\n" 251 "\t[-s modifier] [-t table -T command [address ...]] [-x level]\n", 252 __progname); 253 254 exit(1); 255 } 256 257 int 258 pfctl_enable(int dev, int opts) 259 { 260 if (ioctl(dev, DIOCSTART)) { 261 if (errno == EEXIST) 262 errx(1, "pf already enabled"); 263 else if (errno == ESRCH) 264 errx(1, "pfil registeration failed"); 265 else 266 err(1, "DIOCSTART"); 267 } 268 if ((opts & PF_OPT_QUIET) == 0) 269 fprintf(stderr, "pf enabled\n"); 270 271 if (altqsupport && ioctl(dev, DIOCSTARTALTQ)) 272 if (errno != EEXIST) 273 err(1, "DIOCSTARTALTQ"); 274 275 return (0); 276 } 277 278 int 279 pfctl_disable(int dev, int opts) 280 { 281 if (ioctl(dev, DIOCSTOP)) { 282 if (errno == ENOENT) 283 errx(1, "pf not enabled"); 284 else 285 err(1, "DIOCSTOP"); 286 } 287 if ((opts & PF_OPT_QUIET) == 0) 288 fprintf(stderr, "pf disabled\n"); 289 290 if (altqsupport && ioctl(dev, DIOCSTOPALTQ)) 291 if (errno != ENOENT) 292 err(1, "DIOCSTOPALTQ"); 293 294 return (0); 295 } 296 297 int 298 pfctl_clear_stats(int dev, int opts) 299 { 300 if (ioctl(dev, DIOCCLRSTATUS)) 301 err(1, "DIOCCLRSTATUS"); 302 if ((opts & PF_OPT_QUIET) == 0) 303 fprintf(stderr, "pf: statistics cleared\n"); 304 return (0); 305 } 306 307 int 308 pfctl_get_skip_ifaces(void) 309 { 310 bzero(&skip_b, sizeof(skip_b)); 311 skip_b.pfrb_type = PFRB_IFACES; 312 for (;;) { 313 pfr_buf_grow(&skip_b, skip_b.pfrb_size); 314 skip_b.pfrb_size = skip_b.pfrb_msize; 315 if (pfi_get_ifaces(NULL, skip_b.pfrb_caddr, &skip_b.pfrb_size)) 316 err(1, "pfi_get_ifaces"); 317 if (skip_b.pfrb_size <= skip_b.pfrb_msize) 318 break; 319 } 320 return (0); 321 } 322 323 int 324 pfctl_check_skip_ifaces(char *ifname) 325 { 326 struct pfi_kif *p; 327 struct node_host *h = NULL, *n = NULL; 328 329 PFRB_FOREACH(p, &skip_b) { 330 if (!strcmp(ifname, p->pfik_name) && 331 (p->pfik_flags & PFI_IFLAG_SKIP)) 332 p->pfik_flags &= ~PFI_IFLAG_SKIP; 333 if (!strcmp(ifname, p->pfik_name) && p->pfik_group != NULL) { 334 if ((h = ifa_grouplookup(p->pfik_name, 0)) == NULL) 335 continue; 336 337 for (n = h; n != NULL; n = n->next) { 338 if (p->pfik_ifp == NULL) 339 continue; 340 if (strncmp(p->pfik_name, ifname, IFNAMSIZ)) 341 continue; 342 343 p->pfik_flags &= ~PFI_IFLAG_SKIP; 344 } 345 } 346 } 347 return (0); 348 } 349 350 int 351 pfctl_adjust_skip_ifaces(struct pfctl *pf) 352 { 353 struct pfi_kif *p, *pp; 354 struct node_host *h = NULL, *n = NULL; 355 356 PFRB_FOREACH(p, &skip_b) { 357 if (p->pfik_group == NULL || !(p->pfik_flags & PFI_IFLAG_SKIP)) 358 continue; 359 360 pfctl_set_interface_flags(pf, p->pfik_name, PFI_IFLAG_SKIP, 0); 361 if ((h = ifa_grouplookup(p->pfik_name, 0)) == NULL) 362 continue; 363 364 for (n = h; n != NULL; n = n->next) 365 PFRB_FOREACH(pp, &skip_b) { 366 if (pp->pfik_ifp == NULL) 367 continue; 368 369 if (strncmp(pp->pfik_name, n->ifname, IFNAMSIZ)) 370 continue; 371 372 if (!(pp->pfik_flags & PFI_IFLAG_SKIP)) 373 pfctl_set_interface_flags(pf, 374 pp->pfik_name, PFI_IFLAG_SKIP, 1); 375 if (pp->pfik_flags & PFI_IFLAG_SKIP) 376 pp->pfik_flags &= ~PFI_IFLAG_SKIP; 377 } 378 } 379 380 PFRB_FOREACH(p, &skip_b) { 381 if (p->pfik_ifp == NULL || ! (p->pfik_flags & PFI_IFLAG_SKIP)) 382 continue; 383 384 pfctl_set_interface_flags(pf, p->pfik_name, PFI_IFLAG_SKIP, 0); 385 } 386 387 return (0); 388 } 389 390 int 391 pfctl_clear_interface_flags(int dev, int opts) 392 { 393 struct pfioc_iface pi; 394 395 if ((opts & PF_OPT_NOACTION) == 0) { 396 bzero(&pi, sizeof(pi)); 397 pi.pfiio_flags = PFI_IFLAG_SKIP; 398 399 if (ioctl(dev, DIOCCLRIFFLAG, &pi)) 400 err(1, "DIOCCLRIFFLAG"); 401 if ((opts & PF_OPT_QUIET) == 0) 402 fprintf(stderr, "pf: interface flags reset\n"); 403 } 404 return (0); 405 } 406 407 int 408 pfctl_clear_rules(int dev, int opts, char *anchorname) 409 { 410 struct pfr_buffer t; 411 412 memset(&t, 0, sizeof(t)); 413 t.pfrb_type = PFRB_TRANS; 414 if (pfctl_add_trans(&t, PF_RULESET_SCRUB, anchorname) || 415 pfctl_add_trans(&t, PF_RULESET_FILTER, anchorname) || 416 pfctl_trans(dev, &t, DIOCXBEGIN, 0) || 417 pfctl_trans(dev, &t, DIOCXCOMMIT, 0)) 418 err(1, "pfctl_clear_rules"); 419 if ((opts & PF_OPT_QUIET) == 0) 420 fprintf(stderr, "rules cleared\n"); 421 return (0); 422 } 423 424 int 425 pfctl_clear_nat(int dev, int opts, char *anchorname) 426 { 427 struct pfr_buffer t; 428 429 memset(&t, 0, sizeof(t)); 430 t.pfrb_type = PFRB_TRANS; 431 if (pfctl_add_trans(&t, PF_RULESET_NAT, anchorname) || 432 pfctl_add_trans(&t, PF_RULESET_BINAT, anchorname) || 433 pfctl_add_trans(&t, PF_RULESET_RDR, anchorname) || 434 pfctl_trans(dev, &t, DIOCXBEGIN, 0) || 435 pfctl_trans(dev, &t, DIOCXCOMMIT, 0)) 436 err(1, "pfctl_clear_nat"); 437 if ((opts & PF_OPT_QUIET) == 0) 438 fprintf(stderr, "nat cleared\n"); 439 return (0); 440 } 441 442 int 443 pfctl_clear_altq(int dev, int opts) 444 { 445 struct pfr_buffer t; 446 447 if (!altqsupport) 448 return (-1); 449 memset(&t, 0, sizeof(t)); 450 t.pfrb_type = PFRB_TRANS; 451 if (pfctl_add_trans(&t, PF_RULESET_ALTQ, "") || 452 pfctl_trans(dev, &t, DIOCXBEGIN, 0) || 453 pfctl_trans(dev, &t, DIOCXCOMMIT, 0)) 454 err(1, "pfctl_clear_altq"); 455 if ((opts & PF_OPT_QUIET) == 0) 456 fprintf(stderr, "altq cleared\n"); 457 return (0); 458 } 459 460 int 461 pfctl_clear_src_nodes(int dev, int opts) 462 { 463 if (ioctl(dev, DIOCCLRSRCNODES)) 464 err(1, "DIOCCLRSRCNODES"); 465 if ((opts & PF_OPT_QUIET) == 0) 466 fprintf(stderr, "source tracking entries cleared\n"); 467 return (0); 468 } 469 470 int 471 pfctl_clear_iface_states(int dev, const char *iface, int opts) 472 { 473 struct pfctl_kill kill; 474 unsigned int killed; 475 476 memset(&kill, 0, sizeof(kill)); 477 if (iface != NULL && strlcpy(kill.ifname, iface, 478 sizeof(kill.ifname)) >= sizeof(kill.ifname)) 479 errx(1, "invalid interface: %s", iface); 480 481 if (opts & PF_OPT_KILLMATCH) 482 kill.kill_match = true; 483 484 if (pfctl_clear_states(dev, &kill, &killed)) 485 err(1, "DIOCCLRSTATES"); 486 if ((opts & PF_OPT_QUIET) == 0) 487 fprintf(stderr, "%d states cleared\n", killed); 488 return (0); 489 } 490 491 void 492 pfctl_addrprefix(char *addr, struct pf_addr *mask) 493 { 494 char *p; 495 const char *errstr; 496 int prefix, ret_ga, q, r; 497 struct addrinfo hints, *res; 498 499 if ((p = strchr(addr, '/')) == NULL) 500 return; 501 502 *p++ = '\0'; 503 prefix = strtonum(p, 0, 128, &errstr); 504 if (errstr) 505 errx(1, "prefix is %s: %s", errstr, p); 506 507 bzero(&hints, sizeof(hints)); 508 /* prefix only with numeric addresses */ 509 hints.ai_flags |= AI_NUMERICHOST; 510 511 if ((ret_ga = getaddrinfo(addr, NULL, &hints, &res))) { 512 errx(1, "getaddrinfo: %s", gai_strerror(ret_ga)); 513 /* NOTREACHED */ 514 } 515 516 if (res->ai_family == AF_INET && prefix > 32) 517 errx(1, "prefix too long for AF_INET"); 518 else if (res->ai_family == AF_INET6 && prefix > 128) 519 errx(1, "prefix too long for AF_INET6"); 520 521 q = prefix >> 3; 522 r = prefix & 7; 523 switch (res->ai_family) { 524 case AF_INET: 525 bzero(&mask->v4, sizeof(mask->v4)); 526 mask->v4.s_addr = htonl((u_int32_t) 527 (0xffffffffffULL << (32 - prefix))); 528 break; 529 case AF_INET6: 530 bzero(&mask->v6, sizeof(mask->v6)); 531 if (q > 0) 532 memset((void *)&mask->v6, 0xff, q); 533 if (r > 0) 534 *((u_char *)&mask->v6 + q) = 535 (0xff00 >> r) & 0xff; 536 break; 537 } 538 freeaddrinfo(res); 539 } 540 541 int 542 pfctl_kill_src_nodes(int dev, const char *iface, int opts) 543 { 544 struct pfioc_src_node_kill psnk; 545 struct addrinfo *res[2], *resp[2]; 546 struct sockaddr last_src, last_dst; 547 int killed, sources, dests; 548 int ret_ga; 549 550 killed = sources = dests = 0; 551 552 memset(&psnk, 0, sizeof(psnk)); 553 memset(&psnk.psnk_src.addr.v.a.mask, 0xff, 554 sizeof(psnk.psnk_src.addr.v.a.mask)); 555 memset(&last_src, 0xff, sizeof(last_src)); 556 memset(&last_dst, 0xff, sizeof(last_dst)); 557 558 pfctl_addrprefix(src_node_kill[0], &psnk.psnk_src.addr.v.a.mask); 559 560 if ((ret_ga = getaddrinfo(src_node_kill[0], NULL, NULL, &res[0]))) { 561 errx(1, "getaddrinfo: %s", gai_strerror(ret_ga)); 562 /* NOTREACHED */ 563 } 564 for (resp[0] = res[0]; resp[0]; resp[0] = resp[0]->ai_next) { 565 if (resp[0]->ai_addr == NULL) 566 continue; 567 /* We get lots of duplicates. Catch the easy ones */ 568 if (memcmp(&last_src, resp[0]->ai_addr, sizeof(last_src)) == 0) 569 continue; 570 last_src = *(struct sockaddr *)resp[0]->ai_addr; 571 572 psnk.psnk_af = resp[0]->ai_family; 573 sources++; 574 575 if (psnk.psnk_af == AF_INET) 576 psnk.psnk_src.addr.v.a.addr.v4 = 577 ((struct sockaddr_in *)resp[0]->ai_addr)->sin_addr; 578 else if (psnk.psnk_af == AF_INET6) 579 psnk.psnk_src.addr.v.a.addr.v6 = 580 ((struct sockaddr_in6 *)resp[0]->ai_addr)-> 581 sin6_addr; 582 else 583 errx(1, "Unknown address family %d", psnk.psnk_af); 584 585 if (src_node_killers > 1) { 586 dests = 0; 587 memset(&psnk.psnk_dst.addr.v.a.mask, 0xff, 588 sizeof(psnk.psnk_dst.addr.v.a.mask)); 589 memset(&last_dst, 0xff, sizeof(last_dst)); 590 pfctl_addrprefix(src_node_kill[1], 591 &psnk.psnk_dst.addr.v.a.mask); 592 if ((ret_ga = getaddrinfo(src_node_kill[1], NULL, NULL, 593 &res[1]))) { 594 errx(1, "getaddrinfo: %s", 595 gai_strerror(ret_ga)); 596 /* NOTREACHED */ 597 } 598 for (resp[1] = res[1]; resp[1]; 599 resp[1] = resp[1]->ai_next) { 600 if (resp[1]->ai_addr == NULL) 601 continue; 602 if (psnk.psnk_af != resp[1]->ai_family) 603 continue; 604 605 if (memcmp(&last_dst, resp[1]->ai_addr, 606 sizeof(last_dst)) == 0) 607 continue; 608 last_dst = *(struct sockaddr *)resp[1]->ai_addr; 609 610 dests++; 611 612 if (psnk.psnk_af == AF_INET) 613 psnk.psnk_dst.addr.v.a.addr.v4 = 614 ((struct sockaddr_in *)resp[1]-> 615 ai_addr)->sin_addr; 616 else if (psnk.psnk_af == AF_INET6) 617 psnk.psnk_dst.addr.v.a.addr.v6 = 618 ((struct sockaddr_in6 *)resp[1]-> 619 ai_addr)->sin6_addr; 620 else 621 errx(1, "Unknown address family %d", 622 psnk.psnk_af); 623 624 if (ioctl(dev, DIOCKILLSRCNODES, &psnk)) 625 err(1, "DIOCKILLSRCNODES"); 626 killed += psnk.psnk_killed; 627 } 628 freeaddrinfo(res[1]); 629 } else { 630 if (ioctl(dev, DIOCKILLSRCNODES, &psnk)) 631 err(1, "DIOCKILLSRCNODES"); 632 killed += psnk.psnk_killed; 633 } 634 } 635 636 freeaddrinfo(res[0]); 637 638 if ((opts & PF_OPT_QUIET) == 0) 639 fprintf(stderr, "killed %d src nodes from %d sources and %d " 640 "destinations\n", killed, sources, dests); 641 return (0); 642 } 643 644 int 645 pfctl_net_kill_states(int dev, const char *iface, int opts) 646 { 647 struct pfctl_kill kill; 648 struct addrinfo *res[2], *resp[2]; 649 struct sockaddr last_src, last_dst; 650 unsigned int newkilled; 651 int killed, sources, dests; 652 int ret_ga; 653 654 killed = sources = dests = 0; 655 656 memset(&kill, 0, sizeof(kill)); 657 memset(&kill.src.addr.v.a.mask, 0xff, 658 sizeof(kill.src.addr.v.a.mask)); 659 memset(&last_src, 0xff, sizeof(last_src)); 660 memset(&last_dst, 0xff, sizeof(last_dst)); 661 if (iface != NULL && strlcpy(kill.ifname, iface, 662 sizeof(kill.ifname)) >= sizeof(kill.ifname)) 663 errx(1, "invalid interface: %s", iface); 664 665 pfctl_addrprefix(state_kill[0], &kill.src.addr.v.a.mask); 666 667 if (opts & PF_OPT_KILLMATCH) 668 kill.kill_match = true; 669 670 if ((ret_ga = getaddrinfo(state_kill[0], NULL, NULL, &res[0]))) { 671 errx(1, "getaddrinfo: %s", gai_strerror(ret_ga)); 672 /* NOTREACHED */ 673 } 674 for (resp[0] = res[0]; resp[0]; resp[0] = resp[0]->ai_next) { 675 if (resp[0]->ai_addr == NULL) 676 continue; 677 /* We get lots of duplicates. Catch the easy ones */ 678 if (memcmp(&last_src, resp[0]->ai_addr, sizeof(last_src)) == 0) 679 continue; 680 last_src = *(struct sockaddr *)resp[0]->ai_addr; 681 682 kill.af = resp[0]->ai_family; 683 sources++; 684 685 if (kill.af == AF_INET) 686 kill.src.addr.v.a.addr.v4 = 687 ((struct sockaddr_in *)resp[0]->ai_addr)->sin_addr; 688 else if (kill.af == AF_INET6) 689 kill.src.addr.v.a.addr.v6 = 690 ((struct sockaddr_in6 *)resp[0]->ai_addr)-> 691 sin6_addr; 692 else 693 errx(1, "Unknown address family %d", kill.af); 694 695 if (state_killers > 1) { 696 dests = 0; 697 memset(&kill.dst.addr.v.a.mask, 0xff, 698 sizeof(kill.dst.addr.v.a.mask)); 699 memset(&last_dst, 0xff, sizeof(last_dst)); 700 pfctl_addrprefix(state_kill[1], 701 &kill.dst.addr.v.a.mask); 702 if ((ret_ga = getaddrinfo(state_kill[1], NULL, NULL, 703 &res[1]))) { 704 errx(1, "getaddrinfo: %s", 705 gai_strerror(ret_ga)); 706 /* NOTREACHED */ 707 } 708 for (resp[1] = res[1]; resp[1]; 709 resp[1] = resp[1]->ai_next) { 710 if (resp[1]->ai_addr == NULL) 711 continue; 712 if (kill.af != resp[1]->ai_family) 713 continue; 714 715 if (memcmp(&last_dst, resp[1]->ai_addr, 716 sizeof(last_dst)) == 0) 717 continue; 718 last_dst = *(struct sockaddr *)resp[1]->ai_addr; 719 720 dests++; 721 722 if (kill.af == AF_INET) 723 kill.dst.addr.v.a.addr.v4 = 724 ((struct sockaddr_in *)resp[1]-> 725 ai_addr)->sin_addr; 726 else if (kill.af == AF_INET6) 727 kill.dst.addr.v.a.addr.v6 = 728 ((struct sockaddr_in6 *)resp[1]-> 729 ai_addr)->sin6_addr; 730 else 731 errx(1, "Unknown address family %d", 732 kill.af); 733 734 if (pfctl_kill_states(dev, &kill, &newkilled)) 735 err(1, "DIOCKILLSTATES"); 736 killed += newkilled; 737 } 738 freeaddrinfo(res[1]); 739 } else { 740 if (pfctl_kill_states(dev, &kill, &newkilled)) 741 err(1, "DIOCKILLSTATES"); 742 killed += newkilled; 743 } 744 } 745 746 freeaddrinfo(res[0]); 747 748 if ((opts & PF_OPT_QUIET) == 0) 749 fprintf(stderr, "killed %d states from %d sources and %d " 750 "destinations\n", killed, sources, dests); 751 return (0); 752 } 753 754 int 755 pfctl_gateway_kill_states(int dev, const char *iface, int opts) 756 { 757 struct pfctl_kill kill; 758 struct addrinfo *res, *resp; 759 struct sockaddr last_src; 760 unsigned int newkilled; 761 int killed = 0; 762 int ret_ga; 763 764 if (state_killers != 2 || (strlen(state_kill[1]) == 0)) { 765 warnx("no gateway specified"); 766 usage(); 767 } 768 769 memset(&kill, 0, sizeof(kill)); 770 memset(&kill.rt_addr.addr.v.a.mask, 0xff, 771 sizeof(kill.rt_addr.addr.v.a.mask)); 772 memset(&last_src, 0xff, sizeof(last_src)); 773 if (iface != NULL && strlcpy(kill.ifname, iface, 774 sizeof(kill.ifname)) >= sizeof(kill.ifname)) 775 errx(1, "invalid interface: %s", iface); 776 777 if (opts & PF_OPT_KILLMATCH) 778 kill.kill_match = true; 779 780 pfctl_addrprefix(state_kill[1], &kill.rt_addr.addr.v.a.mask); 781 782 if ((ret_ga = getaddrinfo(state_kill[1], NULL, NULL, &res))) { 783 errx(1, "getaddrinfo: %s", gai_strerror(ret_ga)); 784 /* NOTREACHED */ 785 } 786 for (resp = res; resp; resp = resp->ai_next) { 787 if (resp->ai_addr == NULL) 788 continue; 789 /* We get lots of duplicates. Catch the easy ones */ 790 if (memcmp(&last_src, resp->ai_addr, sizeof(last_src)) == 0) 791 continue; 792 last_src = *(struct sockaddr *)resp->ai_addr; 793 794 kill.af = resp->ai_family; 795 796 if (kill.af == AF_INET) 797 kill.rt_addr.addr.v.a.addr.v4 = 798 ((struct sockaddr_in *)resp->ai_addr)->sin_addr; 799 else if (kill.af == AF_INET6) 800 kill.rt_addr.addr.v.a.addr.v6 = 801 ((struct sockaddr_in6 *)resp->ai_addr)-> 802 sin6_addr; 803 else 804 errx(1, "Unknown address family %d", kill.af); 805 806 if (pfctl_kill_states(dev, &kill, &newkilled)) 807 err(1, "DIOCKILLSTATES"); 808 killed += newkilled; 809 } 810 811 freeaddrinfo(res); 812 813 if ((opts & PF_OPT_QUIET) == 0) 814 fprintf(stderr, "killed %d states\n", killed); 815 return (0); 816 } 817 818 int 819 pfctl_label_kill_states(int dev, const char *iface, int opts) 820 { 821 struct pfctl_kill kill; 822 unsigned int killed; 823 824 if (state_killers != 2 || (strlen(state_kill[1]) == 0)) { 825 warnx("no label specified"); 826 usage(); 827 } 828 memset(&kill, 0, sizeof(kill)); 829 if (iface != NULL && strlcpy(kill.ifname, iface, 830 sizeof(kill.ifname)) >= sizeof(kill.ifname)) 831 errx(1, "invalid interface: %s", iface); 832 833 if (opts & PF_OPT_KILLMATCH) 834 kill.kill_match = true; 835 836 if (strlcpy(kill.label, state_kill[1], sizeof(kill.label)) >= 837 sizeof(kill.label)) 838 errx(1, "label too long: %s", state_kill[1]); 839 840 if (pfctl_kill_states(dev, &kill, &killed)) 841 err(1, "DIOCKILLSTATES"); 842 843 if ((opts & PF_OPT_QUIET) == 0) 844 fprintf(stderr, "killed %d states\n", killed); 845 846 return (0); 847 } 848 849 int 850 pfctl_id_kill_states(int dev, const char *iface, int opts) 851 { 852 struct pfctl_kill kill; 853 unsigned int killed; 854 855 if (state_killers != 2 || (strlen(state_kill[1]) == 0)) { 856 warnx("no id specified"); 857 usage(); 858 } 859 860 memset(&kill, 0, sizeof(kill)); 861 862 if (opts & PF_OPT_KILLMATCH) 863 kill.kill_match = true; 864 865 if ((sscanf(state_kill[1], "%jx/%x", 866 &kill.cmp.id, &kill.cmp.creatorid)) == 2) 867 HTONL(kill.cmp.creatorid); 868 else if ((sscanf(state_kill[1], "%jx", &kill.cmp.id)) == 1) { 869 kill.cmp.creatorid = 0; 870 } else { 871 warnx("wrong id format specified"); 872 usage(); 873 } 874 if (kill.cmp.id == 0) { 875 warnx("cannot kill id 0"); 876 usage(); 877 } 878 879 kill.cmp.id = htobe64(kill.cmp.id); 880 if (pfctl_kill_states(dev, &kill, &killed)) 881 err(1, "DIOCKILLSTATES"); 882 883 if ((opts & PF_OPT_QUIET) == 0) 884 fprintf(stderr, "killed %d states\n", killed); 885 886 return (0); 887 } 888 889 int 890 pfctl_get_pool(int dev, struct pfctl_pool *pool, u_int32_t nr, 891 u_int32_t ticket, int r_action, char *anchorname) 892 { 893 struct pfioc_pooladdr pp; 894 struct pf_pooladdr *pa; 895 u_int32_t pnr, mpnr; 896 897 memset(&pp, 0, sizeof(pp)); 898 memcpy(pp.anchor, anchorname, sizeof(pp.anchor)); 899 pp.r_action = r_action; 900 pp.r_num = nr; 901 pp.ticket = ticket; 902 if (ioctl(dev, DIOCGETADDRS, &pp)) { 903 warn("DIOCGETADDRS"); 904 return (-1); 905 } 906 mpnr = pp.nr; 907 TAILQ_INIT(&pool->list); 908 for (pnr = 0; pnr < mpnr; ++pnr) { 909 pp.nr = pnr; 910 if (ioctl(dev, DIOCGETADDR, &pp)) { 911 warn("DIOCGETADDR"); 912 return (-1); 913 } 914 pa = calloc(1, sizeof(struct pf_pooladdr)); 915 if (pa == NULL) 916 err(1, "calloc"); 917 bcopy(&pp.addr, pa, sizeof(struct pf_pooladdr)); 918 TAILQ_INSERT_TAIL(&pool->list, pa, entries); 919 } 920 921 return (0); 922 } 923 924 void 925 pfctl_move_pool(struct pfctl_pool *src, struct pfctl_pool *dst) 926 { 927 struct pf_pooladdr *pa; 928 929 while ((pa = TAILQ_FIRST(&src->list)) != NULL) { 930 TAILQ_REMOVE(&src->list, pa, entries); 931 TAILQ_INSERT_TAIL(&dst->list, pa, entries); 932 } 933 } 934 935 void 936 pfctl_clear_pool(struct pfctl_pool *pool) 937 { 938 struct pf_pooladdr *pa; 939 940 while ((pa = TAILQ_FIRST(&pool->list)) != NULL) { 941 TAILQ_REMOVE(&pool->list, pa, entries); 942 free(pa); 943 } 944 } 945 946 void 947 pfctl_print_rule_counters(struct pfctl_rule *rule, int opts) 948 { 949 if (opts & PF_OPT_DEBUG) { 950 const char *t[PF_SKIP_COUNT] = { "i", "d", "f", 951 "p", "sa", "sp", "da", "dp" }; 952 int i; 953 954 printf(" [ Skip steps: "); 955 for (i = 0; i < PF_SKIP_COUNT; ++i) { 956 if (rule->skip[i].nr == rule->nr + 1) 957 continue; 958 printf("%s=", t[i]); 959 if (rule->skip[i].nr == -1) 960 printf("end "); 961 else 962 printf("%u ", rule->skip[i].nr); 963 } 964 printf("]\n"); 965 966 printf(" [ queue: qname=%s qid=%u pqname=%s pqid=%u ]\n", 967 rule->qname, rule->qid, rule->pqname, rule->pqid); 968 } 969 if (opts & PF_OPT_VERBOSE) { 970 printf(" [ Evaluations: %-8llu Packets: %-8llu " 971 "Bytes: %-10llu States: %-6ju]\n", 972 (unsigned long long)rule->evaluations, 973 (unsigned long long)(rule->packets[0] + 974 rule->packets[1]), 975 (unsigned long long)(rule->bytes[0] + 976 rule->bytes[1]), (uintmax_t)rule->states_cur); 977 if (!(opts & PF_OPT_DEBUG)) 978 printf(" [ Inserted: uid %u pid %u " 979 "State Creations: %-6ju]\n", 980 (unsigned)rule->cuid, (unsigned)rule->cpid, 981 (uintmax_t)rule->states_tot); 982 } 983 } 984 985 void 986 pfctl_print_title(char *title) 987 { 988 if (!first_title) 989 printf("\n"); 990 first_title = 0; 991 printf("%s\n", title); 992 } 993 994 int 995 pfctl_show_rules(int dev, char *path, int opts, enum pfctl_show format, 996 char *anchorname, int depth) 997 { 998 struct pfioc_rule pr; 999 struct pfctl_rule rule; 1000 u_int32_t nr, mnr, header = 0; 1001 int rule_numbers = opts & (PF_OPT_VERBOSE2 | PF_OPT_DEBUG); 1002 int numeric = opts & PF_OPT_NUMERIC; 1003 int len = strlen(path); 1004 int brace; 1005 char *p; 1006 1007 if (path[0]) 1008 snprintf(&path[len], MAXPATHLEN - len, "/%s", anchorname); 1009 else 1010 snprintf(&path[len], MAXPATHLEN - len, "%s", anchorname); 1011 1012 memset(&pr, 0, sizeof(pr)); 1013 memcpy(pr.anchor, path, sizeof(pr.anchor)); 1014 if (opts & PF_OPT_SHOWALL) { 1015 pr.rule.action = PF_PASS; 1016 if (ioctl(dev, DIOCGETRULES, &pr)) { 1017 warn("DIOCGETRULES"); 1018 goto error; 1019 } 1020 header++; 1021 } 1022 pr.rule.action = PF_SCRUB; 1023 if (ioctl(dev, DIOCGETRULES, &pr)) { 1024 warn("DIOCGETRULES"); 1025 goto error; 1026 } 1027 if (opts & PF_OPT_SHOWALL) { 1028 if (format == PFCTL_SHOW_RULES && (pr.nr > 0 || header)) 1029 pfctl_print_title("FILTER RULES:"); 1030 else if (format == PFCTL_SHOW_LABELS && labels) 1031 pfctl_print_title("LABEL COUNTERS:"); 1032 } 1033 mnr = pr.nr; 1034 1035 for (nr = 0; nr < mnr; ++nr) { 1036 pr.nr = nr; 1037 if (pfctl_get_clear_rule(dev, nr, pr.ticket, path, PF_SCRUB, 1038 &rule, pr.anchor_call, opts & PF_OPT_CLRRULECTRS)) { 1039 warn("DIOCGETRULENV"); 1040 goto error; 1041 } 1042 1043 if (pfctl_get_pool(dev, &rule.rpool, 1044 nr, pr.ticket, PF_SCRUB, path) != 0) 1045 goto error; 1046 1047 switch (format) { 1048 case PFCTL_SHOW_LABELS: 1049 break; 1050 case PFCTL_SHOW_RULES: 1051 if (rule.label[0] && (opts & PF_OPT_SHOWALL)) 1052 labels = 1; 1053 print_rule(&rule, pr.anchor_call, rule_numbers, numeric); 1054 printf("\n"); 1055 pfctl_print_rule_counters(&rule, opts); 1056 break; 1057 case PFCTL_SHOW_NOTHING: 1058 break; 1059 } 1060 pfctl_clear_pool(&rule.rpool); 1061 } 1062 pr.rule.action = PF_PASS; 1063 if (ioctl(dev, DIOCGETRULES, &pr)) { 1064 warn("DIOCGETRULES"); 1065 goto error; 1066 } 1067 mnr = pr.nr; 1068 for (nr = 0; nr < mnr; ++nr) { 1069 pr.nr = nr; 1070 if (pfctl_get_clear_rule(dev, nr, pr.ticket, path, PF_PASS, 1071 &rule, pr.anchor_call, opts & PF_OPT_CLRRULECTRS)) { 1072 warn("DIOCGETRULE"); 1073 goto error; 1074 } 1075 1076 if (pfctl_get_pool(dev, &rule.rpool, 1077 nr, pr.ticket, PF_PASS, path) != 0) 1078 goto error; 1079 1080 switch (format) { 1081 case PFCTL_SHOW_LABELS: { 1082 bool show = false; 1083 int i = 0; 1084 1085 while (rule.label[i][0]) { 1086 printf("%s ", rule.label[i++]); 1087 show = true; 1088 } 1089 1090 if (show) { 1091 printf("%llu %llu %llu %llu" 1092 " %llu %llu %llu %ju\n", 1093 (unsigned long long)rule.evaluations, 1094 (unsigned long long)(rule.packets[0] + 1095 rule.packets[1]), 1096 (unsigned long long)(rule.bytes[0] + 1097 rule.bytes[1]), 1098 (unsigned long long)rule.packets[0], 1099 (unsigned long long)rule.bytes[0], 1100 (unsigned long long)rule.packets[1], 1101 (unsigned long long)rule.bytes[1], 1102 (uintmax_t)rule.states_tot); 1103 } 1104 break; 1105 } 1106 case PFCTL_SHOW_RULES: 1107 brace = 0; 1108 if (rule.label[0] && (opts & PF_OPT_SHOWALL)) 1109 labels = 1; 1110 INDENT(depth, !(opts & PF_OPT_VERBOSE)); 1111 if (pr.anchor_call[0] && 1112 ((((p = strrchr(pr.anchor_call, '_')) != NULL) && 1113 ((void *)p == (void *)pr.anchor_call || 1114 *(--p) == '/')) || (opts & PF_OPT_RECURSE))) { 1115 brace++; 1116 if ((p = strrchr(pr.anchor_call, '/')) != 1117 NULL) 1118 p++; 1119 else 1120 p = &pr.anchor_call[0]; 1121 } else 1122 p = &pr.anchor_call[0]; 1123 1124 print_rule(&rule, p, rule_numbers, numeric); 1125 if (brace) 1126 printf(" {\n"); 1127 else 1128 printf("\n"); 1129 pfctl_print_rule_counters(&rule, opts); 1130 if (brace) { 1131 pfctl_show_rules(dev, path, opts, format, 1132 p, depth + 1); 1133 INDENT(depth, !(opts & PF_OPT_VERBOSE)); 1134 printf("}\n"); 1135 } 1136 break; 1137 case PFCTL_SHOW_NOTHING: 1138 break; 1139 } 1140 pfctl_clear_pool(&rule.rpool); 1141 } 1142 path[len] = '\0'; 1143 return (0); 1144 1145 error: 1146 path[len] = '\0'; 1147 return (-1); 1148 } 1149 1150 int 1151 pfctl_show_nat(int dev, int opts, char *anchorname) 1152 { 1153 struct pfioc_rule pr; 1154 struct pfctl_rule rule; 1155 u_int32_t mnr, nr; 1156 static int nattype[3] = { PF_NAT, PF_RDR, PF_BINAT }; 1157 int i, dotitle = opts & PF_OPT_SHOWALL; 1158 1159 memset(&pr, 0, sizeof(pr)); 1160 memcpy(pr.anchor, anchorname, sizeof(pr.anchor)); 1161 for (i = 0; i < 3; i++) { 1162 pr.rule.action = nattype[i]; 1163 if (ioctl(dev, DIOCGETRULES, &pr)) { 1164 warn("DIOCGETRULES"); 1165 return (-1); 1166 } 1167 mnr = pr.nr; 1168 for (nr = 0; nr < mnr; ++nr) { 1169 pr.nr = nr; 1170 if (pfctl_get_rule(dev, nr, pr.ticket, anchorname, 1171 nattype[i], &rule, pr.anchor_call)) { 1172 warn("DIOCGETRULE"); 1173 return (-1); 1174 } 1175 if (pfctl_get_pool(dev, &rule.rpool, nr, 1176 pr.ticket, nattype[i], anchorname) != 0) 1177 return (-1); 1178 if (dotitle) { 1179 pfctl_print_title("TRANSLATION RULES:"); 1180 dotitle = 0; 1181 } 1182 print_rule(&rule, pr.anchor_call, 1183 opts & PF_OPT_VERBOSE2, opts & PF_OPT_NUMERIC); 1184 printf("\n"); 1185 pfctl_print_rule_counters(&rule, opts); 1186 pfctl_clear_pool(&rule.rpool); 1187 } 1188 } 1189 return (0); 1190 } 1191 1192 int 1193 pfctl_show_src_nodes(int dev, int opts) 1194 { 1195 struct pfioc_src_nodes psn; 1196 struct pf_src_node *p; 1197 char *inbuf = NULL, *newinbuf = NULL; 1198 unsigned int len = 0; 1199 int i; 1200 1201 memset(&psn, 0, sizeof(psn)); 1202 for (;;) { 1203 psn.psn_len = len; 1204 if (len) { 1205 newinbuf = realloc(inbuf, len); 1206 if (newinbuf == NULL) 1207 err(1, "realloc"); 1208 psn.psn_buf = inbuf = newinbuf; 1209 } 1210 if (ioctl(dev, DIOCGETSRCNODES, &psn) < 0) { 1211 warn("DIOCGETSRCNODES"); 1212 free(inbuf); 1213 return (-1); 1214 } 1215 if (psn.psn_len + sizeof(struct pfioc_src_nodes) < len) 1216 break; 1217 if (len == 0 && psn.psn_len == 0) 1218 goto done; 1219 if (len == 0 && psn.psn_len != 0) 1220 len = psn.psn_len; 1221 if (psn.psn_len == 0) 1222 goto done; /* no src_nodes */ 1223 len *= 2; 1224 } 1225 p = psn.psn_src_nodes; 1226 if (psn.psn_len > 0 && (opts & PF_OPT_SHOWALL)) 1227 pfctl_print_title("SOURCE TRACKING NODES:"); 1228 for (i = 0; i < psn.psn_len; i += sizeof(*p)) { 1229 print_src_node(p, opts); 1230 p++; 1231 } 1232 done: 1233 free(inbuf); 1234 return (0); 1235 } 1236 1237 int 1238 pfctl_show_states(int dev, const char *iface, int opts) 1239 { 1240 struct pfioc_states ps; 1241 struct pfsync_state *p; 1242 char *inbuf = NULL, *newinbuf = NULL; 1243 unsigned int len = 0; 1244 int i, dotitle = (opts & PF_OPT_SHOWALL); 1245 1246 memset(&ps, 0, sizeof(ps)); 1247 for (;;) { 1248 ps.ps_len = len; 1249 if (len) { 1250 newinbuf = realloc(inbuf, len); 1251 if (newinbuf == NULL) 1252 err(1, "realloc"); 1253 ps.ps_buf = inbuf = newinbuf; 1254 } 1255 if (ioctl(dev, DIOCGETSTATES, &ps) < 0) { 1256 warn("DIOCGETSTATES"); 1257 free(inbuf); 1258 return (-1); 1259 } 1260 if (ps.ps_len + sizeof(struct pfioc_states) < len) 1261 break; 1262 if (len == 0 && ps.ps_len == 0) 1263 goto done; 1264 if (len == 0 && ps.ps_len != 0) 1265 len = ps.ps_len; 1266 if (ps.ps_len == 0) 1267 goto done; /* no states */ 1268 len *= 2; 1269 } 1270 p = ps.ps_states; 1271 for (i = 0; i < ps.ps_len; i += sizeof(*p), p++) { 1272 if (iface != NULL && strcmp(p->ifname, iface)) 1273 continue; 1274 if (dotitle) { 1275 pfctl_print_title("STATES:"); 1276 dotitle = 0; 1277 } 1278 print_state(p, opts); 1279 } 1280 done: 1281 free(inbuf); 1282 return (0); 1283 } 1284 1285 int 1286 pfctl_show_status(int dev, int opts) 1287 { 1288 struct pf_status status; 1289 1290 if (ioctl(dev, DIOCGETSTATUS, &status)) { 1291 warn("DIOCGETSTATUS"); 1292 return (-1); 1293 } 1294 if (opts & PF_OPT_SHOWALL) 1295 pfctl_print_title("INFO:"); 1296 print_status(&status, opts); 1297 return (0); 1298 } 1299 1300 int 1301 pfctl_show_running(int dev) 1302 { 1303 struct pf_status status; 1304 1305 if (ioctl(dev, DIOCGETSTATUS, &status)) { 1306 warn("DIOCGETSTATUS"); 1307 return (-1); 1308 } 1309 1310 print_running(&status); 1311 return (!status.running); 1312 } 1313 1314 int 1315 pfctl_show_timeouts(int dev, int opts) 1316 { 1317 struct pfioc_tm pt; 1318 int i; 1319 1320 if (opts & PF_OPT_SHOWALL) 1321 pfctl_print_title("TIMEOUTS:"); 1322 memset(&pt, 0, sizeof(pt)); 1323 for (i = 0; pf_timeouts[i].name; i++) { 1324 pt.timeout = pf_timeouts[i].timeout; 1325 if (ioctl(dev, DIOCGETTIMEOUT, &pt)) 1326 err(1, "DIOCGETTIMEOUT"); 1327 printf("%-20s %10d", pf_timeouts[i].name, pt.seconds); 1328 if (pf_timeouts[i].timeout >= PFTM_ADAPTIVE_START && 1329 pf_timeouts[i].timeout <= PFTM_ADAPTIVE_END) 1330 printf(" states"); 1331 else 1332 printf("s"); 1333 printf("\n"); 1334 } 1335 return (0); 1336 1337 } 1338 1339 int 1340 pfctl_show_limits(int dev, int opts) 1341 { 1342 struct pfioc_limit pl; 1343 int i; 1344 1345 if (opts & PF_OPT_SHOWALL) 1346 pfctl_print_title("LIMITS:"); 1347 memset(&pl, 0, sizeof(pl)); 1348 for (i = 0; pf_limits[i].name; i++) { 1349 pl.index = pf_limits[i].index; 1350 if (ioctl(dev, DIOCGETLIMIT, &pl)) 1351 err(1, "DIOCGETLIMIT"); 1352 printf("%-13s ", pf_limits[i].name); 1353 if (pl.limit == UINT_MAX) 1354 printf("unlimited\n"); 1355 else 1356 printf("hard limit %8u\n", pl.limit); 1357 } 1358 return (0); 1359 } 1360 1361 /* callbacks for rule/nat/rdr/addr */ 1362 int 1363 pfctl_add_pool(struct pfctl *pf, struct pfctl_pool *p, sa_family_t af) 1364 { 1365 struct pf_pooladdr *pa; 1366 1367 if ((pf->opts & PF_OPT_NOACTION) == 0) { 1368 if (ioctl(pf->dev, DIOCBEGINADDRS, &pf->paddr)) 1369 err(1, "DIOCBEGINADDRS"); 1370 } 1371 1372 pf->paddr.af = af; 1373 TAILQ_FOREACH(pa, &p->list, entries) { 1374 memcpy(&pf->paddr.addr, pa, sizeof(struct pf_pooladdr)); 1375 if ((pf->opts & PF_OPT_NOACTION) == 0) { 1376 if (ioctl(pf->dev, DIOCADDADDR, &pf->paddr)) 1377 err(1, "DIOCADDADDR"); 1378 } 1379 } 1380 return (0); 1381 } 1382 1383 int 1384 pfctl_append_rule(struct pfctl *pf, struct pfctl_rule *r, 1385 const char *anchor_call) 1386 { 1387 u_int8_t rs_num; 1388 struct pfctl_rule *rule; 1389 struct pfctl_ruleset *rs; 1390 char *p; 1391 1392 rs_num = pf_get_ruleset_number(r->action); 1393 if (rs_num == PF_RULESET_MAX) 1394 errx(1, "Invalid rule type %d", r->action); 1395 1396 rs = &pf->anchor->ruleset; 1397 1398 if (anchor_call[0] && r->anchor == NULL) { 1399 /* 1400 * Don't make non-brace anchors part of the main anchor pool. 1401 */ 1402 if ((r->anchor = calloc(1, sizeof(*r->anchor))) == NULL) 1403 err(1, "pfctl_append_rule: calloc"); 1404 1405 pf_init_ruleset(&r->anchor->ruleset); 1406 r->anchor->ruleset.anchor = r->anchor; 1407 if (strlcpy(r->anchor->path, anchor_call, 1408 sizeof(rule->anchor->path)) >= sizeof(rule->anchor->path)) 1409 errx(1, "pfctl_append_rule: strlcpy"); 1410 if ((p = strrchr(anchor_call, '/')) != NULL) { 1411 if (!strlen(p)) 1412 err(1, "pfctl_append_rule: bad anchor name %s", 1413 anchor_call); 1414 } else 1415 p = (char *)anchor_call; 1416 if (strlcpy(r->anchor->name, p, 1417 sizeof(rule->anchor->name)) >= sizeof(rule->anchor->name)) 1418 errx(1, "pfctl_append_rule: strlcpy"); 1419 } 1420 1421 if ((rule = calloc(1, sizeof(*rule))) == NULL) 1422 err(1, "calloc"); 1423 bcopy(r, rule, sizeof(*rule)); 1424 TAILQ_INIT(&rule->rpool.list); 1425 pfctl_move_pool(&r->rpool, &rule->rpool); 1426 1427 TAILQ_INSERT_TAIL(rs->rules[rs_num].active.ptr, rule, entries); 1428 return (0); 1429 } 1430 1431 int 1432 pfctl_ruleset_trans(struct pfctl *pf, char *path, struct pfctl_anchor *a) 1433 { 1434 int osize = pf->trans->pfrb_size; 1435 1436 if ((pf->loadopt & PFCTL_FLAG_NAT) != 0) { 1437 if (pfctl_add_trans(pf->trans, PF_RULESET_NAT, path) || 1438 pfctl_add_trans(pf->trans, PF_RULESET_BINAT, path) || 1439 pfctl_add_trans(pf->trans, PF_RULESET_RDR, path)) 1440 return (1); 1441 } 1442 if (a == pf->astack[0] && ((altqsupport && 1443 (pf->loadopt & PFCTL_FLAG_ALTQ) != 0))) { 1444 if (pfctl_add_trans(pf->trans, PF_RULESET_ALTQ, path)) 1445 return (2); 1446 } 1447 if ((pf->loadopt & PFCTL_FLAG_FILTER) != 0) { 1448 if (pfctl_add_trans(pf->trans, PF_RULESET_SCRUB, path) || 1449 pfctl_add_trans(pf->trans, PF_RULESET_FILTER, path)) 1450 return (3); 1451 } 1452 if (pf->loadopt & PFCTL_FLAG_TABLE) 1453 if (pfctl_add_trans(pf->trans, PF_RULESET_TABLE, path)) 1454 return (4); 1455 if (pfctl_trans(pf->dev, pf->trans, DIOCXBEGIN, osize)) 1456 return (5); 1457 1458 return (0); 1459 } 1460 1461 int 1462 pfctl_load_ruleset(struct pfctl *pf, char *path, struct pfctl_ruleset *rs, 1463 int rs_num, int depth) 1464 { 1465 struct pfctl_rule *r; 1466 int error, len = strlen(path); 1467 int brace = 0; 1468 1469 pf->anchor = rs->anchor; 1470 1471 if (path[0]) 1472 snprintf(&path[len], MAXPATHLEN - len, "/%s", pf->anchor->name); 1473 else 1474 snprintf(&path[len], MAXPATHLEN - len, "%s", pf->anchor->name); 1475 1476 if (depth) { 1477 if (TAILQ_FIRST(rs->rules[rs_num].active.ptr) != NULL) { 1478 brace++; 1479 if (pf->opts & PF_OPT_VERBOSE) 1480 printf(" {\n"); 1481 if ((pf->opts & PF_OPT_NOACTION) == 0 && 1482 (error = pfctl_ruleset_trans(pf, 1483 path, rs->anchor))) { 1484 printf("pfctl_load_rulesets: " 1485 "pfctl_ruleset_trans %d\n", error); 1486 goto error; 1487 } 1488 } else if (pf->opts & PF_OPT_VERBOSE) 1489 printf("\n"); 1490 1491 } 1492 1493 if (pf->optimize && rs_num == PF_RULESET_FILTER) 1494 pfctl_optimize_ruleset(pf, rs); 1495 1496 while ((r = TAILQ_FIRST(rs->rules[rs_num].active.ptr)) != NULL) { 1497 TAILQ_REMOVE(rs->rules[rs_num].active.ptr, r, entries); 1498 if ((error = pfctl_load_rule(pf, path, r, depth))) 1499 goto error; 1500 if (r->anchor) { 1501 if ((error = pfctl_load_ruleset(pf, path, 1502 &r->anchor->ruleset, rs_num, depth + 1))) 1503 goto error; 1504 } else if (pf->opts & PF_OPT_VERBOSE) 1505 printf("\n"); 1506 free(r); 1507 } 1508 if (brace && pf->opts & PF_OPT_VERBOSE) { 1509 INDENT(depth - 1, (pf->opts & PF_OPT_VERBOSE)); 1510 printf("}\n"); 1511 } 1512 path[len] = '\0'; 1513 return (0); 1514 1515 error: 1516 path[len] = '\0'; 1517 return (error); 1518 1519 } 1520 1521 int 1522 pfctl_load_rule(struct pfctl *pf, char *path, struct pfctl_rule *r, int depth) 1523 { 1524 u_int8_t rs_num = pf_get_ruleset_number(r->action); 1525 char *name; 1526 u_int32_t ticket; 1527 char anchor[PF_ANCHOR_NAME_SIZE]; 1528 int len = strlen(path); 1529 1530 /* set up anchor before adding to path for anchor_call */ 1531 if ((pf->opts & PF_OPT_NOACTION) == 0) 1532 ticket = pfctl_get_ticket(pf->trans, rs_num, path); 1533 if (strlcpy(anchor, path, sizeof(anchor)) >= sizeof(anchor)) 1534 errx(1, "pfctl_load_rule: strlcpy"); 1535 1536 if (r->anchor) { 1537 if (r->anchor->match) { 1538 if (path[0]) 1539 snprintf(&path[len], MAXPATHLEN - len, 1540 "/%s", r->anchor->name); 1541 else 1542 snprintf(&path[len], MAXPATHLEN - len, 1543 "%s", r->anchor->name); 1544 name = r->anchor->name; 1545 } else 1546 name = r->anchor->path; 1547 } else 1548 name = ""; 1549 1550 if ((pf->opts & PF_OPT_NOACTION) == 0) { 1551 if (pfctl_add_pool(pf, &r->rpool, r->af)) 1552 return (1); 1553 if (pfctl_add_rule(pf->dev, r, anchor, name, ticket, 1554 pf->paddr.ticket)) 1555 err(1, "DIOCADDRULENV"); 1556 } 1557 1558 if (pf->opts & PF_OPT_VERBOSE) { 1559 INDENT(depth, !(pf->opts & PF_OPT_VERBOSE2)); 1560 print_rule(r, r->anchor ? r->anchor->name : "", 1561 pf->opts & PF_OPT_VERBOSE2, 1562 pf->opts & PF_OPT_NUMERIC); 1563 } 1564 path[len] = '\0'; 1565 pfctl_clear_pool(&r->rpool); 1566 return (0); 1567 } 1568 1569 int 1570 pfctl_add_altq(struct pfctl *pf, struct pf_altq *a) 1571 { 1572 if (altqsupport && 1573 (loadopt & PFCTL_FLAG_ALTQ) != 0) { 1574 memcpy(&pf->paltq->altq, a, sizeof(struct pf_altq)); 1575 if ((pf->opts & PF_OPT_NOACTION) == 0) { 1576 if (ioctl(pf->dev, DIOCADDALTQ, pf->paltq)) { 1577 if (errno == ENXIO) 1578 errx(1, "qtype not configured"); 1579 else if (errno == ENODEV) 1580 errx(1, "%s: driver does not support " 1581 "altq", a->ifname); 1582 else 1583 err(1, "DIOCADDALTQ"); 1584 } 1585 } 1586 pfaltq_store(&pf->paltq->altq); 1587 } 1588 return (0); 1589 } 1590 1591 int 1592 pfctl_rules(int dev, char *filename, int opts, int optimize, 1593 char *anchorname, struct pfr_buffer *trans) 1594 { 1595 #define ERR(x) do { warn(x); goto _error; } while(0) 1596 #define ERRX(x) do { warnx(x); goto _error; } while(0) 1597 1598 struct pfr_buffer *t, buf; 1599 struct pfioc_altq pa; 1600 struct pfctl pf; 1601 struct pfctl_ruleset *rs; 1602 struct pfr_table trs; 1603 char *path; 1604 int osize; 1605 1606 RB_INIT(&pf_anchors); 1607 memset(&pf_main_anchor, 0, sizeof(pf_main_anchor)); 1608 pf_init_ruleset(&pf_main_anchor.ruleset); 1609 pf_main_anchor.ruleset.anchor = &pf_main_anchor; 1610 if (trans == NULL) { 1611 bzero(&buf, sizeof(buf)); 1612 buf.pfrb_type = PFRB_TRANS; 1613 t = &buf; 1614 osize = 0; 1615 } else { 1616 t = trans; 1617 osize = t->pfrb_size; 1618 } 1619 1620 memset(&pa, 0, sizeof(pa)); 1621 pa.version = PFIOC_ALTQ_VERSION; 1622 memset(&pf, 0, sizeof(pf)); 1623 memset(&trs, 0, sizeof(trs)); 1624 if ((path = calloc(1, MAXPATHLEN)) == NULL) 1625 ERRX("pfctl_rules: calloc"); 1626 if (strlcpy(trs.pfrt_anchor, anchorname, 1627 sizeof(trs.pfrt_anchor)) >= sizeof(trs.pfrt_anchor)) 1628 ERRX("pfctl_rules: strlcpy"); 1629 pf.dev = dev; 1630 pf.opts = opts; 1631 pf.optimize = optimize; 1632 pf.loadopt = loadopt; 1633 1634 /* non-brace anchor, create without resolving the path */ 1635 if ((pf.anchor = calloc(1, sizeof(*pf.anchor))) == NULL) 1636 ERRX("pfctl_rules: calloc"); 1637 rs = &pf.anchor->ruleset; 1638 pf_init_ruleset(rs); 1639 rs->anchor = pf.anchor; 1640 if (strlcpy(pf.anchor->path, anchorname, 1641 sizeof(pf.anchor->path)) >= sizeof(pf.anchor->path)) 1642 errx(1, "pfctl_add_rule: strlcpy"); 1643 if (strlcpy(pf.anchor->name, anchorname, 1644 sizeof(pf.anchor->name)) >= sizeof(pf.anchor->name)) 1645 errx(1, "pfctl_add_rule: strlcpy"); 1646 1647 1648 pf.astack[0] = pf.anchor; 1649 pf.asd = 0; 1650 if (anchorname[0]) 1651 pf.loadopt &= ~PFCTL_FLAG_ALTQ; 1652 pf.paltq = &pa; 1653 pf.trans = t; 1654 pfctl_init_options(&pf); 1655 1656 if ((opts & PF_OPT_NOACTION) == 0) { 1657 /* 1658 * XXX For the time being we need to open transactions for 1659 * the main ruleset before parsing, because tables are still 1660 * loaded at parse time. 1661 */ 1662 if (pfctl_ruleset_trans(&pf, anchorname, pf.anchor)) 1663 ERRX("pfctl_rules"); 1664 if (altqsupport && (pf.loadopt & PFCTL_FLAG_ALTQ)) 1665 pa.ticket = 1666 pfctl_get_ticket(t, PF_RULESET_ALTQ, anchorname); 1667 if (pf.loadopt & PFCTL_FLAG_TABLE) 1668 pf.astack[0]->ruleset.tticket = 1669 pfctl_get_ticket(t, PF_RULESET_TABLE, anchorname); 1670 } 1671 1672 if (parse_config(filename, &pf) < 0) { 1673 if ((opts & PF_OPT_NOACTION) == 0) 1674 ERRX("Syntax error in config file: " 1675 "pf rules not loaded"); 1676 else 1677 goto _error; 1678 } 1679 if (loadopt & PFCTL_FLAG_OPTION) 1680 pfctl_adjust_skip_ifaces(&pf); 1681 1682 if ((pf.loadopt & PFCTL_FLAG_FILTER && 1683 (pfctl_load_ruleset(&pf, path, rs, PF_RULESET_SCRUB, 0))) || 1684 (pf.loadopt & PFCTL_FLAG_NAT && 1685 (pfctl_load_ruleset(&pf, path, rs, PF_RULESET_NAT, 0) || 1686 pfctl_load_ruleset(&pf, path, rs, PF_RULESET_RDR, 0) || 1687 pfctl_load_ruleset(&pf, path, rs, PF_RULESET_BINAT, 0))) || 1688 (pf.loadopt & PFCTL_FLAG_FILTER && 1689 pfctl_load_ruleset(&pf, path, rs, PF_RULESET_FILTER, 0))) { 1690 if ((opts & PF_OPT_NOACTION) == 0) 1691 ERRX("Unable to load rules into kernel"); 1692 else 1693 goto _error; 1694 } 1695 1696 if ((altqsupport && (pf.loadopt & PFCTL_FLAG_ALTQ) != 0)) 1697 if (check_commit_altq(dev, opts) != 0) 1698 ERRX("errors in altq config"); 1699 1700 /* process "load anchor" directives */ 1701 if (!anchorname[0]) 1702 if (pfctl_load_anchors(dev, &pf, t) == -1) 1703 ERRX("load anchors"); 1704 1705 if (trans == NULL && (opts & PF_OPT_NOACTION) == 0) { 1706 if (!anchorname[0]) 1707 if (pfctl_load_options(&pf)) 1708 goto _error; 1709 if (pfctl_trans(dev, t, DIOCXCOMMIT, osize)) 1710 ERR("DIOCXCOMMIT"); 1711 } 1712 free(path); 1713 return (0); 1714 1715 _error: 1716 if (trans == NULL) { /* main ruleset */ 1717 if ((opts & PF_OPT_NOACTION) == 0) 1718 if (pfctl_trans(dev, t, DIOCXROLLBACK, osize)) 1719 err(1, "DIOCXROLLBACK"); 1720 exit(1); 1721 } else { /* sub ruleset */ 1722 free(path); 1723 return (-1); 1724 } 1725 1726 #undef ERR 1727 #undef ERRX 1728 } 1729 1730 FILE * 1731 pfctl_fopen(const char *name, const char *mode) 1732 { 1733 struct stat st; 1734 FILE *fp; 1735 1736 fp = fopen(name, mode); 1737 if (fp == NULL) 1738 return (NULL); 1739 if (fstat(fileno(fp), &st)) { 1740 fclose(fp); 1741 return (NULL); 1742 } 1743 if (S_ISDIR(st.st_mode)) { 1744 fclose(fp); 1745 errno = EISDIR; 1746 return (NULL); 1747 } 1748 return (fp); 1749 } 1750 1751 void 1752 pfctl_init_options(struct pfctl *pf) 1753 { 1754 1755 pf->timeout[PFTM_TCP_FIRST_PACKET] = PFTM_TCP_FIRST_PACKET_VAL; 1756 pf->timeout[PFTM_TCP_OPENING] = PFTM_TCP_OPENING_VAL; 1757 pf->timeout[PFTM_TCP_ESTABLISHED] = PFTM_TCP_ESTABLISHED_VAL; 1758 pf->timeout[PFTM_TCP_CLOSING] = PFTM_TCP_CLOSING_VAL; 1759 pf->timeout[PFTM_TCP_FIN_WAIT] = PFTM_TCP_FIN_WAIT_VAL; 1760 pf->timeout[PFTM_TCP_CLOSED] = PFTM_TCP_CLOSED_VAL; 1761 pf->timeout[PFTM_UDP_FIRST_PACKET] = PFTM_UDP_FIRST_PACKET_VAL; 1762 pf->timeout[PFTM_UDP_SINGLE] = PFTM_UDP_SINGLE_VAL; 1763 pf->timeout[PFTM_UDP_MULTIPLE] = PFTM_UDP_MULTIPLE_VAL; 1764 pf->timeout[PFTM_ICMP_FIRST_PACKET] = PFTM_ICMP_FIRST_PACKET_VAL; 1765 pf->timeout[PFTM_ICMP_ERROR_REPLY] = PFTM_ICMP_ERROR_REPLY_VAL; 1766 pf->timeout[PFTM_OTHER_FIRST_PACKET] = PFTM_OTHER_FIRST_PACKET_VAL; 1767 pf->timeout[PFTM_OTHER_SINGLE] = PFTM_OTHER_SINGLE_VAL; 1768 pf->timeout[PFTM_OTHER_MULTIPLE] = PFTM_OTHER_MULTIPLE_VAL; 1769 pf->timeout[PFTM_FRAG] = PFTM_FRAG_VAL; 1770 pf->timeout[PFTM_INTERVAL] = PFTM_INTERVAL_VAL; 1771 pf->timeout[PFTM_SRC_NODE] = PFTM_SRC_NODE_VAL; 1772 pf->timeout[PFTM_TS_DIFF] = PFTM_TS_DIFF_VAL; 1773 pf->timeout[PFTM_ADAPTIVE_START] = PFSTATE_ADAPT_START; 1774 pf->timeout[PFTM_ADAPTIVE_END] = PFSTATE_ADAPT_END; 1775 1776 pf->limit[PF_LIMIT_STATES] = PFSTATE_HIWAT; 1777 pf->limit[PF_LIMIT_FRAGS] = PFFRAG_FRENT_HIWAT; 1778 pf->limit[PF_LIMIT_SRC_NODES] = PFSNODE_HIWAT; 1779 pf->limit[PF_LIMIT_TABLE_ENTRIES] = PFR_KENTRY_HIWAT; 1780 1781 pf->debug = PF_DEBUG_URGENT; 1782 } 1783 1784 int 1785 pfctl_load_options(struct pfctl *pf) 1786 { 1787 int i, error = 0; 1788 1789 if ((loadopt & PFCTL_FLAG_OPTION) == 0) 1790 return (0); 1791 1792 /* load limits */ 1793 for (i = 0; i < PF_LIMIT_MAX; i++) { 1794 if ((pf->opts & PF_OPT_MERGE) && !pf->limit_set[i]) 1795 continue; 1796 if (pfctl_load_limit(pf, i, pf->limit[i])) 1797 error = 1; 1798 } 1799 1800 /* 1801 * If we've set the limit, but haven't explicitly set adaptive 1802 * timeouts, do it now with a start of 60% and end of 120%. 1803 */ 1804 if (pf->limit_set[PF_LIMIT_STATES] && 1805 !pf->timeout_set[PFTM_ADAPTIVE_START] && 1806 !pf->timeout_set[PFTM_ADAPTIVE_END]) { 1807 pf->timeout[PFTM_ADAPTIVE_START] = 1808 (pf->limit[PF_LIMIT_STATES] / 10) * 6; 1809 pf->timeout_set[PFTM_ADAPTIVE_START] = 1; 1810 pf->timeout[PFTM_ADAPTIVE_END] = 1811 (pf->limit[PF_LIMIT_STATES] / 10) * 12; 1812 pf->timeout_set[PFTM_ADAPTIVE_END] = 1; 1813 } 1814 1815 /* load timeouts */ 1816 for (i = 0; i < PFTM_MAX; i++) { 1817 if ((pf->opts & PF_OPT_MERGE) && !pf->timeout_set[i]) 1818 continue; 1819 if (pfctl_load_timeout(pf, i, pf->timeout[i])) 1820 error = 1; 1821 } 1822 1823 /* load debug */ 1824 if (!(pf->opts & PF_OPT_MERGE) || pf->debug_set) 1825 if (pfctl_load_debug(pf, pf->debug)) 1826 error = 1; 1827 1828 /* load logif */ 1829 if (!(pf->opts & PF_OPT_MERGE) || pf->ifname_set) 1830 if (pfctl_load_logif(pf, pf->ifname)) 1831 error = 1; 1832 1833 /* load hostid */ 1834 if (!(pf->opts & PF_OPT_MERGE) || pf->hostid_set) 1835 if (pfctl_load_hostid(pf, pf->hostid)) 1836 error = 1; 1837 1838 /* load keepcounters */ 1839 if (pfctl_set_keepcounters(pf->dev, pf->keep_counters)) 1840 error = 1; 1841 1842 return (error); 1843 } 1844 1845 int 1846 pfctl_set_limit(struct pfctl *pf, const char *opt, unsigned int limit) 1847 { 1848 int i; 1849 1850 1851 for (i = 0; pf_limits[i].name; i++) { 1852 if (strcasecmp(opt, pf_limits[i].name) == 0) { 1853 pf->limit[pf_limits[i].index] = limit; 1854 pf->limit_set[pf_limits[i].index] = 1; 1855 break; 1856 } 1857 } 1858 if (pf_limits[i].name == NULL) { 1859 warnx("Bad pool name."); 1860 return (1); 1861 } 1862 1863 if (pf->opts & PF_OPT_VERBOSE) 1864 printf("set limit %s %d\n", opt, limit); 1865 1866 return (0); 1867 } 1868 1869 int 1870 pfctl_load_limit(struct pfctl *pf, unsigned int index, unsigned int limit) 1871 { 1872 struct pfioc_limit pl; 1873 1874 memset(&pl, 0, sizeof(pl)); 1875 pl.index = index; 1876 pl.limit = limit; 1877 if (ioctl(pf->dev, DIOCSETLIMIT, &pl)) { 1878 if (errno == EBUSY) 1879 warnx("Current pool size exceeds requested hard limit"); 1880 else 1881 warnx("DIOCSETLIMIT"); 1882 return (1); 1883 } 1884 return (0); 1885 } 1886 1887 int 1888 pfctl_set_timeout(struct pfctl *pf, const char *opt, int seconds, int quiet) 1889 { 1890 int i; 1891 1892 if ((loadopt & PFCTL_FLAG_OPTION) == 0) 1893 return (0); 1894 1895 for (i = 0; pf_timeouts[i].name; i++) { 1896 if (strcasecmp(opt, pf_timeouts[i].name) == 0) { 1897 pf->timeout[pf_timeouts[i].timeout] = seconds; 1898 pf->timeout_set[pf_timeouts[i].timeout] = 1; 1899 break; 1900 } 1901 } 1902 1903 if (pf_timeouts[i].name == NULL) { 1904 warnx("Bad timeout name."); 1905 return (1); 1906 } 1907 1908 1909 if (pf->opts & PF_OPT_VERBOSE && ! quiet) 1910 printf("set timeout %s %d\n", opt, seconds); 1911 1912 return (0); 1913 } 1914 1915 int 1916 pfctl_load_timeout(struct pfctl *pf, unsigned int timeout, unsigned int seconds) 1917 { 1918 struct pfioc_tm pt; 1919 1920 memset(&pt, 0, sizeof(pt)); 1921 pt.timeout = timeout; 1922 pt.seconds = seconds; 1923 if (ioctl(pf->dev, DIOCSETTIMEOUT, &pt)) { 1924 warnx("DIOCSETTIMEOUT"); 1925 return (1); 1926 } 1927 return (0); 1928 } 1929 1930 int 1931 pfctl_set_optimization(struct pfctl *pf, const char *opt) 1932 { 1933 const struct pf_hint *hint; 1934 int i, r; 1935 1936 if ((loadopt & PFCTL_FLAG_OPTION) == 0) 1937 return (0); 1938 1939 for (i = 0; pf_hints[i].name; i++) 1940 if (strcasecmp(opt, pf_hints[i].name) == 0) 1941 break; 1942 1943 hint = pf_hints[i].hint; 1944 if (hint == NULL) { 1945 warnx("invalid state timeouts optimization"); 1946 return (1); 1947 } 1948 1949 for (i = 0; hint[i].name; i++) 1950 if ((r = pfctl_set_timeout(pf, hint[i].name, 1951 hint[i].timeout, 1))) 1952 return (r); 1953 1954 if (pf->opts & PF_OPT_VERBOSE) 1955 printf("set optimization %s\n", opt); 1956 1957 return (0); 1958 } 1959 1960 int 1961 pfctl_set_logif(struct pfctl *pf, char *ifname) 1962 { 1963 1964 if ((loadopt & PFCTL_FLAG_OPTION) == 0) 1965 return (0); 1966 1967 if (!strcmp(ifname, "none")) { 1968 free(pf->ifname); 1969 pf->ifname = NULL; 1970 } else { 1971 pf->ifname = strdup(ifname); 1972 if (!pf->ifname) 1973 errx(1, "pfctl_set_logif: strdup"); 1974 } 1975 pf->ifname_set = 1; 1976 1977 if (pf->opts & PF_OPT_VERBOSE) 1978 printf("set loginterface %s\n", ifname); 1979 1980 return (0); 1981 } 1982 1983 int 1984 pfctl_load_logif(struct pfctl *pf, char *ifname) 1985 { 1986 struct pfioc_if pi; 1987 1988 memset(&pi, 0, sizeof(pi)); 1989 if (ifname && strlcpy(pi.ifname, ifname, 1990 sizeof(pi.ifname)) >= sizeof(pi.ifname)) { 1991 warnx("pfctl_load_logif: strlcpy"); 1992 return (1); 1993 } 1994 if (ioctl(pf->dev, DIOCSETSTATUSIF, &pi)) { 1995 warnx("DIOCSETSTATUSIF"); 1996 return (1); 1997 } 1998 return (0); 1999 } 2000 2001 int 2002 pfctl_set_hostid(struct pfctl *pf, u_int32_t hostid) 2003 { 2004 if ((loadopt & PFCTL_FLAG_OPTION) == 0) 2005 return (0); 2006 2007 HTONL(hostid); 2008 2009 pf->hostid = hostid; 2010 pf->hostid_set = 1; 2011 2012 if (pf->opts & PF_OPT_VERBOSE) 2013 printf("set hostid 0x%08x\n", ntohl(hostid)); 2014 2015 return (0); 2016 } 2017 2018 int 2019 pfctl_load_hostid(struct pfctl *pf, u_int32_t hostid) 2020 { 2021 if (ioctl(dev, DIOCSETHOSTID, &hostid)) { 2022 warnx("DIOCSETHOSTID"); 2023 return (1); 2024 } 2025 return (0); 2026 } 2027 2028 int 2029 pfctl_set_debug(struct pfctl *pf, char *d) 2030 { 2031 u_int32_t level; 2032 2033 if ((loadopt & PFCTL_FLAG_OPTION) == 0) 2034 return (0); 2035 2036 if (!strcmp(d, "none")) 2037 pf->debug = PF_DEBUG_NONE; 2038 else if (!strcmp(d, "urgent")) 2039 pf->debug = PF_DEBUG_URGENT; 2040 else if (!strcmp(d, "misc")) 2041 pf->debug = PF_DEBUG_MISC; 2042 else if (!strcmp(d, "loud")) 2043 pf->debug = PF_DEBUG_NOISY; 2044 else { 2045 warnx("unknown debug level \"%s\"", d); 2046 return (-1); 2047 } 2048 2049 pf->debug_set = 1; 2050 level = pf->debug; 2051 2052 if ((pf->opts & PF_OPT_NOACTION) == 0) 2053 if (ioctl(dev, DIOCSETDEBUG, &level)) 2054 err(1, "DIOCSETDEBUG"); 2055 2056 if (pf->opts & PF_OPT_VERBOSE) 2057 printf("set debug %s\n", d); 2058 2059 return (0); 2060 } 2061 2062 int 2063 pfctl_load_debug(struct pfctl *pf, unsigned int level) 2064 { 2065 if (ioctl(pf->dev, DIOCSETDEBUG, &level)) { 2066 warnx("DIOCSETDEBUG"); 2067 return (1); 2068 } 2069 return (0); 2070 } 2071 2072 int 2073 pfctl_set_interface_flags(struct pfctl *pf, char *ifname, int flags, int how) 2074 { 2075 struct pfioc_iface pi; 2076 struct node_host *h = NULL, *n = NULL; 2077 2078 if ((loadopt & PFCTL_FLAG_OPTION) == 0) 2079 return (0); 2080 2081 bzero(&pi, sizeof(pi)); 2082 2083 pi.pfiio_flags = flags; 2084 2085 /* Make sure our cache matches the kernel. If we set or clear the flag 2086 * for a group this applies to all members. */ 2087 h = ifa_grouplookup(ifname, 0); 2088 for (n = h; n != NULL; n = n->next) 2089 pfctl_set_interface_flags(pf, n->ifname, flags, how); 2090 2091 if (strlcpy(pi.pfiio_name, ifname, sizeof(pi.pfiio_name)) >= 2092 sizeof(pi.pfiio_name)) 2093 errx(1, "pfctl_set_interface_flags: strlcpy"); 2094 2095 if ((pf->opts & PF_OPT_NOACTION) == 0) { 2096 if (how == 0) { 2097 if (ioctl(pf->dev, DIOCCLRIFFLAG, &pi)) 2098 err(1, "DIOCCLRIFFLAG"); 2099 } else { 2100 if (ioctl(pf->dev, DIOCSETIFFLAG, &pi)) 2101 err(1, "DIOCSETIFFLAG"); 2102 pfctl_check_skip_ifaces(ifname); 2103 } 2104 } 2105 return (0); 2106 } 2107 2108 void 2109 pfctl_debug(int dev, u_int32_t level, int opts) 2110 { 2111 if (ioctl(dev, DIOCSETDEBUG, &level)) 2112 err(1, "DIOCSETDEBUG"); 2113 if ((opts & PF_OPT_QUIET) == 0) { 2114 fprintf(stderr, "debug level set to '"); 2115 switch (level) { 2116 case PF_DEBUG_NONE: 2117 fprintf(stderr, "none"); 2118 break; 2119 case PF_DEBUG_URGENT: 2120 fprintf(stderr, "urgent"); 2121 break; 2122 case PF_DEBUG_MISC: 2123 fprintf(stderr, "misc"); 2124 break; 2125 case PF_DEBUG_NOISY: 2126 fprintf(stderr, "loud"); 2127 break; 2128 default: 2129 fprintf(stderr, "<invalid>"); 2130 break; 2131 } 2132 fprintf(stderr, "'\n"); 2133 } 2134 } 2135 2136 int 2137 pfctl_test_altqsupport(int dev, int opts) 2138 { 2139 struct pfioc_altq pa; 2140 2141 pa.version = PFIOC_ALTQ_VERSION; 2142 if (ioctl(dev, DIOCGETALTQS, &pa)) { 2143 if (errno == ENODEV) { 2144 if (opts & PF_OPT_VERBOSE) 2145 fprintf(stderr, "No ALTQ support in kernel\n" 2146 "ALTQ related functions disabled\n"); 2147 return (0); 2148 } else 2149 err(1, "DIOCGETALTQS"); 2150 } 2151 return (1); 2152 } 2153 2154 int 2155 pfctl_show_anchors(int dev, int opts, char *anchorname) 2156 { 2157 struct pfioc_ruleset pr; 2158 u_int32_t mnr, nr; 2159 2160 memset(&pr, 0, sizeof(pr)); 2161 memcpy(pr.path, anchorname, sizeof(pr.path)); 2162 if (ioctl(dev, DIOCGETRULESETS, &pr)) { 2163 if (errno == EINVAL) 2164 fprintf(stderr, "Anchor '%s' not found.\n", 2165 anchorname); 2166 else 2167 err(1, "DIOCGETRULESETS"); 2168 return (-1); 2169 } 2170 mnr = pr.nr; 2171 for (nr = 0; nr < mnr; ++nr) { 2172 char sub[MAXPATHLEN]; 2173 2174 pr.nr = nr; 2175 if (ioctl(dev, DIOCGETRULESET, &pr)) 2176 err(1, "DIOCGETRULESET"); 2177 if (!strcmp(pr.name, PF_RESERVED_ANCHOR)) 2178 continue; 2179 sub[0] = 0; 2180 if (pr.path[0]) { 2181 strlcat(sub, pr.path, sizeof(sub)); 2182 strlcat(sub, "/", sizeof(sub)); 2183 } 2184 strlcat(sub, pr.name, sizeof(sub)); 2185 if (sub[0] != '_' || (opts & PF_OPT_VERBOSE)) 2186 printf(" %s\n", sub); 2187 if ((opts & PF_OPT_VERBOSE) && pfctl_show_anchors(dev, opts, sub)) 2188 return (-1); 2189 } 2190 return (0); 2191 } 2192 2193 const char * 2194 pfctl_lookup_option(char *cmd, const char * const *list) 2195 { 2196 if (cmd != NULL && *cmd) 2197 for (; *list; list++) 2198 if (!strncmp(cmd, *list, strlen(cmd))) 2199 return (*list); 2200 return (NULL); 2201 } 2202 2203 int 2204 main(int argc, char *argv[]) 2205 { 2206 int error = 0; 2207 int ch; 2208 int mode = O_RDONLY; 2209 int opts = 0; 2210 int optimize = PF_OPTIMIZE_BASIC; 2211 char anchorname[MAXPATHLEN]; 2212 char *path; 2213 2214 if (argc < 2) 2215 usage(); 2216 2217 while ((ch = getopt(argc, argv, 2218 "a:AdD:eqf:F:ghi:k:K:mMnNOo:Pp:rRs:t:T:vx:z")) != -1) { 2219 switch (ch) { 2220 case 'a': 2221 anchoropt = optarg; 2222 break; 2223 case 'd': 2224 opts |= PF_OPT_DISABLE; 2225 mode = O_RDWR; 2226 break; 2227 case 'D': 2228 if (pfctl_cmdline_symset(optarg) < 0) 2229 warnx("could not parse macro definition %s", 2230 optarg); 2231 break; 2232 case 'e': 2233 opts |= PF_OPT_ENABLE; 2234 mode = O_RDWR; 2235 break; 2236 case 'q': 2237 opts |= PF_OPT_QUIET; 2238 break; 2239 case 'F': 2240 clearopt = pfctl_lookup_option(optarg, clearopt_list); 2241 if (clearopt == NULL) { 2242 warnx("Unknown flush modifier '%s'", optarg); 2243 usage(); 2244 } 2245 mode = O_RDWR; 2246 break; 2247 case 'i': 2248 ifaceopt = optarg; 2249 break; 2250 case 'k': 2251 if (state_killers >= 2) { 2252 warnx("can only specify -k twice"); 2253 usage(); 2254 /* NOTREACHED */ 2255 } 2256 state_kill[state_killers++] = optarg; 2257 mode = O_RDWR; 2258 break; 2259 case 'K': 2260 if (src_node_killers >= 2) { 2261 warnx("can only specify -K twice"); 2262 usage(); 2263 /* NOTREACHED */ 2264 } 2265 src_node_kill[src_node_killers++] = optarg; 2266 mode = O_RDWR; 2267 break; 2268 case 'm': 2269 opts |= PF_OPT_MERGE; 2270 break; 2271 case 'M': 2272 opts |= PF_OPT_KILLMATCH; 2273 break; 2274 case 'n': 2275 opts |= PF_OPT_NOACTION; 2276 break; 2277 case 'N': 2278 loadopt |= PFCTL_FLAG_NAT; 2279 break; 2280 case 'r': 2281 opts |= PF_OPT_USEDNS; 2282 break; 2283 case 'f': 2284 rulesopt = optarg; 2285 mode = O_RDWR; 2286 break; 2287 case 'g': 2288 opts |= PF_OPT_DEBUG; 2289 break; 2290 case 'A': 2291 loadopt |= PFCTL_FLAG_ALTQ; 2292 break; 2293 case 'R': 2294 loadopt |= PFCTL_FLAG_FILTER; 2295 break; 2296 case 'o': 2297 optiopt = pfctl_lookup_option(optarg, optiopt_list); 2298 if (optiopt == NULL) { 2299 warnx("Unknown optimization '%s'", optarg); 2300 usage(); 2301 } 2302 opts |= PF_OPT_OPTIMIZE; 2303 break; 2304 case 'O': 2305 loadopt |= PFCTL_FLAG_OPTION; 2306 break; 2307 case 'p': 2308 pf_device = optarg; 2309 break; 2310 case 'P': 2311 opts |= PF_OPT_NUMERIC; 2312 break; 2313 case 's': 2314 showopt = pfctl_lookup_option(optarg, showopt_list); 2315 if (showopt == NULL) { 2316 warnx("Unknown show modifier '%s'", optarg); 2317 usage(); 2318 } 2319 break; 2320 case 't': 2321 tableopt = optarg; 2322 break; 2323 case 'T': 2324 tblcmdopt = pfctl_lookup_option(optarg, tblcmdopt_list); 2325 if (tblcmdopt == NULL) { 2326 warnx("Unknown table command '%s'", optarg); 2327 usage(); 2328 } 2329 break; 2330 case 'v': 2331 if (opts & PF_OPT_VERBOSE) 2332 opts |= PF_OPT_VERBOSE2; 2333 opts |= PF_OPT_VERBOSE; 2334 break; 2335 case 'x': 2336 debugopt = pfctl_lookup_option(optarg, debugopt_list); 2337 if (debugopt == NULL) { 2338 warnx("Unknown debug level '%s'", optarg); 2339 usage(); 2340 } 2341 mode = O_RDWR; 2342 break; 2343 case 'z': 2344 opts |= PF_OPT_CLRRULECTRS; 2345 mode = O_RDWR; 2346 break; 2347 case 'h': 2348 /* FALLTHROUGH */ 2349 default: 2350 usage(); 2351 /* NOTREACHED */ 2352 } 2353 } 2354 2355 if (tblcmdopt != NULL) { 2356 argc -= optind; 2357 argv += optind; 2358 ch = *tblcmdopt; 2359 if (ch == 'l') { 2360 loadopt |= PFCTL_FLAG_TABLE; 2361 tblcmdopt = NULL; 2362 } else 2363 mode = strchr("acdefkrz", ch) ? O_RDWR : O_RDONLY; 2364 } else if (argc != optind) { 2365 warnx("unknown command line argument: %s ...", argv[optind]); 2366 usage(); 2367 /* NOTREACHED */ 2368 } 2369 if (loadopt == 0) 2370 loadopt = ~0; 2371 2372 if ((path = calloc(1, MAXPATHLEN)) == NULL) 2373 errx(1, "pfctl: calloc"); 2374 memset(anchorname, 0, sizeof(anchorname)); 2375 if (anchoropt != NULL) { 2376 int len = strlen(anchoropt); 2377 2378 if (anchoropt[len - 1] == '*') { 2379 if (len >= 2 && anchoropt[len - 2] == '/') 2380 anchoropt[len - 2] = '\0'; 2381 else 2382 anchoropt[len - 1] = '\0'; 2383 opts |= PF_OPT_RECURSE; 2384 } 2385 if (strlcpy(anchorname, anchoropt, 2386 sizeof(anchorname)) >= sizeof(anchorname)) 2387 errx(1, "anchor name '%s' too long", 2388 anchoropt); 2389 loadopt &= PFCTL_FLAG_FILTER|PFCTL_FLAG_NAT|PFCTL_FLAG_TABLE; 2390 } 2391 2392 if ((opts & PF_OPT_NOACTION) == 0) { 2393 dev = open(pf_device, mode); 2394 if (dev == -1) 2395 err(1, "%s", pf_device); 2396 altqsupport = pfctl_test_altqsupport(dev, opts); 2397 } else { 2398 dev = open(pf_device, O_RDONLY); 2399 if (dev >= 0) 2400 opts |= PF_OPT_DUMMYACTION; 2401 /* turn off options */ 2402 opts &= ~ (PF_OPT_DISABLE | PF_OPT_ENABLE); 2403 clearopt = showopt = debugopt = NULL; 2404 #if !defined(ENABLE_ALTQ) 2405 altqsupport = 0; 2406 #else 2407 altqsupport = 1; 2408 #endif 2409 } 2410 2411 if (opts & PF_OPT_DISABLE) 2412 if (pfctl_disable(dev, opts)) 2413 error = 1; 2414 2415 if (showopt != NULL) { 2416 switch (*showopt) { 2417 case 'A': 2418 pfctl_show_anchors(dev, opts, anchorname); 2419 break; 2420 case 'r': 2421 pfctl_load_fingerprints(dev, opts); 2422 pfctl_show_rules(dev, path, opts, PFCTL_SHOW_RULES, 2423 anchorname, 0); 2424 break; 2425 case 'l': 2426 pfctl_load_fingerprints(dev, opts); 2427 pfctl_show_rules(dev, path, opts, PFCTL_SHOW_LABELS, 2428 anchorname, 0); 2429 break; 2430 case 'n': 2431 pfctl_load_fingerprints(dev, opts); 2432 pfctl_show_nat(dev, opts, anchorname); 2433 break; 2434 case 'q': 2435 pfctl_show_altq(dev, ifaceopt, opts, 2436 opts & PF_OPT_VERBOSE2); 2437 break; 2438 case 's': 2439 pfctl_show_states(dev, ifaceopt, opts); 2440 break; 2441 case 'S': 2442 pfctl_show_src_nodes(dev, opts); 2443 break; 2444 case 'i': 2445 pfctl_show_status(dev, opts); 2446 break; 2447 case 'R': 2448 error = pfctl_show_running(dev); 2449 break; 2450 case 't': 2451 pfctl_show_timeouts(dev, opts); 2452 break; 2453 case 'm': 2454 pfctl_show_limits(dev, opts); 2455 break; 2456 case 'a': 2457 opts |= PF_OPT_SHOWALL; 2458 pfctl_load_fingerprints(dev, opts); 2459 2460 pfctl_show_nat(dev, opts, anchorname); 2461 pfctl_show_rules(dev, path, opts, 0, anchorname, 0); 2462 pfctl_show_altq(dev, ifaceopt, opts, 0); 2463 pfctl_show_states(dev, ifaceopt, opts); 2464 pfctl_show_src_nodes(dev, opts); 2465 pfctl_show_status(dev, opts); 2466 pfctl_show_rules(dev, path, opts, 1, anchorname, 0); 2467 pfctl_show_timeouts(dev, opts); 2468 pfctl_show_limits(dev, opts); 2469 pfctl_show_tables(anchorname, opts); 2470 pfctl_show_fingerprints(opts); 2471 break; 2472 case 'T': 2473 pfctl_show_tables(anchorname, opts); 2474 break; 2475 case 'o': 2476 pfctl_load_fingerprints(dev, opts); 2477 pfctl_show_fingerprints(opts); 2478 break; 2479 case 'I': 2480 pfctl_show_ifaces(ifaceopt, opts); 2481 break; 2482 } 2483 } 2484 2485 if ((opts & PF_OPT_CLRRULECTRS) && showopt == NULL) 2486 pfctl_show_rules(dev, path, opts, PFCTL_SHOW_NOTHING, 2487 anchorname, 0); 2488 2489 if (clearopt != NULL) { 2490 if (anchorname[0] == '_' || strstr(anchorname, "/_") != NULL) 2491 errx(1, "anchor names beginning with '_' cannot " 2492 "be modified from the command line"); 2493 2494 switch (*clearopt) { 2495 case 'r': 2496 pfctl_clear_rules(dev, opts, anchorname); 2497 break; 2498 case 'n': 2499 pfctl_clear_nat(dev, opts, anchorname); 2500 break; 2501 case 'q': 2502 pfctl_clear_altq(dev, opts); 2503 break; 2504 case 's': 2505 pfctl_clear_iface_states(dev, ifaceopt, opts); 2506 break; 2507 case 'S': 2508 pfctl_clear_src_nodes(dev, opts); 2509 break; 2510 case 'i': 2511 pfctl_clear_stats(dev, opts); 2512 break; 2513 case 'a': 2514 pfctl_clear_rules(dev, opts, anchorname); 2515 pfctl_clear_nat(dev, opts, anchorname); 2516 pfctl_clear_tables(anchorname, opts); 2517 if (!*anchorname) { 2518 pfctl_clear_altq(dev, opts); 2519 pfctl_clear_iface_states(dev, ifaceopt, opts); 2520 pfctl_clear_src_nodes(dev, opts); 2521 pfctl_clear_stats(dev, opts); 2522 pfctl_clear_fingerprints(dev, opts); 2523 pfctl_clear_interface_flags(dev, opts); 2524 } 2525 break; 2526 case 'o': 2527 pfctl_clear_fingerprints(dev, opts); 2528 break; 2529 case 'T': 2530 pfctl_clear_tables(anchorname, opts); 2531 break; 2532 } 2533 } 2534 if (state_killers) { 2535 if (!strcmp(state_kill[0], "label")) 2536 pfctl_label_kill_states(dev, ifaceopt, opts); 2537 else if (!strcmp(state_kill[0], "id")) 2538 pfctl_id_kill_states(dev, ifaceopt, opts); 2539 else if (!strcmp(state_kill[0], "gateway")) 2540 pfctl_gateway_kill_states(dev, ifaceopt, opts); 2541 else 2542 pfctl_net_kill_states(dev, ifaceopt, opts); 2543 } 2544 2545 if (src_node_killers) 2546 pfctl_kill_src_nodes(dev, ifaceopt, opts); 2547 2548 if (tblcmdopt != NULL) { 2549 error = pfctl_command_tables(argc, argv, tableopt, 2550 tblcmdopt, rulesopt, anchorname, opts); 2551 rulesopt = NULL; 2552 } 2553 if (optiopt != NULL) { 2554 switch (*optiopt) { 2555 case 'n': 2556 optimize = 0; 2557 break; 2558 case 'b': 2559 optimize |= PF_OPTIMIZE_BASIC; 2560 break; 2561 case 'o': 2562 case 'p': 2563 optimize |= PF_OPTIMIZE_PROFILE; 2564 break; 2565 } 2566 } 2567 2568 if ((rulesopt != NULL) && (loadopt & PFCTL_FLAG_OPTION) && 2569 !anchorname[0] && !(opts & PF_OPT_NOACTION)) 2570 if (pfctl_get_skip_ifaces()) 2571 error = 1; 2572 2573 if (rulesopt != NULL && !(opts & (PF_OPT_MERGE|PF_OPT_NOACTION)) && 2574 !anchorname[0] && (loadopt & PFCTL_FLAG_OPTION)) 2575 if (pfctl_file_fingerprints(dev, opts, PF_OSFP_FILE)) 2576 error = 1; 2577 2578 if (rulesopt != NULL) { 2579 if (anchorname[0] == '_' || strstr(anchorname, "/_") != NULL) 2580 errx(1, "anchor names beginning with '_' cannot " 2581 "be modified from the command line"); 2582 if (pfctl_rules(dev, rulesopt, opts, optimize, 2583 anchorname, NULL)) 2584 error = 1; 2585 else if (!(opts & PF_OPT_NOACTION) && 2586 (loadopt & PFCTL_FLAG_TABLE)) 2587 warn_namespace_collision(NULL); 2588 } 2589 2590 if (opts & PF_OPT_ENABLE) 2591 if (pfctl_enable(dev, opts)) 2592 error = 1; 2593 2594 if (debugopt != NULL) { 2595 switch (*debugopt) { 2596 case 'n': 2597 pfctl_debug(dev, PF_DEBUG_NONE, opts); 2598 break; 2599 case 'u': 2600 pfctl_debug(dev, PF_DEBUG_URGENT, opts); 2601 break; 2602 case 'm': 2603 pfctl_debug(dev, PF_DEBUG_MISC, opts); 2604 break; 2605 case 'l': 2606 pfctl_debug(dev, PF_DEBUG_NOISY, opts); 2607 break; 2608 } 2609 } 2610 2611 exit(error); 2612 } 2613