charon-tkm: Don't select new outbound SA until the policy is installed
authorTobias Brunner <tobias@strongswan.org>
Tue, 11 Jul 2017 12:05:01 +0000 (14:05 +0200)
committerTobias Brunner <tobias@strongswan.org>
Mon, 7 Aug 2017 08:44:05 +0000 (10:44 +0200)
This tries to avoid packet loss during rekeying by delaying the usage of
the new outbound IKE_SA until the old one is deleted.

Note that esa_select() is a no-op in the current TKM implementation. And
the implementation also doesn't benefit from the delayed deletion of the
inbound SA as it calls esa_reset() when the outbound SA is deleted.

src/charon-tkm/src/tkm/tkm_kernel_ipsec.c

index 9229c3d..8ccae4c 100644 (file)
@@ -1,7 +1,8 @@
 /*
+ * Copyright (C) 2017 Tobias Brunner
  * Copyright (C) 2012-2014 Reto Buerki
  * Copyright (C) 2012 Adrian-Ken Rueegsegger
- * Hochschule fuer Technik Rapperswil
+ * HSR Hochschule fuer Technik Rapperswil
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the
@@ -182,15 +183,6 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
                tkm->chunk_map->remove(tkm->chunk_map, nonce_loc);
                tkm->idmgr->release_id(tkm->idmgr, TKM_CTX_NONCE, nonce_loc_id);
        }
-       if (ike_esa_select(esa_id) != TKM_OK)
-       {
-               DBG1(DBG_KNL, "error selecting new child SA (%llu)", esa_id);
-               if (ike_esa_reset(esa_id) != TKM_OK)
-               {
-                       DBG1(DBG_KNL, "child SA (%llu) deletion failed", esa_id);
-               }
-               goto failure;
-       }
 
        DBG1(DBG_KNL, "added child SA (esa: %llu, isa: %llu, esp_spi_loc: %x, "
                 "esp_spi_rem: %x, role: %s)", esa_id, esa.isa_id, ntohl(spi_loc),
@@ -221,23 +213,12 @@ METHOD(kernel_ipsec_t, del_sa, status_t,
        private_tkm_kernel_ipsec_t *this, kernel_ipsec_sa_id_t *id,
        kernel_ipsec_del_sa_t *data)
 {
-       esa_id_type esa_id, other_esa_id;
+       esa_id_type esa_id;
 
        esa_id = tkm->sad->get_esa_id(tkm->sad, id->src, id->dst,
                                                                  id->spi, id->proto);
        if (esa_id)
        {
-               other_esa_id = tkm->sad->get_other_esa_id(tkm->sad, esa_id);
-               if (other_esa_id)
-               {
-                       DBG1(DBG_KNL, "selecting child SA (esa: %llu)", other_esa_id);
-                       if (ike_esa_select(other_esa_id) != TKM_OK)
-                       {
-                               DBG1(DBG_KNL, "error selecting other child SA (esa: %llu)",
-                                               other_esa_id);
-                       }
-               }
-
                DBG1(DBG_KNL, "deleting child SA (esa: %llu, spi: %x)", esa_id,
                         ntohl(id->spi));
                if (ike_esa_reset(esa_id) != TKM_OK)
@@ -269,6 +250,43 @@ METHOD(kernel_ipsec_t, add_policy, status_t,
        private_tkm_kernel_ipsec_t *this, kernel_ipsec_policy_id_t *id,
        kernel_ipsec_manage_policy_t *data)
 {
+       esa_id_type esa_id;
+       uint32_t spi;
+       uint8_t proto;
+
+       if (id->dir == POLICY_OUT && data->type == POLICY_IPSEC &&
+               data->prio == POLICY_PRIORITY_DEFAULT)
+       {
+               if (data->sa->esp.use)
+               {
+                       spi = data->sa->esp.spi;
+                       proto = IPPROTO_ESP;
+               }
+               else if (data->sa->ah.use)
+               {
+                       spi = data->sa->ah.spi;
+                       proto = IPPROTO_AH;
+               }
+               else
+               {
+                       return FAILED;
+               }
+               esa_id = tkm->sad->get_esa_id(tkm->sad, data->src, data->dst,
+                                                                         spi, proto);
+               if (!esa_id)
+               {
+                       DBG1(DBG_KNL, "unable to find esa ID for policy (spi: %x)",
+                                ntohl(spi));
+                       return FAILED;
+               }
+               DBG1(DBG_KNL, "selecting child SA (esa: %llu, spi: %x)", esa_id,
+                        ntohl(spi));
+               if (ike_esa_select(esa_id) != TKM_OK)
+               {
+                       DBG1(DBG_KNL, "error selecting new child SA (%llu)", esa_id);
+                       return FAILED;
+               }
+       }
        return SUCCESS;
 }