aboutsummaryrefslogtreecommitdiffstats
path: root/src/libcharon/sa/ikev1/task_manager_v1.c
diff options
context:
space:
mode:
authorTobias Brunner <tobias@strongswan.org>2015-08-19 15:28:02 +0200
committerTobias Brunner <tobias@strongswan.org>2015-08-20 19:13:45 +0200
commit4de361d92c542283c9d24088c0474f147596fa13 (patch)
tree89a45071354f348e9aa7186f7b8d67a6f96467ca /src/libcharon/sa/ikev1/task_manager_v1.c
parente2a252a86f5f65b6f6a5ff80fa7f97f5b8470817 (diff)
downloadstrongswan-4de361d92c54.tar.bz2
strongswan-4de361d92c54.tar.xz
ikev1: Fix handling of overlapping Quick Mode exchanges
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.
Diffstat (limited to 'src/libcharon/sa/ikev1/task_manager_v1.c')
-rw-r--r--src/libcharon/sa/ikev1/task_manager_v1.c35
1 files changed, 34 insertions, 1 deletions
diff --git a/src/libcharon/sa/ikev1/task_manager_v1.c b/src/libcharon/sa/ikev1/task_manager_v1.c
index ed547c4c2..678f99df1 100644
--- a/src/libcharon/sa/ikev1/task_manager_v1.c
+++ b/src/libcharon/sa/ikev1/task_manager_v1.c
@@ -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
*
@@ -901,6 +901,34 @@ static bool process_dpd(private_task_manager_t *this, message_t *message)
}
/**
+ * 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
*/
static status_t process_request(private_task_manager_t *this,
@@ -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);