mirror of
https://github.com/strongswan/strongswan.git
synced 2025-10-03 00:00:24 -04:00
child-create: Maintain traffic selectors during rekeying/reauthentication
If we don't do this, narrowed SAs would default to the wide configured traffic selectors and the peer won't know if/how to narrow.
This commit is contained in:
parent
9205458355
commit
e7fc7a4ecc
@ -117,6 +117,16 @@ struct private_child_create_t {
|
||||
*/
|
||||
traffic_selector_t *packet_tsr;
|
||||
|
||||
/**
|
||||
* Local traffic selectors as configured or previously negotiated
|
||||
*/
|
||||
traffic_selector_list_t *my_ts;
|
||||
|
||||
/**
|
||||
* Remote traffic selectors as configured or previously negotiated
|
||||
*/
|
||||
traffic_selector_list_t *other_ts;
|
||||
|
||||
/**
|
||||
* Key exchanges to perform
|
||||
*/
|
||||
@ -256,6 +266,15 @@ static void schedule_delayed_retry(private_child_create_t *this)
|
||||
task->use_if_ids(task, this->child.if_id_in, this->child.if_id_out);
|
||||
task->use_label(task, this->child.label);
|
||||
|
||||
/* clone these directly as we don't have a public method */
|
||||
if (this->my_ts && this->other_ts)
|
||||
{
|
||||
private_child_create_t *priv = (private_child_create_t*)task;
|
||||
|
||||
priv->my_ts = this->my_ts->clone(this->my_ts);
|
||||
priv->other_ts = this->other_ts->clone(this->other_ts);
|
||||
}
|
||||
|
||||
DBG1(DBG_IKE, "creating CHILD_SA failed, trying again in %d seconds",
|
||||
retry);
|
||||
this->ike_sa->queue_task_delayed(this->ike_sa, (task_t*)task, retry);
|
||||
@ -452,15 +471,37 @@ static linked_list_t* get_transport_nat_ts(private_child_create_t *this,
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure we have traffic selector lists when not recreating an SA.
|
||||
*/
|
||||
static void ensure_ts_lists(private_child_create_t *this)
|
||||
{
|
||||
linked_list_t *ts;
|
||||
|
||||
if (!this->my_ts)
|
||||
{
|
||||
ts = this->config->get_traffic_selectors(this->config, TRUE, NULL);
|
||||
this->my_ts = traffic_selector_list_create_from_list(ts);
|
||||
}
|
||||
if (!this->other_ts)
|
||||
{
|
||||
ts = this->config->get_traffic_selectors(this->config, FALSE, NULL);
|
||||
this->other_ts = traffic_selector_list_create_from_list(ts);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Narrow received traffic selectors with configuration
|
||||
*/
|
||||
static linked_list_t* narrow_ts(private_child_create_t *this, bool local,
|
||||
linked_list_t *in)
|
||||
{
|
||||
linked_list_t *hosts, *nat, *ts;
|
||||
traffic_selector_list_t *ts;
|
||||
linked_list_t *hosts, *nat, *result;
|
||||
ike_condition_t cond;
|
||||
|
||||
ensure_ts_lists(this);
|
||||
ts = local ? this->my_ts : this->other_ts;
|
||||
cond = local ? COND_NAT_HERE : COND_NAT_THERE;
|
||||
hosts = ike_sa_get_dynamic_hosts(this->ike_sa, local);
|
||||
|
||||
@ -468,19 +509,16 @@ static linked_list_t* narrow_ts(private_child_create_t *this, bool local,
|
||||
this->ike_sa->has_condition(this->ike_sa, cond))
|
||||
{
|
||||
nat = get_transport_nat_ts(this, local, in);
|
||||
ts = this->config->select_traffic_selectors(this->config, local, nat,
|
||||
hosts);
|
||||
result = child_cfg_select_ts(this->config, local, ts, nat, hosts);
|
||||
nat->destroy_offset(nat, offsetof(traffic_selector_t, destroy));
|
||||
}
|
||||
else
|
||||
{
|
||||
ts = this->config->select_traffic_selectors(this->config, local, in,
|
||||
hosts);
|
||||
result = child_cfg_select_ts(this->config, local, ts, in, hosts);
|
||||
}
|
||||
|
||||
hosts->destroy(hosts);
|
||||
|
||||
return ts;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1435,13 +1473,66 @@ METHOD(task_t, build_i_multi_ke, status_t,
|
||||
return NEED_MORE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare proposed traffic selectors as initiator.
|
||||
*/
|
||||
static void prepare_proposed_ts(private_child_create_t *this)
|
||||
{
|
||||
enumerator_t *enumerator;
|
||||
peer_cfg_t *peer_cfg;
|
||||
linked_list_t *list;
|
||||
host_t *vip;
|
||||
|
||||
ensure_ts_lists(this);
|
||||
|
||||
list = linked_list_create();
|
||||
if (!this->rekey)
|
||||
{
|
||||
/* check if we want a virtual IP */
|
||||
peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa);
|
||||
enumerator = peer_cfg->create_virtual_ip_enumerator(peer_cfg);
|
||||
while (enumerator->enumerate(enumerator, &vip))
|
||||
{
|
||||
/* propose a 0.0.0.0/0 or ::/0 subnet when we use a virtual IP */
|
||||
vip = host_create_any(vip->get_family(vip));
|
||||
list->insert_last(list, vip);
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
}
|
||||
if (list->get_count(list))
|
||||
{
|
||||
this->tsi = child_cfg_select_ts(this->config, TRUE, this->my_ts, NULL,
|
||||
list);
|
||||
list->destroy_offset(list, offsetof(host_t, destroy));
|
||||
}
|
||||
else
|
||||
{
|
||||
list->destroy(list);
|
||||
list = ike_sa_get_dynamic_hosts(this->ike_sa, TRUE);
|
||||
this->tsi = child_cfg_select_ts(this->config, TRUE, this->my_ts, NULL,
|
||||
list);
|
||||
list->destroy(list);
|
||||
}
|
||||
list = ike_sa_get_dynamic_hosts(this->ike_sa, FALSE);
|
||||
this->tsr = child_cfg_select_ts(this->config, FALSE, this->other_ts, NULL,
|
||||
list);
|
||||
list->destroy(list);
|
||||
|
||||
if (this->packet_tsi)
|
||||
{
|
||||
this->tsi->insert_first(this->tsi,
|
||||
this->packet_tsi->clone(this->packet_tsi));
|
||||
}
|
||||
if (this->packet_tsr)
|
||||
{
|
||||
this->tsr->insert_first(this->tsr,
|
||||
this->packet_tsr->clone(this->packet_tsr));
|
||||
}
|
||||
}
|
||||
|
||||
METHOD(task_t, build_i, status_t,
|
||||
private_child_create_t *this, message_t *message)
|
||||
{
|
||||
enumerator_t *enumerator;
|
||||
host_t *vip;
|
||||
peer_cfg_t *peer_cfg;
|
||||
linked_list_t *list;
|
||||
bool no_ke = TRUE;
|
||||
|
||||
switch (message->get_exchange_type(message))
|
||||
@ -1477,49 +1568,7 @@ METHOD(task_t, build_i, status_t,
|
||||
return NEED_MORE;
|
||||
}
|
||||
|
||||
/* check if we want a virtual IP, but don't have one */
|
||||
list = linked_list_create();
|
||||
peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa);
|
||||
if (!this->rekey)
|
||||
{
|
||||
enumerator = peer_cfg->create_virtual_ip_enumerator(peer_cfg);
|
||||
while (enumerator->enumerate(enumerator, &vip))
|
||||
{
|
||||
/* propose a 0.0.0.0/0 or ::/0 subnet when we use virtual ip */
|
||||
vip = host_create_any(vip->get_family(vip));
|
||||
list->insert_last(list, vip);
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
}
|
||||
if (list->get_count(list))
|
||||
{
|
||||
this->tsi = this->config->select_traffic_selectors(this->config, TRUE,
|
||||
NULL, list);
|
||||
list->destroy_offset(list, offsetof(host_t, destroy));
|
||||
}
|
||||
else
|
||||
{ /* no virtual IPs configured */
|
||||
list->destroy(list);
|
||||
list = ike_sa_get_dynamic_hosts(this->ike_sa, TRUE);
|
||||
this->tsi = this->config->select_traffic_selectors(this->config, TRUE,
|
||||
NULL, list);
|
||||
list->destroy(list);
|
||||
}
|
||||
list = ike_sa_get_dynamic_hosts(this->ike_sa, FALSE);
|
||||
this->tsr = this->config->select_traffic_selectors(this->config, FALSE,
|
||||
NULL, list);
|
||||
list->destroy(list);
|
||||
|
||||
if (this->packet_tsi)
|
||||
{
|
||||
this->tsi->insert_first(this->tsi,
|
||||
this->packet_tsi->clone(this->packet_tsi));
|
||||
}
|
||||
if (this->packet_tsr)
|
||||
{
|
||||
this->tsr->insert_first(this->tsr,
|
||||
this->packet_tsr->clone(this->packet_tsr));
|
||||
}
|
||||
prepare_proposed_ts(this);
|
||||
|
||||
if (!generic_label_only(this) && !this->child.label)
|
||||
{ /* in the simple label mode we propose the configured label as we
|
||||
@ -2544,6 +2593,61 @@ METHOD(child_create_t, use_label, void,
|
||||
this->child.label = label ? label->clone(label) : NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare traffic selectors for reuse when recreating a CHILD_SA.
|
||||
*/
|
||||
static void reuse_ts(private_child_create_t *this, bool local, child_sa_t *old,
|
||||
traffic_selector_list_t **target)
|
||||
{
|
||||
enumerator_t *old_ts, *hosts_enum;
|
||||
linked_list_t *hosts, *list;
|
||||
traffic_selector_t *ts, *new_ts;
|
||||
host_t *host;
|
||||
|
||||
old_ts = old->create_ts_enumerator(old, local);
|
||||
if (this->rekey)
|
||||
{
|
||||
/* when rekeying, we just reuse the previous TS. this is also the only
|
||||
* way a responder reuses TS */
|
||||
*target = traffic_selector_list_create_from_enumerator(old_ts);
|
||||
return;
|
||||
}
|
||||
|
||||
/* when recreating/reauthenticating, we check whether the dynamic IPs of
|
||||
* the IKE_SA (as copied from the old SA) match the TS and replace
|
||||
* them with dynamic TS (reusing protocol/ports in case of narrowing) so
|
||||
* they get updated to possibly new IPs when the TS are prepared later */
|
||||
list = linked_list_create();
|
||||
hosts = ike_sa_get_dynamic_hosts(this->ike_sa, local);
|
||||
hosts_enum = hosts->create_enumerator(hosts);
|
||||
while (old_ts->enumerate(old_ts, &ts))
|
||||
{
|
||||
new_ts = NULL;
|
||||
while (hosts_enum->enumerate(hosts_enum, &host))
|
||||
{
|
||||
if (ts->is_host(ts, host))
|
||||
{
|
||||
new_ts = traffic_selector_create_dynamic(ts->get_protocol(ts),
|
||||
ts->get_from_port(ts),
|
||||
ts->get_to_port(ts));
|
||||
break;
|
||||
}
|
||||
}
|
||||
hosts->reset_enumerator(hosts, hosts_enum);
|
||||
|
||||
if (!new_ts)
|
||||
{
|
||||
new_ts = ts->clone(ts);
|
||||
}
|
||||
list->insert_last(list, new_ts);
|
||||
}
|
||||
hosts_enum->destroy(hosts_enum);
|
||||
hosts->destroy(hosts);
|
||||
old_ts->destroy(old_ts);
|
||||
|
||||
*target = traffic_selector_list_create_from_list(list);
|
||||
}
|
||||
|
||||
METHOD(child_create_t, recreate_sa, void,
|
||||
private_child_create_t *this, child_sa_t *old)
|
||||
{
|
||||
@ -2560,6 +2664,10 @@ METHOD(child_create_t, recreate_sa, void,
|
||||
this->ke_method = ke_method;
|
||||
}
|
||||
}
|
||||
|
||||
/* use previously negotiated traffic selectors */
|
||||
reuse_ts(this, TRUE, old, &this->my_ts);
|
||||
reuse_ts(this, FALSE, old, &this->other_ts);
|
||||
}
|
||||
|
||||
METHOD(child_create_t, get_child, child_sa_t*,
|
||||
@ -2619,32 +2727,17 @@ METHOD(task_t, migrate, void,
|
||||
chunk_free(&this->my_nonce);
|
||||
chunk_free(&this->other_nonce);
|
||||
chunk_free(&this->link);
|
||||
if (this->tsr)
|
||||
{
|
||||
this->tsr->destroy_offset(this->tsr, offsetof(traffic_selector_t, destroy));
|
||||
}
|
||||
if (this->tsi)
|
||||
{
|
||||
this->tsi->destroy_offset(this->tsi, offsetof(traffic_selector_t, destroy));
|
||||
}
|
||||
if (this->labels_i)
|
||||
{
|
||||
this->labels_i->destroy_offset(this->labels_i, offsetof(sec_label_t, destroy));
|
||||
}
|
||||
if (this->labels_r)
|
||||
{
|
||||
this->labels_r->destroy_offset(this->labels_r, offsetof(sec_label_t, destroy));
|
||||
}
|
||||
DESTROY_OFFSET_IF(this->tsr, offsetof(traffic_selector_t, destroy));
|
||||
DESTROY_OFFSET_IF(this->tsi, offsetof(traffic_selector_t, destroy));
|
||||
DESTROY_OFFSET_IF(this->labels_i, offsetof(sec_label_t, destroy));
|
||||
DESTROY_OFFSET_IF(this->labels_r, offsetof(sec_label_t, destroy));
|
||||
DESTROY_IF(this->child_sa);
|
||||
DESTROY_IF(this->proposal);
|
||||
DESTROY_IF(this->nonceg);
|
||||
DESTROY_IF(this->ke);
|
||||
this->ke_failed = FALSE;
|
||||
clear_key_exchanges(this);
|
||||
if (this->proposals)
|
||||
{
|
||||
this->proposals->destroy_offset(this->proposals, offsetof(proposal_t, destroy));
|
||||
}
|
||||
DESTROY_OFFSET_IF(this->proposals, offsetof(proposal_t, destroy));
|
||||
if (!this->rekey && !this->retry)
|
||||
{
|
||||
this->ke_method = KE_NONE;
|
||||
@ -2675,22 +2768,10 @@ METHOD(task_t, destroy, void,
|
||||
chunk_free(&this->my_nonce);
|
||||
chunk_free(&this->other_nonce);
|
||||
chunk_free(&this->link);
|
||||
if (this->tsr)
|
||||
{
|
||||
this->tsr->destroy_offset(this->tsr, offsetof(traffic_selector_t, destroy));
|
||||
}
|
||||
if (this->tsi)
|
||||
{
|
||||
this->tsi->destroy_offset(this->tsi, offsetof(traffic_selector_t, destroy));
|
||||
}
|
||||
if (this->labels_i)
|
||||
{
|
||||
this->labels_i->destroy_offset(this->labels_i, offsetof(sec_label_t, destroy));
|
||||
}
|
||||
if (this->labels_r)
|
||||
{
|
||||
this->labels_r->destroy_offset(this->labels_r, offsetof(sec_label_t, destroy));
|
||||
}
|
||||
DESTROY_OFFSET_IF(this->tsr, offsetof(traffic_selector_t, destroy));
|
||||
DESTROY_OFFSET_IF(this->tsi, offsetof(traffic_selector_t, destroy));
|
||||
DESTROY_OFFSET_IF(this->labels_i, offsetof(sec_label_t, destroy));
|
||||
DESTROY_OFFSET_IF(this->labels_r, offsetof(sec_label_t, destroy));
|
||||
if (!this->established)
|
||||
{
|
||||
DESTROY_IF(this->child_sa);
|
||||
@ -2701,13 +2782,12 @@ METHOD(task_t, destroy, void,
|
||||
}
|
||||
DESTROY_IF(this->packet_tsi);
|
||||
DESTROY_IF(this->packet_tsr);
|
||||
DESTROY_IF(this->my_ts);
|
||||
DESTROY_IF(this->other_ts);
|
||||
DESTROY_IF(this->proposal);
|
||||
DESTROY_IF(this->ke);
|
||||
clear_key_exchanges(this);
|
||||
if (this->proposals)
|
||||
{
|
||||
this->proposals->destroy_offset(this->proposals, offsetof(proposal_t, destroy));
|
||||
}
|
||||
DESTROY_OFFSET_IF(this->proposals, offsetof(proposal_t, destroy));
|
||||
DESTROY_IF(this->config);
|
||||
DESTROY_IF(this->nonceg);
|
||||
DESTROY_IF(this->child.label);
|
||||
|
Loading…
x
Reference in New Issue
Block a user