Remove policies in kernel interfaces based on their priority.

This allows to unroute a connection while the same connection is
currently established.  In this case both CHILD_SAs share the same
reqid but the installed policies have different priorities.
This commit is contained in:
Tobias Brunner
2011-07-27 13:41:35 +02:00
parent a2e377fcfd
commit fbedc6a45b
10 changed files with 140 additions and 80 deletions
@@ -86,7 +86,7 @@ METHOD(kernel_ipsec_t, add_policy, status_t,
private_load_tester_ipsec_t *this, host_t *src, host_t *dst, private_load_tester_ipsec_t *this, host_t *src, host_t *dst,
traffic_selector_t *src_ts, traffic_selector_t *dst_ts, traffic_selector_t *src_ts, traffic_selector_t *dst_ts,
policy_dir_t direction, policy_type_t type, ipsec_sa_cfg_t *sa, policy_dir_t direction, policy_type_t type, ipsec_sa_cfg_t *sa,
mark_t mark, bool routed) mark_t mark, policy_priority_t priority)
{ {
return SUCCESS; return SUCCESS;
} }
@@ -103,7 +103,7 @@ METHOD(kernel_ipsec_t, query_policy, status_t,
METHOD(kernel_ipsec_t, del_policy, status_t, METHOD(kernel_ipsec_t, del_policy, status_t,
private_load_tester_ipsec_t *this, traffic_selector_t *src_ts, private_load_tester_ipsec_t *this, traffic_selector_t *src_ts,
traffic_selector_t *dst_ts, policy_dir_t direction, u_int32_t reqid, traffic_selector_t *dst_ts, policy_dir_t direction, u_int32_t reqid,
mark_t mark, bool unrouted) mark_t mark, policy_priority_t priority)
{ {
return SUCCESS; return SUCCESS;
} }
+21 -15
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2006-2010 Tobias Brunner * Copyright (C) 2006-2011 Tobias Brunner
* Copyright (C) 2005-2008 Martin Willi * Copyright (C) 2005-2008 Martin Willi
* Copyright (C) 2006 Daniel Roethlisberger * Copyright (C) 2006 Daniel Roethlisberger
* Copyright (C) 2005 Jan Hutter * Copyright (C) 2005 Jan Hutter
@@ -664,7 +664,6 @@ METHOD(child_sa_t, add_policies, status_t,
enumerator_t *enumerator; enumerator_t *enumerator;
traffic_selector_t *my_ts, *other_ts; traffic_selector_t *my_ts, *other_ts;
status_t status = SUCCESS; status_t status = SUCCESS;
bool routed = (this->state == CHILD_CREATED);
/* apply traffic selectors */ /* apply traffic selectors */
enumerator = my_ts_list->create_enumerator(my_ts_list); enumerator = my_ts_list->create_enumerator(my_ts_list);
@@ -682,6 +681,7 @@ METHOD(child_sa_t, add_policies, status_t,
if (this->config->install_policy(this->config)) if (this->config->install_policy(this->config))
{ {
policy_priority_t priority;
ipsec_sa_cfg_t my_sa = { ipsec_sa_cfg_t my_sa = {
.mode = this->mode, .mode = this->mode,
.reqid = this->reqid, .reqid = this->reqid,
@@ -708,6 +708,9 @@ METHOD(child_sa_t, add_policies, status_t,
other_sa.ah.spi = this->other_spi; other_sa.ah.spi = this->other_spi;
} }
priority = this->state == CHILD_CREATED ? POLICY_PRIORITY_ROUTED
: POLICY_PRIORITY_DEFAULT;
/* enumerate pairs of traffic selectors */ /* enumerate pairs of traffic selectors */
enumerator = create_policy_enumerator(this); enumerator = create_policy_enumerator(this);
while (enumerator->enumerate(enumerator, &my_ts, &other_ts)) while (enumerator->enumerate(enumerator, &my_ts, &other_ts))
@@ -717,20 +720,20 @@ METHOD(child_sa_t, add_policies, status_t,
hydra->kernel_interface, hydra->kernel_interface,
this->my_addr, this->other_addr, my_ts, other_ts, this->my_addr, this->other_addr, my_ts, other_ts,
POLICY_OUT, POLICY_IPSEC, &other_sa, POLICY_OUT, POLICY_IPSEC, &other_sa,
this->mark_out, routed); this->mark_out, priority);
status |= hydra->kernel_interface->add_policy( status |= hydra->kernel_interface->add_policy(
hydra->kernel_interface, hydra->kernel_interface,
this->other_addr, this->my_addr, other_ts, my_ts, this->other_addr, this->my_addr, other_ts, my_ts,
POLICY_IN, POLICY_IPSEC, &my_sa, POLICY_IN, POLICY_IPSEC, &my_sa,
this->mark_in, routed); this->mark_in, priority);
if (this->mode != MODE_TRANSPORT) if (this->mode != MODE_TRANSPORT)
{ {
status |= hydra->kernel_interface->add_policy( status |= hydra->kernel_interface->add_policy(
hydra->kernel_interface, hydra->kernel_interface,
this->other_addr, this->my_addr, other_ts, my_ts, this->other_addr, this->my_addr, other_ts, my_ts,
POLICY_FWD, POLICY_IPSEC, &my_sa, POLICY_FWD, POLICY_IPSEC, &my_sa,
this->mark_in, routed); this->mark_in, priority);
} }
if (status != SUCCESS) if (status != SUCCESS)
@@ -838,15 +841,15 @@ METHOD(child_sa_t, update, status_t,
/* remove old policies first */ /* remove old policies first */
hydra->kernel_interface->del_policy(hydra->kernel_interface, hydra->kernel_interface->del_policy(hydra->kernel_interface,
my_ts, other_ts, POLICY_OUT, this->reqid, my_ts, other_ts, POLICY_OUT, this->reqid,
this->mark_out, FALSE); this->mark_out, POLICY_PRIORITY_DEFAULT);
hydra->kernel_interface->del_policy(hydra->kernel_interface, hydra->kernel_interface->del_policy(hydra->kernel_interface,
other_ts, my_ts, POLICY_IN, this->reqid, other_ts, my_ts, POLICY_IN, this->reqid,
this->mark_in, FALSE); this->mark_in, POLICY_PRIORITY_DEFAULT);
if (this->mode != MODE_TRANSPORT) if (this->mode != MODE_TRANSPORT)
{ {
hydra->kernel_interface->del_policy(hydra->kernel_interface, hydra->kernel_interface->del_policy(hydra->kernel_interface,
other_ts, my_ts, POLICY_FWD, this->reqid, other_ts, my_ts, POLICY_FWD, this->reqid,
this->mark_in, FALSE); this->mark_in, POLICY_PRIORITY_DEFAULT);
} }
/* check whether we have to update a "dynamic" traffic selector */ /* check whether we have to update a "dynamic" traffic selector */
@@ -872,15 +875,15 @@ METHOD(child_sa_t, update, status_t,
/* reinstall updated policies */ /* reinstall updated policies */
hydra->kernel_interface->add_policy(hydra->kernel_interface, hydra->kernel_interface->add_policy(hydra->kernel_interface,
me, other, my_ts, other_ts, POLICY_OUT, POLICY_IPSEC, me, other, my_ts, other_ts, POLICY_OUT, POLICY_IPSEC,
&other_sa, this->mark_out, FALSE); &other_sa, this->mark_out, POLICY_PRIORITY_DEFAULT);
hydra->kernel_interface->add_policy(hydra->kernel_interface, hydra->kernel_interface->add_policy(hydra->kernel_interface,
other, me, other_ts, my_ts, POLICY_IN, POLICY_IPSEC, other, me, other_ts, my_ts, POLICY_IN, POLICY_IPSEC,
&my_sa, this->mark_in, FALSE); &my_sa, this->mark_in, POLICY_PRIORITY_DEFAULT);
if (this->mode != MODE_TRANSPORT) if (this->mode != MODE_TRANSPORT)
{ {
hydra->kernel_interface->add_policy(hydra->kernel_interface, hydra->kernel_interface->add_policy(hydra->kernel_interface,
other, me, other_ts, my_ts, POLICY_FWD, POLICY_IPSEC, other, me, other_ts, my_ts, POLICY_FWD, POLICY_IPSEC,
&my_sa, this->mark_in, FALSE); &my_sa, this->mark_in, POLICY_PRIORITY_DEFAULT);
} }
} }
enumerator->destroy(enumerator); enumerator->destroy(enumerator);
@@ -913,7 +916,10 @@ METHOD(child_sa_t, destroy, void,
{ {
enumerator_t *enumerator; enumerator_t *enumerator;
traffic_selector_t *my_ts, *other_ts; traffic_selector_t *my_ts, *other_ts;
bool unrouted = (this->state == CHILD_ROUTED); policy_priority_t priority;
priority = this->state == CHILD_ROUTED ? POLICY_PRIORITY_ROUTED
: POLICY_PRIORITY_DEFAULT;
set_state(this, CHILD_DESTROYING); set_state(this, CHILD_DESTROYING);
@@ -947,15 +953,15 @@ METHOD(child_sa_t, destroy, void,
{ {
hydra->kernel_interface->del_policy(hydra->kernel_interface, hydra->kernel_interface->del_policy(hydra->kernel_interface,
my_ts, other_ts, POLICY_OUT, this->reqid, my_ts, other_ts, POLICY_OUT, this->reqid,
this->mark_out, unrouted); this->mark_out, priority);
hydra->kernel_interface->del_policy(hydra->kernel_interface, hydra->kernel_interface->del_policy(hydra->kernel_interface,
other_ts, my_ts, POLICY_IN, this->reqid, other_ts, my_ts, POLICY_IN, this->reqid,
this->mark_in, unrouted); this->mark_in, priority);
if (this->mode != MODE_TRANSPORT) if (this->mode != MODE_TRANSPORT)
{ {
hydra->kernel_interface->del_policy(hydra->kernel_interface, hydra->kernel_interface->del_policy(hydra->kernel_interface,
other_ts, my_ts, POLICY_FWD, this->reqid, other_ts, my_ts, POLICY_FWD, this->reqid,
this->mark_in, unrouted); this->mark_in, priority);
} }
} }
enumerator->destroy(enumerator); enumerator->destroy(enumerator);
+9 -6
View File
@@ -69,19 +69,22 @@ static bool install_shunt_policy(child_cfg_t *child)
status |= hydra->kernel_interface->add_policy( status |= hydra->kernel_interface->add_policy(
hydra->kernel_interface, host_any, host_any, hydra->kernel_interface, host_any, host_any,
my_ts, other_ts, POLICY_OUT, policy_type, my_ts, other_ts, POLICY_OUT, policy_type,
&sa, child->get_mark(child, FALSE), FALSE); &sa, child->get_mark(child, FALSE),
POLICY_PRIORITY_DEFAULT);
/* install in policy */ /* install in policy */
status |= hydra->kernel_interface->add_policy( status |= hydra->kernel_interface->add_policy(
hydra->kernel_interface, host_any, host_any, hydra->kernel_interface, host_any, host_any,
other_ts, my_ts, POLICY_IN, policy_type, other_ts, my_ts, POLICY_IN, policy_type,
&sa, child->get_mark(child, TRUE), FALSE); &sa, child->get_mark(child, TRUE),
POLICY_PRIORITY_DEFAULT);
/* install forward policy */ /* install forward policy */
status |= hydra->kernel_interface->add_policy( status |= hydra->kernel_interface->add_policy(
hydra->kernel_interface, host_any, host_any, hydra->kernel_interface, host_any, host_any,
other_ts, my_ts, POLICY_FWD, policy_type, other_ts, my_ts, POLICY_FWD, policy_type,
&sa, child->get_mark(child, TRUE), FALSE); &sa, child->get_mark(child, TRUE),
POLICY_PRIORITY_DEFAULT);
} }
e_other_ts->destroy(e_other_ts); e_other_ts->destroy(e_other_ts);
} }
@@ -150,19 +153,19 @@ static void uninstall_shunt_policy(child_cfg_t *child)
status |= hydra->kernel_interface->del_policy( status |= hydra->kernel_interface->del_policy(
hydra->kernel_interface, my_ts, other_ts, hydra->kernel_interface, my_ts, other_ts,
POLICY_OUT, 0, child->get_mark(child, FALSE), POLICY_OUT, 0, child->get_mark(child, FALSE),
FALSE); POLICY_PRIORITY_DEFAULT);
/* uninstall in policy */ /* uninstall in policy */
status |= hydra->kernel_interface->del_policy( status |= hydra->kernel_interface->del_policy(
hydra->kernel_interface, other_ts, my_ts, hydra->kernel_interface, other_ts, my_ts,
POLICY_IN, 0, child->get_mark(child, TRUE), POLICY_IN, 0, child->get_mark(child, TRUE),
FALSE); POLICY_PRIORITY_DEFAULT);
/* uninstall forward policy */ /* uninstall forward policy */
status |= hydra->kernel_interface->del_policy( status |= hydra->kernel_interface->del_policy(
hydra->kernel_interface, other_ts, my_ts, hydra->kernel_interface, other_ts, my_ts,
POLICY_FWD, 0, child->get_mark(child, TRUE), POLICY_FWD, 0, child->get_mark(child, TRUE),
FALSE); POLICY_PRIORITY_DEFAULT);
} }
e_other_ts->destroy(e_other_ts); e_other_ts->destroy(e_other_ts);
} }
+4 -4
View File
@@ -132,14 +132,14 @@ METHOD(kernel_interface_t, add_policy, status_t,
private_kernel_interface_t *this, host_t *src, host_t *dst, private_kernel_interface_t *this, host_t *src, host_t *dst,
traffic_selector_t *src_ts, traffic_selector_t *dst_ts, traffic_selector_t *src_ts, traffic_selector_t *dst_ts,
policy_dir_t direction, policy_type_t type, ipsec_sa_cfg_t *sa, policy_dir_t direction, policy_type_t type, ipsec_sa_cfg_t *sa,
mark_t mark, bool routed) mark_t mark, policy_priority_t priority)
{ {
if (!this->ipsec) if (!this->ipsec)
{ {
return NOT_SUPPORTED; return NOT_SUPPORTED;
} }
return this->ipsec->add_policy(this->ipsec, src, dst, src_ts, dst_ts, return this->ipsec->add_policy(this->ipsec, src, dst, src_ts, dst_ts,
direction, type, sa, mark, routed); direction, type, sa, mark, priority);
} }
METHOD(kernel_interface_t, query_policy, status_t, METHOD(kernel_interface_t, query_policy, status_t,
@@ -158,14 +158,14 @@ METHOD(kernel_interface_t, query_policy, status_t,
METHOD(kernel_interface_t, del_policy, status_t, METHOD(kernel_interface_t, del_policy, status_t,
private_kernel_interface_t *this, traffic_selector_t *src_ts, private_kernel_interface_t *this, traffic_selector_t *src_ts,
traffic_selector_t *dst_ts, policy_dir_t direction, u_int32_t reqid, traffic_selector_t *dst_ts, policy_dir_t direction, u_int32_t reqid,
mark_t mark, bool unrouted) mark_t mark, policy_priority_t priority)
{ {
if (!this->ipsec) if (!this->ipsec)
{ {
return NOT_SUPPORTED; return NOT_SUPPORTED;
} }
return this->ipsec->del_policy(this->ipsec, src_ts, dst_ts, return this->ipsec->del_policy(this->ipsec, src_ts, dst_ts,
direction, reqid, mark, unrouted); direction, reqid, mark, priority);
} }
METHOD(kernel_interface_t, get_source_addr, host_t*, METHOD(kernel_interface_t, get_source_addr, host_t*,
+5 -4
View File
@@ -188,7 +188,7 @@ struct kernel_interface_t {
* @param type type of policy, POLICY_(IPSEC|PASS|DROP) * @param type type of policy, POLICY_(IPSEC|PASS|DROP)
* @param sa details about the SA(s) tied to this policy * @param sa details about the SA(s) tied to this policy
* @param mark mark for this policy * @param mark mark for this policy
* @param routed TRUE, if this policy is routed in the kernel * @param priority priority of this policy
* @return SUCCESS if operation completed * @return SUCCESS if operation completed
*/ */
status_t (*add_policy) (kernel_interface_t *this, status_t (*add_policy) (kernel_interface_t *this,
@@ -196,7 +196,8 @@ struct kernel_interface_t {
traffic_selector_t *src_ts, traffic_selector_t *src_ts,
traffic_selector_t *dst_ts, traffic_selector_t *dst_ts,
policy_dir_t direction, policy_type_t type, policy_dir_t direction, policy_type_t type,
ipsec_sa_cfg_t *sa, mark_t mark, bool routed); ipsec_sa_cfg_t *sa, mark_t mark,
policy_priority_t priority);
/** /**
* Query the use time of a policy. * Query the use time of a policy.
@@ -230,14 +231,14 @@ struct kernel_interface_t {
* @param direction direction of traffic, POLICY_(IN|OUT|FWD) * @param direction direction of traffic, POLICY_(IN|OUT|FWD)
* @param reqid unique ID of the associated SA * @param reqid unique ID of the associated SA
* @param mark optional mark * @param mark optional mark
* @param unrouted TRUE, if this policy is unrouted from the kernel * @param priority priority of the policy
* @return SUCCESS if operation completed * @return SUCCESS if operation completed
*/ */
status_t (*del_policy) (kernel_interface_t *this, status_t (*del_policy) (kernel_interface_t *this,
traffic_selector_t *src_ts, traffic_selector_t *src_ts,
traffic_selector_t *dst_ts, traffic_selector_t *dst_ts,
policy_dir_t direction, u_int32_t reqid, policy_dir_t direction, u_int32_t reqid,
mark_t mark, bool unrouted); mark_t mark, policy_priority_t priority);
/** /**
* Get our outgoing source address for a destination. * Get our outgoing source address for a destination.
+16 -4
View File
@@ -27,6 +27,7 @@
typedef enum ipsec_mode_t ipsec_mode_t; typedef enum ipsec_mode_t ipsec_mode_t;
typedef enum policy_dir_t policy_dir_t; typedef enum policy_dir_t policy_dir_t;
typedef enum policy_type_t policy_type_t; typedef enum policy_type_t policy_type_t;
typedef enum policy_priority_t policy_priority_t;
typedef enum ipcomp_transform_t ipcomp_transform_t; typedef enum ipcomp_transform_t ipcomp_transform_t;
typedef struct kernel_ipsec_t kernel_ipsec_t; typedef struct kernel_ipsec_t kernel_ipsec_t;
typedef struct ipsec_sa_cfg_t ipsec_sa_cfg_t; typedef struct ipsec_sa_cfg_t ipsec_sa_cfg_t;
@@ -89,6 +90,16 @@ enum policy_type_t {
POLICY_DROP, POLICY_DROP,
}; };
/**
* High-level priority of a policy.
*/
enum policy_priority_t {
/** Default priority */
POLICY_PRIORITY_DEFAULT,
/** Priority for trap policies */
POLICY_PRIORITY_ROUTED,
};
/** /**
* IPComp transform IDs, as in RFC 4306 * IPComp transform IDs, as in RFC 4306
*/ */
@@ -305,7 +316,7 @@ struct kernel_ipsec_t {
* @param type type of policy, POLICY_(IPSEC|PASS|DROP) * @param type type of policy, POLICY_(IPSEC|PASS|DROP)
* @param sa details about the SA(s) tied to this policy * @param sa details about the SA(s) tied to this policy
* @param mark mark for this policy * @param mark mark for this policy
* @param routed TRUE, if this policy is routed in the kernel * @param priority priority of this policy
* @return SUCCESS if operation completed * @return SUCCESS if operation completed
*/ */
status_t (*add_policy) (kernel_ipsec_t *this, status_t (*add_policy) (kernel_ipsec_t *this,
@@ -313,7 +324,8 @@ struct kernel_ipsec_t {
traffic_selector_t *src_ts, traffic_selector_t *src_ts,
traffic_selector_t *dst_ts, traffic_selector_t *dst_ts,
policy_dir_t direction, policy_type_t type, policy_dir_t direction, policy_type_t type,
ipsec_sa_cfg_t *sa, mark_t mark, bool routed); ipsec_sa_cfg_t *sa, mark_t mark,
policy_priority_t priority);
/** /**
* Query the use time of a policy. * Query the use time of a policy.
@@ -348,14 +360,14 @@ struct kernel_ipsec_t {
* @param direction direction of traffic, POLICY_(IN|OUT|FWD) * @param direction direction of traffic, POLICY_(IN|OUT|FWD)
* @param reqid unique ID of the associated SA * @param reqid unique ID of the associated SA
* @param mark optional mark * @param mark optional mark
* @param unrouted TRUE, if this policy is unrouted from the kernel * @param priority priority of the policy
* @return SUCCESS if operation completed * @return SUCCESS if operation completed
*/ */
status_t (*del_policy) (kernel_ipsec_t *this, status_t (*del_policy) (kernel_ipsec_t *this,
traffic_selector_t *src_ts, traffic_selector_t *src_ts,
traffic_selector_t *dst_ts, traffic_selector_t *dst_ts,
policy_dir_t direction, u_int32_t reqid, policy_dir_t direction, u_int32_t reqid,
mark_t mark, bool unrouted); mark_t mark, policy_priority_t priority);
/** /**
* Install a bypass policy for the given socket. * Install a bypass policy for the given socket.
@@ -1971,7 +1971,7 @@ METHOD(kernel_ipsec_t, add_policy, status_t,
private_kernel_klips_ipsec_t *this, host_t *src, host_t *dst, private_kernel_klips_ipsec_t *this, host_t *src, host_t *dst,
traffic_selector_t *src_ts, traffic_selector_t *dst_ts, traffic_selector_t *src_ts, traffic_selector_t *dst_ts,
policy_dir_t direction, policy_type_t type, ipsec_sa_cfg_t *sa, policy_dir_t direction, policy_type_t type, ipsec_sa_cfg_t *sa,
mark_t mark, bool routed) mark_t mark, policy_priority_t priority)
{ {
unsigned char request[PFKEY_BUFFER_SIZE]; unsigned char request[PFKEY_BUFFER_SIZE];
struct sadb_msg *msg, *out; struct sadb_msg *msg, *out;
@@ -2013,7 +2013,7 @@ METHOD(kernel_ipsec_t, add_policy, status_t,
this->policies->insert_last(this->policies, policy); this->policies->insert_last(this->policies, policy);
} }
if (routed) if (priority == POLICY_PRIORITY_ROUTED)
{ {
/* we install this as a %trap eroute in the kernel, later to be /* we install this as a %trap eroute in the kernel, later to be
* triggered by packets matching the policy (-> ACQUIRE). */ * triggered by packets matching the policy (-> ACQUIRE). */
@@ -2049,9 +2049,11 @@ METHOD(kernel_ipsec_t, add_policy, status_t,
msg = (struct sadb_msg*)request; msg = (struct sadb_msg*)request;
/* FIXME: SADB_X_SAFLAGS_INFLOW may be required, if we add an inbound policy for an IPIP SA */ /* FIXME: SADB_X_SAFLAGS_INFLOW may be required, if we add an inbound policy for an IPIP SA */
build_addflow(msg, satype, spi, routed ? NULL : src, routed ? NULL : dst, build_addflow(msg, satype, spi,
policy->src.net, policy->src.mask, policy->dst.net, policy->dst.mask, priority == POLICY_PRIORITY_ROUTED ? NULL : src,
policy->src.proto, found != NULL); priority == POLICY_PRIORITY_ROUTED ? NULL : dst,
policy->src.net, policy->src.mask, policy->dst.net,
policy->dst.mask, policy->src.proto, found != NULL);
this->mutex->unlock(this->mutex); this->mutex->unlock(this->mutex);
@@ -2348,7 +2350,7 @@ METHOD(kernel_ipsec_t, query_policy, status_t,
METHOD(kernel_ipsec_t, del_policy, status_t, METHOD(kernel_ipsec_t, del_policy, status_t,
private_kernel_klips_ipsec_t *this, traffic_selector_t *src_ts, private_kernel_klips_ipsec_t *this, traffic_selector_t *src_ts,
traffic_selector_t *dst_ts, policy_dir_t direction, u_int32_t reqid, traffic_selector_t *dst_ts, policy_dir_t direction, u_int32_t reqid,
mark_t mark, bool unrouted) mark_t mark, policy_priority_t priority)
{ {
unsigned char request[PFKEY_BUFFER_SIZE]; unsigned char request[PFKEY_BUFFER_SIZE];
struct sadb_msg *msg = (struct sadb_msg*)request, *out; struct sadb_msg *msg = (struct sadb_msg*)request, *out;
@@ -2382,7 +2384,8 @@ METHOD(kernel_ipsec_t, del_policy, status_t,
policy_entry_destroy(policy); policy_entry_destroy(policy);
/* decrease appropriate counter */ /* decrease appropriate counter */
unrouted ? found->trapcount-- : found->activecount--; priority == POLICY_PRIORITY_ROUTED ? found->trapcount--
: found->activecount--;
if (found->trapcount == 0) if (found->trapcount == 0)
{ {
@@ -59,8 +59,7 @@
#endif /*IPV6_XFRM_POLICY*/ #endif /*IPV6_XFRM_POLICY*/
/** Default priority of installed policies */ /** Default priority of installed policies */
#define PRIO_LOW 1024 #define PRIO_BASE 512
#define PRIO_HIGH 512
/** Default replay window size, if not set using charon.replay_window */ /** Default replay window size, if not set using charon.replay_window */
#define DEFAULT_REPLAY_WINDOW 32 #define DEFAULT_REPLAY_WINDOW 32
@@ -567,6 +566,30 @@ static bool policy_equals(policy_entry_t *key, policy_entry_t *other_key)
key->direction == other_key->direction; key->direction == other_key->direction;
} }
/**
* Calculate the priority of a policy
*/
static inline u_int32_t get_priority(policy_entry_t *policy,
policy_priority_t prio)
{
u_int32_t priority = PRIO_BASE;
switch (prio)
{
case POLICY_PRIORITY_ROUTED:
priority <<= 1;
/* fall-through */
case POLICY_PRIORITY_DEFAULT:
break;
}
/* calculate priority based on selector size, small size = high prio */
priority -= policy->sel.prefixlen_s;
priority -= policy->sel.prefixlen_d;
priority <<= 2; /* make some room for the two flags */
priority += policy->sel.sport_mask || policy->sel.dport_mask ? 0 : 2;
priority += policy->sel.proto ? 0 : 1;
return priority;
}
/** /**
* Convert the general ipsec mode to the one defined in xfrm.h * Convert the general ipsec mode to the one defined in xfrm.h
*/ */
@@ -2149,7 +2172,7 @@ METHOD(kernel_ipsec_t, add_policy, status_t,
private_kernel_netlink_ipsec_t *this, host_t *src, host_t *dst, private_kernel_netlink_ipsec_t *this, host_t *src, host_t *dst,
traffic_selector_t *src_ts, traffic_selector_t *dst_ts, traffic_selector_t *src_ts, traffic_selector_t *dst_ts,
policy_dir_t direction, policy_type_t type, ipsec_sa_cfg_t *sa, policy_dir_t direction, policy_type_t type, ipsec_sa_cfg_t *sa,
mark_t mark, bool routed) mark_t mark, policy_priority_t priority)
{ {
policy_entry_t *policy, *current; policy_entry_t *policy, *current;
policy_sa_t *assigned_sa, *current_sa; policy_sa_t *assigned_sa, *current_sa;
@@ -2195,15 +2218,7 @@ METHOD(kernel_ipsec_t, add_policy, status_t,
/* cache the assigned IPsec SA */ /* cache the assigned IPsec SA */
assigned_sa = policy_sa_create(this, direction, type, src, dst, src_ts, assigned_sa = policy_sa_create(this, direction, type, src, dst, src_ts,
dst_ts, mark, sa); dst_ts, mark, sa);
assigned_sa->priority = get_priority(policy, priority);
/* calculate priority based on selector size, small size = high prio */
assigned_sa->priority = routed ? PRIO_LOW : PRIO_HIGH;
assigned_sa->priority -= policy->sel.prefixlen_s;
assigned_sa->priority -= policy->sel.prefixlen_d;
assigned_sa->priority <<= 2; /* make some room for the two flags */
assigned_sa->priority += policy->sel.sport_mask ||
policy->sel.dport_mask ? 0 : 2;
assigned_sa->priority += policy->sel.proto ? 0 : 1;
/* insert the SA according to its priority */ /* insert the SA according to its priority */
enumerator = policy->used_by->create_enumerator(policy->used_by); enumerator = policy->used_by->create_enumerator(policy->used_by);
@@ -2354,7 +2369,7 @@ METHOD(kernel_ipsec_t, query_policy, status_t,
METHOD(kernel_ipsec_t, del_policy, status_t, METHOD(kernel_ipsec_t, del_policy, status_t,
private_kernel_netlink_ipsec_t *this, traffic_selector_t *src_ts, private_kernel_netlink_ipsec_t *this, traffic_selector_t *src_ts,
traffic_selector_t *dst_ts, policy_dir_t direction, u_int32_t reqid, traffic_selector_t *dst_ts, policy_dir_t direction, u_int32_t reqid,
mark_t mark, bool unrouted) mark_t mark, policy_priority_t prio)
{ {
policy_entry_t *current, policy; policy_entry_t *current, policy;
enumerator_t *enumerator; enumerator_t *enumerator;
@@ -2363,6 +2378,7 @@ METHOD(kernel_ipsec_t, del_policy, status_t,
struct nlmsghdr *hdr; struct nlmsghdr *hdr;
struct xfrm_userpolicy_id *policy_id; struct xfrm_userpolicy_id *policy_id;
bool is_installed = TRUE; bool is_installed = TRUE;
u_int32_t priority;
if (mark.value) if (mark.value)
{ {
@@ -2402,11 +2418,12 @@ METHOD(kernel_ipsec_t, del_policy, status_t,
return NOT_FOUND; return NOT_FOUND;
} }
/* remove mapping to SA by reqid */ /* remove mapping to SA by reqid and priority */
priority = get_priority(current, prio);
enumerator = current->used_by->create_enumerator(current->used_by); enumerator = current->used_by->create_enumerator(current->used_by);
while (enumerator->enumerate(enumerator, (void**)&mapping)) while (enumerator->enumerate(enumerator, (void**)&mapping))
{ {
if (reqid == mapping->sa->cfg.reqid) if (reqid == mapping->sa->cfg.reqid && priority == mapping->priority)
{ {
current->used_by->remove_at(current->used_by, enumerator); current->used_by->remove_at(current->used_by, enumerator);
policy_sa_destroy(mapping, &direction, this); policy_sa_destroy(mapping, &direction, this);
@@ -100,8 +100,7 @@
#endif #endif
/** default priority of installed policies */ /** default priority of installed policies */
#define PRIO_LOW 1024 #define PRIO_BASE 512
#define PRIO_HIGH 512
#ifdef __APPLE__ #ifdef __APPLE__
/** from xnu/bsd/net/pfkeyv2.h */ /** from xnu/bsd/net/pfkeyv2.h */
@@ -501,6 +500,32 @@ static inline bool policy_entry_match_byindex(policy_entry_t *current,
return current->index == *index; return current->index == *index;
} }
/**
* Calculate the priority of a policy
*/
static inline u_int32_t get_priority(policy_entry_t *policy,
policy_priority_t prio)
{
u_int32_t priority = PRIO_BASE;
switch (prio)
{
case POLICY_PRIORITY_ROUTED:
priority <<= 1;
/* fall-through */
case POLICY_PRIORITY_DEFAULT:
break;
}
/* calculate priority based on selector size, small size = high prio */
priority -= policy->src.mask;
priority -= policy->dst.mask;
priority <<= 2; /* make some room for the two flags */
priority += policy->src.net->get_port(policy->src.net) ||
policy->dst.net->get_port(policy->dst.net) ?
0 : 2;
priority += policy->src.proto != IPSEC_PROTO_ANY ? 0 : 1;
return priority;
}
typedef struct pfkey_msg_t pfkey_msg_t; typedef struct pfkey_msg_t pfkey_msg_t;
struct pfkey_msg_t struct pfkey_msg_t
@@ -2008,7 +2033,7 @@ METHOD(kernel_ipsec_t, add_policy, status_t,
private_kernel_pfkey_ipsec_t *this, host_t *src, host_t *dst, private_kernel_pfkey_ipsec_t *this, host_t *src, host_t *dst,
traffic_selector_t *src_ts, traffic_selector_t *dst_ts, traffic_selector_t *src_ts, traffic_selector_t *dst_ts,
policy_dir_t direction, policy_type_t type, ipsec_sa_cfg_t *sa, policy_dir_t direction, policy_type_t type, ipsec_sa_cfg_t *sa,
mark_t mark, bool routed) mark_t mark, policy_priority_t priority)
{ {
policy_entry_t *policy, *found = NULL; policy_entry_t *policy, *found = NULL;
policy_sa_t *assigned_sa, *current_sa; policy_sa_t *assigned_sa, *current_sa;
@@ -2043,17 +2068,7 @@ METHOD(kernel_ipsec_t, add_policy, status_t,
/* cache the assigned IPsec SA */ /* cache the assigned IPsec SA */
assigned_sa = policy_sa_create(this, direction, type, src, dst, src_ts, assigned_sa = policy_sa_create(this, direction, type, src, dst, src_ts,
dst_ts, sa); dst_ts, sa);
assigned_sa->priority = get_priority(policy, priority);
/* calculate priority based on selector size, small size = high prio */
assigned_sa->priority = routed ? PRIO_LOW : PRIO_HIGH;
assigned_sa->priority -= policy->src.mask;
assigned_sa->priority -= policy->dst.mask;
assigned_sa->priority <<= 2; /* make some room for the two flags */
assigned_sa->priority += policy->src.net->get_port(policy->src.net) ||
policy->dst.net->get_port(policy->dst.net) ?
0 : 2;
assigned_sa->priority += policy->src.proto != IPSEC_PROTO_ANY ? 0 : 1;
/* insert the SA according to its priority */ /* insert the SA according to its priority */
enumerator = policy->used_by->create_enumerator(policy->used_by); enumerator = policy->used_by->create_enumerator(policy->used_by);
@@ -2197,7 +2212,7 @@ METHOD(kernel_ipsec_t, query_policy, status_t,
METHOD(kernel_ipsec_t, del_policy, status_t, METHOD(kernel_ipsec_t, del_policy, status_t,
private_kernel_pfkey_ipsec_t *this, traffic_selector_t *src_ts, private_kernel_pfkey_ipsec_t *this, traffic_selector_t *src_ts,
traffic_selector_t *dst_ts, policy_dir_t direction, u_int32_t reqid, traffic_selector_t *dst_ts, policy_dir_t direction, u_int32_t reqid,
mark_t mark, bool unrouted) mark_t mark, policy_priority_t prio)
{ {
unsigned char request[PFKEY_BUFFER_SIZE]; unsigned char request[PFKEY_BUFFER_SIZE];
struct sadb_msg *msg, *out; struct sadb_msg *msg, *out;
@@ -2206,6 +2221,7 @@ METHOD(kernel_ipsec_t, del_policy, status_t,
policy_sa_t *mapping; policy_sa_t *mapping;
enumerator_t *enumerator; enumerator_t *enumerator;
bool is_installed = TRUE; bool is_installed = TRUE;
u_int32_t priority;
size_t len; size_t len;
if (dir2kernel(direction) == IPSEC_DIR_INVALID) if (dir2kernel(direction) == IPSEC_DIR_INVALID)
@@ -2234,11 +2250,12 @@ METHOD(kernel_ipsec_t, del_policy, status_t,
policy_entry_destroy(policy, this); policy_entry_destroy(policy, this);
policy = found; policy = found;
/* remove mapping to SA by reqid */ /* remove mapping to SA by reqid and priority */
priority = get_priority(policy, prio);
enumerator = policy->used_by->create_enumerator(policy->used_by); enumerator = policy->used_by->create_enumerator(policy->used_by);
while (enumerator->enumerate(enumerator, (void**)&mapping)) while (enumerator->enumerate(enumerator, (void**)&mapping))
{ {
if (reqid == mapping->sa->cfg.reqid) if (reqid == mapping->sa->cfg.reqid && priority == mapping->priority)
{ {
policy->used_by->remove_at(policy->used_by, enumerator); policy->used_by->remove_at(policy->used_by, enumerator);
break; break;
+7 -6
View File
@@ -780,8 +780,9 @@ static bool raw_eroute(const ip_address *this_host,
host_t *host_src, *host_dst; host_t *host_src, *host_dst;
policy_type_t type = POLICY_IPSEC; policy_type_t type = POLICY_IPSEC;
policy_dir_t dir = POLICY_OUT; policy_dir_t dir = POLICY_OUT;
policy_priority_t priority = POLICY_PRIORITY_DEFAULT;
char text_said[SATOT_BUF]; char text_said[SATOT_BUF];
bool ok = TRUE, routed = FALSE, bool ok = TRUE,
deleting = (op & ERO_MASK) == ERO_DELETE, deleting = (op & ERO_MASK) == ERO_DELETE,
replacing = op & (SADB_X_SAFLAGS_REPLACEFLOW << ERO_FLAG_SHIFT); replacing = op & (SADB_X_SAFLAGS_REPLACEFLOW << ERO_FLAG_SHIFT);
@@ -819,7 +820,7 @@ static bool raw_eroute(const ip_address *this_host,
{ {
return TRUE; return TRUE;
} }
routed = TRUE; priority = POLICY_PRIORITY_ROUTED;
break; break;
} }
} }
@@ -837,14 +838,14 @@ static bool raw_eroute(const ip_address *this_host,
if (deleting || replacing) if (deleting || replacing)
{ {
hydra->kernel_interface->del_policy(hydra->kernel_interface, hydra->kernel_interface->del_policy(hydra->kernel_interface,
ts_src, ts_dst, dir, sa->reqid, mark, routed); ts_src, ts_dst, dir, sa->reqid, mark, priority);
} }
if (!deleting) if (!deleting)
{ {
ok = hydra->kernel_interface->add_policy(hydra->kernel_interface, ok = hydra->kernel_interface->add_policy(hydra->kernel_interface,
host_src, host_dst, ts_src, ts_dst, dir, type, sa, host_src, host_dst, ts_src, ts_dst, dir, type, sa,
mark, routed) == SUCCESS; mark, priority) == SUCCESS;
} }
if (dir == POLICY_IN) if (dir == POLICY_IN)
@@ -853,7 +854,7 @@ static bool raw_eroute(const ip_address *this_host,
if (deleting || replacing) if (deleting || replacing)
{ {
hydra->kernel_interface->del_policy(hydra->kernel_interface, hydra->kernel_interface->del_policy(hydra->kernel_interface,
ts_src, ts_dst, dir, sa->reqid, mark, routed); ts_src, ts_dst, dir, sa->reqid, mark, priority);
} }
if (!deleting && ok && if (!deleting && ok &&
@@ -861,7 +862,7 @@ static bool raw_eroute(const ip_address *this_host,
{ {
ok = hydra->kernel_interface->add_policy(hydra->kernel_interface, ok = hydra->kernel_interface->add_policy(hydra->kernel_interface,
host_src, host_dst, ts_src, ts_dst, dir, type, sa, host_src, host_dst, ts_src, ts_dst, dir, type, sa,
mark, routed) == SUCCESS; mark, priority) == SUCCESS;
} }
} }