diff --git a/src/libcharon/plugins/ha/ha_dispatcher.c b/src/libcharon/plugins/ha/ha_dispatcher.c index ab845317fd..11f3bd914c 100644 --- a/src/libcharon/plugins/ha/ha_dispatcher.c +++ b/src/libcharon/plugins/ha/ha_dispatcher.c @@ -746,7 +746,7 @@ static void process_child_add(private_ha_dispatcher_t *this, child_sa = child_sa_create(ike_sa->get_my_host(ike_sa), ike_sa->get_other_host(ike_sa), config, 0, ike_sa->has_condition(ike_sa, COND_NAT_ANY), - 0, 0); + 0, 0, 0, 0); child_sa->set_mode(child_sa, mode); child_sa->set_protocol(child_sa, PROTO_ESP); child_sa->set_ipcomp(child_sa, ipcomp); diff --git a/src/libcharon/sa/child_sa.c b/src/libcharon/sa/child_sa.c index f74d0c2ce0..2ea678067a 100644 --- a/src/libcharon/sa/child_sa.c +++ b/src/libcharon/sa/child_sa.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2018 Tobias Brunner + * Copyright (C) 2006-2019 Tobias Brunner * Copyright (C) 2016 Andreas Steffen * Copyright (C) 2005-2008 Martin Willi * Copyright (C) 2006 Daniel Roethlisberger @@ -153,6 +153,16 @@ struct private_child_sa_t { */ bool policies_fwd_out; + /** + * Inbound interface ID + */ + uint32_t if_id_in; + + /** + * Outbound interface ID + */ + uint32_t if_id_out; + /** * inbound mark used for this child_sa */ @@ -539,6 +549,7 @@ static status_t update_usebytes(private_child_sa_t *this, bool inbound) .spi = this->my_spi, .proto = proto_ike2ip(this->protocol), .mark = mark_in_sa(this), + .if_id = this->if_id_in, }; kernel_ipsec_query_sa_t query = {}; @@ -572,6 +583,7 @@ static status_t update_usebytes(private_child_sa_t *this, bool inbound) .spi = this->other_spi, .proto = proto_ike2ip(this->protocol), .mark = this->mark_out, + .if_id = this->if_id_out, }; kernel_ipsec_query_sa_t query = {}; @@ -619,6 +631,7 @@ static bool update_usetime(private_child_sa_t *this, bool inbound) .src_ts = other_ts, .dst_ts = my_ts, .mark = this->mark_in, + .if_id = this->if_id_in, }; kernel_ipsec_query_policy_t query = {}; @@ -644,6 +657,7 @@ static bool update_usetime(private_child_sa_t *this, bool inbound) .src_ts = my_ts, .dst_ts = other_ts, .mark = this->mark_out, + .if_id = this->if_id_out, .interface = this->config->get_interface(this->config), }; kernel_ipsec_query_policy_t query = {}; @@ -707,11 +721,13 @@ METHOD(child_sa_t, get_usestats, void, METHOD(child_sa_t, get_mark, mark_t, private_child_sa_t *this, bool inbound) { - if (inbound) - { - return this->mark_in; - } - return this->mark_out; + return inbound ? this->mark_in : this->mark_out; +} + +METHOD(child_sa_t, get_if_id, uint32_t, + private_child_sa_t *this, bool inbound) +{ + return inbound ? this->if_id_in : this->if_id_out; } METHOD(child_sa_t, get_lifetime, time_t, @@ -832,8 +848,8 @@ static status_t install_internal(private_child_sa_t *this, chunk_t encr, if (!this->reqid_allocated && !this->static_reqid) { status = charon->kernel->alloc_reqid(charon->kernel, my_ts, other_ts, - this->mark_in, this->mark_out, 0, 0, - &this->reqid); + this->mark_in, this->mark_out, this->if_id_in, + this->if_id_out, &this->reqid); if (status != SUCCESS) { my_ts->destroy(my_ts); @@ -873,6 +889,7 @@ static status_t install_internal(private_child_sa_t *this, chunk_t encr, .spi = spi, .proto = proto_ike2ip(this->protocol), .mark = inbound ? mark_in_sa(this) : this->mark_out, + .if_id = inbound ? this->if_id_in : this->if_id_out, }; sa = (kernel_ipsec_add_sa_t){ .reqid = this->reqid, @@ -992,6 +1009,7 @@ static status_t install_policies_inbound(private_child_sa_t *this, .src_ts = other_ts, .dst_ts = my_ts, .mark = this->mark_in, + .if_id = this->if_id_in, }; kernel_ipsec_manage_policy_t in_policy = { .type = type, @@ -1026,6 +1044,7 @@ static status_t install_policies_outbound(private_child_sa_t *this, .src_ts = my_ts, .dst_ts = other_ts, .mark = this->mark_out, + .if_id = this->if_id_out, .interface = this->config->get_interface(this->config), }; kernel_ipsec_manage_policy_t out_policy = { @@ -1099,6 +1118,7 @@ static void del_policies_inbound(private_child_sa_t *this, .src_ts = other_ts, .dst_ts = my_ts, .mark = this->mark_in, + .if_id = this->if_id_in, }; kernel_ipsec_manage_policy_t in_policy = { .type = type, @@ -1132,6 +1152,7 @@ static void del_policies_outbound(private_child_sa_t *this, .src_ts = my_ts, .dst_ts = other_ts, .mark = this->mark_out, + .if_id = this->if_id_out, .interface = this->config->get_interface(this->config), }; kernel_ipsec_manage_policy_t out_policy = { @@ -1229,7 +1250,8 @@ METHOD(child_sa_t, install_policies, status_t, array_create_enumerator(this->other_ts)); status = charon->kernel->alloc_reqid( charon->kernel, my_ts_list, other_ts_list, - this->mark_in, this->mark_out, 0, 0, &this->reqid); + this->mark_in, this->mark_out, this->if_id_in, + this->if_id_out, &this->reqid); my_ts_list->destroy(my_ts_list); other_ts_list->destroy(other_ts_list); if (status != SUCCESS) @@ -1404,6 +1426,7 @@ METHOD(child_sa_t, remove_outbound, void, .spi = this->other_spi, .proto = proto_ike2ip(this->protocol), .mark = this->mark_out, + .if_id = this->if_id_out, }; kernel_ipsec_del_sa_t sa = { .cpi = this->other_cpi, @@ -1454,6 +1477,7 @@ static status_t update_sas(private_child_sa_t *this, host_t *me, host_t *other, .spi = this->my_spi, .proto = proto_ike2ip(this->protocol), .mark = mark_in_sa(this), + .if_id = this->if_id_in, }; kernel_ipsec_update_sa_t sa = { .cpi = this->ipcomp != IPCOMP_NONE ? this->my_cpi : 0, @@ -1478,6 +1502,7 @@ static status_t update_sas(private_child_sa_t *this, host_t *me, host_t *other, .spi = this->other_spi, .proto = proto_ike2ip(this->protocol), .mark = this->mark_out, + .if_id = this->if_id_out, }; kernel_ipsec_update_sa_t sa = { .cpi = this->ipcomp != IPCOMP_NONE ? this->other_cpi : 0, @@ -1680,6 +1705,7 @@ METHOD(child_sa_t, destroy, void, .spi = this->my_spi, .proto = proto_ike2ip(this->protocol), .mark = mark_in_sa(this), + .if_id = this->if_id_in, }; kernel_ipsec_del_sa_t sa = { .cpi = this->my_cpi, @@ -1694,6 +1720,7 @@ METHOD(child_sa_t, destroy, void, .spi = this->other_spi, .proto = proto_ike2ip(this->protocol), .mark = this->mark_out, + .if_id = this->if_id_out, }; kernel_ipsec_del_sa_t sa = { .cpi = this->other_cpi, @@ -1705,7 +1732,7 @@ METHOD(child_sa_t, destroy, void, { if (charon->kernel->release_reqid(charon->kernel, this->reqid, this->mark_in, this->mark_out, - 0, 0) != SUCCESS) + this->if_id_in, this->if_id_out) != SUCCESS) { DBG1(DBG_CHD, "releasing reqid %u failed", this->reqid); } @@ -1762,11 +1789,11 @@ static host_t* get_proxy_addr(child_cfg_t *config, host_t *ike, bool local) */ child_sa_t * child_sa_create(host_t *me, host_t* other, child_cfg_t *config, uint32_t reqid, bool encap, - u_int mark_in, u_int mark_out) + uint32_t mark_in, uint32_t mark_out, + uint32_t if_id_in, uint32_t if_id_out) { private_child_sa_t *this; - static refcount_t unique_id = 0, unique_mark = 0; - refcount_t mark = 0; + static refcount_t unique_id = 0, unique_mark = 0, unique_if_id = 0; INIT(this, .public = { @@ -1789,6 +1816,7 @@ child_sa_t * child_sa_create(host_t *me, host_t* other, .get_installtime = _get_installtime, .get_usestats = _get_usestats, .get_mark = _get_mark, + .get_if_id = _get_if_id, .has_encap = _has_encap, .get_ipcomp = _get_ipcomp, .set_ipcomp = _set_ipcomp, @@ -1824,6 +1852,8 @@ child_sa_t * child_sa_create(host_t *me, host_t* other, .unique_id = ref_get(&unique_id), .mark_in = config->get_mark(config, TRUE), .mark_out = config->get_mark(config, FALSE), + .if_id_in = config->get_if_id(config, TRUE), + .if_id_out = config->get_if_id(config, FALSE), .install_time = time_monotonic(NULL), .policies_fwd_out = config->has_option(config, OPT_FWD_OUT_POLICIES), ); @@ -1839,14 +1869,21 @@ child_sa_t * child_sa_create(host_t *me, host_t* other, { this->mark_out.value = mark_out; } + if (if_id_in) + { + this->if_id_in = if_id_in; + } + if (if_id_out) + { + this->if_id_out = if_id_out; + } if (MARK_IS_UNIQUE(this->mark_in.value) || MARK_IS_UNIQUE(this->mark_out.value)) { - bool unique_dir; - - unique_dir = this->mark_in.value == MARK_UNIQUE_DIR || - this->mark_out.value == MARK_UNIQUE_DIR; + refcount_t mark = 0; + bool unique_dir = this->mark_in.value == MARK_UNIQUE_DIR || + this->mark_out.value == MARK_UNIQUE_DIR; if (!unique_dir) { @@ -1854,19 +1891,32 @@ child_sa_t * child_sa_create(host_t *me, host_t* other, } if (MARK_IS_UNIQUE(this->mark_in.value)) { - if (unique_dir) - { - mark = ref_get(&unique_mark); - } - this->mark_in.value = mark; + this->mark_in.value = unique_dir ? ref_get(&unique_mark) : mark; } if (MARK_IS_UNIQUE(this->mark_out.value)) { - if (unique_dir) - { - mark = ref_get(&unique_mark); - } - this->mark_out.value = mark; + this->mark_out.value = unique_dir ? ref_get(&unique_mark) : mark; + } + } + + if (IF_ID_IS_UNIQUE(this->if_id_in) || + IF_ID_IS_UNIQUE(this->if_id_out)) + { + refcount_t if_id = 0; + bool unique_dir = this->if_id_in == IF_ID_UNIQUE_DIR || + this->if_id_out == IF_ID_UNIQUE_DIR; + + if (!unique_dir) + { + if_id = ref_get(&unique_if_id); + } + if (IF_ID_IS_UNIQUE(this->if_id_in)) + { + this->if_id_in = unique_dir ? ref_get(&unique_if_id) : if_id; + } + if (IF_ID_IS_UNIQUE(this->if_id_out)) + { + this->if_id_out = unique_dir ? ref_get(&unique_if_id) : if_id; } } diff --git a/src/libcharon/sa/child_sa.h b/src/libcharon/sa/child_sa.h index 183033f462..483dd1512f 100644 --- a/src/libcharon/sa/child_sa.h +++ b/src/libcharon/sa/child_sa.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2017 Tobias Brunner + * Copyright (C) 2006-2019 Tobias Brunner * Copyright (C) 2006-2008 Martin Willi * Copyright (C) 2006 Daniel Roethlisberger * HSR Hochschule fuer Technik Rapperswil @@ -360,6 +360,14 @@ struct child_sa_t { */ mark_t (*get_mark)(child_sa_t *this, bool inbound); + /** + * Get the interface ID used with this CHILD_SA. + * + * @param inbound TRUE to get inbound ID, FALSE for outbound + * @return interface ID used with this CHILD_SA + */ + uint32_t (*get_if_id)(child_sa_t *this, bool inbound); + /** * Create an enumerator over traffic selectors of one side. * @@ -514,10 +522,13 @@ struct child_sa_t { * @param encap TRUE to enable UDP encapsulation (NAT traversal) * @param mark_in explicit inbound mark value to use, 0 for config * @param mark_out explicit outbound mark value to use, 0 for config + * @param if_id_in explicit inbound interface ID to use, 0 for config + * @param if_id_out explicit outbound interface ID to use, 0 for config * @return child_sa_t object */ child_sa_t * child_sa_create(host_t *me, host_t *other, child_cfg_t *config, uint32_t reqid, bool encap, - u_int mark_in, u_int mark_out); + uint32_t mark_in, uint32_t mark_out, + uint32_t if_id_in, uint32_t if_id_out); #endif /** CHILD_SA_H_ @}*/ diff --git a/src/libcharon/sa/ikev1/tasks/quick_mode.c b/src/libcharon/sa/ikev1/tasks/quick_mode.c index b0a42b8bd0..876b99e5f3 100644 --- a/src/libcharon/sa/ikev1/tasks/quick_mode.c +++ b/src/libcharon/sa/ikev1/tasks/quick_mode.c @@ -845,7 +845,8 @@ METHOD(task_t, build_i, status_t, this->ike_sa->get_my_host(this->ike_sa), this->ike_sa->get_other_host(this->ike_sa), this->config, this->reqid, this->udp, - this->mark_in, this->mark_out); + this->mark_in, this->mark_out, + 0, 0); if (this->udp && this->mode == MODE_TRANSPORT) { @@ -1185,7 +1186,8 @@ METHOD(task_t, process_r, status_t, this->ike_sa->get_my_host(this->ike_sa), this->ike_sa->get_other_host(this->ike_sa), this->config, this->reqid, this->udp, - this->mark_in, this->mark_out); + this->mark_in, this->mark_out, + 0, 0); tsi = linked_list_create_with_items(this->tsi, NULL); tsr = linked_list_create_with_items(this->tsr, NULL); diff --git a/src/libcharon/sa/ikev2/tasks/child_create.c b/src/libcharon/sa/ikev2/tasks/child_create.c index ce61ef9882..1f93be4846 100644 --- a/src/libcharon/sa/ikev2/tasks/child_create.c +++ b/src/libcharon/sa/ikev2/tasks/child_create.c @@ -1110,7 +1110,7 @@ METHOD(task_t, build_i, status_t, this->child_sa = child_sa_create(this->ike_sa->get_my_host(this->ike_sa), this->ike_sa->get_other_host(this->ike_sa), this->config, this->reqid, this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY), - this->mark_in, this->mark_out); + this->mark_in, this->mark_out, 0, 0); if (this->reqid) { @@ -1395,7 +1395,7 @@ METHOD(task_t, build_r, status_t, this->child_sa = child_sa_create(this->ike_sa->get_my_host(this->ike_sa), this->ike_sa->get_other_host(this->ike_sa), this->config, this->reqid, this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY), - this->mark_in, this->mark_out); + this->mark_in, this->mark_out, 0, 0); if (this->ipcomp_received != IPCOMP_NONE) { diff --git a/src/libcharon/sa/trap_manager.c b/src/libcharon/sa/trap_manager.c index c35b8c0de8..7acbb28c21 100644 --- a/src/libcharon/sa/trap_manager.c +++ b/src/libcharon/sa/trap_manager.c @@ -293,7 +293,7 @@ METHOD(trap_manager_t, install, bool, this->lock->unlock(this->lock); /* create and route CHILD_SA */ - child_sa = child_sa_create(me, other, child, 0, FALSE, 0, 0); + child_sa = child_sa_create(me, other, child, 0, FALSE, 0, 0, 0, 0); list = linked_list_create_with_items(me, NULL); my_ts = child->get_traffic_selectors(child, TRUE, NULL, list, FALSE);