diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/libcharon/plugins/kernel_wfp/kernel_wfp_compat.c | 6 | ||||
-rw-r--r-- | src/libcharon/plugins/kernel_wfp/kernel_wfp_compat.h | 11 | ||||
-rw-r--r-- | src/libcharon/plugins/kernel_wfp/kernel_wfp_ipsec.c | 98 |
3 files changed, 114 insertions, 1 deletions
diff --git a/src/libcharon/plugins/kernel_wfp/kernel_wfp_compat.c b/src/libcharon/plugins/kernel_wfp/kernel_wfp_compat.c index a687c4371..6b32f3192 100644 --- a/src/libcharon/plugins/kernel_wfp/kernel_wfp_compat.c +++ b/src/libcharon/plugins/kernel_wfp/kernel_wfp_compat.c @@ -90,3 +90,9 @@ STUB(fwpuclnt, DWORD, IPsecSaContextCreate1, 40, STUB(fwpuclnt, DWORD, IPsecSaContextSetSpi0, 32, HANDLE engineHandle, UINT64 id, const void *getSpi, UINT32 inboundSpi) + +STUB(fwpuclnt, DWORD, IPsecSaContextGetById1, 24, + HANDLE engineHandle, UINT64 id, void **saContext) + +STUB(fwpuclnt, DWORD, IPsecSaContextUpdate0, 24, + HANDLE engineHandle, UINT32 flags, const void *newValues) diff --git a/src/libcharon/plugins/kernel_wfp/kernel_wfp_compat.h b/src/libcharon/plugins/kernel_wfp/kernel_wfp_compat.h index efccd4c45..76a6c85b8 100644 --- a/src/libcharon/plugins/kernel_wfp/kernel_wfp_compat.h +++ b/src/libcharon/plugins/kernel_wfp/kernel_wfp_compat.h @@ -51,6 +51,17 @@ enum { FWPM_TUNNEL_FLAG_ENABLE_VIRTUAL_IF_TUNNELING = (1<<1), }; +/* missing in MinGW */ +enum { + IPSEC_SA_DETAILS_UPDATE_TRAFFIC = (1<<0), + IPSEC_SA_DETAILS_UPDATE_UDP_ENCAPSULATION = (1<<1), + IPSEC_SA_BUNDLE_UPDATE_FLAGS = (1<<2), + IPSEC_SA_BUNDLE_UPDATE_NAP_CONTEXT = (1<<3), + IPSEC_SA_BUNDLE_UPDATE_KEY_MODULE_STATE = (1<<4), + IPSEC_SA_BUNDLE_UPDATE_PEER_V4_PRIVATE_ADDRESS = (1<<5), + IPSEC_SA_BUNDLE_UPDATE_MM_SA_ID = (1<<6), +}; + DWORD WINAPI FwpmIPsecTunnelAdd0(HANDLE, UINT32, const FWPM_PROVIDER_CONTEXT0*, const FWPM_PROVIDER_CONTEXT0*, UINT32, const FWPM_FILTER_CONDITION0*, PSECURITY_DESCRIPTOR); diff --git a/src/libcharon/plugins/kernel_wfp/kernel_wfp_ipsec.c b/src/libcharon/plugins/kernel_wfp/kernel_wfp_ipsec.c index f26b60a92..3dbbb30a6 100644 --- a/src/libcharon/plugins/kernel_wfp/kernel_wfp_ipsec.c +++ b/src/libcharon/plugins/kernel_wfp/kernel_wfp_ipsec.c @@ -1509,7 +1509,103 @@ METHOD(kernel_ipsec_t, update_sa, status_t, u_int16_t cpi, host_t *src, host_t *dst, host_t *new_src, host_t *new_dst, bool encap, bool new_encap, mark_t mark) { - return NOT_SUPPORTED; + entry_t *entry; + sa_entry_t key = { + .dst = dst, + .spi = spi, + }; + UINT64 sa_id = 0; + IPSEC_SA_CONTEXT1 *ctx; + IPSEC_V4_UDP_ENCAPSULATION0 ports; + UINT32 flags = IPSEC_SA_DETAILS_UPDATE_TRAFFIC; + DWORD res; + + this->mutex->lock(this->mutex); + entry = this->osas->get(this->osas, &key); + this->mutex->unlock(this->mutex); + + if (entry) + { + /* outbound entry, nothing to do */ + return SUCCESS; + } + + this->mutex->lock(this->mutex); + entry = this->isas->get(this->isas, &key); + if (entry) + { + /* inbound entry, do update */ + sa_id = entry->sa_id; + ports.localUdpEncapPort = entry->local->get_port(entry->local); + ports.remoteUdpEncapPort = entry->remote->get_port(entry->remote); + } + this->mutex->unlock(this->mutex); + + if (!sa_id) + { + return NOT_FOUND; + } + + res = IPsecSaContextGetById1(this->handle, sa_id, &ctx); + if (res != ERROR_SUCCESS) + { + DBG1(DBG_KNL, "getting WFP SA context for updated failed: 0x%08x", res); + return FAILED; + } + if (!hosts2traffic(this, new_dst, new_src, &ctx->inboundSa->traffic) || + !hosts2traffic(this, new_dst, new_src, &ctx->outboundSa->traffic)) + { + FwpmFreeMemory0((void**)&ctx); + return FAILED; + } + + if (new_encap != encap) + { + if (new_encap) + { + ctx->inboundSa->udpEncapsulation = &ports; + ctx->outboundSa->udpEncapsulation = &ports; + } + else + { + ctx->inboundSa->udpEncapsulation = NULL; + ctx->outboundSa->udpEncapsulation = NULL; + } + flags |= IPSEC_SA_DETAILS_UPDATE_UDP_ENCAPSULATION; + } + + res = IPsecSaContextUpdate0(this->handle, flags, ctx); + FwpmFreeMemory0((void**)&ctx); + if (res != ERROR_SUCCESS) + { + DBG1(DBG_KNL, "updating WFP SA context failed: 0x%08x", res); + return FAILED; + } + + this->mutex->lock(this->mutex); + entry = this->isas->remove(this->isas, &key); + if (entry) + { + key.spi = entry->osa.spi; + key.dst = entry->osa.dst; + this->osas->remove(this->osas, &key); + + entry->local->destroy(entry->local); + entry->remote->destroy(entry->remote); + entry->local = new_dst->clone(new_dst); + entry->remote = new_src->clone(new_src); + entry->isa.dst = entry->local; + entry->osa.dst = entry->remote; + + this->isas->put(this->isas, &entry->isa, entry); + this->osas->put(this->osas, &entry->osa, entry); + + manage_routes(this, entry, FALSE); + manage_routes(this, entry, TRUE); + } + this->mutex->unlock(this->mutex); + + return SUCCESS; } METHOD(kernel_ipsec_t, query_sa, status_t, |