]> git.ipfire.org Git - thirdparty/strongswan.git/commitdiff
ikev1: Fix handling of overlapping Quick Mode exchanges
authorTobias Brunner <tobias@strongswan.org>
Wed, 19 Aug 2015 13:28:02 +0000 (15:28 +0200)
committerTobias Brunner <tobias@strongswan.org>
Thu, 20 Aug 2015 17:13:45 +0000 (19:13 +0200)
In some cases the third message of a Quick Mode exchange might arrive
after the first message of a subsequent Quick Mode exchange.  Previously
these messages were handled incorrectly and the second Quick Mode
exchange failed.

Some implementations might even try to establish multiple Quick Modes
simultaneously, which is explicitly allowed in RFC 2409.  We don't fully
support that, though, in particular in case of retransmits.

Fixes #1076.

src/libcharon/sa/ikev1/task_manager_v1.c
src/libcharon/sa/ikev1/tasks/quick_mode.c
src/libcharon/sa/ikev1/tasks/quick_mode.h

index ed547c4c26f14c75671453994ddc4ef53289f941..678f99df1a6bd6ec2c71b1a0ddc0b622a78f30a1 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2007-2014 Tobias Brunner
+ * Copyright (C) 2007-2015 Tobias Brunner
  * Copyright (C) 2007-2011 Martin Willi
  * Hochschule fuer Technik Rapperswil
  *
@@ -900,6 +900,34 @@ static bool process_dpd(private_task_manager_t *this, message_t *message)
        return TRUE;
 }
 
+/**
+ * Check if we already have a quick mode task queued for the exchange with the
+ * given message ID
+ */
+static bool have_quick_mode_task(private_task_manager_t *this, u_int32_t mid)
+{
+       enumerator_t *enumerator;
+       quick_mode_t *qm;
+       task_t *task;
+       bool found = FALSE;
+
+       enumerator = this->passive_tasks->create_enumerator(this->passive_tasks);
+       while (enumerator->enumerate(enumerator, &task))
+       {
+               if (task->get_type(task) == TASK_QUICK_MODE)
+               {
+                       qm = (quick_mode_t*)task;
+                       if (qm->get_mid(qm) == mid)
+                       {
+                               found = TRUE;
+                               break;
+                       }
+               }
+       }
+       enumerator->destroy(enumerator);
+       return found;
+}
+
 /**
  * handle an incoming request message
  */
@@ -911,6 +939,7 @@ static status_t process_request(private_task_manager_t *this,
        bool send_response = FALSE, dpd = FALSE;
 
        if (message->get_exchange_type(message) == INFORMATIONAL_V1 ||
+               message->get_exchange_type(message) == QUICK_MODE ||
                this->passive_tasks->get_count(this->passive_tasks) == 0)
        {       /* create tasks depending on request type, if not already some queued */
                switch (message->get_exchange_type(message))
@@ -946,6 +975,10 @@ static status_t process_request(private_task_manager_t *this,
                                                 "unestablished IKE_SA, ignored");
                                        return FAILED;
                                }
+                               if (have_quick_mode_task(this, message->get_message_id(message)))
+                               {
+                                       break;
+                               }
                                task = (task_t *)quick_mode_create(this->ike_sa, NULL,
                                                                                                   NULL, NULL);
                                this->passive_tasks->insert_last(this->passive_tasks, task);
index 96edfd8d8541a046ad58748ce4b2db63809bc0d5..d6a3f2cd1ca37985fd6777a1cf32c5ce528f0d24 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012 Tobias Brunner
+ * Copyright (C) 2012-2015 Tobias Brunner
  * Hochschule fuer Technik Rapperswil
  *
  * Copyright (C) 2011 Martin Willi
@@ -185,6 +185,11 @@ struct private_quick_mode_t {
         */
        bool udp;
 
+       /**
+        * Message ID of handled quick mode exchange
+        */
+       u_int32_t mid;
+
        /** states of quick mode */
        enum {
                QM_INIT,
@@ -1019,6 +1024,11 @@ static void check_for_rekeyed_child(private_quick_mode_t *this)
 METHOD(task_t, process_r, status_t,
        private_quick_mode_t *this, message_t *message)
 {
+       if (this->mid && this->mid != message->get_message_id(message))
+       {       /* not responsible for this quick mode exchange */
+               return NEED_MORE;
+       }
+
        switch (this->state)
        {
                case QM_INIT:
@@ -1188,6 +1198,11 @@ METHOD(task_t, process_r, status_t,
 METHOD(task_t, build_r, status_t,
        private_quick_mode_t *this, message_t *message)
 {
+       if (this->mid && this->mid != message->get_message_id(message))
+       {       /* not responsible for this quick mode exchange */
+               return NEED_MORE;
+       }
+
        switch (this->state)
        {
                case QM_INIT:
@@ -1242,6 +1257,7 @@ METHOD(task_t, build_r, status_t,
                        add_ts(this, message);
 
                        this->state = QM_NEGOTIATED;
+                       this->mid = message->get_message_id(message);
                        return NEED_MORE;
                }
                case QM_NEGOTIATED:
@@ -1335,6 +1351,12 @@ METHOD(task_t, get_type, task_type_t,
        return TASK_QUICK_MODE;
 }
 
+METHOD(quick_mode_t, get_mid, u_int32_t,
+       private_quick_mode_t *this)
+{
+       return this->mid;
+}
+
 METHOD(quick_mode_t, use_reqid, void,
        private_quick_mode_t *this, u_int32_t reqid)
 {
@@ -1368,6 +1390,7 @@ METHOD(task_t, migrate, void,
        this->ike_sa = ike_sa;
        this->keymat = (keymat_v1_t*)ike_sa->get_keymat(ike_sa);
        this->state = QM_INIT;
+       this->mid = 0;
        this->tsi = NULL;
        this->tsr = NULL;
        this->proposal = NULL;
@@ -1414,6 +1437,7 @@ quick_mode_t *quick_mode_create(ike_sa_t *ike_sa, child_cfg_t *config,
                                .migrate = _migrate,
                                .destroy = _destroy,
                        },
+                       .get_mid = _get_mid,
                        .use_reqid = _use_reqid,
                        .use_marks = _use_marks,
                        .rekey = _rekey,
index ee9b64d1394cdde4f6024e451565c434164e5e3b..062d634655c1ef39d34f4e2170e5846bf7c5d068 100644 (file)
@@ -1,4 +1,7 @@
 /*
+ * Copyright (C) 2015 Tobias Brunner
+ * Hochschule fuer Technik Rapperswil
+ *
  * Copyright (C) 2011 Martin Willi
  * Copyright (C) 2011 revosec AG
  *
@@ -37,6 +40,14 @@ struct quick_mode_t {
         */
        task_t task;
 
+       /**
+        * Get the message ID of the quick mode exchange handled by this task as
+        * responder.
+        *
+        * @return                              message ID, or 0 (not defined yet or as initiator)
+        */
+       u_int32_t (*get_mid)(quick_mode_t *this);
+
        /**
         * Use a specific reqid to install this CHILD_SA.
         *