diff --git a/sbin/pfctl/parse.y b/sbin/pfctl/parse.y --- a/sbin/pfctl/parse.y +++ b/sbin/pfctl/parse.y @@ -1276,7 +1276,14 @@ memset(&r, 0, sizeof(r)); if (pf->eastack[pf->asd + 1]) { - /* move inline rules into relative location */ + if ($3 && strchr($3, '/') != NULL) { + free($3); + yyerror("anchor paths containing '/' " + "cannot be used for inline anchors."); + YYERROR; + } + + /* Move inline rules into relative location. */ pfctl_eth_anchor_setup(pf, &r, &pf->eastack[pf->asd]->ruleset, $3 ? $3 : pf->ealast->name); diff --git a/sbin/pfctl/pfctl.c b/sbin/pfctl/pfctl.c --- a/sbin/pfctl/pfctl.c +++ b/sbin/pfctl/pfctl.c @@ -99,7 +99,7 @@ char *); void pfctl_print_eth_rule_counters(struct pfctl_eth_rule *, int); void pfctl_print_rule_counters(struct pfctl_rule *, int); -int pfctl_show_eth_rules(int, char *, int, enum pfctl_show, char *, int); +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); @@ -1091,20 +1091,73 @@ int pfctl_show_eth_rules(int dev, char *path, int opts, enum pfctl_show format, - char *anchorname, int depth) + 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); - int brace; - char *p; + 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 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"); @@ -1141,7 +1194,7 @@ pfctl_print_eth_rule_counters(&rule, opts); if (brace) { pfctl_show_eth_rules(dev, path, opts, format, - p, depth + 1); + p, depth + 1, rule.anchor_wildcard); INDENT(depth, !(opts & PF_OPT_VERBOSE)); printf("}\n"); } @@ -2988,13 +3041,15 @@ pfctl_show_limits(dev, opts); break; case 'e': - pfctl_show_eth_rules(dev, path, opts, 0, anchorname, 0); + 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_eth_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); @@ -3023,7 +3078,7 @@ if ((opts & PF_OPT_CLRRULECTRS) && showopt == NULL) { pfctl_show_eth_rules(dev, path, opts, PFCTL_SHOW_NOTHING, - anchorname, 0); + anchorname, 0, 0); pfctl_show_rules(dev, path, opts, PFCTL_SHOW_NOTHING, anchorname, 0, 0); }