aboutsummaryrefslogtreecommitdiff
path: root/sbin/pfctl
diff options
context:
space:
mode:
Diffstat (limited to 'sbin/pfctl')
-rw-r--r--sbin/pfctl/parse.y107
-rw-r--r--sbin/pfctl/pfctl.838
-rw-r--r--sbin/pfctl/pfctl.c575
-rw-r--r--sbin/pfctl/pfctl.h18
-rw-r--r--sbin/pfctl/pfctl_optimize.c36
-rw-r--r--sbin/pfctl/pfctl_osfp.c2
-rw-r--r--sbin/pfctl/pfctl_parser.c19
-rw-r--r--sbin/pfctl/pfctl_parser.h4
-rw-r--r--sbin/pfctl/pfctl_radix.c13
-rw-r--r--sbin/pfctl/pfctl_table.c80
-rwxr-xr-xsbin/pfctl/tests/macro.sh1
-rw-r--r--sbin/pfctl/tests/pfctl_test.c25
12 files changed, 549 insertions, 369 deletions
diff --git a/sbin/pfctl/parse.y b/sbin/pfctl/parse.y
index c59204d3d5a4..9a917d1d8464 100644
--- a/sbin/pfctl/parse.y
+++ b/sbin/pfctl/parse.y
@@ -95,7 +95,7 @@ static struct file {
int eof_reached;
int lineno;
int errors;
-} *file;
+} *file, *topfile;
struct file *pushfile(const char *, int);
int popfile(void);
int check_file_secrecy(int, const char *);
@@ -921,7 +921,27 @@ varset : STRING '=' varstring {
}
;
-anchorname : STRING { $$ = $1; }
+anchorname : STRING {
+ if ($1[0] == '\0') {
+ free($1);
+ yyerror("anchor name must not be empty");
+ YYERROR;
+ }
+ if (strlen(pf->anchor->path) + 1 +
+ strlen($1) >= PATH_MAX) {
+ free($1);
+ yyerror("anchor name is longer than %u",
+ PATH_MAX - 1);
+ YYERROR;
+ }
+ if ($1[0] == '_' || strstr($1, "/_") != NULL) {
+ free($1);
+ yyerror("anchor names beginning with '_' "
+ "are reserved for internal use");
+ YYERROR;
+ }
+ $$ = $1;
+ }
| /* empty */ { $$ = NULL; }
;
@@ -938,6 +958,8 @@ pfa_anchor : '{'
struct pfctl_ruleset *rs;
/* stepping into a brace anchor */
+ if (pf->asd >= PFCTL_ANCHOR_STACK_DEPTH)
+ errx(1, "pfa_anchor: anchors too deep");
pf->asd++;
pf->bn++;
@@ -974,13 +996,6 @@ anchorrule : ANCHOR anchorname dir quick interface af proto fromto
YYERROR;
}
- if ($2 && ($2[0] == '_' || strstr($2, "/_") != NULL)) {
- free($2);
- yyerror("anchor names beginning with '_' "
- "are reserved for internal use");
- YYERROR;
- }
-
pfctl_init_rule(&r);
if (pf->astack[pf->asd + 1]) {
@@ -1162,14 +1177,11 @@ anchorrule : ANCHOR anchorname dir quick interface af proto fromto
}
;
-loadrule : LOAD ANCHOR string FROM string {
+loadrule : LOAD ANCHOR anchorname FROM string {
struct loadanchors *loadanchor;
- if (strlen(pf->anchor->path) + 1 +
- strlen($3) >= MAXPATHLEN) {
- yyerror("anchorname %s too long, max %u\n",
- $3, MAXPATHLEN - 1);
- free($3);
+ if ($3 == NULL) {
+ yyerror("anchor name is missing");
YYERROR;
}
loadanchor = calloc(1, sizeof(struct loadanchors));
@@ -1251,6 +1263,8 @@ etherpfa_anchor : '{'
struct pfctl_eth_ruleset *rs;
/* steping into a brace anchor */
+ if (pf->asd >= PFCTL_ANCHOR_STACK_DEPTH)
+ errx(1, "pfa_anchor: anchors too deep");
pf->asd++;
pf->bn++;
@@ -3891,7 +3905,7 @@ uid_item : uid {
$$->tail = $$;
}
| unaryop uid {
- if ($2 == UID_MAX && $1 != PF_OP_EQ && $1 != PF_OP_NE) {
+ if ($2 == -1 && $1 != PF_OP_EQ && $1 != PF_OP_NE) {
yyerror("user unknown requires operator = or "
"!=");
YYERROR;
@@ -3906,7 +3920,7 @@ uid_item : uid {
$$->tail = $$;
}
| uid PORTBINARY uid {
- if ($1 == UID_MAX || $3 == UID_MAX) {
+ if ($1 == -1 || $3 == -1) {
yyerror("user unknown requires operator = or "
"!=");
YYERROR;
@@ -3924,7 +3938,7 @@ uid_item : uid {
uid : STRING {
if (!strcmp($1, "unknown"))
- $$ = UID_MAX;
+ $$ = -1;
else {
uid_t uid;
@@ -3969,7 +3983,7 @@ gid_item : gid {
$$->tail = $$;
}
| unaryop gid {
- if ($2 == GID_MAX && $1 != PF_OP_EQ && $1 != PF_OP_NE) {
+ if ($2 == -1 && $1 != PF_OP_EQ && $1 != PF_OP_NE) {
yyerror("group unknown requires operator = or "
"!=");
YYERROR;
@@ -3984,7 +3998,7 @@ gid_item : gid {
$$->tail = $$;
}
| gid PORTBINARY gid {
- if ($1 == GID_MAX || $3 == GID_MAX) {
+ if ($1 == -1 || $3 == -1) {
yyerror("group unknown requires operator = or "
"!=");
YYERROR;
@@ -4002,7 +4016,7 @@ gid_item : gid {
gid : STRING {
if (!strcmp($1, "unknown"))
- $$ = GID_MAX;
+ $$ = -1;
else {
gid_t gid;
@@ -5424,6 +5438,12 @@ process_tabledef(char *name, struct table_opts *opts, int popts)
if (pf->opts & PF_OPT_VERBOSE)
print_tabledef(name, opts->flags, opts->init_addr,
&opts->init_nodes);
+ if (!(pf->opts & PF_OPT_NOACTION) ||
+ (pf->opts & PF_OPT_DUMMYACTION))
+ warn_duplicate_tables(name, pf->anchor->path);
+ else if (pf->opts & PF_OPT_VERBOSE)
+ fprintf(stderr, "%s:%d: skipping duplicate table checks"
+ " for <%s>\n", file->name, yylval.lineno, name);
if (!(pf->opts & PF_OPT_NOACTION) &&
pfctl_define_table(name, opts->flags, opts->init_addr,
pf->anchor->path, &ab, pf->anchor->ruleset.tticket)) {
@@ -5438,7 +5458,7 @@ process_tabledef(char *name, struct table_opts *opts, int popts)
name);
else
yyerror("cannot define table %s: %s", name,
- pfr_strerror(errno));
+ pf_strerror(errno));
goto _error;
}
@@ -6723,7 +6743,7 @@ lgetc(int quotec)
if (quotec) {
if ((c = igetc()) == EOF) {
yyerror("reached end of file while parsing quoted string");
- if (popfile() == EOF)
+ if (file == topfile || popfile() == EOF)
return (EOF);
return (quotec);
}
@@ -6751,7 +6771,7 @@ lgetc(int quotec)
return ('\n');
}
while (c == EOF) {
- if (popfile() == EOF)
+ if (file == topfile || popfile() == EOF)
return (EOF);
c = igetc();
}
@@ -6918,7 +6938,7 @@ top:
if (c == '-' || isdigit(c)) {
do {
*p++ = c;
- if ((unsigned)(p-buf) >= sizeof(buf)) {
+ if ((size_t)(p-buf) >= sizeof(buf)) {
yyerror("string too long");
return (findeol());
}
@@ -6957,7 +6977,7 @@ nodigits:
if (isalnum(c) || c == ':' || c == '_') {
do {
*p++ = c;
- if ((unsigned)(p-buf) >= sizeof(buf)) {
+ if ((size_t)(p-buf) >= sizeof(buf)) {
yyerror("string too long");
return (findeol());
}
@@ -7049,17 +7069,17 @@ popfile(void)
{
struct file *prev;
- if ((prev = TAILQ_PREV(file, files, entry)) != NULL) {
+ if ((prev = TAILQ_PREV(file, files, entry)) != NULL)
prev->errors += file->errors;
- TAILQ_REMOVE(&files, file, entry);
- fclose(file->stream);
- free(file->name);
- free(file->ungetbuf);
- free(file);
- file = prev;
- return (0);
- }
- return (EOF);
+
+ TAILQ_REMOVE(&files, file, entry);
+ fclose(file->stream);
+ free(file->name);
+ free(file->ungetbuf);
+ free(file);
+ file = prev;
+
+ return (file ? 0 : EOF);
}
int
@@ -7082,6 +7102,7 @@ parse_config(char *filename, struct pfctl *xpf)
warn("cannot open the main config file!");
return (-1);
}
+ topfile = file;
yyparse();
errors = file->errors;
@@ -7181,19 +7202,11 @@ mv_rules(struct pfctl_ruleset *src, struct pfctl_ruleset *dst)
struct pfctl_rule *r;
for (i = 0; i < PF_RULESET_MAX; ++i) {
- while ((r = TAILQ_FIRST(src->rules[i].active.ptr))
- != NULL) {
- TAILQ_REMOVE(src->rules[i].active.ptr, r, entries);
- TAILQ_INSERT_TAIL(dst->rules[i].active.ptr, r, entries);
+ TAILQ_FOREACH(r, src->rules[i].active.ptr, entries)
dst->anchor->match++;
- }
+ TAILQ_CONCAT(dst->rules[i].active.ptr, src->rules[i].active.ptr, entries);
src->anchor->match = 0;
- while ((r = TAILQ_FIRST(src->rules[i].inactive.ptr))
- != NULL) {
- TAILQ_REMOVE(src->rules[i].inactive.ptr, r, entries);
- TAILQ_INSERT_TAIL(dst->rules[i].inactive.ptr,
- r, entries);
- }
+ TAILQ_CONCAT(dst->rules[i].inactive.ptr, src->rules[i].inactive.ptr, entries);
}
}
diff --git a/sbin/pfctl/pfctl.8 b/sbin/pfctl/pfctl.8
index c7fad58262dc..f582c6301124 100644
--- a/sbin/pfctl/pfctl.8
+++ b/sbin/pfctl/pfctl.8
@@ -24,7 +24,7 @@
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
-.Dd June 30, 2025
+.Dd July 7, 2025
.Dt PFCTL 8
.Os
.Sh NAME
@@ -186,6 +186,13 @@ as the anchor name:
.Bd -literal -offset indent
# pfctl -a '*' -sr
.Ed
+.Pp
+To flush all rulesets and tables recursively, specify only
+.Sq *
+as the anchor name:
+.Bd -literal -offset indent
+# pfctl -a '*' -Fa
+.Ed
.It Fl D Ar macro Ns = Ns Ar value
Define
.Ar macro
@@ -223,9 +230,27 @@ Flush the filter information (statistics that are not bound to rules).
Flush the tables.
.It Fl F Cm osfp
Flush the passive operating system fingerprints.
+.It Fl F Cm Reset
+Reset limits, timeouts and other options back to default settings.
+See the OPTIONS section in
+.Xr pf.conf 5
+for details.
.It Fl F Cm all
Flush all of the above.
.El
+.Pp
+If
+.Fl a
+is specified as well and
+.Ar anchor
+is terminated with a
+.Sq *
+character,
+.Cm rules ,
+.Cm Tables
+and
+.Cm all
+flush the given anchor recursively.
.It Fl f Ar file
Load the rules contained in
.Ar file .
@@ -401,7 +426,11 @@ Only print errors and warnings.
Load only the filter rules present in the rule file.
Other rules and options are ignored.
.It Fl r
-Perform reverse DNS lookups on states when displaying them.
+Perform reverse DNS lookups on states and tables when displaying them.
+.Fl N
+and
+.Fl r
+are mutually exclusive.
.It Fl s Ar modifier
Show the filter parameters specified by
.Ar modifier
@@ -458,7 +487,10 @@ Show the contents of the source tracking table.
Show filter information (statistics and counters).
When used together with
.Fl v ,
-source tracking statistics are also shown.
+source tracking statistics, the firewall's 32-bit hostid number and the
+main ruleset's MD5 checksum for use with
+.Xr pfsync 4
+are also shown.
.It Fl s Cm Running
Show the running status and provide a non-zero exit status when disabled.
.It Fl s Cm labels
diff --git a/sbin/pfctl/pfctl.c b/sbin/pfctl/pfctl.c
index 8c6497b4d1ee..271286deeda7 100644
--- a/sbin/pfctl/pfctl.c
+++ b/sbin/pfctl/pfctl.c
@@ -59,6 +59,8 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+#include <stdarg.h>
+#include <libgen.h>
#include "pfctl_parser.h"
#include "pfctl.h"
@@ -72,13 +74,14 @@ void pfctl_check_skip_ifaces(char *);
void pfctl_adjust_skip_ifaces(struct pfctl *);
void pfctl_clear_interface_flags(int, int);
void pfctl_flush_eth_rules(int, int, char *);
-void pfctl_flush_rules(int, int, char *);
+int pfctl_flush_rules(int, int, char *);
void pfctl_flush_nat(int, int, char *);
int pfctl_clear_altq(int, int);
void pfctl_clear_src_nodes(int, int);
void pfctl_clear_iface_states(int, const char *, int);
-void pfctl_addrprefix(char *, struct pf_addr *);
-void pfctl_kill_src_nodes(int, const char *, int);
+struct addrinfo *
+ pfctl_addrprefix(char *, struct pf_addr *, int);
+void pfctl_kill_src_nodes(int, int);
void pfctl_net_kill_states(int, const char *, int);
void pfctl_gateway_kill_states(int, const char *, int);
void pfctl_label_kill_states(int, const char *, int);
@@ -122,6 +125,18 @@ int pfctl_load_ruleset(struct pfctl *, char *,
struct pfctl_ruleset *, int, int);
int pfctl_load_rule(struct pfctl *, char *, struct pfctl_rule *, int);
const char *pfctl_lookup_option(char *, const char * const *);
+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, const char *,
+ int(*)(int, struct pfioc_ruleset *, void *), void *);
+struct pfr_anchors *
+ pfctl_get_anchors(int, char *, int);
+int pfctl_recurse(int, int, 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 *);
static struct pfctl_anchor_global pf_anchors;
struct pfctl_anchor pf_main_anchor;
@@ -149,6 +164,7 @@ int dev = -1;
struct pfctl_handle *pfh = NULL;
static int first_title = 1;
static int labels = 0;
+static int exit_val = 0;
#define INDENT(d, o) do { \
if (o) { \
@@ -230,7 +246,7 @@ static const struct {
static const char * const clearopt_list[] = {
"nat", "queue", "rules", "Sources",
"states", "info", "Tables", "osfp", "all",
- "ethernet", NULL
+ "ethernet", "Reset", NULL
};
static const char * const showopt_list[] = {
@@ -267,6 +283,40 @@ usage(void)
exit(1);
}
+void
+pfctl_err(int opts, int eval, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+
+ if ((opts & PF_OPT_IGNFAIL) == 0)
+ verr(eval, fmt, ap);
+ else
+ vwarn(fmt, ap);
+
+ va_end(ap);
+
+ exit_val = eval;
+}
+
+void
+pfctl_errx(int opts, int eval, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+
+ if ((opts & PF_OPT_IGNFAIL) == 0)
+ verrx(eval, fmt, ap);
+ else
+ vwarnx(fmt, ap);
+
+ va_end(ap);
+
+ exit_val = eval;
+}
+
/*
* Cache protocol number to name translations.
*
@@ -359,7 +409,7 @@ pfctl_clear_stats(struct pfctl_handle *h, int opts)
{
int ret;
if ((ret = pfctl_clear_status(h)) != 0)
- errc(1, ret, "DIOCCLRSTATUS");
+ pfctl_err(opts, 1, "DIOCCLRSTATUS");
if ((opts & PF_OPT_QUIET) == 0)
fprintf(stderr, "pf: statistics cleared\n");
}
@@ -467,16 +517,19 @@ pfctl_flush_eth_rules(int dev, int opts, char *anchorname)
fprintf(stderr, "Ethernet rules cleared\n");
}
-void
+int
pfctl_flush_rules(int dev, int opts, char *anchorname)
{
int ret;
ret = pfctl_clear_rules(dev, anchorname);
- if (ret != 0)
- err(1, "pfctl_clear_rules");
- if ((opts & PF_OPT_QUIET) == 0)
+ if (ret != 0) {
+ pfctl_err(opts, 1, "%s", __func__);
+ return (1);
+ } else if ((opts & PF_OPT_QUIET) == 0)
fprintf(stderr, "rules cleared\n");
+
+ return (0);
}
void
@@ -513,7 +566,7 @@ void
pfctl_clear_src_nodes(int dev, int opts)
{
if (ioctl(dev, DIOCCLRSRCNODES))
- err(1, "DIOCCLRSRCNODES");
+ pfctl_err(opts, 1, "DIOCCLRSRCNODES");
if ((opts & PF_OPT_QUIET) == 0)
fprintf(stderr, "source tracking entries cleared\n");
}
@@ -528,46 +581,47 @@ pfctl_clear_iface_states(int dev, const char *iface, int opts)
memset(&kill, 0, sizeof(kill));
if (iface != NULL && strlcpy(kill.ifname, iface,
sizeof(kill.ifname)) >= sizeof(kill.ifname))
- errx(1, "invalid interface: %s", iface);
+ pfctl_errx(opts, 1, "invalid interface: %s", iface);
if (opts & PF_OPT_KILLMATCH)
kill.kill_match = true;
if ((ret = pfctl_clear_states_h(pfh, &kill, &killed)) != 0)
- errc(1, ret, "DIOCCLRSTATES");
+ pfctl_err(opts, 1, "DIOCCLRSTATUS");
if ((opts & PF_OPT_QUIET) == 0)
fprintf(stderr, "%d states cleared\n", killed);
}
-void
-pfctl_addrprefix(char *addr, struct pf_addr *mask)
+struct addrinfo *
+pfctl_addrprefix(char *addr, struct pf_addr *mask, int numeric)
{
char *p;
const char *errstr;
int prefix, ret_ga, q, r;
struct addrinfo hints, *res;
- if ((p = strchr(addr, '/')) == NULL)
- return;
-
- *p++ = '\0';
- prefix = strtonum(p, 0, 128, &errstr);
- if (errstr)
- errx(1, "prefix is %s: %s", errstr, p);
-
bzero(&hints, sizeof(hints));
- /* prefix only with numeric addresses */
- hints.ai_flags |= AI_NUMERICHOST;
+ hints.ai_socktype = SOCK_DGRAM; /* dummy */
+ if (numeric)
+ hints.ai_flags = AI_NUMERICHOST;
+
+ if ((p = strchr(addr, '/')) != NULL) {
+ *p++ = '\0';
+ /* prefix only with numeric addresses */
+ hints.ai_flags |= AI_NUMERICHOST;
+ }
if ((ret_ga = getaddrinfo(addr, NULL, &hints, &res))) {
errx(1, "getaddrinfo: %s", gai_strerror(ret_ga));
/* NOTREACHED */
}
- if (res->ai_family == AF_INET && prefix > 32)
- errx(1, "prefix too long for AF_INET");
- else if (res->ai_family == AF_INET6 && prefix > 128)
- errx(1, "prefix too long for AF_INET6");
+ if (p == NULL)
+ return (res);
+
+ prefix = strtonum(p, 0, res->ai_family == AF_INET6 ? 128 : 32, &errstr);
+ if (errstr)
+ errx(1, "prefix is %s: %s", errstr, p);
q = prefix >> 3;
r = prefix & 7;
@@ -586,17 +640,17 @@ pfctl_addrprefix(char *addr, struct pf_addr *mask)
(0xff00 >> r) & 0xff;
break;
}
- freeaddrinfo(res);
+
+ return (res);
}
void
-pfctl_kill_src_nodes(int dev, const char *iface, int opts)
+pfctl_kill_src_nodes(int dev, int opts)
{
struct pfioc_src_node_kill psnk;
struct addrinfo *res[2], *resp[2];
struct sockaddr last_src, last_dst;
int killed, sources, dests;
- int ret_ga;
killed = sources = dests = 0;
@@ -606,12 +660,9 @@ pfctl_kill_src_nodes(int dev, const char *iface, int opts)
memset(&last_src, 0xff, sizeof(last_src));
memset(&last_dst, 0xff, sizeof(last_dst));
- pfctl_addrprefix(src_node_kill[0], &psnk.psnk_src.addr.v.a.mask);
+ res[0] = pfctl_addrprefix(src_node_kill[0],
+ &psnk.psnk_src.addr.v.a.mask, (opts & PF_OPT_NODNS));
- if ((ret_ga = getaddrinfo(src_node_kill[0], NULL, NULL, &res[0]))) {
- errx(1, "getaddrinfo: %s", gai_strerror(ret_ga));
- /* NOTREACHED */
- }
for (resp[0] = res[0]; resp[0]; resp[0] = resp[0]->ai_next) {
if (resp[0]->ai_addr == NULL)
continue;
@@ -623,29 +674,16 @@ pfctl_kill_src_nodes(int dev, const char *iface, int opts)
psnk.psnk_af = resp[0]->ai_family;
sources++;
- if (psnk.psnk_af == AF_INET)
- psnk.psnk_src.addr.v.a.addr.v4 =
- ((struct sockaddr_in *)resp[0]->ai_addr)->sin_addr;
- else if (psnk.psnk_af == AF_INET6)
- psnk.psnk_src.addr.v.a.addr.v6 =
- ((struct sockaddr_in6 *)resp[0]->ai_addr)->
- sin6_addr;
- else
- errx(1, "Unknown address family %d", psnk.psnk_af);
+ copy_satopfaddr(&psnk.psnk_src.addr.v.a.addr, resp[0]->ai_addr);
if (src_node_killers > 1) {
dests = 0;
memset(&psnk.psnk_dst.addr.v.a.mask, 0xff,
sizeof(psnk.psnk_dst.addr.v.a.mask));
memset(&last_dst, 0xff, sizeof(last_dst));
- pfctl_addrprefix(src_node_kill[1],
- &psnk.psnk_dst.addr.v.a.mask);
- if ((ret_ga = getaddrinfo(src_node_kill[1], NULL, NULL,
- &res[1]))) {
- errx(1, "getaddrinfo: %s",
- gai_strerror(ret_ga));
- /* NOTREACHED */
- }
+ res[1] = pfctl_addrprefix(src_node_kill[1],
+ &psnk.psnk_dst.addr.v.a.mask,
+ (opts & PF_OPT_NODNS));
for (resp[1] = res[1]; resp[1];
resp[1] = resp[1]->ai_next) {
if (resp[1]->ai_addr == NULL)
@@ -660,18 +698,8 @@ pfctl_kill_src_nodes(int dev, const char *iface, int opts)
dests++;
- if (psnk.psnk_af == AF_INET)
- psnk.psnk_dst.addr.v.a.addr.v4 =
- ((struct sockaddr_in *)resp[1]->
- ai_addr)->sin_addr;
- else if (psnk.psnk_af == AF_INET6)
- psnk.psnk_dst.addr.v.a.addr.v6 =
- ((struct sockaddr_in6 *)resp[1]->
- ai_addr)->sin6_addr;
- else
- errx(1, "Unknown address family %d",
- psnk.psnk_af);
-
+ copy_satopfaddr(&psnk.psnk_src.addr.v.a.addr,
+ resp[1]->ai_addr);
if (ioctl(dev, DIOCKILLSRCNODES, &psnk))
err(1, "DIOCKILLSRCNODES");
killed += psnk.psnk_killed;
@@ -699,7 +727,7 @@ pfctl_net_kill_states(int dev, const char *iface, int opts)
struct sockaddr last_src, last_dst;
unsigned int newkilled;
int killed, sources, dests;
- int ret_ga, ret;
+ int ret;
killed = sources = dests = 0;
@@ -710,7 +738,7 @@ pfctl_net_kill_states(int dev, const char *iface, int opts)
memset(&last_dst, 0xff, sizeof(last_dst));
if (iface != NULL && strlcpy(kill.ifname, iface,
sizeof(kill.ifname)) >= sizeof(kill.ifname))
- errx(1, "invalid interface: %s", iface);
+ pfctl_errx(opts, 1, "invalid interface: %s", iface);
if (state_killers == 2 && (strcmp(state_kill[0], "nat") == 0)) {
kill.nat = true;
@@ -718,15 +746,12 @@ pfctl_net_kill_states(int dev, const char *iface, int opts)
state_killers = 1;
}
- pfctl_addrprefix(state_kill[0], &kill.src.addr.v.a.mask);
+ res[0] = pfctl_addrprefix(state_kill[0],
+ &kill.src.addr.v.a.mask, (opts & PF_OPT_NODNS));
if (opts & PF_OPT_KILLMATCH)
kill.kill_match = true;
- if ((ret_ga = getaddrinfo(state_kill[0], NULL, NULL, &res[0]))) {
- errx(1, "getaddrinfo: %s", gai_strerror(ret_ga));
- /* NOTREACHED */
- }
for (resp[0] = res[0]; resp[0]; resp[0] = resp[0]->ai_next) {
if (resp[0]->ai_addr == NULL)
continue;
@@ -738,29 +763,16 @@ pfctl_net_kill_states(int dev, const char *iface, int opts)
kill.af = resp[0]->ai_family;
sources++;
- if (kill.af == AF_INET)
- kill.src.addr.v.a.addr.v4 =
- ((struct sockaddr_in *)resp[0]->ai_addr)->sin_addr;
- else if (kill.af == AF_INET6)
- kill.src.addr.v.a.addr.v6 =
- ((struct sockaddr_in6 *)resp[0]->ai_addr)->
- sin6_addr;
- else
- errx(1, "Unknown address family %d", kill.af);
+ copy_satopfaddr(&kill.src.addr.v.a.addr, resp[0]->ai_addr);
if (state_killers > 1) {
dests = 0;
memset(&kill.dst.addr.v.a.mask, 0xff,
sizeof(kill.dst.addr.v.a.mask));
memset(&last_dst, 0xff, sizeof(last_dst));
- pfctl_addrprefix(state_kill[1],
- &kill.dst.addr.v.a.mask);
- if ((ret_ga = getaddrinfo(state_kill[1], NULL, NULL,
- &res[1]))) {
- errx(1, "getaddrinfo: %s",
- gai_strerror(ret_ga));
- /* NOTREACHED */
- }
+ res[1] = pfctl_addrprefix(state_kill[1],
+ &kill.dst.addr.v.a.mask,
+ (opts & PF_OPT_NODNS));
for (resp[1] = res[1]; resp[1];
resp[1] = resp[1]->ai_next) {
if (resp[1]->ai_addr == NULL)
@@ -775,26 +787,17 @@ pfctl_net_kill_states(int dev, const char *iface, int opts)
dests++;
- if (kill.af == AF_INET)
- kill.dst.addr.v.a.addr.v4 =
- ((struct sockaddr_in *)resp[1]->
- ai_addr)->sin_addr;
- else if (kill.af == AF_INET6)
- kill.dst.addr.v.a.addr.v6 =
- ((struct sockaddr_in6 *)resp[1]->
- ai_addr)->sin6_addr;
- else
- errx(1, "Unknown address family %d",
- kill.af);
+ copy_satopfaddr(&kill.src.addr.v.a.addr,
+ resp[1]->ai_addr);
if ((ret = pfctl_kill_states_h(pfh, &kill, &newkilled)) != 0)
- errc(1, ret, "DIOCKILLSTATES");
+ pfctl_errx(opts, 1, "DIOCKILLSTATES");
killed += newkilled;
}
freeaddrinfo(res[1]);
} else {
if ((ret = pfctl_kill_states_h(pfh, &kill, &newkilled)) != 0)
- errc(1, ret, "DIOCKILLSTATES");
+ pfctl_errx(opts, 1, "DIOCKILLSTATES");
killed += newkilled;
}
}
@@ -814,7 +817,6 @@ pfctl_gateway_kill_states(int dev, const char *iface, int opts)
struct sockaddr last_src;
unsigned int newkilled;
int killed = 0;
- int ret_ga;
if (state_killers != 2 || (strlen(state_kill[1]) == 0)) {
warnx("no gateway specified");
@@ -827,17 +829,14 @@ pfctl_gateway_kill_states(int dev, const char *iface, int opts)
memset(&last_src, 0xff, sizeof(last_src));
if (iface != NULL && strlcpy(kill.ifname, iface,
sizeof(kill.ifname)) >= sizeof(kill.ifname))
- errx(1, "invalid interface: %s", iface);
+ pfctl_errx(opts, 1, "invalid interface: %s", iface);
if (opts & PF_OPT_KILLMATCH)
kill.kill_match = true;
- pfctl_addrprefix(state_kill[1], &kill.rt_addr.addr.v.a.mask);
+ res = pfctl_addrprefix(state_kill[1], &kill.rt_addr.addr.v.a.mask,
+ (opts & PF_OPT_NODNS));
- if ((ret_ga = getaddrinfo(state_kill[1], NULL, NULL, &res))) {
- errx(1, "getaddrinfo: %s", gai_strerror(ret_ga));
- /* NOTREACHED */
- }
for (resp = res; resp; resp = resp->ai_next) {
if (resp->ai_addr == NULL)
continue;
@@ -848,18 +847,10 @@ pfctl_gateway_kill_states(int dev, const char *iface, int opts)
kill.af = resp->ai_family;
- if (kill.af == AF_INET)
- kill.rt_addr.addr.v.a.addr.v4 =
- ((struct sockaddr_in *)resp->ai_addr)->sin_addr;
- else if (kill.af == AF_INET6)
- kill.rt_addr.addr.v.a.addr.v6 =
- ((struct sockaddr_in6 *)resp->ai_addr)->
- sin6_addr;
- else
- errx(1, "Unknown address family %d", kill.af);
-
+ copy_satopfaddr(&kill.rt_addr.addr.v.a.addr,
+ resp->ai_addr);
if (pfctl_kill_states_h(pfh, &kill, &newkilled))
- err(1, "DIOCKILLSTATES");
+ pfctl_errx(opts, 1, "DIOCKILLSTATES");
killed += newkilled;
}
@@ -883,7 +874,7 @@ pfctl_label_kill_states(int dev, const char *iface, int opts)
memset(&kill, 0, sizeof(kill));
if (iface != NULL && strlcpy(kill.ifname, iface,
sizeof(kill.ifname)) >= sizeof(kill.ifname))
- errx(1, "invalid interface: %s", iface);
+ pfctl_errx(opts, 1, "invalid interface: %s", iface);
if (opts & PF_OPT_KILLMATCH)
kill.kill_match = true;
@@ -893,7 +884,7 @@ pfctl_label_kill_states(int dev, const char *iface, int opts)
errx(1, "label too long: %s", state_kill[1]);
if ((ret = pfctl_kill_states_h(pfh, &kill, &killed)) != 0)
- errc(1, ret, "DIOCKILLSTATES");
+ pfctl_errx(opts, 1, "DIOCKILLSTATES");
if ((opts & PF_OPT_QUIET) == 0)
fprintf(stderr, "killed %d states\n", killed);
@@ -931,7 +922,7 @@ pfctl_id_kill_states(int dev, const char *iface, int opts)
}
if ((ret = pfctl_kill_states_h(pfh, &kill, &killed)) != 0)
- errc(1, ret, "DIOCKILLSTATES");
+ pfctl_errx(opts, 1, "DIOCKILLSTATES");
if ((opts & PF_OPT_QUIET) == 0)
fprintf(stderr, "killed %d states\n", killed);
@@ -955,7 +946,7 @@ pfctl_key_kill_states(int dev, const char *iface, int opts)
if (iface != NULL &&
strlcpy(kill.ifname, iface, sizeof(kill.ifname)) >=
sizeof(kill.ifname))
- errx(1, "invalid interface: %s", iface);
+ pfctl_errx(opts, 1, "invalid interface: %s", iface);
s = strdup(state_kill[1]);
if (!s)
@@ -991,7 +982,7 @@ pfctl_key_kill_states(int dev, const char *iface, int opts)
errx(1, "invalid host: %s", tokens[didx]);
if ((ret = pfctl_kill_states_h(pfh, &kill, &killed)) != 0)
- errc(1, ret, "DIOCKILLSTATES");
+ pfctl_errx(opts, 1, "DIOCKILLSTATES");
if ((opts & PF_OPT_QUIET) == 0)
fprintf(stderr, "killed %d states\n", killed);
@@ -1002,8 +993,6 @@ pfctl_parse_host(char *str, struct pf_rule_addr *addr)
{
char *s = NULL, *sbs, *sbe;
struct addrinfo hints, *ai;
- struct sockaddr_in *sin4;
- struct sockaddr_in6 *sin6;
s = strdup(str);
if (!s)
@@ -1026,19 +1015,10 @@ pfctl_parse_host(char *str, struct pf_rule_addr *addr)
if (getaddrinfo(s, sbs, &hints, &ai) != 0)
goto error;
- switch (ai->ai_family) {
- case AF_INET:
- sin4 = (struct sockaddr_in *)ai->ai_addr;
- addr->addr.v.a.addr.v4 = sin4->sin_addr;
- addr->port[0] = sin4->sin_port;
- break;
-
- case AF_INET6:
- sin6 = (struct sockaddr_in6 *)ai->ai_addr;
- addr->addr.v.a.addr.v6 = sin6->sin6_addr;
- addr->port[0] = sin6->sin6_port;
- break;
- }
+ copy_satopfaddr(&addr->addr.v.a.addr, ai->ai_addr);
+ addr->port[0] = ai->ai_family == AF_INET6 ?
+ ((struct sockaddr_in6 *)ai->ai_addr)->sin6_port :
+ ((struct sockaddr_in *)ai->ai_addr)->sin_port;
freeaddrinfo(ai);
free(s);
@@ -1360,17 +1340,12 @@ pfctl_show_rules(int dev, char *path, int opts, enum pfctl_show format,
u_int32_t mnr, nr;
memset(&prs, 0, sizeof(prs));
- if ((ret = pfctl_get_rulesets(pfh, npath, &mnr)) != 0) {
- if (ret == EINVAL)
- fprintf(stderr, "Anchor '%s' "
- "not found.\n", anchorname);
- else
- errc(1, ret, "DIOCGETRULESETS");
- }
+ if ((ret = pfctl_get_rulesets(pfh, npath, &mnr)) != 0)
+ errx(1, "%s", pf_strerror(ret));
for (nr = 0; nr < mnr; ++nr) {
if ((ret = pfctl_get_ruleset(pfh, npath, nr, &prs)) != 0)
- errc(1, ret, "DIOCGETRULESET");
+ errx(1, "%s", pf_strerror(ret));
INDENT(depth, !(opts & PF_OPT_VERBOSE));
printf("anchor \"%s\" all {\n", prs.name);
pfctl_show_rules(dev, npath, opts,
@@ -1385,14 +1360,14 @@ pfctl_show_rules(int dev, char *path, int opts, enum pfctl_show format,
if (opts & PF_OPT_SHOWALL) {
ret = pfctl_get_rules_info_h(pfh, &ri, PF_PASS, path);
if (ret != 0) {
- warnc(ret, "DIOCGETRULES");
+ warnx("%s", pf_strerror(ret));
goto error;
}
header++;
}
ret = pfctl_get_rules_info_h(pfh, &ri, PF_SCRUB, path);
if (ret != 0) {
- warnc(ret, "DIOCGETRULES");
+ warnx("%s", pf_strerror(ret));
goto error;
}
if (opts & PF_OPT_SHOWALL) {
@@ -1585,12 +1560,12 @@ pfctl_show_nat(int dev, const char *path, int opts, char *anchorname, int depth,
fprintf(stderr, "NAT anchor '%s' "
"not found.\n", anchorname);
else
- errc(1, ret, "DIOCGETRULESETS");
+ errx(1, "%s", pf_strerror(ret));
}
for (nr = 0; nr < mnr; ++nr) {
if ((ret = pfctl_get_ruleset(pfh, npath, nr, &prs)) != 0)
- errc(1, ret, "DIOCGETRULESET");
+ errx(1, "%s", pf_strerror(ret));
INDENT(depth, !(opts & PF_OPT_VERBOSE));
printf("nat-anchor \"%s\" all {\n", prs.name);
pfctl_show_nat(dev, npath, opts,
@@ -1703,7 +1678,7 @@ pfctl_show_states(int dev, const char *iface, int opts)
struct pfctl_state_filter filter = {};
if (iface != NULL)
- strncpy(filter.ifname, iface, IFNAMSIZ);
+ strlcpy(filter.ifname, iface, IFNAMSIZ);
arg.opts = opts;
arg.dotitle = opts & PF_OPT_SHOWALL;
@@ -2109,13 +2084,12 @@ pfctl_load_ruleset(struct pfctl *pf, char *path, struct pfctl_ruleset *rs,
if ((pf->opts & PF_OPT_NOACTION) == 0 &&
(error = pfctl_ruleset_trans(pf,
path, rs->anchor, false))) {
- printf("pfctl_load_rulesets: "
- "pfctl_ruleset_trans %d\n", error);
+ printf("%s: "
+ "pfctl_ruleset_trans %d\n", __func__, error);
goto error;
}
} else if (pf->opts & PF_OPT_VERBOSE)
printf("\n");
-
}
if (pf->optimize && rs_num == PF_RULESET_FILTER)
@@ -2877,7 +2851,7 @@ pfctl_set_interface_flags(struct pfctl *pf, char *ifname, int flags, int how)
if ((pf->opts & PF_OPT_NOACTION) == 0) {
if (how == 0) {
if (ioctl(pf->dev, DIOCCLRIFFLAG, &pi))
- err(1, "DIOCCLRIFFLAG");
+ pfctl_err(pf->opts, 1, "DIOCCLRIFFLAG");
} else {
if (ioctl(pf->dev, DIOCSETIFFLAG, &pi))
err(1, "DIOCSETIFFLAG");
@@ -2936,43 +2910,175 @@ pfctl_test_altqsupport(int dev, int opts)
}
int
-pfctl_show_anchors(int dev, int opts, char *anchorname)
+pfctl_walk_show(int opts, struct pfioc_ruleset *pr, void *warg)
+{
+ if (pr->path[0]) {
+ if (pr->path[0] != '_' || (opts & PF_OPT_VERBOSE))
+ printf(" %s/%s\n", pr->path, pr->name);
+ } else if (pr->name[0] != '_' || (opts & PF_OPT_VERBOSE))
+ printf(" %s\n", pr->name);
+
+ return (0);
+}
+
+int
+pfctl_walk_get(int opts, struct pfioc_ruleset *pr, void *warg)
+{
+ struct pfr_anchoritem *pfra;
+ struct pfr_anchors *anchors;
+ int e;
+
+ anchors = (struct pfr_anchors *)warg;
+
+ pfra = malloc(sizeof(*pfra));
+ if (pfra == NULL)
+ err(1, "%s", __func__);
+
+ if (pr->path[0])
+ e = asprintf(&pfra->pfra_anchorname, "%s/%s", pr->path,
+ pr->name);
+ else
+ e = asprintf(&pfra->pfra_anchorname, "%s", pr->name);
+
+ if (e == -1)
+ err(1, "%s", __func__);
+
+ SLIST_INSERT_HEAD(anchors, pfra, pfra_sle);
+
+ return (0);
+}
+
+int
+pfctl_walk_anchors(int dev, int opts, const char *anchor,
+ int(walkf)(int, struct pfioc_ruleset *, void *), void *warg)
{
struct pfioc_ruleset pr;
u_int32_t mnr, nr;
int ret;
memset(&pr, 0, sizeof(pr));
- if ((ret = pfctl_get_rulesets(pfh, anchorname, &mnr)) != 0) {
- if (ret == EINVAL)
- fprintf(stderr, "Anchor '%s' not found.\n",
- anchorname);
- else
- errc(1, ret, "DIOCGETRULESETS");
- return (-1);
- }
+ if ((ret = pfctl_get_rulesets(pfh, anchor, &mnr)) != 0)
+ errx(1, "%s", pf_strerror(ret));
for (nr = 0; nr < mnr; ++nr) {
char sub[MAXPATHLEN];
- if ((ret = pfctl_get_ruleset(pfh, anchorname, nr, &pr)) != 0)
+ if ((ret = pfctl_get_ruleset(pfh, anchor, nr, &pr)) != 0)
errc(1, ret, "DIOCGETRULESET");
if (!strcmp(pr.name, PF_RESERVED_ANCHOR))
continue;
- sub[0] = 0;
- if (pr.path[0]) {
- strlcat(sub, pr.path, sizeof(sub));
- strlcat(sub, "/", sizeof(sub));
- }
- strlcat(sub, pr.name, sizeof(sub));
- if (sub[0] != '_' || (opts & PF_OPT_VERBOSE))
- printf(" %s\n", sub);
- if ((opts & PF_OPT_VERBOSE) && pfctl_show_anchors(dev, opts, sub))
+ sub[0] = '\0';
+ if (walkf(opts, &pr, warg))
+ return (-1);
+
+ if (pr.path[0])
+ snprintf(sub, sizeof(sub), "%s/%s", pr.path, pr.name);
+ else
+ snprintf(sub, sizeof(sub), "%s", pr.name);
+ if (pfctl_walk_anchors(dev, opts, sub, walkf, warg))
return (-1);
}
return (0);
}
int
+pfctl_show_anchors(int dev, int opts, char *anchor)
+{
+ return (
+ pfctl_walk_anchors(dev, opts, anchor, pfctl_walk_show, NULL));
+}
+
+struct pfr_anchors *
+pfctl_get_anchors(int dev, char *anchor, int opts)
+{
+ struct pfioc_ruleset pr;
+ static struct pfr_anchors anchors;
+ char *n;
+
+ SLIST_INIT(&anchors);
+
+ memset(&pr, 0, sizeof(pr));
+ if (*anchor != '\0') {
+ n = dirname(anchor);
+ if (n[0] != '.' && n[1] != '\0')
+ strlcpy(pr.path, n, sizeof(pr.path));
+ n = basename(anchor);
+ if (n != NULL)
+ strlcpy(pr.name, n, sizeof(pr.name));
+ }
+
+ /* insert a root anchor first. */
+ pfctl_walk_get(opts, &pr, &anchors);
+
+ if (pfctl_walk_anchors(dev, opts, anchor, pfctl_walk_get, &anchors))
+ errx(1, "%s failed to retrieve list of anchors, can't continue",
+ __func__);
+
+ return (&anchors);
+}
+
+int
+pfctl_call_cleartables(int dev, int opts, struct pfr_anchoritem *pfra)
+{
+ /*
+ * PF_OPT_QUIET makes pfctl_clear_tables() to stop printing number of
+ * tables cleared for given anchor.
+ */
+ opts |= PF_OPT_QUIET;
+ return ((pfctl_do_clear_tables(pfra->pfra_anchorname, opts) == -1) ?
+ 1 : 0);
+}
+
+int
+pfctl_call_clearrules(int dev, int opts, struct pfr_anchoritem *pfra)
+{
+ /*
+ * PF_OPT_QUIET makes pfctl_clear_rules() to stop printing a 'rules
+ * cleared' message for every anchor it deletes.
+ */
+ opts |= PF_OPT_QUIET;
+ return (pfctl_flush_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_call_clearrules(dev, opts, pfra);
+
+ return (rv);
+}
+
+int
+pfctl_recurse(int dev, int opts, 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, anchorname, opts);
+ /*
+ * While traversing the list, pfctl_clear_*() must always return
+ * so that failures on one anchor do not prevent clearing others.
+ */
+ opts |= PF_OPT_IGNFAIL;
+ printf("Removing:\n");
+ SLIST_FOREACH_SAFE(pfra, anchors, pfra_sle, pfra_save) {
+ printf(" %s\n",
+ (*pfra->pfra_anchorname == '\0') ? "/" :
+ pfra->pfra_anchorname);
+ rv |= walkf(dev, opts, pfra);
+ SLIST_REMOVE(anchors, pfra, pfr_anchoritem, pfra_sle);
+ free(pfra->pfra_anchorname);
+ free(pfra);
+ }
+
+ return (rv);
+}
+
+int
pfctl_show_eth_anchors(int dev, int opts, char *anchorname)
{
struct pfctl_eth_rulesets_info ri;
@@ -3020,10 +3126,48 @@ pfctl_lookup_option(char *cmd, const char * const *list)
return (NULL);
}
+void
+pfctl_reset(int dev, int opts)
+{
+ struct pfctl pf;
+ struct pfr_buffer t;
+ int i;
+
+ pf.dev = dev;
+ pf.h = pfh;
+ pfctl_init_options(&pf);
+
+ /* Force reset upon pfctl_load_options() */
+ pf.debug_set = 1;
+ pf.reass_set = 1;
+ pf.syncookieswat_set = 1;
+ pf.ifname = strdup("none");
+ if (pf.ifname == NULL)
+ err(1, "%s: strdup", __func__);
+ pf.ifname_set = 1;
+
+ memset(&t, 0, sizeof(t));
+ t.pfrb_type = PFRB_TRANS;
+ if (pfctl_trans(dev, &t, DIOCXBEGIN, 0))
+ err(1, "%s: DIOCXBEGIN", __func__);
+
+ for (i = 0; pf_limits[i].name; i++)
+ pf.limit_set[pf_limits[i].index] = 1;
+
+ for (i = 0; pf_timeouts[i].name; i++)
+ pf.timeout_set[pf_timeouts[i].timeout] = 1;
+
+ pfctl_load_options(&pf);
+
+ if (pfctl_trans(dev, &t, DIOCXCOMMIT, 0))
+ err(1, "%s: DIOCXCOMMIT", __func__);
+
+ pfctl_clear_interface_flags(dev, opts);
+}
+
int
main(int argc, char *argv[])
{
- int error = 0;
int ch;
int mode = O_RDONLY;
int opts = 0;
@@ -3175,6 +3319,12 @@ main(int argc, char *argv[])
}
}
+ if ((opts & PF_OPT_NODNS) && (opts & PF_OPT_USEDNS))
+ errx(1, "-N and -r are mutually exclusive");
+
+ if ((tblcmdopt == NULL) ^ (tableopt == NULL))
+ usage();
+
if (tblcmdopt != NULL) {
argc -= optind;
argv += optind;
@@ -3196,6 +3346,8 @@ main(int argc, char *argv[])
if (anchoropt != NULL) {
int len = strlen(anchoropt);
+ if (anchoropt[0] == '\0')
+ errx(1, "anchor name must not be empty");
if (mode == O_RDONLY && showopt == NULL && tblcmdopt == NULL) {
warnx("anchors apply to -f, -F, -s, and -T only");
usage();
@@ -3243,7 +3395,7 @@ main(int argc, char *argv[])
if (opts & PF_OPT_DISABLE)
if (pfctl_disable(dev, opts))
- error = 1;
+ exit_val = 1;
if ((path = calloc(1, MAXPATHLEN)) == NULL)
errx(1, "%s: calloc", __func__);
@@ -3284,7 +3436,7 @@ main(int argc, char *argv[])
pfctl_show_status(dev, opts);
break;
case 'R':
- error = pfctl_show_running(dev);
+ exit_val = pfctl_show_running(dev);
break;
case 't':
pfctl_show_timeouts(dev, opts);
@@ -3304,12 +3456,14 @@ main(int argc, char *argv[])
0);
pfctl_show_nat(dev, path, opts, anchorname, 0, 0);
- pfctl_show_rules(dev, path, opts, 0, anchorname, 0, 0);
+ pfctl_show_rules(dev, path, opts, PFCTL_SHOW_RULES,
+ anchorname, 0, 0);
pfctl_show_altq(dev, ifaceopt, opts, 0);
pfctl_show_states(dev, ifaceopt, opts);
pfctl_show_src_nodes(dev, opts);
pfctl_show_status(dev, opts);
- pfctl_show_rules(dev, path, opts, 1, anchorname, 0, 0);
+ pfctl_show_rules(dev, path, opts, PFCTL_SHOW_LABELS,
+ anchorname, 0, 0);
pfctl_show_timeouts(dev, opts);
pfctl_show_limits(dev, opts);
pfctl_show_tables(anchorname, opts);
@@ -3344,7 +3498,11 @@ main(int argc, char *argv[])
pfctl_flush_eth_rules(dev, opts, anchorname);
break;
case 'r':
- pfctl_flush_rules(dev, opts, anchorname);
+ if (opts & PF_OPT_RECURSE)
+ pfctl_recurse(dev, opts, anchorname,
+ pfctl_call_clearrules);
+ else
+ pfctl_flush_rules(dev, opts, anchorname);
break;
case 'n':
pfctl_flush_nat(dev, opts, anchorname);
@@ -3362,24 +3520,42 @@ main(int argc, char *argv[])
pfctl_clear_stats(pfh, opts);
break;
case 'a':
+ if (ifaceopt) {
+ warnx("don't specify an interface with -Fall");
+ usage();
+ /* NOTREACHED */
+ }
pfctl_flush_eth_rules(dev, opts, anchorname);
pfctl_flush_rules(dev, opts, anchorname);
pfctl_flush_nat(dev, opts, anchorname);
- pfctl_do_clear_tables(anchorname, opts);
+ if (opts & PF_OPT_RECURSE)
+ pfctl_recurse(dev, opts, anchorname,
+ pfctl_call_clearanchors);
+ else {
+ pfctl_do_clear_tables(anchorname, opts);
+ pfctl_flush_rules(dev, opts, anchorname);
+ }
if (!*anchorname) {
pfctl_clear_altq(dev, opts);
pfctl_clear_iface_states(dev, ifaceopt, opts);
pfctl_clear_src_nodes(dev, opts);
pfctl_clear_stats(pfh, opts);
pfctl_clear_fingerprints(dev, opts);
- pfctl_clear_interface_flags(dev, opts);
+ pfctl_reset(dev, opts);
}
break;
case 'o':
pfctl_clear_fingerprints(dev, opts);
break;
case 'T':
- pfctl_do_clear_tables(anchorname, opts);
+ if ((opts & PF_OPT_RECURSE) == 0)
+ pfctl_do_clear_tables(anchorname, opts);
+ else
+ pfctl_recurse(dev, opts, anchorname,
+ pfctl_call_cleartables);
+ break;
+ case 'R':
+ pfctl_reset(dev, opts);
break;
}
}
@@ -3397,10 +3573,10 @@ main(int argc, char *argv[])
}
if (src_node_killers)
- pfctl_kill_src_nodes(dev, ifaceopt, opts);
+ pfctl_kill_src_nodes(dev, opts);
if (tblcmdopt != NULL) {
- error = pfctl_command_tables(argc, argv, tableopt,
+ exit_val = pfctl_table(argc, argv, tableopt,
tblcmdopt, rulesopt, anchorname, opts);
rulesopt = NULL;
}
@@ -3426,20 +3602,17 @@ main(int argc, char *argv[])
if (rulesopt != NULL && !(opts & PF_OPT_MERGE) &&
!anchorname[0] && (loadopt & PFCTL_FLAG_OPTION))
if (pfctl_file_fingerprints(dev, opts, PF_OSFP_FILE))
- error = 1;
+ exit_val = 1;
if (rulesopt != NULL) {
if (pfctl_rules(dev, rulesopt, opts, optimize,
anchorname, NULL))
- error = 1;
- else if (!(opts & PF_OPT_NOACTION) &&
- (loadopt & PFCTL_FLAG_TABLE))
- warn_namespace_collision(NULL);
+ exit_val = 1;
}
if (opts & PF_OPT_ENABLE)
if (pfctl_enable(dev, opts))
- error = 1;
+ exit_val = 1;
if (debugopt != NULL) {
switch (*debugopt) {
@@ -3458,5 +3631,19 @@ main(int argc, char *argv[])
}
}
- exit(error);
+ exit(exit_val);
+}
+
+char *
+pf_strerror(int errnum)
+{
+ switch (errnum) {
+ case ESRCH:
+ return "Table does not exist.";
+ case EINVAL:
+ case ENOENT:
+ return "Anchor does not exist.";
+ default:
+ return strerror(errnum);
+ }
}
diff --git a/sbin/pfctl/pfctl.h b/sbin/pfctl/pfctl.h
index 5abd5ddcdf8f..afecc78086e0 100644
--- a/sbin/pfctl/pfctl.h
+++ b/sbin/pfctl/pfctl.h
@@ -55,6 +55,13 @@ 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_add_table(struct pfr_table *, int *, int);
int pfr_del_table(struct pfr_table *, int *, int);
@@ -76,17 +83,17 @@ void *pfr_buf_next(struct pfr_buffer *, const void *);
int pfr_buf_grow(struct pfr_buffer *, int);
int pfr_buf_load(struct pfr_buffer *, char *, int,
int (*)(struct pfr_buffer *, char *, int, int), int);
-char *pfr_strerror(int);
+char *pf_strerror(int);
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_do_clear_tables(const char *, int);
+int pfctl_do_clear_tables(const char *, int);
void pfctl_show_tables(const char *, int);
-int pfctl_command_tables(int, char *[], char *, const char *, char *,
+int pfctl_table(int, char *[], char *, const char *, char *,
const char *, int);
int pfctl_show_altq(int, const char *, int, int);
-void warn_namespace_collision(const char *);
+void warn_duplicate_tables(const char *, const char *);
void pfctl_show_ifaces(const char *, int);
void pfctl_show_creators(int);
FILE *pfctl_fopen(const char *, const char *);
@@ -150,4 +157,7 @@ void expand_label(char *, size_t, struct pfctl_rule *);
const char *pfctl_proto2name(int);
+void pfctl_err(int, int, const char *, ...);
+void pfctl_errx(int, int, const char *, ...);
+
#endif /* _PFCTL_H_ */
diff --git a/sbin/pfctl/pfctl_optimize.c b/sbin/pfctl/pfctl_optimize.c
index b58bace326c2..1d2a60555f19 100644
--- a/sbin/pfctl/pfctl_optimize.c
+++ b/sbin/pfctl/pfctl_optimize.c
@@ -273,7 +273,10 @@ pfctl_optimize_ruleset(struct pfctl *pf, struct pfctl_ruleset *rs)
struct pfctl_rule *r;
struct pfctl_rulequeue *old_rules;
- DEBUG("optimizing ruleset");
+ if (TAILQ_EMPTY(rs->rules[PF_RULESET_FILTER].active.ptr))
+ return (0);
+
+ DEBUG("optimizing ruleset \"%s\"", rs->anchor->path);
memset(&table_buffer, 0, sizeof(table_buffer));
skip_init();
TAILQ_INIT(&opt_queue);
@@ -720,11 +723,7 @@ reorder_rules(struct pfctl *pf, struct superblock *block, int depth)
* it based on a more optimal skipstep order.
*/
TAILQ_INIT(&head);
- while ((por = TAILQ_FIRST(&block->sb_rules))) {
- TAILQ_REMOVE(&block->sb_rules, por, por_entry);
- TAILQ_INSERT_TAIL(&head, por, por_entry);
- }
-
+ TAILQ_CONCAT(&head, &block->sb_rules, por_entry);
while (!TAILQ_EMPTY(&head)) {
largest = 1;
@@ -745,11 +744,7 @@ reorder_rules(struct pfctl *pf, struct superblock *block, int depth)
* Nothing useful left. Leave remaining rules in order.
*/
DEBUG("(%d) no more commonality for skip steps", depth);
- while ((por = TAILQ_FIRST(&head))) {
- TAILQ_REMOVE(&head, por, por_entry);
- TAILQ_INSERT_TAIL(&block->sb_rules, por,
- por_entry);
- }
+ TAILQ_CONCAT(&block->sb_rules, &head, por_entry);
} else {
/*
* There is commonality. Extract those common rules
@@ -860,10 +855,7 @@ block_feedback(struct pfctl *pf, struct superblock *block)
*/
TAILQ_INIT(&queue);
- while ((por1 = TAILQ_FIRST(&block->sb_rules)) != NULL) {
- TAILQ_REMOVE(&block->sb_rules, por1, por_entry);
- TAILQ_INSERT_TAIL(&queue, por1, por_entry);
- }
+ TAILQ_CONCAT(&queue, &block->sb_rules, por_entry);
while ((por1 = TAILQ_FIRST(&queue)) != NULL) {
TAILQ_REMOVE(&queue, por1, por_entry);
@@ -900,13 +892,13 @@ load_feedback_profile(struct pfctl *pf, struct superblocks *superblocks)
struct pf_opt_queue queue;
struct pfctl_rules_info rules;
struct pfctl_rule a, b, rule;
- int nr, mnr;
+ int nr, mnr, ret;
TAILQ_INIT(&queue);
TAILQ_INIT(&prof_superblocks);
- if (pfctl_get_rules_info_h(pf->h, &rules, PF_PASS, "")) {
- warn("DIOCGETRULES");
+ if ((ret = pfctl_get_rules_info_h(pf->h, &rules, PF_PASS, "")) != 0) {
+ warnx("%s", pf_strerror(ret));
return (1);
}
mnr = rules.nr;
@@ -921,7 +913,7 @@ load_feedback_profile(struct pfctl *pf, struct superblocks *superblocks)
if (pfctl_get_rule_h(pf->h, nr, rules.ticket, "", PF_PASS,
&rule, anchor_call)) {
- warn("DIOCGETRULENV");
+ warnx("%s", pf_strerror(ret));
free(por);
return (1);
}
@@ -1256,7 +1248,7 @@ add_opt_table(struct pfctl *pf, struct pf_opt_tbl **tbl, sa_family_t af,
/* This is just a temporary table name */
snprintf((*tbl)->pt_name, sizeof((*tbl)->pt_name), "%s%d",
- PF_OPT_TABLE_PREFIX, tablenum++);
+ PF_OPTIMIZER_TABLE_PFX, tablenum++);
DEBUG("creating table <%s>", (*tbl)->pt_name);
}
@@ -1323,9 +1315,9 @@ pf_opt_create_table(struct pfctl *pf, struct pf_opt_tbl *tbl)
/* Now we have to pick a table name that isn't used */
again:
DEBUG("translating temporary table <%s> to <%s%x_%d>", tbl->pt_name,
- PF_OPT_TABLE_PREFIX, table_identifier, tablenum);
+ PF_OPTIMIZER_TABLE_PFX, table_identifier, tablenum);
snprintf(tbl->pt_name, sizeof(tbl->pt_name), "%s%x_%d",
- PF_OPT_TABLE_PREFIX, table_identifier, tablenum);
+ PF_OPTIMIZER_TABLE_PFX, table_identifier, tablenum);
PFRB_FOREACH(t, &table_buffer) {
if (strcasecmp(t->pfrt_name, tbl->pt_name) == 0) {
/* Collision. Try again */
diff --git a/sbin/pfctl/pfctl_osfp.c b/sbin/pfctl/pfctl_osfp.c
index 3a94c2e8c81b..5770c8343a46 100644
--- a/sbin/pfctl/pfctl_osfp.c
+++ b/sbin/pfctl/pfctl_osfp.c
@@ -264,7 +264,7 @@ void
pfctl_clear_fingerprints(int dev, int opts)
{
if (ioctl(dev, DIOCOSFPFLUSH))
- err(1, "DIOCOSFPFLUSH");
+ pfctl_err(opts, 1, "DIOCOSFPFLUSH");
}
/* flush pfctl's view of the fingerprints */
diff --git a/sbin/pfctl/pfctl_parser.c b/sbin/pfctl/pfctl_parser.c
index 1db98c6103d4..bd2c10c8080f 100644
--- a/sbin/pfctl/pfctl_parser.c
+++ b/sbin/pfctl/pfctl_parser.c
@@ -66,10 +66,9 @@
#include "pfctl_parser.h"
#include "pfctl.h"
-void copy_satopfaddr(struct pf_addr *, struct sockaddr *);
void print_op (u_int8_t, const char *, const char *);
void print_port (u_int8_t, u_int16_t, u_int16_t, const char *, int);
-void print_ugid (u_int8_t, unsigned, unsigned, const char *, unsigned);
+void print_ugid (u_int8_t, id_t, id_t, const char *);
void print_flags (uint16_t);
void print_fromto(struct pf_rule_addr *, pf_osfp_t,
struct pf_rule_addr *, sa_family_t, u_int8_t, int, int);
@@ -365,14 +364,14 @@ print_port(u_int8_t op, u_int16_t p1, u_int16_t p2, const char *proto, int numer
}
void
-print_ugid(u_int8_t op, unsigned u1, unsigned u2, const char *t, unsigned umax)
+print_ugid(u_int8_t op, id_t i1, id_t i2, const char *t)
{
char a1[11], a2[11];
- snprintf(a1, sizeof(a1), "%u", u1);
- snprintf(a2, sizeof(a2), "%u", u2);
+ snprintf(a1, sizeof(a1), "%ju", (uintmax_t)i1);
+ snprintf(a2, sizeof(a2), "%ju", (uintmax_t)i2);
printf(" %s", t);
- if (u1 == umax && (op == PF_OP_EQ || op == PF_OP_NE))
+ if (i1 == -1 && (op == PF_OP_EQ || op == PF_OP_NE))
print_op(op, "unknown", a2);
else
print_op(op, a1, a2);
@@ -978,11 +977,9 @@ print_rule(struct pfctl_rule *r, const char *anchor_call, int verbose, int numer
printf(" %sreceived-on %s", r->rcvifnot ? "!" : "",
r->rcv_ifname);
if (r->uid.op)
- print_ugid(r->uid.op, r->uid.uid[0], r->uid.uid[1], "user",
- UID_MAX);
+ print_ugid(r->uid.op, r->uid.uid[0], r->uid.uid[1], "user");
if (r->gid.op)
- print_ugid(r->gid.op, r->gid.gid[0], r->gid.gid[1], "group",
- GID_MAX);
+ print_ugid(r->gid.op, r->gid.gid[0], r->gid.gid[1], "group");
if (r->flags || r->flagset) {
printf(" flags ");
print_flags(r->flags);
@@ -1795,7 +1792,7 @@ host(const char *s, int opts)
char *p, *ps;
const char *errstr;
- if ((p = strrchr(s, '/')) != NULL) {
+ if ((p = strchr(s, '/')) != NULL) {
mask = strtonum(p+1, 0, 128, &errstr);
if (errstr) {
fprintf(stderr, "netmask is %s: %s\n", errstr, p);
diff --git a/sbin/pfctl/pfctl_parser.h b/sbin/pfctl/pfctl_parser.h
index 91c0f655e008..7a3c0c2a523f 100644
--- a/sbin/pfctl/pfctl_parser.h
+++ b/sbin/pfctl/pfctl_parser.h
@@ -55,6 +55,7 @@
#define PF_OPT_RECURSE 0x04000
#define PF_OPT_KILLMATCH 0x08000
#define PF_OPT_NODNS 0x10000
+#define PF_OPT_IGNFAIL 0x20000
#define PF_NAT_PROXY_PORT_LOW 50001
#define PF_NAT_PROXY_PORT_HIGH 65535
@@ -262,7 +263,6 @@ struct pf_opt_tbl {
struct node_tinithead pt_nodes;
struct pfr_buffer *pt_buf;
};
-#define PF_OPT_TABLE_PREFIX "__automatic_"
/* optimizer pf_rule container */
struct pf_opt_rule {
@@ -276,6 +276,8 @@ struct pf_opt_rule {
TAILQ_HEAD(pf_opt_queue, pf_opt_rule);
+void copy_satopfaddr(struct pf_addr *, struct sockaddr *);
+
int pfctl_rules(int, char *, int, int, char *, struct pfr_buffer *);
int pfctl_optimize_ruleset(struct pfctl *, struct pfctl_ruleset *);
diff --git a/sbin/pfctl/pfctl_radix.c b/sbin/pfctl/pfctl_radix.c
index 21191259adff..00e4207d377b 100644
--- a/sbin/pfctl/pfctl_radix.c
+++ b/sbin/pfctl/pfctl_radix.c
@@ -461,16 +461,3 @@ pfr_next_token(char buf[BUF_SIZE], FILE *fp)
buf[i] = '\0';
return (1);
}
-
-char *
-pfr_strerror(int errnum)
-{
- switch (errnum) {
- case ESRCH:
- return "Table does not exist";
- case ENOENT:
- return "Anchor or Ruleset does not exist";
- default:
- return strerror(errnum);
- }
-}
diff --git a/sbin/pfctl/pfctl_table.c b/sbin/pfctl/pfctl_table.c
index abe22a3258de..f583f5ef8e79 100644
--- a/sbin/pfctl/pfctl_table.c
+++ b/sbin/pfctl/pfctl_table.c
@@ -55,15 +55,12 @@
#include "pfctl.h"
extern void usage(void);
-static int pfctl_table(int, char *[], char *, const char *, char *,
- const char *, int);
static void print_table(const struct pfr_table *, int, int);
static int print_tstats(const struct pfr_tstats *, int);
static int load_addr(struct pfr_buffer *, int, char *[], char *, int, int);
static void print_addrx(struct pfr_addr *, struct pfr_addr *, int);
static int nonzero_astats(struct pfr_astats *);
static void print_astats(struct pfr_astats *, int);
-static void radix_perror(void);
static void xprintf(int, const char *, ...);
static void print_iface(struct pfi_kif *, int);
@@ -77,26 +74,28 @@ static const char *istats_text[2][2][2] = {
{ { "In6/Pass:", "In6/Block:" }, { "Out6/Pass:", "Out6/Block:" } }
};
-#define RVTEST(fct) do { \
- if ((!(opts & PF_OPT_NOACTION) || \
- (opts & PF_OPT_DUMMYACTION)) && \
- (fct)) { \
- radix_perror(); \
- goto _error; \
- } \
+#define RVTEST(fct) do { \
+ if ((!(opts & PF_OPT_NOACTION) || \
+ (opts & PF_OPT_DUMMYACTION)) && \
+ (fct)) { \
+ if ((opts & PF_OPT_RECURSE) == 0) \
+ warnx("%s", pf_strerror(errno)); \
+ goto _error; \
+ } \
} while (0)
#define CREATE_TABLE do { \
+ warn_duplicate_tables(table.pfrt_name, \
+ table.pfrt_anchor); \
table.pfrt_flags |= PFR_TFLAG_PERSIST; \
if ((!(opts & PF_OPT_NOACTION) || \
(opts & PF_OPT_DUMMYACTION)) && \
(pfr_add_table(&table, &nadd, flags)) && \
(errno != EPERM)) { \
- radix_perror(); \
+ warnx("%s", pf_strerror(errno)); \
goto _error; \
} \
if (nadd) { \
- warn_namespace_collision(table.pfrt_name); \
xprintf(opts, "%d table created", nadd); \
if (opts & PF_OPT_NOACTION) \
return (0); \
@@ -104,11 +103,17 @@ static const char *istats_text[2][2][2] = {
table.pfrt_flags &= ~PFR_TFLAG_PERSIST; \
} while(0)
-void
+int
pfctl_do_clear_tables(const char *anchor, int opts)
{
- if (pfctl_table(0, NULL, NULL, "-F", NULL, anchor, opts))
- 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
@@ -119,15 +124,6 @@ pfctl_show_tables(const char *anchor, int opts)
}
int
-pfctl_command_tables(int argc, char *argv[], char *tname,
- const char *command, char *file, const char *anchor, int opts)
-{
- if (tname == NULL || command == NULL)
- usage();
- return pfctl_table(argc, argv, tname, command, file, anchor, opts);
-}
-
-int
pfctl_table(int argc, char *argv[], char *tname, const char *command,
char *file, const char *anchor, int opts)
{
@@ -562,13 +558,6 @@ print_astats(struct pfr_astats *as, int dns)
(unsigned long long)as->pfras_bytes[dir][op]);
}
-void
-radix_perror(void)
-{
- extern char *__progname;
- fprintf(stderr, "%s: %s.\n", __progname, pfr_strerror(errno));
-}
-
int
pfctl_define_table(char *name, int flags, int addrs, const char *anchor,
struct pfr_buffer *ab, u_int32_t ticket)
@@ -587,12 +576,10 @@ pfctl_define_table(char *name, int flags, int addrs, const char *anchor,
}
void
-warn_namespace_collision(const char *filter)
+warn_duplicate_tables(const char *tablename, const char *anchorname)
{
struct pfr_buffer b;
struct pfr_table *t;
- const char *name = NULL, *lastcoll;
- int coll = 0;
bzero(&b, sizeof(b));
b.pfrb_type = PFRB_TABLES;
@@ -608,22 +595,13 @@ warn_namespace_collision(const char *filter)
PFRB_FOREACH(t, &b) {
if (!(t->pfrt_flags & PFR_TFLAG_ACTIVE))
continue;
- if (filter != NULL && strcmp(filter, t->pfrt_name))
+ if (!strcmp(anchorname, t->pfrt_anchor))
continue;
- if (!t->pfrt_anchor[0])
- name = t->pfrt_name;
- else if (name != NULL && !strcmp(name, t->pfrt_name)) {
- coll++;
- lastcoll = name;
- name = NULL;
- }
+ if (!strcmp(tablename, t->pfrt_name))
+ warnx("warning: table <%s> already defined"
+ " in anchor \"%s\"", tablename,
+ t->pfrt_anchor[0] ? t->pfrt_anchor : "/");
}
- if (coll == 1)
- warnx("warning: namespace collision with <%s> global table.",
- lastcoll);
- else if (coll > 1)
- warnx("warning: namespace collisions with %d global tables.",
- coll);
pfr_buf_clear(&b);
}
@@ -661,10 +639,8 @@ pfctl_show_ifaces(const char *filter, int opts)
for (;;) {
pfr_buf_grow(&b, b.pfrb_size);
b.pfrb_size = b.pfrb_msize;
- if (pfi_get_ifaces(filter, b.pfrb_caddr, &b.pfrb_size)) {
- radix_perror();
- exit(1);
- }
+ if (pfi_get_ifaces(filter, b.pfrb_caddr, &b.pfrb_size))
+ errx(1, "%s", pf_strerror(errno));
if (b.pfrb_size <= b.pfrb_msize)
break;
}
diff --git a/sbin/pfctl/tests/macro.sh b/sbin/pfctl/tests/macro.sh
index 9c48dbbc69f0..071c6cb4f426 100755
--- a/sbin/pfctl/tests/macro.sh
+++ b/sbin/pfctl/tests/macro.sh
@@ -3,6 +3,7 @@ atf_test_case "space" cleanup
space_head()
{
atf_set descr "Test macros with spaces"
+ atf_set require.kmods "pf"
}
space_body()
diff --git a/sbin/pfctl/tests/pfctl_test.c b/sbin/pfctl/tests/pfctl_test.c
index dbdcaa4900ea..5f0aa7826bb4 100644
--- a/sbin/pfctl/tests/pfctl_test.c
+++ b/sbin/pfctl/tests/pfctl_test.c
@@ -65,24 +65,6 @@
* Copied from OpenBSD.
*/
-static bool
-check_pf_module_available(void)
-{
- int modid;
- struct module_stat stat;
-
- if ((modid = modfind("pf")) < 0) {
- warn("pf module not found");
- return false;
- }
- stat.version = sizeof(struct module_stat);
- if (modstat(modid, &stat) < 0) {
- warn("can't stat pf module id %d", modid);
- return false;
- }
- return (true);
-}
-
extern char **environ;
static struct sbuf *
@@ -185,9 +167,6 @@ run_pfctl_test(const char *input_path, const char *output_path,
struct sbuf *expected_output;
struct sbuf *real_output;
- if (!check_pf_module_available())
- atf_tc_skip("pf(4) is not loaded");
-
/* The test inputs need to be able to use relative includes. */
snprintf(input_files_path, sizeof(input_files_path), "%s/files",
atf_tc_get_config_var(tc, "srcdir"));
@@ -292,6 +271,7 @@ do_selfpf_test(const char *number, const atf_tc_t *tc)
ATF_TC_HEAD(pf##number, tc) \
{ \
atf_tc_set_md_var(tc, "descr", descr); \
+ atf_tc_set_md_var(tc, "require.kmods", "pf"); \
} \
ATF_TC_BODY(pf##number, tc) \
{ \
@@ -301,6 +281,7 @@ do_selfpf_test(const char *number, const atf_tc_t *tc)
ATF_TC_HEAD(selfpf##number, tc) \
{ \
atf_tc_set_md_var(tc, "descr", "Self " descr); \
+ atf_tc_set_md_var(tc, "require.kmods", "pf"); \
} \
ATF_TC_BODY(selfpf##number, tc) \
{ \
@@ -312,6 +293,7 @@ do_selfpf_test(const char *number, const atf_tc_t *tc)
ATF_TC_HEAD(pf##number, tc) \
{ \
atf_tc_set_md_var(tc, "descr", descr); \
+ atf_tc_set_md_var(tc, "require.kmods", "pf"); \
} \
ATF_TC_BODY(pf##number, tc) \
{ \
@@ -325,6 +307,7 @@ do_selfpf_test(const char *number, const atf_tc_t *tc)
atf_tc_set_md_var(tc, "descr", descr); \
atf_tc_set_md_var(tc, "execenv", "jail"); \
atf_tc_set_md_var(tc, "execenv.jail.params", "vnet"); \
+ atf_tc_set_md_var(tc, "require.kmods", "pf"); \
} \
ATF_TC_BODY(pf##number, tc) \
{ \