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