*/
uint32_t manual_prio;
+ /**
+ * Optional restriction of IPsec policy to a given network interface
+ */
+ char *interface;
+
/**
* set up IPsec transport SA in MIPv6 proxy mode
*/
return this->manual_prio;
}
+METHOD(child_cfg_t, get_interface, char*,
+ private_child_cfg_t *this)
+{
+ return this->interface;
+}
+
METHOD(child_cfg_t, get_replay_window, uint32_t,
private_child_cfg_t *this)
{
}
#define LT_PART_EQUALS(a, b) ({ a.life == b.life && a.rekey == b.rekey && a.jitter == b.jitter; })
-#define LIFETIME_EQUALS(a, b) ({ LT_PART_EQUALS(a.time, b.time) && LT_PART_EQUALS(a.bytes, b.bytes) && LT_PART_EQUALS(a.packets, b.packets); })
+#define LIFETIME_EQUALS(a, b) ({ LT_PART_EQUALS(a.time, b.time) && LT_PART_EQUALS(a.bytes, b.bytes) && LT_PART_EQUALS(a.packets, b.packets); })
METHOD(child_cfg_t, equals, bool,
private_child_cfg_t *this, child_cfg_t *other_pub)
this->replay_window == other->replay_window &&
this->proxy_mode == other->proxy_mode &&
this->install_policy == other->install_policy &&
- streq(this->updown, other->updown);
+ streq(this->updown, other->updown) &&
+ streq(this->interface, other->interface);
}
METHOD(child_cfg_t, get_ref, child_cfg_t*,
this->proposals->destroy_offset(this->proposals, offsetof(proposal_t, destroy));
this->my_ts->destroy_offset(this->my_ts, offsetof(traffic_selector_t, destroy));
this->other_ts->destroy_offset(this->other_ts, offsetof(traffic_selector_t, destroy));
- if (this->updown)
- {
- free(this->updown);
- }
+ free(this->updown);
+ free(this->interface);
free(this->name);
free(this);
}
.get_mark = _get_mark,
.get_tfc = _get_tfc,
.get_manual_prio = _get_manual_prio,
+ .get_interface = _get_interface,
.get_replay_window = _get_replay_window,
.set_replay_window = _set_replay_window,
.use_proxy_mode = _use_proxy_mode,
.use_ipcomp = data->ipcomp,
.tfc = data->tfc,
.manual_prio = data->priority,
+ .interface = strdupnull(data->interface),
.install_policy = !data->suppress_policies,
.refcount = 1,
.proposals = linked_list_create(),
*/
uint32_t (*get_manual_prio)(child_cfg_t *this);
+ /**
+ * Get optional network interface restricting IPsec policy
+ *
+ * @return network interface)
+ */
+ char* (*get_interface)(child_cfg_t *this);
+
/**
* Get anti-replay window size
*
uint32_t tfc;
/** Optional manually-set IPsec policy priority */
uint32_t priority;
+ /** Optional network interface restricting IPsec policy (cloned) */
+ char *interface;
/** lifetime_cfg_t for this child_cfg */
lifetime_cfg_t lifetime;
/** Inactivity timeout in s before closing a CHILD_SA */
linked_list_t *src_ts;
/** List of destination traffic selectors */
linked_list_t *dst_ts;
+ /** Network interface restricting policy */
+ char *interface;
/** Lifetime configuration */
lifetime_cfg_t *lifetime;
/** Encryption algorithm */
traffic_selector_t *dst_ts;
/** Optional mark */
mark_t mark;
+ /** Network interface restricting policy */
+ char *interface;
};
/**
#include <linux/rtnetlink.h>
#include <linux/xfrm.h>
#include <linux/udp.h>
+#include <net/if.h>
#include <unistd.h>
#include <time.h>
#include <errno.h>
* Convert a pair of traffic_selectors to an xfrm_selector
*/
static struct xfrm_selector ts2selector(traffic_selector_t *src,
- traffic_selector_t *dst)
+ traffic_selector_t *dst,
+ char *interface)
{
struct xfrm_selector sel;
uint16_t port;
sel.dport = htons(traffic_selector_icmp_code(port));
sel.dport_mask = sel.dport ? ~0 : 0;
}
- sel.ifindex = 0;
+ sel.ifindex = interface ? if_nametoindex(interface) : 0;
sel.user = 0;
return sel;
data->dst_ts->get_first(data->dst_ts,
(void**)&first_dst_ts) == SUCCESS)
{
- sa->sel = ts2selector(first_src_ts, first_dst_ts);
+ sa->sel = ts2selector(first_src_ts, first_dst_ts,
+ data->interface);
if (!this->proto_port_transport)
{
/* don't install proto/port on SA. This would break
/* create a policy */
INIT(policy,
- .sel = ts2selector(id->src_ts, id->dst_ts),
+ .sel = ts2selector(id->src_ts, id->dst_ts, id->interface),
.mark = id->mark.value & id->mark.mask,
.direction = id->dir,
.reqid = data->sa->reqid,
hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct xfrm_userpolicy_id));
policy_id = NLMSG_DATA(hdr);
- policy_id->sel = ts2selector(id->src_ts, id->dst_ts);
+ policy_id->sel = ts2selector(id->src_ts, id->dst_ts, id->interface);
policy_id->dir = id->dir;
if (!add_mark(hdr, sizeof(request), id->mark))
/* create a policy */
memset(&policy, 0, sizeof(policy_entry_t));
- policy.sel = ts2selector(id->src_ts, id->dst_ts);
+ policy.sel = ts2selector(id->src_ts, id->dst_ts, id->interface);
policy.mark = id->mark.value & id->mark.mask;
policy.direction = id->dir;
DBG2(DBG_CFG, " reqid = %u", cfg->reqid);
DBG2(DBG_CFG, " tfc = %d", cfg->tfc);
DBG2(DBG_CFG, " priority = %d", cfg->priority);
+ DBG2(DBG_CFG, " interface = %s", cfg->interface);
DBG2(DBG_CFG, " mark_in = %u/%u",
cfg->mark_in.value, cfg->mark_in.mask);
DBG2(DBG_CFG, " mark_out = %u/%u",
data->remote_ts->destroy_offset(data->remote_ts,
offsetof(traffic_selector_t, destroy));
free(data->cfg.updown);
+ free(data->cfg.interface);
}
/**
{ "mark_out", parse_mark, &child->cfg.mark_out },
{ "tfc_padding", parse_tfc, &child->cfg.tfc },
{ "priority", parse_uint32, &child->cfg.priority },
+ { "interface", parse_string, &child->cfg.interface },
};
return parse_rules(rules, countof(rules), name, value,
.src_ts = my_ts,
.dst_ts = other_ts,
.mark = this->mark_out,
+ .interface = this->config->get_interface(this->config),
};
kernel_ipsec_query_policy_t query = {};
.mode = this->mode,
.src_ts = src_ts,
.dst_ts = dst_ts,
+ .interface = inbound ? NULL : this->config->get_interface(this->config),
.lifetime = lifetime,
.enc_alg = enc_alg,
.enc_key = encr,
.src_ts = my_ts,
.dst_ts = other_ts,
.mark = this->mark_out,
+ .interface = this->config->get_interface(this->config),
}, in_id = {
.dir = POLICY_IN,
.src_ts = other_ts,
.src_ts = my_ts,
.dst_ts = other_ts,
.mark = this->mark_out,
+ .interface = this->config->get_interface(this->config),
}, in_id = {
.dir = POLICY_IN,
.src_ts = other_ts,
policy_type_t policy_type;
policy_priority_t policy_prio;
status_t status = SUCCESS;
+ uint32_t manual_prio;
+ char *interface;
ipsec_sa_cfg_t sa = { .mode = MODE_TRANSPORT };
switch (child->get_mode(child))
other_ts_list = child->get_traffic_selectors(child, FALSE, NULL, hosts);
hosts->destroy(hosts);
+ manual_prio = child->get_manual_prio(child);
+ interface = child->get_interface(child);
+
/* enumerate pairs of traffic selectors */
e_my_ts = my_ts_list->create_enumerator(my_ts_list);
while (e_my_ts->enumerate(e_my_ts, &my_ts))
.src_ts = my_ts,
.dst_ts = other_ts,
.mark = child->get_mark(child, FALSE),
+ .interface = interface,
};
kernel_ipsec_manage_policy_t policy = {
.type = policy_type,
.prio = policy_prio,
- .manual_prio = child->get_manual_prio(child),
+ .manual_prio = manual_prio,
.src = host_any,
.dst = host_any,
.sa = &sa,
.src_ts = other_ts,
.dst_ts = my_ts,
.mark = child->get_mark(child, TRUE),
+ .interface = interface,
};
status |= charon->kernel->add_policy(charon->kernel, &id, &policy);
/* install "inbound" forward policy */
policy_type_t policy_type;
policy_priority_t policy_prio;
status_t status = SUCCESS;
+ uint32_t manual_prio;
+ char *interface;
ipsec_sa_cfg_t sa = { .mode = MODE_TRANSPORT };
switch (child->get_mode(child))
other_ts_list = child->get_traffic_selectors(child, FALSE, NULL, hosts);
hosts->destroy(hosts);
+ manual_prio = child->get_manual_prio(child);
+ interface = child->get_interface(child);
+
/* enumerate pairs of traffic selectors */
e_my_ts = my_ts_list->create_enumerator(my_ts_list);
while (e_my_ts->enumerate(e_my_ts, &my_ts))
.src_ts = my_ts,
.dst_ts = other_ts,
.mark = child->get_mark(child, FALSE),
+ .interface = interface,
};
kernel_ipsec_manage_policy_t policy = {
.type = policy_type,
.prio = policy_prio,
- .manual_prio = child->get_manual_prio(child),
+ .manual_prio = manual_prio,
.src = host_any,
.dst = host_any,
.sa = &sa,
.src_ts = other_ts,
.dst_ts = my_ts,
.mark = child->get_mark(child, TRUE),
+ .interface = interface,
};
status |= charon->kernel->del_policy(charon->kernel, &id, &policy);
/* uninstall "inbound" forward policy */
high-priority drop policies. The default of _0_ uses dynamically calculated
priorities based on the size of the traffic selectors.
+connections.<conn>.children.<child>.interface =
+ Optional interface name to restrict IPsec policies.
+
connections.<conn>.children.<child>.mark_in = 0/0x00000000
Netfilter mark and mask for input traffic.