return found;
}
+/**
+ * Get the host from the first (only) traffc selector if peer is behind a NAT
+ */
+static host_t *get_nat_host(linked_list_t *proposed)
+{
+ host_t *host = NULL;
+ traffic_selector_t *ts;
+ uint8_t mask;
+
+ if ((proposed->get_first(proposed, (void**)&ts) == SUCCESS) &&
+ ts->is_host(ts, NULL))
+ {
+ ts->to_subnet(ts, &host, &mask);
+ }
+ return host;
+}
+
/**
* Get hosts to use for dynamic traffic selectors
*/
-static linked_list_t *get_dynamic_hosts(ike_sa_t *ike_sa, bool local)
+static linked_list_t *get_dynamic_hosts(private_quick_mode_t *this,
+ bool local, linked_list_t *proposed)
{
+ ike_sa_t *ike_sa = this->ike_sa;
enumerator_t *enumerator;
linked_list_t *list;
- host_t *host;
+ host_t *host = NULL;
list = linked_list_create();
enumerator = ike_sa->create_virtual_ip_enumerator(ike_sa, local);
}
enumerator->destroy(enumerator);
- if (list->get_count(list) == 0)
+ if (!list->get_count(list))
{ /* no virtual IPs assigned */
if (local)
{
host = ike_sa->get_my_host(ike_sa);
- list->insert_last(list, host);
}
else if (!have_pool(ike_sa))
{ /* use host only if we don't have a pool configured */
- host = ike_sa->get_other_host(ike_sa);
+ if (proposed && this->mode == MODE_TUNNEL &&
+ ike_sa->has_condition(ike_sa, COND_NAT_THERE))
+ {
+ host = get_nat_host(proposed);
+ }
+ if (!host)
+ {
+ host = ike_sa->get_other_host(ike_sa);
+ }
+ }
+ if (host)
+ {
list->insert_last(list, host);
}
}
traffic_selector_t *ts;
linked_list_t *list, *hosts;
- hosts = get_dynamic_hosts(this->ike_sa, local);
+ hosts = get_dynamic_hosts(this, local, supplied);
list = this->config->get_traffic_selectors(this->config,
local, supplied, hosts);
hosts->destroy(hosts);
tsi = linked_list_create_with_items(this->tsi, NULL);
tsr = linked_list_create_with_items(this->tsr, NULL);
this->tsi = this->tsr = NULL;
- hostsi = get_dynamic_hosts(this->ike_sa, FALSE);
- hostsr = get_dynamic_hosts(this->ike_sa, TRUE);
+ hostsi = get_dynamic_hosts(this, FALSE, tsi);
+ hostsr = get_dynamic_hosts(this, TRUE, NULL);
this->config = peer_cfg->select_child_cfg(peer_cfg, tsr, tsi,
hostsr, hostsi);
hostsi->destroy(hostsi);
return found;
}
+/**
+ * Return the single host proposed by the peer if it is behind a NAT
+ */
+static host_t *get_nat_host(linked_list_t *supplied)
+{
+ enumerator_t *enumerator;
+ traffic_selector_t *ts;
+ host_t *host = NULL;
+ uint8_t mask;
+
+ enumerator = supplied->create_enumerator(supplied);
+ while (enumerator->enumerate(enumerator, &ts))
+ { /* all supplied traffic selectors must be to the same host */
+ if (!ts->is_host(ts, host))
+ {
+ DESTROY_IF(host);
+ host = NULL;
+ break;
+ }
+ if (!host)
+ {
+ ts->to_subnet(ts, &host, &mask);
+ }
+ }
+ enumerator->destroy(enumerator);
+ return host;
+}
+
/**
* Get hosts to use for dynamic traffic selectors
*/
-static linked_list_t *get_dynamic_hosts(ike_sa_t *ike_sa, bool local)
+static linked_list_t *get_dynamic_hosts(private_child_create_t *this,
+ bool local, linked_list_t *supplied)
{
+ ike_sa_t *ike_sa = this->ike_sa;
enumerator_t *enumerator;
linked_list_t *list;
- host_t *host;
+ host_t *host = NULL;
list = linked_list_create();
enumerator = ike_sa->create_virtual_ip_enumerator(ike_sa, local);
}
enumerator->destroy(enumerator);
- if (list->get_count(list) == 0)
+ if (!list->get_count(list))
{ /* no virtual IPs assigned */
if (local)
{
host = ike_sa->get_my_host(ike_sa);
- list->insert_last(list, host);
}
else if (!have_pool(ike_sa))
{ /* use host only if we don't have a pool configured */
- host = ike_sa->get_other_host(ike_sa);
+ if (supplied && this->mode == MODE_TUNNEL &&
+ ike_sa->has_condition(ike_sa, COND_NAT_THERE))
+ {
+ host = get_nat_host(supplied);
+ }
+ if (!host)
+ {
+ host = ike_sa->get_other_host(ike_sa);
+ }
+ }
+ if (host)
+ {
list->insert_last(list, host);
}
}
ike_condition_t cond;
cond = local ? COND_NAT_HERE : COND_NAT_THERE;
- hosts = get_dynamic_hosts(this->ike_sa, local);
+ hosts = get_dynamic_hosts(this, local, in);
if (this->mode == MODE_TRANSPORT &&
this->ike_sa->has_condition(this->ike_sa, cond))
else
{ /* no virtual IPs configured */
list->destroy(list);
- list = get_dynamic_hosts(this->ike_sa, TRUE);
+ list = get_dynamic_hosts(this, TRUE, NULL);
this->tsi = this->config->get_traffic_selectors(this->config,
TRUE, NULL, list);
list->destroy(list);
}
- list = get_dynamic_hosts(this->ike_sa, FALSE);
+ list = get_dynamic_hosts(this, FALSE, NULL);
this->tsr = this->config->get_traffic_selectors(this->config,
FALSE, NULL, list);
list->destroy(list);
tsr = get_ts_if_nat_transport(this, TRUE, this->tsr);
tsi = get_ts_if_nat_transport(this, FALSE, this->tsi);
- listr = get_dynamic_hosts(this->ike_sa, TRUE);
- listi = get_dynamic_hosts(this->ike_sa, FALSE);
+ listr = get_dynamic_hosts(this, TRUE, NULL);
+ listi = get_dynamic_hosts(this, FALSE, this->tsi);
child_cfg = peer_cfg->select_child_cfg(peer_cfg,
tsr ?: this->tsr, tsi ?: this->tsi,
listr, listi);