Changeset View
Changeset View
Standalone View
Standalone View
sys/netpfil/pf/pf_ioctl.c
Show First 20 Lines • Show All 100 Lines • ▼ Show 20 Lines | |||||
static struct pf_kpool *pf_get_kpool(const char *, u_int32_t, u_int8_t, | static struct pf_kpool *pf_get_kpool(const char *, u_int32_t, u_int8_t, | ||||
u_int32_t, u_int8_t, u_int8_t, u_int8_t); | u_int32_t, u_int8_t, u_int8_t, u_int8_t); | ||||
static void pf_mv_kpool(struct pf_kpalist *, struct pf_kpalist *); | static void pf_mv_kpool(struct pf_kpalist *, struct pf_kpalist *); | ||||
static void pf_empty_kpool(struct pf_kpalist *); | static void pf_empty_kpool(struct pf_kpalist *); | ||||
static int pfioctl(struct cdev *, u_long, caddr_t, int, | static int pfioctl(struct cdev *, u_long, caddr_t, int, | ||||
struct thread *); | 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 void pf_rollback_eth_cb(struct epoch_context *); | ||||
static int pf_rollback_eth(uint32_t); | static int pf_rollback_eth(uint32_t, const char *); | ||||
static int pf_commit_eth(uint32_t); | static int pf_commit_eth(uint32_t, const char *); | ||||
static void pf_free_eth_rule(struct pf_keth_rule *); | static void pf_free_eth_rule(struct pf_keth_rule *); | ||||
#ifdef ALTQ | #ifdef ALTQ | ||||
static int pf_begin_altq(u_int32_t *); | static int pf_begin_altq(u_int32_t *); | ||||
static int pf_rollback_altq(u_int32_t); | static int pf_rollback_altq(u_int32_t); | ||||
static int pf_commit_altq(u_int32_t); | static int pf_commit_altq(u_int32_t); | ||||
static int pf_enable_altq(struct pf_altq *); | static int pf_enable_altq(struct pf_altq *); | ||||
static int pf_disable_altq(struct pf_altq *); | static int pf_disable_altq(struct pf_altq *); | ||||
static uint16_t pf_qname2qid(const char *); | static uint16_t pf_qname2qid(const char *); | ||||
▲ Show 20 Lines • Show All 192 Lines • ▼ Show 20 Lines | pfattach_vnet(void) | ||||
V_pf_limits[PF_LIMIT_STATES].limit = PFSTATE_HIWAT; | V_pf_limits[PF_LIMIT_STATES].limit = PFSTATE_HIWAT; | ||||
V_pf_limits[PF_LIMIT_SRC_NODES].limit = PFSNODE_HIWAT; | V_pf_limits[PF_LIMIT_SRC_NODES].limit = PFSNODE_HIWAT; | ||||
RB_INIT(&V_pf_anchors); | RB_INIT(&V_pf_anchors); | ||||
pf_init_kruleset(&pf_main_ruleset); | pf_init_kruleset(&pf_main_ruleset); | ||||
pf_init_keth(V_pf_keth); | pf_init_keth(V_pf_keth); | ||||
pf_init_keth(V_pf_keth_inactive); | |||||
/* default rule should never be garbage collected */ | /* default rule should never be garbage collected */ | ||||
V_pf_default_rule.entries.tqe_prev = &V_pf_default_rule.entries.tqe_next; | V_pf_default_rule.entries.tqe_prev = &V_pf_default_rule.entries.tqe_next; | ||||
#ifdef PF_DEFAULT_TO_DROP | #ifdef PF_DEFAULT_TO_DROP | ||||
V_pf_default_rule.action = PF_DROP; | V_pf_default_rule.action = PF_DROP; | ||||
#else | #else | ||||
V_pf_default_rule.action = PF_PASS; | V_pf_default_rule.action = PF_PASS; | ||||
#endif | #endif | ||||
▲ Show 20 Lines • Show All 175 Lines • ▼ Show 20 Lines | #endif | ||||
if (rule->kif) | if (rule->kif) | ||||
pfi_kkif_unref(rule->kif); | pfi_kkif_unref(rule->kif); | ||||
counter_u64_free(rule->evaluations); | counter_u64_free(rule->evaluations); | ||||
for (int i = 0; i < 2; i++) { | for (int i = 0; i < 2; i++) { | ||||
counter_u64_free(rule->packets[i]); | counter_u64_free(rule->packets[i]); | ||||
counter_u64_free(rule->bytes[i]); | counter_u64_free(rule->bytes[i]); | ||||
} | } | ||||
pf_keth_anchor_remove(rule); | |||||
free(rule, M_PFRULE); | free(rule, M_PFRULE); | ||||
} | } | ||||
void | void | ||||
pf_free_rule(struct pf_krule *rule) | pf_free_rule(struct pf_krule *rule) | ||||
{ | { | ||||
▲ Show 20 Lines • Show All 175 Lines • ▼ Show 20 Lines | |||||
static uint16_t | static uint16_t | ||||
pf_tagname2tag(const char *tagname) | pf_tagname2tag(const char *tagname) | ||||
{ | { | ||||
return (tagname2tag(&V_pf_tags, tagname)); | return (tagname2tag(&V_pf_tags, tagname)); | ||||
} | } | ||||
static int | 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_rule *rule, *tmp; | ||||
struct pf_keth_ruleset *rs; | |||||
PF_RULES_WASSERT(); | 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 | /* We may be waiting for NET_EPOCH_CALL(pf_rollback_eth_cb) to | ||||
* finish. */ | * finish. */ | ||||
return (EBUSY); | return (EBUSY); | ||||
} | |||||
/* Purge old inactive rules. */ | /* Purge old inactive rules. */ | ||||
TAILQ_FOREACH_SAFE(rule, &V_pf_keth_inactive->rules, entries, tmp) { | TAILQ_FOREACH_SAFE(rule, rs->inactive.rules, entries, | ||||
TAILQ_REMOVE(&V_pf_keth_inactive->rules, rule, entries); | tmp) { | ||||
TAILQ_REMOVE(rs->inactive.rules, rule, | |||||
entries); | |||||
pf_free_eth_rule(rule); | pf_free_eth_rule(rule); | ||||
} | } | ||||
*ticket = ++V_pf_keth_inactive->ticket; | *ticket = ++rs->inactive.ticket; | ||||
V_pf_keth_inactive->open = 1; | rs->inactive.open = 1; | ||||
return (0); | return (0); | ||||
} | } | ||||
static void | static void | ||||
pf_rollback_eth_cb(struct epoch_context *ctx) | 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); | CURVNET_SET(rs->vnet); | ||||
MPASS(settings == V_pf_keth_inactive); | |||||
PF_RULES_WLOCK(); | 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(); | PF_RULES_WUNLOCK(); | ||||
CURVNET_RESTORE(); | CURVNET_RESTORE(); | ||||
} | } | ||||
static int | 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_rule *rule, *tmp; | ||||
struct pf_keth_ruleset *rs; | |||||
PF_RULES_WASSERT(); | 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); | return (0); | ||||
/* Purge old inactive rules. */ | /* Purge old inactive rules. */ | ||||
TAILQ_FOREACH_SAFE(rule, &V_pf_keth_inactive->rules, entries, tmp) { | TAILQ_FOREACH_SAFE(rule, rs->inactive.rules, entries, | ||||
TAILQ_REMOVE(&V_pf_keth_inactive->rules, rule, entries); | tmp) { | ||||
TAILQ_REMOVE(rs->inactive.rules, rule, entries); | |||||
pf_free_eth_rule(rule); | pf_free_eth_rule(rule); | ||||
} | } | ||||
V_pf_keth_inactive->open = 0; | rs->inactive.open = 0; | ||||
pf_remove_if_empty_keth_ruleset(rs); | |||||
return (0); | return (0); | ||||
} | } | ||||
#define PF_SET_SKIP_STEPS(i) \ | #define PF_SET_SKIP_STEPS(i) \ | ||||
do { \ | do { \ | ||||
while (head[i] != cur) { \ | while (head[i] != cur) { \ | ||||
head[i]->skip[i].ptr = cur; \ | head[i]->skip[i].ptr = cur; \ | ||||
head[i] = TAILQ_NEXT(head[i], entries); \ | head[i] = TAILQ_NEXT(head[i], entries); \ | ||||
} \ | } \ | ||||
} while (0) | } while (0) | ||||
static void | 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]; | struct pf_keth_rule *cur, *prev, *head[PFE_SKIP_COUNT]; | ||||
int i; | int i; | ||||
cur = TAILQ_FIRST(rules); | cur = TAILQ_FIRST(rules); | ||||
prev = cur; | prev = cur; | ||||
for (i = 0; i < PFE_SKIP_COUNT; ++i) | for (i = 0; i < PFE_SKIP_COUNT; ++i) | ||||
head[i] = cur; | head[i] = cur; | ||||
Show All 12 Lines | while (cur != NULL) { | ||||
prev = cur; | prev = cur; | ||||
cur = TAILQ_NEXT(cur, entries); | cur = TAILQ_NEXT(cur, entries); | ||||
} | } | ||||
for (i = 0; i < PFE_SKIP_COUNT; ++i) | for (i = 0; i < PFE_SKIP_COUNT; ++i) | ||||
PF_SET_SKIP_STEPS(i); | PF_SET_SKIP_STEPS(i); | ||||
} | } | ||||
static int | 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 || | rs = pf_find_keth_ruleset(anchor); | ||||
ticket != V_pf_keth_inactive->ticket) | if (rs == NULL) { | ||||
return (EINVAL); | |||||
} | |||||
if (!rs->inactive.open || | |||||
ticket != rs->inactive.ticket) | |||||
return (EBUSY); | return (EBUSY); | ||||
PF_RULES_WASSERT(); | 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; | rules = rs->active.rules; | ||||
ck_pr_store_ptr(&V_pf_keth, V_pf_keth_inactive); | ck_pr_store_ptr(&rs->active.rules, rs->inactive.rules); | ||||
V_pf_keth_inactive = settings; | rs->inactive.rules = rules; | ||||
V_pf_keth_inactive->ticket = V_pf_keth->ticket; | rs->inactive.ticket = rs->active.ticket; | ||||
/* Clean up inactive rules (i.e. previously active rules), only when | /* Clean up inactive rules (i.e. previously active rules), only when | ||||
* we're sure they're no longer used. */ | * 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); | return (0); | ||||
} | } | ||||
#ifdef ALTQ | #ifdef ALTQ | ||||
static uint16_t | static uint16_t | ||||
pf_qname2qid(const char *qname) | pf_qname2qid(const char *qname) | ||||
{ | { | ||||
▲ Show 20 Lines • Show All 1,637 Lines • ▼ Show 20 Lines | #define ERROUT_IOCTL(target, x) \ | ||||
case DIOCSTART: | case DIOCSTART: | ||||
sx_xlock(&pf_ioctl_lock); | sx_xlock(&pf_ioctl_lock); | ||||
if (V_pf_status.running) | if (V_pf_status.running) | ||||
error = EEXIST; | error = EEXIST; | ||||
else { | else { | ||||
int cpu; | int cpu; | ||||
hook_pf(); | hook_pf(); | ||||
if (! TAILQ_EMPTY(&V_pf_keth->rules)) | if (! TAILQ_EMPTY(V_pf_keth->active.rules)) | ||||
hook_pf_eth(); | hook_pf_eth(); | ||||
V_pf_status.running = 1; | V_pf_status.running = 1; | ||||
V_pf_status.since = time_second; | V_pf_status.since = time_second; | ||||
CPU_FOREACH(cpu) | CPU_FOREACH(cpu) | ||||
V_pf_stateid[cpu] = time_second; | V_pf_stateid[cpu] = time_second; | ||||
DPFPRINTF(PF_DEBUG_MISC, ("pf: started\n")); | DPFPRINTF(PF_DEBUG_MISC, ("pf: started\n")); | ||||
Show All 13 Lines | case DIOCSTOP: | ||||
} | } | ||||
break; | break; | ||||
case DIOCGETETHRULES: { | case DIOCGETETHRULES: { | ||||
struct pfioc_nv *nv = (struct pfioc_nv *)addr; | struct pfioc_nv *nv = (struct pfioc_nv *)addr; | ||||
nvlist_t *nvl; | nvlist_t *nvl; | ||||
void *packed; | void *packed; | ||||
struct pf_keth_rule *tail; | struct pf_keth_rule *tail; | ||||
struct pf_keth_ruleset *rs; | |||||
u_int32_t ticket, nr; | u_int32_t ticket, nr; | ||||
const char *anchor = ""; | |||||
nvl = NULL; | nvl = NULL; | ||||
packed = NULL; | packed = NULL; | ||||
#define ERROUT(x) do { error = (x); goto DIOCGETETHRULES_error; } while (0) | #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); | nvl = nvlist_create(0); | ||||
if (nvl == NULL) | if (nvl == NULL) | ||||
ERROUT(ENOMEM); | ERROUT(ENOMEM); | ||||
PF_RULES_RLOCK(); | PF_RULES_RLOCK(); | ||||
ticket = V_pf_keth->ticket; | ticket = rs->active.ticket; | ||||
tail = TAILQ_LAST(&V_pf_keth->rules, pf_keth_rules); | tail = TAILQ_LAST(rs->active.rules, pf_keth_ruleq); | ||||
if (tail) | if (tail) | ||||
nr = tail->nr + 1; | nr = tail->nr + 1; | ||||
else | else | ||||
nr = 0; | nr = 0; | ||||
PF_RULES_RUNLOCK(); | PF_RULES_RUNLOCK(); | ||||
nvlist_add_number(nvl, "ticket", ticket); | nvlist_add_number(nvl, "ticket", ticket); | ||||
nvlist_add_number(nvl, "nr", nr); | nvlist_add_number(nvl, "nr", nr); | ||||
packed = nvlist_pack(nvl, &nv->len); | packed = nvlist_pack(nvl, &nv->len); | ||||
if (packed == NULL) | if (packed == NULL) | ||||
ERROUT(ENOMEM); | ERROUT(ENOMEM); | ||||
if (nv->size == 0) | if (nv->size == 0) | ||||
ERROUT(0); | ERROUT(0); | ||||
else if (nv->size < nv->len) | else if (nv->size < nv->len) | ||||
ERROUT(ENOSPC); | ERROUT(ENOSPC); | ||||
error = copyout(packed, nv->data, nv->len); | error = copyout(packed, nv->data, nv->len); | ||||
#undef ERROUT | #undef ERROUT | ||||
DIOCGETETHRULES_error: | DIOCGETETHRULES_error: | ||||
free(packed, M_TEMP); | free(packed, M_NVLIST); | ||||
nvlist_destroy(nvl); | nvlist_destroy(nvl); | ||||
break; | break; | ||||
} | } | ||||
case DIOCGETETHRULE: { | case DIOCGETETHRULE: { | ||||
struct epoch_tracker et; | struct epoch_tracker et; | ||||
struct pfioc_nv *nv = (struct pfioc_nv *)addr; | struct pfioc_nv *nv = (struct pfioc_nv *)addr; | ||||
nvlist_t *nvl = NULL; | nvlist_t *nvl = NULL; | ||||
void *nvlpacked = NULL; | void *nvlpacked = NULL; | ||||
struct pf_keth_rule *rule = NULL; | struct pf_keth_rule *rule = NULL; | ||||
struct pf_keth_ruleset *rs; | |||||
u_int32_t ticket, nr; | u_int32_t ticket, nr; | ||||
bool clear = false; | bool clear = false; | ||||
const char *anchor; | |||||
#define ERROUT(x) do { error = (x); goto DIOCGETETHRULE_error; } while (0) | #define ERROUT(x) do { error = (x); goto DIOCGETETHRULE_error; } while (0) | ||||
nvlpacked = malloc(nv->len, M_TEMP, M_WAITOK); | nvlpacked = malloc(nv->len, M_TEMP, M_WAITOK); | ||||
if (nvlpacked == NULL) | if (nvlpacked == NULL) | ||||
ERROUT(ENOMEM); | ERROUT(ENOMEM); | ||||
error = copyin(nv->data, nvlpacked, nv->len); | error = copyin(nv->data, nvlpacked, nv->len); | ||||
if (error) | if (error) | ||||
ERROUT(error); | ERROUT(error); | ||||
nvl = nvlist_unpack(nvlpacked, nv->len, 0); | nvl = nvlist_unpack(nvlpacked, nv->len, 0); | ||||
if (! nvlist_exists_number(nvl, "ticket")) | if (! nvlist_exists_number(nvl, "ticket")) | ||||
ERROUT(EBADMSG); | ERROUT(EBADMSG); | ||||
ticket = nvlist_get_number(nvl, "ticket"); | 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")) | if (nvlist_exists_bool(nvl, "clear")) | ||||
clear = nvlist_get_bool(nvl, "clear"); | clear = nvlist_get_bool(nvl, "clear"); | ||||
if (clear && !(flags & FWRITE)) | if (clear && !(flags & FWRITE)) | ||||
ERROUT(EACCES); | ERROUT(EACCES); | ||||
if (! nvlist_exists_number(nvl, "nr")) | if (! nvlist_exists_number(nvl, "nr")) | ||||
ERROUT(EBADMSG); | ERROUT(EBADMSG); | ||||
nr = nvlist_get_number(nvl, "nr"); | 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); | nvlist_destroy(nvl); | ||||
nvl = NULL; | nvl = NULL; | ||||
free(nvlpacked, M_TEMP); | free(nvlpacked, M_TEMP); | ||||
nvlpacked = NULL; | nvlpacked = NULL; | ||||
nvl = nvlist_create(0); | nvl = nvlist_create(0); | ||||
PF_RULES_RLOCK(); | rule = TAILQ_FIRST(rs->active.rules); | ||||
if (ticket != V_pf_keth->ticket) { | |||||
PF_RULES_RUNLOCK(); | |||||
ERROUT(EBUSY); | |||||
} | |||||
rule = TAILQ_FIRST(&V_pf_keth->rules); | |||||
while ((rule != NULL) && (rule->nr != nr)) | while ((rule != NULL) && (rule->nr != nr)) | ||||
rule = TAILQ_NEXT(rule, entries); | rule = TAILQ_NEXT(rule, entries); | ||||
if (rule == NULL) { | if (rule == NULL) { | ||||
PF_RULES_RUNLOCK(); | PF_RULES_RUNLOCK(); | ||||
ERROUT(ENOENT); | ERROUT(ENOENT); | ||||
} | } | ||||
/* Make sure rule can't go away. */ | /* Make sure rule can't go away. */ | ||||
NET_EPOCH_ENTER(et); | NET_EPOCH_ENTER(et); | ||||
PF_RULES_RUNLOCK(); | PF_RULES_RUNLOCK(); | ||||
nvl = pf_keth_rule_to_nveth_rule(rule); | nvl = pf_keth_rule_to_nveth_rule(rule); | ||||
if (pf_keth_anchor_nvcopyout(rs, rule, nvl)) | |||||
ERROUT(EBUSY); | |||||
NET_EPOCH_EXIT(et); | NET_EPOCH_EXIT(et); | ||||
if (nvl == NULL) | if (nvl == NULL) | ||||
ERROUT(ENOMEM); | ERROUT(ENOMEM); | ||||
nvlpacked = nvlist_pack(nvl, &nv->len); | nvlpacked = nvlist_pack(nvl, &nv->len); | ||||
if (nvlpacked == NULL) | if (nvlpacked == NULL) | ||||
ERROUT(ENOMEM); | ERROUT(ENOMEM); | ||||
Show All 17 Lines | DIOCGETETHRULE_error: | ||||
nvlist_destroy(nvl); | nvlist_destroy(nvl); | ||||
break; | break; | ||||
} | } | ||||
case DIOCADDETHRULE: { | case DIOCADDETHRULE: { | ||||
struct pfioc_nv *nv = (struct pfioc_nv *)addr; | struct pfioc_nv *nv = (struct pfioc_nv *)addr; | ||||
nvlist_t *nvl = NULL; | nvlist_t *nvl = NULL; | ||||
void *nvlpacked = 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; | struct pfi_kkif *kif = NULL; | ||||
const char *anchor = "", *anchor_call = ""; | |||||
#define ERROUT(x) do { error = (x); goto DIOCADDETHRULE_error; } while (0) | #define ERROUT(x) do { error = (x); goto DIOCADDETHRULE_error; } while (0) | ||||
nvlpacked = malloc(nv->len, M_TEMP, M_WAITOK); | nvlpacked = malloc(nv->len, M_TEMP, M_WAITOK); | ||||
if (nvlpacked == NULL) | if (nvlpacked == NULL) | ||||
ERROUT(ENOMEM); | ERROUT(ENOMEM); | ||||
error = copyin(nv->data, nvlpacked, nv->len); | error = copyin(nv->data, nvlpacked, nv->len); | ||||
if (error) | if (error) | ||||
ERROUT(error); | ERROUT(error); | ||||
nvl = nvlist_unpack(nvlpacked, nv->len, 0); | nvl = nvlist_unpack(nvlpacked, nv->len, 0); | ||||
if (nvl == NULL) | if (nvl == NULL) | ||||
ERROUT(EBADMSG); | ERROUT(EBADMSG); | ||||
if (! nvlist_exists_number(nvl, "ticket")) | if (! nvlist_exists_number(nvl, "ticket")) | ||||
ERROUT(EBADMSG); | 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") != | if (nvlist_get_number(nvl, "ticket") != | ||||
V_pf_keth_inactive->ticket) { | ruleset->inactive.ticket) { | ||||
DPFPRINTF(PF_DEBUG_MISC, | DPFPRINTF(PF_DEBUG_MISC, | ||||
("ticket: %d != %d\n", | ("ticket: %d != %d\n", | ||||
(u_int32_t)nvlist_get_number(nvl, "ticket"), | (u_int32_t)nvlist_get_number(nvl, "ticket"), | ||||
V_pf_keth_inactive->ticket)); | ruleset->inactive.ticket)); | ||||
ERROUT(EBUSY); | ERROUT(EBUSY); | ||||
} | } | ||||
rule = malloc(sizeof(*rule), M_PFRULE, M_WAITOK); | rule = malloc(sizeof(*rule), M_PFRULE, M_WAITOK); | ||||
if (rule == NULL) | if (rule == NULL) | ||||
ERROUT(ENOMEM); | ERROUT(ENOMEM); | ||||
error = pf_nveth_rule_to_keth_rule(nvl, rule); | error = pf_nveth_rule_to_keth_rule(nvl, rule); | ||||
Show All 30 Lines | if (rule->tagname[0]) | ||||
error = EBUSY; | error = EBUSY; | ||||
if (error) { | if (error) { | ||||
pf_free_eth_rule(rule); | pf_free_eth_rule(rule); | ||||
PF_RULES_WUNLOCK(); | PF_RULES_WUNLOCK(); | ||||
ERROUT(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(); | PF_RULES_WUNLOCK(); | ||||
#undef ERROUT | #undef ERROUT | ||||
DIOCADDETHRULE_error: | DIOCADDETHRULE_error: | ||||
nvlist_destroy(nvl); | nvlist_destroy(nvl); | ||||
free(nvlpacked, M_TEMP); | free(nvlpacked, M_TEMP); | ||||
break; | break; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 2,037 Lines • ▼ Show 20 Lines | if (error) { | ||||
free(ioes, M_TEMP); | free(ioes, M_TEMP); | ||||
break; | break; | ||||
} | } | ||||
PF_RULES_WLOCK(); | PF_RULES_WLOCK(); | ||||
for (i = 0, ioe = ioes; i < io->size; i++, ioe++) { | for (i = 0, ioe = ioes; i < io->size; i++, ioe++) { | ||||
ioe->anchor[sizeof(ioe->anchor) - 1] = '\0'; | ioe->anchor[sizeof(ioe->anchor) - 1] = '\0'; | ||||
switch (ioe->rs_num) { | switch (ioe->rs_num) { | ||||
case PF_RULESET_ETH: | case PF_RULESET_ETH: | ||||
if (ioe->anchor[0]) { | if ((error = pf_begin_eth(&ioe->ticket, ioe->anchor))) { | ||||
PF_RULES_WUNLOCK(); | PF_RULES_WUNLOCK(); | ||||
free(ioes, M_TEMP); | free(ioes, M_TEMP); | ||||
error = EINVAL; | |||||
goto fail; | goto fail; | ||||
} | } | ||||
if ((error = pf_begin_eth(&ioe->ticket))) { | |||||
PF_RULES_WUNLOCK(); | |||||
free(ioes, M_TEMP); | |||||
goto fail; | |||||
} | |||||
break; | break; | ||||
#ifdef ALTQ | #ifdef ALTQ | ||||
case PF_RULESET_ALTQ: | case PF_RULESET_ALTQ: | ||||
if (ioe->anchor[0]) { | if (ioe->anchor[0]) { | ||||
PF_RULES_WUNLOCK(); | PF_RULES_WUNLOCK(); | ||||
free(ioes, M_TEMP); | free(ioes, M_TEMP); | ||||
error = EINVAL; | error = EINVAL; | ||||
goto fail; | goto fail; | ||||
▲ Show 20 Lines • Show All 60 Lines • ▼ Show 20 Lines | if (error) { | ||||
free(ioes, M_TEMP); | free(ioes, M_TEMP); | ||||
break; | break; | ||||
} | } | ||||
PF_RULES_WLOCK(); | PF_RULES_WLOCK(); | ||||
for (i = 0, ioe = ioes; i < io->size; i++, ioe++) { | for (i = 0, ioe = ioes; i < io->size; i++, ioe++) { | ||||
ioe->anchor[sizeof(ioe->anchor) - 1] = '\0'; | ioe->anchor[sizeof(ioe->anchor) - 1] = '\0'; | ||||
switch (ioe->rs_num) { | switch (ioe->rs_num) { | ||||
case PF_RULESET_ETH: | case PF_RULESET_ETH: | ||||
if (ioe->anchor[0]) { | if ((error = pf_rollback_eth(ioe->ticket, | ||||
ioe->anchor))) { | |||||
PF_RULES_WUNLOCK(); | PF_RULES_WUNLOCK(); | ||||
free(ioes, M_TEMP); | free(ioes, M_TEMP); | ||||
error = EINVAL; | |||||
goto fail; | |||||
} | |||||
if ((error = pf_rollback_eth(ioe->ticket))) { | |||||
PF_RULES_WUNLOCK(); | |||||
free(ioes, M_TEMP); | |||||
goto fail; /* really bad */ | goto fail; /* really bad */ | ||||
} | } | ||||
break; | break; | ||||
#ifdef ALTQ | #ifdef ALTQ | ||||
case PF_RULESET_ALTQ: | case PF_RULESET_ALTQ: | ||||
if (ioe->anchor[0]) { | if (ioe->anchor[0]) { | ||||
PF_RULES_WUNLOCK(); | PF_RULES_WUNLOCK(); | ||||
free(ioes, M_TEMP); | free(ioes, M_TEMP); | ||||
Show All 36 Lines | #endif /* ALTQ */ | ||||
free(ioes, M_TEMP); | free(ioes, M_TEMP); | ||||
break; | break; | ||||
} | } | ||||
case DIOCXCOMMIT: { | case DIOCXCOMMIT: { | ||||
struct pfioc_trans *io = (struct pfioc_trans *)addr; | struct pfioc_trans *io = (struct pfioc_trans *)addr; | ||||
struct pfioc_trans_e *ioe, *ioes; | struct pfioc_trans_e *ioe, *ioes; | ||||
struct pf_kruleset *rs; | struct pf_kruleset *rs; | ||||
struct pf_keth_ruleset *ers; | |||||
size_t totlen; | size_t totlen; | ||||
int i; | int i; | ||||
if (io->esize != sizeof(*ioe)) { | if (io->esize != sizeof(*ioe)) { | ||||
error = ENODEV; | error = ENODEV; | ||||
break; | break; | ||||
} | } | ||||
Show All 13 Lines | if (error) { | ||||
break; | break; | ||||
} | } | ||||
PF_RULES_WLOCK(); | PF_RULES_WLOCK(); | ||||
/* First makes sure everything will succeed. */ | /* First makes sure everything will succeed. */ | ||||
for (i = 0, ioe = ioes; i < io->size; i++, ioe++) { | for (i = 0, ioe = ioes; i < io->size; i++, ioe++) { | ||||
ioe->anchor[sizeof(ioe->anchor) - 1] = 0; | ioe->anchor[sizeof(ioe->anchor) - 1] = 0; | ||||
switch (ioe->rs_num) { | switch (ioe->rs_num) { | ||||
case PF_RULESET_ETH: | 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(); | PF_RULES_WUNLOCK(); | ||||
free(ioes, M_TEMP); | free(ioes, M_TEMP); | ||||
error = EINVAL; | error = EINVAL; | ||||
goto fail; | 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; | break; | ||||
#ifdef ALTQ | #ifdef ALTQ | ||||
case PF_RULESET_ALTQ: | case PF_RULESET_ALTQ: | ||||
if (ioe->anchor[0]) { | if (ioe->anchor[0]) { | ||||
PF_RULES_WUNLOCK(); | PF_RULES_WUNLOCK(); | ||||
free(ioes, M_TEMP); | free(ioes, M_TEMP); | ||||
error = EINVAL; | error = EINVAL; | ||||
goto fail; | goto fail; | ||||
Show All 37 Lines | #endif /* ALTQ */ | ||||
} | } | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
/* Now do the commit - no errors should happen here. */ | /* Now do the commit - no errors should happen here. */ | ||||
for (i = 0, ioe = ioes; i < io->size; i++, ioe++) { | for (i = 0, ioe = ioes; i < io->size; i++, ioe++) { | ||||
switch (ioe->rs_num) { | switch (ioe->rs_num) { | ||||
case PF_RULESET_ETH: | case PF_RULESET_ETH: | ||||
if ((error = pf_commit_eth(ioe->ticket))) { | if ((error = pf_commit_eth(ioe->ticket, ioe->anchor))) { | ||||
PF_RULES_WUNLOCK(); | PF_RULES_WUNLOCK(); | ||||
free(ioes, M_TEMP); | free(ioes, M_TEMP); | ||||
goto fail; /* really bad */ | goto fail; /* really bad */ | ||||
} | } | ||||
break; | break; | ||||
#ifdef ALTQ | #ifdef ALTQ | ||||
case PF_RULESET_ALTQ: | case PF_RULESET_ALTQ: | ||||
if ((error = pf_commit_altq(ioe->ticket))) { | if ((error = pf_commit_altq(ioe->ticket))) { | ||||
Show All 26 Lines | #endif /* ALTQ */ | ||||
goto fail; /* really bad */ | goto fail; /* really bad */ | ||||
} | } | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
PF_RULES_WUNLOCK(); | PF_RULES_WUNLOCK(); | ||||
/* Only hook into EtherNet taffic if we've got rules for it. */ | /* 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(); | hook_pf_eth(); | ||||
else | else | ||||
dehook_pf_eth(); | dehook_pf_eth(); | ||||
free(ioes, M_TEMP); | free(ioes, M_TEMP); | ||||
break; | break; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 894 Lines • ▼ Show 20 Lines | do { | ||||
pf_commit_rules(t[1], PF_RULESET_FILTER, &nn); | pf_commit_rules(t[1], PF_RULESET_FILTER, &nn); | ||||
pf_commit_rules(t[2], PF_RULESET_NAT, &nn); | pf_commit_rules(t[2], PF_RULESET_NAT, &nn); | ||||
pf_commit_rules(t[3], PF_RULESET_BINAT, &nn); | pf_commit_rules(t[3], PF_RULESET_BINAT, &nn); | ||||
pf_commit_rules(t[4], PF_RULESET_RDR, &nn); | pf_commit_rules(t[4], PF_RULESET_RDR, &nn); | ||||
if ((error = pf_clear_tables()) != 0) | if ((error = pf_clear_tables()) != 0) | ||||
break; | 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")); | DPFPRINTF(PF_DEBUG_MISC, ("shutdown_pf: eth\n")); | ||||
break; | break; | ||||
} | } | ||||
pf_commit_eth(t[0]); | pf_commit_eth(t[0], &nn); | ||||
#ifdef ALTQ | #ifdef ALTQ | ||||
if ((error = pf_begin_altq(&t[0])) != 0) { | if ((error = pf_begin_altq(&t[0])) != 0) { | ||||
DPFPRINTF(PF_DEBUG_MISC, ("shutdown_pf: ALTQ\n")); | DPFPRINTF(PF_DEBUG_MISC, ("shutdown_pf: ALTQ\n")); | ||||
break; | break; | ||||
} | } | ||||
pf_commit_altq(t[0]); | pf_commit_altq(t[0]); | ||||
#endif | #endif | ||||
▲ Show 20 Lines • Show All 267 Lines • ▼ Show 20 Lines | pf_load_vnet(void) | ||||
pf_init_tagset(&V_pf_tags, &pf_rule_tag_hashsize, | pf_init_tagset(&V_pf_tags, &pf_rule_tag_hashsize, | ||||
PF_RULE_TAG_HASH_SIZE_DEFAULT); | PF_RULE_TAG_HASH_SIZE_DEFAULT); | ||||
#ifdef ALTQ | #ifdef ALTQ | ||||
pf_init_tagset(&V_pf_qids, &pf_queue_tag_hashsize, | pf_init_tagset(&V_pf_qids, &pf_queue_tag_hashsize, | ||||
PF_QUEUE_TAG_HASH_SIZE_DEFAULT); | PF_QUEUE_TAG_HASH_SIZE_DEFAULT); | ||||
#endif | #endif | ||||
V_pf_keth = malloc(sizeof(*V_pf_keth), M_PFRULE, M_WAITOK); | V_pf_keth = &V_pf_main_keth_anchor.ruleset; | ||||
V_pf_keth_inactive = malloc(sizeof(*V_pf_keth_inactive), | |||||
M_PFRULE, M_WAITOK); | |||||
pfattach_vnet(); | pfattach_vnet(); | ||||
V_pf_vnet_active = 1; | V_pf_vnet_active = 1; | ||||
} | } | ||||
static int | static int | ||||
pf_load(void) | pf_load(void) | ||||
{ | { | ||||
▲ Show 20 Lines • Show All 95 Lines • ▼ Show 20 Lines | #endif | ||||
for (int i = 0; i < PFRES_MAX; i++) | for (int i = 0; i < PFRES_MAX; i++) | ||||
counter_u64_free(V_pf_status.counters[i]); | counter_u64_free(V_pf_status.counters[i]); | ||||
for (int i = 0; i < KLCNT_MAX; i++) | for (int i = 0; i < KLCNT_MAX; i++) | ||||
counter_u64_free(V_pf_status.lcounters[i]); | counter_u64_free(V_pf_status.lcounters[i]); | ||||
for (int i = 0; i < FCNT_MAX; i++) | for (int i = 0; i < FCNT_MAX; i++) | ||||
pf_counter_u64_deinit(&V_pf_status.fcounters[i]); | pf_counter_u64_deinit(&V_pf_status.fcounters[i]); | ||||
for (int i = 0; i < SCNT_MAX; i++) | for (int i = 0; i < SCNT_MAX; i++) | ||||
counter_u64_free(V_pf_status.scounters[i]); | counter_u64_free(V_pf_status.scounters[i]); | ||||
free(V_pf_keth, M_PFRULE); | |||||
free(V_pf_keth_inactive, M_PFRULE); | |||||
} | } | ||||
static void | static void | ||||
pf_unload(void) | pf_unload(void) | ||||
{ | { | ||||
sx_xlock(&pf_end_lock); | sx_xlock(&pf_end_lock); | ||||
pf_end_threads = 1; | pf_end_threads = 1; | ||||
▲ Show 20 Lines • Show All 64 Lines • Show Last 20 Lines |