diff options
Diffstat (limited to 'src/libcharon/plugins/kernel_wfp/kernel_wfp_ipsec.c')
-rw-r--r-- | src/libcharon/plugins/kernel_wfp/kernel_wfp_ipsec.c | 118 |
1 files changed, 51 insertions, 67 deletions
diff --git a/src/libcharon/plugins/kernel_wfp/kernel_wfp_ipsec.c b/src/libcharon/plugins/kernel_wfp/kernel_wfp_ipsec.c index ac038e16b..5c956ea69 100644 --- a/src/libcharon/plugins/kernel_wfp/kernel_wfp_ipsec.c +++ b/src/libcharon/plugins/kernel_wfp/kernel_wfp_ipsec.c @@ -174,10 +174,12 @@ typedef struct { ipsec_mode_t mode; /** UDP encapsulation */ bool encap; - /** WFP allocated LUID for inbound filter/tunnel policy ID */ + /** WFP allocated LUID for inbound filter ID */ u_int64_t policy_in; - /** WFP allocated LUID for outbound filter ID, unused for tunnel mode */ + /** WFP allocated LUID for outbound filter ID */ u_int64_t policy_out; + /** provider context, for tunnel mode only */ + u_int64_t provider; /** WFP allocated LUID for SA context */ u_int64_t sa_id; } entry_t; @@ -233,41 +235,18 @@ static bool manage_routes(private_kernel_wfp_ipsec_t *this, entry_t *entry, bool add); /** - * Remove a transport or tunnel policy from kernel - */ -static void cleanup_policy(private_kernel_wfp_ipsec_t *this, bool transport, - u_int64_t policy) -{ - if (transport) - { - FwpmFilterDeleteById0(this->handle, policy); - } - else - { - FWPM_PROVIDER_CONTEXT0 *ctx; - - if (FwpmProviderContextGetById0(this->handle, policy, - &ctx) == ERROR_SUCCESS) - { - FwpmIPsecTunnelDeleteByKey0(this->handle, &ctx->providerContextKey); - FwpmFreeMemory0((void**)&ctx); - } - } -} - -/** * Remove policies associated to an entry from kernel */ static void cleanup_policies(private_kernel_wfp_ipsec_t *this, entry_t *entry) { if (entry->policy_in) { - cleanup_policy(this, entry->mode == MODE_TRANSPORT, entry->policy_in); + FwpmFilterDeleteById0(this->handle, entry->policy_in); entry->policy_in = 0; } if (entry->policy_out) { - cleanup_policy(this, entry->mode == MODE_TRANSPORT, entry->policy_out); + FwpmFilterDeleteById0(this->handle, entry->policy_out); entry->policy_out = 0; } if (entry->mode == MODE_TUNNEL) @@ -285,6 +264,10 @@ static void entry_destroy(private_kernel_wfp_ipsec_t *this, entry_t *entry) { IPsecSaContextDeleteById0(this->handle, entry->sa_id); } + if (entry->provider) + { + FwpmProviderContextDeleteById0(this->handle, entry->provider); + } cleanup_policies(this, entry); array_destroy_function(entry->sps, (void*)sp_entry_destroy, NULL); entry->local->destroy(entry->local); @@ -547,10 +530,10 @@ static void free_conditions(FWPM_FILTER_CONDITION0 *conds, int count) } /** - * Install transport mode SP to the kernel + * Install a single policy in to the kernel */ -static bool install_transport_sp(private_kernel_wfp_ipsec_t *this, - entry_t *entry, bool inbound) +static bool install_sp(private_kernel_wfp_ipsec_t *this, + entry_t *entry, GUID *context, bool inbound) { FWPM_FILTER_CONDITION0 *conds = NULL; int count = 0; @@ -560,17 +543,41 @@ static bool install_transport_sp(private_kernel_wfp_ipsec_t *this, DWORD res; FWPM_FILTER0 filter = { .displayData = { - .name = L"charon IPsec transport", + .name = L"charon IPsec policy", }, .action = { .type = FWP_ACTION_CALLOUT_TERMINATING, - .calloutKey = inbound ? FWPM_CALLOUT_IPSEC_INBOUND_TRANSPORT_V4 : - FWPM_CALLOUT_IPSEC_OUTBOUND_TRANSPORT_V4, }, .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)); + } + else + { + if (inbound) + { + filter.action.calloutKey = FWPM_CALLOUT_IPSEC_INBOUND_TRANSPORT_V4; + } + else + { + filter.action.calloutKey = FWPM_CALLOUT_IPSEC_OUTBOUND_TRANSPORT_V4; + } + } + enumerator = array_create_enumerator(entry->sps); while (enumerator->enumerate(enumerator, &sp)) { @@ -609,7 +616,8 @@ static bool install_transport_sp(private_kernel_wfp_ipsec_t *this, free_conditions(conds, count); if (res != ERROR_SUCCESS) { - DBG1(DBG_KNL, "installing inbound FWP filter failed: 0x%08x", res); + DBG1(DBG_KNL, "installing %sbound FWP filter failed: 0x%08x", + inbound ? "in" : "out", res); return FALSE; } return TRUE; @@ -883,8 +891,8 @@ static bool install_sas(private_kernel_wfp_ipsec_t *this, entry_t *entry, } else { - traffic.tunnelPolicyId = entry->policy_in; - spi.inboundIpsecTraffic.tunnelPolicyId = entry->policy_in; + traffic.tunnelPolicyId = entry->provider; + spi.inboundIpsecTraffic.tunnelPolicyId = entry->provider; } if (!hosts2traffic(this, entry->local, entry->remote, &traffic)) @@ -963,8 +971,8 @@ 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_transport_sp(this, entry, TRUE) && - install_transport_sp(this, entry, FALSE) && + if (install_sp(this, entry, NULL, TRUE) && + install_sp(this, entry, NULL, FALSE) && install_sas(this, entry, IPSEC_TRAFFIC_TYPE_TRANSPORT)) { return TRUE; @@ -996,10 +1004,6 @@ static bool generate_guid(private_kernel_wfp_ipsec_t *this, GUID *guid) */ static bool install_tunnel_sps(private_kernel_wfp_ipsec_t *this, entry_t *entry) { - FWPM_FILTER_CONDITION0 *conds = NULL; - int count = 0; - enumerator_t *enumerator; - sp_entry_t *sp; DWORD res; IPSEC_AUTH_TRANSFORM0 transform = { @@ -1031,7 +1035,7 @@ static bool install_tunnel_sps(private_kernel_wfp_ipsec_t *this, entry_t *entry) .idleTimeoutSecondsFailOver = proposal.lifetime.lifetimeSeconds, }, }; - FWPM_PROVIDER_CONTEXT0 *ctx, qm = { + FWPM_PROVIDER_CONTEXT0 qm = { .displayData = { .name = L"charon tunnel provider context", }, @@ -1065,38 +1069,18 @@ static bool install_tunnel_sps(private_kernel_wfp_ipsec_t *this, entry_t *entry) return FALSE; } - enumerator = array_create_enumerator(entry->sps); - while (enumerator->enumerate(enumerator, &sp)) - { - if (!ts2condition(sp->src, TRUE, &conds, &count) || - !ts2condition(sp->dst, FALSE, &conds, &count)) - { - free_conditions(conds, count); - enumerator->destroy(enumerator); - return FALSE; - } - } - enumerator->destroy(enumerator); - - res = FwpmIPsecTunnelAdd0(this->handle, 0, NULL, &qm, count, conds, NULL); - free_conditions(conds, count); + res = FwpmProviderContextAdd0(this->handle, &qm, NULL, &entry->provider); if (res != ERROR_SUCCESS) { - DBG1(DBG_KNL, "installing FWP tunnel policy failed: 0x%08x", res); + DBG1(DBG_KNL, "adding provider context failed: 0x%08x", res); return FALSE; } - /* to get the tunnelPolicyId LUID we have to query the context */ - res = FwpmProviderContextGetByKey0(this->handle, &qm.providerContextKey, - &ctx); - if (res != ERROR_SUCCESS) + if (!install_sp(this, entry, &qm.providerContextKey, TRUE) || + !install_sp(this, entry, &qm.providerContextKey, FALSE)) { - DBG1(DBG_KNL, "getting FWP tunnel policy context failed: 0x%08x", res); return FALSE; } - entry->policy_in = ctx->providerContextId; - FwpmFreeMemory0((void**)&ctx); - return TRUE; } |