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