Hello, change introduces a pfctl_recurse() function we use to implement recursive flush operation. The pfctl_recurse() is built from two pieces: - pfctl_walk_get(), which itself is a new callback for pfctl_walk() we introduced in earlier patch. The pfctl_walk_get() puts every anchor found in tree to single linked list
- pfctl_get_anchors() uses pfctl_walk() to collect all anchors found in PF driver to list - once there is a list of anchors pfctl_recurse() consumes the list of anchors applying a nuke() function. The nuke() function is an argument to pfctl_recurse(). The actual implementation is subject of follow up diff. I've done some expirements with making pfctl_recurse() to pass a nuke() callback directly to pfctl_walk() function, but the results where 'disappointing'. We soon were tripping a panics on dangling pointers. I think we need to revisit pf_ruleset.c before we will be able to get rid of the extra list here. I'd like to stay pragmatic and go ahead with list and makes things nice and tidy later. thanks and regards sashan --------8<---------------8<---------------8<------------------8<-------- diff --git a/sbin/pfctl/pfctl.c b/sbin/pfctl/pfctl.c index ba3610a6a7b..2c5835df7c6 100644 --- a/sbin/pfctl/pfctl.c +++ b/sbin/pfctl/pfctl.c @@ -107,8 +107,12 @@ void pfctl_state_store(int, const char *); 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(*)(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 *)); const char *clearopt; char *rulesopt; @@ -2123,6 +2127,39 @@ pfctl_walk_show(int opts, struct pfioc_ruleset *pr, void *warg) return (0); } +int +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; + + pfra = malloc(sizeof(*pfra)); + if (pfra == NULL) + err(1, "%s", __func__); + + len = strlen(pr->path) + 1; + len += strlen(pr->name) + 1; + pfra->pfra_anchorname = malloc(len); + if (pfra->pfra_anchorname == NULL) + err(1, "%s", __func__); + + if (pr->path[0]) + snprintf(pfra->pfra_anchorname, len, "%s/%s", + pr->path, pr->name); + 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; + + return (0); +} + int pfctl_walk_anchors(int dev, int opts, char *anchorname, void *warg, int(walkf)(int, struct pfioc_ruleset *, void *)) @@ -2131,7 +2168,7 @@ pfctl_walk_anchors(int dev, int opts, char *anchorname, void *warg, u_int32_t mnr, nr; memset(&pr, 0, sizeof(pr)); - memcpy(pr.path, anchorname, sizeof(pr.path)); + strlcpy(pr.path, anchorname, sizeof(pr.path)); if (ioctl(dev, DIOCGETRULESETS, &pr) == -1) { if (errno == EINVAL) fprintf(stderr, "Anchor '%s' not found.\n", @@ -2179,6 +2216,56 @@ pfctl_show_anchors(int dev, int opts, char *anchorname) return (rv); } +struct pfr_anchors * +pfctl_get_anchors(int dev, int opts) +{ + struct pfioc_ruleset pr; + struct { + struct pfr_anchoritem *pfra; + } pfra; + static struct pfr_anchors anchors; + + 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); + } + SLIST_INSERT_HEAD(&anchors, pfra.pfra, pfra_sle); + + 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", + __func__); + exit(1); + } + + return (&anchors); +} + +int +pfctl_recurse(int dev, int opts, int(*nuke)(int, int, struct pfr_anchoritem *)) +{ + int rv = 0; + struct pfr_anchors *anchors; + struct pfr_anchoritem *pfra, *pfra_save; + + anchors = pfctl_get_anchors(dev, opts); + SLIST_FOREACH_SAFE(pfra, anchors, pfra_sle, pfra_save) { + rv |= nuke(dev, opts, pfra); + SLIST_REMOVE(anchors, pfra, pfr_anchoritem, pfra_sle); + free(pfra->pfra_anchorname); + free(pfra); + } + + return (rv); +} + const char * pfctl_lookup_option(char *cmd, const char **list) { diff --git a/sbin/pfctl/pfctl.h b/sbin/pfctl/pfctl.h index 7981cf66fdb..9e9552e62ae 100644 --- a/sbin/pfctl/pfctl.h +++ b/sbin/pfctl/pfctl.h @@ -48,6 +48,14 @@ struct pfr_buffer { (var) != NULL; \ (var) = pfr_buf_next((buf), (var))) + +struct pfr_anchoritem { + SLIST_ENTRY(pfr_anchoritem) pfra_sle; + char *pfra_anchorname; +}; + +SLIST_HEAD(pfr_anchors, pfr_anchoritem); + int pfr_get_fd(void); int pfr_clr_tables(struct pfr_table *, int *, int); int pfr_add_tables(struct pfr_table *, int, int *, int);