Use the vararg list constructor in quick mode task
[strongswan.git] / src / libcharon / sa / ikev1 / tasks / quick_mode.c
index 67d1b45..39fbd59 100644 (file)
@@ -175,6 +175,62 @@ static void schedule_inactivity_timeout(private_quick_mode_t *this)
 }
 
 /**
+ * Check if we have a an address pool configured
+ */
+static bool have_pool(ike_sa_t *ike_sa)
+{
+       enumerator_t *enumerator;
+       peer_cfg_t *peer_cfg;
+       char *pool;
+       bool found = FALSE;
+
+       peer_cfg = ike_sa->get_peer_cfg(ike_sa);
+       if (peer_cfg)
+       {
+               enumerator = peer_cfg->create_pool_enumerator(peer_cfg);
+               if (enumerator->enumerate(enumerator, &pool))
+               {
+                       found = TRUE;
+               }
+               enumerator->destroy(enumerator);
+       }
+       return found;
+}
+
+/**
+ * Get host to use for dynamic traffic selectors
+ */
+static host_t *get_dynamic_host(ike_sa_t *ike_sa, bool local)
+{
+       enumerator_t *enumerator;
+       host_t *host;
+
+       enumerator = ike_sa->create_virtual_ip_enumerator(ike_sa, local);
+       if (!enumerator->enumerate(enumerator, &host))
+       {
+               if (local)
+               {
+                       host = ike_sa->get_my_host(ike_sa);
+               }
+               else
+               {
+                       if (have_pool(ike_sa))
+                       {
+                               /* we have an IP address pool, but didn't negotiate a
+                                * virtual IP. */
+                               host = NULL;
+                       }
+                       else
+                       {
+                               host = ike_sa->get_other_host(ike_sa);
+                       }
+               }
+       }
+       enumerator->destroy(enumerator);
+       return host;
+}
+
+/**
  * Install negotiated CHILD_SA
  */
 static bool install(private_quick_mode_t *this)
@@ -202,10 +258,8 @@ static bool install(private_quick_mode_t *this)
 
        status_i = status_o = FAILED;
        encr_i = encr_r = integ_i = integ_r = chunk_empty;
