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