diff options
-rw-r--r-- | src/libcharon/config/child_cfg.c | 24 | ||||
-rw-r--r-- | src/libcharon/config/child_cfg.h | 9 | ||||
-rw-r--r-- | src/libcharon/kernel/kernel_ipsec.h | 4 | ||||
-rw-r--r-- | src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c | 15 | ||||
-rw-r--r-- | src/libcharon/plugins/vici/vici_config.c | 3 | ||||
-rw-r--r-- | src/libcharon/sa/child_sa.c | 4 | ||||
-rw-r--r-- | src/libcharon/sa/shunt_manager.c | 18 | ||||
-rw-r--r-- | src/swanctl/swanctl.opt | 3 |
8 files changed, 66 insertions, 14 deletions
diff --git a/src/libcharon/config/child_cfg.c b/src/libcharon/config/child_cfg.c index a7ec167a4..be84621d4 100644 --- a/src/libcharon/config/child_cfg.c +++ b/src/libcharon/config/child_cfg.c @@ -139,6 +139,11 @@ struct private_child_cfg_t { 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 */ bool proxy_mode; @@ -512,6 +517,12 @@ METHOD(child_cfg_t, get_manual_prio, uint32_t, 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) { @@ -537,7 +548,7 @@ METHOD(child_cfg_t, install_policy, bool, } #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) @@ -585,7 +596,8 @@ METHOD(child_cfg_t, equals, bool, 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*, @@ -603,10 +615,8 @@ METHOD(child_cfg_t, destroy, void, 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); } @@ -641,6 +651,7 @@ child_cfg_t *child_cfg_create(char *name, child_cfg_create_t *data) .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, @@ -665,6 +676,7 @@ child_cfg_t *child_cfg_create(char *name, child_cfg_create_t *data) .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(), diff --git a/src/libcharon/config/child_cfg.h b/src/libcharon/config/child_cfg.h index 8ac9c30ca..7d348fd6c 100644 --- a/src/libcharon/config/child_cfg.h +++ b/src/libcharon/config/child_cfg.h @@ -244,6 +244,13 @@ struct child_cfg_t { 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 * * @return anti-replay window size @@ -318,6 +325,8 @@ struct child_cfg_create_t { 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 */ diff --git a/src/libcharon/kernel/kernel_ipsec.h b/src/libcharon/kernel/kernel_ipsec.h index 3a06ce66b..0ad566068 100644 --- a/src/libcharon/kernel/kernel_ipsec.h +++ b/src/libcharon/kernel/kernel_ipsec.h @@ -69,6 +69,8 @@ struct kernel_ipsec_add_sa_t { 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 */ @@ -142,6 +144,8 @@ struct kernel_ipsec_policy_id_t { traffic_selector_t *dst_ts; /** Optional mark */ mark_t mark; + /** Network interface restricting policy */ + char *interface; }; /** diff --git a/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c b/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c index bad343eba..95c0e3ce0 100644 --- a/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c +++ b/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c @@ -26,6 +26,7 @@ #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> @@ -739,7 +740,8 @@ static void ts2ports(traffic_selector_t* ts, * 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; @@ -763,7 +765,7 @@ static struct xfrm_selector ts2selector(traffic_selector_t *src, 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; @@ -1279,7 +1281,8 @@ METHOD(kernel_ipsec_t, add_sa, status_t, 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 @@ -2358,7 +2361,7 @@ METHOD(kernel_ipsec_t, add_policy, status_t, /* 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, @@ -2468,7 +2471,7 @@ METHOD(kernel_ipsec_t, query_policy, status_t, 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)) @@ -2552,7 +2555,7 @@ METHOD(kernel_ipsec_t, del_policy, status_t, /* 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; diff --git a/src/libcharon/plugins/vici/vici_config.c b/src/libcharon/plugins/vici/vici_config.c index 8358336af..a1ab56df9 100644 --- a/src/libcharon/plugins/vici/vici_config.c +++ b/src/libcharon/plugins/vici/vici_config.c @@ -462,6 +462,7 @@ static void log_child_data(child_data_t *data, char *name) 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", @@ -484,6 +485,7 @@ static void free_child_data(child_data_t *data) data->remote_ts->destroy_offset(data->remote_ts, offsetof(traffic_selector_t, destroy)); free(data->cfg.updown); + free(data->cfg.interface); } /** @@ -1342,6 +1344,7 @@ CALLBACK(child_kv, bool, { "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, diff --git a/src/libcharon/sa/child_sa.c b/src/libcharon/sa/child_sa.c index a1e47a2a4..6e0113ee7 100644 --- a/src/libcharon/sa/child_sa.c +++ b/src/libcharon/sa/child_sa.c @@ -576,6 +576,7 @@ static bool update_usetime(private_child_sa_t *this, bool inbound) .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 = {}; @@ -798,6 +799,7 @@ METHOD(child_sa_t, install, status_t, .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, @@ -890,6 +892,7 @@ static status_t install_policies_internal(private_child_sa_t *this, .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, @@ -948,6 +951,7 @@ static void del_policies_internal(private_child_sa_t *this, .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, diff --git a/src/libcharon/sa/shunt_manager.c b/src/libcharon/sa/shunt_manager.c index b74b454ea..40e291be5 100644 --- a/src/libcharon/sa/shunt_manager.c +++ b/src/libcharon/sa/shunt_manager.c @@ -68,6 +68,8 @@ static bool install_shunt_policy(child_cfg_t *child) 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)) @@ -92,6 +94,9 @@ static bool install_shunt_policy(child_cfg_t *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)) @@ -115,11 +120,12 @@ static bool install_shunt_policy(child_cfg_t *child) .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, @@ -134,6 +140,7 @@ static bool install_shunt_policy(child_cfg_t *child) .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 */ @@ -215,6 +222,8 @@ static void uninstall_shunt_policy(child_cfg_t *child) 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)) @@ -239,6 +248,9 @@ static void uninstall_shunt_policy(child_cfg_t *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)) @@ -262,11 +274,12 @@ static void uninstall_shunt_policy(child_cfg_t *child) .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, @@ -281,6 +294,7 @@ static void uninstall_shunt_policy(child_cfg_t *child) .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 */ diff --git a/src/swanctl/swanctl.opt b/src/swanctl/swanctl.opt index 08d3cf1c9..fe5b293fb 100644 --- a/src/swanctl/swanctl.opt +++ b/src/swanctl/swanctl.opt @@ -691,6 +691,9 @@ connections.<conn>.children.<child>.priority = 0 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. |