mirror of
https://github.com/opnsense/src.git
synced 2026-04-15 14:29:58 -04:00
pf: add anchor support for ether rules
Support anchors in ether rules.
Sponsored by: Rubicon Communications, LLC ("Netgate")
Differential Revision: https://reviews.freebsd.org/D32482
This commit is contained in:
parent
87a89d6e14
commit
c5131afee3
13 changed files with 1247 additions and 167 deletions
|
|
@ -606,20 +606,34 @@ pfctl_nveth_rule_to_eth_rule(const nvlist_t *nvl, struct pfctl_eth_rule *rule)
|
|||
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);
|
||||
|
|
@ -637,7 +651,8 @@ pfctl_get_eth_rules_info(int dev, struct pfctl_eth_rules_info *rules)
|
|||
|
||||
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;
|
||||
|
|
@ -647,6 +662,7 @@ pfctl_get_eth_rule(int dev, uint32_t nr, uint32_t ticket,
|
|||
|
||||
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);
|
||||
|
|
@ -670,12 +686,17 @@ pfctl_get_eth_rule(int dev, uint32_t nr, uint32_t ticket,
|
|||
|
||||
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;
|
||||
|
|
@ -686,6 +707,8 @@ pfctl_add_eth_rule(int dev, const struct pfctl_eth_rule *r, uint32_t ticket)
|
|||
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);
|
||||
|
|
|
|||
|
|
@ -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 @@ struct pfctl_eth_rule {
|
|||
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;
|
||||
|
|
@ -331,11 +349,13 @@ struct pfctl_syncookies {
|
|||
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, uint32_t nr, uint32_t ticket,
|
||||
const char *anchor, uint32_t ruleset, struct pfctl_rule *rule,
|
||||
char *anchor_call);
|
||||
|
|
|
|||
|
|
@ -350,7 +350,7 @@ void expand_label_nr(const char *, char *, size_t,
|
|||
struct pfctl_rule *);
|
||||
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 rule_label(struct pfctl_rule *, char *s[PF_RULE_MAX_LABEL_COUNT]);
|
|||
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 : /* empty */
|
|||
| ruleset '\n'
|
||||
| ruleset option '\n'
|
||||
| ruleset etherrule '\n'
|
||||
| ruleset etheranchorrule '\n'
|
||||
| ruleset scrubrule '\n'
|
||||
| ruleset natrule '\n'
|
||||
| ruleset binatrule '\n'
|
||||
|
|
@ -1196,7 +1198,95 @@ etherrule : ETHER action dir quick interface etherproto etherfromto etherfilter_
|
|||
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;
|
||||
}
|
||||
;
|
||||
|
||||
|
|
@ -5640,15 +5730,12 @@ expand_queue(struct pf_altq *a, struct node_if *interfaces,
|
|||
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;
|
||||
|
|
@ -5657,12 +5744,9 @@ expand_eth_rule(struct pfctl_eth_rule *r,
|
|||
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);
|
||||
|
|
@ -6525,6 +6609,19 @@ mv_rules(struct pfctl_ruleset *src, struct pfctl_ruleset *dst)
|
|||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -65,6 +65,7 @@ __FBSDID("$FreeBSD$");
|
|||
#define rs_free(x) free(x)
|
||||
|
||||
#include "pfctl.h"
|
||||
#include "pfctl_parser.h"
|
||||
|
||||
#ifdef PFDEBUG
|
||||
#include <sys/stdarg.h>
|
||||
|
|
@ -74,7 +75,8 @@ __FBSDID("$FreeBSD$");
|
|||
#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 @@ pf_remove_if_empty_ruleset(struct pfctl_ruleset *ruleset)
|
|||
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 @@ pfctl_anchor_setup(struct pfctl_rule *r, const struct pfctl_ruleset *s,
|
|||
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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -98,7 +98,7 @@ int pfctl_get_pool(int, struct pfctl_pool *, u_int32_t, u_int32_t, int,
|
|||
char *);
|
||||
void pfctl_print_eth_rule_counters(struct pfctl_eth_rule *, int);
|
||||
void pfctl_print_rule_counters(struct pfctl_rule *, int);
|
||||
int pfctl_show_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 @@ int pfctl_show_limits(int, int);
|
|||
void pfctl_debug(int, u_int32_t, int);
|
||||
int pfctl_test_altqsupport(int, int);
|
||||
int pfctl_show_anchors(int, int, char *);
|
||||
int pfctl_ruleset_trans(struct pfctl *, char *, struct pfctl_anchor *);
|
||||
int pfctl_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 @@ pfctl_print_title(char *title)
|
|||
}
|
||||
|
||||
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 (pfctl_get_eth_rules_info(dev, &info)) {
|
||||
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, 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 @@ pfctl_append_rule(struct pfctl *pf, struct pfctl_rule *r,
|
|||
}
|
||||
|
||||
int
|
||||
pfctl_ruleset_trans(struct pfctl *pf, char *path, struct pfctl_anchor *a)
|
||||
pfctl_append_eth_rule(struct pfctl *pf, struct pfctl_eth_rule *r,
|
||||
const char *anchor_call)
|
||||
{
|
||||
struct pfctl_eth_rule *rule;
|
||||
struct pfctl_eth_ruleset *rs;
|
||||
char *p;
|
||||
|
||||
rs = &pf->eanchor->ruleset;
|
||||
|
||||
if (anchor_call[0] && r->anchor == NULL) {
|
||||
/*
|
||||
* Don't make non-brace anchors part of the main anchor pool.
|
||||
*/
|
||||
if ((r->anchor = calloc(1, sizeof(*r->anchor))) == NULL)
|
||||
err(1, "pfctl_append_rule: calloc");
|
||||
|
||||
pf_init_eth_ruleset(&r->anchor->ruleset);
|
||||
r->anchor->ruleset.anchor = r->anchor;
|
||||
if (strlcpy(r->anchor->path, anchor_call,
|
||||
sizeof(rule->anchor->path)) >= sizeof(rule->anchor->path))
|
||||
errx(1, "pfctl_append_rule: strlcpy");
|
||||
if ((p = strrchr(anchor_call, '/')) != NULL) {
|
||||
if (!strlen(p))
|
||||
err(1, "pfctl_append_eth_rule: bad anchor name %s",
|
||||
anchor_call);
|
||||
} else
|
||||
p = (char *)anchor_call;
|
||||
if (strlcpy(r->anchor->name, p,
|
||||
sizeof(rule->anchor->name)) >= sizeof(rule->anchor->name))
|
||||
errx(1, "pfctl_append_eth_rule: strlcpy");
|
||||
}
|
||||
|
||||
if ((rule = calloc(1, sizeof(*rule))) == NULL)
|
||||
err(1, "calloc");
|
||||
bcopy(r, rule, sizeof(*rule));
|
||||
|
||||
TAILQ_INSERT_TAIL(&rs->rules, rule, entries);
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
pfctl_eth_ruleset_trans(struct pfctl *pf, char *path,
|
||||
struct pfctl_eth_anchor *a)
|
||||
{
|
||||
int osize = pf->trans->pfrb_size;
|
||||
|
||||
if ((pf->loadopt & PFCTL_FLAG_ETH) != 0) {
|
||||
if (! 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,22 +1640,92 @@ pfctl_ruleset_trans(struct pfctl *pf, char *path, struct pfctl_anchor *a)
|
|||
}
|
||||
|
||||
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;
|
||||
|
||||
while ((r = TAILQ_FIRST(&pf->eth_rules)) != NULL) {
|
||||
TAILQ_REMOVE(&pf->eth_rules, r, entries);
|
||||
pf->eanchor = rs->anchor;
|
||||
if (path[0])
|
||||
snprintf(&path[len], MAXPATHLEN - len, "/%s", pf->eanchor->name);
|
||||
else
|
||||
snprintf(&path[len], MAXPATHLEN - len, "%s", pf->eanchor->name);
|
||||
|
||||
if ((pf->opts & PF_OPT_NOACTION) == 0) {
|
||||
error = pfctl_add_eth_rule(pf->dev, r, pf->eth_ticket);
|
||||
if (error)
|
||||
if (depth) {
|
||||
if (TAILQ_FIRST(&rs->rules) != NULL) {
|
||||
brace++;
|
||||
if (pf->opts & PF_OPT_VERBOSE)
|
||||
printf(" {\n");
|
||||
if ((pf->opts & PF_OPT_NOACTION) == 0 &&
|
||||
(error = pfctl_eth_ruleset_trans(pf,
|
||||
path, rs->anchor))) {
|
||||
printf("pfctl_load_eth_rulesets: "
|
||||
"pfctl_eth_ruleset_trans %d\n", error);
|
||||
goto error;
|
||||
}
|
||||
} else if (pf->opts & PF_OPT_VERBOSE)
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
while ((r = TAILQ_FIRST(&rs->rules)) != NULL) {
|
||||
TAILQ_REMOVE(&rs->rules, r, entries);
|
||||
|
||||
error = pfctl_load_eth_rule(pf, path, r, depth);
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
if (r->anchor) {
|
||||
if ((error = pfctl_load_eth_ruleset(pf, path,
|
||||
&r->anchor->ruleset, depth + 1)))
|
||||
return (error);
|
||||
}
|
||||
|
||||
free(r);
|
||||
}
|
||||
if (brace && pf->opts & PF_OPT_VERBOSE) {
|
||||
INDENT(depth - 1, (pf->opts & PF_OPT_VERBOSE));
|
||||
printf("}\n");
|
||||
}
|
||||
path[len] = '\0';
|
||||
|
||||
return (0);
|
||||
error:
|
||||
path[len] = '\0';
|
||||
return (error);
|
||||
}
|
||||
|
||||
int
|
||||
pfctl_load_eth_rule(struct pfctl *pf, char *path, struct pfctl_eth_rule *r,
|
||||
int depth)
|
||||
{
|
||||
char *name;
|
||||
char anchor[PF_ANCHOR_NAME_SIZE];
|
||||
int len = strlen(path);
|
||||
|
||||
if (strlcpy(anchor, path, sizeof(anchor)) >= sizeof(anchor))
|
||||
errx(1, "pfctl_load_eth_rule: strlcpy");
|
||||
|
||||
if (r->anchor) {
|
||||
if (r->anchor->match) {
|
||||
if (path[0])
|
||||
snprintf(&path[len], MAXPATHLEN - len,
|
||||
"/%s", r->anchor->name);
|
||||
else
|
||||
snprintf(&path[len], MAXPATHLEN - len,
|
||||
"%s", r->anchor->name);
|
||||
name = r->anchor->name;
|
||||
} else
|
||||
name = r->anchor->path;
|
||||
} else
|
||||
name = "";
|
||||
|
||||
if ((pf->opts & PF_OPT_NOACTION) == 0)
|
||||
if (pfctl_add_eth_rule(pf->dev, r, anchor, name,
|
||||
pf->eth_ticket))
|
||||
err(1, "DIOCADDETHRULENV");
|
||||
|
||||
path[len] = '\0';
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
|
@ -1586,7 +1752,7 @@ pfctl_load_ruleset(struct pfctl *pf, char *path, struct pfctl_ruleset *rs,
|
|||
printf(" {\n");
|
||||
if ((pf->opts & PF_OPT_NOACTION) == 0 &&
|
||||
(error = pfctl_ruleset_trans(pf,
|
||||
path, rs->anchor))) {
|
||||
path, rs->anchor, false))) {
|
||||
printf("pfctl_load_rulesets: "
|
||||
"pfctl_ruleset_trans %d\n", error);
|
||||
goto error;
|
||||
|
|
@ -1711,6 +1877,7 @@ pfctl_rules(int dev, char *filename, int opts, int optimize,
|
|||
struct pfioc_altq pa;
|
||||
struct pfctl pf;
|
||||
struct pfctl_ruleset *rs;
|
||||
struct pfctl_eth_ruleset *ethrs;
|
||||
struct pfr_table trs;
|
||||
char *path;
|
||||
int osize;
|
||||
|
|
@ -1719,6 +1886,11 @@ pfctl_rules(int dev, char *filename, int opts, int optimize,
|
|||
memset(&pf_main_anchor, 0, sizeof(pf_main_anchor));
|
||||
pf_init_ruleset(&pf_main_anchor.ruleset);
|
||||
pf_main_anchor.ruleset.anchor = &pf_main_anchor;
|
||||
|
||||
memset(&pf_eth_main_anchor, 0, sizeof(pf_eth_main_anchor));
|
||||
pf_init_eth_ruleset(&pf_eth_main_anchor.ruleset);
|
||||
pf_eth_main_anchor.ruleset.anchor = &pf_eth_main_anchor;
|
||||
|
||||
if (trans == NULL) {
|
||||
bzero(&buf, sizeof(buf));
|
||||
buf.pfrb_type = PFRB_TRANS;
|
||||
|
|
@ -1742,7 +1914,6 @@ pfctl_rules(int dev, char *filename, int opts, int optimize,
|
|||
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)
|
||||
|
|
@ -1752,10 +1923,10 @@ pfctl_rules(int dev, char *filename, int opts, int optimize,
|
|||
rs->anchor = pf.anchor;
|
||||
if (strlcpy(pf.anchor->path, anchorname,
|
||||
sizeof(pf.anchor->path)) >= sizeof(pf.anchor->path))
|
||||
errx(1, "pfctl_add_rule: strlcpy");
|
||||
errx(1, "pfctl_rules: strlcpy");
|
||||
if (strlcpy(pf.anchor->name, anchorname,
|
||||
sizeof(pf.anchor->name)) >= sizeof(pf.anchor->name))
|
||||
errx(1, "pfctl_add_rule: strlcpy");
|
||||
errx(1, "pfctl_rules: strlcpy");
|
||||
|
||||
|
||||
pf.astack[0] = pf.anchor;
|
||||
|
|
@ -1766,13 +1937,29 @@ pfctl_rules(int dev, char *filename, int opts, int optimize,
|
|||
pf.trans = t;
|
||||
pfctl_init_options(&pf);
|
||||
|
||||
/* Set up ethernet anchor */
|
||||
if ((pf.eanchor = calloc(1, sizeof(*pf.eanchor))) == NULL)
|
||||
ERRX("pfctl_rules: calloc");
|
||||
|
||||
if (strlcpy(pf.eanchor->path, anchorname,
|
||||
sizeof(pf.eanchor->path)) >= sizeof(pf.eanchor->path))
|
||||
errx(1, "pfctl_rules: strlcpy");
|
||||
if (strlcpy(pf.eanchor->name, anchorname,
|
||||
sizeof(pf.eanchor->name)) >= sizeof(pf.eanchor->name))
|
||||
errx(1, "pfctl_rules: strlcpy");
|
||||
|
||||
ethrs = &pf.eanchor->ruleset;
|
||||
pf_init_eth_ruleset(ethrs);
|
||||
ethrs->anchor = pf.eanchor;
|
||||
pf.eastack[0] = pf.eanchor;
|
||||
|
||||
if ((opts & PF_OPT_NOACTION) == 0) {
|
||||
/*
|
||||
* XXX For the time being we need to open transactions for
|
||||
* the main ruleset before parsing, because tables are still
|
||||
* loaded at parse time.
|
||||
*/
|
||||
if (pfctl_ruleset_trans(&pf, anchorname, pf.anchor))
|
||||
if (pfctl_ruleset_trans(&pf, anchorname, pf.anchor, true))
|
||||
ERRX("pfctl_rules");
|
||||
if (pf.loadopt & PFCTL_FLAG_ETH)
|
||||
pf.eth_ticket = pfctl_get_ticket(t, PF_RULESET_ETH, anchorname);
|
||||
|
|
@ -1797,7 +1984,7 @@ pfctl_rules(int dev, char *filename, int opts, int optimize,
|
|||
if ((pf.loadopt & PFCTL_FLAG_FILTER &&
|
||||
(pfctl_load_ruleset(&pf, path, rs, PF_RULESET_SCRUB, 0))) ||
|
||||
(pf.loadopt & PFCTL_FLAG_ETH &&
|
||||
(pfctl_load_eth_ruleset(&pf))) ||
|
||||
(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) ||
|
||||
|
|
@ -2572,7 +2759,7 @@ main(int argc, char *argv[])
|
|||
sizeof(anchorname)) >= sizeof(anchorname))
|
||||
errx(1, "anchor name '%s' too long",
|
||||
anchoropt);
|
||||
loadopt &= PFCTL_FLAG_FILTER|PFCTL_FLAG_NAT|PFCTL_FLAG_TABLE;
|
||||
loadopt &= PFCTL_FLAG_FILTER|PFCTL_FLAG_NAT|PFCTL_FLAG_TABLE|PFCTL_FLAG_ETH;
|
||||
}
|
||||
|
||||
if ((opts & PF_OPT_NOACTION) == 0) {
|
||||
|
|
@ -2640,13 +2827,13 @@ main(int argc, char *argv[])
|
|||
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);
|
||||
|
|
@ -2674,7 +2861,8 @@ main(int argc, char *argv[])
|
|||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 @@ int pfctl_anchor_setup(struct pfctl_rule *,
|
|||
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 *);
|
||||
|
||||
void expand_label(char *, size_t, struct pfctl_rule *);
|
||||
|
||||
|
|
|
|||
|
|
@ -710,14 +710,23 @@ print_eth_addr(const struct pfctl_eth_addr *a)
|
|||
}
|
||||
|
||||
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)
|
||||
|
|
|
|||
|
|
@ -91,7 +91,8 @@ struct pfctl {
|
|||
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_rules(int, char *, int, int, char *, struct pfr_buffer *);
|
|||
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 @@ int pfctl_load_anchors(int, struct pfctl *, struct pfr_buffer *);
|
|||
|
||||
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);
|
||||
|
|
|
|||
|
|
@ -583,6 +583,41 @@ struct pf_keth_rule_addr {
|
|||
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
|
||||
|
|
@ -594,6 +629,10 @@ struct pf_keth_rule {
|
|||
|
||||
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;
|
||||
|
|
@ -621,16 +660,6 @@ struct pf_keth_rule {
|
|||
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;
|
||||
|
|
@ -1151,6 +1180,7 @@ RB_PROTOTYPE(pf_kanchor_node, pf_kanchor, entry_node, pf_kanchor_compare);
|
|||
PFR_TFLAG_COUNTERS)
|
||||
|
||||
struct pf_kanchor_stackframe;
|
||||
struct pf_keth_anchor_stackframe;
|
||||
|
||||
struct pfr_table {
|
||||
char pfrt_anchor[MAXPATHLEN];
|
||||
|
|
@ -2206,15 +2236,17 @@ VNET_DECLARE(struct pf_kanchor_global, pf_anchors);
|
|||
#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 *,
|
||||
|
|
@ -2227,7 +2259,21 @@ struct pf_kruleset *pf_find_kruleset(const char *);
|
|||
struct pf_kruleset *pf_find_or_create_kruleset(const char *);
|
||||
void pf_rs_initialize(void);
|
||||
|
||||
|
||||
struct pf_krule *pf_krule_alloc(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
|
||||
|
||||
|
|
@ -2251,6 +2297,14 @@ void pf_step_into_anchor(struct pf_kanchor_stackframe *, int *,
|
|||
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 *,
|
||||
|
|
|
|||
|
|
@ -3404,6 +3404,110 @@ pf_step_out_of_anchor(struct pf_kanchor_stackframe *stack, int *depth,
|
|||
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,
|
||||
|
|
@ -3719,10 +3823,13 @@ static int
|
|||
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();
|
||||
|
||||
|
|
@ -3733,8 +3840,9 @@ pf_test_eth_rule(int dir, struct pfi_kkif *kif, struct mbuf *m)
|
|||
|
||||
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) {
|
||||
|
|
@ -3767,16 +3875,24 @@ pf_test_eth_rule(int dir, struct pfi_kkif *kif, struct mbuf *m)
|
|||
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;
|
||||
|
|
|
|||
|
|
@ -106,10 +106,10 @@ static void pf_mv_kpool(struct pf_kpalist *, struct pf_kpalist *);
|
|||
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 @@ pfattach_vnet(void)
|
|||
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 @@ pf_free_eth_rule(struct pf_keth_rule *rule)
|
|||
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 @@ pf_tagname2tag(const char *tagname)
|
|||
}
|
||||
|
||||
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 @@ pf_begin_eth(uint32_t *ticket)
|
|||
static void
|
||||
pf_rollback_eth_cb(struct epoch_context *ctx)
|
||||
{
|
||||
struct pf_keth_settings *settings;
|
||||
struct pf_keth_ruleset *rs;
|
||||
|
||||
settings = __containerof(ctx, struct pf_keth_settings, epoch_ctx);
|
||||
rs = __containerof(ctx, struct pf_keth_ruleset, epoch_ctx);
|
||||
|
||||
CURVNET_SET(settings->vnet);
|
||||
|
||||
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 @@ pf_rollback_eth(uint32_t ticket)
|
|||
} 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 @@ pf_eth_calc_skip_steps(struct pf_keth_rules *rules)
|
|||
}
|
||||
|
||||
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;
|
||||
|
||||
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 (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);
|
||||
}
|
||||
|
|
@ -2475,7 +2495,7 @@ pfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td
|
|||
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;
|
||||
|
|
@ -2505,21 +2525,55 @@ pfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td
|
|||
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
|
||||
|
|
@ -2543,7 +2597,7 @@ pfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td
|
|||
|
||||
#undef ERROUT
|
||||
DIOCGETETHRULES_error:
|
||||
free(packed, M_TEMP);
|
||||
free(packed, M_NVLIST);
|
||||
nvlist_destroy(nvl);
|
||||
break;
|
||||
}
|
||||
|
|
@ -2554,8 +2608,10 @@ DIOCGETETHRULES_error:
|
|||
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)
|
||||
|
||||
|
|
@ -2571,6 +2627,9 @@ DIOCGETETHRULES_error:
|
|||
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");
|
||||
|
|
@ -2582,6 +2641,17 @@ DIOCGETETHRULES_error:
|
|||
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);
|
||||
|
|
@ -2589,12 +2659,7 @@ DIOCGETETHRULES_error:
|
|||
|
||||
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) {
|
||||
|
|
@ -2605,6 +2670,8 @@ DIOCGETETHRULES_error:
|
|||
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);
|
||||
|
|
@ -2638,8 +2705,10 @@ DIOCGETETHRULE_error:
|
|||
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)
|
||||
|
||||
|
|
@ -2658,12 +2727,21 @@ DIOCGETETHRULE_error:
|
|||
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);
|
||||
}
|
||||
|
||||
|
|
@ -2710,7 +2788,19 @@ DIOCGETETHRULE_error:
|
|||
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();
|
||||
|
||||
|
|
@ -4765,13 +4855,7 @@ DIOCCHANGEADDR_error:
|
|||
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;
|
||||
|
|
@ -4852,13 +4936,8 @@ DIOCCHANGEADDR_error:
|
|||
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 */
|
||||
|
|
@ -4913,6 +4992,7 @@ DIOCCHANGEADDR_error:
|
|||
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;
|
||||
|
||||
|
|
@ -4942,19 +5022,14 @@ DIOCCHANGEADDR_error:
|
|||
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:
|
||||
|
|
@ -5008,7 +5083,7 @@ DIOCCHANGEADDR_error:
|
|||
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 */
|
||||
|
|
@ -5051,7 +5126,7 @@ DIOCCHANGEADDR_error:
|
|||
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();
|
||||
|
|
@ -5962,11 +6037,11 @@ shutdown_pf(void)
|
|||
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) {
|
||||
|
|
@ -6250,9 +6325,7 @@ pf_load_vnet(void)
|
|||
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;
|
||||
|
|
@ -6364,9 +6437,6 @@ pf_unload_vnet(void)
|
|||
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
|
||||
|
|
|
|||
|
|
@ -1084,6 +1084,9 @@ pf_keth_rule_to_nveth_rule(const struct pf_keth_rule *krule)
|
|||
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);
|
||||
|
|
|
|||
|
|
@ -70,15 +70,22 @@ __FBSDID("$FreeBSD$");
|
|||
|
||||
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 @@ pf_kanchor_compare(struct pf_kanchor *a, struct pf_kanchor *b)
|
|||
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 @@ pf_init_kruleset(struct pf_kruleset *ruleset)
|
|||
}
|
||||
|
||||
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 @@ done:
|
|||
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_kanchor_remove(struct pf_krule *r)
|
|||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue