diff options
Diffstat (limited to 'sbin/pfctl/pfctl.c')
-rw-r--r-- | sbin/pfctl/pfctl.c | 912 |
1 files changed, 746 insertions, 166 deletions
diff --git a/sbin/pfctl/pfctl.c b/sbin/pfctl/pfctl.c index a0eec1b09289..8d59871701f8 100644 --- a/sbin/pfctl/pfctl.c +++ b/sbin/pfctl/pfctl.c @@ -34,13 +34,10 @@ */ #include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #define PFIOC_USE_LATEST #include <sys/types.h> #include <sys/ioctl.h> -#include <sys/nv.h> #include <sys/socket.h> #include <sys/stat.h> #include <sys/endian.h> @@ -50,7 +47,6 @@ __FBSDID("$FreeBSD$"); #include <net/pfvar.h> #include <arpa/inet.h> #include <net/altq/altq.h> -#include <sys/sysctl.h> #include <err.h> #include <errno.h> @@ -75,8 +71,9 @@ int pfctl_get_skip_ifaces(void); int pfctl_check_skip_ifaces(char *); int pfctl_adjust_skip_ifaces(struct pfctl *); int pfctl_clear_interface_flags(int, int); -int pfctl_clear_rules(int, int, char *); -int pfctl_clear_nat(int, int, char *); +int pfctl_flush_eth_rules(int, int, char *); +int pfctl_flush_rules(int, int, char *); +int pfctl_flush_nat(int, int, char *); int pfctl_clear_altq(int, int); int pfctl_clear_src_nodes(int, int); int pfctl_clear_iface_states(int, const char *, int); @@ -93,12 +90,15 @@ int pfctl_load_timeout(struct pfctl *, unsigned int, unsigned int); int pfctl_load_debug(struct pfctl *, unsigned int); int pfctl_load_logif(struct pfctl *, char *); int pfctl_load_hostid(struct pfctl *, u_int32_t); +int pfctl_load_reassembly(struct pfctl *, u_int32_t); int pfctl_load_syncookies(struct pfctl *, u_int8_t); int pfctl_get_pool(int, struct pfctl_pool *, u_int32_t, u_int32_t, int, char *); +void pfctl_print_eth_rule_counters(struct pfctl_eth_rule *, int); void pfctl_print_rule_counters(struct pfctl_rule *, int); -int pfctl_show_rules(int, char *, int, enum pfctl_show, char *, int); -int pfctl_show_nat(int, int, char *); +int pfctl_show_eth_rules(int, char *, int, enum pfctl_show, char *, int, int); +int pfctl_show_rules(int, char *, int, enum pfctl_show, char *, int, int); +int pfctl_show_nat(int, char *, int, char *, int); int pfctl_show_src_nodes(int, int); int pfctl_show_states(int, const char *, int); int pfctl_show_status(int, int); @@ -108,14 +108,22 @@ int pfctl_show_limits(int, int); void pfctl_debug(int, u_int32_t, int); int pfctl_test_altqsupport(int, int); int pfctl_show_anchors(int, int, char *); -int pfctl_ruleset_trans(struct pfctl *, char *, struct pfctl_anchor *); +int pfctl_show_eth_anchors(int, int, char *); +int pfctl_ruleset_trans(struct pfctl *, char *, struct pfctl_anchor *, bool); +int pfctl_eth_ruleset_trans(struct pfctl *, char *, + struct pfctl_eth_anchor *); +int pfctl_load_eth_ruleset(struct pfctl *, char *, + struct pfctl_eth_ruleset *, int); +int pfctl_load_eth_rule(struct pfctl *, char *, struct pfctl_eth_rule *, + int); int pfctl_load_ruleset(struct pfctl *, char *, struct pfctl_ruleset *, int, int); int pfctl_load_rule(struct pfctl *, char *, struct pfctl_rule *, int); const char *pfctl_lookup_option(char *, const char * const *); static struct pfctl_anchor_global pf_anchors; -static struct pfctl_anchor pf_main_anchor; +struct pfctl_anchor pf_main_anchor; +struct pfctl_eth_anchor pf_eth_main_anchor; static struct pfr_buffer skip_b; static const char *clearopt; @@ -124,7 +132,7 @@ static const char *showopt; static const char *debugopt; static char *anchoropt; static const char *optiopt = NULL; -static const char *pf_device = "/dev/pf"; +static const char *pf_device = PF_DEVICE; static char *ifaceopt; static char *tableopt; static const char *tblcmdopt; @@ -136,6 +144,7 @@ int loadopt; int altqsupport; int dev = -1; +struct pfctl_handle *pfh = NULL; static int first_title = 1; static int labels = 0; @@ -218,13 +227,14 @@ static const struct { static const char * const clearopt_list[] = { "nat", "queue", "rules", "Sources", - "states", "info", "Tables", "osfp", "all", NULL + "states", "info", "Tables", "osfp", "all", + "ethernet", NULL }; static const char * const showopt_list[] = { - "nat", "queue", "rules", "Anchors", "Sources", "states", "info", - "Interfaces", "labels", "timeouts", "memory", "Tables", "osfp", - "Running", "all", NULL + "ether", "nat", "queue", "rules", "Anchors", "Sources", "states", + "info", "Interfaces", "labels", "timeouts", "memory", "Tables", + "osfp", "Running", "all", "creatorids", NULL }; static const char * const tblcmdopt_list[] = { @@ -301,10 +311,12 @@ pfctl_proto2name(int proto) int pfctl_enable(int dev, int opts) { - if (ioctl(dev, DIOCSTART)) { - if (errno == EEXIST) + int ret; + + if ((ret = pfctl_startstop(pfh, 1)) != 0) { + if (ret == EEXIST) errx(1, "pf already enabled"); - else if (errno == ESRCH) + else if (ret == ESRCH) errx(1, "pfil registeration failed"); else err(1, "DIOCSTART"); @@ -322,8 +334,10 @@ pfctl_enable(int dev, int opts) int pfctl_disable(int dev, int opts) { - if (ioctl(dev, DIOCSTOP)) { - if (errno == ENOENT) + int ret; + + if ((ret = pfctl_startstop(pfh, 0)) != 0) { + if (ret == ENOENT) errx(1, "pf not enabled"); else err(1, "DIOCSTOP"); @@ -449,16 +463,27 @@ pfctl_clear_interface_flags(int dev, int opts) } int -pfctl_clear_rules(int dev, int opts, char *anchorname) +pfctl_flush_eth_rules(int dev, int opts, char *anchorname) { - struct pfr_buffer t; + int ret; - memset(&t, 0, sizeof(t)); - t.pfrb_type = PFRB_TRANS; - if (pfctl_add_trans(&t, PF_RULESET_SCRUB, anchorname) || - pfctl_add_trans(&t, PF_RULESET_FILTER, anchorname) || - pfctl_trans(dev, &t, DIOCXBEGIN, 0) || - pfctl_trans(dev, &t, DIOCXCOMMIT, 0)) + ret = pfctl_clear_eth_rules(dev, anchorname); + if (ret != 0) + err(1, "pfctl_clear_eth_rules"); + + if ((opts & PF_OPT_QUIET) == 0) + fprintf(stderr, "Ethernet rules cleared\n"); + + return (ret); +} + +int +pfctl_flush_rules(int dev, int opts, char *anchorname) +{ + int ret; + + ret = pfctl_clear_rules(dev, anchorname); + if (ret != 0) err(1, "pfctl_clear_rules"); if ((opts & PF_OPT_QUIET) == 0) fprintf(stderr, "rules cleared\n"); @@ -466,17 +491,12 @@ pfctl_clear_rules(int dev, int opts, char *anchorname) } int -pfctl_clear_nat(int dev, int opts, char *anchorname) +pfctl_flush_nat(int dev, int opts, char *anchorname) { - struct pfr_buffer t; + int ret; - memset(&t, 0, sizeof(t)); - t.pfrb_type = PFRB_TRANS; - if (pfctl_add_trans(&t, PF_RULESET_NAT, anchorname) || - pfctl_add_trans(&t, PF_RULESET_BINAT, anchorname) || - pfctl_add_trans(&t, PF_RULESET_RDR, anchorname) || - pfctl_trans(dev, &t, DIOCXBEGIN, 0) || - pfctl_trans(dev, &t, DIOCXCOMMIT, 0)) + ret = pfctl_clear_nat(dev, anchorname); + if (ret != 0) err(1, "pfctl_clear_nat"); if ((opts & PF_OPT_QUIET) == 0) fprintf(stderr, "nat cleared\n"); @@ -525,7 +545,7 @@ pfctl_clear_iface_states(int dev, const char *iface, int opts) if (opts & PF_OPT_KILLMATCH) kill.kill_match = true; - if (pfctl_clear_states(dev, &kill, &killed)) + if (pfctl_clear_states_h(pfh, &kill, &killed)) err(1, "DIOCCLRSTATES"); if ((opts & PF_OPT_QUIET) == 0) fprintf(stderr, "%d states cleared\n", killed); @@ -706,6 +726,12 @@ pfctl_net_kill_states(int dev, const char *iface, int opts) sizeof(kill.ifname)) >= sizeof(kill.ifname)) errx(1, "invalid interface: %s", iface); + if (state_killers == 2 && (strcmp(state_kill[0], "nat") == 0)) { + kill.nat = true; + state_kill[0] = state_kill[1]; + state_killers = 1; + } + pfctl_addrprefix(state_kill[0], &kill.src.addr.v.a.mask); if (opts & PF_OPT_KILLMATCH) @@ -775,13 +801,13 @@ pfctl_net_kill_states(int dev, const char *iface, int opts) errx(1, "Unknown address family %d", kill.af); - if (pfctl_kill_states(dev, &kill, &newkilled)) + if (pfctl_kill_states_h(pfh, &kill, &newkilled)) err(1, "DIOCKILLSTATES"); killed += newkilled; } freeaddrinfo(res[1]); } else { - if (pfctl_kill_states(dev, &kill, &newkilled)) + if (pfctl_kill_states_h(pfh, &kill, &newkilled)) err(1, "DIOCKILLSTATES"); killed += newkilled; } @@ -847,7 +873,7 @@ pfctl_gateway_kill_states(int dev, const char *iface, int opts) else errx(1, "Unknown address family %d", kill.af); - if (pfctl_kill_states(dev, &kill, &newkilled)) + if (pfctl_kill_states_h(pfh, &kill, &newkilled)) err(1, "DIOCKILLSTATES"); killed += newkilled; } @@ -881,7 +907,7 @@ pfctl_label_kill_states(int dev, const char *iface, int opts) sizeof(kill.label)) errx(1, "label too long: %s", state_kill[1]); - if (pfctl_kill_states(dev, &kill, &killed)) + if (pfctl_kill_states_h(pfh, &kill, &killed)) err(1, "DIOCKILLSTATES"); if ((opts & PF_OPT_QUIET) == 0) @@ -920,7 +946,7 @@ pfctl_id_kill_states(int dev, const char *iface, int opts) usage(); } - if (pfctl_kill_states(dev, &kill, &killed)) + if (pfctl_kill_states_h(pfh, &kill, &killed)) err(1, "DIOCKILLSTATES"); if ((opts & PF_OPT_QUIET) == 0) @@ -987,6 +1013,32 @@ pfctl_clear_pool(struct pfctl_pool *pool) } void +pfctl_print_eth_rule_counters(struct pfctl_eth_rule *rule, int opts) +{ + if (opts & PF_OPT_VERBOSE) { + printf(" [ Evaluations: %-8llu Packets: %-8llu " + "Bytes: %-10llu]\n", + (unsigned long long)rule->evaluations, + (unsigned long long)(rule->packets[0] + + rule->packets[1]), + (unsigned long long)(rule->bytes[0] + + rule->bytes[1])); + } + if (opts & PF_OPT_VERBOSE2) { + char timestr[30]; + + if (rule->last_active_timestamp != 0) { + bcopy(ctime(&rule->last_active_timestamp), timestr, + sizeof(timestr)); + *strchr(timestr, '\n') = '\0'; + } else { + snprintf(timestr, sizeof(timestr), "N/A"); + } + printf(" [ Last Active Time: %s ]\n", timestr); + } +} + +void pfctl_print_rule_counters(struct pfctl_rule *rule, int opts) { if (opts & PF_OPT_DEBUG) { @@ -1023,6 +1075,17 @@ pfctl_print_rule_counters(struct pfctl_rule *rule, int opts) (unsigned)rule->cuid, (unsigned)rule->cpid, (uintmax_t)rule->states_tot); } + if (opts & PF_OPT_VERBOSE2) { + char timestr[30]; + if (rule->last_active_timestamp != 0) { + bcopy(ctime(&rule->last_active_timestamp), timestr, + sizeof(timestr)); + *strchr(timestr, '\n') = '\0'; + } else { + snprintf(timestr, sizeof(timestr), "N/A"); + } + printf(" [ Last Active Time: %s ]\n", timestr); + } } void @@ -1035,65 +1098,228 @@ pfctl_print_title(char *title) } int +pfctl_show_eth_rules(int dev, char *path, int opts, enum pfctl_show format, + char *anchorname, int depth, int wildcard) +{ + char anchor_call[MAXPATHLEN]; + struct pfctl_eth_rules_info info; + struct pfctl_eth_rule rule; + int brace; + int dotitle = opts & PF_OPT_SHOWALL; + int len = strlen(path); + char *npath, *p; + + /* + * Truncate a trailing / and * on an anchorname before searching for + * the ruleset, this is syntactic sugar that doesn't actually make it + * to the kernel. + */ + if ((p = strrchr(anchorname, '/')) != NULL && + p[1] == '*' && p[2] == '\0') { + p[0] = '\0'; + } + + if (anchorname[0] == '/') { + if ((npath = calloc(1, MAXPATHLEN)) == NULL) + errx(1, "pfctl_rules: calloc"); + snprintf(npath, MAXPATHLEN, "%s", anchorname); + } else { + if (path[0]) + snprintf(&path[len], MAXPATHLEN - len, "/%s", anchorname); + else + snprintf(&path[len], MAXPATHLEN - len, "%s", anchorname); + npath = path; + } + + /* + * If this anchor was called with a wildcard path, go through + * the rulesets in the anchor rather than the rules. + */ + if (wildcard && (opts & PF_OPT_RECURSE)) { + struct pfctl_eth_rulesets_info ri; + u_int32_t mnr, nr; + + if (pfctl_get_eth_rulesets_info(dev, &ri, npath)) { + if (errno == EINVAL) { + fprintf(stderr, "Anchor '%s' " + "not found.\n", anchorname); + } else { + warn("DIOCGETETHRULESETS"); + return (-1); + } + } + mnr = ri.nr; + + pfctl_print_eth_rule_counters(&rule, opts); + for (nr = 0; nr < mnr; ++nr) { + struct pfctl_eth_ruleset_info rs; + + if (pfctl_get_eth_ruleset(dev, npath, nr, &rs)) + err(1, "DIOCGETETHRULESET"); + INDENT(depth, !(opts & PF_OPT_VERBOSE)); + printf("anchor \"%s\" all {\n", rs.name); + pfctl_show_eth_rules(dev, npath, opts, + format, rs.name, depth + 1, 0); + INDENT(depth, !(opts & PF_OPT_VERBOSE)); + printf("}\n"); + } + path[len] = '\0'; + return (0); + } + + if (pfctl_get_eth_rules_info(dev, &info, path)) { + warn("DIOCGETETHRULES"); + return (-1); + } + for (int nr = 0; nr < info.nr; nr++) { + brace = 0; + INDENT(depth, !(opts & PF_OPT_VERBOSE)); + if (pfctl_get_eth_rule(dev, nr, info.ticket, path, &rule, + opts & PF_OPT_CLRRULECTRS, anchor_call) != 0) { + warn("DIOCGETETHRULE"); + return (-1); + } + if (anchor_call[0] && + ((((p = strrchr(anchor_call, '_')) != NULL) && + (p == anchor_call || + *(--p) == '/')) || (opts & PF_OPT_RECURSE))) { + brace++; + int aclen = strlen(anchor_call); + if (anchor_call[aclen - 1] == '*') + anchor_call[aclen - 2] = '\0'; + } + p = &anchor_call[0]; + if (dotitle) { + pfctl_print_title("ETH RULES:"); + dotitle = 0; + } + print_eth_rule(&rule, anchor_call, + opts & (PF_OPT_VERBOSE2 | PF_OPT_DEBUG)); + if (brace) + printf(" {\n"); + else + printf("\n"); + pfctl_print_eth_rule_counters(&rule, opts); + if (brace) { + pfctl_show_eth_rules(dev, path, opts, format, + p, depth + 1, rule.anchor_wildcard); + INDENT(depth, !(opts & PF_OPT_VERBOSE)); + printf("}\n"); + } + } + + path[len] = '\0'; + return (0); +} + +int pfctl_show_rules(int dev, char *path, int opts, enum pfctl_show format, - char *anchorname, int depth) + char *anchorname, int depth, int wildcard) { - struct pfioc_rule pr; + struct pfctl_rules_info ri; struct pfctl_rule rule; - u_int32_t nr, mnr, header = 0; + char anchor_call[MAXPATHLEN]; + u_int32_t nr, header = 0; int rule_numbers = opts & (PF_OPT_VERBOSE2 | PF_OPT_DEBUG); int numeric = opts & PF_OPT_NUMERIC; - int len = strlen(path); - int brace; - char *p; + int len = strlen(path), ret = 0; + char *npath, *p; - if (path[0]) - snprintf(&path[len], MAXPATHLEN - len, "/%s", anchorname); - else - snprintf(&path[len], MAXPATHLEN - len, "%s", anchorname); + /* + * Truncate a trailing / and * on an anchorname before searching for + * the ruleset, this is syntactic sugar that doesn't actually make it + * to the kernel. + */ + if ((p = strrchr(anchorname, '/')) != NULL && + p[1] == '*' && p[2] == '\0') { + p[0] = '\0'; + } + + if (anchorname[0] == '/') { + if ((npath = calloc(1, MAXPATHLEN)) == NULL) + errx(1, "pfctl_rules: calloc"); + snprintf(npath, MAXPATHLEN, "%s", anchorname); + } else { + if (path[0]) + snprintf(&path[len], MAXPATHLEN - len, "/%s", anchorname); + else + snprintf(&path[len], MAXPATHLEN - len, "%s", anchorname); + npath = path; + } + + /* + * If this anchor was called with a wildcard path, go through + * the rulesets in the anchor rather than the rules. + */ + if (wildcard && (opts & PF_OPT_RECURSE)) { + struct pfioc_ruleset prs; + u_int32_t mnr, nr; + + memset(&prs, 0, sizeof(prs)); + memcpy(prs.path, npath, sizeof(prs.path)); + if (ioctl(dev, DIOCGETRULESETS, &prs)) { + if (errno == EINVAL) + fprintf(stderr, "Anchor '%s' " + "not found.\n", anchorname); + else + err(1, "DIOCGETRULESETS"); + } + mnr = prs.nr; + + pfctl_print_rule_counters(&rule, opts); + for (nr = 0; nr < mnr; ++nr) { + prs.nr = nr; + if (ioctl(dev, DIOCGETRULESET, &prs)) + err(1, "DIOCGETRULESET"); + INDENT(depth, !(opts & PF_OPT_VERBOSE)); + printf("anchor \"%s\" all {\n", prs.name); + pfctl_show_rules(dev, npath, opts, + format, prs.name, depth + 1, 0); + INDENT(depth, !(opts & PF_OPT_VERBOSE)); + printf("}\n"); + } + path[len] = '\0'; + return (0); + } - memset(&pr, 0, sizeof(pr)); - memcpy(pr.anchor, path, sizeof(pr.anchor)); if (opts & PF_OPT_SHOWALL) { - pr.rule.action = PF_PASS; - if (ioctl(dev, DIOCGETRULES, &pr)) { + ret = pfctl_get_rules_info(dev, &ri, PF_PASS, path); + if (ret != 0) { warn("DIOCGETRULES"); goto error; } header++; } - pr.rule.action = PF_SCRUB; - if (ioctl(dev, DIOCGETRULES, &pr)) { + ret = pfctl_get_rules_info(dev, &ri, PF_SCRUB, path); + if (ret != 0) { warn("DIOCGETRULES"); goto error; } if (opts & PF_OPT_SHOWALL) { - if (format == PFCTL_SHOW_RULES && (pr.nr > 0 || header)) + if (format == PFCTL_SHOW_RULES && (ri.nr > 0 || header)) pfctl_print_title("FILTER RULES:"); else if (format == PFCTL_SHOW_LABELS && labels) pfctl_print_title("LABEL COUNTERS:"); } - mnr = pr.nr; - for (nr = 0; nr < mnr; ++nr) { - pr.nr = nr; - if (pfctl_get_clear_rule(dev, nr, pr.ticket, path, PF_SCRUB, - &rule, pr.anchor_call, opts & PF_OPT_CLRRULECTRS)) { + for (nr = 0; nr < ri.nr; ++nr) { + if (pfctl_get_clear_rule_h(pfh, nr, ri.ticket, path, PF_SCRUB, + &rule, anchor_call, opts & PF_OPT_CLRRULECTRS)) { warn("DIOCGETRULENV"); goto error; } if (pfctl_get_pool(dev, &rule.rpool, - nr, pr.ticket, PF_SCRUB, path) != 0) + nr, ri.ticket, PF_SCRUB, path) != 0) goto error; switch (format) { case PFCTL_SHOW_LABELS: break; case PFCTL_SHOW_RULES: - if (rule.label[0] && (opts & PF_OPT_SHOWALL)) + if (rule.label[0][0] && (opts & PF_OPT_SHOWALL)) labels = 1; - print_rule(&rule, pr.anchor_call, rule_numbers, numeric); + print_rule(&rule, anchor_call, rule_numbers, numeric); printf("\n"); pfctl_print_rule_counters(&rule, opts); break; @@ -1102,22 +1328,20 @@ pfctl_show_rules(int dev, char *path, int opts, enum pfctl_show format, } pfctl_clear_pool(&rule.rpool); } - pr.rule.action = PF_PASS; - if (ioctl(dev, DIOCGETRULES, &pr)) { + ret = pfctl_get_rules_info(dev, &ri, PF_PASS, path); + if (ret != 0) { warn("DIOCGETRULES"); goto error; } - mnr = pr.nr; - for (nr = 0; nr < mnr; ++nr) { - pr.nr = nr; - if (pfctl_get_clear_rule(dev, nr, pr.ticket, path, PF_PASS, - &rule, pr.anchor_call, opts & PF_OPT_CLRRULECTRS)) { + for (nr = 0; nr < ri.nr; ++nr) { + if (pfctl_get_clear_rule_h(pfh, nr, ri.ticket, path, PF_PASS, + &rule, anchor_call, opts & PF_OPT_CLRRULECTRS)) { warn("DIOCGETRULE"); goto error; } if (pfctl_get_pool(dev, &rule.rpool, - nr, pr.ticket, PF_PASS, path) != 0) + nr, ri.ticket, PF_PASS, path) != 0) goto error; switch (format) { @@ -1144,37 +1368,41 @@ pfctl_show_rules(int dev, char *path, int opts, enum pfctl_show format, (unsigned long long)rule.bytes[1], (uintmax_t)rule.states_tot); } + + if (anchor_call[0] && + (((p = strrchr(anchor_call, '/')) ? + p[1] == '_' : anchor_call[0] == '_') || + opts & PF_OPT_RECURSE)) { + pfctl_show_rules(dev, npath, opts, format, + anchor_call, depth, rule.anchor_wildcard); + } break; } case PFCTL_SHOW_RULES: - brace = 0; - if (rule.label[0] && (opts & PF_OPT_SHOWALL)) + if (rule.label[0][0] && (opts & PF_OPT_SHOWALL)) labels = 1; INDENT(depth, !(opts & PF_OPT_VERBOSE)); - if (pr.anchor_call[0] && - ((((p = strrchr(pr.anchor_call, '_')) != NULL) && - ((void *)p == (void *)pr.anchor_call || - *(--p) == '/')) || (opts & PF_OPT_RECURSE))) { - brace++; - if ((p = strrchr(pr.anchor_call, '/')) != - NULL) - p++; - else - p = &pr.anchor_call[0]; - } else - p = &pr.anchor_call[0]; - - print_rule(&rule, p, rule_numbers, numeric); - if (brace) + print_rule(&rule, anchor_call, rule_numbers, numeric); + + /* + * If this is a 'unnamed' brace notation + * anchor, OR the user has explicitly requested + * recursion, print it recursively. + */ + if (anchor_call[0] && + (((p = strrchr(anchor_call, '/')) ? + p[1] == '_' : anchor_call[0] == '_') || + opts & PF_OPT_RECURSE)) { printf(" {\n"); - else - printf("\n"); - pfctl_print_rule_counters(&rule, opts); - if (brace) { - pfctl_show_rules(dev, path, opts, format, - p, depth + 1); + pfctl_print_rule_counters(&rule, opts); + pfctl_show_rules(dev, npath, opts, format, + anchor_call, depth + 1, + rule.anchor_wildcard); INDENT(depth, !(opts & PF_OPT_VERBOSE)); printf("}\n"); + } else { + printf("\n"); + pfctl_print_rule_counters(&rule, opts); } break; case PFCTL_SHOW_NOTHING: @@ -1182,51 +1410,79 @@ pfctl_show_rules(int dev, char *path, int opts, enum pfctl_show format, } pfctl_clear_pool(&rule.rpool); } - path[len] = '\0'; - return (0); error: path[len] = '\0'; - return (-1); + return (ret); } int -pfctl_show_nat(int dev, int opts, char *anchorname) +pfctl_show_nat(int dev, char *path, int opts, char *anchorname, int depth) { - struct pfioc_rule pr; + struct pfctl_rules_info ri; struct pfctl_rule rule; - u_int32_t mnr, nr; + char anchor_call[MAXPATHLEN]; + u_int32_t nr; static int nattype[3] = { PF_NAT, PF_RDR, PF_BINAT }; int i, dotitle = opts & PF_OPT_SHOWALL; + int brace, ret; + int len = strlen(path); + char *p; + + if (path[0]) + snprintf(&path[len], MAXPATHLEN - len, "/%s", anchorname); + else + snprintf(&path[len], MAXPATHLEN - len, "%s", anchorname); - memset(&pr, 0, sizeof(pr)); - memcpy(pr.anchor, anchorname, sizeof(pr.anchor)); for (i = 0; i < 3; i++) { - pr.rule.action = nattype[i]; - if (ioctl(dev, DIOCGETRULES, &pr)) { + ret = pfctl_get_rules_info(dev, &ri, nattype[i], path); + if (ret != 0) { warn("DIOCGETRULES"); return (-1); } - mnr = pr.nr; - for (nr = 0; nr < mnr; ++nr) { - pr.nr = nr; - if (pfctl_get_rule(dev, nr, pr.ticket, anchorname, - nattype[i], &rule, pr.anchor_call)) { + for (nr = 0; nr < ri.nr; ++nr) { + brace = 0; + INDENT(depth, !(opts & PF_OPT_VERBOSE)); + + if (pfctl_get_rule(dev, nr, ri.ticket, path, + nattype[i], &rule, anchor_call)) { warn("DIOCGETRULE"); return (-1); } if (pfctl_get_pool(dev, &rule.rpool, nr, - pr.ticket, nattype[i], anchorname) != 0) + ri.ticket, nattype[i], path) != 0) return (-1); + + if (anchor_call[0] && + ((((p = strrchr(anchor_call, '_')) != NULL) && + (p == anchor_call || + *(--p) == '/')) || (opts & PF_OPT_RECURSE))) { + brace++; + if ((p = strrchr(anchor_call, '/')) != + NULL) + p++; + else + p = &anchor_call[0]; + } else + p = &anchor_call[0]; + if (dotitle) { pfctl_print_title("TRANSLATION RULES:"); dotitle = 0; } - print_rule(&rule, pr.anchor_call, + print_rule(&rule, anchor_call, opts & PF_OPT_VERBOSE2, opts & PF_OPT_NUMERIC); - printf("\n"); + if (brace) + printf(" {\n"); + else + printf("\n"); pfctl_print_rule_counters(&rule, opts); pfctl_clear_pool(&rule.rpool); + if (brace) { + pfctl_show_nat(dev, path, opts, p, depth + 1); + INDENT(depth, !(opts & PF_OPT_VERBOSE)); + printf("}\n"); + } } } return (0); @@ -1277,29 +1533,41 @@ done: return (0); } +struct pfctl_show_state_arg { + int opts; + int dotitle; + const char *iface; +}; + +static int +pfctl_show_state(struct pfctl_state *s, void *arg) +{ + struct pfctl_show_state_arg *a = (struct pfctl_show_state_arg *)arg; + + if (a->dotitle) { + pfctl_print_title("STATES:"); + a->dotitle = 0; + } + print_state(s, a->opts); + + return (0); +} + int pfctl_show_states(int dev, const char *iface, int opts) { - struct pfctl_states states; - struct pfctl_state *s; - int dotitle = (opts & PF_OPT_SHOWALL); + struct pfctl_show_state_arg arg; + struct pfctl_state_filter filter = {}; - memset(&states, 0, sizeof(states)); + if (iface != NULL) + strncpy(filter.ifname, iface, IFNAMSIZ); - if (pfctl_get_states(dev, &states)) - return (-1); + arg.opts = opts; + arg.dotitle = opts & PF_OPT_SHOWALL; + arg.iface = iface; - TAILQ_FOREACH(s, &states.states, entry) { - if (iface != NULL && strcmp(s->ifname, iface)) - continue; - if (dotitle) { - pfctl_print_title("STATES:"); - dotitle = 0; - } - print_state(s, opts); - } - - pfctl_free_states(&states); + if (pfctl_get_filtered_states_iter(&filter, pfctl_show_state, &arg)) + return (-1); return (0); } @@ -1391,6 +1659,22 @@ pfctl_show_limits(int dev, int opts) return (0); } +void +pfctl_show_creators(int opts) +{ + int ret; + uint32_t creators[16]; + size_t count = nitems(creators); + + ret = pfctl_get_creatorids(pfh, creators, &count); + if (ret != 0) + errx(ret, "Failed to retrieve creators"); + + printf("Creator IDs:\n"); + for (size_t i = 0; i < count; i++) + printf("%08x\n", creators[i]); +} + /* callbacks for rule/nat/rdr/addr */ int pfctl_add_pool(struct pfctl *pf, struct pfctl_pool *p, sa_family_t af) @@ -1462,10 +1746,71 @@ pfctl_append_rule(struct pfctl *pf, struct pfctl_rule *r, } int -pfctl_ruleset_trans(struct pfctl *pf, char *path, struct pfctl_anchor *a) +pfctl_append_eth_rule(struct pfctl *pf, struct pfctl_eth_rule *r, + const char *anchor_call) +{ + struct pfctl_eth_rule *rule; + struct pfctl_eth_ruleset *rs; + char *p; + + rs = &pf->eanchor->ruleset; + + if (anchor_call[0] && r->anchor == NULL) { + /* + * Don't make non-brace anchors part of the main anchor pool. + */ + if ((r->anchor = calloc(1, sizeof(*r->anchor))) == NULL) + err(1, "pfctl_append_rule: calloc"); + + pf_init_eth_ruleset(&r->anchor->ruleset); + r->anchor->ruleset.anchor = r->anchor; + if (strlcpy(r->anchor->path, anchor_call, + sizeof(rule->anchor->path)) >= sizeof(rule->anchor->path)) + errx(1, "pfctl_append_rule: strlcpy"); + if ((p = strrchr(anchor_call, '/')) != NULL) { + if (!strlen(p)) + err(1, "pfctl_append_eth_rule: bad anchor name %s", + anchor_call); + } else + p = (char *)anchor_call; + if (strlcpy(r->anchor->name, p, + sizeof(rule->anchor->name)) >= sizeof(rule->anchor->name)) + errx(1, "pfctl_append_eth_rule: strlcpy"); + } + + if ((rule = calloc(1, sizeof(*rule))) == NULL) + err(1, "calloc"); + bcopy(r, rule, sizeof(*rule)); + + TAILQ_INSERT_TAIL(&rs->rules, rule, entries); + return (0); +} + +int +pfctl_eth_ruleset_trans(struct pfctl *pf, char *path, + struct pfctl_eth_anchor *a) +{ + int osize = pf->trans->pfrb_size; + + if ((pf->loadopt & PFCTL_FLAG_ETH) != 0) { + if (pfctl_add_trans(pf->trans, PF_RULESET_ETH, path)) + return (1); + } + if (pfctl_trans(pf->dev, pf->trans, DIOCXBEGIN, osize)) + return (5); + + return (0); +} + +int +pfctl_ruleset_trans(struct pfctl *pf, char *path, struct pfctl_anchor *a, bool do_eth) { int osize = pf->trans->pfrb_size; + if ((pf->loadopt & PFCTL_FLAG_ETH) != 0 && do_eth) { + if (pfctl_add_trans(pf->trans, PF_RULESET_ETH, path)) + return (1); + } if ((pf->loadopt & PFCTL_FLAG_NAT) != 0) { if (pfctl_add_trans(pf->trans, PF_RULESET_NAT, path) || pfctl_add_trans(pf->trans, PF_RULESET_BINAT, path) || @@ -1492,6 +1837,104 @@ pfctl_ruleset_trans(struct pfctl *pf, char *path, struct pfctl_anchor *a) } int +pfctl_load_eth_ruleset(struct pfctl *pf, char *path, + struct pfctl_eth_ruleset *rs, int depth) +{ + struct pfctl_eth_rule *r; + int error, len = strlen(path); + int brace = 0; + + pf->eanchor = rs->anchor; + if (path[0]) + snprintf(&path[len], MAXPATHLEN - len, "/%s", pf->eanchor->name); + else + snprintf(&path[len], MAXPATHLEN - len, "%s", pf->eanchor->name); + + if (depth) { + if (TAILQ_FIRST(&rs->rules) != NULL) { + brace++; + if (pf->opts & PF_OPT_VERBOSE) + printf(" {\n"); + if ((pf->opts & PF_OPT_NOACTION) == 0 && + (error = pfctl_eth_ruleset_trans(pf, + path, rs->anchor))) { + printf("pfctl_load_eth_rulesets: " + "pfctl_eth_ruleset_trans %d\n", error); + goto error; + } + } else if (pf->opts & PF_OPT_VERBOSE) + printf("\n"); + } + + while ((r = TAILQ_FIRST(&rs->rules)) != NULL) { + TAILQ_REMOVE(&rs->rules, r, entries); + + error = pfctl_load_eth_rule(pf, path, r, depth); + if (error) + return (error); + + if (r->anchor) { + if ((error = pfctl_load_eth_ruleset(pf, path, + &r->anchor->ruleset, depth + 1))) + return (error); + } else if (pf->opts & PF_OPT_VERBOSE) + printf("\n"); + free(r); + } + if (brace && pf->opts & PF_OPT_VERBOSE) { + INDENT(depth - 1, (pf->opts & PF_OPT_VERBOSE)); + printf("}\n"); + } + path[len] = '\0'; + + return (0); +error: + path[len] = '\0'; + return (error); +} + +int +pfctl_load_eth_rule(struct pfctl *pf, char *path, struct pfctl_eth_rule *r, + int depth) +{ + char *name; + char anchor[PF_ANCHOR_NAME_SIZE]; + int len = strlen(path); + + if (strlcpy(anchor, path, sizeof(anchor)) >= sizeof(anchor)) + errx(1, "pfctl_load_eth_rule: strlcpy"); + + if (r->anchor) { + if (r->anchor->match) { + if (path[0]) + snprintf(&path[len], MAXPATHLEN - len, + "/%s", r->anchor->name); + else + snprintf(&path[len], MAXPATHLEN - len, + "%s", r->anchor->name); + name = r->anchor->name; + } else + name = r->anchor->path; + } else + name = ""; + + if ((pf->opts & PF_OPT_NOACTION) == 0) + if (pfctl_add_eth_rule(pf->dev, r, anchor, name, + pf->eth_ticket)) + err(1, "DIOCADDETHRULENV"); + + if (pf->opts & PF_OPT_VERBOSE) { + INDENT(depth, !(pf->opts & PF_OPT_VERBOSE2)); + print_eth_rule(r, r->anchor ? r->anchor->name : "", + pf->opts & (PF_OPT_VERBOSE2 | PF_OPT_DEBUG)); + } + + path[len] = '\0'; + + return (0); +} + +int pfctl_load_ruleset(struct pfctl *pf, char *path, struct pfctl_ruleset *rs, int rs_num, int depth) { @@ -1513,7 +1956,7 @@ pfctl_load_ruleset(struct pfctl *pf, char *path, struct pfctl_ruleset *rs, printf(" {\n"); if ((pf->opts & PF_OPT_NOACTION) == 0 && (error = pfctl_ruleset_trans(pf, - path, rs->anchor))) { + path, rs->anchor, false))) { printf("pfctl_load_rulesets: " "pfctl_ruleset_trans %d\n", error); goto error; @@ -1565,6 +2008,8 @@ pfctl_load_rule(struct pfctl *pf, char *path, struct pfctl_rule *r, int depth) u_int32_t ticket; char anchor[PF_ANCHOR_NAME_SIZE]; int len = strlen(path); + int error; + bool was_present; /* set up anchor before adding to path for anchor_call */ if ((pf->opts & PF_OPT_NOACTION) == 0) @@ -1586,19 +2031,32 @@ pfctl_load_rule(struct pfctl *pf, char *path, struct pfctl_rule *r, int depth) } else name = ""; + was_present = false; if ((pf->opts & PF_OPT_NOACTION) == 0) { if (pfctl_add_pool(pf, &r->rpool, r->af)) return (1); - if (pfctl_add_rule(pf->dev, r, anchor, name, ticket, - pf->paddr.ticket)) + error = pfctl_add_rule(pf->dev, r, anchor, name, ticket, + pf->paddr.ticket); + switch (error) { + case 0: + /* things worked, do nothing */ + break; + case EEXIST: + /* an identical rule is already present */ + was_present = true; + break; + default: err(1, "DIOCADDRULENV"); + } } if (pf->opts & PF_OPT_VERBOSE) { INDENT(depth, !(pf->opts & PF_OPT_VERBOSE2)); - print_rule(r, r->anchor ? r->anchor->name : "", + print_rule(r, name, pf->opts & PF_OPT_VERBOSE2, pf->opts & PF_OPT_NUMERIC); + if (was_present) + printf(" -- rule was already present"); } path[len] = '\0'; pfctl_clear_pool(&r->rpool); @@ -1638,6 +2096,7 @@ pfctl_rules(int dev, char *filename, int opts, int optimize, struct pfioc_altq pa; struct pfctl pf; struct pfctl_ruleset *rs; + struct pfctl_eth_ruleset *ethrs; struct pfr_table trs; char *path; int osize; @@ -1646,6 +2105,11 @@ pfctl_rules(int dev, char *filename, int opts, int optimize, memset(&pf_main_anchor, 0, sizeof(pf_main_anchor)); pf_init_ruleset(&pf_main_anchor.ruleset); pf_main_anchor.ruleset.anchor = &pf_main_anchor; + + memset(&pf_eth_main_anchor, 0, sizeof(pf_eth_main_anchor)); + pf_init_eth_ruleset(&pf_eth_main_anchor.ruleset); + pf_eth_main_anchor.ruleset.anchor = &pf_eth_main_anchor; + if (trans == NULL) { bzero(&buf, sizeof(buf)); buf.pfrb_type = PFRB_TRANS; @@ -1678,10 +2142,10 @@ pfctl_rules(int dev, char *filename, int opts, int optimize, rs->anchor = pf.anchor; if (strlcpy(pf.anchor->path, anchorname, sizeof(pf.anchor->path)) >= sizeof(pf.anchor->path)) - errx(1, "pfctl_add_rule: strlcpy"); + errx(1, "pfctl_rules: strlcpy"); if (strlcpy(pf.anchor->name, anchorname, sizeof(pf.anchor->name)) >= sizeof(pf.anchor->name)) - errx(1, "pfctl_add_rule: strlcpy"); + errx(1, "pfctl_rules: strlcpy"); pf.astack[0] = pf.anchor; @@ -1692,14 +2156,32 @@ pfctl_rules(int dev, char *filename, int opts, int optimize, pf.trans = t; pfctl_init_options(&pf); + /* Set up ethernet anchor */ + if ((pf.eanchor = calloc(1, sizeof(*pf.eanchor))) == NULL) + ERRX("pfctl_rules: calloc"); + + if (strlcpy(pf.eanchor->path, anchorname, + sizeof(pf.eanchor->path)) >= sizeof(pf.eanchor->path)) + errx(1, "pfctl_rules: strlcpy"); + if (strlcpy(pf.eanchor->name, anchorname, + sizeof(pf.eanchor->name)) >= sizeof(pf.eanchor->name)) + errx(1, "pfctl_rules: strlcpy"); + + ethrs = &pf.eanchor->ruleset; + pf_init_eth_ruleset(ethrs); + ethrs->anchor = pf.eanchor; + pf.eastack[0] = pf.eanchor; + if ((opts & PF_OPT_NOACTION) == 0) { /* * XXX For the time being we need to open transactions for * the main ruleset before parsing, because tables are still * loaded at parse time. */ - if (pfctl_ruleset_trans(&pf, anchorname, pf.anchor)) + if (pfctl_ruleset_trans(&pf, anchorname, pf.anchor, true)) ERRX("pfctl_rules"); + if (pf.loadopt & PFCTL_FLAG_ETH) + pf.eth_ticket = pfctl_get_ticket(t, PF_RULESET_ETH, anchorname); if (altqsupport && (pf.loadopt & PFCTL_FLAG_ALTQ)) pa.ticket = pfctl_get_ticket(t, PF_RULESET_ALTQ, anchorname); @@ -1720,6 +2202,8 @@ pfctl_rules(int dev, char *filename, int opts, int optimize, if ((pf.loadopt & PFCTL_FLAG_FILTER && (pfctl_load_ruleset(&pf, path, rs, PF_RULESET_SCRUB, 0))) || + (pf.loadopt & PFCTL_FLAG_ETH && + (pfctl_load_eth_ruleset(&pf, path, ethrs, 0))) || (pf.loadopt & PFCTL_FLAG_NAT && (pfctl_load_ruleset(&pf, path, rs, PF_RULESET_NAT, 0) || pfctl_load_ruleset(&pf, path, rs, PF_RULESET_RDR, 0) || @@ -1797,6 +2281,11 @@ pfctl_init_options(struct pfctl *pf) pf->timeout[PFTM_TCP_CLOSING] = PFTM_TCP_CLOSING_VAL; pf->timeout[PFTM_TCP_FIN_WAIT] = PFTM_TCP_FIN_WAIT_VAL; pf->timeout[PFTM_TCP_CLOSED] = PFTM_TCP_CLOSED_VAL; + pf->timeout[PFTM_SCTP_FIRST_PACKET] = PFTM_TCP_FIRST_PACKET_VAL; + pf->timeout[PFTM_SCTP_OPENING] = PFTM_TCP_OPENING_VAL; + pf->timeout[PFTM_SCTP_ESTABLISHED] = PFTM_TCP_ESTABLISHED_VAL; + pf->timeout[PFTM_SCTP_CLOSING] = PFTM_TCP_CLOSING_VAL; + pf->timeout[PFTM_SCTP_CLOSED] = PFTM_TCP_CLOSED_VAL; pf->timeout[PFTM_UDP_FIRST_PACKET] = PFTM_UDP_FIRST_PACKET_VAL; pf->timeout[PFTM_UDP_SINGLE] = PFTM_UDP_SINGLE_VAL; pf->timeout[PFTM_UDP_MULTIPLE] = PFTM_UDP_MULTIPLE_VAL; @@ -1818,6 +2307,7 @@ pfctl_init_options(struct pfctl *pf) pf->limit[PF_LIMIT_TABLE_ENTRIES] = PFR_KENTRY_HIWAT; pf->debug = PF_DEBUG_URGENT; + pf->reassemble = 0; pf->syncookies = false; pf->syncookieswat[0] = PF_SYNCOOKIES_LOWATPCT; @@ -1878,6 +2368,11 @@ pfctl_load_options(struct pfctl *pf) if (pfctl_load_hostid(pf, pf->hostid)) error = 1; + /* load reassembly settings */ + if (!(pf->opts & PF_OPT_MERGE) || pf->reass_set) + if (pfctl_load_reassembly(pf, pf->reassemble)) + error = 1; + /* load keepcounters */ if (pfctl_set_keepcounters(pf->dev, pf->keep_counters)) error = 1; @@ -1975,6 +2470,28 @@ pfctl_load_timeout(struct pfctl *pf, unsigned int timeout, unsigned int seconds) } int +pfctl_set_reassembly(struct pfctl *pf, int on, int nodf) +{ + if ((loadopt & PFCTL_FLAG_OPTION) == 0) + return (0); + + pf->reass_set = 1; + if (on) { + pf->reassemble = PF_REASS_ENABLED; + if (nodf) + pf->reassemble |= PF_REASS_NODF; + } else { + pf->reassemble = 0; + } + + if (pf->opts & PF_OPT_VERBOSE) + printf("set reassemble %s %s\n", on ? "yes" : "no", + nodf ? "no-df" : ""); + + return (0); +} + +int pfctl_set_optimization(struct pfctl *pf, const char *opt) { const struct pf_hint *hint; @@ -2030,19 +2547,11 @@ pfctl_set_logif(struct pfctl *pf, char *ifname) int pfctl_load_logif(struct pfctl *pf, char *ifname) { - struct pfioc_if pi; - - memset(&pi, 0, sizeof(pi)); - if (ifname && strlcpy(pi.ifname, ifname, - sizeof(pi.ifname)) >= sizeof(pi.ifname)) { + if (ifname != NULL && strlen(ifname) >= IFNAMSIZ) { warnx("pfctl_load_logif: strlcpy"); return (1); } - if (ioctl(pf->dev, DIOCSETSTATUSIF, &pi)) { - warnx("DIOCSETSTATUSIF"); - return (1); - } - return (0); + return (pfctl_set_statusif(pfh, ifname ? ifname : "")); } int @@ -2073,6 +2582,16 @@ pfctl_load_hostid(struct pfctl *pf, u_int32_t hostid) } int +pfctl_load_reassembly(struct pfctl *pf, u_int32_t reassembly) +{ + if (ioctl(dev, DIOCSETREASS, &reassembly)) { + warnx("DIOCSETREASS"); + return (1); + } + return (0); +} + +int pfctl_load_syncookies(struct pfctl *pf, u_int8_t val) { struct pfctl_syncookies cookies; @@ -2298,6 +2817,44 @@ pfctl_show_anchors(int dev, int opts, char *anchorname) return (0); } +int +pfctl_show_eth_anchors(int dev, int opts, char *anchorname) +{ + struct pfctl_eth_rulesets_info ri; + struct pfctl_eth_ruleset_info rs; + int ret; + + if ((ret = pfctl_get_eth_rulesets_info(dev, &ri, anchorname)) != 0) { + if (ret == ENOENT) + fprintf(stderr, "Anchor '%s' not found.\n", + anchorname); + else + err(1, "DIOCGETETHRULESETS"); + return (-1); + } + + for (int nr = 0; nr < ri.nr; nr++) { + char sub[MAXPATHLEN]; + + if (pfctl_get_eth_ruleset(dev, anchorname, nr, &rs) != 0) + err(1, "DIOCGETETHRULESET"); + + if (!strcmp(rs.name, PF_RESERVED_ANCHOR)) + continue; + sub[0] = 0; + if (rs.path[0]) { + strlcat(sub, rs.path, sizeof(sub)); + strlcat(sub, "/", sizeof(sub)); + } + strlcat(sub, rs.name, sizeof(sub)); + if (sub[0] != '_' || (opts & PF_OPT_VERBOSE)) + printf(" %s\n", sub); + if ((opts & PF_OPT_VERBOSE) && pfctl_show_eth_anchors(dev, opts, sub)) + return (-1); + } + return (0); +} + const char * pfctl_lookup_option(char *cmd, const char * const *list) { @@ -2483,7 +3040,7 @@ main(int argc, char *argv[]) if (anchoropt != NULL) { int len = strlen(anchoropt); - if (anchoropt[len - 1] == '*') { + if (len >= 1 && anchoropt[len - 1] == '*') { if (len >= 2 && anchoropt[len - 2] == '/') anchoropt[len - 2] = '\0'; else @@ -2494,7 +3051,7 @@ main(int argc, char *argv[]) sizeof(anchorname)) >= sizeof(anchorname)) errx(1, "anchor name '%s' too long", anchoropt); - loadopt &= PFCTL_FLAG_FILTER|PFCTL_FLAG_NAT|PFCTL_FLAG_TABLE; + loadopt &= PFCTL_FLAG_FILTER|PFCTL_FLAG_NAT|PFCTL_FLAG_TABLE|PFCTL_FLAG_ETH; } if ((opts & PF_OPT_NOACTION) == 0) { @@ -2515,6 +3072,9 @@ main(int argc, char *argv[]) altqsupport = 1; #endif } + pfh = pfctl_open(pf_device); + if (pfh == NULL) + err(1, "Failed to open netlink"); if (opts & PF_OPT_DISABLE) if (pfctl_disable(dev, opts)) @@ -2524,20 +3084,23 @@ main(int argc, char *argv[]) switch (*showopt) { case 'A': pfctl_show_anchors(dev, opts, anchorname); + if (opts & PF_OPT_VERBOSE2) + printf("Ethernet:\n"); + pfctl_show_eth_anchors(dev, opts, anchorname); break; case 'r': pfctl_load_fingerprints(dev, opts); pfctl_show_rules(dev, path, opts, PFCTL_SHOW_RULES, - anchorname, 0); + anchorname, 0, 0); break; case 'l': pfctl_load_fingerprints(dev, opts); pfctl_show_rules(dev, path, opts, PFCTL_SHOW_LABELS, - anchorname, 0); + anchorname, 0, 0); break; case 'n': pfctl_load_fingerprints(dev, opts); - pfctl_show_nat(dev, opts, anchorname); + pfctl_show_nat(dev, path, opts, anchorname, 0); break; case 'q': pfctl_show_altq(dev, ifaceopt, opts, @@ -2561,17 +3124,24 @@ main(int argc, char *argv[]) case 'm': pfctl_show_limits(dev, opts); break; + case 'e': + pfctl_show_eth_rules(dev, path, opts, 0, anchorname, 0, + 0); + break; case 'a': opts |= PF_OPT_SHOWALL; pfctl_load_fingerprints(dev, opts); - pfctl_show_nat(dev, opts, anchorname); - pfctl_show_rules(dev, path, opts, 0, anchorname, 0); + pfctl_show_eth_rules(dev, path, opts, 0, anchorname, 0, + 0); + + pfctl_show_nat(dev, path, opts, anchorname, 0); + pfctl_show_rules(dev, path, opts, 0, anchorname, 0, 0); pfctl_show_altq(dev, ifaceopt, opts, 0); pfctl_show_states(dev, ifaceopt, opts); pfctl_show_src_nodes(dev, opts); pfctl_show_status(dev, opts); - pfctl_show_rules(dev, path, opts, 1, anchorname, 0); + pfctl_show_rules(dev, path, opts, 1, anchorname, 0, 0); pfctl_show_timeouts(dev, opts); pfctl_show_limits(dev, opts); pfctl_show_tables(anchorname, opts); @@ -2587,12 +3157,18 @@ main(int argc, char *argv[]) case 'I': pfctl_show_ifaces(ifaceopt, opts); break; + case 'c': + pfctl_show_creators(opts); + break; } } - if ((opts & PF_OPT_CLRRULECTRS) && showopt == NULL) + if ((opts & PF_OPT_CLRRULECTRS) && showopt == NULL) { + pfctl_show_eth_rules(dev, path, opts, PFCTL_SHOW_NOTHING, + anchorname, 0, 0); pfctl_show_rules(dev, path, opts, PFCTL_SHOW_NOTHING, - anchorname, 0); + anchorname, 0, 0); + } if (clearopt != NULL) { if (anchorname[0] == '_' || strstr(anchorname, "/_") != NULL) @@ -2600,11 +3176,14 @@ main(int argc, char *argv[]) "be modified from the command line"); switch (*clearopt) { + case 'e': + pfctl_flush_eth_rules(dev, opts, anchorname); + break; case 'r': - pfctl_clear_rules(dev, opts, anchorname); + pfctl_flush_rules(dev, opts, anchorname); break; case 'n': - pfctl_clear_nat(dev, opts, anchorname); + pfctl_flush_nat(dev, opts, anchorname); break; case 'q': pfctl_clear_altq(dev, opts); @@ -2619,8 +3198,9 @@ main(int argc, char *argv[]) pfctl_clear_stats(dev, opts); break; case 'a': - pfctl_clear_rules(dev, opts, anchorname); - pfctl_clear_nat(dev, opts, anchorname); + pfctl_flush_eth_rules(dev, opts, anchorname); + pfctl_flush_rules(dev, opts, anchorname); + pfctl_flush_nat(dev, opts, anchorname); pfctl_clear_tables(anchorname, opts); if (!*anchorname) { pfctl_clear_altq(dev, opts); |