aboutsummaryrefslogtreecommitdiff
path: root/sbin/pfctl/pfctl.c
diff options
context:
space:
mode:
Diffstat (limited to 'sbin/pfctl/pfctl.c')
-rw-r--r--sbin/pfctl/pfctl.c912
1 files changed, 746 insertions, 166 deletions
diff --git a/sbin/pfctl/pfctl.c b/sbin/pfctl/pfctl.c
index a0eec1b09289..8d59871701f8 100644
--- a/sbin/pfctl/pfctl.c
+++ b/sbin/pfctl/pfctl.c
@@ -34,13 +34,10 @@
*/
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
#define PFIOC_USE_LATEST
#include <sys/types.h>
#include <sys/ioctl.h>
-#include <sys/nv.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/endian.h>
@@ -50,7 +47,6 @@ __FBSDID("$FreeBSD$");
#include <net/pfvar.h>
#include <arpa/inet.h>
#include <net/altq/altq.h>
-#include <sys/sysctl.h>
#include <err.h>
#include <errno.h>
@@ -75,8 +71,9 @@ int pfctl_get_skip_ifaces(void);
int pfctl_check_skip_ifaces(char *);
int pfctl_adjust_skip_ifaces(struct pfctl *);
int pfctl_clear_interface_flags(int, int);
-int pfctl_clear_rules(int, int, char *);
-int pfctl_clear_nat(int, int, char *);
+int pfctl_flush_eth_rules(int, int, char *);
+int pfctl_flush_rules(int, int, char *);
+int pfctl_flush_nat(int, int, char *);
int pfctl_clear_altq(int, int);
int pfctl_clear_src_nodes(int, int);
int pfctl_clear_iface_states(int, const char *, int);
@@ -93,12 +90,15 @@ int pfctl_load_timeout(struct pfctl *, unsigned int, unsigned int);
int pfctl_load_debug(struct pfctl *, unsigned int);
int pfctl_load_logif(struct pfctl *, char *);
int pfctl_load_hostid(struct pfctl *, u_int32_t);
+int pfctl_load_reassembly(struct pfctl *, u_int32_t);
int pfctl_load_syncookies(struct pfctl *, u_int8_t);
int pfctl_get_pool(int, struct pfctl_pool *, u_int32_t, u_int32_t, int,
char *);
+void pfctl_print_eth_rule_counters(struct pfctl_eth_rule *, int);
void pfctl_print_rule_counters(struct pfctl_rule *, int);
-int pfctl_show_rules(int, char *, int, enum pfctl_show, char *, int);
-int pfctl_show_nat(int, int, char *);
+int pfctl_show_eth_rules(int, char *, int, enum pfctl_show, char *, int, int);
+int pfctl_show_rules(int, char *, int, enum pfctl_show, char *, int, int);
+int pfctl_show_nat(int, char *, int, char *, int);
int pfctl_show_src_nodes(int, int);
int pfctl_show_states(int, const char *, int);
int pfctl_show_status(int, int);
@@ -108,14 +108,22 @@ int pfctl_show_limits(int, int);
void pfctl_debug(int, u_int32_t, int);
int pfctl_test_altqsupport(int, int);
int pfctl_show_anchors(int, int, char *);
-int pfctl_ruleset_trans(struct pfctl *, char *, struct pfctl_anchor *);
+int pfctl_show_eth_anchors(int, int, char *);
+int pfctl_ruleset_trans(struct pfctl *, char *, struct pfctl_anchor *, bool);
+int pfctl_eth_ruleset_trans(struct pfctl *, char *,
+ struct pfctl_eth_anchor *);
+int pfctl_load_eth_ruleset(struct pfctl *, char *,
+ struct pfctl_eth_ruleset *, int);
+int pfctl_load_eth_rule(struct pfctl *, char *, struct pfctl_eth_rule *,
+ int);
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 *);
static struct pfctl_anchor_global pf_anchors;
-static struct pfctl_anchor pf_main_anchor;
+struct pfctl_anchor pf_main_anchor;
+struct pfctl_eth_anchor pf_eth_main_anchor;
static struct pfr_buffer skip_b;
static const char *clearopt;
@@ -124,7 +132,7 @@ static const char *showopt;
static const char *debugopt;
static char *anchoropt;
static const char *optiopt = NULL;
-static const char *pf_device = "/dev/pf";
+static const char *pf_device = PF_DEVICE;
static char *ifaceopt;
static char *tableopt;
static const char *tblcmdopt;
@@ -136,6 +144,7 @@ int loadopt;
int altqsupport;
int dev = -1;
+struct pfctl_handle *pfh = NULL;
static int first_title = 1;
static int labels = 0;
@@ -218,13 +227,14 @@ static const struct {
static const char * const clearopt_list[] = {
"nat", "queue", "rules", "Sources",
- "states", "info", "Tables", "osfp", "all", NULL
+ "states", "info", "Tables", "osfp", "all",
+ "ethernet", NULL
};
static const char * const showopt_list[] = {
- "nat", "queue", "rules", "Anchors", "Sources", "states", "info",
- "Interfaces", "labels", "timeouts", "memory", "Tables", "osfp",
- "Running", "all", NULL
+ "ether", "nat", "queue", "rules", "Anchors", "Sources", "states",
+ "info", "Interfaces", "labels", "timeouts", "memory", "Tables",
+ "osfp", "Running", "all", "creatorids", NULL
};
static const char * const tblcmdopt_list[] = {
@@ -301,10 +311,12 @@ pfctl_proto2name(int proto)
int
pfctl_enable(int dev, int opts)
{
- if (ioctl(dev, DIOCSTART)) {
- if (errno == EEXIST)
+ int ret;
+
+ if ((ret = pfctl_startstop(pfh, 1)) != 0) {
+ if (ret == EEXIST)
errx(1, "pf already enabled");
- else if (errno == ESRCH)
+ else if (ret == ESRCH)
errx(1, "pfil registeration failed");
else
err(1, "DIOCSTART");
@@ -322,8 +334,10 @@ pfctl_enable(int dev, int opts)
int
pfctl_disable(int dev, int opts)
{
- if (ioctl(dev, DIOCSTOP)) {
- if (errno == ENOENT)
+ int ret;
+
+ if ((ret = pfctl_startstop(pfh, 0)) != 0) {
+ if (ret == ENOENT)
errx(1, "pf not enabled");
else
err(1, "DIOCSTOP");
@@ -449,16 +463,27 @@ pfctl_clear_interface_flags(int dev, int opts)
}
int
-pfctl_clear_rules(int dev, int opts, char *anchorname)
+pfctl_flush_eth_rules(int dev, int opts, char *anchorname)
{
- struct pfr_buffer t;
+ int ret;
- memset(&t, 0, sizeof(t));
- t.pfrb_type = PFRB_TRANS;
- if (pfctl_add_trans(&t, PF_RULESET_SCRUB, anchorname) ||
- pfctl_add_trans(&t, PF_RULESET_FILTER, anchorname) ||
- pfctl_trans(dev, &t, DIOCXBEGIN, 0) ||
- pfctl_trans(dev, &t, DIOCXCOMMIT, 0))
+ ret = pfctl_clear_eth_rules(dev, anchorname);
+ if (ret != 0)
+ err(1, "pfctl_clear_eth_rules");
+
+ if ((opts & PF_OPT_QUIET) == 0)
+ fprintf(stderr, "Ethernet rules cleared\n");
+
+ return (ret);
+}
+
+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)
fprintf(stderr, "rules cleared\n");
@@ -466,17 +491,12 @@ pfctl_clear_rules(int dev, int opts, char *anchorname)
}
int
-pfctl_clear_nat(int dev, int opts, char *anchorname)
+pfctl_flush_nat(int dev, int opts, char *anchorname)
{
- struct pfr_buffer t;
+ int ret;
- memset(&t, 0, sizeof(t));
- t.pfrb_type = PFRB_TRANS;
- if (pfctl_add_trans(&t, PF_RULESET_NAT, anchorname) ||
- pfctl_add_trans(&t, PF_RULESET_BINAT, anchorname) ||
- pfctl_add_trans(&t, PF_RULESET_RDR, anchorname) ||
- pfctl_trans(dev, &t, DIOCXBEGIN, 0) ||
- pfctl_trans(dev, &t, DIOCXCOMMIT, 0))
+ ret = pfctl_clear_nat(dev, anchorname);
+ if (ret != 0)
err(1, "pfctl_clear_nat");
if ((opts & PF_OPT_QUIET) == 0)
fprintf(stderr, "nat cleared\n");
@@ -525,7 +545,7 @@ pfctl_clear_iface_states(int dev, const char *iface, int opts)
if (opts & PF_OPT_KILLMATCH)
kill.kill_match = true;
- if (pfctl_clear_states(dev, &kill, &killed))
+ if (pfctl_clear_states_h(pfh, &kill, &killed))
err(1, "DIOCCLRSTATES");
if ((opts & PF_OPT_QUIET) == 0)
fprintf(stderr, "%d states cleared\n", killed);
@@ -706,6 +726,12 @@ pfctl_net_kill_states(int dev, const char *iface, int opts)
sizeof(kill.ifname)) >= sizeof(kill.ifname))
errx(1, "invalid interface: %s", iface);
+ if (state_killers == 2 && (strcmp(state_kill[0], "nat") == 0)) {
+ kill.nat = true;
+ state_kill[0] = state_kill[1];
+ state_killers = 1;
+ }
+
pfctl_addrprefix(state_kill[0], &kill.src.addr.v.a.mask);
if (opts & PF_OPT_KILLMATCH)
@@ -775,13 +801,13 @@ pfctl_net_kill_states(int dev, const char *iface, int opts)
errx(1, "Unknown address family %d",
kill.af);
- if (pfctl_kill_states(dev, &kill, &newkilled))
+ if (pfctl_kill_states_h(pfh, &kill, &newkilled))
err(1, "DIOCKILLSTATES");
killed += newkilled;
}
freeaddrinfo(res[1]);
} else {
- if (pfctl_kill_states(dev, &kill, &newkilled))
+ if (pfctl_kill_states_h(pfh, &kill, &newkilled))
err(1, "DIOCKILLSTATES");
killed += newkilled;
}
@@ -847,7 +873,7 @@ pfctl_gateway_kill_states(int dev, const char *iface, int opts)
else
errx(1, "Unknown address family %d", kill.af);
- if (pfctl_kill_states(dev, &kill, &newkilled))
+ if (pfctl_kill_states_h(pfh, &kill, &newkilled))
err(1, "DIOCKILLSTATES");
killed += newkilled;
}
@@ -881,7 +907,7 @@ pfctl_label_kill_states(int dev, const char *iface, int opts)
sizeof(kill.label))
errx(1, "label too long: %s", state_kill[1]);
- if (pfctl_kill_states(dev, &kill, &killed))
+ if (pfctl_kill_states_h(pfh, &kill, &killed))
err(1, "DIOCKILLSTATES");
if ((opts & PF_OPT_QUIET) == 0)
@@ -920,7 +946,7 @@ pfctl_id_kill_states(int dev, const char *iface, int opts)
usage();
}
- if (pfctl_kill_states(dev, &kill, &killed))
+ if (pfctl_kill_states_h(pfh, &kill, &killed))
err(1, "DIOCKILLSTATES");
if ((opts & PF_OPT_QUIET) == 0)
@@ -987,6 +1013,32 @@ pfctl_clear_pool(struct pfctl_pool *pool)
}
void
+pfctl_print_eth_rule_counters(struct pfctl_eth_rule *rule, int opts)
+{
+ if (opts & PF_OPT_VERBOSE) {
+ printf(" [ Evaluations: %-8llu Packets: %-8llu "
+ "Bytes: %-10llu]\n",
+ (unsigned long long)rule->evaluations,
+ (unsigned long long)(rule->packets[0] +
+ rule->packets[1]),
+ (unsigned long long)(rule->bytes[0] +
+ rule->bytes[1]));
+ }
+ if (opts & PF_OPT_VERBOSE2) {
+ char timestr[30];
+
+ if (rule->last_active_timestamp != 0) {
+ bcopy(ctime(&rule->last_active_timestamp), timestr,
+ sizeof(timestr));
+ *strchr(timestr, '\n') = '\0';
+ } else {
+ snprintf(timestr, sizeof(timestr), "N/A");
+ }
+ printf(" [ Last Active Time: %s ]\n", timestr);
+ }
+}
+
+void
pfctl_print_rule_counters(struct pfctl_rule *rule, int opts)
{
if (opts & PF_OPT_DEBUG) {
@@ -1023,6 +1075,17 @@ pfctl_print_rule_counters(struct pfctl_rule *rule, int opts)
(unsigned)rule->cuid, (unsigned)rule->cpid,
(uintmax_t)rule->states_tot);
}
+ if (opts & PF_OPT_VERBOSE2) {
+ char timestr[30];
+ if (rule->last_active_timestamp != 0) {
+ bcopy(ctime(&rule->last_active_timestamp), timestr,
+ sizeof(timestr));
+ *strchr(timestr, '\n') = '\0';
+ } else {
+ snprintf(timestr, sizeof(timestr), "N/A");
+ }
+ printf(" [ Last Active Time: %s ]\n", timestr);
+ }
}
void
@@ -1035,65 +1098,228 @@ pfctl_print_title(char *title)
}
int
+pfctl_show_eth_rules(int dev, char *path, int opts, enum pfctl_show format,
+ char *anchorname, int depth, int wildcard)
+{
+ char anchor_call[MAXPATHLEN];
+ struct pfctl_eth_rules_info info;
+ struct pfctl_eth_rule rule;
+ int brace;
+ int dotitle = opts & PF_OPT_SHOWALL;
+ int len = strlen(path);
+ char *npath, *p;
+
+ /*
+ * Truncate a trailing / and * on an anchorname before searching for
+ * the ruleset, this is syntactic sugar that doesn't actually make it
+ * to the kernel.
+ */
+ if ((p = strrchr(anchorname, '/')) != NULL &&
+ p[1] == '*' && p[2] == '\0') {
+ p[0] = '\0';
+ }
+
+ if (anchorname[0] == '/') {
+ if ((npath = calloc(1, MAXPATHLEN)) == NULL)
+ errx(1, "pfctl_rules: calloc");
+ snprintf(npath, MAXPATHLEN, "%s", anchorname);
+ } else {
+ if (path[0])
+ snprintf(&path[len], MAXPATHLEN - len, "/%s", anchorname);
+ else
+ snprintf(&path[len], MAXPATHLEN - len, "%s", anchorname);
+ npath = path;
+ }
+
+ /*
+ * If this anchor was called with a wildcard path, go through
+ * the rulesets in the anchor rather than the rules.
+ */
+ if (wildcard && (opts & PF_OPT_RECURSE)) {
+ struct pfctl_eth_rulesets_info ri;
+ u_int32_t mnr, nr;
+
+ if (pfctl_get_eth_rulesets_info(dev, &ri, npath)) {
+ if (errno == EINVAL) {
+ fprintf(stderr, "Anchor '%s' "
+ "not found.\n", anchorname);
+ } else {
+ warn("DIOCGETETHRULESETS");
+ return (-1);
+ }
+ }
+ mnr = ri.nr;
+
+ pfctl_print_eth_rule_counters(&rule, opts);
+ for (nr = 0; nr < mnr; ++nr) {
+ struct pfctl_eth_ruleset_info rs;
+
+ if (pfctl_get_eth_ruleset(dev, npath, nr, &rs))
+ err(1, "DIOCGETETHRULESET");
+ INDENT(depth, !(opts & PF_OPT_VERBOSE));
+ printf("anchor \"%s\" all {\n", rs.name);
+ pfctl_show_eth_rules(dev, npath, opts,
+ format, rs.name, depth + 1, 0);
+ INDENT(depth, !(opts & PF_OPT_VERBOSE));
+ printf("}\n");
+ }
+ path[len] = '\0';
+ return (0);
+ }
+
+ if (pfctl_get_eth_rules_info(dev, &info, path)) {
+ warn("DIOCGETETHRULES");
+ return (-1);
+ }
+ for (int nr = 0; nr < info.nr; nr++) {
+ brace = 0;
+ INDENT(depth, !(opts & PF_OPT_VERBOSE));
+ if (pfctl_get_eth_rule(dev, nr, info.ticket, path, &rule,
+ opts & PF_OPT_CLRRULECTRS, anchor_call) != 0) {
+ warn("DIOCGETETHRULE");
+ return (-1);
+ }
+ if (anchor_call[0] &&
+ ((((p = strrchr(anchor_call, '_')) != NULL) &&
+ (p == anchor_call ||
+ *(--p) == '/')) || (opts & PF_OPT_RECURSE))) {
+ brace++;
+ int aclen = strlen(anchor_call);
+ if (anchor_call[aclen - 1] == '*')
+ anchor_call[aclen - 2] = '\0';
+ }
+ p = &anchor_call[0];
+ if (dotitle) {
+ pfctl_print_title("ETH RULES:");
+ dotitle = 0;
+ }
+ print_eth_rule(&rule, anchor_call,
+ opts & (PF_OPT_VERBOSE2 | PF_OPT_DEBUG));
+ if (brace)
+ printf(" {\n");
+ else
+ printf("\n");
+ pfctl_print_eth_rule_counters(&rule, opts);
+ if (brace) {
+ pfctl_show_eth_rules(dev, path, opts, format,
+ p, depth + 1, rule.anchor_wildcard);
+ INDENT(depth, !(opts & PF_OPT_VERBOSE));
+ printf("}\n");
+ }
+ }
+
+ path[len] = '\0';
+ return (0);
+}
+
+int
pfctl_show_rules(int dev, char *path, int opts, enum pfctl_show format,
- char *anchorname, int depth)
+ char *anchorname, int depth, int wildcard)
{
- struct pfioc_rule pr;
+ struct pfctl_rules_info ri;
struct pfctl_rule rule;
- u_int32_t nr, mnr, header = 0;
+ char anchor_call[MAXPATHLEN];
+ u_int32_t nr, header = 0;
int rule_numbers = opts & (PF_OPT_VERBOSE2 | PF_OPT_DEBUG);
int numeric = opts & PF_OPT_NUMERIC;
- int len = strlen(path);
- int brace;
- char *p;
+ int len = strlen(path), ret = 0;
+ char *npath, *p;
- if (path[0])
- snprintf(&path[len], MAXPATHLEN - len, "/%s", anchorname);
- else
- snprintf(&path[len], MAXPATHLEN - len, "%s", anchorname);
+ /*
+ * Truncate a trailing / and * on an anchorname before searching for
+ * the ruleset, this is syntactic sugar that doesn't actually make it
+ * to the kernel.
+ */
+ if ((p = strrchr(anchorname, '/')) != NULL &&
+ p[1] == '*' && p[2] == '\0') {
+ p[0] = '\0';
+ }
+
+ if (anchorname[0] == '/') {
+ if ((npath = calloc(1, MAXPATHLEN)) == NULL)
+ errx(1, "pfctl_rules: calloc");
+ snprintf(npath, MAXPATHLEN, "%s", anchorname);
+ } else {
+ if (path[0])
+ snprintf(&path[len], MAXPATHLEN - len, "/%s", anchorname);
+ else
+ snprintf(&path[len], MAXPATHLEN - len, "%s", anchorname);
+ npath = path;
+ }
+
+ /*
+ * If this anchor was called with a wildcard path, go through
+ * the rulesets in the anchor rather than the rules.
+ */
+ if (wildcard && (opts & PF_OPT_RECURSE)) {
+ struct pfioc_ruleset prs;
+ u_int32_t mnr, nr;
+
+ memset(&prs, 0, sizeof(prs));
+ memcpy(prs.path, npath, sizeof(prs.path));
+ if (ioctl(dev, DIOCGETRULESETS, &prs)) {
+ if (errno == EINVAL)
+ fprintf(stderr, "Anchor '%s' "
+ "not found.\n", anchorname);
+ else
+ err(1, "DIOCGETRULESETS");
+ }
+ mnr = prs.nr;
+
+ pfctl_print_rule_counters(&rule, opts);
+ for (nr = 0; nr < mnr; ++nr) {
+ prs.nr = nr;
+ if (ioctl(dev, DIOCGETRULESET, &prs))
+ err(1, "DIOCGETRULESET");
+ INDENT(depth, !(opts & PF_OPT_VERBOSE));
+ printf("anchor \"%s\" all {\n", prs.name);
+ pfctl_show_rules(dev, npath, opts,
+ format, prs.name, depth + 1, 0);
+ INDENT(depth, !(opts & PF_OPT_VERBOSE));
+ printf("}\n");
+ }
+ path[len] = '\0';
+ return (0);
+ }
- memset(&pr, 0, sizeof(pr));
- memcpy(pr.anchor, path, sizeof(pr.anchor));
if (opts & PF_OPT_SHOWALL) {
- pr.rule.action = PF_PASS;
- if (ioctl(dev, DIOCGETRULES, &pr)) {
+ ret = pfctl_get_rules_info(dev, &ri, PF_PASS, path);
+ if (ret != 0) {
warn("DIOCGETRULES");
goto error;
}
header++;
}
- pr.rule.action = PF_SCRUB;
- if (ioctl(dev, DIOCGETRULES, &pr)) {
+ ret = pfctl_get_rules_info(dev, &ri, PF_SCRUB, path);
+ if (ret != 0) {
warn("DIOCGETRULES");
goto error;
}
if (opts & PF_OPT_SHOWALL) {
- if (format == PFCTL_SHOW_RULES && (pr.nr > 0 || header))
+ if (format == PFCTL_SHOW_RULES && (ri.nr > 0 || header))
pfctl_print_title("FILTER RULES:");
else if (format == PFCTL_SHOW_LABELS && labels)
pfctl_print_title("LABEL COUNTERS:");
}
- mnr = pr.nr;
- for (nr = 0; nr < mnr; ++nr) {
- pr.nr = nr;
- if (pfctl_get_clear_rule(dev, nr, pr.ticket, path, PF_SCRUB,
- &rule, pr.anchor_call, opts & PF_OPT_CLRRULECTRS)) {
+ for (nr = 0; nr < ri.nr; ++nr) {
+ if (pfctl_get_clear_rule_h(pfh, nr, ri.ticket, path, PF_SCRUB,
+ &rule, anchor_call, opts & PF_OPT_CLRRULECTRS)) {
warn("DIOCGETRULENV");
goto error;
}
if (pfctl_get_pool(dev, &rule.rpool,
- nr, pr.ticket, PF_SCRUB, path) != 0)
+ nr, ri.ticket, PF_SCRUB, path) != 0)
goto error;
switch (format) {
case PFCTL_SHOW_LABELS:
break;
case PFCTL_SHOW_RULES:
- if (rule.label[0] && (opts & PF_OPT_SHOWALL))
+ if (rule.label[0][0] && (opts & PF_OPT_SHOWALL))
labels = 1;
- print_rule(&rule, pr.anchor_call, rule_numbers, numeric);
+ print_rule(&rule, anchor_call, rule_numbers, numeric);
printf("\n");
pfctl_print_rule_counters(&rule, opts);
break;
@@ -1102,22 +1328,20 @@ pfctl_show_rules(int dev, char *path, int opts, enum pfctl_show format,
}
pfctl_clear_pool(&rule.rpool);
}
- pr.rule.action = PF_PASS;
- if (ioctl(dev, DIOCGETRULES, &pr)) {
+ ret = pfctl_get_rules_info(dev, &ri, PF_PASS, path);
+ if (ret != 0) {
warn("DIOCGETRULES");
goto error;
}
- mnr = pr.nr;
- for (nr = 0; nr < mnr; ++nr) {
- pr.nr = nr;
- if (pfctl_get_clear_rule(dev, nr, pr.ticket, path, PF_PASS,
- &rule, pr.anchor_call, opts & PF_OPT_CLRRULECTRS)) {
+ for (nr = 0; nr < ri.nr; ++nr) {
+ if (pfctl_get_clear_rule_h(pfh, nr, ri.ticket, path, PF_PASS,
+ &rule, anchor_call, opts & PF_OPT_CLRRULECTRS)) {
warn("DIOCGETRULE");
goto error;
}
if (pfctl_get_pool(dev, &rule.rpool,
- nr, pr.ticket, PF_PASS, path) != 0)
+ nr, ri.ticket, PF_PASS, path) != 0)
goto error;
switch (format) {
@@ -1144,37 +1368,41 @@ pfctl_show_rules(int dev, char *path, int opts, enum pfctl_show format,
(unsigned long long)rule.bytes[1],
(uintmax_t)rule.states_tot);
}
+
+ if (anchor_call[0] &&
+ (((p = strrchr(anchor_call, '/')) ?
+ p[1] == '_' : anchor_call[0] == '_') ||
+ opts & PF_OPT_RECURSE)) {
+ pfctl_show_rules(dev, npath, opts, format,
+ anchor_call, depth, rule.anchor_wildcard);
+ }
break;
}
case PFCTL_SHOW_RULES:
- brace = 0;
- if (rule.label[0] && (opts & PF_OPT_SHOWALL))
+ if (rule.label[0][0] && (opts & PF_OPT_SHOWALL))
labels = 1;
INDENT(depth, !(opts & PF_OPT_VERBOSE));
- if (pr.anchor_call[0] &&
- ((((p = strrchr(pr.anchor_call, '_')) != NULL) &&
- ((void *)p == (void *)pr.anchor_call ||
- *(--p) == '/')) || (opts & PF_OPT_RECURSE))) {
- brace++;
- if ((p = strrchr(pr.anchor_call, '/')) !=
- NULL)
- p++;
- else
- p = &pr.anchor_call[0];
- } else
- p = &pr.anchor_call[0];
-
- print_rule(&rule, p, rule_numbers, numeric);
- if (brace)
+ print_rule(&rule, anchor_call, rule_numbers, numeric);
+
+ /*
+ * If this is a 'unnamed' brace notation
+ * anchor, OR the user has explicitly requested
+ * recursion, print it recursively.
+ */
+ if (anchor_call[0] &&
+ (((p = strrchr(anchor_call, '/')) ?
+ p[1] == '_' : anchor_call[0] == '_') ||
+ opts & PF_OPT_RECURSE)) {
printf(" {\n");
- else
- printf("\n");
- pfctl_print_rule_counters(&rule, opts);
- if (brace) {
- pfctl_show_rules(dev, path, opts, format,
- p, depth + 1);
+ pfctl_print_rule_counters(&rule, opts);
+ pfctl_show_rules(dev, npath, opts, format,
+ anchor_call, depth + 1,
+ rule.anchor_wildcard);
INDENT(depth, !(opts & PF_OPT_VERBOSE));
printf("}\n");
+ } else {
+ printf("\n");
+ pfctl_print_rule_counters(&rule, opts);
}
break;
case PFCTL_SHOW_NOTHING:
@@ -1182,51 +1410,79 @@ pfctl_show_rules(int dev, char *path, int opts, enum pfctl_show format,
}
pfctl_clear_pool(&rule.rpool);
}
- path[len] = '\0';
- return (0);
error:
path[len] = '\0';
- return (-1);
+ return (ret);
}
int
-pfctl_show_nat(int dev, int opts, char *anchorname)
+pfctl_show_nat(int dev, char *path, int opts, char *anchorname, int depth)
{
- struct pfioc_rule pr;
+ struct pfctl_rules_info ri;
struct pfctl_rule rule;
- u_int32_t mnr, nr;
+ char anchor_call[MAXPATHLEN];
+ u_int32_t nr;
static int nattype[3] = { PF_NAT, PF_RDR, PF_BINAT };
int i, dotitle = opts & PF_OPT_SHOWALL;
+ int brace, ret;
+ int len = strlen(path);
+ char *p;
+
+ if (path[0])
+ snprintf(&path[len], MAXPATHLEN - len, "/%s", anchorname);
+ else
+ snprintf(&path[len], MAXPATHLEN - len, "%s", anchorname);
- memset(&pr, 0, sizeof(pr));
- memcpy(pr.anchor, anchorname, sizeof(pr.anchor));
for (i = 0; i < 3; i++) {
- pr.rule.action = nattype[i];
- if (ioctl(dev, DIOCGETRULES, &pr)) {
+ ret = pfctl_get_rules_info(dev, &ri, nattype[i], path);
+ if (ret != 0) {
warn("DIOCGETRULES");
return (-1);
}
- mnr = pr.nr;
- for (nr = 0; nr < mnr; ++nr) {
- pr.nr = nr;
- if (pfctl_get_rule(dev, nr, pr.ticket, anchorname,
- nattype[i], &rule, pr.anchor_call)) {
+ for (nr = 0; nr < ri.nr; ++nr) {
+ brace = 0;
+ INDENT(depth, !(opts & PF_OPT_VERBOSE));
+
+ if (pfctl_get_rule(dev, nr, ri.ticket, path,
+ nattype[i], &rule, anchor_call)) {
warn("DIOCGETRULE");
return (-1);
}
if (pfctl_get_pool(dev, &rule.rpool, nr,
- pr.ticket, nattype[i], anchorname) != 0)
+ ri.ticket, nattype[i], path) != 0)
return (-1);
+
+ if (anchor_call[0] &&
+ ((((p = strrchr(anchor_call, '_')) != NULL) &&
+ (p == anchor_call ||
+ *(--p) == '/')) || (opts & PF_OPT_RECURSE))) {
+ brace++;
+ if ((p = strrchr(anchor_call, '/')) !=
+ NULL)
+ p++;
+ else
+ p = &anchor_call[0];
+ } else
+ p = &anchor_call[0];
+
if (dotitle) {
pfctl_print_title("TRANSLATION RULES:");
dotitle = 0;
}
- print_rule(&rule, pr.anchor_call,
+ print_rule(&rule, anchor_call,
opts & PF_OPT_VERBOSE2, opts & PF_OPT_NUMERIC);
- printf("\n");
+ if (brace)
+ printf(" {\n");
+ else
+ printf("\n");
pfctl_print_rule_counters(&rule, opts);
pfctl_clear_pool(&rule.rpool);
+ if (brace) {
+ pfctl_show_nat(dev, path, opts, p, depth + 1);
+ INDENT(depth, !(opts & PF_OPT_VERBOSE));
+ printf("}\n");
+ }
}
}
return (0);
@@ -1277,29 +1533,41 @@ done:
return (0);
}
+struct pfctl_show_state_arg {
+ int opts;
+ int dotitle;
+ const char *iface;
+};
+
+static int
+pfctl_show_state(struct pfctl_state *s, void *arg)
+{
+ struct pfctl_show_state_arg *a = (struct pfctl_show_state_arg *)arg;
+
+ if (a->dotitle) {
+ pfctl_print_title("STATES:");
+ a->dotitle = 0;
+ }
+ print_state(s, a->opts);
+
+ return (0);
+}
+
int
pfctl_show_states(int dev, const char *iface, int opts)
{
- struct pfctl_states states;
- struct pfctl_state *s;
- int dotitle = (opts & PF_OPT_SHOWALL);
+ struct pfctl_show_state_arg arg;
+ struct pfctl_state_filter filter = {};
- memset(&states, 0, sizeof(states));
+ if (iface != NULL)
+ strncpy(filter.ifname, iface, IFNAMSIZ);
- if (pfctl_get_states(dev, &states))
- return (-1);
+ arg.opts = opts;
+ arg.dotitle = opts & PF_OPT_SHOWALL;
+ arg.iface = iface;
- TAILQ_FOREACH(s, &states.states, entry) {
- if (iface != NULL && strcmp(s->ifname, iface))
- continue;
- if (dotitle) {
- pfctl_print_title("STATES:");
- dotitle = 0;
- }
- print_state(s, opts);
- }
-
- pfctl_free_states(&states);
+ if (pfctl_get_filtered_states_iter(&filter, pfctl_show_state, &arg))
+ return (-1);
return (0);
}
@@ -1391,6 +1659,22 @@ pfctl_show_limits(int dev, int opts)
return (0);
}
+void
+pfctl_show_creators(int opts)
+{
+ int ret;
+ uint32_t creators[16];
+ size_t count = nitems(creators);
+
+ ret = pfctl_get_creatorids(pfh, creators, &count);
+ if (ret != 0)
+ errx(ret, "Failed to retrieve creators");
+
+ printf("Creator IDs:\n");
+ for (size_t i = 0; i < count; i++)
+ printf("%08x\n", creators[i]);
+}
+
/* callbacks for rule/nat/rdr/addr */
int
pfctl_add_pool(struct pfctl *pf, struct pfctl_pool *p, sa_family_t af)
@@ -1462,10 +1746,71 @@ pfctl_append_rule(struct pfctl *pf, struct pfctl_rule *r,
}
int
-pfctl_ruleset_trans(struct pfctl *pf, char *path, struct pfctl_anchor *a)
+pfctl_append_eth_rule(struct pfctl *pf, struct pfctl_eth_rule *r,
+ const char *anchor_call)
+{
+ struct pfctl_eth_rule *rule;
+ struct pfctl_eth_ruleset *rs;
+ char *p;
+
+ rs = &pf->eanchor->ruleset;
+
+ if (anchor_call[0] && r->anchor == NULL) {
+ /*
+ * Don't make non-brace anchors part of the main anchor pool.
+ */
+ if ((r->anchor = calloc(1, sizeof(*r->anchor))) == NULL)
+ err(1, "pfctl_append_rule: calloc");
+
+ pf_init_eth_ruleset(&r->anchor->ruleset);
+ r->anchor->ruleset.anchor = r->anchor;
+ if (strlcpy(r->anchor->path, anchor_call,
+ sizeof(rule->anchor->path)) >= sizeof(rule->anchor->path))
+ errx(1, "pfctl_append_rule: strlcpy");
+ if ((p = strrchr(anchor_call, '/')) != NULL) {
+ if (!strlen(p))
+ err(1, "pfctl_append_eth_rule: bad anchor name %s",
+ anchor_call);
+ } else
+ p = (char *)anchor_call;
+ if (strlcpy(r->anchor->name, p,
+ sizeof(rule->anchor->name)) >= sizeof(rule->anchor->name))
+ errx(1, "pfctl_append_eth_rule: strlcpy");
+ }
+
+ if ((rule = calloc(1, sizeof(*rule))) == NULL)
+ err(1, "calloc");
+ bcopy(r, rule, sizeof(*rule));
+
+ TAILQ_INSERT_TAIL(&rs->rules, rule, entries);
+ return (0);
+}
+
+int
+pfctl_eth_ruleset_trans(struct pfctl *pf, char *path,
+ struct pfctl_eth_anchor *a)
+{
+ int osize = pf->trans->pfrb_size;
+
+ if ((pf->loadopt & PFCTL_FLAG_ETH) != 0) {
+ if (pfctl_add_trans(pf->trans, PF_RULESET_ETH, path))
+ return (1);
+ }
+ if (pfctl_trans(pf->dev, pf->trans, DIOCXBEGIN, osize))
+ return (5);
+
+ return (0);
+}
+
+int
+pfctl_ruleset_trans(struct pfctl *pf, char *path, struct pfctl_anchor *a, bool do_eth)
{
int osize = pf->trans->pfrb_size;
+ if ((pf->loadopt & PFCTL_FLAG_ETH) != 0 && do_eth) {
+ if (pfctl_add_trans(pf->trans, PF_RULESET_ETH, path))
+ return (1);
+ }
if ((pf->loadopt & PFCTL_FLAG_NAT) != 0) {
if (pfctl_add_trans(pf->trans, PF_RULESET_NAT, path) ||
pfctl_add_trans(pf->trans, PF_RULESET_BINAT, path) ||
@@ -1492,6 +1837,104 @@ pfctl_ruleset_trans(struct pfctl *pf, char *path, struct pfctl_anchor *a)
}
int
+pfctl_load_eth_ruleset(struct pfctl *pf, char *path,
+ struct pfctl_eth_ruleset *rs, int depth)
+{
+ struct pfctl_eth_rule *r;
+ int error, len = strlen(path);
+ int brace = 0;
+
+ pf->eanchor = rs->anchor;
+ if (path[0])
+ snprintf(&path[len], MAXPATHLEN - len, "/%s", pf->eanchor->name);
+ else
+ snprintf(&path[len], MAXPATHLEN - len, "%s", pf->eanchor->name);
+
+ if (depth) {
+ if (TAILQ_FIRST(&rs->rules) != NULL) {
+ brace++;
+ if (pf->opts & PF_OPT_VERBOSE)
+ printf(" {\n");
+ if ((pf->opts & PF_OPT_NOACTION) == 0 &&
+ (error = pfctl_eth_ruleset_trans(pf,
+ path, rs->anchor))) {
+ printf("pfctl_load_eth_rulesets: "
+ "pfctl_eth_ruleset_trans %d\n", error);
+ goto error;
+ }
+ } else if (pf->opts & PF_OPT_VERBOSE)
+ printf("\n");
+ }
+
+ while ((r = TAILQ_FIRST(&rs->rules)) != NULL) {
+ TAILQ_REMOVE(&rs->rules, r, entries);
+
+ error = pfctl_load_eth_rule(pf, path, r, depth);
+ if (error)
+ return (error);
+
+ if (r->anchor) {
+ if ((error = pfctl_load_eth_ruleset(pf, path,
+ &r->anchor->ruleset, depth + 1)))
+ return (error);
+ } else if (pf->opts & PF_OPT_VERBOSE)
+ printf("\n");
+ free(r);
+ }
+ if (brace && pf->opts & PF_OPT_VERBOSE) {
+ INDENT(depth - 1, (pf->opts & PF_OPT_VERBOSE));
+ printf("}\n");
+ }
+ path[len] = '\0';
+
+ return (0);
+error:
+ path[len] = '\0';
+ return (error);
+}
+
+int
+pfctl_load_eth_rule(struct pfctl *pf, char *path, struct pfctl_eth_rule *r,
+ int depth)
+{
+ char *name;
+ char anchor[PF_ANCHOR_NAME_SIZE];
+ int len = strlen(path);
+
+ if (strlcpy(anchor, path, sizeof(anchor)) >= sizeof(anchor))
+ errx(1, "pfctl_load_eth_rule: strlcpy");
+
+ if (r->anchor) {
+ if (r->anchor->match) {
+ if (path[0])
+ snprintf(&path[len], MAXPATHLEN - len,
+ "/%s", r->anchor->name);
+ else
+ snprintf(&path[len], MAXPATHLEN - len,
+ "%s", r->anchor->name);
+ name = r->anchor->name;
+ } else
+ name = r->anchor->path;
+ } else
+ name = "";
+
+ if ((pf->opts & PF_OPT_NOACTION) == 0)
+ if (pfctl_add_eth_rule(pf->dev, r, anchor, name,
+ pf->eth_ticket))
+ err(1, "DIOCADDETHRULENV");
+
+ if (pf->opts & PF_OPT_VERBOSE) {
+ INDENT(depth, !(pf->opts & PF_OPT_VERBOSE2));
+ print_eth_rule(r, r->anchor ? r->anchor->name : "",
+ pf->opts & (PF_OPT_VERBOSE2 | PF_OPT_DEBUG));
+ }
+
+ path[len] = '\0';
+
+ return (0);
+}
+
+int
pfctl_load_ruleset(struct pfctl *pf, char *path, struct pfctl_ruleset *rs,
int rs_num, int depth)
{
@@ -1513,7 +1956,7 @@ pfctl_load_ruleset(struct pfctl *pf, char *path, struct pfctl_ruleset *rs,
printf(" {\n");
if ((pf->opts & PF_OPT_NOACTION) == 0 &&
(error = pfctl_ruleset_trans(pf,
- path, rs->anchor))) {
+ path, rs->anchor, false))) {
printf("pfctl_load_rulesets: "
"pfctl_ruleset_trans %d\n", error);
goto error;
@@ -1565,6 +2008,8 @@ pfctl_load_rule(struct pfctl *pf, char *path, struct pfctl_rule *r, int depth)
u_int32_t ticket;
char anchor[PF_ANCHOR_NAME_SIZE];
int len = strlen(path);
+ int error;
+ bool was_present;
/* set up anchor before adding to path for anchor_call */
if ((pf->opts & PF_OPT_NOACTION) == 0)
@@ -1586,19 +2031,32 @@ pfctl_load_rule(struct pfctl *pf, char *path, struct pfctl_rule *r, int depth)
} else
name = "";
+ was_present = false;
if ((pf->opts & PF_OPT_NOACTION) == 0) {
if (pfctl_add_pool(pf, &r->rpool, r->af))
return (1);
- if (pfctl_add_rule(pf->dev, r, anchor, name, ticket,
- pf->paddr.ticket))
+ error = pfctl_add_rule(pf->dev, r, anchor, name, ticket,
+ pf->paddr.ticket);
+ switch (error) {
+ case 0:
+ /* things worked, do nothing */
+ break;
+ case EEXIST:
+ /* an identical rule is already present */
+ was_present = true;
+ break;
+ default:
err(1, "DIOCADDRULENV");
+ }
}
if (pf->opts & PF_OPT_VERBOSE) {
INDENT(depth, !(pf->opts & PF_OPT_VERBOSE2));
- print_rule(r, r->anchor ? r->anchor->name : "",
+ print_rule(r, name,
pf->opts & PF_OPT_VERBOSE2,
pf->opts & PF_OPT_NUMERIC);
+ if (was_present)
+ printf(" -- rule was already present");
}
path[len] = '\0';
pfctl_clear_pool(&r->rpool);
@@ -1638,6 +2096,7 @@ pfctl_rules(int dev, char *filename, int opts, int optimize,
struct pfioc_altq pa;
struct pfctl pf;
struct pfctl_ruleset *rs;
+ struct pfctl_eth_ruleset *ethrs;
struct pfr_table trs;
char *path;
int osize;
@@ -1646,6 +2105,11 @@ pfctl_rules(int dev, char *filename, int opts, int optimize,
memset(&pf_main_anchor, 0, sizeof(pf_main_anchor));
pf_init_ruleset(&pf_main_anchor.ruleset);
pf_main_anchor.ruleset.anchor = &pf_main_anchor;
+
+ memset(&pf_eth_main_anchor, 0, sizeof(pf_eth_main_anchor));
+ pf_init_eth_ruleset(&pf_eth_main_anchor.ruleset);
+ pf_eth_main_anchor.ruleset.anchor = &pf_eth_main_anchor;
+
if (trans == NULL) {
bzero(&buf, sizeof(buf));
buf.pfrb_type = PFRB_TRANS;
@@ -1678,10 +2142,10 @@ pfctl_rules(int dev, char *filename, int opts, int optimize,
rs->anchor = pf.anchor;
if (strlcpy(pf.anchor->path, anchorname,
sizeof(pf.anchor->path)) >= sizeof(pf.anchor->path))
- errx(1, "pfctl_add_rule: strlcpy");
+ errx(1, "pfctl_rules: strlcpy");
if (strlcpy(pf.anchor->name, anchorname,
sizeof(pf.anchor->name)) >= sizeof(pf.anchor->name))
- errx(1, "pfctl_add_rule: strlcpy");
+ errx(1, "pfctl_rules: strlcpy");
pf.astack[0] = pf.anchor;
@@ -1692,14 +2156,32 @@ pfctl_rules(int dev, char *filename, int opts, int optimize,
pf.trans = t;
pfctl_init_options(&pf);
+ /* Set up ethernet anchor */
+ if ((pf.eanchor = calloc(1, sizeof(*pf.eanchor))) == NULL)
+ ERRX("pfctl_rules: calloc");
+
+ if (strlcpy(pf.eanchor->path, anchorname,
+ sizeof(pf.eanchor->path)) >= sizeof(pf.eanchor->path))
+ errx(1, "pfctl_rules: strlcpy");
+ if (strlcpy(pf.eanchor->name, anchorname,
+ sizeof(pf.eanchor->name)) >= sizeof(pf.eanchor->name))
+ errx(1, "pfctl_rules: strlcpy");
+
+ ethrs = &pf.eanchor->ruleset;
+ pf_init_eth_ruleset(ethrs);
+ ethrs->anchor = pf.eanchor;
+ pf.eastack[0] = pf.eanchor;
+
if ((opts & PF_OPT_NOACTION) == 0) {
/*
* XXX For the time being we need to open transactions for
* the main ruleset before parsing, because tables are still
* loaded at parse time.
*/
- if (pfctl_ruleset_trans(&pf, anchorname, pf.anchor))
+ if (pfctl_ruleset_trans(&pf, anchorname, pf.anchor, true))
ERRX("pfctl_rules");
+ if (pf.loadopt & PFCTL_FLAG_ETH)
+ pf.eth_ticket = pfctl_get_ticket(t, PF_RULESET_ETH, anchorname);
if (altqsupport && (pf.loadopt & PFCTL_FLAG_ALTQ))
pa.ticket =
pfctl_get_ticket(t, PF_RULESET_ALTQ, anchorname);
@@ -1720,6 +2202,8 @@ pfctl_rules(int dev, char *filename, int opts, int optimize,
if ((pf.loadopt & PFCTL_FLAG_FILTER &&
(pfctl_load_ruleset(&pf, path, rs, PF_RULESET_SCRUB, 0))) ||
+ (pf.loadopt & PFCTL_FLAG_ETH &&
+ (pfctl_load_eth_ruleset(&pf, path, ethrs, 0))) ||
(pf.loadopt & PFCTL_FLAG_NAT &&
(pfctl_load_ruleset(&pf, path, rs, PF_RULESET_NAT, 0) ||
pfctl_load_ruleset(&pf, path, rs, PF_RULESET_RDR, 0) ||
@@ -1797,6 +2281,11 @@ pfctl_init_options(struct pfctl *pf)
pf->timeout[PFTM_TCP_CLOSING] = PFTM_TCP_CLOSING_VAL;
pf->timeout[PFTM_TCP_FIN_WAIT] = PFTM_TCP_FIN_WAIT_VAL;
pf->timeout[PFTM_TCP_CLOSED] = PFTM_TCP_CLOSED_VAL;
+ pf->timeout[PFTM_SCTP_FIRST_PACKET] = PFTM_TCP_FIRST_PACKET_VAL;
+ pf->timeout[PFTM_SCTP_OPENING] = PFTM_TCP_OPENING_VAL;
+ pf->timeout[PFTM_SCTP_ESTABLISHED] = PFTM_TCP_ESTABLISHED_VAL;
+ pf->timeout[PFTM_SCTP_CLOSING] = PFTM_TCP_CLOSING_VAL;
+ pf->timeout[PFTM_SCTP_CLOSED] = PFTM_TCP_CLOSED_VAL;
pf->timeout[PFTM_UDP_FIRST_PACKET] = PFTM_UDP_FIRST_PACKET_VAL;
pf->timeout[PFTM_UDP_SINGLE] = PFTM_UDP_SINGLE_VAL;
pf->timeout[PFTM_UDP_MULTIPLE] = PFTM_UDP_MULTIPLE_VAL;
@@ -1818,6 +2307,7 @@ pfctl_init_options(struct pfctl *pf)
pf->limit[PF_LIMIT_TABLE_ENTRIES] = PFR_KENTRY_HIWAT;
pf->debug = PF_DEBUG_URGENT;
+ pf->reassemble = 0;
pf->syncookies = false;
pf->syncookieswat[0] = PF_SYNCOOKIES_LOWATPCT;
@@ -1878,6 +2368,11 @@ pfctl_load_options(struct pfctl *pf)
if (pfctl_load_hostid(pf, pf->hostid))
error = 1;
+ /* load reassembly settings */
+ if (!(pf->opts & PF_OPT_MERGE) || pf->reass_set)
+ if (pfctl_load_reassembly(pf, pf->reassemble))
+ error = 1;
+
/* load keepcounters */
if (pfctl_set_keepcounters(pf->dev, pf->keep_counters))
error = 1;
@@ -1975,6 +2470,28 @@ pfctl_load_timeout(struct pfctl *pf, unsigned int timeout, unsigned int seconds)
}
int
+pfctl_set_reassembly(struct pfctl *pf, int on, int nodf)
+{
+ if ((loadopt & PFCTL_FLAG_OPTION) == 0)
+ return (0);
+
+ pf->reass_set = 1;
+ if (on) {
+ pf->reassemble = PF_REASS_ENABLED;
+ if (nodf)
+ pf->reassemble |= PF_REASS_NODF;
+ } else {
+ pf->reassemble = 0;
+ }
+
+ if (pf->opts & PF_OPT_VERBOSE)
+ printf("set reassemble %s %s\n", on ? "yes" : "no",
+ nodf ? "no-df" : "");
+
+ return (0);
+}
+
+int
pfctl_set_optimization(struct pfctl *pf, const char *opt)
{
const struct pf_hint *hint;
@@ -2030,19 +2547,11 @@ pfctl_set_logif(struct pfctl *pf, char *ifname)
int
pfctl_load_logif(struct pfctl *pf, char *ifname)
{
- struct pfioc_if pi;
-
- memset(&pi, 0, sizeof(pi));
- if (ifname && strlcpy(pi.ifname, ifname,
- sizeof(pi.ifname)) >= sizeof(pi.ifname)) {
+ if (ifname != NULL && strlen(ifname) >= IFNAMSIZ) {
warnx("pfctl_load_logif: strlcpy");
return (1);
}
- if (ioctl(pf->dev, DIOCSETSTATUSIF, &pi)) {
- warnx("DIOCSETSTATUSIF");
- return (1);
- }
- return (0);
+ return (pfctl_set_statusif(pfh, ifname ? ifname : ""));
}
int
@@ -2073,6 +2582,16 @@ pfctl_load_hostid(struct pfctl *pf, u_int32_t hostid)
}
int
+pfctl_load_reassembly(struct pfctl *pf, u_int32_t reassembly)
+{
+ if (ioctl(dev, DIOCSETREASS, &reassembly)) {
+ warnx("DIOCSETREASS");
+ return (1);
+ }
+ return (0);
+}
+
+int
pfctl_load_syncookies(struct pfctl *pf, u_int8_t val)
{
struct pfctl_syncookies cookies;
@@ -2298,6 +2817,44 @@ pfctl_show_anchors(int dev, int opts, char *anchorname)
return (0);
}
+int
+pfctl_show_eth_anchors(int dev, int opts, char *anchorname)
+{
+ struct pfctl_eth_rulesets_info ri;
+ struct pfctl_eth_ruleset_info rs;
+ int ret;
+
+ if ((ret = pfctl_get_eth_rulesets_info(dev, &ri, anchorname)) != 0) {
+ if (ret == ENOENT)
+ fprintf(stderr, "Anchor '%s' not found.\n",
+ anchorname);
+ else
+ err(1, "DIOCGETETHRULESETS");
+ return (-1);
+ }
+
+ for (int nr = 0; nr < ri.nr; nr++) {
+ char sub[MAXPATHLEN];
+
+ if (pfctl_get_eth_ruleset(dev, anchorname, nr, &rs) != 0)
+ err(1, "DIOCGETETHRULESET");
+
+ if (!strcmp(rs.name, PF_RESERVED_ANCHOR))
+ continue;
+ sub[0] = 0;
+ if (rs.path[0]) {
+ strlcat(sub, rs.path, sizeof(sub));
+ strlcat(sub, "/", sizeof(sub));
+ }
+ strlcat(sub, rs.name, sizeof(sub));
+ if (sub[0] != '_' || (opts & PF_OPT_VERBOSE))
+ printf(" %s\n", sub);
+ if ((opts & PF_OPT_VERBOSE) && pfctl_show_eth_anchors(dev, opts, sub))
+ return (-1);
+ }
+ return (0);
+}
+
const char *
pfctl_lookup_option(char *cmd, const char * const *list)
{
@@ -2483,7 +3040,7 @@ main(int argc, char *argv[])
if (anchoropt != NULL) {
int len = strlen(anchoropt);
- if (anchoropt[len - 1] == '*') {
+ if (len >= 1 && anchoropt[len - 1] == '*') {
if (len >= 2 && anchoropt[len - 2] == '/')
anchoropt[len - 2] = '\0';
else
@@ -2494,7 +3051,7 @@ main(int argc, char *argv[])
sizeof(anchorname)) >= sizeof(anchorname))
errx(1, "anchor name '%s' too long",
anchoropt);
- loadopt &= PFCTL_FLAG_FILTER|PFCTL_FLAG_NAT|PFCTL_FLAG_TABLE;
+ loadopt &= PFCTL_FLAG_FILTER|PFCTL_FLAG_NAT|PFCTL_FLAG_TABLE|PFCTL_FLAG_ETH;
}
if ((opts & PF_OPT_NOACTION) == 0) {
@@ -2515,6 +3072,9 @@ main(int argc, char *argv[])
altqsupport = 1;
#endif
}
+ pfh = pfctl_open(pf_device);
+ if (pfh == NULL)
+ err(1, "Failed to open netlink");
if (opts & PF_OPT_DISABLE)
if (pfctl_disable(dev, opts))
@@ -2524,20 +3084,23 @@ main(int argc, char *argv[])
switch (*showopt) {
case 'A':
pfctl_show_anchors(dev, opts, anchorname);
+ if (opts & PF_OPT_VERBOSE2)
+ printf("Ethernet:\n");
+ pfctl_show_eth_anchors(dev, opts, anchorname);
break;
case 'r':
pfctl_load_fingerprints(dev, opts);
pfctl_show_rules(dev, path, opts, PFCTL_SHOW_RULES,
- anchorname, 0);
+ anchorname, 0, 0);
break;
case 'l':
pfctl_load_fingerprints(dev, opts);
pfctl_show_rules(dev, path, opts, PFCTL_SHOW_LABELS,
- anchorname, 0);
+ anchorname, 0, 0);
break;
case 'n':
pfctl_load_fingerprints(dev, opts);
- pfctl_show_nat(dev, opts, anchorname);
+ pfctl_show_nat(dev, path, opts, anchorname, 0);
break;
case 'q':
pfctl_show_altq(dev, ifaceopt, opts,
@@ -2561,17 +3124,24 @@ main(int argc, char *argv[])
case 'm':
pfctl_show_limits(dev, opts);
break;
+ case 'e':
+ pfctl_show_eth_rules(dev, path, opts, 0, anchorname, 0,
+ 0);
+ break;
case 'a':
opts |= PF_OPT_SHOWALL;
pfctl_load_fingerprints(dev, opts);
- pfctl_show_nat(dev, opts, anchorname);
- pfctl_show_rules(dev, path, opts, 0, anchorname, 0);
+ pfctl_show_eth_rules(dev, path, opts, 0, anchorname, 0,
+ 0);
+
+ pfctl_show_nat(dev, path, opts, anchorname, 0);
+ pfctl_show_rules(dev, path, opts, 0, 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);
+ pfctl_show_rules(dev, path, opts, 1, anchorname, 0, 0);
pfctl_show_timeouts(dev, opts);
pfctl_show_limits(dev, opts);
pfctl_show_tables(anchorname, opts);
@@ -2587,12 +3157,18 @@ main(int argc, char *argv[])
case 'I':
pfctl_show_ifaces(ifaceopt, opts);
break;
+ case 'c':
+ pfctl_show_creators(opts);
+ break;
}
}
- if ((opts & PF_OPT_CLRRULECTRS) && showopt == NULL)
+ if ((opts & PF_OPT_CLRRULECTRS) && showopt == NULL) {
+ pfctl_show_eth_rules(dev, path, opts, PFCTL_SHOW_NOTHING,
+ anchorname, 0, 0);
pfctl_show_rules(dev, path, opts, PFCTL_SHOW_NOTHING,
- anchorname, 0);
+ anchorname, 0, 0);
+ }
if (clearopt != NULL) {
if (anchorname[0] == '_' || strstr(anchorname, "/_") != NULL)
@@ -2600,11 +3176,14 @@ main(int argc, char *argv[])
"be modified from the command line");
switch (*clearopt) {
+ case 'e':
+ pfctl_flush_eth_rules(dev, opts, anchorname);
+ break;
case 'r':
- pfctl_clear_rules(dev, opts, anchorname);
+ pfctl_flush_rules(dev, opts, anchorname);
break;
case 'n':
- pfctl_clear_nat(dev, opts, anchorname);
+ pfctl_flush_nat(dev, opts, anchorname);
break;
case 'q':
pfctl_clear_altq(dev, opts);
@@ -2619,8 +3198,9 @@ main(int argc, char *argv[])
pfctl_clear_stats(dev, opts);
break;
case 'a':
- pfctl_clear_rules(dev, opts, anchorname);
- pfctl_clear_nat(dev, opts, anchorname);
+ pfctl_flush_eth_rules(dev, opts, anchorname);
+ pfctl_flush_rules(dev, opts, anchorname);
+ pfctl_flush_nat(dev, opts, anchorname);
pfctl_clear_tables(anchorname, opts);
if (!*anchorname) {
pfctl_clear_altq(dev, opts);