Switch to alternative peer config in IKEv1 Main and Aggressive Mode.
authorTobias Brunner <tobias@strongswan.org>
Mon, 21 May 2012 10:07:17 +0000 (12:07 +0200)
committerTobias Brunner <tobias@strongswan.org>
Mon, 21 May 2012 13:49:25 +0000 (15:49 +0200)
src/libcharon/sa/ikev1/phase1.c
src/libcharon/sa/ikev1/phase1.h
src/libcharon/sa/ikev1/tasks/aggressive_mode.c
src/libcharon/sa/ikev1/tasks/main_mode.c

index ec55d53..709bc6c 100644 (file)
@@ -1,4 +1,7 @@
 /*
+ * Copyright (C) 2012 Tobias Brunner
+ * Hochschule fuer Technik Rapperswil
+ *
  * Copyright (C) 2012 Martin Willi
  * Copyright (C) 2012 revosec AG
  *
@@ -19,6 +22,7 @@
 #include <sa/ikev1/keymat_v1.h>
 #include <encoding/payloads/ke_payload.h>
 #include <encoding/payloads/nonce_payload.h>
+#include <utils/linked_list.h>
 
 typedef struct private_phase1_t private_phase1_t;
 
@@ -38,6 +42,16 @@ struct private_phase1_t {
        ike_sa_t *ike_sa;
 
        /**
+        * Currently selected peer config
+        */
+       peer_cfg_t *peer_cfg;
+
+       /**
+        * Other possible peer config candidates
+        */
+       linked_list_t *candidates;
+
+       /**
         * Acting as initiator
         */
        bool initiator;
