Commit 2d856cb1a5 for strongswan.org

commit 2d856cb1a588a8d83cf92d220276a1ef8476e4da
Author: Tobias Brunner <tobias@strongswan.org>
Date:   Thu Oct 29 17:23:36 2026 +0100

    charon-nm: Terminate all IKE SAs when disconnecting

    Since we currently only support a single concurrent SA, this ensures we
    don't keep any lingering IKE SAs around (e.g. during a make-before-break
    reauthentication), which could mess with the next connection attempt.
    For instance, `checkout_by_config()` could return an existing SA and the
    peer and child config objects get destroyed causing a crash when the
    added create-child task is executed.

    We also don't wait for a response to our delete as the peer might not
    be reachable when this happens (e.g. when NM already suspended the
    interfaces).

    Closes strongswan/strongswan#3194

diff --git a/src/charon-nm/nm/nm_service.c b/src/charon-nm/nm/nm_service.c
index 5a3b83b737..43504cd9cc 100644
--- a/src/charon-nm/nm/nm_service.c
+++ b/src/charon-nm/nm/nm_service.c
@@ -1320,31 +1320,30 @@ static gboolean do_disconnect(gpointer plugin)
 {
 	NMStrongswanPluginPrivate *priv = NM_STRONGSWAN_PLUGIN_GET_PRIVATE(plugin);
 	enumerator_t *enumerator;
+	array_t *ids = NULL;
 	ike_sa_t *ike_sa;
-	u_int id = 0;
+	uint32_t id = 0;

-	/* our ike_sa pointer might be invalid, lookup sa */
+	/* don't trigger events anymore while terminating SAs */
+	priv->ike_sa = NULL;
+
+	/* terminate all SAs in case e.g. a make-before-break reauthentication
+	 * is currently active */
 	enumerator = charon->controller->create_ike_sa_enumerator(
 													charon->controller, TRUE);
 	while (enumerator->enumerate(enumerator, &ike_sa))
 	{
-		if (priv->ike_sa == ike_sa)
-		{
-			id = ike_sa->get_unique_id(ike_sa);
-			break;
-		}
+		id = ike_sa->get_unique_id(ike_sa);
+		array_insert_create_value(&ids, sizeof(id), ARRAY_TAIL, &id);
 	}
 	enumerator->destroy(enumerator);

-	if (id)
+	while (array_remove(ids, ARRAY_HEAD, &id))
 	{
-		charon->controller->terminate_ike(charon->controller, id, FALSE,
+		charon->controller->terminate_ike(charon->controller, id, TRUE,
 									controller_cb_empty, NULL, LEVEL_SILENT, 0);
 	}
-	else
-	{
-		g_debug("Connection not found.");
-	}
+	array_destroy(ids);

 	/* clear secrets as we are asked for new secrets (where we'd find the cached
 	 * secrets from earlier connections) before we clear them in connect() */