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