Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F160339895
D32482.id96826.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
59 KB
Referenced Files
None
Subscribers
None
D32482.id96826.diff
View Options
Index: lib/libpfctl/libpfctl.h
===================================================================
--- lib/libpfctl/libpfctl.h
+++ lib/libpfctl/libpfctl.h
@@ -37,6 +37,7 @@
#include <netpfil/pf/pf.h>
struct pfctl_anchor;
+struct pfctl_eth_anchor;
struct pfctl_status_counter {
uint64_t id;
@@ -100,11 +101,28 @@
uint32_t dnflags;
uint8_t action;
+ struct pfctl_eth_anchor *anchor;
+ uint8_t anchor_relative;
+ uint8_t anchor_wildcard;
+
TAILQ_ENTRY(pfctl_eth_rule) entries;
};
-
TAILQ_HEAD(pfctl_eth_rules, pfctl_eth_rule);
+struct pfctl_eth_ruleset {
+ struct pfctl_eth_rules rules;
+ struct pfctl_eth_anchor *anchor;
+};
+
+struct pfctl_eth_anchor {
+ struct pfctl_eth_anchor *parent;
+ char name[PF_ANCHOR_NAME_SIZE];
+ char path[MAXPATHLEN];
+ struct pfctl_eth_ruleset ruleset;
+ int refcnt; /* anchor rules */
+ int match; /* XXX: used for pfctl black magic */
+};
+
struct pfctl_pool {
struct pf_palist list;
struct pf_pooladdr *cur;
@@ -330,11 +348,13 @@
struct pfctl_status* pfctl_get_status(int dev);
void pfctl_free_status(struct pfctl_status *status);
-int pfctl_get_eth_rules_info(int dev, struct pfctl_eth_rules_info *rules);
+int pfctl_get_eth_rules_info(int dev, struct pfctl_eth_rules_info *rules,
+ const char *path);
int pfctl_get_eth_rule(int dev, uint32_t nr, uint32_t ticket,
- struct pfctl_eth_rule *rule, bool clear);
+ const char *path, struct pfctl_eth_rule *rule, bool clear,
+ char *anchor_call);
int pfctl_add_eth_rule(int dev, const struct pfctl_eth_rule *r,
- uint32_t ticket);
+ const char *anchor, const char *anchor_call, uint32_t ticket);
int pfctl_get_rule(int dev, u_int32_t nr, u_int32_t ticket,
const char *anchor, u_int32_t ruleset, struct pfctl_rule *rule,
char *anchor_call);
Index: lib/libpfctl/libpfctl.c
===================================================================
--- lib/libpfctl/libpfctl.c
+++ lib/libpfctl/libpfctl.c
@@ -599,20 +599,34 @@
rule->dnpipe = nvlist_get_number(nvl, "dnpipe");
rule->dnflags = nvlist_get_number(nvl, "dnflags");
+ rule->anchor_relative = nvlist_get_number(nvl, "anchor_relative");
+ rule->anchor_wildcard = nvlist_get_number(nvl, "anchor_wildcard");
+
rule->action = nvlist_get_number(nvl, "action");
}
int
-pfctl_get_eth_rules_info(int dev, struct pfctl_eth_rules_info *rules)
+pfctl_get_eth_rules_info(int dev, struct pfctl_eth_rules_info *rules,
+ const char *path)
{
uint8_t buf[1024];
struct pfioc_nv nv;
nvlist_t *nvl;
+ void *packed;
+ size_t len;
bzero(rules, sizeof(*rules));
+ nvl = nvlist_create(0);
+ nvlist_add_string(nvl, "anchor", path);
+ packed = nvlist_pack(nvl, &len);
+ memcpy(buf, packed, len);
+ free(packed);
+ nvlist_destroy(nvl);
+
nv.data = buf;
- nv.len = nv.size = sizeof(buf);
+ nv.len = len;
+ nv.size = sizeof(buf);
if (ioctl(dev, DIOCGETETHRULES, &nv) != 0)
return (errno);
@@ -630,7 +644,8 @@
int
pfctl_get_eth_rule(int dev, uint32_t nr, uint32_t ticket,
- struct pfctl_eth_rule *rule, bool clear)
+ const char *path, struct pfctl_eth_rule *rule, bool clear,
+ char *anchor_call)
{
uint8_t buf[1024];
struct pfioc_nv nv;
@@ -640,6 +655,7 @@
nvl = nvlist_create(0);
+ nvlist_add_string(nvl, "anchor", path);
nvlist_add_number(nvl, "ticket", ticket);
nvlist_add_number(nvl, "nr", nr);
nvlist_add_bool(nvl, "clear", clear);
@@ -663,12 +679,17 @@
pfctl_nveth_rule_to_eth_rule(nvl, rule);
+ if (anchor_call)
+ strlcpy(anchor_call, nvlist_get_string(nvl, "anchor_call"),
+ MAXPATHLEN);
+
nvlist_destroy(nvl);
return (0);
}
int
-pfctl_add_eth_rule(int dev, const struct pfctl_eth_rule *r, uint32_t ticket)
+pfctl_add_eth_rule(int dev, const struct pfctl_eth_rule *r, const char *anchor,
+ const char *anchor_call, uint32_t ticket)
{
struct pfioc_nv nv;
nvlist_t *nvl, *addr;
@@ -679,6 +700,8 @@
nvl = nvlist_create(0);
nvlist_add_number(nvl, "ticket", ticket);
+ nvlist_add_string(nvl, "anchor", anchor);
+ nvlist_add_string(nvl, "anchor_call", anchor_call);
nvlist_add_number(nvl, "nr", r->nr);
nvlist_add_bool(nvl, "quick", r->quick);
Index: sbin/pfctl/parse.y
===================================================================
--- sbin/pfctl/parse.y
+++ sbin/pfctl/parse.y
@@ -350,7 +350,7 @@
struct node_port *, u_int8_t);
void expand_eth_rule(struct pfctl_eth_rule *,
struct node_if *, struct node_etherproto *,
- struct node_mac *, struct node_mac *);
+ struct node_mac *, struct node_mac *, const char *);
void expand_rule(struct pfctl_rule *, struct node_if *,
struct node_host *, struct node_proto *, struct node_os *,
struct node_host *, struct node_port *, struct node_host *,
@@ -370,6 +370,7 @@
int rt_tableid_max(void);
void mv_rules(struct pfctl_ruleset *, struct pfctl_ruleset *);
+void mv_eth_rules(struct pfctl_eth_ruleset *, struct pfctl_eth_ruleset *);
void decide_address_family(struct node_host *, sa_family_t *);
void remove_invalid_hosts(struct node_host **, sa_family_t *);
int invalid_redirect(struct node_host *, sa_family_t);
@@ -566,6 +567,7 @@
| ruleset '\n'
| ruleset option '\n'
| ruleset etherrule '\n'
+ | ruleset etheranchorrule '\n'
| ruleset scrubrule '\n'
| ruleset natrule '\n'
| ruleset binatrule '\n'
@@ -1195,7 +1197,95 @@
r.dnpipe = $8.dnpipe;
r.dnflags = $8.free_flags;
- expand_eth_rule(&r, $5, $6, $7.src, $7.dst);
+ expand_eth_rule(&r, $5, $6, $7.src, $7.dst, "");
+ }
+ ;
+
+etherpfa_anchorlist : /* empty */
+ | etherpfa_anchorlist '\n'
+ | etherpfa_anchorlist etherrule '\n'
+ | etherpfa_anchorlist etheranchorrule '\n'
+ ;
+
+etherpfa_anchor : '{'
+ {
+ char ta[PF_ANCHOR_NAME_SIZE];
+ struct pfctl_eth_ruleset *rs;
+
+ /* steping into a brace anchor */
+ pf->asd++;
+ pf->bn++;
+
+ /* create a holding ruleset in the root */
+ snprintf(ta, PF_ANCHOR_NAME_SIZE, "_%d", pf->bn);
+ rs = pf_find_or_create_eth_ruleset(ta);
+ if (rs == NULL)
+ err(1, "etherpfa_anchor: pf_find_or_create_eth_ruleset");
+ pf->eastack[pf->asd] = rs->anchor;
+ pf->eanchor = rs->anchor;
+ } '\n' etherpfa_anchorlist '}'
+ {
+ pf->ealast = pf->eanchor;
+ pf->asd--;
+ pf->eanchor = pf->eastack[pf->asd];
+ }
+ | /* empty */
+ ;
+
+etheranchorrule : ETHER ANCHOR anchorname dir quick interface etherproto etherfromto etherpfa_anchor
+ {
+ struct pfctl_eth_rule r;
+
+ if (check_rulestate(PFCTL_STATE_ETHER)) {
+ free($3);
+ YYERROR;
+ }
+
+ if ($3 && ($3[0] == '_' || strstr($3, "/_") != NULL)) {
+ free($3);
+ yyerror("anchor names beginning with '_' "
+ "are reserved for internal use");
+ YYERROR;
+ }
+
+ memset(&r, 0, sizeof(r));
+ if (pf->eastack[pf->asd + 1]) {
+ /* move inline rules into relative location */
+ pfctl_eth_anchor_setup(pf, &r,
+ &pf->eastack[pf->asd]->ruleset,
+ $3 ? $3 : pf->ealast->name);
+ if (r.anchor == NULL)
+ err(1, "etheranchorrule: unable to "
+ "create ruleset");
+
+ if (pf->ealast != r.anchor) {
+ if (r.anchor->match) {
+ yyerror("inline anchor '%s' "
+ "already exists",
+ r.anchor->name);
+ YYERROR;
+ }
+ mv_eth_rules(&pf->ealast->ruleset,
+ &r.anchor->ruleset);
+ }
+ pf_remove_if_empty_eth_ruleset(&pf->ealast->ruleset);
+ pf->ealast = r.anchor;
+ } else {
+ if (!$3) {
+ yyerror("anchors without explicit "
+ "rules must specify a name");
+ YYERROR;
+ }
+ }
+
+ r.direction = $4;
+ r.quick = $5.quick;
+
+ expand_eth_rule(&r, $6, $7, $8.src, $8.dst,
+ pf->eastack[pf->asd + 1] ? pf->ealast->name : $3);
+
+ free($3);
+ pf->eastack[pf->asd + 1] = NULL;
}
;
@@ -5623,15 +5713,12 @@
void
expand_eth_rule(struct pfctl_eth_rule *r,
struct node_if *interfaces, struct node_etherproto *protos,
- struct node_mac *srcs, struct node_mac *dsts)
+ struct node_mac *srcs, struct node_mac *dsts, const char *anchor_call)
{
- struct pfctl_eth_rule *rule;
-
LOOP_THROUGH(struct node_if, interface, interfaces,
LOOP_THROUGH(struct node_etherproto, proto, protos,
LOOP_THROUGH(struct node_mac, src, srcs,
LOOP_THROUGH(struct node_mac, dst, dsts,
- r->nr = pf->eth_nr++;
strlcpy(r->ifname, interface->ifname,
sizeof(r->ifname));
r->ifnot = interface->not;
@@ -5640,12 +5727,9 @@
r->src.neg = src->neg;
bcopy(dst->mac, r->dst.addr, ETHER_ADDR_LEN);
r->dst.neg = dst->neg;
+ r->nr = pf->eastack[pf->asd]->match++;
- if ((rule = calloc(1, sizeof(*rule))) == NULL)
- err(1, "calloc");
- bcopy(r, rule, sizeof(*rule));
-
- TAILQ_INSERT_TAIL(&pf->eth_rules, rule, entries);
+ pfctl_append_eth_rule(pf, r, anchor_call);
))));
FREE_LIST(struct node_if, interfaces);
@@ -6516,6 +6600,19 @@
}
}
+void
+mv_eth_rules(struct pfctl_eth_ruleset *src, struct pfctl_eth_ruleset *dst)
+{
+ struct pfctl_eth_rule *r;
+
+ while ((r = TAILQ_FIRST(&src->rules)) != NULL) {
+ TAILQ_REMOVE(&src->rules, r, entries);
+ TAILQ_INSERT_TAIL(&dst->rules, r, entries);
+ dst->anchor->match++;
+ }
+ src->anchor->match = 0;
+}
+
void
decide_address_family(struct node_host *n, sa_family_t *af)
{
Index: sbin/pfctl/pf_ruleset.c
===================================================================
--- sbin/pfctl/pf_ruleset.c
+++ sbin/pfctl/pf_ruleset.c
@@ -65,6 +65,7 @@
#define rs_free(x) free(x)
#include "pfctl.h"
+#include "pfctl_parser.h"
#ifdef PFDEBUG
#include <sys/stdarg.h>
@@ -74,7 +75,8 @@
#endif /* PFDEBUG */
struct pfctl_anchor_global pf_anchors;
-struct pfctl_anchor pf_main_anchor;
+extern struct pfctl_anchor pf_main_anchor;
+extern struct pfctl_eth_anchor pf_eth_main_anchor;
#undef V_pf_anchors
#define V_pf_anchors pf_anchors
#undef pf_main_ruleset
@@ -290,6 +292,148 @@
ruleset = &parent->ruleset;
}
}
+
+void
+pf_remove_if_empty_eth_ruleset(struct pfctl_eth_ruleset *ruleset)
+{
+ struct pfctl_eth_anchor *parent;
+
+ return;
+ while (ruleset != NULL) {
+ if (ruleset == &pf_eth_main_anchor.ruleset ||
+ ruleset->anchor == NULL || ruleset->anchor->refcnt > 0)
+ return;
+ if (!TAILQ_EMPTY(&ruleset->rules))
+ return;
+ rs_free(ruleset->anchor);
+ if (parent == NULL)
+ return;
+ ruleset = &parent->ruleset;
+ }
+}
+
+void
+pf_init_eth_ruleset(struct pfctl_eth_ruleset *ruleset)
+{
+
+ memset(ruleset, 0, sizeof(*ruleset));
+ TAILQ_INIT(&ruleset->rules);
+}
+
+
+static struct pfctl_eth_anchor*
+_pf_find_eth_anchor(struct pfctl_eth_anchor *anchor, const char *path)
+{
+ struct pfctl_eth_rule *r;
+ struct pfctl_eth_anchor *a;
+
+ if (strcmp(path, anchor->path) == 0)
+ return (anchor);
+
+ TAILQ_FOREACH(r, &anchor->ruleset.rules, entries) {
+ if (! r->anchor)
+ continue;
+
+ /* Step into anchor */
+ a = _pf_find_eth_anchor(r->anchor, path);
+ if (a)
+ return (a);
+ }
+
+ return (NULL);
+}
+
+static struct pfctl_eth_anchor*
+pf_find_eth_anchor(const char *path)
+{
+ return (_pf_find_eth_anchor(&pf_eth_main_anchor, path));
+}
+
+static struct pfctl_eth_ruleset*
+pf_find_eth_ruleset(const char *path)
+{
+ struct pfctl_eth_anchor *anchor;
+
+ while (*path == '/')
+ path++;
+ if (!*path)
+ return (&pf_eth_main_anchor.ruleset);
+ anchor = pf_find_eth_anchor(path);
+ if (anchor == NULL)
+ return (NULL);
+ else
+ return (&anchor->ruleset);
+}
+
+struct pfctl_eth_ruleset *
+pf_find_or_create_eth_ruleset(const char *path)
+{
+ char *p, *q, *r;
+ struct pfctl_eth_ruleset *ruleset;
+ struct pfctl_eth_anchor *anchor = NULL, *parent = NULL;
+
+ if (path[0] == 0)
+ return (&pf_eth_main_anchor.ruleset);
+ while (*path == '/')
+ path++;
+ ruleset = pf_find_eth_ruleset(path);
+ if (ruleset != NULL)
+ return (ruleset);
+ p = (char *)rs_malloc(MAXPATHLEN);
+ if (p == NULL)
+ return (NULL);
+ strlcpy(p, path, MAXPATHLEN);
+ while (parent == NULL && (q = strrchr(p, '/')) != NULL) {
+ *q = 0;
+ if ((ruleset = pf_find_eth_ruleset(p)) != NULL) {
+ parent = ruleset->anchor;
+ break;
+ }
+ }
+ if (q == NULL)
+ q = p;
+ else
+ q++;
+ strlcpy(p, path, MAXPATHLEN);
+ if (!*q) {
+ rs_free(p);
+ return (NULL);
+ }
+ while ((r = strchr(q, '/')) != NULL || *q) {
+ if (r != NULL)
+ *r = 0;
+ if (!*q || strlen(q) >= PF_ANCHOR_NAME_SIZE ||
+ (parent != NULL && strlen(parent->path) >=
+ MAXPATHLEN - PF_ANCHOR_NAME_SIZE - 1)) {
+ rs_free(p);
+ return (NULL);
+ }
+ anchor = (struct pfctl_eth_anchor *)rs_malloc(sizeof(*anchor));
+ if (anchor == NULL) {
+ rs_free(p);
+ return (NULL);
+ }
+ strlcpy(anchor->name, q, sizeof(anchor->name));
+ if (parent != NULL) {
+ strlcpy(anchor->path, parent->path,
+ sizeof(anchor->path));
+ strlcat(anchor->path, "/", sizeof(anchor->path));
+ }
+ strlcat(anchor->path, anchor->name, sizeof(anchor->path));
+ if (parent != NULL)
+ anchor->parent = parent;
+ pf_init_eth_ruleset(&anchor->ruleset);
+ anchor->ruleset.anchor = anchor;
+ parent = anchor;
+ if (r != NULL)
+ q = r + 1;
+ else
+ *q = 0;
+ }
+ rs_free(p);
+ return (&anchor->ruleset);
+}
+
int
pfctl_anchor_setup(struct pfctl_rule *r, const struct pfctl_ruleset *s,
const char *name)
@@ -345,3 +489,54 @@
r->anchor->refcnt++;
return (0);
}
+
+int
+pfctl_eth_anchor_setup(struct pfctl *pf, struct pfctl_eth_rule *r,
+ const struct pfctl_eth_ruleset *s, const char *name)
+{
+ char *p, *path;
+ struct pfctl_eth_ruleset *ruleset;
+
+ r->anchor = NULL;
+ if (!name[0])
+ return (0);
+ path = (char *)rs_malloc(MAXPATHLEN);
+ if (path == NULL)
+ return (1);
+ if (name[0] == '/')
+ strlcpy(path, name + 1, MAXPATHLEN);
+ else {
+ /* relative path */
+ if (s->anchor == NULL || !s->anchor->path[0])
+ path[0] = 0;
+ else
+ strlcpy(path, s->anchor->path, MAXPATHLEN);
+ while (name[0] == '.' && name[1] == '.' && name[2] == '/') {
+ if (!path[0]) {
+ printf("%s: .. beyond root\n", __func__);
+ rs_free(path);
+ return (1);
+ }
+ if ((p = strrchr(path, '/')) != NULL)
+ *p = 0;
+ else
+ path[0] = 0;
+ name += 3;
+ }
+ if (path[0])
+ strlcat(path, "/", MAXPATHLEN);
+ strlcat(path, name, MAXPATHLEN);
+ }
+ if ((p = strrchr(path, '/')) != NULL && !strcmp(p, "/*")) {
+ *p = 0;
+ }
+ ruleset = pf_find_or_create_eth_ruleset(path);
+ rs_free(path);
+ if (ruleset == NULL || ruleset->anchor == NULL) {
+ printf("%s: ruleset\n", __func__);
+ return (1);
+ }
+ r->anchor = ruleset->anchor;
+ r->anchor->refcnt++;
+ return (0);
+}
Index: sbin/pfctl/pfctl.h
===================================================================
--- sbin/pfctl/pfctl.h
+++ sbin/pfctl/pfctl.h
@@ -38,6 +38,8 @@
#include <libpfctl.h>
+struct pfctl;
+
enum pfctl_show { PFCTL_SHOW_RULES, PFCTL_SHOW_LABELS, PFCTL_SHOW_NOTHING };
enum { PFRB_TABLES = 1, PFRB_TSTATS, PFRB_ADDRS, PFRB_ASTATS,
@@ -137,6 +139,13 @@
void pf_remove_if_empty_ruleset(struct pfctl_ruleset *);
struct pfctl_ruleset *pf_find_ruleset(const char *);
struct pfctl_ruleset *pf_find_or_create_ruleset(const char *);
+void pf_init_eth_ruleset(struct pfctl_eth_ruleset *);
+int pfctl_eth_anchor_setup(struct pfctl *,
+ struct pfctl_eth_rule *,
+ const struct pfctl_eth_ruleset *, const char *);
+struct pfctl_eth_ruleset *pf_find_or_create_eth_ruleset(const char *);
+void pf_remove_if_empty_eth_ruleset(
+ struct pfctl_eth_ruleset *);
const char *pfctl_proto2name(int);
Index: sbin/pfctl/pfctl.c
===================================================================
--- sbin/pfctl/pfctl.c
+++ sbin/pfctl/pfctl.c
@@ -98,7 +98,7 @@
char *);
void pfctl_print_eth_rule_counters(struct pfctl_eth_rule *, int);
void pfctl_print_rule_counters(struct pfctl_rule *, int);
-int pfctl_show_eth_rules(int, int, enum pfctl_show);
+int pfctl_show_eth_rules(int, char *, int, enum pfctl_show, char *, int);
int pfctl_show_rules(int, char *, int, enum pfctl_show, char *, int);
int pfctl_show_nat(int, int, char *);
int pfctl_show_src_nodes(int, int);
@@ -110,15 +110,21 @@
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_load_eth_ruleset(struct pfctl *);
+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;
@@ -1052,31 +1058,66 @@
}
int
-pfctl_show_eth_rules(int dev, int opts, enum pfctl_show format)
+pfctl_show_eth_rules(int dev, char *path, int opts, enum pfctl_show format,
+ char *anchorname, int depth)
{
+ char anchor_call[MAXPATHLEN];
struct pfctl_eth_rules_info info;
struct pfctl_eth_rule rule;
int dotitle = opts & PF_OPT_SHOWALL;
+ int len = strlen(path);
+ int brace;
+ char *p;
+
+ if (path[0])
+ snprintf(&path[len], MAXPATHLEN - len, "/%s", anchorname);
+ else
+ snprintf(&path[len], MAXPATHLEN - len, "%s", anchorname);
- if (pfctl_get_eth_rules_info(dev, &info)) {
+ if (pfctl_get_eth_rules_info(dev, &info, path)) {
warn("DIOCGETETHRULES");
return (-1);
}
for (int nr = 0; nr < info.nr; nr++) {
- if (pfctl_get_eth_rule(dev, nr, info.ticket, &rule,
- opts & PF_OPT_CLRRULECTRS) != 0) {
+ 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++;
+ if ((p = strrchr(anchor_call, '/')) !=
+ NULL)
+ p++;
+ else
+ p = &anchor_call[0];
+ } else
+ p = &anchor_call[0];
if (dotitle) {
pfctl_print_title("ETH RULES:");
dotitle = 0;
}
- print_eth_rule(&rule, opts & (PF_OPT_VERBOSE2 | PF_OPT_DEBUG));
- printf("\n");
+ 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);
+ INDENT(depth, !(opts & PF_OPT_VERBOSE));
+ printf("}\n");
+ }
}
+ path[len] = '\0';
return (0);
}
@@ -1508,15 +1549,70 @@
}
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 (! path[0]) {
- if (pfctl_add_trans(pf->trans, PF_RULESET_ETH, path))
- return (1);
- }
+ 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) ||
@@ -1544,20 +1640,90 @@
}
int
-pfctl_load_eth_ruleset(struct pfctl *pf)
+pfctl_load_eth_ruleset(struct pfctl *pf, char *path,
+ struct pfctl_eth_ruleset *rs, int depth)
{
struct pfctl_eth_rule *r;
- int error;
+ 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);
- while ((r = TAILQ_FIRST(&pf->eth_rules)) != NULL) {
- TAILQ_REMOVE(&pf->eth_rules, r, entries);
+ 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");
+ }
- error = pfctl_add_eth_rule(pf->dev, r, pf->eth_ticket);
+ 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);
+ }
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 (pfctl_add_eth_rule(pf->dev, r, anchor, name, pf->eth_ticket))
+ err(1, "DIOCADDETHRULENV");
+
+ path[len] = '\0';
return (0);
}
@@ -1584,7 +1750,7 @@
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;
@@ -1703,6 +1869,7 @@
struct pfioc_altq pa;
struct pfctl pf;
struct pfctl_ruleset *rs;
+ struct pfctl_eth_ruleset *ethrs;
struct pfr_table trs;
char *path;
int osize;
@@ -1711,6 +1878,11 @@
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;
@@ -1734,7 +1906,6 @@
pf.opts = opts;
pf.optimize = optimize;
pf.loadopt = loadopt;
- TAILQ_INIT(&pf.eth_rules);
/* non-brace anchor, create without resolving the path */
if ((pf.anchor = calloc(1, sizeof(*pf.anchor))) == NULL)
@@ -1744,10 +1915,10 @@
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;
@@ -1758,13 +1929,29 @@
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);
@@ -1789,7 +1976,7 @@
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))) ||
+ (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) ||
@@ -2632,13 +2819,13 @@
pfctl_show_limits(dev, opts);
break;
case 'e':
- pfctl_show_eth_rules(dev, opts, 0);
+ pfctl_show_eth_rules(dev, path, opts, 0, anchorname, 0);
break;
case 'a':
opts |= PF_OPT_SHOWALL;
pfctl_load_fingerprints(dev, opts);
- pfctl_show_eth_rules(dev, opts, 0);
+ pfctl_show_eth_rules(dev, path, opts, 0, anchorname, 0);
pfctl_show_nat(dev, opts, anchorname);
pfctl_show_rules(dev, path, opts, 0, anchorname, 0);
@@ -2666,7 +2853,8 @@
}
if ((opts & PF_OPT_CLRRULECTRS) && showopt == NULL) {
- pfctl_show_eth_rules(dev, opts, PFCTL_SHOW_NOTHING);
+ pfctl_show_eth_rules(dev, path, opts, PFCTL_SHOW_NOTHING,
+ anchorname, 0);
pfctl_show_rules(dev, path, opts, PFCTL_SHOW_NOTHING,
anchorname, 0);
}
Index: sbin/pfctl/pfctl_parser.h
===================================================================
--- sbin/pfctl/pfctl_parser.h
+++ sbin/pfctl/pfctl_parser.h
@@ -91,7 +91,8 @@
struct pfr_buffer *trans;
struct pfctl_anchor *anchor, *alast;
int eth_nr;
- struct pfctl_eth_rules eth_rules;
+ struct pfctl_eth_anchor *eanchor, *ealast;
+ struct pfctl_eth_anchor *eastack[PFCTL_ANCHOR_STACK_DEPTH];
u_int32_t eth_ticket;
const char *ruleset;
@@ -274,6 +275,8 @@
int pfctl_optimize_ruleset(struct pfctl *, struct pfctl_ruleset *);
int pfctl_append_rule(struct pfctl *, struct pfctl_rule *, const char *);
+int pfctl_append_eth_rule(struct pfctl *, struct pfctl_eth_rule *,
+ const char *);
int pfctl_add_altq(struct pfctl *, struct pf_altq *);
int pfctl_add_pool(struct pfctl *, struct pfctl_pool *, sa_family_t);
void pfctl_move_pool(struct pfctl_pool *, struct pfctl_pool *);
@@ -294,7 +297,7 @@
void print_pool(struct pfctl_pool *, u_int16_t, u_int16_t, sa_family_t, int);
void print_src_node(struct pf_src_node *, int);
-void print_eth_rule(struct pfctl_eth_rule *, int);
+void print_eth_rule(struct pfctl_eth_rule *, const char *, int);
void print_rule(struct pfctl_rule *, const char *, int, int);
void print_tabledef(const char *, int, int, struct node_tinithead *);
void print_status(struct pfctl_status *, struct pfctl_syncookies *, int);
Index: sbin/pfctl/pfctl_parser.c
===================================================================
--- sbin/pfctl/pfctl_parser.c
+++ sbin/pfctl/pfctl_parser.c
@@ -710,14 +710,23 @@
}
void
-print_eth_rule(struct pfctl_eth_rule *r, int rule_numbers)
+print_eth_rule(struct pfctl_eth_rule *r, const char *anchor_call,
+ int rule_numbers)
{
static const char *actiontypes[] = { "pass", "block" };
if (rule_numbers)
printf("@%u ", r->nr);
- printf("ether %s", actiontypes[r->action]);
+ printf("ether ");
+ if (anchor_call[0]) {
+ if (anchor_call[0] == '_') {
+ printf("anchor");
+ } else
+ printf("anchor \"%s\"", anchor_call);
+ } else {
+ printf("%s", actiontypes[r->action]);
+ }
if (r->direction == PF_IN)
printf(" in");
else if (r->direction == PF_OUT)
Index: sys/net/pfvar.h
===================================================================
--- sys/net/pfvar.h
+++ sys/net/pfvar.h
@@ -581,6 +581,41 @@
uint8_t isset;
};
+struct pf_keth_anchor;
+
+TAILQ_HEAD(pf_keth_ruleq, pf_keth_rule);
+
+struct pf_keth_ruleset {
+ struct pf_keth_ruleq rules[2];
+ struct pf_keth_rules {
+ struct pf_keth_ruleq *rules;
+ int open;
+ uint32_t ticket;
+ } active, inactive;
+ struct epoch_context epoch_ctx;
+ struct vnet *vnet;
+ struct pf_keth_anchor *anchor;
+};
+
+RB_HEAD(pf_keth_anchor_global, pf_keth_anchor);
+RB_HEAD(pf_keth_anchor_node, pf_keth_anchor);
+struct pf_keth_anchor {
+ RB_ENTRY(pf_keth_anchor) entry_node;
+ RB_ENTRY(pf_keth_anchor) entry_global;
+ struct pf_keth_anchor *parent;
+ struct pf_keth_anchor_node children;
+ char name[PF_ANCHOR_NAME_SIZE];
+ char path[MAXPATHLEN];
+ struct pf_keth_ruleset ruleset;
+ int refcnt; /* anchor rules */
+ uint8_t anchor_relative;
+ uint8_t anchor_wildcard;
+};
+RB_PROTOTYPE(pf_keth_anchor_node, pf_keth_anchor, entry_node,
+ pf_keth_anchor_compare);
+RB_PROTOTYPE(pf_keth_anchor_global, pf_keth_anchor, entry_global,
+ pf_keth_anchor_compare);
+
struct pf_keth_rule {
#define PFE_SKIP_IFP 0
#define PFE_SKIP_DIR 1
@@ -592,6 +627,10 @@
TAILQ_ENTRY(pf_keth_rule) entries;
+ struct pf_keth_anchor *anchor;
+ u_int8_t anchor_relative;
+ u_int8_t anchor_wildcard;
+
uint32_t nr;
bool quick;
@@ -619,16 +658,6 @@
uint32_t dnflags;
};
-TAILQ_HEAD(pf_keth_rules, pf_keth_rule);
-
-struct pf_keth_settings {
- struct pf_keth_rules rules;
- uint32_t ticket;
- int open;
- struct vnet *vnet;
- struct epoch_context epoch_ctx;
-};
-
union pf_krule_ptr {
struct pf_krule *ptr;
u_int32_t nr;
@@ -1148,6 +1177,7 @@
PFR_TFLAG_COUNTERS)
struct pf_kanchor_stackframe;
+struct pf_keth_anchor_stackframe;
struct pfr_table {
char pfrt_anchor[MAXPATHLEN];
@@ -2205,15 +2235,17 @@
#define V_pf_anchors VNET(pf_anchors)
VNET_DECLARE(struct pf_kanchor, pf_main_anchor);
#define V_pf_main_anchor VNET(pf_main_anchor)
+VNET_DECLARE(struct pf_keth_anchor_global, pf_keth_anchors);
+#define V_pf_keth_anchors VNET(pf_keth_anchors)
#define pf_main_ruleset V_pf_main_anchor.ruleset
-VNET_DECLARE(struct pf_keth_settings*, pf_keth);
+VNET_DECLARE(struct pf_keth_anchor, pf_main_keth_anchor);
+#define V_pf_main_keth_anchor VNET(pf_main_keth_anchor)
+VNET_DECLARE(struct pf_keth_ruleset*, pf_keth);
#define V_pf_keth VNET(pf_keth)
-VNET_DECLARE(struct pf_keth_settings*, pf_keth_inactive);
-#define V_pf_keth_inactive VNET(pf_keth_inactive)
void pf_init_kruleset(struct pf_kruleset *);
-void pf_init_keth(struct pf_keth_settings *);
+void pf_init_keth(struct pf_keth_ruleset *);
int pf_kanchor_setup(struct pf_krule *,
const struct pf_kruleset *, const char *);
int pf_kanchor_nvcopyout(const struct pf_kruleset *,
@@ -2226,6 +2258,18 @@
struct pf_kruleset *pf_find_or_create_kruleset(const char *);
void pf_rs_initialize(void);
+void pf_remove_if_empty_keth_ruleset(
+ struct pf_keth_ruleset *);
+struct pf_keth_ruleset *pf_find_keth_ruleset(const char *);
+struct pf_keth_anchor *pf_find_keth_anchor(const char *);
+int pf_keth_anchor_setup(struct pf_keth_rule *,
+ const struct pf_keth_ruleset *, const char *);
+int pf_keth_anchor_nvcopyout(
+ const struct pf_keth_ruleset *,
+ const struct pf_keth_rule *, nvlist_t *);
+struct pf_keth_ruleset *pf_find_or_create_keth_ruleset(const char *);
+void pf_keth_anchor_remove(struct pf_keth_rule *);
+
void pf_krule_free(struct pf_krule *);
#endif
@@ -2249,6 +2293,14 @@
int pf_step_out_of_anchor(struct pf_kanchor_stackframe *, int *,
struct pf_kruleset **, int, struct pf_krule **,
struct pf_krule **, int *);
+void pf_step_into_keth_anchor(struct pf_keth_anchor_stackframe *,
+ int *, struct pf_keth_ruleset **,
+ struct pf_keth_rule **, struct pf_keth_rule **,
+ int *);
+int pf_step_out_of_keth_anchor(struct pf_keth_anchor_stackframe *,
+ int *, struct pf_keth_ruleset **,
+ struct pf_keth_rule **, struct pf_keth_rule **,
+ int *);
int pf_map_addr(u_int8_t, struct pf_krule *,
struct pf_addr *, struct pf_addr *,
Index: sys/netpfil/pf/pf.c
===================================================================
--- sys/netpfil/pf/pf.c
+++ sys/netpfil/pf/pf.c
@@ -3278,6 +3278,110 @@
return (quick);
}
+struct pf_keth_anchor_stackframe {
+ struct pf_keth_ruleset *rs;
+ struct pf_keth_rule *r; /* XXX: + match bit */
+ struct pf_keth_anchor *child;
+};
+
+#define PF_ETH_ANCHOR_MATCH(f) ((uintptr_t)(f)->r & PF_ANCHORSTACK_MATCH)
+#define PF_ETH_ANCHOR_RULE(f) (struct pf_keth_rule *) \
+ ((uintptr_t)(f)->r & ~PF_ANCHORSTACK_MASK)
+#define PF_ETH_ANCHOR_SET_MATCH(f) do { (f)->r = (void *) \
+ ((uintptr_t)(f)->r | PF_ANCHORSTACK_MATCH); \
+} while (0)
+
+void
+pf_step_into_keth_anchor(struct pf_keth_anchor_stackframe *stack, int *depth,
+ struct pf_keth_ruleset **rs, struct pf_keth_rule **r,
+ struct pf_keth_rule **a, int *match)
+{
+ struct pf_keth_anchor_stackframe *f;
+
+ NET_EPOCH_ASSERT();
+
+ if (match)
+ *match = 0;
+ if (*depth >= PF_ANCHOR_STACKSIZE) {
+ printf("%s: anchor stack overflow on %s\n",
+ __func__, (*r)->anchor->name);
+ *r = TAILQ_NEXT(*r, entries);
+ return;
+ } else if (*depth == 0 && a != NULL)
+ *a = *r;
+ f = stack + (*depth)++;
+ f->rs = *rs;
+ f->r = *r;
+ if ((*r)->anchor_wildcard) {
+ struct pf_keth_anchor_node *parent = &(*r)->anchor->children;
+
+ if ((f->child = RB_MIN(pf_keth_anchor_node, parent)) == NULL) {
+ *r = NULL;
+ return;
+ }
+ *rs = &f->child->ruleset;
+ } else {
+ f->child = NULL;
+ *rs = &(*r)->anchor->ruleset;
+ }
+ *r = TAILQ_FIRST((*rs)->active.rules);
+}
+
+int
+pf_step_out_of_keth_anchor(struct pf_keth_anchor_stackframe *stack, int *depth,
+ struct pf_keth_ruleset **rs, struct pf_keth_rule **r,
+ struct pf_keth_rule **a, int *match)
+{
+ struct pf_keth_anchor_stackframe *f;
+ struct pf_keth_rule *fr;
+ int quick = 0;
+
+ NET_EPOCH_ASSERT();
+
+ do {
+ if (*depth <= 0)
+ break;
+ f = stack + *depth - 1;
+ fr = PF_ETH_ANCHOR_RULE(f);
+ if (f->child != NULL) {
+ struct pf_keth_anchor_node *parent;
+ /*
+ * This block traverses through
+ * a wildcard anchor.
+ */
+ parent = &fr->anchor->children;
+ if (match != NULL && *match) {
+ /*
+ * If any of "*" matched, then
+ * "foo/ *" matched, mark frame
+ * appropriately.
+ */
+ PF_ETH_ANCHOR_SET_MATCH(f);
+ *match = 0;
+ }
+ f->child = RB_NEXT(pf_keth_anchor_node, parent,
+ f->child);
+ if (f->child != NULL) {
+ *rs = &f->child->ruleset;
+ *r = TAILQ_FIRST((*rs)->active.rules);
+ if (*r == NULL)
+ continue;
+ else
+ break;
+ }
+ }
+ (*depth)--;
+ if (*depth == 0 && a != NULL)
+ *a = NULL;
+ *rs = f->rs;
+ if (PF_ETH_ANCHOR_MATCH(f) || (match != NULL && *match))
+ quick = fr->quick;
+ *r = TAILQ_NEXT(fr, entries);
+ } while (*r == NULL);
+
+ return (quick);
+}
+
#ifdef INET6
void
pf_poolmask(struct pf_addr *naddr, struct pf_addr *raddr,
@@ -3593,10 +3697,13 @@
pf_test_eth_rule(int dir, struct pfi_kkif *kif, struct mbuf *m)
{
struct ether_header *e;
- struct pf_keth_rule *r, *rm;
+ struct pf_keth_rule *r, *rm, *a = NULL;
+ struct pf_keth_ruleset *ruleset = NULL;
struct pf_mtag *mtag;
- struct pf_keth_settings *settings;
+ struct pf_keth_ruleq *rules;
+ int asd = 0, match = 0;
uint8_t action;
+ struct pf_keth_anchor_stackframe anchor_stack[PF_ANCHOR_STACKSIZE];
NET_EPOCH_ASSERT();
@@ -3607,8 +3714,9 @@
e = mtod(m, struct ether_header *);
- settings = ck_pr_load_ptr(&V_pf_keth);
- r = TAILQ_FIRST(&settings->rules);
+ ruleset = V_pf_keth;
+ rules = ck_pr_load_ptr(&ruleset->active.rules);
+ r = TAILQ_FIRST(rules);
rm = NULL;
while (r != NULL) {
@@ -3641,16 +3749,24 @@
r = TAILQ_NEXT(r, entries);
}
else {
- /* Rule matches */
- rm = r;
+ if (r->anchor == NULL) {
+ /* Rule matches */
+ rm = r;
- SDT_PROBE2(pf, eth, test_rule, match, r->nr, r);
+ SDT_PROBE2(pf, eth, test_rule, match, r->nr, r);
- if (r->quick)
- break;
+ if (r->quick)
+ break;
- r = TAILQ_NEXT(r, entries);
+ r = TAILQ_NEXT(r, entries);
+ } else {
+ pf_step_into_keth_anchor(anchor_stack, &asd,
+ &ruleset, &r, &a, &match);
+ }
}
+ if (r == NULL && pf_step_out_of_keth_anchor(anchor_stack, &asd,
+ &ruleset, &r, &a, &match))
+ break;
}
r = rm;
Index: sys/netpfil/pf/pf_ioctl.c
===================================================================
--- sys/netpfil/pf/pf_ioctl.c
+++ sys/netpfil/pf/pf_ioctl.c
@@ -106,10 +106,10 @@
static void pf_empty_kpool(struct pf_kpalist *);
static int pfioctl(struct cdev *, u_long, caddr_t, int,
struct thread *);
-static int pf_begin_eth(uint32_t *);
+static int pf_begin_eth(uint32_t *, const char *);
static void pf_rollback_eth_cb(struct epoch_context *);
-static int pf_rollback_eth(uint32_t);
-static int pf_commit_eth(uint32_t);
+static int pf_rollback_eth(uint32_t, const char *);
+static int pf_commit_eth(uint32_t, const char *);
static void pf_free_eth_rule(struct pf_keth_rule *);
#ifdef ALTQ
static int pf_begin_altq(u_int32_t *);
@@ -318,7 +318,6 @@
pf_init_kruleset(&pf_main_ruleset);
pf_init_keth(V_pf_keth);
- pf_init_keth(V_pf_keth_inactive);
/* default rule should never be garbage collected */
V_pf_default_rule.entries.tqe_prev = &V_pf_default_rule.entries.tqe_next;
@@ -510,6 +509,7 @@
counter_u64_free(rule->packets[i]);
counter_u64_free(rule->bytes[i]);
}
+ pf_keth_anchor_remove(rule);
free(rule, M_PFRULE);
}
@@ -701,26 +701,32 @@
}
static int
-pf_begin_eth(uint32_t *ticket)
+pf_begin_eth(uint32_t *ticket, const char *anchor)
{
struct pf_keth_rule *rule, *tmp;
+ struct pf_keth_ruleset *rs;
PF_RULES_WASSERT();
- if (V_pf_keth_inactive->open) {
+ rs = pf_find_or_create_keth_ruleset(anchor);
+ if (rs == NULL)
+ return (EINVAL);
+
+ if (rs->inactive.open)
/* We may be waiting for NET_EPOCH_CALL(pf_rollback_eth_cb) to
* finish. */
return (EBUSY);
- }
/* Purge old inactive rules. */
- TAILQ_FOREACH_SAFE(rule, &V_pf_keth_inactive->rules, entries, tmp) {
- TAILQ_REMOVE(&V_pf_keth_inactive->rules, rule, entries);
+ TAILQ_FOREACH_SAFE(rule, rs->inactive.rules, entries,
+ tmp) {
+ TAILQ_REMOVE(rs->inactive.rules, rule,
+ entries);
pf_free_eth_rule(rule);
}
- *ticket = ++V_pf_keth_inactive->ticket;
- V_pf_keth_inactive->open = 1;
+ *ticket = ++rs->inactive.ticket;
+ rs->inactive.open = 1;
return (0);
}
@@ -728,38 +734,46 @@
static void
pf_rollback_eth_cb(struct epoch_context *ctx)
{
- struct pf_keth_settings *settings;
-
- settings = __containerof(ctx, struct pf_keth_settings, epoch_ctx);
+ struct pf_keth_ruleset *rs;
- CURVNET_SET(settings->vnet);
+ rs = __containerof(ctx, struct pf_keth_ruleset, epoch_ctx);
- MPASS(settings == V_pf_keth_inactive);
+ CURVNET_SET(rs->vnet);
PF_RULES_WLOCK();
- pf_rollback_eth(V_pf_keth_inactive->ticket);
+ pf_rollback_eth(rs->inactive.ticket,
+ rs->anchor ? rs->anchor->path : "");
PF_RULES_WUNLOCK();
CURVNET_RESTORE();
}
static int
-pf_rollback_eth(uint32_t ticket)
+pf_rollback_eth(uint32_t ticket, const char *anchor)
{
struct pf_keth_rule *rule, *tmp;
+ struct pf_keth_ruleset *rs;
PF_RULES_WASSERT();
- if (!V_pf_keth_inactive->open || ticket != V_pf_keth_inactive->ticket)
+ rs = pf_find_keth_ruleset(anchor);
+ if (rs == NULL)
+ return (EINVAL);
+
+ if (!rs->inactive.open ||
+ ticket != rs->inactive.ticket)
return (0);
/* Purge old inactive rules. */
- TAILQ_FOREACH_SAFE(rule, &V_pf_keth_inactive->rules, entries, tmp) {
- TAILQ_REMOVE(&V_pf_keth_inactive->rules, rule, entries);
+ TAILQ_FOREACH_SAFE(rule, rs->inactive.rules, entries,
+ tmp) {
+ TAILQ_REMOVE(rs->inactive.rules, rule, entries);
pf_free_eth_rule(rule);
}
- V_pf_keth_inactive->open = 0;
+ rs->inactive.open = 0;
+
+ pf_remove_if_empty_keth_ruleset(rs);
return (0);
}
@@ -773,7 +787,7 @@
} while (0)
static void
-pf_eth_calc_skip_steps(struct pf_keth_rules *rules)
+pf_eth_calc_skip_steps(struct pf_keth_ruleq *rules)
{
struct pf_keth_rule *cur, *prev, *head[PFE_SKIP_COUNT];
int i;
@@ -802,26 +816,32 @@
}
static int
-pf_commit_eth(uint32_t ticket)
+pf_commit_eth(uint32_t ticket, const char *anchor)
{
- struct pf_keth_settings *settings;
+ struct pf_keth_ruleq *rules;
+ struct pf_keth_ruleset *rs;
+
+ rs = pf_find_keth_ruleset(anchor);
+ if (rs == NULL) {
+ return (EINVAL);
+ }
- if (!V_pf_keth_inactive->open ||
- ticket != V_pf_keth_inactive->ticket)
+ if (!rs->inactive.open ||
+ ticket != rs->inactive.ticket)
return (EBUSY);
PF_RULES_WASSERT();
- pf_eth_calc_skip_steps(&V_pf_keth_inactive->rules);
+ pf_eth_calc_skip_steps(rs->inactive.rules);
- settings = V_pf_keth;
- ck_pr_store_ptr(&V_pf_keth, V_pf_keth_inactive);
- V_pf_keth_inactive = settings;
- V_pf_keth_inactive->ticket = V_pf_keth->ticket;
+ rules = rs->active.rules;
+ ck_pr_store_ptr(&rs->active.rules, rs->inactive.rules);
+ rs->inactive.rules = rules;
+ rs->inactive.ticket = rs->active.ticket;
/* Clean up inactive rules (i.e. previously active rules), only when
* we're sure they're no longer used. */
- NET_EPOCH_CALL(pf_rollback_eth_cb, &V_pf_keth_inactive->epoch_ctx);
+ NET_EPOCH_CALL(pf_rollback_eth_cb, &rs->epoch_ctx);
return (0);
}
@@ -2469,7 +2489,7 @@
int cpu;
hook_pf();
- if (! TAILQ_EMPTY(&V_pf_keth->rules))
+ if (! TAILQ_EMPTY(V_pf_keth->active.rules))
hook_pf_eth();
V_pf_status.running = 1;
V_pf_status.since = time_second;
@@ -2499,21 +2519,55 @@
nvlist_t *nvl;
void *packed;
struct pf_keth_rule *tail;
+ struct pf_keth_ruleset *rs;
u_int32_t ticket, nr;
+ const char *anchor = "";
nvl = NULL;
packed = NULL;
#define ERROUT(x) do { error = (x); goto DIOCGETETHRULES_error; } while (0)
+ if (nv->len > pf_ioctl_maxcount)
+ ERROUT(ENOMEM);
+
+ /* Copy the request in */
+ packed = malloc(nv->len, M_NVLIST, M_WAITOK);
+ if (packed == NULL)
+ ERROUT(ENOMEM);
+
+ error = copyin(nv->data, packed, nv->len);
+ if (error)
+ ERROUT(error);
+
+ nvl = nvlist_unpack(packed, nv->len, 0);
+ if (nvl == NULL)
+ ERROUT(EBADMSG);
+
+ if (! nvlist_exists_string(nvl, "anchor"))
+ ERROUT(EBADMSG);
+
+ anchor = nvlist_get_string(nvl, "anchor");
+
+ rs = pf_find_keth_ruleset(anchor);
+
+ nvlist_destroy(nvl);
+ nvl = NULL;
+ free(packed, M_NVLIST);
+ packed = NULL;
+
+ if (rs == NULL)
+ ERROUT(ENOENT);
+
+ /* Reply */
nvl = nvlist_create(0);
if (nvl == NULL)
ERROUT(ENOMEM);
PF_RULES_RLOCK();
- ticket = V_pf_keth->ticket;
- tail = TAILQ_LAST(&V_pf_keth->rules, pf_keth_rules);
+ ticket = rs->active.ticket;
+ tail = TAILQ_LAST(rs->active.rules, pf_keth_ruleq);
if (tail)
nr = tail->nr + 1;
else
@@ -2537,7 +2591,7 @@
#undef ERROUT
DIOCGETETHRULES_error:
- free(packed, M_TEMP);
+ free(packed, M_NVLIST);
nvlist_destroy(nvl);
break;
}
@@ -2548,8 +2602,10 @@
nvlist_t *nvl = NULL;
void *nvlpacked = NULL;
struct pf_keth_rule *rule = NULL;
+ struct pf_keth_ruleset *rs;
u_int32_t ticket, nr;
bool clear = false;
+ const char *anchor;
#define ERROUT(x) do { error = (x); goto DIOCGETETHRULE_error; } while (0)
@@ -2565,6 +2621,9 @@
if (! nvlist_exists_number(nvl, "ticket"))
ERROUT(EBADMSG);
ticket = nvlist_get_number(nvl, "ticket");
+ if (! nvlist_exists_string(nvl, "anchor"))
+ ERROUT(EBADMSG);
+ anchor = nvlist_get_string(nvl, "anchor");
if (nvlist_exists_bool(nvl, "clear")) {
clear = nvlist_get_bool(nvl, "clear");
@@ -2577,6 +2636,17 @@
ERROUT(EBADMSG);
nr = nvlist_get_number(nvl, "nr");
+ PF_RULES_RLOCK();
+ rs = pf_find_keth_ruleset(anchor);
+ if (rs == NULL) {
+ PF_RULES_RUNLOCK();
+ ERROUT(ENOENT);
+ }
+ if (ticket != rs->active.ticket) {
+ PF_RULES_RUNLOCK();
+ ERROUT(EBUSY);
+ }
+
nvlist_destroy(nvl);
nvl = NULL;
free(nvlpacked, M_TEMP);
@@ -2584,12 +2654,7 @@
nvl = nvlist_create(0);
- PF_RULES_RLOCK();
- if (ticket != V_pf_keth->ticket) {
- PF_RULES_RUNLOCK();
- ERROUT(EBUSY);
- }
- rule = TAILQ_FIRST(&V_pf_keth->rules);
+ rule = TAILQ_FIRST(rs->active.rules);
while ((rule != NULL) && (rule->nr != nr))
rule = TAILQ_NEXT(rule, entries);
if (rule == NULL) {
@@ -2600,6 +2665,8 @@
NET_EPOCH_ENTER(et);
PF_RULES_RUNLOCK();
nvl = pf_keth_rule_to_nveth_rule(rule);
+ if (pf_keth_anchor_nvcopyout(rs, rule, nvl))
+ ERROUT(EBUSY);
NET_EPOCH_EXIT(et);
if (nvl == NULL)
ERROUT(ENOMEM);
@@ -2633,8 +2700,10 @@
struct pfioc_nv *nv = (struct pfioc_nv *)addr;
nvlist_t *nvl = NULL;
void *nvlpacked = NULL;
- struct pf_keth_rule *rule = NULL;
+ struct pf_keth_rule *rule = NULL, *tail = NULL;
+ struct pf_keth_ruleset *ruleset = NULL;
struct pfi_kkif *kif = NULL;
+ const char *anchor = "", *anchor_call = "";
#define ERROUT(x) do { error = (x); goto DIOCADDETHRULE_error; } while (0)
@@ -2653,12 +2722,21 @@
if (! nvlist_exists_number(nvl, "ticket"))
ERROUT(EBADMSG);
+ if (nvlist_exists_string(nvl, "anchor"))
+ anchor = nvlist_get_string(nvl, "anchor");
+ if (nvlist_exists_string(nvl, "anchor_call"))
+ anchor_call = nvlist_get_string(nvl, "anchor_call");
+
+ ruleset = pf_find_keth_ruleset(anchor);
+ if (ruleset == NULL)
+ ERROUT(EINVAL);
+
if (nvlist_get_number(nvl, "ticket") !=
- V_pf_keth_inactive->ticket) {
+ ruleset->inactive.ticket) {
DPFPRINTF(PF_DEBUG_MISC,
("ticket: %d != %d\n",
(u_int32_t)nvlist_get_number(nvl, "ticket"),
- V_pf_keth_inactive->ticket));
+ ruleset->inactive.ticket));
ERROUT(EBUSY);
}
@@ -2705,7 +2783,19 @@
ERROUT(error);
}
- TAILQ_INSERT_TAIL(&V_pf_keth_inactive->rules, rule, entries);
+ if (pf_keth_anchor_setup(rule, ruleset, anchor_call)) {
+ pf_free_eth_rule(rule);
+ PF_RULES_WUNLOCK();
+ ERROUT(EINVAL);
+ }
+
+ tail = TAILQ_LAST(ruleset->inactive.rules, pf_keth_ruleq);
+ if (tail)
+ rule->nr = tail->nr + 1;
+ else
+ rule->nr = 0;
+
+ TAILQ_INSERT_TAIL(ruleset->inactive.rules, rule, entries);
PF_RULES_WUNLOCK();
@@ -4757,13 +4847,7 @@
ioe->anchor[sizeof(ioe->anchor) - 1] = '\0';
switch (ioe->rs_num) {
case PF_RULESET_ETH:
- if (ioe->anchor[0]) {
- PF_RULES_WUNLOCK();
- free(ioes, M_TEMP);
- error = EINVAL;
- goto fail;
- }
- if ((error = pf_begin_eth(&ioe->ticket))) {
+ if ((error = pf_begin_eth(&ioe->ticket, ioe->anchor))) {
PF_RULES_WUNLOCK();
free(ioes, M_TEMP);
goto fail;
@@ -4844,13 +4928,8 @@
ioe->anchor[sizeof(ioe->anchor) - 1] = '\0';
switch (ioe->rs_num) {
case PF_RULESET_ETH:
- if (ioe->anchor[0]) {
- PF_RULES_WUNLOCK();
- free(ioes, M_TEMP);
- error = EINVAL;
- goto fail;
- }
- if ((error = pf_rollback_eth(ioe->ticket))) {
+ if ((error = pf_rollback_eth(ioe->ticket,
+ ioe->anchor))) {
PF_RULES_WUNLOCK();
free(ioes, M_TEMP);
goto fail; /* really bad */
@@ -4905,6 +4984,7 @@
struct pfioc_trans *io = (struct pfioc_trans *)addr;
struct pfioc_trans_e *ioe, *ioes;
struct pf_kruleset *rs;
+ struct pf_keth_ruleset *ers;
size_t totlen;
int i;
@@ -4934,19 +5014,14 @@
ioe->anchor[sizeof(ioe->anchor) - 1] = 0;
switch (ioe->rs_num) {
case PF_RULESET_ETH:
- if (ioe->anchor[0]) {
+ ers = pf_find_keth_ruleset(ioe->anchor);
+ if (ers == NULL || ioe->ticket == 0 ||
+ ioe->ticket != ers->inactive.ticket) {
PF_RULES_WUNLOCK();
free(ioes, M_TEMP);
error = EINVAL;
goto fail;
}
- if (!V_pf_keth_inactive->ticket ||
- ioe->ticket != V_pf_keth_inactive->ticket) {
- PF_RULES_WUNLOCK();
- free(ioes, M_TEMP);
- error = EBUSY;
- goto fail;
- }
break;
#ifdef ALTQ
case PF_RULESET_ALTQ:
@@ -5000,7 +5075,7 @@
for (i = 0, ioe = ioes; i < io->size; i++, ioe++) {
switch (ioe->rs_num) {
case PF_RULESET_ETH:
- if ((error = pf_commit_eth(ioe->ticket))) {
+ if ((error = pf_commit_eth(ioe->ticket, ioe->anchor))) {
PF_RULES_WUNLOCK();
free(ioes, M_TEMP);
goto fail; /* really bad */
@@ -5043,7 +5118,7 @@
PF_RULES_WUNLOCK();
/* Only hook into EtherNet taffic if we've got rules for it. */
- if (! TAILQ_EMPTY(&V_pf_keth->rules))
+ if (! TAILQ_EMPTY(V_pf_keth->active.rules))
hook_pf_eth();
else
dehook_pf_eth();
@@ -5951,11 +6026,11 @@
if ((error = pf_clear_tables()) != 0)
break;
- if ((error = pf_begin_eth(&t[0])) != 0) {
+ if ((error = pf_begin_eth(&t[0], &nn)) != 0) {
DPFPRINTF(PF_DEBUG_MISC, ("shutdown_pf: eth\n"));
break;
}
- pf_commit_eth(t[0]);
+ pf_commit_eth(t[0], &nn);
#ifdef ALTQ
if ((error = pf_begin_altq(&t[0])) != 0) {
@@ -6239,9 +6314,7 @@
PF_QUEUE_TAG_HASH_SIZE_DEFAULT);
#endif
- V_pf_keth = malloc(sizeof(*V_pf_keth), M_PFRULE, M_WAITOK);
- V_pf_keth_inactive = malloc(sizeof(*V_pf_keth_inactive),
- M_PFRULE, M_WAITOK);
+ V_pf_keth = &V_pf_main_keth_anchor.ruleset;
pfattach_vnet();
V_pf_vnet_active = 1;
@@ -6353,9 +6426,6 @@
pf_counter_u64_deinit(&V_pf_status.fcounters[i]);
for (int i = 0; i < SCNT_MAX; i++)
counter_u64_free(V_pf_status.scounters[i]);
-
- free(V_pf_keth, M_PFRULE);
- free(V_pf_keth_inactive, M_PFRULE);
}
static void
Index: sys/netpfil/pf/pf_nv.c
===================================================================
--- sys/netpfil/pf/pf_nv.c
+++ sys/netpfil/pf/pf_nv.c
@@ -1067,6 +1067,9 @@
nvlist_add_number(nvl, "dnpipe", krule->dnpipe);
nvlist_add_number(nvl, "dnflags", krule->dnflags);
+ nvlist_add_number(nvl, "anchor_relative", krule->anchor_relative);
+ nvlist_add_number(nvl, "anchor_wildcard", krule->anchor_wildcard);
+
nvlist_add_number(nvl, "action", krule->action);
return (nvl);
Index: sys/netpfil/pf/pf_ruleset.c
===================================================================
--- sys/netpfil/pf/pf_ruleset.c
+++ sys/netpfil/pf/pf_ruleset.c
@@ -70,15 +70,22 @@
VNET_DEFINE(struct pf_kanchor_global, pf_anchors);
VNET_DEFINE(struct pf_kanchor, pf_main_anchor);
-VNET_DEFINE(struct pf_keth_settings*, pf_keth);
-VNET_DEFINE(struct pf_keth_settings*, pf_keth_inactive);
+VNET_DEFINE(struct pf_keth_ruleset*, pf_keth);
+VNET_DEFINE(struct pf_keth_anchor, pf_main_keth_anchor);
+VNET_DEFINE(struct pf_keth_anchor_global, pf_keth_anchors);
static __inline int pf_kanchor_compare(struct pf_kanchor *,
struct pf_kanchor *);
+static __inline int pf_keth_anchor_compare(struct pf_keth_anchor *,
+ struct pf_keth_anchor *);
static struct pf_kanchor *pf_find_kanchor(const char *);
RB_GENERATE(pf_kanchor_global, pf_kanchor, entry_global, pf_kanchor_compare);
RB_GENERATE(pf_kanchor_node, pf_kanchor, entry_node, pf_kanchor_compare);
+RB_GENERATE(pf_keth_anchor_global, pf_keth_anchor, entry_global,
+ pf_keth_anchor_compare);
+RB_GENERATE(pf_keth_anchor_node, pf_keth_anchor, entry_node,
+ pf_keth_anchor_compare);
static __inline int
pf_kanchor_compare(struct pf_kanchor *a, struct pf_kanchor *b)
@@ -88,6 +95,14 @@
return (c ? (c < 0 ? -1 : 1) : 0);
}
+static __inline int
+pf_keth_anchor_compare(struct pf_keth_anchor *a, struct pf_keth_anchor *b)
+{
+ int c = strcmp(a->path, b->path);
+
+ return (c ? (c < 0 ? -1 : 1) : 0);
+}
+
int
pf_get_ruleset_number(u_int8_t action)
{
@@ -148,13 +163,18 @@
}
void
-pf_init_keth(struct pf_keth_settings *settings)
+pf_init_keth(struct pf_keth_ruleset *rs)
{
- TAILQ_INIT(&settings->rules);
- settings->ticket = 0;
- settings->open = 0;
- settings->vnet = curvnet;
+ bzero(rs, sizeof(*rs));
+ TAILQ_INIT(&rs->rules[0]);
+ TAILQ_INIT(&rs->rules[1]);
+ rs->active.rules = &rs->rules[0];
+ rs->active.open = 0;
+ rs->inactive.rules = &rs->rules[1];
+ rs->inactive.open = 0;
+
+ rs->vnet = curvnet;
}
struct pf_kruleset *
@@ -396,6 +416,53 @@
return (0);
}
+int
+pf_keth_anchor_nvcopyout(const struct pf_keth_ruleset *rs,
+ const struct pf_keth_rule *r, nvlist_t *nvl)
+{
+ char anchor_call[MAXPATHLEN] = { 0 };
+
+ if (r->anchor == NULL)
+ goto done;
+ if (!r->anchor_relative) {
+ strlcpy(anchor_call, "/", sizeof(anchor_call));
+ strlcat(anchor_call, r->anchor->path,
+ sizeof(anchor_call));
+ } else {
+ char a[MAXPATHLEN];
+ char *p;
+ int i;
+ if (rs->anchor == NULL)
+ a[0] = 0;
+ else
+ strlcpy(a, rs->anchor->path, MAXPATHLEN);
+ for (i = 1; i < r->anchor_relative; ++i) {
+ if ((p = strrchr(a, '/')) == NULL)
+ p = a;
+ *p = 0;
+ strlcat(anchor_call, "../",
+ sizeof(anchor_call));
+ }
+ if (strncmp(a, r->anchor->path, strlen(a))) {
+ printf("%s(): '%s' '%s'\n", __func__, a,
+ r->anchor->path);
+ return (1);
+ }
+ if (strlen(r->anchor->path) > strlen(a))
+ strlcat(anchor_call, r->anchor->path + (a[0] ?
+ strlen(a) + 1 : 0), sizeof(anchor_call));
+
+ }
+ if (r->anchor_wildcard)
+ strlcat(anchor_call, anchor_call[0] ? "/*" : "*",
+ sizeof(anchor_call));
+
+done:
+ nvlist_add_string(nvl, "anchor_call", anchor_call);
+
+ return (0);
+}
+
int
pf_kanchor_copyout(const struct pf_kruleset *rs, const struct pf_krule *r,
struct pfioc_rule *pr)
@@ -456,3 +523,229 @@
pf_remove_if_empty_kruleset(&r->anchor->ruleset);
r->anchor = NULL;
}
+
+struct pf_keth_ruleset *
+pf_find_keth_ruleset(const char *path)
+{
+ struct pf_keth_anchor *anchor;
+
+ while (*path == '/')
+ path++;
+ if (!*path)
+ return (V_pf_keth);
+ anchor = pf_find_keth_anchor(path);
+ if (anchor == NULL)
+ return (NULL);
+ else
+ return (&anchor->ruleset);
+}
+
+static struct pf_keth_anchor *
+_pf_find_keth_anchor(struct pf_keth_ruleset *rs, const char *path)
+{
+ struct pf_keth_anchor *key, *found;
+
+ key = (struct pf_keth_anchor *)rs_malloc(sizeof(*key));
+ if (key == NULL)
+ return (NULL);
+ strlcpy(key->path, path, sizeof(key->path));
+ found = RB_FIND(pf_keth_anchor_global, &V_pf_keth_anchors, key);
+ rs_free(key);
+ return (found);
+}
+
+struct pf_keth_anchor *
+pf_find_keth_anchor(const char *path)
+{
+ return (_pf_find_keth_anchor(V_pf_keth, path));
+}
+
+struct pf_keth_ruleset *
+pf_find_or_create_keth_ruleset(const char *path)
+{
+ char *p, *q, *r;
+ struct pf_keth_anchor *anchor = NULL, *dup = NULL, *parent = NULL;
+ struct pf_keth_ruleset *ruleset;
+
+ if (path[0] == 0)
+ return (V_pf_keth);
+ while (*path == '/')
+ path++;
+ ruleset = pf_find_keth_ruleset(path);
+ if (ruleset != NULL)
+ return (ruleset);
+ p = (char *)rs_malloc(MAXPATHLEN);
+ if (p == NULL)
+ return (NULL);
+ strlcpy(p, path, MAXPATHLEN);
+ while (parent == NULL && (q = strrchr(p, '/')) != NULL) {
+ *q = 0;
+ if ((ruleset = pf_find_keth_ruleset(p)) != NULL) {
+ parent = ruleset->anchor;
+ break;
+ }
+ }
+ if (q == NULL)
+ q = p;
+ else
+ q++;
+ strlcpy(p, path, MAXPATHLEN);
+ if (!*q) {
+ rs_free(p);
+ return (NULL);
+ }
+ while ((r = strchr(q, '/')) != NULL || *q) {
+ if (r != NULL)
+ *r = 0;
+ if (!*q || strlen(q) >= PF_ANCHOR_NAME_SIZE ||
+ (parent != NULL && strlen(parent->path) >=
+ MAXPATHLEN - PF_ANCHOR_NAME_SIZE - 1)) {
+ rs_free(p);
+ return (NULL);
+ }
+ anchor = (struct pf_keth_anchor *)rs_malloc(sizeof(*anchor));
+ if (anchor == NULL) {
+ rs_free(p);
+ return (NULL);
+ }
+ RB_INIT(&anchor->children);
+ strlcpy(anchor->name, q, sizeof(anchor->name));
+ if (parent != NULL) {
+ strlcpy(anchor->path, parent->path,
+ sizeof(anchor->path));
+ strlcat(anchor->path, "/", sizeof(anchor->path));
+ }
+ strlcat(anchor->path, anchor->name, sizeof(anchor->path));
+ if ((dup = RB_INSERT(pf_keth_anchor_global, &V_pf_keth_anchors, anchor)) !=
+ NULL) {
+ printf("%s: RB_INSERT1 "
+ "'%s' '%s' collides with '%s' '%s'\n", __func__,
+ anchor->path, anchor->name, dup->path, dup->name);
+ rs_free(anchor);
+ rs_free(p);
+ return (NULL);
+ }
+ if (parent != NULL) {
+ anchor->parent = parent;
+ if ((dup = RB_INSERT(pf_keth_anchor_node, &parent->children,
+ anchor)) != NULL) {
+ printf("%s: "
+ "RB_INSERT2 '%s' '%s' collides with "
+ "'%s' '%s'\n", __func__, anchor->path,
+ anchor->name, dup->path, dup->name);
+ RB_REMOVE(pf_keth_anchor_global, &V_pf_keth_anchors,
+ anchor);
+ rs_free(anchor);
+ rs_free(p);
+ return (NULL);
+ }
+ }
+ pf_init_keth(&anchor->ruleset);
+ anchor->ruleset.anchor = anchor;
+ parent = anchor;
+ if (r != NULL)
+ q = r + 1;
+ else
+ *q = 0;
+ }
+ rs_free(p);
+ return (&anchor->ruleset);
+}
+
+int
+pf_keth_anchor_setup(struct pf_keth_rule *r, const struct pf_keth_ruleset *s,
+ const char *name)
+{
+ char *p, *path;
+ struct pf_keth_ruleset *ruleset;
+
+ r->anchor = NULL;
+ r->anchor_relative = 0;
+ r->anchor_wildcard = 0;
+ if (!name[0])
+ return (0);
+ path = (char *)rs_malloc(MAXPATHLEN);
+ if (path == NULL)
+ return (1);
+ if (name[0] == '/')
+ strlcpy(path, name + 1, MAXPATHLEN);
+ else {
+ /* relative path */
+ r->anchor_relative = 1;
+ if (s->anchor == NULL || !s->anchor->path[0])
+ path[0] = 0;
+ else
+ strlcpy(path, s->anchor->path, MAXPATHLEN);
+ while (name[0] == '.' && name[1] == '.' && name[2] == '/') {
+ if (!path[0]) {
+ DPFPRINTF("pf_anchor_setup: .. beyond root\n");
+ rs_free(path);
+ return (1);
+ }
+ if ((p = strrchr(path, '/')) != NULL)
+ *p = 0;
+ else
+ path[0] = 0;
+ r->anchor_relative++;
+ name += 3;
+ }
+ if (path[0])
+ strlcat(path, "/", MAXPATHLEN);
+ strlcat(path, name, MAXPATHLEN);
+ }
+ if ((p = strrchr(path, '/')) != NULL && !strcmp(p, "/*")) {
+ r->anchor_wildcard = 1;
+ *p = 0;
+ }
+ ruleset = pf_find_or_create_keth_ruleset(path);
+ rs_free(path);
+ if (ruleset == NULL || ruleset->anchor == NULL) {
+ DPFPRINTF("pf_anchor_setup: ruleset\n");
+ return (1);
+ }
+ r->anchor = ruleset->anchor;
+ r->anchor->refcnt++;
+ return (0);
+}
+
+void
+pf_keth_anchor_remove(struct pf_keth_rule *r)
+{
+ if (r->anchor == NULL)
+ return;
+ if (r->anchor->refcnt <= 0) {
+ printf("%s: broken refcount\n", __func__);
+ r->anchor = NULL;
+ return;
+ }
+ if (!--r->anchor->refcnt)
+ pf_remove_if_empty_keth_ruleset(&r->anchor->ruleset);
+ r->anchor = NULL;
+}
+
+void
+pf_remove_if_empty_keth_ruleset(struct pf_keth_ruleset *ruleset)
+{
+ struct pf_keth_anchor *parent;
+ int i;
+
+ while (ruleset != NULL) {
+ if (ruleset == V_pf_keth || ruleset->anchor == NULL ||
+ !RB_EMPTY(&ruleset->anchor->children) ||
+ ruleset->anchor->refcnt > 0)
+ return;
+ for (i = 0; i < PF_RULESET_MAX; ++i)
+ if (!TAILQ_EMPTY(ruleset->active.rules) ||
+ !TAILQ_EMPTY(ruleset->inactive.rules) ||
+ ruleset->inactive.open)
+ return;
+ RB_REMOVE(pf_keth_anchor_global, &V_pf_keth_anchors, ruleset->anchor);
+ if ((parent = ruleset->anchor->parent) != NULL)
+ RB_REMOVE(pf_keth_anchor_node, &parent->children,
+ ruleset->anchor);
+ rs_free(ruleset->anchor);
+ if (parent == NULL)
+ return;
+ ruleset = &parent->ruleset;
+ }
+}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Wed, Jun 24, 11:23 AM (11 h, 58 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
34281604
Default Alt Text
D32482.id96826.diff (59 KB)
Attached To
Mode
D32482: pf: add anchor support for ether rules
Attached
Detach File
Event Timeline
Log In to Comment