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