Changeset View
Changeset View
Standalone View
Standalone View
sys/netpfil/pf/pf_ruleset.c
Show First 20 Lines • Show All 64 Lines • ▼ Show 20 Lines | |||||
#define DPFPRINTF(format, x...) \ | #define DPFPRINTF(format, x...) \ | ||||
if (V_pf_status.debug >= PF_DEBUG_NOISY) \ | if (V_pf_status.debug >= PF_DEBUG_NOISY) \ | ||||
printf(format , ##x) | printf(format , ##x) | ||||
#define rs_malloc(x) malloc(x, M_TEMP, M_NOWAIT|M_ZERO) | #define rs_malloc(x) malloc(x, M_TEMP, M_NOWAIT|M_ZERO) | ||||
#define rs_free(x) free(x, M_TEMP) | #define rs_free(x) free(x, M_TEMP) | ||||
VNET_DEFINE(struct pf_kanchor_global, pf_anchors); | VNET_DEFINE(struct pf_kanchor_global, pf_anchors); | ||||
VNET_DEFINE(struct pf_kanchor, pf_main_anchor); | VNET_DEFINE(struct pf_kanchor, pf_main_anchor); | ||||
VNET_DEFINE(struct pf_keth_settings*, pf_keth); | VNET_DEFINE(struct pf_keth_ruleset*, pf_keth); | ||||
VNET_DEFINE(struct pf_keth_settings*, pf_keth_inactive); | 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 *, | static __inline int pf_kanchor_compare(struct pf_kanchor *, | ||||
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 *); | 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_global, pf_kanchor, entry_global, pf_kanchor_compare); | ||||
RB_GENERATE(pf_kanchor_node, pf_kanchor, entry_node, 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 | static __inline int | ||||
pf_kanchor_compare(struct pf_kanchor *a, struct pf_kanchor *b) | pf_kanchor_compare(struct pf_kanchor *a, struct pf_kanchor *b) | ||||
{ | { | ||||
int c = strcmp(a->path, b->path); | int c = strcmp(a->path, b->path); | ||||
return (c ? (c < 0 ? -1 : 1) : 0); | 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 | int | ||||
pf_get_ruleset_number(u_int8_t action) | pf_get_ruleset_number(u_int8_t action) | ||||
{ | { | ||||
switch (action) { | switch (action) { | ||||
case PF_SCRUB: | case PF_SCRUB: | ||||
case PF_NOSCRUB: | case PF_NOSCRUB: | ||||
return (PF_RULESET_SCRUB); | return (PF_RULESET_SCRUB); | ||||
break; | break; | ||||
▲ Show 20 Lines • Show All 44 Lines • ▼ Show 20 Lines | for (i = 0; i < PF_RULESET_MAX; i++) { | ||||
TAILQ_INIT(&ruleset->rules[i].queues[0]); | TAILQ_INIT(&ruleset->rules[i].queues[0]); | ||||
TAILQ_INIT(&ruleset->rules[i].queues[1]); | TAILQ_INIT(&ruleset->rules[i].queues[1]); | ||||
ruleset->rules[i].active.ptr = &ruleset->rules[i].queues[0]; | ruleset->rules[i].active.ptr = &ruleset->rules[i].queues[0]; | ||||
ruleset->rules[i].inactive.ptr = &ruleset->rules[i].queues[1]; | ruleset->rules[i].inactive.ptr = &ruleset->rules[i].queues[1]; | ||||
} | } | ||||
} | } | ||||
void | void | ||||
pf_init_keth(struct pf_keth_settings *settings) | pf_init_keth(struct pf_keth_ruleset *rs) | ||||
{ | { | ||||
TAILQ_INIT(&settings->rules); | bzero(rs, sizeof(*rs)); | ||||
settings->ticket = 0; | TAILQ_INIT(&rs->rules[0]); | ||||
settings->open = 0; | TAILQ_INIT(&rs->rules[1]); | ||||
settings->vnet = curvnet; | 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 * | struct pf_kruleset * | ||||
pf_find_kruleset(const char *path) | pf_find_kruleset(const char *path) | ||||
{ | { | ||||
struct pf_kanchor *anchor; | struct pf_kanchor *anchor; | ||||
while (*path == '/') | while (*path == '/') | ||||
▲ Show 20 Lines • Show All 226 Lines • ▼ Show 20 Lines | |||||
done: | done: | ||||
nvlist_add_string(nvl, "anchor_call", anchor_call); | nvlist_add_string(nvl, "anchor_call", anchor_call); | ||||
return (0); | return (0); | ||||
} | } | ||||
int | 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, | pf_kanchor_copyout(const struct pf_kruleset *rs, const struct pf_krule *r, | ||||
struct pfioc_rule *pr) | struct pfioc_rule *pr) | ||||
{ | { | ||||
pr->anchor_call[0] = 0; | pr->anchor_call[0] = 0; | ||||
if (r->anchor == NULL) | if (r->anchor == NULL) | ||||
return (0); | return (0); | ||||
if (!r->anchor_relative) { | if (!r->anchor_relative) { | ||||
strlcpy(pr->anchor_call, "/", sizeof(pr->anchor_call)); | strlcpy(pr->anchor_call, "/", sizeof(pr->anchor_call)); | ||||
▲ Show 20 Lines • Show All 42 Lines • ▼ Show 20 Lines | pf_kanchor_remove(struct pf_krule *r) | ||||
if (r->anchor->refcnt <= 0) { | if (r->anchor->refcnt <= 0) { | ||||
printf("pf_anchor_remove: broken refcount\n"); | printf("pf_anchor_remove: broken refcount\n"); | ||||
r->anchor = NULL; | r->anchor = NULL; | ||||
return; | return; | ||||
} | } | ||||
if (!--r->anchor->refcnt) | if (!--r->anchor->refcnt) | ||||
pf_remove_if_empty_kruleset(&r->anchor->ruleset); | pf_remove_if_empty_kruleset(&r->anchor->ruleset); | ||||
r->anchor = NULL; | 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; | |||||
} | |||||
} | } |