Commit b3ef007d28 for strongswan.org

commit b3ef007d28bc92929753079d75d8f7331a1e0da4
Author: Tobias Brunner <tobias@strongswan.org>
Date:   Wed May 27 08:27:15 2026 +0200

    vici: Return proposals in a more structured way

    This allows clients to distinguish between algorithms of different
    transform types more easily.  The names are similar to those used
    when returning the algorithms of the selected proposal in list-sas (except
    for `ke` instead of `dh` and `sn` instead of `esn` to reflect the
    latest IETF/IANA changes).

diff --git a/src/libcharon/plugins/vici/README.md b/src/libcharon/plugins/vici/README.md
index aeb2832d9d..925aca24d0 100644
--- a/src/libcharon/plugins/vici/README.md
+++ b/src/libcharon/plugins/vici/README.md
@@ -893,9 +893,18 @@ _list-conns_ command.
 			version = <IKE version as string, IKEv1|IKEv2 or 0 for any>
 			reauth_time = <IKE_SA reauthentication interval in seconds>
 			rekey_time = <IKE_SA rekeying interval in seconds>
-			proposals = [
-				<list of configured IKE proposals>
-			]
+			proposals = { # numbered (zero-based) sub-sections for IKE proposal
+				<num> = { # lists with NAME[_KEYSIZE] for each transform type in proposal
+					encr = [ <list of encryption algorithms> ]
+					integ = [ <list of integrity algorithms> ]
+					prf = [ <list of pseudo random functions> ]
+					ke = [ <list of key exchange methods> ]
+					ake1 = [ <list of first additional key exchange methods> ]
+					...
+					ake7 = [ <list fo seventh additional key exchange methods> ]
+					sn = [ <list of sequence number transforms> ]
+				}
+			}
 			local*, remote* = { # multiple local and remote auth sections
 				class = <authentication type>
 				eap-type = <EAP type to authenticate if when using EAP>
@@ -923,12 +932,12 @@ _list-conns_ command.
 					rekey_time = <CHILD_SA rekeying interval in seconds>
 					rekey_bytes = <CHILD_SA rekeying interval in bytes>
 					rekey_packets = <CHILD_SA rekeying interval in packets>
-					esp_proposals = [
-						<list of configured ESP proposals>
-					]
-					ah_proposals = [
-						<list of configured AH proposals>
-					]
+					esp_proposals = {
+						<sub-sections for ESP proposals, see above for details>
+					}
+					ah_proposals = {
+						<sub-sections for AH proposals, see above for details>
+					}
 					local-ts = [
 						<list of local traffic selectors>
 					]
diff --git a/src/libcharon/plugins/vici/vici_query.c b/src/libcharon/plugins/vici/vici_query.c
index a2ea5bc1f9..b5c84d4a98 100644
--- a/src/libcharon/plugins/vici/vici_query.c
+++ b/src/libcharon/plugins/vici/vici_query.c
@@ -208,6 +208,43 @@ static void list_label(vici_builder_t *b, child_sa_t *child, child_cfg_t *cfg)
 	}
 }

+/**
+ * Print all algorithms of the given type
+ */
+static void list_transforms(vici_builder_t *b, proposal_t *proposal, char *name,
+							transform_type_t type)
+{
+	enumerator_t *enumerator;
+	enum_name_t *names;
+	char buf[BUF_LEN];
+	uint16_t alg, ks;
+	bool first = TRUE;
+
+	names = transform_get_enum_names(type);
+
+	enumerator = proposal->create_enumerator(proposal, type);
+	while (enumerator->enumerate(enumerator, &alg, &ks))
+	{
+		if (first)
+		{
+			b->begin_list(b, name);
+			first = FALSE;
+		}
+		buf[0] = '\0';
+		if (ks)
+		{
+			snprintf(buf, sizeof(buf), "_%u", ks);
+		}
+		b->add_li(b, "%N%s", names, alg, buf);
+	}
+	enumerator->destroy(enumerator);
+
+	if (!first)
+	{
+		b->end_list(b);
+	}
+}
+
 /**
  * List proposals for a config
  */
@@ -216,18 +253,34 @@ static void list_proposals(vici_builder_t *b, linked_list_t *proposals,
 {
 	enumerator_t *enumerator;
 	proposal_t *proposal;
+	char buf[BUF_LEN];
+	u_int num = 0;

-	b->begin_list(b, label);
+	b->begin_section(b, label);
 	enumerator = proposals->create_enumerator(proposals);
 	while (enumerator->enumerate(enumerator, &proposal))
 	{
 		if (proposal->get_protocol(proposal) == protocol)
 		{
-			b->add_li(b, "%P", proposal);
+			snprintf(buf, sizeof(buf), "%u", num++);
+			b->begin_section(b, buf);
+			list_transforms(b, proposal, "encr", ENCRYPTION_ALGORITHM);
+			list_transforms(b, proposal, "integ", INTEGRITY_ALGORITHM);
+			list_transforms(b, proposal, "prf", PSEUDO_RANDOM_FUNCTION);
+			list_transforms(b, proposal, "ke", KEY_EXCHANGE_METHOD);
+			list_transforms(b, proposal, "ake1", ADDITIONAL_KEY_EXCHANGE_1);
+			list_transforms(b, proposal, "ake2", ADDITIONAL_KEY_EXCHANGE_2);
+			list_transforms(b, proposal, "ake3", ADDITIONAL_KEY_EXCHANGE_3);
+			list_transforms(b, proposal, "ake4", ADDITIONAL_KEY_EXCHANGE_4);
+			list_transforms(b, proposal, "ake5", ADDITIONAL_KEY_EXCHANGE_5);
+			list_transforms(b, proposal, "ake6", ADDITIONAL_KEY_EXCHANGE_6);
+			list_transforms(b, proposal, "ake7", ADDITIONAL_KEY_EXCHANGE_7);
+			list_transforms(b, proposal, "sn", EXTENDED_SEQUENCE_NUMBERS);
+			b->end_section(b);
 		}
 	}
 	enumerator->destroy(enumerator);
-	b->end_list(b);
+	b->end_section(b);
 }

 /**