diff options
author | Martin Willi <martin@revosec.ch> | 2013-12-20 14:42:10 +0100 |
---|---|---|
committer | Martin Willi <martin@revosec.ch> | 2014-06-04 16:32:10 +0200 |
commit | 6de788704b0cb4b087719341f0900b1b1992cdb0 (patch) | |
tree | 77c157f66eaeb7def9e567145032568b90302808 /src | |
parent | 1678f0a999bed5e486b56824381332a85c505033 (diff) | |
download | strongswan-6de788704b0cb4b087719341f0900b1b1992cdb0.tar.bz2 strongswan-6de788704b0cb4b087719341f0900b1b1992cdb0.tar.xz |
kernel-wfp: Install tunnel and trap forward policies
Diffstat (limited to 'src')
-rw-r--r-- | src/libcharon/plugins/kernel_wfp/ipsecdump.c | 26 | ||||
-rw-r--r-- | src/libcharon/plugins/kernel_wfp/kernel_wfp_compat.c | 24 | ||||
-rw-r--r-- | src/libcharon/plugins/kernel_wfp/kernel_wfp_ipsec.c | 361 |
3 files changed, 275 insertions, 136 deletions
diff --git a/src/libcharon/plugins/kernel_wfp/ipsecdump.c b/src/libcharon/plugins/kernel_wfp/ipsecdump.c index 55e64fe93..7ca7df5a1 100644 --- a/src/libcharon/plugins/kernel_wfp/ipsecdump.c +++ b/src/libcharon/plugins/kernel_wfp/ipsecdump.c @@ -92,13 +92,6 @@ static char *guid2string(GUID *guid) return buf; } -const GUID FWPM_CONDITION_IP_SOURCE_ADDRESS = { - 0xae96897e, 0x2e94, 0x4bc9, { 0xb3,0x13,0xb2,0x7e,0xe8,0x0e,0x57,0x4d } -}; -const GUID FWPM_CONDITION_IP_DESTINATION_ADDRESS = { - 0x2d79133b, 0xb390, 0x45c6, { 0x86,0x99,0xac,0xac,0xea,0xaf,0xed,0x33 } -}; - /** * Convert filter condition key GUID to some known strings */ @@ -431,15 +424,9 @@ const GUID FWPM_LAYER_OUTBOUND_IPPACKET_V6 = { const GUID FWPM_LAYER_OUTBOUND_IPPACKET_V6_DISCARD = { 0x9513d7c4, 0xa934, 0x49dc, { 0x91, 0xa7, 0x6c, 0xcb, 0x80, 0xcc, 0x02, 0xe3 } }; -const GUID FWPM_LAYER_IPFORWARD_V4 = { - 0xa82acc24, 0x4ee1, 0x4ee1, { 0xb4, 0x65, 0xfd, 0x1d, 0x25, 0xcb, 0x10, 0xa4 } -}; const GUID FWPM_LAYER_IPFORWARD_V4_DISCARD = { 0x9e9ea773, 0x2fae, 0x4210, { 0x8f, 0x17, 0x34, 0x12, 0x9e, 0xf3, 0x69, 0xeb } }; -const GUID FWPM_LAYER_IPFORWARD_V6 = { - 0x7b964818, 0x19c7, 0x493a, { 0xb7, 0x1f, 0x83, 0x2c, 0x36, 0x84, 0xd2, 0x8c } -}; const GUID FWPM_LAYER_IPFORWARD_V6_DISCARD = { 0x31524a5d, 0x1dfe, 0x472f, { 0xbb, 0x93, 0x51, 0x8e, 0xe9, 0x45, 0xd8, 0xa2 } }; @@ -504,19 +491,6 @@ static char* layer2name(GUID *guid) return NULL; } -const GUID FWPM_CALLOUT_IPSEC_FORWARD_INBOUND_TUNNEL_V4 = { - 0x28829633, 0xc4f0, 0x4e66, { 0x87,0x3f,0x84,0x4d,0xb2,0xa8,0x99,0xc7 } -}; -const GUID FWPM_CALLOUT_IPSEC_FORWARD_INBOUND_TUNNEL_V6 = { - 0xaf50bec2, 0xc686, 0x429a, { 0x88,0x4d,0xb7,0x44,0x43,0xe7,0xb0,0xb4 } -}; -const GUID FWPM_CALLOUT_IPSEC_FORWARD_OUTBOUND_TUNNEL_V4 = { - 0xfb532136, 0x15cb, 0x440b, { 0x93,0x7c,0x17,0x17,0xca,0x32,0x0c,0x40 } -}; -const GUID FWPM_CALLOUT_IPSEC_FORWARD_OUTBOUND_TUNNEL_V6 = { - 0xdae640cc, 0xe021, 0x4bee, { 0x9e,0xb6,0xa4,0x8b,0x27,0x5c,0x8c,0x1d } -}; - /** * Convert filter callout GUID to name */ diff --git a/src/libcharon/plugins/kernel_wfp/kernel_wfp_compat.c b/src/libcharon/plugins/kernel_wfp/kernel_wfp_compat.c index 3660ac9d6..41f85ba5c 100644 --- a/src/libcharon/plugins/kernel_wfp/kernel_wfp_compat.c +++ b/src/libcharon/plugins/kernel_wfp/kernel_wfp_compat.c @@ -21,6 +21,12 @@ const GUID FWPM_CONDITION_IP_REMOTE_ADDRESS = { const GUID FWPM_CONDITION_IP_LOCAL_ADDRESS = { 0xd9ee00de, 0xc1ef, 0x4617, { 0xbf,0xe3,0xff,0xd8,0xf5,0xa0,0x89,0x57 } }; +const GUID FWPM_CONDITION_IP_SOURCE_ADDRESS = { + 0xae96897e, 0x2e94, 0x4bc9, { 0xb3,0x13,0xb2,0x7e,0xe8,0x0e,0x57,0x4d } +}; +const GUID FWPM_CONDITION_IP_DESTINATION_ADDRESS = { + 0x2d79133b, 0xb390, 0x45c6, { 0x86,0x99,0xac,0xac,0xea,0xaf,0xed,0x33 } +}; const GUID FWPM_CONDITION_IP_LOCAL_PORT = { 0x0c1ba1af, 0x5765, 0x453f, { 0xaf,0x22,0xa8,0xf7,0x91,0xac,0x77,0x5b } }; @@ -42,6 +48,12 @@ const GUID FWPM_LAYER_OUTBOUND_TRANSPORT_V4 = { const GUID FWPM_LAYER_OUTBOUND_TRANSPORT_V6 = { 0xe1735bde, 0x013f, 0x4655, { 0xb3,0x51,0xa4,0x9e,0x15,0x76,0x2d,0xf0 } }; +const GUID FWPM_LAYER_IPFORWARD_V4 = { + 0xa82acc24, 0x4ee1, 0x4ee1, { 0xb4,0x65,0xfd,0x1d,0x25,0xcb,0x10,0xa4} +}; +const GUID FWPM_LAYER_IPFORWARD_V6 = { + 0x7b964818, 0x19c7, 0x493a, { 0xb7,0x1f,0x83,0x2c,0x36,0x84,0xd2,0x8c } +}; const GUID FWPM_CALLOUT_IPSEC_INBOUND_TRANSPORT_V4 = { 0x5132900d, 0x5e84, 0x4b5f, { 0x80,0xe4,0x01,0x74,0x1e,0x81,0xff,0x10 } }; @@ -66,6 +78,18 @@ const GUID FWPM_CALLOUT_IPSEC_OUTBOUND_TUNNEL_V4 = { const GUID FWPM_CALLOUT_IPSEC_OUTBOUND_TUNNEL_V6 = { 0xf1835363, 0xa6a5, 0x4e62, { 0xb1,0x80,0x23,0xdb,0x78,0x9d,0x8d,0xa6 } }; +const GUID FWPM_CALLOUT_IPSEC_FORWARD_INBOUND_TUNNEL_V4 = { + 0x28829633, 0xc4f0, 0x4e66, { 0x87,0x3f,0x84,0x4d,0xb2,0xa8,0x99,0xc7 } +}; +const GUID FWPM_CALLOUT_IPSEC_FORWARD_INBOUND_TUNNEL_V6 = { + 0xaf50bec2, 0xc686, 0x429a, { 0x88,0x4d,0xb7,0x44,0x43,0xe7,0xb0,0xb4 } +}; +const GUID FWPM_CALLOUT_IPSEC_FORWARD_OUTBOUND_TUNNEL_V4 = { + 0xfb532136, 0x15cb, 0x440b, { 0x93,0x7c,0x17,0x17,0xca,0x32,0x0c,0x40 } +}; +const GUID FWPM_CALLOUT_IPSEC_FORWARD_OUTBOUND_TUNNEL_V6 = { + 0xdae640cc, 0xe021, 0x4bee, { 0x9e,0xb6,0xa4,0x8b,0x27,0x5c,0x8c,0x1d } +}; /** * Load a function symbol from a loaded dll diff --git a/src/libcharon/plugins/kernel_wfp/kernel_wfp_ipsec.c b/src/libcharon/plugins/kernel_wfp/kernel_wfp_ipsec.c index 5c956ea69..b6d7d7a58 100644 --- a/src/libcharon/plugins/kernel_wfp/kernel_wfp_ipsec.c +++ b/src/libcharon/plugins/kernel_wfp/kernel_wfp_ipsec.c @@ -178,6 +178,10 @@ typedef struct { u_int64_t policy_in; /** WFP allocated LUID for outbound filter ID */ u_int64_t policy_out; + /** WFP allocated LUID for forward inbound filter ID, tunnel mode only */ + u_int64_t policy_fwd_in; + /** WFP allocated LUID for forward outbound filter ID, tunnel mode only */ + u_int64_t policy_fwd_out; /** provider context, for tunnel mode only */ u_int64_t provider; /** WFP allocated LUID for SA context */ @@ -252,6 +256,16 @@ static void cleanup_policies(private_kernel_wfp_ipsec_t *this, entry_t *entry) if (entry->mode == MODE_TUNNEL) { manage_routes(this, entry, FALSE); + if (entry->policy_fwd_in) + { + FwpmFilterDeleteById0(this->handle, entry->policy_fwd_in); + entry->policy_fwd_in = 0; + } + if (entry->policy_fwd_out) + { + FwpmFilterDeleteById0(this->handle, entry->policy_fwd_out); + entry->policy_fwd_out = 0; + } } } @@ -343,7 +357,7 @@ static void range2cond(FWPM_FILTER_CONDITION0 *cond, /** * (Re-)allocate filter conditions for given local or remote traffic selector */ -static bool ts2condition(traffic_selector_t *ts, bool local, +static bool ts2condition(traffic_selector_t *ts, const GUID *target, FWPM_FILTER_CONDITION0 *conds[], int *count) { FWPM_FILTER_CONDITION0 *cond; @@ -361,14 +375,7 @@ static bool ts2condition(traffic_selector_t *ts, bool local, to_port = ts->get_to_port(ts); cond = append_condition(conds, count); - if (local) - { - cond->fieldKey = FWPM_CONDITION_IP_LOCAL_ADDRESS; - } - else - { - cond->fieldKey = FWPM_CONDITION_IP_REMOTE_ADDRESS; - } + cond->fieldKey = *target; if (ts->is_host(ts, NULL)) { cond->matchType = FWP_MATCH_EQUAL; @@ -440,7 +447,7 @@ static bool ts2condition(traffic_selector_t *ts, bool local, } proto = ts->get_protocol(ts); - if (proto && local) + if (proto && target == &FWPM_CONDITION_IP_LOCAL_ADDRESS) { cond = append_condition(conds, count); cond->fieldKey = FWPM_CONDITION_IP_PROTOCOL; @@ -451,7 +458,7 @@ static bool ts2condition(traffic_selector_t *ts, bool local, if (proto == IPPROTO_ICMP) { - if (local) + if (target == &FWPM_CONDITION_IP_LOCAL_ADDRESS) { u_int8_t from_type, to_type, from_code, to_code; @@ -476,16 +483,18 @@ static bool ts2condition(traffic_selector_t *ts, bool local, } else if (from_port != 0 || to_port != 0xFFFF) { - cond = append_condition(conds, count); - if (local) + if (target == &FWPM_CONDITION_IP_LOCAL_ADDRESS) { + cond = append_condition(conds, count); cond->fieldKey = FWPM_CONDITION_IP_LOCAL_PORT; + range2cond(cond, from_port, to_port); } - else + if (target == &FWPM_CONDITION_IP_REMOTE_ADDRESS) { + cond = append_condition(conds, count); cond->fieldKey = FWPM_CONDITION_IP_REMOTE_PORT; + range2cond(cond, from_port, to_port); } - range2cond(cond, from_port, to_port); } return TRUE; } @@ -530,16 +539,72 @@ static void free_conditions(FWPM_FILTER_CONDITION0 *conds, int count) } /** + * Find the callout GUID for given parameters + */ +static bool find_callout(bool tunnel, bool v6, bool inbound, bool forward, + GUID *layer, GUID *callout) +{ + struct { + bool tunnel; + bool v6; + bool inbound; + bool forward; + const GUID *layer; + const GUID *callout; + } map[] = { + { 0, 0, 0, 0, &FWPM_LAYER_OUTBOUND_TRANSPORT_V4, + &FWPM_CALLOUT_IPSEC_OUTBOUND_TRANSPORT_V4 }, + { 0, 0, 1, 0, &FWPM_LAYER_INBOUND_TRANSPORT_V4, + &FWPM_CALLOUT_IPSEC_INBOUND_TRANSPORT_V4 }, + { 0, 1, 0, 0, &FWPM_LAYER_OUTBOUND_TRANSPORT_V6, + &FWPM_CALLOUT_IPSEC_OUTBOUND_TRANSPORT_V6 }, + { 0, 1, 1, 0, &FWPM_LAYER_INBOUND_TRANSPORT_V6, + &FWPM_CALLOUT_IPSEC_INBOUND_TRANSPORT_V6 }, + { 1, 0, 0, 0, &FWPM_LAYER_OUTBOUND_TRANSPORT_V4, + &FWPM_CALLOUT_IPSEC_OUTBOUND_TUNNEL_V4 }, + { 1, 0, 0, 1, &FWPM_LAYER_IPFORWARD_V4, + &FWPM_CALLOUT_IPSEC_FORWARD_OUTBOUND_TUNNEL_V4 }, + { 1, 0, 1, 0, &FWPM_LAYER_INBOUND_TRANSPORT_V4, + &FWPM_CALLOUT_IPSEC_INBOUND_TUNNEL_V4 }, + { 1, 0, 1, 1, &FWPM_LAYER_IPFORWARD_V4, + &FWPM_CALLOUT_IPSEC_FORWARD_INBOUND_TUNNEL_V4 }, + { 1, 1, 0, 0, &FWPM_LAYER_OUTBOUND_TRANSPORT_V6, + &FWPM_CALLOUT_IPSEC_OUTBOUND_TUNNEL_V6 }, + { 1, 1, 0, 1, &FWPM_LAYER_IPFORWARD_V6, + &FWPM_CALLOUT_IPSEC_FORWARD_OUTBOUND_TUNNEL_V6 }, + { 1, 1, 1, 0, &FWPM_LAYER_INBOUND_TRANSPORT_V6, + &FWPM_CALLOUT_IPSEC_INBOUND_TUNNEL_V6 }, + { 1, 1, 1, 1, &FWPM_LAYER_IPFORWARD_V6, + &FWPM_CALLOUT_IPSEC_FORWARD_INBOUND_TUNNEL_V6 }, + }; + int i; + + for (i = 0; i < countof(map); i++) + { + if (tunnel == map[i].tunnel && + v6 == map[i].v6 && + inbound == map[i].inbound && + forward == map[i].forward) + { + *callout = *map[i].callout; + *layer = *map[i].layer; + return TRUE; + } + } + return FALSE; +} + +/** * Install a single policy in to the kernel */ -static bool install_sp(private_kernel_wfp_ipsec_t *this, - entry_t *entry, GUID *context, bool inbound) +static bool install_sp(private_kernel_wfp_ipsec_t *this, sp_entry_t *sp, + GUID *context, bool inbound, bool fwd, UINT64 *filter_id) { FWPM_FILTER_CONDITION0 *conds = NULL; - int count = 0; - enumerator_t *enumerator; traffic_selector_t *local, *remote; - sp_entry_t *sp; + const GUID *ltarget, *rtarget; + int count = 0; + bool v6; DWORD res; FWPM_FILTER0 filter = { .displayData = { @@ -548,78 +613,111 @@ static bool install_sp(private_kernel_wfp_ipsec_t *this, .action = { .type = FWP_ACTION_CALLOUT_TERMINATING, }, - .layerKey = inbound ? FWPM_LAYER_INBOUND_TRANSPORT_V4 : - FWPM_LAYER_OUTBOUND_TRANSPORT_V4, }; if (context) { - if (inbound) - { - filter.action.calloutKey = FWPM_CALLOUT_IPSEC_INBOUND_TUNNEL_V4; - } - else - { - filter.action.calloutKey = FWPM_CALLOUT_IPSEC_OUTBOUND_TUNNEL_V4; - } filter.flags |= FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT; - filter.providerKey = (GUID*)&this->provider.providerKey, - memcpy(&filter.providerContextKey, context, sizeof(GUID)); + filter.providerKey = (GUID*)&this->provider.providerKey; + filter.providerContextKey = *context; + } + + v6 = sp->src->get_type(sp->src) == TS_IPV6_ADDR_RANGE; + if (!find_callout(context != NULL, v6, inbound, fwd, + &filter.layerKey, &filter.action.calloutKey)) + { + return FALSE; + } + + if (inbound && fwd) + { + local = sp->dst; + remote = sp->src; } else { - if (inbound) - { - filter.action.calloutKey = FWPM_CALLOUT_IPSEC_INBOUND_TRANSPORT_V4; - } - else - { - filter.action.calloutKey = FWPM_CALLOUT_IPSEC_OUTBOUND_TRANSPORT_V4; - } + local = sp->src; + remote = sp->dst; + } + if (fwd) + { + ltarget = &FWPM_CONDITION_IP_SOURCE_ADDRESS; + rtarget = &FWPM_CONDITION_IP_DESTINATION_ADDRESS; + } + else + { + ltarget = &FWPM_CONDITION_IP_LOCAL_ADDRESS; + rtarget = &FWPM_CONDITION_IP_REMOTE_ADDRESS; } + if (!ts2condition(local, ltarget, &conds, &count) || + !ts2condition(remote, rtarget, &conds, &count)) + { + free_conditions(conds, count); + return FALSE; + } + + filter.numFilterConditions = count; + filter.filterCondition = conds; + + res = FwpmFilterAdd0(this->handle, &filter, NULL, filter_id); + free_conditions(conds, count); + if (res != ERROR_SUCCESS) + { + DBG1(DBG_KNL, "installing %s%sbound WFP filter failed: 0x%08x", + fwd ? "forward " : "", inbound ? "in" : "out", res); + return FALSE; + } + return TRUE; +} + +/** + * Install a set of policies in to the kernel + */ +static bool install_sps(private_kernel_wfp_ipsec_t *this, + entry_t *entry, GUID *context) +{ + enumerator_t *enumerator; + sp_entry_t *sp; enumerator = array_create_enumerator(entry->sps); while (enumerator->enumerate(enumerator, &sp)) { - if (inbound) + /* inbound policy */ + if (!install_sp(this, sp, context, TRUE, FALSE, &entry->policy_in)) { - local = sp->dst; - remote = sp->src; - } - else - { - local = sp->src; - remote = sp->dst; + enumerator->destroy(enumerator); + return FALSE; } - - if (!ts2condition(local, TRUE, &conds, &count) || - !ts2condition(remote, FALSE, &conds, &count)) + /* outbound policy */ + if (!install_sp(this, sp, context, FALSE, FALSE, &entry->policy_out)) { - free_conditions(conds, count); enumerator->destroy(enumerator); return FALSE; } + if (context) + { + if (!sp->src->is_host(sp->src, entry->local) || + !sp->dst->is_host(sp->dst, entry->remote)) + { + /* inbound forward policy, from decapsulation */ + if (!install_sp(this, sp, context, + TRUE, TRUE, &entry->policy_fwd_in)) + { + enumerator->destroy(enumerator); + return FALSE; + } + /* outbound forward policy, to encapsulate */ + if (!install_sp(this, sp, context, + FALSE, TRUE, &entry->policy_fwd_out)) + { + enumerator->destroy(enumerator); + return FALSE; + } + } + } } enumerator->destroy(enumerator); - filter.numFilterConditions = count; - filter.filterCondition = conds; - - if (inbound) - { - res = FwpmFilterAdd0(this->handle, &filter, NULL, &entry->policy_in); - } - else - { - res = FwpmFilterAdd0(this->handle, &filter, NULL, &entry->policy_out); - } - free_conditions(conds, count); - if (res != ERROR_SUCCESS) - { - DBG1(DBG_KNL, "installing %sbound FWP filter failed: 0x%08x", - inbound ? "in" : "out", res); - return FALSE; - } return TRUE; } @@ -971,8 +1069,7 @@ static bool install_sas(private_kernel_wfp_ipsec_t *this, entry_t *entry, */ static bool install_transport(private_kernel_wfp_ipsec_t *this, entry_t *entry) { - if (install_sp(this, entry, NULL, TRUE) && - install_sp(this, entry, NULL, FALSE) && + if (install_sps(this, entry, NULL) && install_sas(this, entry, IPSEC_TRAFFIC_TYPE_TRANSPORT)) { return TRUE; @@ -1000,9 +1097,10 @@ static bool generate_guid(private_kernel_wfp_ipsec_t *this, GUID *guid) } /** - * Install tunnel mode SPs to the kernel + * Register a dummy tunnel provider to associate tunnel filters to */ -static bool install_tunnel_sps(private_kernel_wfp_ipsec_t *this, entry_t *entry) +static bool add_tunnel_provider(private_kernel_wfp_ipsec_t *this, + entry_t *entry, GUID *guid, UINT64 *luid) { DWORD res; @@ -1037,7 +1135,7 @@ static bool install_tunnel_sps(private_kernel_wfp_ipsec_t *this, entry_t *entry) }; FWPM_PROVIDER_CONTEXT0 qm = { .displayData = { - .name = L"charon tunnel provider context", + .name = L"charon tunnel provider", }, .providerKey = (GUID*)&this->provider.providerKey, .type = FWPM_IPSEC_IKE_QM_TUNNEL_CONTEXT, @@ -1055,10 +1153,8 @@ static bool install_tunnel_sps(private_kernel_wfp_ipsec_t *this, entry_t *entry) break; case AF_INET6: policy.tunnelEndpoints.ipVersion = FWP_IP_VERSION_V6; - memcpy(&policy.tunnelEndpoints.localV6Address, - entry->local->get_address(entry->local).ptr, 16); - memcpy(&policy.tunnelEndpoints.remoteV6Address, - entry->remote->get_address(entry->remote).ptr, 16); + host2address6(entry->local, &policy.tunnelEndpoints.localV6Address); + host2address6(entry->remote, &policy.tunnelEndpoints.remoteV6Address); break; default: return FALSE; @@ -1069,15 +1165,28 @@ static bool install_tunnel_sps(private_kernel_wfp_ipsec_t *this, entry_t *entry) return FALSE; } - res = FwpmProviderContextAdd0(this->handle, &qm, NULL, &entry->provider); + res = FwpmProviderContextAdd0(this->handle, &qm, NULL, luid); if (res != ERROR_SUCCESS) { DBG1(DBG_KNL, "adding provider context failed: 0x%08x", res); return FALSE; } + *guid = qm.providerContextKey; + return TRUE; +} - if (!install_sp(this, entry, &qm.providerContextKey, TRUE) || - !install_sp(this, entry, &qm.providerContextKey, FALSE)) +/** + * Install tunnel mode SPs to the kernel + */ +static bool install_tunnel_sps(private_kernel_wfp_ipsec_t *this, entry_t *entry) +{ + GUID guid; + + if (!add_tunnel_provider(this, entry, &guid, &entry->provider)) + { + return FALSE; + } + if (!install_sps(this, entry, &guid)) { return FALSE; } @@ -1267,10 +1376,12 @@ static bool install(private_kernel_wfp_ipsec_t *this, entry_t *entry) typedef struct { /** reqid this trap is installed for */ u_int32_t reqid; - /** local traffic selector */ - traffic_selector_t *local; - /** remote traffic selector */ - traffic_selector_t *remote; + /** is this a forward policy trap for tunnel mode? */ + bool fwd; + /** src traffic selector */ + traffic_selector_t *src; + /** dst traffic selector */ + traffic_selector_t *dst; /** LUID of installed tunnel policy filter */ UINT64 filter_id; } trap_t; @@ -1280,8 +1391,8 @@ typedef struct { */ static void destroy_trap(trap_t *this) { - this->local->destroy(this->local); - this->remote->destroy(this->remote); + this->src->destroy(this->src); + this->dst->destroy(this->dst); free(this); } @@ -1438,6 +1549,7 @@ static bool install_trap(private_kernel_wfp_ipsec_t *this, trap_t *trap) FWPM_FILTER_CONDITION0 *conds = NULL; int count = 0; DWORD res; + const GUID *starget, *dtarget; UINT64 weight = 0x000000000000ff00; FWPM_FILTER0 filter = { .displayData = { @@ -1452,18 +1564,35 @@ static bool install_trap(private_kernel_wfp_ipsec_t *this, trap_t *trap) }, }; - switch (trap->local->get_type(trap->local)) + if (trap->fwd) { - case TS_IPV4_ADDR_RANGE: + if (trap->src->get_type(trap->src) == TS_IPV4_ADDR_RANGE) + { + filter.layerKey = FWPM_LAYER_IPFORWARD_V4; + } + else + { + filter.layerKey = FWPM_LAYER_IPFORWARD_V6; + } + starget = &FWPM_CONDITION_IP_SOURCE_ADDRESS; + dtarget = &FWPM_CONDITION_IP_DESTINATION_ADDRESS; + } + else + { + if (trap->src->get_type(trap->src) == TS_IPV4_ADDR_RANGE) + { filter.layerKey = FWPM_LAYER_OUTBOUND_TRANSPORT_V4; - break; - case TS_IPV6_ADDR_RANGE: + } + else + { filter.layerKey = FWPM_LAYER_OUTBOUND_TRANSPORT_V6; - break; + } + starget = &FWPM_CONDITION_IP_LOCAL_ADDRESS; + dtarget = &FWPM_CONDITION_IP_REMOTE_ADDRESS; } - if (!ts2condition(trap->local, TRUE, &conds, &count) || - !ts2condition(trap->remote, FALSE, &conds, &count)) + if (!ts2condition(trap->src, starget, &conds, &count) || + !ts2condition(trap->dst, dtarget, &conds, &count)) { free_conditions(conds, count); return FALSE; @@ -1476,7 +1605,7 @@ static bool install_trap(private_kernel_wfp_ipsec_t *this, trap_t *trap) free_conditions(conds, count); if (res != ERROR_SUCCESS) { - DBG1(DBG_KNL, "installing FWP trap filter failed: 0x%08x", res); + DBG1(DBG_KNL, "installing WFP trap filter failed: 0x%08x", res); return FALSE; } return TRUE; @@ -1492,7 +1621,7 @@ static bool uninstall_trap(private_kernel_wfp_ipsec_t *this, trap_t *trap) res = FwpmFilterDeleteById0(this->handle, trap->filter_id); if (res != ERROR_SUCCESS) { - DBG1(DBG_KNL, "uninstalling FWP trap filter failed: 0x%08x", res); + DBG1(DBG_KNL, "uninstalling WFP trap filter failed: 0x%08x", res); return FALSE; } return TRUE; @@ -1501,15 +1630,17 @@ static bool uninstall_trap(private_kernel_wfp_ipsec_t *this, trap_t *trap) /** * Create and install a new trap entry */ -static bool add_trap(private_kernel_wfp_ipsec_t *this, u_int32_t reqid, - traffic_selector_t *local, traffic_selector_t *remote) +static bool add_trap(private_kernel_wfp_ipsec_t *this, + u_int32_t reqid, bool fwd, + traffic_selector_t *src, traffic_selector_t *dst) { trap_t *trap; INIT(trap, .reqid = reqid, - .local = local->clone(local), - .remote = remote->clone(remote), + .fwd = fwd, + .src = src->clone(src), + .dst = dst->clone(dst), ); if (!install_trap(this, trap)) @@ -1526,8 +1657,9 @@ static bool add_trap(private_kernel_wfp_ipsec_t *this, u_int32_t reqid, /** * Uninstall and remove a new trap entry */ -static bool remove_trap(private_kernel_wfp_ipsec_t *this, u_int32_t reqid, - traffic_selector_t *local, traffic_selector_t *remote) +static bool remove_trap(private_kernel_wfp_ipsec_t *this, + u_int32_t reqid, bool fwd, + traffic_selector_t *src, traffic_selector_t *dst) { enumerator_t *enumerator; trap_t *trap, *found = NULL; @@ -1537,8 +1669,9 @@ static bool remove_trap(private_kernel_wfp_ipsec_t *this, u_int32_t reqid, while (enumerator->enumerate(enumerator, NULL, &trap)) { if (reqid == trap->reqid && - local->equals(local, trap->local) && - remote->equals(remote, trap->remote)) + fwd == trap->fwd && + src->equals(src, trap->src) && + dst->equals(dst, trap->dst)) { this->traps->remove_at(this->traps, enumerator); found = trap; @@ -2014,11 +2147,18 @@ METHOD(kernel_ipsec_t, add_policy, status_t, case POLICY_PRIORITY_DEFAULT: break; case POLICY_PRIORITY_ROUTED: - if (add_trap(this, sa->reqid, src_ts, dst_ts)) + if (!add_trap(this, sa->reqid, FALSE, src_ts, dst_ts)) + { + return FAILED; + } + if (sa->mode == MODE_TUNNEL) { - return SUCCESS; + if (!add_trap(this, sa->reqid, TRUE, src_ts, dst_ts)) + { + return FAILED; + } } - return FAILED; + return SUCCESS; case POLICY_PRIORITY_FALLBACK: default: return NOT_SUPPORTED; @@ -2074,8 +2214,9 @@ METHOD(kernel_ipsec_t, del_policy, status_t, { if (direction == POLICY_OUT && priority == POLICY_PRIORITY_ROUTED) { - if (remove_trap(this, reqid, src_ts, dst_ts)) + if (remove_trap(this, reqid, FALSE, src_ts, dst_ts)) { + remove_trap(this, reqid, TRUE, src_ts, dst_ts); return SUCCESS; } return NOT_FOUND; @@ -2146,7 +2287,7 @@ static bool add_bypass(private_kernel_wfp_ipsec_t *this, free_conditions(conds, count); if (res != ERROR_SUCCESS) { - DBG1(DBG_KNL, "installing FWP trap filter failed: 0x%08x", res); + DBG1(DBG_KNL, "installing WFP bypass filter failed: 0x%08x", res); return FALSE; } return TRUE; |