aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/libcharon/plugins/kernel_wfp/kernel_wfp_compat.c6
-rw-r--r--src/libcharon/plugins/kernel_wfp/kernel_wfp_compat.h11
-rw-r--r--src/libcharon/plugins/kernel_wfp/kernel_wfp_ipsec.c98
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,