kernel-wfp: Install tunnel and trap forward policies

This commit is contained in:
Martin Willi
2014-06-04 16:32:10 +02:00
parent 1678f0a999
commit 6de788704b
3 changed files with 277 additions and 138 deletions
@@ -92,13 +92,6 @@ static char *guid2string(GUID *guid)
return buf; 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 * 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 = { const GUID FWPM_LAYER_OUTBOUND_IPPACKET_V6_DISCARD = {
0x9513d7c4, 0xa934, 0x49dc, { 0x91, 0xa7, 0x6c, 0xcb, 0x80, 0xcc, 0x02, 0xe3 } 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 = { const GUID FWPM_LAYER_IPFORWARD_V4_DISCARD = {
0x9e9ea773, 0x2fae, 0x4210, { 0x8f, 0x17, 0x34, 0x12, 0x9e, 0xf3, 0x69, 0xeb } 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 = { const GUID FWPM_LAYER_IPFORWARD_V6_DISCARD = {
0x31524a5d, 0x1dfe, 0x472f, { 0xbb, 0x93, 0x51, 0x8e, 0xe9, 0x45, 0xd8, 0xa2 } 0x31524a5d, 0x1dfe, 0x472f, { 0xbb, 0x93, 0x51, 0x8e, 0xe9, 0x45, 0xd8, 0xa2 }
}; };
@@ -504,19 +491,6 @@ static char* layer2name(GUID *guid)
return NULL; 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 * Convert filter callout GUID to name
*/ */
@@ -21,6 +21,12 @@ const GUID FWPM_CONDITION_IP_REMOTE_ADDRESS = {
const GUID FWPM_CONDITION_IP_LOCAL_ADDRESS = { const GUID FWPM_CONDITION_IP_LOCAL_ADDRESS = {
0xd9ee00de, 0xc1ef, 0x4617, { 0xbf,0xe3,0xff,0xd8,0xf5,0xa0,0x89,0x57 } 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 = { const GUID FWPM_CONDITION_IP_LOCAL_PORT = {
0x0c1ba1af, 0x5765, 0x453f, { 0xaf,0x22,0xa8,0xf7,0x91,0xac,0x77,0x5b } 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 = { const GUID FWPM_LAYER_OUTBOUND_TRANSPORT_V6 = {
0xe1735bde, 0x013f, 0x4655, { 0xb3,0x51,0xa4,0x9e,0x15,0x76,0x2d,0xf0 } 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 = { const GUID FWPM_CALLOUT_IPSEC_INBOUND_TRANSPORT_V4 = {
0x5132900d, 0x5e84, 0x4b5f, { 0x80,0xe4,0x01,0x74,0x1e,0x81,0xff,0x10 } 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 = { const GUID FWPM_CALLOUT_IPSEC_OUTBOUND_TUNNEL_V6 = {
0xf1835363, 0xa6a5, 0x4e62, { 0xb1,0x80,0x23,0xdb,0x78,0x9d,0x8d,0xa6 } 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 * Load a function symbol from a loaded dll
@@ -178,6 +178,10 @@ typedef struct {
u_int64_t policy_in; u_int64_t policy_in;
/** WFP allocated LUID for outbound filter ID */ /** WFP allocated LUID for outbound filter ID */
u_int64_t policy_out; 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 */ /** provider context, for tunnel mode only */
u_int64_t provider; u_int64_t provider;
/** WFP allocated LUID for SA context */ /** 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) if (entry->mode == MODE_TUNNEL)
{ {
manage_routes(this, entry, FALSE); 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 * (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 *conds[], int *count)
{ {
FWPM_FILTER_CONDITION0 *cond; FWPM_FILTER_CONDITION0 *cond;
@@ -361,14 +375,7 @@ static bool ts2condition(traffic_selector_t *ts, bool local,
to_port = ts->get_to_port(ts); to_port = ts->get_to_port(ts);
cond = append_condition(conds, count); cond = append_condition(conds, count);
if (local) cond->fieldKey = *target;
{
cond->fieldKey = FWPM_CONDITION_IP_LOCAL_ADDRESS;
}
else
{
cond->fieldKey = FWPM_CONDITION_IP_REMOTE_ADDRESS;
}
if (ts->is_host(ts, NULL)) if (ts->is_host(ts, NULL))
{ {
cond->matchType = FWP_MATCH_EQUAL; cond->matchType = FWP_MATCH_EQUAL;
@@ -440,7 +447,7 @@ static bool ts2condition(traffic_selector_t *ts, bool local,
} }
proto = ts->get_protocol(ts); proto = ts->get_protocol(ts);
if (proto && local) if (proto && target == &FWPM_CONDITION_IP_LOCAL_ADDRESS)
{ {
cond = append_condition(conds, count); cond = append_condition(conds, count);
cond->fieldKey = FWPM_CONDITION_IP_PROTOCOL; cond->fieldKey = FWPM_CONDITION_IP_PROTOCOL;
@@ -451,7 +458,7 @@ static bool ts2condition(traffic_selector_t *ts, bool local,
if (proto == IPPROTO_ICMP) if (proto == IPPROTO_ICMP)
{ {
if (local) if (target == &FWPM_CONDITION_IP_LOCAL_ADDRESS)
{ {
u_int8_t from_type, to_type, from_code, to_code; 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) else if (from_port != 0 || to_port != 0xFFFF)
{ {
cond = append_condition(conds, count); if (target == &FWPM_CONDITION_IP_LOCAL_ADDRESS)
if (local)
{ {
cond = append_condition(conds, count);
cond->fieldKey = FWPM_CONDITION_IP_LOCAL_PORT; 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; cond->fieldKey = FWPM_CONDITION_IP_REMOTE_PORT;
range2cond(cond, from_port, to_port);
} }
range2cond(cond, from_port, to_port);
} }
return TRUE; return TRUE;
} }
@@ -529,17 +538,73 @@ static void free_conditions(FWPM_FILTER_CONDITION0 *conds, int count)
free(conds); free(conds);
} }
/**
* 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 * Install a single policy in to the kernel
*/ */
static bool install_sp(private_kernel_wfp_ipsec_t *this, static bool install_sp(private_kernel_wfp_ipsec_t *this, sp_entry_t *sp,
entry_t *entry, GUID *context, bool inbound) GUID *context, bool inbound, bool fwd, UINT64 *filter_id)
{ {
FWPM_FILTER_CONDITION0 *conds = NULL; FWPM_FILTER_CONDITION0 *conds = NULL;
int count = 0;
enumerator_t *enumerator;
traffic_selector_t *local, *remote; traffic_selector_t *local, *remote;
sp_entry_t *sp; const GUID *ltarget, *rtarget;
int count = 0;
bool v6;
DWORD res; DWORD res;
FWPM_FILTER0 filter = { FWPM_FILTER0 filter = {
.displayData = { .displayData = {
@@ -548,81 +613,114 @@ static bool install_sp(private_kernel_wfp_ipsec_t *this,
.action = { .action = {
.type = FWP_ACTION_CALLOUT_TERMINATING, .type = FWP_ACTION_CALLOUT_TERMINATING,
}, },
.layerKey = inbound ? FWPM_LAYER_INBOUND_TRANSPORT_V4 :
FWPM_LAYER_OUTBOUND_TRANSPORT_V4,
}; };
if (context) 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.flags |= FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT;
filter.providerKey = (GUID*)&this->provider.providerKey, filter.providerKey = (GUID*)&this->provider.providerKey;
memcpy(&filter.providerContextKey, context, sizeof(GUID)); 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 else
{ {
if (inbound) local = sp->src;
{ remote = sp->dst;
filter.action.calloutKey = FWPM_CALLOUT_IPSEC_INBOUND_TRANSPORT_V4;
}
else
{
filter.action.calloutKey = FWPM_CALLOUT_IPSEC_OUTBOUND_TRANSPORT_V4;
}
} }
if (fwd)
enumerator = array_create_enumerator(entry->sps);
while (enumerator->enumerate(enumerator, &sp))
{ {
if (inbound) ltarget = &FWPM_CONDITION_IP_SOURCE_ADDRESS;
{ rtarget = &FWPM_CONDITION_IP_DESTINATION_ADDRESS;
local = sp->dst; }
remote = sp->src; else
} {
else ltarget = &FWPM_CONDITION_IP_LOCAL_ADDRESS;
{ rtarget = &FWPM_CONDITION_IP_REMOTE_ADDRESS;
local = sp->src; }
remote = sp->dst; if (!ts2condition(local, ltarget, &conds, &count) ||
} !ts2condition(remote, rtarget, &conds, &count))
{
if (!ts2condition(local, TRUE, &conds, &count) || free_conditions(conds, count);
!ts2condition(remote, FALSE, &conds, &count)) return FALSE;
{
free_conditions(conds, count);
enumerator->destroy(enumerator);
return FALSE;
}
} }
enumerator->destroy(enumerator);
filter.numFilterConditions = count; filter.numFilterConditions = count;
filter.filterCondition = conds; filter.filterCondition = conds;
if (inbound) res = FwpmFilterAdd0(this->handle, &filter, NULL, filter_id);
{
res = FwpmFilterAdd0(this->handle, &filter, NULL, &entry->policy_in);
}
else
{
res = FwpmFilterAdd0(this->handle, &filter, NULL, &entry->policy_out);
}
free_conditions(conds, count); free_conditions(conds, count);
if (res != ERROR_SUCCESS) if (res != ERROR_SUCCESS)
{ {
DBG1(DBG_KNL, "installing %sbound FWP filter failed: 0x%08x", DBG1(DBG_KNL, "installing %s%sbound WFP filter failed: 0x%08x",
inbound ? "in" : "out", res); fwd ? "forward " : "", inbound ? "in" : "out", res);
return FALSE; return FALSE;
} }
return TRUE; 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))
{
/* inbound policy */
if (!install_sp(this, sp, context, TRUE, FALSE, &entry->policy_in))
{
enumerator->destroy(enumerator);
return FALSE;
}
/* outbound policy */
if (!install_sp(this, sp, context, FALSE, FALSE, &entry->policy_out))
{
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);
return TRUE;
}
/** /**
* Convert a chunk_t to a WFP FWP_BYTE_BLOB * Convert a chunk_t to a WFP FWP_BYTE_BLOB
*/ */
@@ -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) static bool install_transport(private_kernel_wfp_ipsec_t *this, entry_t *entry)
{ {
if (install_sp(this, entry, NULL, TRUE) && if (install_sps(this, entry, NULL) &&
install_sp(this, entry, NULL, FALSE) &&
install_sas(this, entry, IPSEC_TRAFFIC_TYPE_TRANSPORT)) install_sas(this, entry, IPSEC_TRAFFIC_TYPE_TRANSPORT))
{ {
return TRUE; 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; DWORD res;
@@ -1037,7 +1135,7 @@ static bool install_tunnel_sps(private_kernel_wfp_ipsec_t *this, entry_t *entry)
}; };
FWPM_PROVIDER_CONTEXT0 qm = { FWPM_PROVIDER_CONTEXT0 qm = {
.displayData = { .displayData = {
.name = L"charon tunnel provider context", .name = L"charon tunnel provider",
}, },
.providerKey = (GUID*)&this->provider.providerKey, .providerKey = (GUID*)&this->provider.providerKey,
.type = FWPM_IPSEC_IKE_QM_TUNNEL_CONTEXT, .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; break;
case AF_INET6: case AF_INET6:
policy.tunnelEndpoints.ipVersion = FWP_IP_VERSION_V6; policy.tunnelEndpoints.ipVersion = FWP_IP_VERSION_V6;
memcpy(&policy.tunnelEndpoints.localV6Address, host2address6(entry->local, &policy.tunnelEndpoints.localV6Address);
entry->local->get_address(entry->local).ptr, 16); host2address6(entry->remote, &policy.tunnelEndpoints.remoteV6Address);
memcpy(&policy.tunnelEndpoints.remoteV6Address,
entry->remote->get_address(entry->remote).ptr, 16);
break; break;
default: default:
return FALSE; return FALSE;
@@ -1069,15 +1165,28 @@ static bool install_tunnel_sps(private_kernel_wfp_ipsec_t *this, entry_t *entry)
return FALSE; return FALSE;
} }
res = FwpmProviderContextAdd0(this->handle, &qm, NULL, &entry->provider); res = FwpmProviderContextAdd0(this->handle, &qm, NULL, luid);
if (res != ERROR_SUCCESS) if (res != ERROR_SUCCESS)
{ {
DBG1(DBG_KNL, "adding provider context failed: 0x%08x", res); DBG1(DBG_KNL, "adding provider context failed: 0x%08x", res);
return FALSE; 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; return FALSE;
} }
@@ -1267,10 +1376,12 @@ static bool install(private_kernel_wfp_ipsec_t *this, entry_t *entry)
typedef struct { typedef struct {
/** reqid this trap is installed for */ /** reqid this trap is installed for */
u_int32_t reqid; u_int32_t reqid;
/** local traffic selector */ /** is this a forward policy trap for tunnel mode? */
traffic_selector_t *local; bool fwd;
/** remote traffic selector */ /** src traffic selector */
traffic_selector_t *remote; traffic_selector_t *src;
/** dst traffic selector */
traffic_selector_t *dst;
/** LUID of installed tunnel policy filter */ /** LUID of installed tunnel policy filter */
UINT64 filter_id; UINT64 filter_id;
} trap_t; } trap_t;
@@ -1280,8 +1391,8 @@ typedef struct {
*/ */
static void destroy_trap(trap_t *this) static void destroy_trap(trap_t *this)
{ {
this->local->destroy(this->local); this->src->destroy(this->src);
this->remote->destroy(this->remote); this->dst->destroy(this->dst);
free(this); free(this);
} }
@@ -1438,6 +1549,7 @@ static bool install_trap(private_kernel_wfp_ipsec_t *this, trap_t *trap)
FWPM_FILTER_CONDITION0 *conds = NULL; FWPM_FILTER_CONDITION0 *conds = NULL;
int count = 0; int count = 0;
DWORD res; DWORD res;
const GUID *starget, *dtarget;
UINT64 weight = 0x000000000000ff00; UINT64 weight = 0x000000000000ff00;
FWPM_FILTER0 filter = { FWPM_FILTER0 filter = {
.displayData = { .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; filter.layerKey = FWPM_LAYER_OUTBOUND_TRANSPORT_V4;
break; }
case TS_IPV6_ADDR_RANGE: else
{
filter.layerKey = FWPM_LAYER_OUTBOUND_TRANSPORT_V6; 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) || if (!ts2condition(trap->src, starget, &conds, &count) ||
!ts2condition(trap->remote, FALSE, &conds, &count)) !ts2condition(trap->dst, dtarget, &conds, &count))
{ {
free_conditions(conds, count); free_conditions(conds, count);
return FALSE; return FALSE;
@@ -1476,7 +1605,7 @@ static bool install_trap(private_kernel_wfp_ipsec_t *this, trap_t *trap)
free_conditions(conds, count); free_conditions(conds, count);
if (res != ERROR_SUCCESS) 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 FALSE;
} }
return TRUE; 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); res = FwpmFilterDeleteById0(this->handle, trap->filter_id);
if (res != ERROR_SUCCESS) 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 FALSE;
} }
return TRUE; 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 * Create and install a new trap entry
*/ */
static bool add_trap(private_kernel_wfp_ipsec_t *this, u_int32_t reqid, static bool add_trap(private_kernel_wfp_ipsec_t *this,
traffic_selector_t *local, traffic_selector_t *remote) u_int32_t reqid, bool fwd,
traffic_selector_t *src, traffic_selector_t *dst)
{ {
trap_t *trap; trap_t *trap;
INIT(trap, INIT(trap,
.reqid = reqid, .reqid = reqid,
.local = local->clone(local), .fwd = fwd,
.remote = remote->clone(remote), .src = src->clone(src),
.dst = dst->clone(dst),
); );
if (!install_trap(this, trap)) 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 * Uninstall and remove a new trap entry
*/ */
static bool remove_trap(private_kernel_wfp_ipsec_t *this, u_int32_t reqid, static bool remove_trap(private_kernel_wfp_ipsec_t *this,
traffic_selector_t *local, traffic_selector_t *remote) u_int32_t reqid, bool fwd,
traffic_selector_t *src, traffic_selector_t *dst)
{ {
enumerator_t *enumerator; enumerator_t *enumerator;
trap_t *trap, *found = NULL; 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)) while (enumerator->enumerate(enumerator, NULL, &trap))
{ {
if (reqid == trap->reqid && if (reqid == trap->reqid &&
local->equals(local, trap->local) && fwd == trap->fwd &&
remote->equals(remote, trap->remote)) src->equals(src, trap->src) &&
dst->equals(dst, trap->dst))
{ {
this->traps->remove_at(this->traps, enumerator); this->traps->remove_at(this->traps, enumerator);
found = trap; found = trap;
@@ -2014,11 +2147,18 @@ METHOD(kernel_ipsec_t, add_policy, status_t,
case POLICY_PRIORITY_DEFAULT: case POLICY_PRIORITY_DEFAULT:
break; break;
case POLICY_PRIORITY_ROUTED: 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 SUCCESS; return FAILED;
} }
return FAILED; if (sa->mode == MODE_TUNNEL)
{
if (!add_trap(this, sa->reqid, TRUE, src_ts, dst_ts))
{
return FAILED;
}
}
return SUCCESS;
case POLICY_PRIORITY_FALLBACK: case POLICY_PRIORITY_FALLBACK:
default: default:
return NOT_SUPPORTED; return NOT_SUPPORTED;
@@ -2074,8 +2214,9 @@ METHOD(kernel_ipsec_t, del_policy, status_t,
{ {
if (direction == POLICY_OUT && priority == POLICY_PRIORITY_ROUTED) 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 SUCCESS;
} }
return NOT_FOUND; return NOT_FOUND;
@@ -2146,7 +2287,7 @@ static bool add_bypass(private_kernel_wfp_ipsec_t *this,
free_conditions(conds, count); free_conditions(conds, count);
if (res != ERROR_SUCCESS) 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 FALSE;
} }
return TRUE; return TRUE;