private_load_tester_ipsec_t *this, host_t *src, host_t *dst,
traffic_selector_t *src_ts, traffic_selector_t *dst_ts,
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;
}
METHOD(kernel_ipsec_t, del_policy, status_t,
private_load_tester_ipsec_t *this, traffic_selector_t *src_ts,
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;
}
/*
- * Copyright (C) 2006-2010 Tobias Brunner
+ * Copyright (C) 2006-2011 Tobias Brunner
* Copyright (C) 2005-2008 Martin Willi
* Copyright (C) 2006 Daniel Roethlisberger
* Copyright (C) 2005 Jan Hutter
enumerator_t *enumerator;
traffic_selector_t *my_ts, *other_ts;
status_t status = SUCCESS;
- bool routed = (this->state == CHILD_CREATED);
/* apply traffic selectors */
enumerator = my_ts_list->create_enumerator(my_ts_list);
if (this->config->install_policy(this->config))
{
+ policy_priority_t priority;
ipsec_sa_cfg_t my_sa = {
.mode = this->mode,
.reqid = this->reqid,
other_sa.ah.spi = this->other_spi;
}
+ priority = this->state == CHILD_CREATED ? POLICY_PRIORITY_ROUTED
+ : POLICY_PRIORITY_DEFAULT;
+
/* enumerate pairs of traffic selectors */
enumerator = create_policy_enumerator(this);
while (enumerator->enumerate(enumerator, &my_ts, &other_ts))
hydra->kernel_interface,
this->my_addr, this->other_addr, my_ts, other_ts,
POLICY_OUT, POLICY_IPSEC, &other_sa,
- this->mark_out, routed);
+ this->mark_out, priority);
status |= hydra->kernel_interface->add_policy(
hydra->kernel_interface,
this->other_addr, this->my_addr, other_ts, my_ts,
POLICY_IN, POLICY_IPSEC, &my_sa,
- this->mark_in, routed);
+ this->mark_in, priority);
if (this->mode != MODE_TRANSPORT)
{
status |= hydra->kernel_interface->add_policy(
hydra->kernel_interface,
this->other_addr, this->my_addr, other_ts, my_ts,
POLICY_FWD, POLICY_IPSEC, &my_sa,
- this->mark_in, routed);
+ this->mark_in, priority);
}
if (status != SUCCESS)
/* remove old policies first */
hydra->kernel_interface->del_policy(hydra->kernel_interface,
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,
other_ts, my_ts, POLICY_IN, this->reqid,
- this->mark_in, FALSE);
+ this->mark_in, POLICY_PRIORITY_DEFAULT);
if (this->mode != MODE_TRANSPORT)
{
hydra->kernel_interface->del_policy(hydra->kernel_interface,
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 */
/* reinstall updated policies */
hydra->kernel_interface->add_policy(hydra->kernel_interface,
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,
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)
{
hydra->kernel_interface->add_policy(hydra->kernel_interface,
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_t *enumerator;
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);
{
hydra->kernel_interface->del_policy(hydra->kernel_interface,
my_ts, other_ts, POLICY_OUT, this->reqid,
- this->mark_out, unrouted);
+ this->mark_out, priority);
hydra->kernel_interface->del_policy(hydra->kernel_interface,
other_ts, my_ts, POLICY_IN, this->reqid,
- this->mark_in, unrouted);
+ this->mark_in, priority);
if (this->mode != MODE_TRANSPORT)
{
hydra->kernel_interface->del_policy(hydra->kernel_interface,
other_ts, my_ts, POLICY_FWD, this->reqid,
- this->mark_in, unrouted);
+ this->mark_in, priority);
}
}
enumerator->destroy(enumerator);
status |= hydra->kernel_interface->add_policy(
hydra->kernel_interface, host_any, host_any,
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 */
status |= hydra->kernel_interface->add_policy(
hydra->kernel_interface, host_any, host_any,
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 */
status |= hydra->kernel_interface->add_policy(
hydra->kernel_interface, host_any, host_any,
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);
}
status |= hydra->kernel_interface->del_policy(
hydra->kernel_interface, my_ts, other_ts,
POLICY_OUT, 0, child->get_mark(child, FALSE),
- FALSE);
+ POLICY_PRIORITY_DEFAULT);
/* uninstall in policy */
status |= hydra->kernel_interface->del_policy(
hydra->kernel_interface, other_ts, my_ts,
POLICY_IN, 0, child->get_mark(child, TRUE),
- FALSE);
+ POLICY_PRIORITY_DEFAULT);
/* uninstall forward policy */
status |= hydra->kernel_interface->del_policy(
hydra->kernel_interface, other_ts, my_ts,
POLICY_FWD, 0, child->get_mark(child, TRUE),
- FALSE);
+ POLICY_PRIORITY_DEFAULT);
}
e_other_ts->destroy(e_other_ts);
}
private_kernel_interface_t *this, host_t *src, host_t *dst,
traffic_selector_t *src_ts, traffic_selector_t *dst_ts,
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)
{
return NOT_SUPPORTED;
}
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, del_policy, status_t,
private_kernel_interface_t *this, traffic_selector_t *src_ts,
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)
{
return NOT_SUPPORTED;
}
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*,
* @param type type of policy, POLICY_(IPSEC|PASS|DROP)
* @param sa details about the SA(s) tied to 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
*/
status_t (*add_policy) (kernel_interface_t *this,
traffic_selector_t *src_ts,
traffic_selector_t *dst_ts,
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.
* @param direction direction of traffic, POLICY_(IN|OUT|FWD)
* @param reqid unique ID of the associated SA
* @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
*/
status_t (*del_policy) (kernel_interface_t *this,
traffic_selector_t *src_ts,
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);
/**
* Get our outgoing source address for a destination.
typedef enum ipsec_mode_t ipsec_mode_t;
typedef enum policy_dir_t policy_dir_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 struct kernel_ipsec_t kernel_ipsec_t;
typedef struct ipsec_sa_cfg_t ipsec_sa_cfg_t;
};
/**
+ * 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
*/
enum ipcomp_transform_t {
* @param type type of policy, POLICY_(IPSEC|PASS|DROP)
* @param sa details about the SA(s) tied to 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
*/
status_t (*add_policy) (kernel_ipsec_t *this,
traffic_selector_t *src_ts,
traffic_selector_t *dst_ts,
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.
* @param direction direction of traffic, POLICY_(IN|OUT|FWD)
* @param reqid unique ID of the associated SA
* @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
*/
status_t (*del_policy) (kernel_ipsec_t *this,
traffic_selector_t *src_ts,
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);
/**
* Install a bypass policy for the given socket.
private_kernel_klips_ipsec_t *this, host_t *src, host_t *dst,
traffic_selector_t *src_ts, traffic_selector_t *dst_ts,
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];
struct sadb_msg *msg, *out;
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
* triggered by packets matching the policy (-> ACQUIRE). */
msg = (struct sadb_msg*)request;
/* 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,
- policy->src.net, policy->src.mask, policy->dst.net, policy->dst.mask,
- policy->src.proto, found != NULL);
+ build_addflow(msg, satype, spi,
+ priority == POLICY_PRIORITY_ROUTED ? NULL : src,
+ 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);
METHOD(kernel_ipsec_t, del_policy, status_t,
private_kernel_klips_ipsec_t *this, traffic_selector_t *src_ts,
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];
struct sadb_msg *msg = (struct sadb_msg*)request, *out;
policy_entry_destroy(policy);
/* decrease appropriate counter */
- unrouted ? found->trapcount-- : found->activecount--;
+ priority == POLICY_PRIORITY_ROUTED ? found->trapcount--
+ : found->activecount--;
if (found->trapcount == 0)
{
#endif /*IPV6_XFRM_POLICY*/
/** Default priority of installed policies */
-#define PRIO_LOW 1024
-#define PRIO_HIGH 512
+#define PRIO_BASE 512
/** Default replay window size, if not set using charon.replay_window */
#define DEFAULT_REPLAY_WINDOW 32
}
/**
+ * 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
*/
static u_int8_t mode2kernel(ipsec_mode_t mode)
private_kernel_netlink_ipsec_t *this, host_t *src, host_t *dst,
traffic_selector_t *src_ts, traffic_selector_t *dst_ts,
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_sa_t *assigned_sa, *current_sa;
/* cache the assigned IPsec SA */
assigned_sa = policy_sa_create(this, direction, type, src, dst, src_ts,
dst_ts, mark, sa);
-
- /* 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;
+ assigned_sa->priority = get_priority(policy, priority);
/* insert the SA according to its priority */
enumerator = policy->used_by->create_enumerator(policy->used_by);
METHOD(kernel_ipsec_t, del_policy, status_t,
private_kernel_netlink_ipsec_t *this, traffic_selector_t *src_ts,
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;
enumerator_t *enumerator;
struct nlmsghdr *hdr;
struct xfrm_userpolicy_id *policy_id;
bool is_installed = TRUE;
+ u_int32_t priority;
if (mark.value)
{
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);
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);
policy_sa_destroy(mapping, &direction, this);
#endif
/** default priority of installed policies */
-#define PRIO_LOW 1024
-#define PRIO_HIGH 512
+#define PRIO_BASE 512
#ifdef __APPLE__
/** from xnu/bsd/net/pfkeyv2.h */
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;
struct pfkey_msg_t
private_kernel_pfkey_ipsec_t *this, host_t *src, host_t *dst,
traffic_selector_t *src_ts, traffic_selector_t *dst_ts,
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_sa_t *assigned_sa, *current_sa;
/* cache the assigned IPsec SA */
assigned_sa = policy_sa_create(this, direction, type, src, dst, src_ts,
dst_ts, sa);
-
-
- /* 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;
+ assigned_sa->priority = get_priority(policy, priority);
/* insert the SA according to its priority */
enumerator = policy->used_by->create_enumerator(policy->used_by);
METHOD(kernel_ipsec_t, del_policy, status_t,
private_kernel_pfkey_ipsec_t *this, traffic_selector_t *src_ts,
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];
struct sadb_msg *msg, *out;
policy_sa_t *mapping;
enumerator_t *enumerator;
bool is_installed = TRUE;
+ u_int32_t priority;
size_t len;
if (dir2kernel(direction) == IPSEC_DIR_INVALID)
policy_entry_destroy(policy, this);
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);
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);
break;
host_t *host_src, *host_dst;
policy_type_t type = POLICY_IPSEC;
policy_dir_t dir = POLICY_OUT;
+ policy_priority_t priority = POLICY_PRIORITY_DEFAULT;
char text_said[SATOT_BUF];
- bool ok = TRUE, routed = FALSE,
+ bool ok = TRUE,
deleting = (op & ERO_MASK) == ERO_DELETE,
replacing = op & (SADB_X_SAFLAGS_REPLACEFLOW << ERO_FLAG_SHIFT);
{
return TRUE;
}
- routed = TRUE;
+ priority = POLICY_PRIORITY_ROUTED;
break;
}
}
if (deleting || replacing)
{
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 = hydra->kernel_interface->add_policy(hydra->kernel_interface,
host_src, host_dst, ts_src, ts_dst, dir, type, sa,
- mark, routed) == SUCCESS;
+ mark, priority) == SUCCESS;
}
if (dir == POLICY_IN)
if (deleting || replacing)
{
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 &&
{
ok = hydra->kernel_interface->add_policy(hydra->kernel_interface,
host_src, host_dst, ts_src, ts_dst, dir, type, sa,
- mark, routed) == SUCCESS;
+ mark, priority) == SUCCESS;
}
}