Changeset View
Changeset View
Standalone View
Standalone View
sys/netpfil/pf/pf_ruleset.c
- This file was copied to sbin/pfctl/pf_ruleset.c.
Show All 35 Lines | |||||
* $OpenBSD: pf_ruleset.c,v 1.2 2008/12/18 15:31:37 dhill Exp $ | * $OpenBSD: pf_ruleset.c,v 1.2 2008/12/18 15:31:37 dhill Exp $ | ||||
*/ | */ | ||||
#include <sys/cdefs.h> | #include <sys/cdefs.h> | ||||
__FBSDID("$FreeBSD$"); | __FBSDID("$FreeBSD$"); | ||||
#include <sys/param.h> | #include <sys/param.h> | ||||
#include <sys/socket.h> | #include <sys/socket.h> | ||||
#ifdef _KERNEL | |||||
# include <sys/systm.h> | #include <sys/systm.h> | ||||
# include <sys/refcount.h> | #include <sys/refcount.h> | ||||
#endif /* _KERNEL */ | |||||
#include <sys/mbuf.h> | #include <sys/mbuf.h> | ||||
#include <netinet/in.h> | #include <netinet/in.h> | ||||
#include <netinet/in_systm.h> | #include <netinet/in_systm.h> | ||||
#include <netinet/ip.h> | #include <netinet/ip.h> | ||||
#include <netinet/tcp.h> | #include <netinet/tcp.h> | ||||
#include <net/if.h> | #include <net/if.h> | ||||
#include <net/vnet.h> | #include <net/vnet.h> | ||||
#include <net/pfvar.h> | #include <net/pfvar.h> | ||||
#ifdef INET6 | #ifdef INET6 | ||||
#include <netinet/ip6.h> | #include <netinet/ip6.h> | ||||
#endif /* INET6 */ | #endif /* INET6 */ | ||||
#ifdef _KERNEL | #ifndef _KERNEL | ||||
#error "Kernel only file. Please use sbin/pfctl/pf_ruleset.c instead." | |||||
#endif | |||||
#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) | ||||
#else | |||||
/* Userland equivalents so we can lend code to pfctl et al. */ | |||||
#include <arpa/inet.h> | |||||
#include <errno.h> | |||||
#include <stdio.h> | |||||
#include <stdlib.h> | |||||
#include <string.h> | |||||
#define rs_malloc(x) calloc(1, x) | |||||
#define rs_free(x) free(x) | |||||
#ifdef PFDEBUG | |||||
#include <sys/stdarg.h> | |||||
#define DPFPRINTF(format, x...) fprintf(stderr, format , ##x) | |||||
#else | |||||
#define DPFPRINTF(format, x...) ((void)0) | |||||
#endif /* PFDEBUG */ | |||||
#endif /* _KERNEL */ | |||||
#ifdef _KERNEL | |||||
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); | ||||
#else /* ! _KERNEL */ | |||||
struct pf_anchor_global pf_anchors; | |||||
struct pf_anchor pf_main_anchor; | |||||
#undef V_pf_anchors | |||||
#define V_pf_anchors pf_anchors | |||||
#undef pf_main_ruleset | |||||
#define pf_main_ruleset pf_main_anchor.ruleset | |||||
#endif /* _KERNEL */ | |||||
#ifdef _KERNEL | |||||
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 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); | ||||
#else | |||||
static __inline int pf_anchor_compare(struct pf_anchor *, | |||||
struct pf_anchor *); | |||||
static struct pf_anchor *pf_find_anchor(const char *); | |||||
RB_GENERATE(pf_anchor_global, pf_anchor, entry_global, pf_anchor_compare); | |||||
RB_GENERATE(pf_anchor_node, pf_anchor, entry_node, pf_anchor_compare); | |||||
#endif | |||||
#ifndef _KERNEL | |||||
static __inline int | static __inline int | ||||
pf_anchor_compare(struct pf_anchor *a, struct pf_anchor *b) | |||||
{ | |||||
int c = strcmp(a->path, b->path); | |||||
return (c ? (c < 0 ? -1 : 1) : 0); | |||||
} | |||||
#else | |||||
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); | ||||
} | } | ||||
#endif | |||||
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); | ||||
Show All 15 Lines | case PF_NORDR: | ||||
return (PF_RULESET_RDR); | return (PF_RULESET_RDR); | ||||
break; | break; | ||||
default: | default: | ||||
return (PF_RULESET_MAX); | return (PF_RULESET_MAX); | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
#ifndef _KERNEL | |||||
void | |||||
pf_init_ruleset(struct pf_ruleset *ruleset) | |||||
{ | |||||
int i; | |||||
memset(ruleset, 0, sizeof(struct pf_ruleset)); | |||||
for (i = 0; i < PF_RULESET_MAX; i++) { | |||||
TAILQ_INIT(&ruleset->rules[i].queues[0]); | |||||
TAILQ_INIT(&ruleset->rules[i].queues[1]); | |||||
ruleset->rules[i].active.ptr = &ruleset->rules[i].queues[0]; | |||||
ruleset->rules[i].inactive.ptr = &ruleset->rules[i].queues[1]; | |||||
} | |||||
} | |||||
static struct pf_anchor * | |||||
pf_find_anchor(const char *path) | |||||
{ | |||||
struct pf_anchor *key, *found; | |||||
key = (struct pf_anchor *)rs_malloc(sizeof(*key)); | |||||
if (key == NULL) | |||||
return (NULL); | |||||
strlcpy(key->path, path, sizeof(key->path)); | |||||
found = RB_FIND(pf_anchor_global, &V_pf_anchors, key); | |||||
rs_free(key); | |||||
return (found); | |||||
} | |||||
#else | |||||
static struct pf_kanchor * | static struct pf_kanchor * | ||||
pf_find_kanchor(const char *path) | pf_find_kanchor(const char *path) | ||||
{ | { | ||||
struct pf_kanchor *key, *found; | struct pf_kanchor *key, *found; | ||||
key = (struct pf_kanchor *)rs_malloc(sizeof(*key)); | key = (struct pf_kanchor *)rs_malloc(sizeof(*key)); | ||||
if (key == NULL) | if (key == NULL) | ||||
return (NULL); | return (NULL); | ||||
Show All 11 Lines | pf_init_kruleset(struct pf_kruleset *ruleset) | ||||
memset(ruleset, 0, sizeof(struct pf_kruleset)); | memset(ruleset, 0, sizeof(struct pf_kruleset)); | ||||
for (i = 0; i < PF_RULESET_MAX; i++) { | 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]; | ||||
} | } | ||||
} | } | ||||
#endif | |||||
#ifdef _KERNEL | |||||
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 == '/') | ||||
path++; | path++; | ||||
if (!*path) | if (!*path) | ||||
▲ Show 20 Lines • Show All 236 Lines • ▼ Show 20 Lines | 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; | ||||
} | } | ||||
#else | |||||
struct pf_ruleset * | |||||
pf_find_ruleset(const char *path) | |||||
{ | |||||
struct pf_anchor *anchor; | |||||
while (*path == '/') | |||||
path++; | |||||
if (!*path) | |||||
return (&pf_main_ruleset); | |||||
anchor = pf_find_anchor(path); | |||||
if (anchor == NULL) | |||||
return (NULL); | |||||
else | |||||
return (&anchor->ruleset); | |||||
} | |||||
struct pf_ruleset * | |||||
pf_find_or_create_ruleset(const char *path) | |||||
{ | |||||
char *p, *q, *r; | |||||
struct pf_ruleset *ruleset; | |||||
struct pf_anchor *anchor = NULL, *dup, *parent = NULL; | |||||
if (path[0] == 0) | |||||
return (&pf_main_ruleset); | |||||
while (*path == '/') | |||||
path++; | |||||
ruleset = pf_find_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_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_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_anchor_global, &V_pf_anchors, anchor)) != | |||||
NULL) { | |||||
printf("pf_find_or_create_ruleset: RB_INSERT1 " | |||||
"'%s' '%s' collides with '%s' '%s'\n", | |||||
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_anchor_node, &parent->children, | |||||
anchor)) != NULL) { | |||||
printf("pf_find_or_create_ruleset: " | |||||
"RB_INSERT2 '%s' '%s' collides with " | |||||
"'%s' '%s'\n", anchor->path, anchor->name, | |||||
dup->path, dup->name); | |||||
RB_REMOVE(pf_anchor_global, &V_pf_anchors, | |||||
anchor); | |||||
rs_free(anchor); | |||||
rs_free(p); | |||||
return (NULL); | |||||
} | |||||
} | |||||
pf_init_ruleset(&anchor->ruleset); | |||||
anchor->ruleset.anchor = anchor; | |||||
parent = anchor; | |||||
if (r != NULL) | |||||
q = r + 1; | |||||
else | |||||
*q = 0; | |||||
} | |||||
rs_free(p); | |||||
return (&anchor->ruleset); | |||||
} | |||||
void | |||||
pf_remove_if_empty_ruleset(struct pf_ruleset *ruleset) | |||||
{ | |||||
struct pf_anchor *parent; | |||||
int i; | |||||
while (ruleset != NULL) { | |||||
if (ruleset == &pf_main_ruleset || ruleset->anchor == NULL || | |||||
!RB_EMPTY(&ruleset->anchor->children) || | |||||
ruleset->anchor->refcnt > 0 || ruleset->tables > 0 || | |||||
ruleset->topen) | |||||
return; | |||||
for (i = 0; i < PF_RULESET_MAX; ++i) | |||||
if (!TAILQ_EMPTY(ruleset->rules[i].active.ptr) || | |||||
!TAILQ_EMPTY(ruleset->rules[i].inactive.ptr) || | |||||
ruleset->rules[i].inactive.open) | |||||
return; | |||||
RB_REMOVE(pf_anchor_global, &V_pf_anchors, ruleset->anchor); | |||||
if ((parent = ruleset->anchor->parent) != NULL) | |||||
RB_REMOVE(pf_anchor_node, &parent->children, | |||||
ruleset->anchor); | |||||
rs_free(ruleset->anchor); | |||||
if (parent == NULL) | |||||
return; | |||||
ruleset = &parent->ruleset; | |||||
} | |||||
} | |||||
int | |||||
pf_anchor_setup(struct pf_rule *r, const struct pf_ruleset *s, | |||||
const char *name) | |||||
{ | |||||
char *p, *path; | |||||
struct pf_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]) { | |||||
printf("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_ruleset(path); | |||||
rs_free(path); | |||||
if (ruleset == NULL || ruleset->anchor == NULL) { | |||||
printf("pf_anchor_setup: ruleset\n"); | |||||
return (1); | |||||
} | |||||
r->anchor = ruleset->anchor; | |||||
r->anchor->refcnt++; | |||||
return (0); | |||||
} | |||||
#endif |