ike-sa: Add option to force the destruction of an IKE_SA after initiating a delete
authorTobias Brunner <tobias@strongswan.org>
Fri, 27 Apr 2018 15:27:53 +0000 (17:27 +0200)
committerTobias Brunner <tobias@strongswan.org>
Tue, 22 May 2018 08:06:07 +0000 (10:06 +0200)
src/libcharon/control/controller.c
src/libcharon/processing/jobs/delete_ike_sa_job.c
src/libcharon/processing/jobs/inactivity_job.c
src/libcharon/sa/ike_sa.c
src/libcharon/sa/ike_sa.h
src/libcharon/sa/ike_sa_manager.c
src/libcharon/sa/ikev2/tasks/ike_rekey.c
src/libcharon/tests/suites/test_child_delete.c
src/libcharon/tests/suites/test_child_rekey.c
src/libcharon/tests/suites/test_ike_delete.c
src/libcharon/tests/suites/test_ike_rekey.c

index dd8255f..6a37fff 100644 (file)
@@ -557,7 +557,7 @@ METHOD(job_t, terminate_ike_execute, job_requeue_t,
        listener->ike_sa = ike_sa;
        listener->lock->unlock(listener->lock);
 
-       if (ike_sa->delete(ike_sa) != DESTROY_ME)
+       if (ike_sa->delete(ike_sa, FALSE) != DESTROY_ME)
        {       /* delete failed */
                listener->status = FAILED;
                charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
index 53a1705..d539e4b 100644 (file)
@@ -64,7 +64,7 @@ METHOD(job_t, execute, job_requeue_t,
                }
                if (this->delete_if_established)
                {
-                       if (ike_sa->delete(ike_sa) == DESTROY_ME)
+                       if (ike_sa->delete(ike_sa, FALSE) == DESTROY_ME)
                        {
                                charon->ike_sa_manager->checkin_and_destroy(
                                                                                                charon->ike_sa_manager, ike_sa);
index bf16e51..e46861f 100644 (file)
@@ -101,7 +101,7 @@ METHOD(job_t, execute, job_requeue_t,
                        {
                                DBG1(DBG_JOB, "deleting IKE_SA after %d seconds "
                                         "of CHILD_SA inactivity", this->timeout);
-                               status = ike_sa->delete(ike_sa);
+                               status = ike_sa->delete(ike_sa, FALSE);
                        }
                        else
                        {
index 18d1c24..f39fed6 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2006-2017 Tobias Brunner
+ * Copyright (C) 2006-2018 Tobias Brunner
  * Copyright (C) 2006 Daniel Roethlisberger
  * Copyright (C) 2005-2009 Martin Willi
  * Copyright (C) 2005 Jan Hutter
@@ -1793,8 +1793,10 @@ METHOD(ike_sa_t, destroy_child_sa, status_t,
 }
 
 METHOD(ike_sa_t, delete_, status_t,
-       private_ike_sa_t *this)
+       private_ike_sa_t *this, bool force)
 {
+       status_t status = DESTROY_ME;
+
        switch (this->state)
        {
                case IKE_ESTABLISHED:
@@ -1806,19 +1808,38 @@ METHOD(ike_sa_t, delete_, status_t,
                                charon->bus->alert(charon->bus, ALERT_IKE_SA_EXPIRED);
                        }
                        this->task_manager->queue_ike_delete(this->task_manager);
-                       return this->task_manager->initiate(this->task_manager);
+                       status = this->task_manager->initiate(this->task_manager);
+                       break;
                case IKE_CREATED:
                        DBG1(DBG_IKE, "deleting unestablished IKE_SA");
                        break;
                case IKE_PASSIVE:
                        break;
                default:
-                       DBG1(DBG_IKE, "destroying IKE_SA in state %N "
-                               "without notification", ike_sa_state_names, this->state);
-                       charon->bus->ike_updown(charon->bus, &this->public, FALSE);
+                       DBG1(DBG_IKE, "destroying IKE_SA in state %N without notification",
+                                ike_sa_state_names, this->state);
+                       force = TRUE;
                        break;
        }
-       return DESTROY_ME;
+
+       if (force)
+       {
+               status = DESTROY_ME;
+
+               if (this->version == IKEV2)
+               {       /* for IKEv1 we trigger this in the ISAKMP delete task */
+                       switch (this->state)
+                       {
+                               case IKE_ESTABLISHED:
+                               case IKE_REKEYING:
+                               case IKE_DELETING:
+                                       charon->bus->ike_updown(charon->bus, &this->public, FALSE);
+                               default:
+                                       break;
+                       }
+               }
+       }
+       return status;
 }
 
 METHOD(ike_sa_t, rekey, status_t,
index b4fbc56..316b713 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2006-2017 Tobias Brunner
+ * Copyright (C) 2006-2018 Tobias Brunner
  * Copyright (C) 2006 Daniel Roethlisberger
  * Copyright (C) 2005-2009 Martin Willi
  * Copyright (C) 2005 Jan Hutter
@@ -776,15 +776,18 @@ struct ike_sa_t {
         *
         * Sends a delete message to the remote peer and waits for
         * its response. If the response comes in, or a timeout occurs,
-        * the IKE SA gets deleted.
+        * the IKE SA gets destroyed, unless force is TRUE then the IKE_SA is
+        * destroyed immediately without waiting for a response.
         *
+        * @param force                 whether to immediately destroy the IKE_SA afterwards
+        *                                              without waiting for a response
         * @return
         *                                              - SUCCESS if deletion is initialized
-        *                                              - DESTROY_ME, if the IKE_SA is not in
-        *                                                an established state and can not be
-        *                                                deleted (but destroyed).
+        *                                              - DESTROY_ME, if destroying is forced, or the IKE_SA
+        *                                                is not in an established state and can not be
+        *                                                deleted (but destroyed)
         */
-       status_t (*delete) (ike_sa_t *this);
+       status_t (*delete) (ike_sa_t *this, bool force);
 
        /**
         * Update IKE_SAs after network interfaces have changed.
index 101d986..2a499db 100644 (file)
@@ -2021,7 +2021,7 @@ static status_t enforce_replace(private_ike_sa_manager_t *this,
        }
        DBG1(DBG_IKE, "deleting duplicate IKE_SA for peer '%Y' due to "
                 "uniqueness policy", other);
-       return duplicate->delete(duplicate);
+       return duplicate->delete(duplicate, FALSE);
 }
 
 METHOD(ike_sa_manager_t, check_uniqueness, bool,
@@ -2266,20 +2266,7 @@ METHOD(ike_sa_manager_t, flush, void,
        while (enumerator->enumerate(enumerator, &entry, &segment))
        {
                charon->bus->set_sa(charon->bus, entry->ike_sa);
-               if (entry->ike_sa->get_version(entry->ike_sa) == IKEV2)
-               {       /* as the delete never gets processed, fire down events */
-                       switch (entry->ike_sa->get_state(entry->ike_sa))
-                       {
-                               case IKE_ESTABLISHED:
-                               case IKE_REKEYING:
-                               case IKE_DELETING:
-                                       charon->bus->ike_updown(charon->bus, entry->ike_sa, FALSE);
-                                       break;
-                               default:
-                                       break;
-                       }
-               }
-               entry->ike_sa->delete(entry->ike_sa);
+               entry->ike_sa->delete(entry->ike_sa, TRUE);
        }
        enumerator->destroy(enumerator);
 
index 2f0552a..11123b4 100644 (file)
@@ -363,7 +363,7 @@ METHOD(task_t, process_i, status_t,
                        /* IKE_SAs in state IKE_REKEYED are silently deleted, so we use
                         * IKE_REKEYING */
                        this->new_sa->set_state(this->new_sa, IKE_REKEYING);
-                       if (this->new_sa->delete(this->new_sa) == DESTROY_ME)
+                       if (this->new_sa->delete(this->new_sa, FALSE) == DESTROY_ME)
                        {
                                this->new_sa->destroy(this->new_sa);
                        }
index 437e919..8660d72 100644 (file)
@@ -290,7 +290,7 @@ START_TEST(test_collision_ike_delete)
        }
        call_ikesa(a, delete_child_sa, PROTO_ESP, spi_a, FALSE);
        assert_child_sa_state(a, spi_a, CHILD_DELETING);
-       call_ikesa(b, delete);
+       call_ikesa(b, delete, FALSE);
        assert_ike_sa_state(b, IKE_DELETING);
 
        /* RFC 7296, 2.25.2 does not explicitly state what the behavior SHOULD be if
index 6bf3588..51d577c 100644 (file)
@@ -1906,7 +1906,7 @@ START_TEST(test_collision_ike_delete)
                                                                                   &a, &b, NULL);
        }
        initiate_rekey(a, spi_a);
-       call_ikesa(b, delete);
+       call_ikesa(b, delete, FALSE);
        assert_ike_sa_state(b, IKE_DELETING);
 
        /* this should never get called as there is no successful rekeying on
index d79f9bc..7633718 100644 (file)
@@ -40,7 +40,7 @@ START_TEST(test_regular)
        }
        assert_hook_not_called(ike_updown);
        assert_hook_not_called(child_updown);
-       call_ikesa(a, delete);
+       call_ikesa(a, delete, FALSE);
        assert_ike_sa_state(a, IKE_DELETING);
        assert_hook();
        assert_hook();
@@ -81,9 +81,9 @@ START_TEST(test_collision)
 
        assert_hook_not_called(ike_updown);
        assert_hook_not_called(child_updown);
-       call_ikesa(a, delete);
+       call_ikesa(a, delete, FALSE);
        assert_ike_sa_state(a, IKE_DELETING);
-       call_ikesa(b, delete);
+       call_ikesa(b, delete, FALSE);
        assert_ike_sa_state(b, IKE_DELETING);
        assert_hook();
        assert_hook();
index e22a0c2..b6a0154 100644 (file)
@@ -1319,7 +1319,7 @@ START_TEST(test_collision_delete)
        assert_hook_not_called(ike_rekey);
 
        initiate_rekey(a);
-       call_ikesa(b, delete);
+       call_ikesa(b, delete, FALSE);
        assert_ike_sa_state(b, IKE_DELETING);
 
        /* RFC 7296, 2.25.2: If a peer receives a request to rekey an IKE SA that
@@ -1401,7 +1401,7 @@ START_TEST(test_collision_delete_drop_delete)
        assert_hook_not_called(ike_rekey);
 
        initiate_rekey(a);
-       call_ikesa(b, delete);
+       call_ikesa(b, delete, FALSE);
        assert_ike_sa_state(b, IKE_DELETING);
 
        /* RFC 7296, 2.25.2: If a peer receives a request to rekey an IKE SA that