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