Hello, this is the last piece, which makes everything fit together. The change introduces three 'nuke()' functions: - pfctl_call_clearrules() - pfctl_call_cleartables() - pfctl_call_clearanchors()
Those are callbacks for pfctl_recurse() we've introduced earlier. Those functions just call existing pfctl_clear_...() function. We also must turn pfctl_clear_...() function from void to int so error can be reported. Also all pfctl_clear_...() function must adhere a PF_OPT_IGNFAIL flag now. Not diff below also includes a change, which does a right thing in case we ask pfctl to remove just subtree: pfctl -a 'foo/bar/*' -Fr However keep in mind all those changes are uncovering glitches, which exit in PF kernel driver already. thanks and regards sashan --------8<---------------8<---------------8<------------------8<-------- diff --git a/sbin/pfctl/pfctl.c b/sbin/pfctl/pfctl.c index 054da006e69..9fe661e8c89 100644 --- a/sbin/pfctl/pfctl.c +++ b/sbin/pfctl/pfctl.c @@ -51,10 +51,9 @@ #include <stdlib.h> #include <string.h> #include <unistd.h> - #include <syslog.h> - #include <stdarg.h> +#include <libgen.h> #include "pfctl_parser.h" #include "pfctl.h" @@ -65,7 +64,7 @@ int pfctl_disable(int, int); void pfctl_clear_queues(struct pf_qihead *); void pfctl_clear_stats(int, const char *, int); void pfctl_clear_interface_flags(int, int); -void pfctl_clear_rules(int, int, char *); +int pfctl_clear_rules(int, int, char *); void pfctl_clear_src_nodes(int, int); void pfctl_clear_states(int, const char *, int); struct addrinfo * @@ -110,11 +109,15 @@ void pfctl_state_load(int, const char *); void pfctl_reset(int, int); int pfctl_walk_show(int, struct pfioc_ruleset *, void *); int pfctl_walk_get(int, struct pfioc_ruleset *, void *); -int pfctl_walk_anchors(int, int, char *, void *, +int pfctl_walk_anchors(int, int, const char *, void *, int(*)(int, struct pfioc_ruleset *, void *)); struct pfr_anchors * - pfctl_get_anchors(int, int); -int pfctl_recurse(int, int, int(*nuke)(int, int, struct pfr_anchoritem *)); + pfctl_get_anchors(int, const char *, int); +int pfctl_recurse(int, int, const char *, + int(*)(int, int, struct pfr_anchoritem *)); +int pfctl_call_clearrules(int, int, struct pfr_anchoritem *); +int pfctl_call_cleartables(int, int, struct pfr_anchoritem *); +int pfctl_call_clearanchors(int, int, struct pfr_anchoritem *); const char *clearopt; char *rulesopt; @@ -244,7 +247,6 @@ static const char *optiopt_list[] = { struct pf_qihead qspecs = TAILQ_HEAD_INITIALIZER(qspecs); struct pf_qihead rootqs = TAILQ_HEAD_INITIALIZER(rootqs); - __dead void usage(void) { @@ -361,11 +363,10 @@ pfctl_clear_interface_flags(int dev, int opts) } } -void +int pfctl_clear_rules(int dev, int opts, char *anchorname) { - struct pfr_buffer t; - int rv = 0; + struct pfr_buffer t; memset(&t, 0, sizeof(t)); t.pfrb_type = PFRB_TRANS; @@ -373,9 +374,11 @@ pfctl_clear_rules(int dev, int opts, char *anchorname) pfctl_trans(dev, &t, DIOCXBEGIN, 0) || pfctl_trans(dev, &t, DIOCXCOMMIT, 0)) { pfctl_err(opts, 1, "%s", __func__); - rv = 1; + return (1); } else if ((opts & PF_OPT_QUIET) == 0) fprintf(stderr, "rules cleared\n"); + + return (0); } void @@ -2171,9 +2174,9 @@ pfctl_walk_get(int opts, struct pfioc_ruleset *pr, void *warg) { struct pfr_anchoritem *pfra; unsigned int len; - struct { - struct pfr_anchoritem *pfra; - } *tail_pfra = warg; + struct pfr_anchors *anchors; + + anchors = (struct pfr_anchors *) warg; pfra = malloc(sizeof(*pfra)); if (pfra == NULL) @@ -2191,16 +2194,13 @@ pfctl_walk_get(int opts, struct pfioc_ruleset *pr, void *warg) else snprintf(pfra->pfra_anchorname, len, "%s", pr->name); - if (tail_pfra->pfra != NULL) - SLIST_INSERT_AFTER(tail_pfra->pfra, pfra, pfra_sle); - - tail_pfra->pfra = pfra; + SLIST_INSERT_HEAD(anchors, pfra, pfra_sle); return (0); } int -pfctl_walk_anchors(int dev, int opts, char *anchorname, void *warg, +pfctl_walk_anchors(int dev, int opts, const char *anchorname, void *warg, int(walkf)(int, struct pfioc_ruleset *, void *)) { struct pfioc_ruleset pr; @@ -2249,54 +2249,82 @@ pfctl_walk_anchors(int dev, int opts, char *anchorname, void *warg, int pfctl_show_anchors(int dev, int opts, char *anchorname) { - int rv; - - rv = pfctl_walk_anchors(dev, opts, anchorname, NULL, pfctl_walk_show); - return (rv); + return ( + pfctl_walk_anchors(dev, opts, anchorname, NULL, pfctl_walk_show)); } struct pfr_anchors * -pfctl_get_anchors(int dev, int opts) +pfctl_get_anchors(int dev, const char *anchorname, int opts) { struct pfioc_ruleset pr; - struct { - struct pfr_anchoritem *pfra; - } pfra; static struct pfr_anchors anchors; + char *n; SLIST_INIT(&anchors); memset(&pr, 0, sizeof(pr)); - pfra.pfra = NULL; - pfctl_walk_get(opts, &pr, &pfra); - if (pfra.pfra == NULL) { - fprintf(stderr, "%s failed to allocate main anchor\n", - __func__); - exit(1); + if (*anchorname != '\0') { + n = dirname(anchorname); + if (n[0] != '.' && n[1] != '\0') + strlcpy(pr.path, n, sizeof(pr.path)); + n = basename(anchorname); + if (n != NULL) + strlcpy(pr.name, n, sizeof(pr.name)); } - SLIST_INSERT_HEAD(&anchors, pfra.pfra, pfra_sle); + + pfctl_walk_get(opts, &pr, &anchors); opts |= PF_OPT_VERBOSE; - if (pfctl_walk_anchors(dev, opts, "", &pfra, pfctl_walk_get)) { - fprintf(stderr, - "%s failed to retreive list of anchors, can't continue\n", + if (pfctl_walk_anchors(dev, opts, anchorname, &anchors, pfctl_walk_get)) + errx(1, + "%s failed to retrieve list of anchors, can't continue", __func__); - exit(1); - } return (&anchors); } int -pfctl_recurse(int dev, int opts, int(*nuke)(int, int, struct pfr_anchoritem *)) +pfctl_call_cleartables(int dev, int opts, struct pfr_anchoritem *pfra) +{ + return ((pfctl_clear_tables(pfra->pfra_anchorname, opts) == -1) ? + 1 : 0); +} + +int +pfctl_call_clearrules(int dev, int opts, struct pfr_anchoritem *pfra) +{ + return (pfctl_clear_rules(dev, opts, pfra->pfra_anchorname)); +} + +int +pfctl_call_clearanchors(int dev, int opts, struct pfr_anchoritem *pfra) +{ + int rv = 0; + + rv |= pfctl_call_cleartables(dev, opts, pfra); + rv |= pfctl_clear_rules(dev, opts, pfra->pfra_anchorname); + + return (rv); +} + +int +pfctl_recurse(int dev, int opts, const char *anchorname, + int(*walkf)(int, int, struct pfr_anchoritem *)) { int rv = 0; struct pfr_anchors *anchors; struct pfr_anchoritem *pfra, *pfra_save; - anchors = pfctl_get_anchors(dev, opts); + anchors = pfctl_get_anchors(dev, anchorname, opts); + /* + * don't let pfctl_clear_*() function to fail with exit + */ + opts |= PF_OPT_IGNFAIL | PF_OPT_QUIET; + printf("Removing:\n"); SLIST_FOREACH_SAFE(pfra, anchors, pfra_sle, pfra_save) { - rv |= nuke(dev, opts, pfra); + printf(" %s\n", (*pfra->pfra_anchorname == '\0') ? + "<root>" : pfra->pfra_anchorname); + rv |= walkf(dev, opts, pfra); SLIST_REMOVE(anchors, pfra, pfr_anchoritem, pfra_sle); free(pfra->pfra_anchorname); free(pfra); @@ -2434,7 +2462,6 @@ pfctl_reset(int dev, int opts) int main(int argc, char *argv[]) { - int exit_val = 0; int ch; int mode = O_RDONLY; int opts = 0; @@ -2732,7 +2759,11 @@ main(int argc, char *argv[]) if (clearopt != NULL) { switch (*clearopt) { case 'r': - pfctl_clear_rules(dev, opts, anchorname); + if (opts & PF_OPT_RECURSE) + pfctl_recurse(dev, opts, anchorname, + pfctl_call_clearrules); + else + pfctl_clear_rules(dev, opts, anchorname); break; case 's': pfctl_clear_states(dev, ifaceopt, opts); @@ -2749,8 +2780,14 @@ main(int argc, char *argv[]) usage(); /* NOTREACHED */ } - pfctl_clear_tables(anchorname, opts); - pfctl_clear_rules(dev, opts, anchorname); + if (opts & PF_OPT_RECURSE) + pfctl_recurse(dev, opts, anchorname, + pfctl_call_clearanchors); + else { + pfctl_clear_tables(anchorname, opts); + pfctl_clear_rules(dev, opts, anchorname); + } + if (!*anchorname) { pfctl_clear_states(dev, ifaceopt, opts); pfctl_clear_src_nodes(dev, opts); @@ -2763,7 +2800,11 @@ main(int argc, char *argv[]) pfctl_clear_fingerprints(dev, opts); break; case 'T': - pfctl_clear_tables(anchorname, opts); + if ((opts & PF_OPT_RECURSE) == 0) + pfctl_clear_tables(anchorname, opts); + else + pfctl_recurse(dev, opts, anchorname, + pfctl_call_cleartables); break; case 'R': pfctl_reset(dev, opts); diff --git a/sbin/pfctl/pfctl.h b/sbin/pfctl/pfctl.h index 7408d56b9c2..6cbd456a21b 100644 --- a/sbin/pfctl/pfctl.h +++ b/sbin/pfctl/pfctl.h @@ -83,7 +83,7 @@ int pfi_get_ifaces(const char *, struct pfi_kif *, int *); int pfi_clr_istats(const char *, int *, int); void pfctl_print_title(char *); -void pfctl_clear_tables(const char *, int); +int pfctl_clear_tables(const char *, int); void pfctl_show_tables(const char *, int); int pfctl_table(int, char *[], char *, const char *, char *, const char *, int); @@ -104,6 +104,7 @@ u_int32_t int pfctl_trans(int, struct pfr_buffer *, u_long, int); int pfctl_show_queues(int, const char *, int, int); + void pfctl_err(int, int, const char *, ...); void pfctl_errx(int, int, const char *, ...); diff --git a/sbin/pfctl/pfctl_table.c b/sbin/pfctl/pfctl_table.c index 9507418644e..6ff9d8c49b0 100644 --- a/sbin/pfctl/pfctl_table.c +++ b/sbin/pfctl/pfctl_table.c @@ -77,7 +77,8 @@ static const char *istats_text[2][2][2] = { if ((!(opts & PF_OPT_NOACTION) || \ (opts & PF_OPT_DUMMYACTION)) && \ (fct)) { \ - radix_perror(); \ + if ((opts & PF_OPT_RECURSE) == 0)\ + radix_perror(); \ goto _error; \ } \ } while (0) @@ -101,11 +102,17 @@ static const char *istats_text[2][2][2] = { table.pfrt_flags &= ~PFR_TFLAG_PERSIST; \ } while(0) -void +int pfctl_clear_tables(const char *anchor, int opts) { - if (pfctl_table(0, NULL, NULL, "-F", NULL, anchor, opts) == -1) - exit(1); + int rv; + + if ((rv = pfctl_table(0, NULL, NULL, "-F", NULL, anchor, opts)) == -1) { + if ((opts & PF_OPT_IGNFAIL) == 0) + exit(1); + } + + return (rv); } void