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