Limiting the "flush all" operation to a specific interface does not
make sense, and the intention was clear as well:

        pfctl.c revision 1.298
        date: 2010/06/28 23:21:41;  author: mcbride;  state: Exp;  lines: +27 
-11;
        Clean up iterface stats handling:
        - 'make -Fi' reset ALL the interface statistics
             can be restricted with -i ifname
        - 'make -Fa -i ifname' fail (it's meaningless)
        - get rid of a silly little struct that's only used for one thing

        ok henning

Yet, tables and rules are always cleared:

        # pfctl -F all -i foo
        0 tables deleted.
        rules cleared
        pfctl: don't specify an interface with -Fall
        usage: pfctl ...

It even clears statistics for the empty interface:

        # pfctl -F all -i ''
        0 tables deleted.
        rules cleared
        8 states cleared
        source tracking entries cleared
        pf: statistics cleared for interface
        pf: interface flags reset

That's unacceptable.

Currently, the idiom `opt && *opt' is used to test for table, key and
interface arguments, but is inherently unable to detect empy values
since the NULL initialised `opt' is unconditionally set to `optarg'
which may be empty.

Diff below bails out immediately when `-i ...' is passed and hoists
empty option argument checks into the getopt(3) routine.  All code using
these arguments can now rely on them not being empty if given.

        $ ./obj/pfctl -F all -i ''
        pfctl: empty interface name
        # ./obj/pfctl -F all -i foo
        pfctl: don't specify an interface with -Fall
        usage: pfctl ...

Feedback? OK?

Regress passes.

NB: parse.y does accept empty strings for anchors, tables, interfaces
and tables and handles them poorly, but that's stuff for another diff.

Index: pfctl.c
===================================================================
RCS file: /cvs/src/sbin/pfctl/pfctl.c,v
retrieving revision 1.362
diff -u -p -r1.362 pfctl.c
--- pfctl.c     2 Jan 2019 23:08:00 -0000       1.362
+++ pfctl.c     5 Jan 2019 19:03:07 -0000
@@ -2342,6 +2342,8 @@ main(int argc, char *argv[])
            "a:dD:eqf:F:ghi:k:K:L:Nno:Pp:R:rS:s:t:T:vV:x:z")) != -1) {
                switch (ch) {
                case 'a':
+                       if (!*optarg)
+                               errx(1, "emtpy anchor name");
                        anchoropt = optarg;
                        break;
                case 'd':
@@ -2369,6 +2371,8 @@ main(int argc, char *argv[])
                        mode = O_RDWR;
                        break;
                case 'i':
+                       if (!*optarg)
+                               errx(1, "empty interface name");
                        ifaceopt = optarg;
                        break;
                case 'k':
@@ -2377,6 +2381,8 @@ main(int argc, char *argv[])
                                usage();
                                /* NOTREACHED */
                        }
+                       if (!*optarg)
+                               errx(1, "empty state key");
                        state_kill[state_killers++] = optarg;
                        mode = O_RDWR;
                        break;
@@ -2386,6 +2392,8 @@ main(int argc, char *argv[])
                                usage();
                                /* NOTREACHED */
                        }
+                       if (!*optarg)
+                               errx(1, "empty source tracking key");
                        src_node_kill[src_node_killers++] = optarg;
                        mode = O_RDWR;
                        break;
@@ -2434,6 +2442,8 @@ main(int argc, char *argv[])
                        }
                        break;
                case 't':
+                       if (!*optarg)
+                               errx(1, "empty table name");
                        tableopt = optarg;
                        break;
                case 'T':
@@ -2626,13 +2636,13 @@ main(int argc, char *argv[])
                        pfctl_clear_stats(dev, ifaceopt, opts);
                        break;
                case 'a':
-                       pfctl_clear_tables(anchorname, opts);
-                       pfctl_clear_rules(dev, opts, anchorname);
-                       if (ifaceopt && *ifaceopt) {
+                       if (ifaceopt) {
                                warnx("don't specify an interface with -Fall");
                                usage();
                                /* NOTREACHED */
                        }
+                       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);

Reply via email to