@@ -513,9 +527,22 @@ METHOD(phase1_t, select_config, peer_cfg_t*,
        identification_t *id)
 {
        enumerator_t *enumerator;
-       peer_cfg_t *current, *found = NULL;
+       peer_cfg_t *current;
        host_t *me, *other;
 
+       if (this->peer_cfg)
+       {       /* try to find an alternative config */
+               if (this->candidates->remove_first(this->candidates,
+                                                                                 (void**)&current) != SUCCESS)
+               {
+                       DBG1(DBG_CFG, "no alternative config found");
+                       return NULL;
+               }
+               DBG1(DBG_CFG, "switching to peer config '%s'",
+                        current->get_name(current));
+               return current;
+       }
+
        me = this->ike_sa->get_my_host(this->ike_sa);
        other = this->ike_sa->get_other_host(this->ike_sa);
        DBG1(DBG_CFG, "looking for %N peer configs matching %H...%H[%Y]",
@@ -527,17 +554,27 @@ METHOD(phase1_t, select_config, peer_cfg_t*,
                if (check_auth_method(this, current, method) &&
                        current->use_aggressive(current) == aggressive)
                {
-                       found = current->get_ref(current);
-                       break;
+                       current->get_ref(current);
+                       if (!this->peer_cfg)
+                       {
+                               this->peer_cfg = current;
+                       }
+                       else
+                       {
+                               this->candidates->insert_last(this->candidates, current);
+                       }
                }
        }
        enumerator->destroy(enumerator);
 
-       if (found)
+       if (this->peer_cfg)
        {
-               DBG2(DBG_CFG, "selected peer config \"%s\"", found->get_name(found));
+               DBG1(DBG_CFG, "selected peer config \"%s\"",
+                        this->peer_cfg->get_name(this->peer_cfg));
+               return this->peer_cfg->get_ref(this->peer_cfg);
        }
-       return found;
+       DBG1(DBG_IKE, "no peer config found");
+       return NULL;
 }
 
 METHOD(phase1_t, get_id, identification_t*,
@@ -661,6 +698,9 @@ METHOD(phase1_t, get_nonce_ke, bool,
 METHOD(phase1_t, destroy, void,
        private_phase1_t *this)
 {
+       DESTROY_IF(this->peer_cfg);
+       this->candidates->destroy_offset(this->candidates,
+                                                                        offsetof(peer_cfg_t, destroy));
        chunk_free(&this->sa_payload);
        DESTROY_IF(this->dh);
        free(this->dh_value.ptr);
@@ -691,6 +731,7 @@ phase1_t *phase1_create(ike_sa_t *ike_sa, bool initiator)
                        .get_nonce_ke = _get_nonce_ke,
                        .destroy = _destroy,
                },
+               .candidates = linked_list_create(),
                .ike_sa = ike_sa,
                .initiator = initiator,
                .keymat = (keymat_v1_t*)ike_sa->get_keymat(ike_sa),
index 91210c3..f1e95d8 100644 (file)
@@ -88,6 +88,9 @@ struct phase1_t {
        /**
         * Select a peer config as responder.
         *
+        * If called after the first successful call the next alternative config
+        * is returned, if any.
+        *
         * @param method                used authentication method
         * @param aggressive    TRUE to get an aggressive mode config
         * @param id                    initiator identity
index 4c581cd..e1c51a8 100644 (file)
@@ -1,4 +1,7 @@
 /*
+ * Copyright (C) 2012 Tobias Brunner
+ * Hochschule fuer Technik Rapperswil
+ *
  * Copyright (C) 2012 Martin Willi
  * Copyright (C) 2012 revosec AG
  *
@@ -399,7 +402,6 @@ METHOD(task_t, process_r, status_t,
                                                                                                          this->method, TRUE, id);
                        if (!this->peer_cfg)
                        {
-                               DBG1(DBG_IKE, "no peer config found");
                                return send_notify(this, AUTHENTICATION_FAILED);
                        }
                        this->ike_sa->set_peer_cfg(this->ike_sa, this->peer_cfg);
@@ -413,11 +415,22 @@ METHOD(task_t, process_r, status_t,
                }
                case AM_AUTH:
                {
-                       if (!this->ph1->verify_auth(this->ph1, this->method, message,
-                                                                               this->id_data))
+                       while (TRUE)
                        {
-                               this->id_data = chunk_empty;
-                               return send_delete(this);
+                               if (this->ph1->verify_auth(this->ph1, this->method, message,
+                                                                                  this->id_data))
+                               {
+                                       break;
+                               }
+                               this->peer_cfg->destroy(this->peer_cfg);
+                               this->peer_cfg = this->ph1->select_config(this->ph1,
+                                                                                                       this->method, TRUE, NULL);
+                               if (!this->peer_cfg)
+                               {
+                                       this->id_data = chunk_empty;
+                                       return send_delete(this);
+                               }
+                               this->ike_sa->set_peer_cfg(this->ike_sa, this->peer_cfg);
                        }
                        this->id_data = chunk_empty;
 
index ff78764..ce047df 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011 Tobias Brunner
+ * Copyright (C) 2011-2012 Tobias Brunner
  * Hochschule fuer Technik Rapperswil
  *
  * Copyright (C) 2011 Martin Willi
@@ -405,23 +405,27 @@ METHOD(task_t, process_r, status_t,
                                DBG1(DBG_IKE, "IDii payload missing");
                                return send_notify(this, INVALID_PAYLOAD_TYPE);
                        }
-
                        id = id_payload->get_identification(id_payload);
                        this->ike_sa->set_other_id(this->ike_sa, id);
-                       this->peer_cfg = this->ph1->select_config(this->ph1,
-                                                                                                         this->method, FALSE, id);
-                       if (!this->peer_cfg)
-                       {
-                               DBG1(DBG_IKE, "no peer config found");
-                               return send_notify(this, AUTHENTICATION_FAILED);
-                       }
-                       this->ike_sa->set_peer_cfg(this->ike_sa, this->peer_cfg);
 
-                       if (!this->ph1->verify_auth(this->ph1, this->method, message,
-                                                                               id_payload->get_encoded(id_payload)))
+                       while (TRUE)
                        {
-                               return send_notify(this, AUTHENTICATION_FAILED);
+                               DESTROY_IF(this->peer_cfg);
+                               this->peer_cfg = this->ph1->select_config(this->ph1,
+                                                                                                       this->method, FALSE, id);
+                               if (!this->peer_cfg)
+                               {
+                                       return send_notify(this, AUTHENTICATION_FAILED);
+                               }
+                               this->ike_sa->set_peer_cfg(this->ike_sa, this->peer_cfg);
+
+                               if (this->ph1->verify_auth(this->ph1, this->method, message,
+                                                                                  id_payload->get_encoded(id_payload)))
+                               {
+                                       break;
+                               }
                        }
+
                        if (!charon->bus->authorize(charon->bus, FALSE))
                        {
                                DBG1(DBG_IKE, "Main Mode authorization hook forbids IKE_SA, "