Page MenuHomeFreeBSD

D32482.id96826.diff
No OneTemporary

D32482.id96826.diff

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

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)

Event Timeline