1 /* $OpenBSD: pfctl.c,v 1.213 2004/03/20 09:31:42 david Exp $ */ 2 3 /* 4 * Copyright (c) 2001 Daniel Hartmeier 5 * Copyright (c) 2002,2003 Henning Brauer 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * - Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * - Redistributions in binary form must reproduce the above 15 * copyright notice, this list of conditions and the following 16 * disclaimer in the documentation and/or other materials provided 17 * with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 22 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 23 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 25 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 26 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 29 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 * POSSIBILITY OF SUCH DAMAGE. 31 * 32 */ 33 34 #include <sys/types.h> 35 #include <sys/ioctl.h> 36 #include <sys/socket.h> 37 38 #include <net/if.h> 39 #include <netinet/in.h> 40 #include <net/pfvar.h> 41 #include <arpa/inet.h> 42 #include <altq/altq.h> 43 44 #include <err.h> 45 #include <errno.h> 46 #include <fcntl.h> 47 #include <limits.h> 48 #include <netdb.h> 49 #include <stdio.h> 50 #include <stdlib.h> 51 #include <string.h> 52 #include <unistd.h> 53 54 #include "pfctl_parser.h" 55 #include "pfctl.h" 56 57 void usage(void); 58 int pfctl_enable(int, int); 59 int pfctl_disable(int, int); 60 int pfctl_clear_stats(int, int); 61 int pfctl_clear_rules(int, int, char *, char *); 62 int pfctl_clear_nat(int, int, char *, char *); 63 int pfctl_clear_altq(int, int); 64 int pfctl_clear_src_nodes(int, int); 65 int pfctl_clear_states(int, const char *, int); 66 int pfctl_kill_states(int, const char *, int); 67 int pfctl_get_pool(int, struct pf_pool *, u_int32_t, u_int32_t, int, 68 char *, char *); 69 void pfctl_print_rule_counters(struct pf_rule *, int); 70 int pfctl_show_rules(int, int, int, char *, char *); 71 int pfctl_show_nat(int, int, char *, char *); 72 int pfctl_show_src_nodes(int, int); 73 int pfctl_show_states(int, const char *, int); 74 int pfctl_show_status(int, int); 75 int pfctl_show_timeouts(int, int); 76 int pfctl_show_limits(int, int); 77 int pfctl_debug(int, u_int32_t, int); 78 int pfctl_clear_rule_counters(int, int); 79 int pfctl_test_altqsupport(int, int); 80 int pfctl_show_anchors(int, int, char *); 81 const char *pfctl_lookup_option(char *, const char **); 82 83 const char *clearopt; 84 char *rulesopt; 85 const char *showopt; 86 const char *debugopt; 87 char *anchoropt; 88 char *pf_device = "/dev/pf"; 89 char *ifaceopt; 90 char *tableopt; 91 const char *tblcmdopt; 92 int state_killers; 93 char *state_kill[2]; 94 int loadopt; 95 int altqsupport; 96 97 int dev = -1; 98 int first_title = 1; 99 int labels = 0; 100 101 const char *infile; 102 103 static const struct { 104 const char *name; 105 int index; 106 } pf_limits[] = { 107 { "states", PF_LIMIT_STATES }, 108 { "src-nodes", PF_LIMIT_SRC_NODES }, 109 { "frags", PF_LIMIT_FRAGS }, 110 { NULL, 0 } 111 }; 112 113 struct pf_hint { 114 const char *name; 115 int timeout; 116 }; 117 static const struct pf_hint pf_hint_normal[] = { 118 { "tcp.first", 2 * 60 }, 119 { "tcp.opening", 30 }, 120 { "tcp.established", 24 * 60 * 60 }, 121 { "tcp.closing", 15 * 60 }, 122 { "tcp.finwait", 45 }, 123 { "tcp.closed", 90 }, 124 { NULL, 0 } 125 }; 126 static const struct pf_hint pf_hint_satellite[] = { 127 { "tcp.first", 3 * 60 }, 128 { "tcp.opening", 30 + 5 }, 129 { "tcp.established", 24 * 60 * 60 }, 130 { "tcp.closing", 15 * 60 + 5 }, 131 { "tcp.finwait", 45 + 5 }, 132 { "tcp.closed", 90 + 5 }, 133 { NULL, 0 } 134 }; 135 static const struct pf_hint pf_hint_conservative[] = { 136 { "tcp.first", 60 * 60 }, 137 { "tcp.opening", 15 * 60 }, 138 { "tcp.established", 5 * 24 * 60 * 60 }, 139 { "tcp.closing", 60 * 60 }, 140 { "tcp.finwait", 10 * 60 }, 141 { "tcp.closed", 3 * 60 }, 142 { NULL, 0 } 143 }; 144 static const struct pf_hint pf_hint_aggressive[] = { 145 { "tcp.first", 30 }, 146 { "tcp.opening", 5 }, 147 { "tcp.established", 5 * 60 * 60 }, 148 { "tcp.closing", 60 }, 149 { "tcp.finwait", 30 }, 150 { "tcp.closed", 30 }, 151 { NULL, 0 } 152 }; 153 154 static const struct { 155 const char *name; 156 const struct pf_hint *hint; 157 } pf_hints[] = { 158 { "normal", pf_hint_normal }, 159 { "satellite", pf_hint_satellite }, 160 { "high-latency", pf_hint_satellite }, 161 { "conservative", pf_hint_conservative }, 162 { "aggressive", pf_hint_aggressive }, 163 { NULL, NULL } 164 }; 165 166 static const char *clearopt_list[] = { 167 "nat", "queue", "rules", "Sources", 168 "state", "info", "Tables", "osfp", "all", NULL 169 }; 170 171 static const char *showopt_list[] = { 172 "nat", "queue", "rules", "Anchors", "Sources", "state", "info", 173 "Interfaces", "labels", "timeouts", "memory", "Tables", "osfp", 174 "all", NULL 175 }; 176 177 static const char *tblcmdopt_list[] = { 178 "kill", "flush", "add", "delete", "load", "replace", "show", 179 "test", "zero", NULL 180 }; 181 182 static const char *debugopt_list[] = { 183 "none", "urgent", "misc", "loud", NULL 184 }; 185 186 187 void 188 usage(void) 189 { 190 extern char *__progname; 191 192 fprintf(stderr, "usage: %s [-AdeghNnOqRrvz] ", __progname); 193 fprintf(stderr, "[-a anchor[:ruleset]] [-D macro=value]\n"); 194 fprintf(stderr, " "); 195 fprintf(stderr, "[-F modifier] [-f file] [-i interface] "); 196 fprintf(stderr, "[-k host] [-p device]\n"); 197 fprintf(stderr, " "); 198 fprintf(stderr, "[-s modifier] [-T command [address ...]] "); 199 fprintf(stderr, "[-t table] [-x level]\n"); 200 exit(1); 201 } 202 203 int 204 pfctl_enable(int dev, int opts) 205 { 206 if (ioctl(dev, DIOCSTART)) { 207 if (errno == EEXIST) 208 errx(1, "pf already enabled"); 209 else 210 err(1, "DIOCSTART"); 211 } 212 if ((opts & PF_OPT_QUIET) == 0) 213 fprintf(stderr, "pf enabled\n"); 214 215 if (altqsupport && ioctl(dev, DIOCSTARTALTQ)) 216 if (errno != EEXIST) 217 err(1, "DIOCSTARTALTQ"); 218 219 return (0); 220 } 221 222 int 223 pfctl_disable(int dev, int opts) 224 { 225 if (ioctl(dev, DIOCSTOP)) { 226 if (errno == ENOENT) 227 errx(1, "pf not enabled"); 228 else 229 err(1, "DIOCSTOP"); 230 } 231 if ((opts & PF_OPT_QUIET) == 0) 232 fprintf(stderr, "pf disabled\n"); 233 234 if (altqsupport && ioctl(dev, DIOCSTOPALTQ)) 235 if (errno != ENOENT) 236 err(1, "DIOCSTOPALTQ"); 237 238 return (0); 239 } 240 241 int 242 pfctl_clear_stats(int dev, int opts) 243 { 244 if (ioctl(dev, DIOCCLRSTATUS)) 245 err(1, "DIOCCLRSTATUS"); 246 if ((opts & PF_OPT_QUIET) == 0) 247 fprintf(stderr, "pf: statistics cleared\n"); 248 return (0); 249 } 250 251 int 252 pfctl_clear_rules(int dev, int opts, char *anchorname, char *rulesetname) 253 { 254 struct pfr_buffer t; 255 256 if (*anchorname && !*rulesetname) { 257 struct pfioc_ruleset pr; 258 int mnr, nr, r; 259 260 memset(&pr, 0, sizeof(pr)); 261 memcpy(pr.anchor, anchorname, sizeof(pr.anchor)); 262 if (ioctl(dev, DIOCGETRULESETS, &pr)) { 263 if (errno == EINVAL) 264 fprintf(stderr, "No rulesets in anchor '%s'.\n", 265 anchorname); 266 else 267 err(1, "DIOCGETRULESETS"); 268 return (-1); 269 } 270 mnr = pr.nr; 271 for (nr = mnr - 1; nr >= 0; --nr) { 272 pr.nr = nr; 273 if (ioctl(dev, DIOCGETRULESET, &pr)) 274 err(1, "DIOCGETRULESET"); 275 r = pfctl_clear_rules(dev, opts | PF_OPT_QUIET, 276 anchorname, pr.name); 277 if (r) 278 return (r); 279 } 280 if ((opts & PF_OPT_QUIET) == 0) 281 fprintf(stderr, "rules cleared\n"); 282 return (0); 283 } 284 memset(&t, 0, sizeof(t)); 285 t.pfrb_type = PFRB_TRANS; 286 if (pfctl_add_trans(&t, PF_RULESET_SCRUB, anchorname, rulesetname) || 287 pfctl_add_trans(&t, PF_RULESET_FILTER, anchorname, rulesetname) || 288 pfctl_trans(dev, &t, DIOCXBEGIN, 0) || 289 pfctl_trans(dev, &t, DIOCXCOMMIT, 0)) 290 err(1, "pfctl_clear_rules"); 291 if ((opts & PF_OPT_QUIET) == 0) 292 fprintf(stderr, "rules cleared\n"); 293 return (0); 294 } 295 296 int 297 pfctl_clear_nat(int dev, int opts, char *anchorname, char *rulesetname) 298 { 299 struct pfr_buffer t; 300 301 if (*anchorname && !*rulesetname) { 302 struct pfioc_ruleset pr; 303 int mnr, nr, r; 304 305 memset(&pr, 0, sizeof(pr)); 306 memcpy(pr.anchor, anchorname, sizeof(pr.anchor)); 307 if (ioctl(dev, DIOCGETRULESETS, &pr)) { 308 if (errno == EINVAL) 309 fprintf(stderr, "No rulesets in anchor '%s'.\n", 310 anchorname); 311 else 312 err(1, "DIOCGETRULESETS"); 313 return (-1); 314 } 315 mnr = pr.nr; 316 for (nr = mnr - 1; nr >= 0; --nr) { 317 pr.nr = nr; 318 if (ioctl(dev, DIOCGETRULESET, &pr)) 319 err(1, "DIOCGETRULESET"); 320 r = pfctl_clear_nat(dev, opts | PF_OPT_QUIET, 321 anchorname, pr.name); 322 if (r) 323 return (r); 324 } 325 if ((opts & PF_OPT_QUIET) == 0) 326 fprintf(stderr, "nat cleared\n"); 327 return (0); 328 } 329 memset(&t, 0, sizeof(t)); 330 t.pfrb_type = PFRB_TRANS; 331 if (pfctl_add_trans(&t, PF_RULESET_NAT, anchorname, rulesetname) || 332 pfctl_add_trans(&t, PF_RULESET_BINAT, anchorname, rulesetname) || 333 pfctl_add_trans(&t, PF_RULESET_RDR, anchorname, rulesetname) || 334 pfctl_trans(dev, &t, DIOCXBEGIN, 0) || 335 pfctl_trans(dev, &t, DIOCXCOMMIT, 0)) 336 err(1, "pfctl_clear_nat"); 337 if ((opts & PF_OPT_QUIET) == 0) 338 fprintf(stderr, "nat cleared\n"); 339 return (0); 340 } 341 342 int 343 pfctl_clear_altq(int dev, int opts) 344 { 345 struct pfr_buffer t; 346 347 if (!altqsupport) 348 return (-1); 349 memset(&t, 0, sizeof(t)); 350 t.pfrb_type = PFRB_TRANS; 351 if (pfctl_add_trans(&t, PF_RULESET_ALTQ, "", "") || 352 pfctl_trans(dev, &t, DIOCXBEGIN, 0) || 353 pfctl_trans(dev, &t, DIOCXCOMMIT, 0)) 354 err(1, "pfctl_clear_altq"); 355 if ((opts & PF_OPT_QUIET) == 0) 356 fprintf(stderr, "altq cleared\n"); 357 return (0); 358 } 359 360 int 361 pfctl_clear_src_nodes(int dev, int opts) 362 { 363 if (ioctl(dev, DIOCCLRSRCNODES)) 364 err(1, "DIOCCLRSRCNODES"); 365 if ((opts & PF_OPT_QUIET) == 0) 366 fprintf(stderr, "source tracking entries cleared\n"); 367 return (0); 368 } 369 370 int 371 pfctl_clear_states(int dev, const char *iface, int opts) 372 { 373 struct pfioc_state_kill psk; 374 375 memset(&psk, 0, sizeof(psk)); 376 if (iface != NULL && strlcpy(psk.psk_ifname, iface, 377 sizeof(psk.psk_ifname)) >= sizeof(psk.psk_ifname)) 378 errx(1, "invalid interface: %s", iface); 379 380 if (ioctl(dev, DIOCCLRSTATES, &psk)) 381 err(1, "DIOCCLRSTATES"); 382 if ((opts & PF_OPT_QUIET) == 0) 383 fprintf(stderr, "%d states cleared\n", psk.psk_af); 384 return (0); 385 } 386 387 int 388 pfctl_kill_states(int dev, const char *iface, int opts) 389 { 390 struct pfioc_state_kill psk; 391 struct addrinfo *res[2], *resp[2]; 392 struct sockaddr last_src, last_dst; 393 int killed, sources, dests; 394 int ret_ga; 395 396 killed = sources = dests = 0; 397 398 memset(&psk, 0, sizeof(psk)); 399 memset(&psk.psk_src.addr.v.a.mask, 0xff, 400 sizeof(psk.psk_src.addr.v.a.mask)); 401 memset(&last_src, 0xff, sizeof(last_src)); 402 memset(&last_dst, 0xff, sizeof(last_dst)); 403 if (iface != NULL && strlcpy(psk.psk_ifname, iface, 404 sizeof(psk.psk_ifname)) >= sizeof(psk.psk_ifname)) 405 errx(1, "invalid interface: %s", iface); 406 407 if ((ret_ga = getaddrinfo(state_kill[0], NULL, NULL, &res[0]))) { 408 errx(1, "getaddrinfo: %s", gai_strerror(ret_ga)); 409 /* NOTREACHED */ 410 } 411 for (resp[0] = res[0]; resp[0]; resp[0] = resp[0]->ai_next) { 412 if (resp[0]->ai_addr == NULL) 413 continue; 414 /* We get lots of duplicates. Catch the easy ones */ 415 if (memcmp(&last_src, resp[0]->ai_addr, sizeof(last_src)) == 0) 416 continue; 417 last_src = *(struct sockaddr *)resp[0]->ai_addr; 418 419 psk.psk_af = resp[0]->ai_family; 420 sources++; 421 422 if (psk.psk_af == AF_INET) 423 psk.psk_src.addr.v.a.addr.v4 = 424 ((struct sockaddr_in *)resp[0]->ai_addr)->sin_addr; 425 else if (psk.psk_af == AF_INET6) 426 psk.psk_src.addr.v.a.addr.v6 = 427 ((struct sockaddr_in6 *)resp[0]->ai_addr)-> 428 sin6_addr; 429 else 430 errx(1, "Unknown address family %d", psk.psk_af); 431 432 if (state_killers > 1) { 433 dests = 0; 434 memset(&psk.psk_dst.addr.v.a.mask, 0xff, 435 sizeof(psk.psk_dst.addr.v.a.mask)); 436 memset(&last_dst, 0xff, sizeof(last_dst)); 437 if ((ret_ga = getaddrinfo(state_kill[1], NULL, NULL, 438 &res[1]))) { 439 errx(1, "getaddrinfo: %s", 440 gai_strerror(ret_ga)); 441 /* NOTREACHED */ 442 } 443 for (resp[1] = res[1]; resp[1]; 444 resp[1] = resp[1]->ai_next) { 445 if (resp[1]->ai_addr == NULL) 446 continue; 447 if (psk.psk_af != resp[1]->ai_family) 448 continue; 449 450 if (memcmp(&last_dst, resp[1]->ai_addr, 451 sizeof(last_dst)) == 0) 452 continue; 453 last_dst = *(struct sockaddr *)resp[1]->ai_addr; 454 455 dests++; 456 457 if (psk.psk_af == AF_INET) 458 psk.psk_dst.addr.v.a.addr.v4 = 459 ((struct sockaddr_in *)resp[1]-> 460 ai_addr)->sin_addr; 461 else if (psk.psk_af == AF_INET6) 462 psk.psk_dst.addr.v.a.addr.v6 = 463 ((struct sockaddr_in6 *)resp[1]-> 464 ai_addr)->sin6_addr; 465 else 466 errx(1, "Unknown address family %d", 467 psk.psk_af); 468 469 if (ioctl(dev, DIOCKILLSTATES, &psk)) 470 err(1, "DIOCKILLSTATES"); 471 killed += psk.psk_af; 472 /* fixup psk.psk_af */ 473 psk.psk_af = resp[1]->ai_family; 474 } 475 freeaddrinfo(res[1]); 476 } else { 477 if (ioctl(dev, DIOCKILLSTATES, &psk)) 478 err(1, "DIOCKILLSTATES"); 479 killed += psk.psk_af; 480 /* fixup psk.psk_af */ 481 psk.psk_af = res[0]->ai_family; 482 } 483 } 484 485 freeaddrinfo(res[0]); 486 487 if ((opts & PF_OPT_QUIET) == 0) 488 fprintf(stderr, "killed %d states from %d sources and %d " 489 "destinations\n", killed, sources, dests); 490 return (0); 491 } 492 493 int 494 pfctl_get_pool(int dev, struct pf_pool *pool, u_int32_t nr, 495 u_int32_t ticket, int r_action, char *anchorname, char *rulesetname) 496 { 497 struct pfioc_pooladdr pp; 498 struct pf_pooladdr *pa; 499 u_int32_t pnr, mpnr; 500 501 memset(&pp, 0, sizeof(pp)); 502 memcpy(pp.anchor, anchorname, sizeof(pp.anchor)); 503 memcpy(pp.ruleset, rulesetname, sizeof(pp.ruleset)); 504 pp.r_action = r_action; 505 pp.r_num = nr; 506 pp.ticket = ticket; 507 if (ioctl(dev, DIOCGETADDRS, &pp)) { 508 warn("DIOCGETADDRS"); 509 return (-1); 510 } 511 mpnr = pp.nr; 512 TAILQ_INIT(&pool->list); 513 for (pnr = 0; pnr < mpnr; ++pnr) { 514 pp.nr = pnr; 515 if (ioctl(dev, DIOCGETADDR, &pp)) { 516 warn("DIOCGETADDR"); 517 return (-1); 518 } 519 pa = calloc(1, sizeof(struct pf_pooladdr)); 520 if (pa == NULL) 521 err(1, "calloc"); 522 bcopy(&pp.addr, pa, sizeof(struct pf_pooladdr)); 523 TAILQ_INSERT_TAIL(&pool->list, pa, entries); 524 } 525 526 return (0); 527 } 528 529 void 530 pfctl_clear_pool(struct pf_pool *pool) 531 { 532 struct pf_pooladdr *pa; 533 534 while ((pa = TAILQ_FIRST(&pool->list)) != NULL) { 535 TAILQ_REMOVE(&pool->list, pa, entries); 536 free(pa); 537 } 538 } 539 540 void 541 pfctl_print_rule_counters(struct pf_rule *rule, int opts) 542 { 543 if (opts & PF_OPT_DEBUG) { 544 const char *t[PF_SKIP_COUNT] = { "i", "d", "f", 545 "p", "sa", "sp", "da", "dp" }; 546 int i; 547 548 printf(" [ Skip steps: "); 549 for (i = 0; i < PF_SKIP_COUNT; ++i) { 550 if (rule->skip[i].nr == rule->nr + 1) 551 continue; 552 printf("%s=", t[i]); 553 if (rule->skip[i].nr == -1) 554 printf("end "); 555 else 556 printf("%u ", rule->skip[i].nr); 557 } 558 printf("]\n"); 559 560 printf(" [ queue: qname=%s qid=%u pqname=%s pqid=%u ]\n", 561 rule->qname, rule->qid, rule->pqname, rule->pqid); 562 } 563 if (opts & PF_OPT_VERBOSE) 564 printf(" [ Evaluations: %-8llu Packets: %-8llu " 565 "Bytes: %-10llu States: %-6u]\n", 566 (unsigned long long)rule->evaluations, 567 (unsigned long long)rule->packets, 568 (unsigned long long)rule->bytes, rule->states); 569 } 570 571 void 572 pfctl_print_title(char *title) 573 { 574 if (!first_title) 575 printf("\n"); 576 first_title = 0; 577 printf("%s\n", title); 578 } 579 580 int 581 pfctl_show_rules(int dev, int opts, int format, char *anchorname, 582 char *rulesetname) 583 { 584 struct pfioc_rule pr; 585 u_int32_t nr, mnr, header = 0; 586 int rule_numbers = opts & (PF_OPT_VERBOSE2 | PF_OPT_DEBUG); 587 588 if (*anchorname && !*rulesetname) { 589 struct pfioc_ruleset pr; 590 int r; 591 592 memset(&pr, 0, sizeof(pr)); 593 memcpy(pr.anchor, anchorname, sizeof(pr.anchor)); 594 if (ioctl(dev, DIOCGETRULESETS, &pr)) { 595 if (errno == EINVAL) 596 fprintf(stderr, "No rulesets in anchor '%s'.\n", 597 anchorname); 598 else 599 err(1, "DIOCGETRULESETS"); 600 return (-1); 601 } 602 if (opts & PF_OPT_SHOWALL && pr.nr) 603 pfctl_print_title("FILTER RULES:"); 604 mnr = pr.nr; 605 for (nr = 0; nr < mnr; ++nr) { 606 pr.nr = nr; 607 if (ioctl(dev, DIOCGETRULESET, &pr)) 608 err(1, "DIOCGETRULESET"); 609 r = pfctl_show_rules(dev, opts, format, anchorname, 610 pr.name); 611 if (r) 612 return (r); 613 } 614 return (0); 615 } 616 617 memset(&pr, 0, sizeof(pr)); 618 memcpy(pr.anchor, anchorname, sizeof(pr.anchor)); 619 memcpy(pr.ruleset, rulesetname, sizeof(pr.ruleset)); 620 if (opts & PF_OPT_SHOWALL) { 621 pr.rule.action = PF_PASS; 622 if (ioctl(dev, DIOCGETRULES, &pr)) { 623 warn("DIOCGETRULES"); 624 return (-1); 625 } 626 header++; 627 } 628 pr.rule.action = PF_SCRUB; 629 if (ioctl(dev, DIOCGETRULES, &pr)) { 630 warn("DIOCGETRULES"); 631 return (-1); 632 } 633 if (opts & PF_OPT_SHOWALL) { 634 if (format == 0 && (pr.nr > 0 || header)) 635 pfctl_print_title("FILTER RULES:"); 636 else if (format == 1 && labels) 637 pfctl_print_title("LABEL COUNTERS:"); 638 } 639 mnr = pr.nr; 640 for (nr = 0; nr < mnr; ++nr) { 641 pr.nr = nr; 642 if (ioctl(dev, DIOCGETRULE, &pr)) { 643 warn("DIOCGETRULE"); 644 return (-1); 645 } 646 647 if (pfctl_get_pool(dev, &pr.rule.rpool, 648 nr, pr.ticket, PF_SCRUB, anchorname, rulesetname) != 0) 649 return (-1); 650 651 switch (format) { 652 case 1: 653 if (pr.rule.label[0]) { 654 printf("%s ", pr.rule.label); 655 printf("%llu %llu %llu\n", 656 (unsigned long long)pr.rule.evaluations, 657 (unsigned long long)pr.rule.packets, 658 (unsigned long long)pr.rule.bytes); 659 } 660 break; 661 default: 662 if (pr.rule.label[0] && (opts & PF_OPT_SHOWALL)) 663 labels = 1; 664 print_rule(&pr.rule, rule_numbers); 665 pfctl_print_rule_counters(&pr.rule, opts); 666 } 667 pfctl_clear_pool(&pr.rule.rpool); 668 } 669 pr.rule.action = PF_PASS; 670 if (ioctl(dev, DIOCGETRULES, &pr)) { 671 warn("DIOCGETRULES"); 672 return (-1); 673 } 674 mnr = pr.nr; 675 for (nr = 0; nr < mnr; ++nr) { 676 pr.nr = nr; 677 if (ioctl(dev, DIOCGETRULE, &pr)) { 678 warn("DIOCGETRULE"); 679 return (-1); 680 } 681 682 if (pfctl_get_pool(dev, &pr.rule.rpool, 683 nr, pr.ticket, PF_PASS, anchorname, rulesetname) != 0) 684 return (-1); 685 686 switch (format) { 687 case 1: 688 if (pr.rule.label[0]) { 689 printf("%s ", pr.rule.label); 690 printf("%llu %llu %llu\n", 691 (unsigned long long)pr.rule.evaluations, 692 (unsigned long long)pr.rule.packets, 693 (unsigned long long)pr.rule.bytes); 694 } 695 break; 696 default: 697 if (pr.rule.label[0] && (opts & PF_OPT_SHOWALL)) 698 labels = 1; 699 print_rule(&pr.rule, rule_numbers); 700 pfctl_print_rule_counters(&pr.rule, opts); 701 } 702 pfctl_clear_pool(&pr.rule.rpool); 703 } 704 return (0); 705 } 706 707 int 708 pfctl_show_nat(int dev, int opts, char *anchorname, char *rulesetname) 709 { 710 struct pfioc_rule pr; 711 u_int32_t mnr, nr; 712 static int nattype[3] = { PF_NAT, PF_RDR, PF_BINAT }; 713 int i, dotitle = opts & PF_OPT_SHOWALL; 714 715 if (*anchorname && !*rulesetname) { 716 struct pfioc_ruleset pr; 717 int r; 718 719 memset(&pr, 0, sizeof(pr)); 720 memcpy(pr.anchor, anchorname, sizeof(pr.anchor)); 721 if (ioctl(dev, DIOCGETRULESETS, &pr)) { 722 if (errno == EINVAL) 723 fprintf(stderr, "No rulesets in anchor '%s'.\n", 724 anchorname); 725 else 726 err(1, "DIOCGETRULESETS"); 727 return (-1); 728 } 729 mnr = pr.nr; 730 for (nr = 0; nr < mnr; ++nr) { 731 pr.nr = nr; 732 if (ioctl(dev, DIOCGETRULESET, &pr)) 733 err(1, "DIOCGETRULESET"); 734 r = pfctl_show_nat(dev, opts, anchorname, pr.name); 735 if (r) 736 return (r); 737 } 738 return (0); 739 } 740 741 memset(&pr, 0, sizeof(pr)); 742 memcpy(pr.anchor, anchorname, sizeof(pr.anchor)); 743 memcpy(pr.ruleset, rulesetname, sizeof(pr.ruleset)); 744 for (i = 0; i < 3; i++) { 745 pr.rule.action = nattype[i]; 746 if (ioctl(dev, DIOCGETRULES, &pr)) { 747 warn("DIOCGETRULES"); 748 return (-1); 749 } 750 mnr = pr.nr; 751 for (nr = 0; nr < mnr; ++nr) { 752 pr.nr = nr; 753 if (ioctl(dev, DIOCGETRULE, &pr)) { 754 warn("DIOCGETRULE"); 755 return (-1); 756 } 757 if (pfctl_get_pool(dev, &pr.rule.rpool, nr, 758 pr.ticket, nattype[i], anchorname, 759 rulesetname) != 0) 760 return (-1); 761 if (dotitle) { 762 pfctl_print_title("TRANSLATION RULES:"); 763 dotitle = 0; 764 } 765 print_rule(&pr.rule, opts & PF_OPT_VERBOSE2); 766 pfctl_print_rule_counters(&pr.rule, opts); 767 pfctl_clear_pool(&pr.rule.rpool); 768 } 769 } 770 return (0); 771 } 772 773 int 774 pfctl_show_src_nodes(int dev, int opts) 775 { 776 struct pfioc_src_nodes psn; 777 struct pf_src_node *p; 778 char *inbuf = NULL, *newinbuf = NULL; 779 unsigned len = 0; 780 int i; 781 782 memset(&psn, 0, sizeof(psn)); 783 for (;;) { 784 psn.psn_len = len; 785 if (len) { 786 newinbuf = realloc(inbuf, len); 787 if (newinbuf == NULL) 788 err(1, "realloc"); 789 psn.psn_buf = inbuf = newinbuf; 790 } 791 if (ioctl(dev, DIOCGETSRCNODES, &psn) < 0) { 792 warn("DIOCGETSRCNODES"); 793 return (-1); 794 } 795 if (psn.psn_len + sizeof(struct pfioc_src_nodes) < len) 796 break; 797 if (len == 0 && psn.psn_len == 0) 798 return (0); 799 if (len == 0 && psn.psn_len != 0) 800 len = psn.psn_len; 801 if (psn.psn_len == 0) 802 return (0); /* no src_nodes */ 803 len *= 2; 804 } 805 p = psn.psn_src_nodes; 806 if (psn.psn_len > 0 && (opts & PF_OPT_SHOWALL)) 807 pfctl_print_title("SOURCE TRACKING NODES:"); 808 for (i = 0; i < psn.psn_len; i += sizeof(*p)) { 809 print_src_node(p, opts); 810 p++; 811 } 812 return (0); 813 } 814 815 int 816 pfctl_show_states(int dev, const char *iface, int opts) 817 { 818 struct pfioc_states ps; 819 struct pf_state *p; 820 char *inbuf = NULL, *newinbuf = NULL; 821 unsigned len = 0; 822 int i, dotitle = (opts & PF_OPT_SHOWALL); 823 824 memset(&ps, 0, sizeof(ps)); 825 for (;;) { 826 ps.ps_len = len; 827 if (len) { 828 newinbuf = realloc(inbuf, len); 829 if (newinbuf == NULL) 830 err(1, "realloc"); 831 ps.ps_buf = inbuf = newinbuf; 832 } 833 if (ioctl(dev, DIOCGETSTATES, &ps) < 0) { 834 warn("DIOCGETSTATES"); 835 return (-1); 836 } 837 if (ps.ps_len + sizeof(struct pfioc_states) < len) 838 break; 839 if (len == 0 && ps.ps_len == 0) 840 return (0); 841 if (len == 0 && ps.ps_len != 0) 842 len = ps.ps_len; 843 if (ps.ps_len == 0) 844 return (0); /* no states */ 845 len *= 2; 846 } 847 p = ps.ps_states; 848 for (i = 0; i < ps.ps_len; i += sizeof(*p), p++) { 849 if (iface != NULL && strcmp(p->u.ifname, iface)) 850 continue; 851 if (dotitle) { 852 pfctl_print_title("STATES:"); 853 dotitle = 0; 854 } 855 print_state(p, opts); 856 } 857 return (0); 858 } 859 860 int 861 pfctl_show_status(int dev, int opts) 862 { 863 struct pf_status status; 864 865 if (ioctl(dev, DIOCGETSTATUS, &status)) { 866 warn("DIOCGETSTATUS"); 867 return (-1); 868 } 869 if (opts & PF_OPT_SHOWALL) 870 pfctl_print_title("INFO:"); 871 print_status(&status, opts); 872 return (0); 873 } 874 875 int 876 pfctl_show_timeouts(int dev, int opts) 877 { 878 struct pfioc_tm pt; 879 int i; 880 881 if (opts & PF_OPT_SHOWALL) 882 pfctl_print_title("TIMEOUTS:"); 883 memset(&pt, 0, sizeof(pt)); 884 for (i = 0; pf_timeouts[i].name; i++) { 885 pt.timeout = pf_timeouts[i].timeout; 886 if (ioctl(dev, DIOCGETTIMEOUT, &pt)) 887 err(1, "DIOCGETTIMEOUT"); 888 printf("%-20s %10d", pf_timeouts[i].name, pt.seconds); 889 if (i >= PFTM_ADAPTIVE_START && i <= PFTM_ADAPTIVE_END) 890 printf(" states"); 891 else 892 printf("s"); 893 printf("\n"); 894 } 895 return (0); 896 897 } 898 899 int 900 pfctl_show_limits(int dev, int opts) 901 { 902 struct pfioc_limit pl; 903 int i; 904 905 if (opts & PF_OPT_SHOWALL) 906 pfctl_print_title("LIMITS:"); 907 memset(&pl, 0, sizeof(pl)); 908 for (i = 0; pf_limits[i].name; i++) { 909 pl.index = pf_limits[i].index; 910 if (ioctl(dev, DIOCGETLIMIT, &pl)) 911 err(1, "DIOCGETLIMIT"); 912 printf("%-10s ", pf_limits[i].name); 913 if (pl.limit == UINT_MAX) 914 printf("unlimited\n"); 915 else 916 printf("hard limit %6u\n", pl.limit); 917 } 918 return (0); 919 } 920 921 /* callbacks for rule/nat/rdr/addr */ 922 int 923 pfctl_add_pool(struct pfctl *pf, struct pf_pool *p, sa_family_t af) 924 { 925 struct pf_pooladdr *pa; 926 927 if ((pf->opts & PF_OPT_NOACTION) == 0) { 928 if (ioctl(pf->dev, DIOCBEGINADDRS, &pf->paddr)) 929 err(1, "DIOCBEGINADDRS"); 930 } 931 932 pf->paddr.af = af; 933 TAILQ_FOREACH(pa, &p->list, entries) { 934 memcpy(&pf->paddr.addr, pa, sizeof(struct pf_pooladdr)); 935 if ((pf->opts & PF_OPT_NOACTION) == 0) { 936 if (ioctl(pf->dev, DIOCADDADDR, &pf->paddr)) 937 err(1, "DIOCADDADDR"); 938 } 939 } 940 return (0); 941 } 942 943 int 944 pfctl_add_rule(struct pfctl *pf, struct pf_rule *r) 945 { 946 u_int8_t rs_num; 947 struct pfioc_rule pr; 948 949 switch (r->action) { 950 case PF_SCRUB: 951 if ((loadopt & PFCTL_FLAG_FILTER) == 0) 952 return (0); 953 rs_num = PF_RULESET_SCRUB; 954 break; 955 case PF_DROP: 956 case PF_PASS: 957 if ((loadopt & PFCTL_FLAG_FILTER) == 0) 958 return (0); 959 rs_num = PF_RULESET_FILTER; 960 break; 961 case PF_NAT: 962 case PF_NONAT: 963 if ((loadopt & PFCTL_FLAG_NAT) == 0) 964 return (0); 965 rs_num = PF_RULESET_NAT; 966 break; 967 case PF_RDR: 968 case PF_NORDR: 969 if ((loadopt & PFCTL_FLAG_NAT) == 0) 970 return (0); 971 rs_num = PF_RULESET_RDR; 972 break; 973 case PF_BINAT: 974 case PF_NOBINAT: 975 if ((loadopt & PFCTL_FLAG_NAT) == 0) 976 return (0); 977 rs_num = PF_RULESET_BINAT; 978 break; 979 default: 980 errx(1, "Invalid rule type"); 981 break; 982 } 983 984 if ((pf->opts & PF_OPT_NOACTION) == 0) { 985 bzero(&pr, sizeof(pr)); 986 if (strlcpy(pr.anchor, pf->anchor, sizeof(pr.anchor)) >= 987 sizeof(pr.anchor) || 988 strlcpy(pr.ruleset, pf->ruleset, sizeof(pr.ruleset)) >= 989 sizeof(pr.ruleset)) 990 errx(1, "pfctl_add_rule: strlcpy"); 991 if (pfctl_add_pool(pf, &r->rpool, r->af)) 992 return (1); 993 pr.ticket = pfctl_get_ticket(pf->trans, rs_num, pf->anchor, 994 pf->ruleset); 995 pr.pool_ticket = pf->paddr.ticket; 996 memcpy(&pr.rule, r, sizeof(pr.rule)); 997 if (ioctl(pf->dev, DIOCADDRULE, &pr)) 998 err(1, "DIOCADDRULE"); 999 } 1000 if (pf->opts & PF_OPT_VERBOSE) 1001 print_rule(r, pf->opts & PF_OPT_VERBOSE2); 1002 pfctl_clear_pool(&r->rpool); 1003 return (0); 1004 } 1005 1006 int 1007 pfctl_add_altq(struct pfctl *pf, struct pf_altq *a) 1008 { 1009 if (altqsupport && 1010 (loadopt & PFCTL_FLAG_ALTQ) != 0) { 1011 memcpy(&pf->paltq->altq, a, sizeof(struct pf_altq)); 1012 if ((pf->opts & PF_OPT_NOACTION) == 0) { 1013 if (ioctl(pf->dev, DIOCADDALTQ, pf->paltq)) { 1014 if (errno == ENXIO) 1015 errx(1, "qtype not configured"); 1016 else if (errno == ENODEV) 1017 errx(1, "%s: driver does not support " 1018 "altq", a->ifname); 1019 else 1020 err(1, "DIOCADDALTQ"); 1021 } 1022 } 1023 pfaltq_store(&pf->paltq->altq); 1024 } 1025 return (0); 1026 } 1027 1028 int 1029 pfctl_rules(int dev, char *filename, int opts, char *anchorname, 1030 char *rulesetname, struct pfr_buffer *trans) 1031 { 1032 #define ERR(x) do { warn(x); goto _error; } while(0) 1033 #define ERRX(x) do { warnx(x); goto _error; } while(0) 1034 1035 FILE *fin; 1036 struct pfr_buffer *t, buf; 1037 struct pfioc_altq pa; 1038 struct pfctl pf; 1039 struct pfr_table trs; 1040 int osize; 1041 1042 if (trans == NULL) { 1043 bzero(&buf, sizeof(buf)); 1044 buf.pfrb_type = PFRB_TRANS; 1045 t = &buf; 1046 osize = 0; 1047 } else { 1048 t = trans; 1049 osize = t->pfrb_size; 1050 } 1051 1052 memset(&pa, 0, sizeof(pa)); 1053 memset(&pf, 0, sizeof(pf)); 1054 memset(&trs, 0, sizeof(trs)); 1055 if (strlcpy(trs.pfrt_anchor, anchorname, 1056 sizeof(trs.pfrt_anchor)) >= sizeof(trs.pfrt_anchor) || 1057 strlcpy(trs.pfrt_ruleset, rulesetname, 1058 sizeof(trs.pfrt_ruleset)) >= sizeof(trs.pfrt_ruleset)) 1059 ERRX("pfctl_rules: strlcpy"); 1060 if (strcmp(filename, "-") == 0) { 1061 fin = stdin; 1062 infile = "stdin"; 1063 } else { 1064 if ((fin = fopen(filename, "r")) == NULL) { 1065 warn("%s", filename); 1066 return (1); 1067 } 1068 infile = filename; 1069 } 1070 pf.dev = dev; 1071 pf.opts = opts; 1072 pf.loadopt = loadopt; 1073 if (anchorname[0]) 1074 pf.loadopt &= ~PFCTL_FLAG_ALTQ; 1075 pf.paltq = &pa; 1076 pf.trans = t; 1077 pf.rule_nr = 0; 1078 pf.anchor = anchorname; 1079 pf.ruleset = rulesetname; 1080 1081 if ((opts & PF_OPT_NOACTION) == 0) { 1082 if ((pf.loadopt & PFCTL_FLAG_NAT) != 0) { 1083 if (pfctl_add_trans(t, PF_RULESET_NAT, anchorname, 1084 rulesetname) || 1085 pfctl_add_trans(t, PF_RULESET_BINAT, anchorname, 1086 rulesetname) || 1087 pfctl_add_trans(t, PF_RULESET_RDR, anchorname, 1088 rulesetname)) 1089 ERR("pfctl_rules"); 1090 } 1091 if (((altqsupport && (pf.loadopt & PFCTL_FLAG_ALTQ) != 0))) { 1092 if (pfctl_add_trans(t, PF_RULESET_ALTQ, anchorname, 1093 rulesetname)) 1094 ERR("pfctl_rules"); 1095 } 1096 if ((pf.loadopt & PFCTL_FLAG_FILTER) != 0) { 1097 if (pfctl_add_trans(t, PF_RULESET_SCRUB, anchorname, 1098 rulesetname) || 1099 pfctl_add_trans(t, PF_RULESET_FILTER, anchorname, 1100 rulesetname)) 1101 ERR("pfctl_rules"); 1102 } 1103 if (pf.loadopt & PFCTL_FLAG_TABLE) { 1104 if (pfctl_add_trans(t, PF_RULESET_TABLE, anchorname, 1105 rulesetname)) 1106 ERR("pfctl_rules"); 1107 } 1108 if (pfctl_trans(dev, t, DIOCXBEGIN, osize)) 1109 ERR("DIOCXBEGIN"); 1110 if (altqsupport && (pf.loadopt & PFCTL_FLAG_ALTQ)) 1111 pa.ticket = pfctl_get_ticket(t, PF_RULESET_ALTQ, 1112 anchorname, rulesetname); 1113 if (pf.loadopt & PFCTL_FLAG_TABLE) 1114 pf.tticket = pfctl_get_ticket(t, PF_RULESET_TABLE, 1115 anchorname, rulesetname); 1116 } 1117 if (parse_rules(fin, &pf) < 0) { 1118 if ((opts & PF_OPT_NOACTION) == 0) 1119 ERRX("Syntax error in config file: " 1120 "pf rules not loaded"); 1121 else 1122 goto _error; 1123 } 1124 if ((altqsupport && (pf.loadopt & PFCTL_FLAG_ALTQ) != 0)) 1125 if (check_commit_altq(dev, opts) != 0) 1126 ERRX("errors in altq config"); 1127 if (fin != stdin) 1128 fclose(fin); 1129 1130 /* process "load anchor" directives */ 1131 if (!anchorname[0] && !rulesetname[0]) 1132 if (pfctl_load_anchors(dev, opts, t) == -1) 1133 ERRX("load anchors"); 1134 1135 if (trans == NULL && (opts & PF_OPT_NOACTION) == 0) 1136 if (pfctl_trans(dev, t, DIOCXCOMMIT, 0)) 1137 ERR("DIOCXCOMMIT"); 1138 return (0); 1139 1140 _error: 1141 if (trans == NULL) { /* main ruleset */ 1142 if ((opts & PF_OPT_NOACTION) == 0) 1143 if (pfctl_trans(dev, t, DIOCXROLLBACK, 0)) 1144 err(1, "DIOCXROLLBACK"); 1145 exit(1); 1146 } else /* sub ruleset */ 1147 return (-1); 1148 1149 #undef ERR 1150 #undef ERRX 1151 } 1152 1153 int 1154 pfctl_set_limit(struct pfctl *pf, const char *opt, unsigned int limit) 1155 { 1156 struct pfioc_limit pl; 1157 int i; 1158 1159 if ((loadopt & PFCTL_FLAG_OPTION) == 0) 1160 return (0); 1161 1162 memset(&pl, 0, sizeof(pl)); 1163 for (i = 0; pf_limits[i].name; i++) { 1164 if (strcasecmp(opt, pf_limits[i].name) == 0) { 1165 pl.index = pf_limits[i].index; 1166 pl.limit = limit; 1167 if ((pf->opts & PF_OPT_NOACTION) == 0) { 1168 if (ioctl(pf->dev, DIOCSETLIMIT, &pl)) { 1169 if (errno == EBUSY) { 1170 warnx("Current pool " 1171 "size exceeds requested " 1172 "hard limit"); 1173 return (1); 1174 } else 1175 err(1, "DIOCSETLIMIT"); 1176 } 1177 } 1178 break; 1179 } 1180 } 1181 if (pf_limits[i].name == NULL) { 1182 warnx("Bad pool name."); 1183 return (1); 1184 } 1185 1186 if (pf->opts & PF_OPT_VERBOSE) 1187 printf("set limit %s %d\n", opt, limit); 1188 1189 return (0); 1190 } 1191 1192 int 1193 pfctl_set_timeout(struct pfctl *pf, const char *opt, int seconds, int quiet) 1194 { 1195 struct pfioc_tm pt; 1196 int i; 1197 1198 if ((loadopt & PFCTL_FLAG_OPTION) == 0) 1199 return (0); 1200 1201 memset(&pt, 0, sizeof(pt)); 1202 for (i = 0; pf_timeouts[i].name; i++) { 1203 if (strcasecmp(opt, pf_timeouts[i].name) == 0) { 1204 pt.timeout = pf_timeouts[i].timeout; 1205 break; 1206 } 1207 } 1208 1209 if (pf_timeouts[i].name == NULL) { 1210 warnx("Bad timeout name."); 1211 return (1); 1212 } 1213 1214 pt.seconds = seconds; 1215 if ((pf->opts & PF_OPT_NOACTION) == 0) { 1216 if (ioctl(pf->dev, DIOCSETTIMEOUT, &pt)) 1217 err(1, "DIOCSETTIMEOUT"); 1218 } 1219 1220 if (pf->opts & PF_OPT_VERBOSE && ! quiet) 1221 printf("set timeout %s %d\n", opt, seconds); 1222 1223 return (0); 1224 } 1225 1226 int 1227 pfctl_set_optimization(struct pfctl *pf, const char *opt) 1228 { 1229 const struct pf_hint *hint; 1230 int i, r; 1231 1232 if ((loadopt & PFCTL_FLAG_OPTION) == 0) 1233 return (0); 1234 1235 for (i = 0; pf_hints[i].name; i++) 1236 if (strcasecmp(opt, pf_hints[i].name) == 0) 1237 break; 1238 1239 hint = pf_hints[i].hint; 1240 if (hint == NULL) { 1241 warnx("Bad hint name."); 1242 return (1); 1243 } 1244 1245 for (i = 0; hint[i].name; i++) 1246 if ((r = pfctl_set_timeout(pf, hint[i].name, 1247 hint[i].timeout, 1))) 1248 return (r); 1249 1250 if (pf->opts & PF_OPT_VERBOSE) 1251 printf("set optimization %s\n", opt); 1252 1253 return (0); 1254 } 1255 1256 int 1257 pfctl_set_logif(struct pfctl *pf, char *ifname) 1258 { 1259 struct pfioc_if pi; 1260 1261 if ((loadopt & PFCTL_FLAG_OPTION) == 0) 1262 return (0); 1263 1264 memset(&pi, 0, sizeof(pi)); 1265 if ((pf->opts & PF_OPT_NOACTION) == 0) { 1266 if (!strcmp(ifname, "none")) 1267 bzero(pi.ifname, sizeof(pi.ifname)); 1268 else { 1269 if (strlcpy(pi.ifname, ifname, 1270 sizeof(pi.ifname)) >= sizeof(pi.ifname)) 1271 errx(1, "pfctl_set_logif: strlcpy"); 1272 } 1273 if (ioctl(pf->dev, DIOCSETSTATUSIF, &pi)) 1274 err(1, "DIOCSETSTATUSIF"); 1275 } 1276 1277 if (pf->opts & PF_OPT_VERBOSE) 1278 printf("set loginterface %s\n", ifname); 1279 1280 return (0); 1281 } 1282 1283 int 1284 pfctl_set_hostid(struct pfctl *pf, u_int32_t hostid) 1285 { 1286 if ((loadopt & PFCTL_FLAG_OPTION) == 0) 1287 return (0); 1288 1289 HTONL(hostid); 1290 1291 if ((pf->opts & PF_OPT_NOACTION) == 0) 1292 if (ioctl(dev, DIOCSETHOSTID, &hostid)) 1293 err(1, "DIOCSETHOSTID"); 1294 1295 if (pf->opts & PF_OPT_VERBOSE) 1296 printf("set hostid 0x%08x\n", ntohl(hostid)); 1297 1298 return (0); 1299 } 1300 1301 int 1302 pfctl_set_debug(struct pfctl *pf, char *d) 1303 { 1304 u_int32_t level; 1305 1306 if ((loadopt & PFCTL_FLAG_OPTION) == 0) 1307 return (0); 1308 1309 if (!strcmp(d, "none")) 1310 level = PF_DEBUG_NONE; 1311 else if (!strcmp(d, "urgent")) 1312 level = PF_DEBUG_URGENT; 1313 else if (!strcmp(d, "misc")) 1314 level = PF_DEBUG_MISC; 1315 else if (!strcmp(d, "loud")) 1316 level = PF_DEBUG_NOISY; 1317 else { 1318 warnx("unknown debug level \"%s\"", d); 1319 return (-1); 1320 } 1321 1322 if ((pf->opts & PF_OPT_NOACTION) == 0) 1323 if (ioctl(dev, DIOCSETDEBUG, &level)) 1324 err(1, "DIOCSETDEBUG"); 1325 1326 if (pf->opts & PF_OPT_VERBOSE) 1327 printf("set debug %s\n", d); 1328 1329 return (0); 1330 } 1331 1332 int 1333 pfctl_debug(int dev, u_int32_t level, int opts) 1334 { 1335 if (ioctl(dev, DIOCSETDEBUG, &level)) 1336 err(1, "DIOCSETDEBUG"); 1337 if ((opts & PF_OPT_QUIET) == 0) { 1338 fprintf(stderr, "debug level set to '"); 1339 switch (level) { 1340 case PF_DEBUG_NONE: 1341 fprintf(stderr, "none"); 1342 break; 1343 case PF_DEBUG_URGENT: 1344 fprintf(stderr, "urgent"); 1345 break; 1346 case PF_DEBUG_MISC: 1347 fprintf(stderr, "misc"); 1348 break; 1349 case PF_DEBUG_NOISY: 1350 fprintf(stderr, "loud"); 1351 break; 1352 default: 1353 fprintf(stderr, "<invalid>"); 1354 break; 1355 } 1356 fprintf(stderr, "'\n"); 1357 } 1358 return (0); 1359 } 1360 1361 int 1362 pfctl_clear_rule_counters(int dev, int opts) 1363 { 1364 if (ioctl(dev, DIOCCLRRULECTRS)) 1365 err(1, "DIOCCLRRULECTRS"); 1366 if ((opts & PF_OPT_QUIET) == 0) 1367 fprintf(stderr, "pf: rule counters cleared\n"); 1368 return (0); 1369 } 1370 1371 int 1372 pfctl_test_altqsupport(int dev, int opts) 1373 { 1374 struct pfioc_altq pa; 1375 1376 if (ioctl(dev, DIOCGETALTQS, &pa)) { 1377 if (errno == ENODEV) { 1378 if (!(opts & PF_OPT_QUIET)) 1379 fprintf(stderr, "No ALTQ support in kernel\n" 1380 "ALTQ related functions disabled\n"); 1381 return (0); 1382 } else 1383 err(1, "DIOCGETALTQS"); 1384 } 1385 return (1); 1386 } 1387 1388 int 1389 pfctl_show_anchors(int dev, int opts, char *anchorname) 1390 { 1391 u_int32_t nr, mnr; 1392 1393 if (!*anchorname) { 1394 struct pfioc_anchor pa; 1395 1396 memset(&pa, 0, sizeof(pa)); 1397 if (ioctl(dev, DIOCGETANCHORS, &pa)) { 1398 warn("DIOCGETANCHORS"); 1399 return (-1); 1400 } 1401 mnr = pa.nr; 1402 for (nr = 0; nr < mnr; ++nr) { 1403 pa.nr = nr; 1404 if (ioctl(dev, DIOCGETANCHOR, &pa)) { 1405 warn("DIOCGETANCHOR"); 1406 return (-1); 1407 } 1408 if (!(opts & PF_OPT_VERBOSE) && 1409 !strcmp(pa.name, PF_RESERVED_ANCHOR)) 1410 continue; 1411 printf(" %s\n", pa.name); 1412 } 1413 } else { 1414 struct pfioc_ruleset pr; 1415 1416 memset(&pr, 0, sizeof(pr)); 1417 memcpy(pr.anchor, anchorname, sizeof(pr.anchor)); 1418 if (ioctl(dev, DIOCGETRULESETS, &pr)) { 1419 if (errno == EINVAL) 1420 fprintf(stderr, "No rulesets in anchor '%s'.\n", 1421 anchorname); 1422 else 1423 err(1, "DIOCGETRULESETS"); 1424 return (-1); 1425 } 1426 mnr = pr.nr; 1427 for (nr = 0; nr < mnr; ++nr) { 1428 pr.nr = nr; 1429 if (ioctl(dev, DIOCGETRULESET, &pr)) 1430 err(1, "DIOCGETRULESET"); 1431 printf(" %s:%s\n", pr.anchor, pr.name); 1432 } 1433 } 1434 return (0); 1435 } 1436 1437 const char * 1438 pfctl_lookup_option(char *cmd, const char **list) 1439 { 1440 if (cmd != NULL && *cmd) 1441 for (; *list; list++) 1442 if (!strncmp(cmd, *list, strlen(cmd))) 1443 return (*list); 1444 return (NULL); 1445 } 1446 1447 int 1448 main(int argc, char *argv[]) 1449 { 1450 int error = 0; 1451 int ch; 1452 int mode = O_RDONLY; 1453 int opts = 0; 1454 char anchorname[PF_ANCHOR_NAME_SIZE]; 1455 char rulesetname[PF_RULESET_NAME_SIZE]; 1456 1457 if (argc < 2) 1458 usage(); 1459 1460 while ((ch = getopt(argc, argv, 1461 "a:AdD:eqf:F:ghi:k:nNOp:rRs:t:T:vx:z")) != -1) { 1462 switch (ch) { 1463 case 'a': 1464 anchoropt = optarg; 1465 break; 1466 case 'd': 1467 opts |= PF_OPT_DISABLE; 1468 mode = O_RDWR; 1469 break; 1470 case 'D': 1471 if (pfctl_cmdline_symset(optarg) < 0) 1472 warnx("could not parse macro definition %s", 1473 optarg); 1474 break; 1475 case 'e': 1476 opts |= PF_OPT_ENABLE; 1477 mode = O_RDWR; 1478 break; 1479 case 'q': 1480 opts |= PF_OPT_QUIET; 1481 break; 1482 case 'F': 1483 clearopt = pfctl_lookup_option(optarg, clearopt_list); 1484 if (clearopt == NULL) { 1485 warnx("Unknown flush modifier '%s'", optarg); 1486 usage(); 1487 } 1488 mode = O_RDWR; 1489 break; 1490 case 'i': 1491 ifaceopt = optarg; 1492 break; 1493 case 'k': 1494 if (state_killers >= 2) { 1495 warnx("can only specify -k twice"); 1496 usage(); 1497 /* NOTREACHED */ 1498 } 1499 state_kill[state_killers++] = optarg; 1500 mode = O_RDWR; 1501 break; 1502 case 'n': 1503 opts |= PF_OPT_NOACTION; 1504 break; 1505 case 'N': 1506 loadopt |= PFCTL_FLAG_NAT; 1507 break; 1508 case 'r': 1509 opts |= PF_OPT_USEDNS; 1510 break; 1511 case 'f': 1512 rulesopt = optarg; 1513 mode = O_RDWR; 1514 break; 1515 case 'g': 1516 opts |= PF_OPT_DEBUG; 1517 break; 1518 case 'A': 1519 loadopt |= PFCTL_FLAG_ALTQ; 1520 break; 1521 case 'R': 1522 loadopt |= PFCTL_FLAG_FILTER; 1523 break; 1524 case 'O': 1525 loadopt |= PFCTL_FLAG_OPTION; 1526 break; 1527 case 'p': 1528 pf_device = optarg; 1529 break; 1530 case 's': 1531 showopt = pfctl_lookup_option(optarg, showopt_list); 1532 if (showopt == NULL) { 1533 warnx("Unknown show modifier '%s'", optarg); 1534 usage(); 1535 } 1536 break; 1537 case 't': 1538 tableopt = optarg; 1539 break; 1540 case 'T': 1541 tblcmdopt = pfctl_lookup_option(optarg, tblcmdopt_list); 1542 if (tblcmdopt == NULL) { 1543 warnx("Unknown table command '%s'", optarg); 1544 usage(); 1545 } 1546 break; 1547 case 'v': 1548 if (opts & PF_OPT_VERBOSE) 1549 opts |= PF_OPT_VERBOSE2; 1550 opts |= PF_OPT_VERBOSE; 1551 break; 1552 case 'x': 1553 debugopt = pfctl_lookup_option(optarg, debugopt_list); 1554 if (debugopt == NULL) { 1555 warnx("Unknown debug level '%s'", optarg); 1556 usage(); 1557 } 1558 mode = O_RDWR; 1559 break; 1560 case 'z': 1561 opts |= PF_OPT_CLRRULECTRS; 1562 mode = O_RDWR; 1563 break; 1564 case 'h': 1565 /* FALLTHROUGH */ 1566 default: 1567 usage(); 1568 /* NOTREACHED */ 1569 } 1570 } 1571 1572 if (tblcmdopt != NULL) { 1573 argc -= optind; 1574 argv += optind; 1575 ch = *tblcmdopt; 1576 if (ch == 'l') { 1577 loadopt |= PFCTL_FLAG_TABLE; 1578 tblcmdopt = NULL; 1579 } else 1580 mode = strchr("acdfkrz", ch) ? O_RDWR : O_RDONLY; 1581 } else if (argc != optind) { 1582 warnx("unknown command line argument: %s ...", argv[optind]); 1583 usage(); 1584 /* NOTREACHED */ 1585 } 1586 if (loadopt == 0) 1587 loadopt = ~0; 1588 1589 memset(anchorname, 0, sizeof(anchorname)); 1590 memset(rulesetname, 0, sizeof(rulesetname)); 1591 if (anchoropt != NULL) { 1592 char *t; 1593 1594 if ((t = strchr(anchoropt, ':')) == NULL) { 1595 if (strlcpy(anchorname, anchoropt, 1596 sizeof(anchorname)) >= sizeof(anchorname)) 1597 errx(1, "anchor name '%s' too long", 1598 anchoropt); 1599 } else { 1600 char *p; 1601 1602 if ((p = strdup(anchoropt)) == NULL) 1603 err(1, "anchoropt: strdup"); 1604 t = strsep(&p, ":"); 1605 if (*t == '\0' || *p == '\0') 1606 errx(1, "anchor '%s' invalid", anchoropt); 1607 if (strlcpy(anchorname, t, sizeof(anchorname)) >= 1608 sizeof(anchorname)) 1609 errx(1, "anchor name '%s' too long", t); 1610 if (strlcpy(rulesetname, p, sizeof(rulesetname)) >= 1611 sizeof(rulesetname)) 1612 errx(1, "ruleset name '%s' too long", p); 1613 free(t); /* not p */ 1614 } 1615 loadopt &= PFCTL_FLAG_FILTER|PFCTL_FLAG_NAT|PFCTL_FLAG_TABLE; 1616 } 1617 1618 if ((opts & PF_OPT_NOACTION) == 0) { 1619 dev = open(pf_device, mode); 1620 if (dev == -1) 1621 err(1, "%s", pf_device); 1622 altqsupport = pfctl_test_altqsupport(dev, opts); 1623 } else { 1624 dev = open(pf_device, O_RDONLY); 1625 if (dev >= 0) 1626 opts |= PF_OPT_DUMMYACTION; 1627 /* turn off options */ 1628 opts &= ~ (PF_OPT_DISABLE | PF_OPT_ENABLE); 1629 clearopt = showopt = debugopt = NULL; 1630 altqsupport = 1; 1631 } 1632 1633 if (opts & PF_OPT_DISABLE) 1634 if (pfctl_disable(dev, opts)) 1635 error = 1; 1636 1637 if (showopt != NULL) { 1638 switch (*showopt) { 1639 case 'A': 1640 pfctl_show_anchors(dev, opts, anchorname); 1641 break; 1642 case 'r': 1643 pfctl_load_fingerprints(dev, opts); 1644 pfctl_show_rules(dev, opts, 0, anchorname, 1645 rulesetname); 1646 break; 1647 case 'l': 1648 pfctl_load_fingerprints(dev, opts); 1649 pfctl_show_rules(dev, opts, 1, anchorname, 1650 rulesetname); 1651 break; 1652 case 'n': 1653 pfctl_load_fingerprints(dev, opts); 1654 pfctl_show_nat(dev, opts, anchorname, rulesetname); 1655 break; 1656 case 'q': 1657 pfctl_show_altq(dev, ifaceopt, opts, 1658 opts & PF_OPT_VERBOSE2); 1659 break; 1660 case 's': 1661 pfctl_show_states(dev, ifaceopt, opts); 1662 break; 1663 case 'S': 1664 pfctl_show_src_nodes(dev, opts); 1665 break; 1666 case 'i': 1667 pfctl_show_status(dev, opts); 1668 break; 1669 case 't': 1670 pfctl_show_timeouts(dev, opts); 1671 break; 1672 case 'm': 1673 pfctl_show_limits(dev, opts); 1674 break; 1675 case 'a': 1676 opts |= PF_OPT_SHOWALL; 1677 pfctl_load_fingerprints(dev, opts); 1678 1679 pfctl_show_nat(dev, opts, anchorname, rulesetname); 1680 pfctl_show_rules(dev, opts, 0, anchorname, 1681 rulesetname); 1682 pfctl_show_altq(dev, ifaceopt, opts, 0); 1683 pfctl_show_states(dev, ifaceopt, opts); 1684 pfctl_show_src_nodes(dev, opts); 1685 pfctl_show_status(dev, opts); 1686 pfctl_show_rules(dev, opts, 1, anchorname, rulesetname); 1687 pfctl_show_timeouts(dev, opts); 1688 pfctl_show_limits(dev, opts); 1689 pfctl_show_tables(anchorname, rulesetname, opts); 1690 pfctl_show_fingerprints(opts); 1691 break; 1692 case 'T': 1693 pfctl_show_tables(anchorname, rulesetname, opts); 1694 break; 1695 case 'o': 1696 pfctl_load_fingerprints(dev, opts); 1697 pfctl_show_fingerprints(opts); 1698 break; 1699 case 'I': 1700 pfctl_show_ifaces(ifaceopt, opts); 1701 break; 1702 } 1703 } 1704 1705 if (clearopt != NULL) { 1706 switch (*clearopt) { 1707 case 'r': 1708 pfctl_clear_rules(dev, opts, anchorname, rulesetname); 1709 break; 1710 case 'n': 1711 pfctl_clear_nat(dev, opts, anchorname, rulesetname); 1712 break; 1713 case 'q': 1714 pfctl_clear_altq(dev, opts); 1715 break; 1716 case 's': 1717 pfctl_clear_states(dev, ifaceopt, opts); 1718 break; 1719 case 'S': 1720 pfctl_clear_src_nodes(dev, opts); 1721 break; 1722 case 'i': 1723 pfctl_clear_stats(dev, opts); 1724 break; 1725 case 'a': 1726 pfctl_clear_rules(dev, opts, anchorname, rulesetname); 1727 pfctl_clear_nat(dev, opts, anchorname, rulesetname); 1728 pfctl_clear_tables(anchorname, rulesetname, opts); 1729 if (!*anchorname && !*rulesetname) { 1730 pfctl_clear_altq(dev, opts); 1731 pfctl_clear_states(dev, ifaceopt, opts); 1732 pfctl_clear_src_nodes(dev, opts); 1733 pfctl_clear_stats(dev, opts); 1734 pfctl_clear_fingerprints(dev, opts); 1735 } 1736 break; 1737 case 'o': 1738 pfctl_clear_fingerprints(dev, opts); 1739 break; 1740 case 'T': 1741 pfctl_clear_tables(anchorname, rulesetname, opts); 1742 break; 1743 } 1744 } 1745 if (state_killers) 1746 pfctl_kill_states(dev, ifaceopt, opts); 1747 1748 if (tblcmdopt != NULL) { 1749 error = pfctl_command_tables(argc, argv, tableopt, 1750 tblcmdopt, rulesopt, anchorname, rulesetname, opts); 1751 rulesopt = NULL; 1752 } 1753 1754 if (rulesopt != NULL) 1755 if (pfctl_file_fingerprints(dev, opts, PF_OSFP_FILE)) 1756 error = 1; 1757 1758 if (rulesopt != NULL) { 1759 if (pfctl_rules(dev, rulesopt, opts, anchorname, rulesetname, 1760 NULL)) 1761 error = 1; 1762 else if (!(opts & PF_OPT_NOACTION) && 1763 (loadopt & PFCTL_FLAG_TABLE)) 1764 warn_namespace_collision(NULL); 1765 } 1766 1767 if (opts & PF_OPT_ENABLE) 1768 if (pfctl_enable(dev, opts)) 1769 error = 1; 1770 1771 if (debugopt != NULL) { 1772 switch (*debugopt) { 1773 case 'n': 1774 pfctl_debug(dev, PF_DEBUG_NONE, opts); 1775 break; 1776 case 'u': 1777 pfctl_debug(dev, PF_DEBUG_URGENT, opts); 1778 break; 1779 case 'm': 1780 pfctl_debug(dev, PF_DEBUG_MISC, opts); 1781 break; 1782 case 'l': 1783 pfctl_debug(dev, PF_DEBUG_NOISY, opts); 1784 break; 1785 } 1786 } 1787 1788 if (opts & PF_OPT_CLRRULECTRS) { 1789 if (pfctl_clear_rule_counters(dev, opts)) 1790 error = 1; 1791 } 1792 exit(error); 1793 } 1794