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