]> git.ipfire.org Git - thirdparty/strongswan.git/commitdiff
ike: For NATted connections use host from traffic selector
authorThomas Egerer <thomas.egerer@secunet.com>
Thu, 22 Mar 2018 17:17:48 +0000 (18:17 +0100)
committerTobias Brunner <tobias@strongswan.org>
Tue, 3 Apr 2018 11:51:15 +0000 (13:51 +0200)
When resolving dynamic hosts with no pool configured, the code used to
replace the remote IP with the peer's perceived address. This fails for road
warriors behind NAT. Hence this patch uses the address from the remote
traffic selector proposed by the peer if NAT was detected and the
address(es) proposed are /32 or /128 subnets to the same host.

Signed-off-by: Thomas Egerer <thomas.egerer@secunet.com>
src/libcharon/sa/ikev1/tasks/quick_mode.c
src/libcharon/sa/ikev2/tasks/child_create.c

index 77592e59ae0a7c86292776ec09a2ede7bfc76a48..1ec88befaaa77f5d4ceeb0e2f4ecfe08eb1a6da8 100644 (file)
@@ -244,14 +244,33 @@ static bool have_pool(ike_sa_t *ike_sa)
        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);
@@ -261,16 +280,26 @@ static linked_list_t *get_dynamic_hosts(ike_sa_t *ike_sa, bool 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);
                }
        }
@@ -542,7 +571,7 @@ static traffic_selector_t* select_ts(private_quick_mode_t *this, bool local,
        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);
@@ -1088,8 +1117,8 @@ METHOD(task_t, process_r, status_t,
                        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);
index c90af23b9939db561998e27b12b206f39fd946e1..78603d42cb8104deba83424e6f08050ed18358ce 100644 (file)
@@ -388,14 +388,44 @@ static bool have_pool(ike_sa_t *ike_sa)
        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);
@@ -405,16 +435,26 @@ static linked_list_t *get_dynamic_hosts(ike_sa_t *ike_sa, bool 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);
                }
        }
@@ -475,7 +515,7 @@ static linked_list_t* narrow_ts(private_child_create_t *this, bool local,
        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))
@@ -1081,12 +1121,12 @@ METHOD(task_t, build_i, status_t,
        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);
@@ -1269,8 +1309,8 @@ static child_cfg_t* select_child_cfg(private_child_create_t *this)
                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);