kernel-wfp: Install tunnel and trap forward policies
This commit is contained in:
@@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user