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

Reply via email to