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);