]> git.ipfire.org Git - thirdparty/strongswan.git/commitdiff
Instead of rekeying, delete a quick mode if we have a fresher instance
authorMartin Willi <martin@revosec.ch>
Tue, 5 Jun 2012 13:03:10 +0000 (15:03 +0200)
committerMartin Willi <martin@revosec.ch>
Fri, 8 Jun 2012 08:22:03 +0000 (10:22 +0200)
If both peers initiate quick mode rekeying simultaneously, we end up
with duplicate SAs for a configuration. This can't be avoided, nor do
the standards provide an appropriate solution. Instead of closing one
SA immediately, we keep both. But once rekeying triggers, we don't
refresh the SA with the shorter soft lifetime, but delete it.

src/libcharon/sa/ikev1/task_manager_v1.c

index e6e7a0dd8e4de2e09a82499998b6e58dab20a5b8..9fa2c9b2ffad7b7cd71afea877b375ce04304896 100644 (file)
@@ -1366,6 +1366,34 @@ METHOD(task_manager_t, queue_child, void,
        queue_task(this, &task->task);
 }
 
+/**
+ * Check if a CHILD_SA is redundant and we should delete instead of rekey
+ */
+static bool is_redundant(private_task_manager_t *this, child_sa_t *child_sa)
+{
+       enumerator_t *enumerator;
+       child_sa_t *current;
+       bool redundant = FALSE;
+
+       enumerator = this->ike_sa->create_child_sa_enumerator(this->ike_sa);
+       while (enumerator->enumerate(enumerator, &current))
+       {
+               if (current->get_state(current) == CHILD_INSTALLED &&
+                       streq(current->get_name(current), child_sa->get_name(child_sa)) &&
+                       current->get_lifetime(current, FALSE) >
+                               child_sa->get_lifetime(child_sa, FALSE))
+               {
+                       DBG1(DBG_IKE, "deleting redundant CHILD_SA %s{%d}",
+                                child_sa->get_name(child_sa), child_sa->get_reqid(child_sa));
+                       redundant = TRUE;
+                       break;
+               }
+       }
+       enumerator->destroy(enumerator);
+
+       return redundant;
+}
+
 METHOD(task_manager_t, queue_child_rekey, void,
        private_task_manager_t *this, protocol_id_t protocol, u_int32_t spi)
 {
@@ -1380,13 +1408,21 @@ METHOD(task_manager_t, queue_child_rekey, void,
        }
        if (child_sa && child_sa->get_state(child_sa) == CHILD_INSTALLED)
        {
-               child_sa->set_state(child_sa, CHILD_REKEYING);
-               cfg = child_sa->get_config(child_sa);
-               task = quick_mode_create(this->ike_sa, cfg->get_ref(cfg), NULL, NULL);
-               task->use_reqid(task, child_sa->get_reqid(child_sa));
-               task->rekey(task, child_sa->get_spi(child_sa, TRUE));
+               if (is_redundant(this, child_sa))
+               {
+                       queue_task(this, (task_t*)quick_delete_create(this->ike_sa,
+                                                                                               protocol, spi, FALSE, FALSE));
+               }
+               else
+               {
+                       child_sa->set_state(child_sa, CHILD_REKEYING);
+                       cfg = child_sa->get_config(child_sa);
+                       task = quick_mode_create(this->ike_sa, cfg->get_ref(cfg), NULL, NULL);
+                       task->use_reqid(task, child_sa->get_reqid(child_sa));
+                       task->rekey(task, child_sa->get_spi(child_sa, TRUE));
 
-               queue_task(this, &task->task);
+                       queue_task(this, &task->task);
+               }
        }
 }