Changeset View
Changeset View
Standalone View
Standalone View
sys/netpfil/pf/pf_ioctl.c
Show First 20 Lines • Show All 234 Lines • ▼ Show 20 Lines | |||||
#endif | #endif | ||||
#ifdef INET6 | #ifdef INET6 | ||||
static pfil_return_t pf_check6_in(struct mbuf **m, struct ifnet *ifp, | static pfil_return_t pf_check6_in(struct mbuf **m, struct ifnet *ifp, | ||||
int flags, void *ruleset __unused, struct inpcb *inp); | int flags, void *ruleset __unused, struct inpcb *inp); | ||||
static pfil_return_t pf_check6_out(struct mbuf **m, struct ifnet *ifp, | static pfil_return_t pf_check6_out(struct mbuf **m, struct ifnet *ifp, | ||||
int flags, void *ruleset __unused, struct inpcb *inp); | int flags, void *ruleset __unused, struct inpcb *inp); | ||||
#endif | #endif | ||||
static void hook_pf_eth(void); | |||||
static void hook_pf(void); | static void hook_pf(void); | ||||
static void dehook_pf_eth(void); | |||||
static void dehook_pf(void); | static void dehook_pf(void); | ||||
static int shutdown_pf(void); | static int shutdown_pf(void); | ||||
static int pf_load(void); | static int pf_load(void); | ||||
static void pf_unload(void); | static void pf_unload(void); | ||||
static struct cdevsw pf_cdevsw = { | static struct cdevsw pf_cdevsw = { | ||||
.d_ioctl = pfioctl, | .d_ioctl = pfioctl, | ||||
.d_name = PF_NAME, | .d_name = PF_NAME, | ||||
.d_version = D_VERSION, | .d_version = D_VERSION, | ||||
}; | }; | ||||
volatile VNET_DEFINE_STATIC(int, pf_pfil_hooked); | volatile VNET_DEFINE_STATIC(int, pf_pfil_hooked); | ||||
#define V_pf_pfil_hooked VNET(pf_pfil_hooked) | #define V_pf_pfil_hooked VNET(pf_pfil_hooked) | ||||
volatile VNET_DEFINE_STATIC(int, pf_pfil_eth_hooked); | |||||
#define V_pf_pfil_eth_hooked VNET(pf_pfil_eth_hooked) | |||||
/* | /* | ||||
* We need a flag that is neither hooked nor running to know when | * We need a flag that is neither hooked nor running to know when | ||||
* the VNET is "valid". We primarily need this to control (global) | * the VNET is "valid". We primarily need this to control (global) | ||||
* external event, e.g., eventhandlers. | * external event, e.g., eventhandlers. | ||||
*/ | */ | ||||
VNET_DEFINE(int, pf_vnet_active); | VNET_DEFINE(int, pf_vnet_active); | ||||
#define V_pf_vnet_active VNET(pf_vnet_active) | #define V_pf_vnet_active VNET(pf_vnet_active) | ||||
▲ Show 20 Lines • Show All 102 Lines • ▼ Show 20 Lines | #endif | ||||
my_timeout[PFTM_TS_DIFF] = PFTM_TS_DIFF_VAL; | my_timeout[PFTM_TS_DIFF] = PFTM_TS_DIFF_VAL; | ||||
my_timeout[PFTM_ADAPTIVE_START] = PFSTATE_ADAPT_START; | my_timeout[PFTM_ADAPTIVE_START] = PFSTATE_ADAPT_START; | ||||
my_timeout[PFTM_ADAPTIVE_END] = PFSTATE_ADAPT_END; | my_timeout[PFTM_ADAPTIVE_END] = PFSTATE_ADAPT_END; | ||||
bzero(&V_pf_status, sizeof(V_pf_status)); | bzero(&V_pf_status, sizeof(V_pf_status)); | ||||
V_pf_status.debug = PF_DEBUG_URGENT; | V_pf_status.debug = PF_DEBUG_URGENT; | ||||
V_pf_pfil_hooked = 0; | V_pf_pfil_hooked = 0; | ||||
V_pf_pfil_eth_hooked = 0; | |||||
/* XXX do our best to avoid a conflict */ | /* XXX do our best to avoid a conflict */ | ||||
V_pf_status.hostid = arc4random(); | V_pf_status.hostid = arc4random(); | ||||
for (int i = 0; i < PFRES_MAX; i++) | for (int i = 0; i < PFRES_MAX; i++) | ||||
V_pf_status.counters[i] = counter_u64_alloc(M_WAITOK); | V_pf_status.counters[i] = counter_u64_alloc(M_WAITOK); | ||||
for (int i = 0; i < KLCNT_MAX; i++) | for (int i = 0; i < KLCNT_MAX; i++) | ||||
V_pf_status.lcounters[i] = counter_u64_alloc(M_WAITOK); | V_pf_status.lcounters[i] = counter_u64_alloc(M_WAITOK); | ||||
▲ Show 20 Lines • Show All 2,076 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)) | |||||
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")); | ||||
} | } | ||||
break; | break; | ||||
case DIOCSTOP: | case DIOCSTOP: | ||||
sx_xlock(&pf_ioctl_lock); | sx_xlock(&pf_ioctl_lock); | ||||
if (!V_pf_status.running) | if (!V_pf_status.running) | ||||
error = ENOENT; | error = ENOENT; | ||||
else { | else { | ||||
V_pf_status.running = 0; | V_pf_status.running = 0; | ||||
dehook_pf(); | dehook_pf(); | ||||
dehook_pf_eth(); | |||||
V_pf_status.since = time_second; | V_pf_status.since = time_second; | ||||
DPFPRINTF(PF_DEBUG_MISC, ("pf: stopped\n")); | DPFPRINTF(PF_DEBUG_MISC, ("pf: stopped\n")); | ||||
} | } | ||||
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; | ||||
▲ Show 20 Lines • Show All 2,521 Lines • ▼ Show 20 Lines | #endif /* ALTQ */ | ||||
PF_RULES_WUNLOCK(); | PF_RULES_WUNLOCK(); | ||||
free(ioes, M_TEMP); | free(ioes, M_TEMP); | ||||
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. */ | |||||
if (! TAILQ_EMPTY(&V_pf_keth->rules)) | |||||
hook_pf_eth(); | |||||
else | |||||
dehook_pf_eth(); | |||||
free(ioes, M_TEMP); | free(ioes, M_TEMP); | ||||
break; | break; | ||||
} | } | ||||
case DIOCGETSRCNODES: { | case DIOCGETSRCNODES: { | ||||
struct pfioc_src_nodes *psn = (struct pfioc_src_nodes *)addr; | struct pfioc_src_nodes *psn = (struct pfioc_src_nodes *)addr; | ||||
struct pf_srchash *sh; | struct pf_srchash *sh; | ||||
struct pf_ksrc_node *n; | struct pf_ksrc_node *n; | ||||
▲ Show 20 Lines • Show All 1,030 Lines • ▼ Show 20 Lines | |||||
#ifdef INET6 | #ifdef INET6 | ||||
VNET_DEFINE_STATIC(pfil_hook_t, pf_ip6_in_hook); | VNET_DEFINE_STATIC(pfil_hook_t, pf_ip6_in_hook); | ||||
VNET_DEFINE_STATIC(pfil_hook_t, pf_ip6_out_hook); | VNET_DEFINE_STATIC(pfil_hook_t, pf_ip6_out_hook); | ||||
#define V_pf_ip6_in_hook VNET(pf_ip6_in_hook) | #define V_pf_ip6_in_hook VNET(pf_ip6_in_hook) | ||||
#define V_pf_ip6_out_hook VNET(pf_ip6_out_hook) | #define V_pf_ip6_out_hook VNET(pf_ip6_out_hook) | ||||
#endif | #endif | ||||
static void | static void | ||||
hook_pf(void) | hook_pf_eth(void) | ||||
{ | { | ||||
struct pfil_hook_args pha; | struct pfil_hook_args pha; | ||||
struct pfil_link_args pla; | struct pfil_link_args pla; | ||||
int ret; | int ret; | ||||
if (V_pf_pfil_hooked) | if (V_pf_pfil_eth_hooked) | ||||
return; | return; | ||||
pha.pa_version = PFIL_VERSION; | pha.pa_version = PFIL_VERSION; | ||||
pha.pa_modname = "pf"; | pha.pa_modname = "pf"; | ||||
pha.pa_ruleset = NULL; | pha.pa_ruleset = NULL; | ||||
pla.pa_version = PFIL_VERSION; | pla.pa_version = PFIL_VERSION; | ||||
pha.pa_type = PFIL_TYPE_ETHERNET; | pha.pa_type = PFIL_TYPE_ETHERNET; | ||||
pha.pa_func = pf_eth_check_in; | pha.pa_func = pf_eth_check_in; | ||||
pha.pa_flags = PFIL_IN; | pha.pa_flags = PFIL_IN; | ||||
pha.pa_rulname = "eth-in"; | pha.pa_rulname = "eth-in"; | ||||
V_pf_eth_in_hook = pfil_add_hook(&pha); | V_pf_eth_in_hook = pfil_add_hook(&pha); | ||||
pla.pa_flags = PFIL_IN | PFIL_HEADPTR | PFIL_HOOKPTR; | pla.pa_flags = PFIL_IN | PFIL_HEADPTR | PFIL_HOOKPTR; | ||||
pla.pa_head = V_link_pfil_head; | pla.pa_head = V_link_pfil_head; | ||||
pla.pa_hook = V_pf_eth_in_hook; | pla.pa_hook = V_pf_eth_in_hook; | ||||
(void)pfil_link(&pla); | ret = pfil_link(&pla); | ||||
MPASS(ret == 0); | |||||
pha.pa_func = pf_eth_check_out; | pha.pa_func = pf_eth_check_out; | ||||
pha.pa_flags = PFIL_OUT; | pha.pa_flags = PFIL_OUT; | ||||
pha.pa_rulname = "eth-out"; | pha.pa_rulname = "eth-out"; | ||||
V_pf_eth_out_hook = pfil_add_hook(&pha); | V_pf_eth_out_hook = pfil_add_hook(&pha); | ||||
pla.pa_flags = PFIL_OUT | PFIL_HEADPTR | PFIL_HOOKPTR; | pla.pa_flags = PFIL_OUT | PFIL_HEADPTR | PFIL_HOOKPTR; | ||||
pla.pa_head = V_link_pfil_head; | pla.pa_head = V_link_pfil_head; | ||||
pla.pa_hook = V_pf_eth_out_hook; | pla.pa_hook = V_pf_eth_out_hook; | ||||
(void)pfil_link(&pla); | ret = pfil_link(&pla); | ||||
MPASS(ret == 0); | |||||
V_pf_pfil_eth_hooked = 1; | |||||
} | |||||
static void | |||||
hook_pf(void) | |||||
{ | |||||
struct pfil_hook_args pha; | |||||
struct pfil_link_args pla; | |||||
int ret; | |||||
if (V_pf_pfil_hooked) | |||||
return; | |||||
pha.pa_version = PFIL_VERSION; | |||||
pha.pa_modname = "pf"; | |||||
pha.pa_ruleset = NULL; | |||||
pla.pa_version = PFIL_VERSION; | |||||
#ifdef INET | #ifdef INET | ||||
pha.pa_type = PFIL_TYPE_IP4; | pha.pa_type = PFIL_TYPE_IP4; | ||||
pha.pa_func = pf_check_in; | pha.pa_func = pf_check_in; | ||||
pha.pa_flags = PFIL_IN; | pha.pa_flags = PFIL_IN; | ||||
pha.pa_rulname = "default-in"; | pha.pa_rulname = "default-in"; | ||||
V_pf_ip4_in_hook = pfil_add_hook(&pha); | V_pf_ip4_in_hook = pfil_add_hook(&pha); | ||||
pla.pa_flags = PFIL_IN | PFIL_HEADPTR | PFIL_HOOKPTR; | pla.pa_flags = PFIL_IN | PFIL_HEADPTR | PFIL_HOOKPTR; | ||||
pla.pa_head = V_inet_pfil_head; | pla.pa_head = V_inet_pfil_head; | ||||
Show All 31 Lines | #ifdef INET6 | ||||
ret = pfil_link(&pla); | ret = pfil_link(&pla); | ||||
MPASS(ret == 0); | MPASS(ret == 0); | ||||
#endif | #endif | ||||
V_pf_pfil_hooked = 1; | V_pf_pfil_hooked = 1; | ||||
} | } | ||||
static void | static void | ||||
dehook_pf(void) | dehook_pf_eth(void) | ||||
{ | { | ||||
if (V_pf_pfil_hooked == 0) | if (V_pf_pfil_eth_hooked == 0) | ||||
return; | return; | ||||
pfil_remove_hook(V_pf_eth_in_hook); | pfil_remove_hook(V_pf_eth_in_hook); | ||||
pfil_remove_hook(V_pf_eth_out_hook); | pfil_remove_hook(V_pf_eth_out_hook); | ||||
V_pf_pfil_eth_hooked = 0; | |||||
} | |||||
static void | |||||
dehook_pf(void) | |||||
{ | |||||
if (V_pf_pfil_hooked == 0) | |||||
return; | |||||
#ifdef INET | #ifdef INET | ||||
pfil_remove_hook(V_pf_ip4_in_hook); | pfil_remove_hook(V_pf_ip4_in_hook); | ||||
pfil_remove_hook(V_pf_ip4_out_hook); | pfil_remove_hook(V_pf_ip4_out_hook); | ||||
#endif | #endif | ||||
#ifdef INET6 | #ifdef INET6 | ||||
pfil_remove_hook(V_pf_ip6_in_hook); | pfil_remove_hook(V_pf_ip6_in_hook); | ||||
pfil_remove_hook(V_pf_ip6_out_hook); | pfil_remove_hook(V_pf_ip6_out_hook); | ||||
#endif | #endif | ||||
▲ Show 20 Lines • Show All 50 Lines • ▼ Show 20 Lines | |||||
static void | static void | ||||
pf_unload_vnet(void) | pf_unload_vnet(void) | ||||
{ | { | ||||
int ret; | int ret; | ||||
V_pf_vnet_active = 0; | V_pf_vnet_active = 0; | ||||
V_pf_status.running = 0; | V_pf_status.running = 0; | ||||
dehook_pf(); | dehook_pf(); | ||||
dehook_pf_eth(); | |||||
PF_RULES_WLOCK(); | PF_RULES_WLOCK(); | ||||
pf_syncookies_cleanup(); | pf_syncookies_cleanup(); | ||||
shutdown_pf(); | shutdown_pf(); | ||||
PF_RULES_WUNLOCK(); | PF_RULES_WUNLOCK(); | ||||
ret = swi_remove(V_pf_swi_cookie); | ret = swi_remove(V_pf_swi_cookie); | ||||
MPASS(ret == 0); | MPASS(ret == 0); | ||||
▲ Show 20 Lines • Show All 139 Lines • Show Last 20 Lines |