-       tsi = linked_list_create();
-       tsr = linked_list_create();
-       tsi->insert_last(tsi, this->tsi->clone(this->tsi));
-       tsr->insert_last(tsr, this->tsr->clone(this->tsr));
+       tsi = linked_list_create_with_items(this->tsi->clone(this->tsi), NULL);
+       tsr = linked_list_create_with_items(this->tsr->clone(this->tsr), NULL);
        if (this->initiator)
        {
                charon->bus->narrow(charon->bus, this->child_sa,
@@ -214,7 +268,7 @@ static bool install(private_quick_mode_t *this)
        else
        {
                charon->bus->narrow(charon->bus, this->child_sa,
-                                                       NARROW_RESPONDER, tsr, tsi);
+                                                       NARROW_RESPONDER_POST, tsr, tsi);
        }
        if (tsi->get_count(tsi) == 0 || tsr->get_count(tsr) == 0)
        {
@@ -399,25 +453,12 @@ static traffic_selector_t* select_ts(private_quick_mode_t *this, bool local,
 {
        traffic_selector_t *ts;
        linked_list_t *list;
-       host_t *host;
 
-       host = this->ike_sa->get_virtual_ip(this->ike_sa, local);
-       if (!host)
-       {
-               if (local)
-               {
-                       host = this->ike_sa->get_my_host(this->ike_sa);
-               }
-               else
-               {
-                       host = this->ike_sa->get_other_host(this->ike_sa);
-               }
-       }
        list = this->config->get_traffic_selectors(this->config, local,
-                                                                                          supplied, host);
+                                                       supplied, get_dynamic_host(this->ike_sa, local));
        if (list->get_first(list, (void**)&ts) == SUCCESS)
        {
-               if (list->get_count(list) > 1)
+               if (this->initiator && list->get_count(list) > 1)
                {
                        DBG1(DBG_IKE, "configuration has more than one %s traffic selector,"
                                 " using first only", local ? "local" : "remote");
@@ -523,6 +564,15 @@ static bool get_ts(private_quick_mode_t *this, message_t *message)
                tsr = traffic_selector_create_from_subnet(hsr->clone(hsr),
                                                        hsr->get_family(hsr) == AF_INET ? 32 : 128, 0, 0);
        }
+       if (!this->initiator && this->mode == MODE_TRANSPORT && this->udp &&
+          (!tsi->is_host(tsi, hsi) || !tsr->is_host(tsr, hsr)))
+       {       /* change TS in case of a NAT in transport mode */
+               DBG2(DBG_IKE, "changing received traffic selectors %R=== %R due to NAT",
+                        tsi, tsr);
+               tsi->set_address(tsi, hsi);
+               tsr->set_address(tsr, hsr);
+       }
+
        if (this->initiator)
        {
                /* check if peer selection valid */
@@ -730,10 +780,8 @@ METHOD(task_t, build_i, status_t,
                        {
                                this->tsr = select_ts(this, FALSE, NULL);
                        }
-                       tsi = linked_list_create();
-                       tsr = linked_list_create();
-                       tsi->insert_last(tsi, this->tsi);
-                       tsr->insert_last(tsr, this->tsr);
+                       tsi = linked_list_create_with_items(this->tsi, NULL);
+                       tsr = linked_list_create_with_items(this->tsr, NULL);
                        this->tsi = this->tsr = NULL;
                        charon->bus->narrow(charon->bus, this->child_sa,
                                                                NARROW_INITIATOR_PRE_AUTH, tsi, tsr);
@@ -841,32 +889,30 @@ METHOD(task_t, process_r, status_t,
                        sa_payload_t *sa_payload;
                        linked_list_t *tsi, *tsr, *list = NULL;
                        peer_cfg_t *peer_cfg;
-                       host_t *me, *other;
                        u_int16_t group;
                        bool private;
 
-                       if (!get_ts(this, message))
-                       {
-                               return FAILED;
-                       }
-                       me = this->ike_sa->get_virtual_ip(this->ike_sa, TRUE);
-                       if (!me)
+                       sa_payload = (sa_payload_t*)message->get_payload(message,
+                                                                                                       SECURITY_ASSOCIATION_V1);
+                       if (!sa_payload)
                        {
-                               me = this->ike_sa->get_my_host(this->ike_sa);
+                               DBG1(DBG_IKE, "sa payload missing");
+                               return send_notify(this, INVALID_PAYLOAD_TYPE);
                        }
-                       other = this->ike_sa->get_virtual_ip(this->ike_sa, FALSE);
-                       if (!other)
+
+                       this->mode = sa_payload->get_encap_mode(sa_payload, &this->udp);
+
+                       if (!get_ts(this, message))
                        {
-                               other = this->ike_sa->get_other_host(this->ike_sa);
+                               return FAILED;
                        }
                        peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa);
-                       tsi = linked_list_create();
-                       tsr = linked_list_create();
-                       tsi->insert_last(tsi, this->tsi);
-                       tsr->insert_last(tsr, this->tsr);
+                       tsi = linked_list_create_with_items(this->tsi, NULL);
+                       tsr = linked_list_create_with_items(this->tsr, NULL);
                        this->tsi = this->tsr = NULL;
                        this->config = peer_cfg->select_child_cfg(peer_cfg, tsr, tsi,
-                                                                                                         me, other);
+                                                                               get_dynamic_host(this->ike_sa, TRUE),
+                                                                               get_dynamic_host(this->ike_sa, FALSE));
                        if (this->config)
                        {
                                this->tsi = select_ts(this, FALSE, tsi);
@@ -880,13 +926,6 @@ METHOD(task_t, process_r, status_t,
                                return send_notify(this, INVALID_ID_INFORMATION);
                        }
 
-                       sa_payload = (sa_payload_t*)message->get_payload(message,
-                                                                                                       SECURITY_ASSOCIATION_V1);
-                       if (!sa_payload)
-                       {
-                               DBG1(DBG_IKE, "sa payload missing");
-                               return send_notify(this, INVALID_PAYLOAD_TYPE);
-                       }
                        if (this->config->use_ipcomp(this->config))
                        {
                                if (this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY))
@@ -917,8 +956,6 @@ METHOD(task_t, process_r, status_t,
                                                                                                                   list, FALSE, private);
                        list->destroy_offset(list, offsetof(proposal_t, destroy));
 
-                       this->mode = sa_payload->get_encap_mode(sa_payload, &this->udp);
-
                        get_lifetimes(this);
                        apply_lifetimes(this, sa_payload);
 
@@ -958,6 +995,22 @@ 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);
+
+                       tsi = linked_list_create_with_items(this->tsi, NULL);
+                       tsr = linked_list_create_with_items(this->tsr, NULL);
+                       this->tsi = this->tsr = NULL;
+                       charon->bus->narrow(charon->bus, this->child_sa,
+                                                               NARROW_RESPONDER, tsr, tsi);
+                       if (tsi->remove_first(tsi, (void**)&this->tsi) != SUCCESS ||
+                               tsr->remove_first(tsr, (void**)&this->tsr) != SUCCESS)
+                       {
+                               tsi->destroy_offset(tsi, offsetof(traffic_selector_t, destroy));
+                               tsr->destroy_offset(tsr, offsetof(traffic_selector_t, destroy));
+                               return send_notify(this, INVALID_ID_INFORMATION);
+                       }
+                       tsi->destroy_offset(tsi, offsetof(traffic_selector_t, destroy));
+                       tsr->destroy_offset(tsr, offsetof(traffic_selector_t, destroy));
+
                        return NEED_MORE;
                }
                case QM_NEGOTIATED: