kernel-wfp: Implement update_sa()

This commit is contained in:
Martin Willi
2014-06-04 16:32:09 +02:00
parent 1987b70989
commit 5a5b9925f8
3 changed files with 114 additions and 1 deletions
@@ -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)
@@ -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);
@@ -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,