From 60adb95f580bb37b127a4f0bbd476ec2df60286e Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Thu, 21 May 2026 17:14:31 +0200 Subject: [PATCH 1/4] child-cfg: Add flag to suppress log message when retrieving proposals --- src/libcharon/config/child_cfg.c | 8 +++++--- src/libcharon/config/child_cfg.h | 3 ++- src/libcharon/sa/ikev1/tasks/quick_mode.c | 4 ++-- src/libcharon/sa/ikev2/tasks/child_create.c | 4 ++-- src/libcharon/sa/trap_manager.c | 2 +- 5 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/libcharon/config/child_cfg.c b/src/libcharon/config/child_cfg.c index 3e18a4af2..e1e2778a7 100644 --- a/src/libcharon/config/child_cfg.c +++ b/src/libcharon/config/child_cfg.c @@ -216,7 +216,7 @@ CALLBACK(match_proposal, bool, } METHOD(child_cfg_t, get_proposals, linked_list_t*, - private_child_cfg_t *this, bool strip_ke) + private_child_cfg_t *this, bool strip_ke, bool log) { enumerator_t *enumerator; proposal_t *current; @@ -241,8 +241,10 @@ METHOD(child_cfg_t, get_proposals, linked_list_t*, } enumerator->destroy(enumerator); - DBG2(DBG_CFG, "configured proposals: %#P", proposals); - + if (log) + { + DBG2(DBG_CFG, "configured proposals: %#P", proposals); + } return proposals; } diff --git a/src/libcharon/config/child_cfg.h b/src/libcharon/config/child_cfg.h index 258af040a..bdeebca4c 100644 --- a/src/libcharon/config/child_cfg.h +++ b/src/libcharon/config/child_cfg.h @@ -91,9 +91,10 @@ struct child_cfg_t { * Resulting list and all of its proposals must be freed after use. * * @param strip_ke TRUE strip out key exchange methods + * @param log whether to log the configured proposals * @return list of proposals */ - linked_list_t* (*get_proposals)(child_cfg_t *this, bool strip_ke); + linked_list_t* (*get_proposals)(child_cfg_t *this, bool strip_ke, bool log); /** * Select a proposal from a supplied list. diff --git a/src/libcharon/sa/ikev1/tasks/quick_mode.c b/src/libcharon/sa/ikev1/tasks/quick_mode.c index 8c06db523..bafe46af0 100644 --- a/src/libcharon/sa/ikev1/tasks/quick_mode.c +++ b/src/libcharon/sa/ikev1/tasks/quick_mode.c @@ -802,7 +802,7 @@ static linked_list_t *get_proposals(private_quick_mode_t *this, proposal_t *proposal; enumerator_t *enumerator; - list = this->config->get_proposals(this->config, FALSE); + list = this->config->get_proposals(this->config, FALSE, TRUE); enumerator = list->create_enumerator(list); while (enumerator->enumerate(enumerator, &proposal)) { @@ -864,7 +864,7 @@ METHOD(task_t, build_i, status_t, } } - list = this->config->get_proposals(this->config, FALSE); + list = this->config->get_proposals(this->config, FALSE, TRUE); if (list->get_first(list, (void**)&proposal) == SUCCESS) { this->proto = proposal->get_protocol(proposal); diff --git a/src/libcharon/sa/ikev2/tasks/child_create.c b/src/libcharon/sa/ikev2/tasks/child_create.c index 149808ee2..13ea7be47 100644 --- a/src/libcharon/sa/ikev2/tasks/child_create.c +++ b/src/libcharon/sa/ikev2/tasks/child_create.c @@ -1768,7 +1768,7 @@ METHOD(task_t, build_i, status_t, OPT_PER_CPU_SAS); } - this->proposals = this->config->get_proposals(this->config, no_ke); + this->proposals = this->config->get_proposals(this->config, no_ke, TRUE); this->mode = this->config->get_mode(this->config); this->child.if_id_in_def = this->ike_sa->get_if_id(this->ike_sa, TRUE); @@ -2486,7 +2486,7 @@ static void raise_alerts(private_child_create_t *this, notify_type_t type) switch (type) { case NO_PROPOSAL_CHOSEN: - list = this->config->get_proposals(this->config, FALSE); + list = this->config->get_proposals(this->config, FALSE, FALSE); charon->bus->alert(charon->bus, ALERT_PROPOSAL_MISMATCH_CHILD, list); list->destroy_offset(list, offsetof(proposal_t, destroy)); break; diff --git a/src/libcharon/sa/trap_manager.c b/src/libcharon/sa/trap_manager.c index 90a29b29b..9a4f08d07 100644 --- a/src/libcharon/sa/trap_manager.c +++ b/src/libcharon/sa/trap_manager.c @@ -219,7 +219,7 @@ static status_t install_trap(child_sa_t *child_sa, linked_list_t *local, /* we don't know the finally negotiated protocol (ESP|AH), we install * the SA with the protocol of the first proposal */ - proposals = child->get_proposals(child, TRUE); + proposals = child->get_proposals(child, TRUE, FALSE); if (proposals->get_first(proposals, (void**)&proposal) == SUCCESS) { proto = proposal->get_protocol(proposal); From eb9e44f783b685f98ba01eac80739ab36531a326 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Thu, 21 May 2026 17:16:09 +0200 Subject: [PATCH 2/4] ike-cfg: Add flag to suppress log message when retrieving proposals --- src/libcharon/config/ike_cfg.c | 8 +++++--- src/libcharon/config/ike_cfg.h | 3 ++- src/libcharon/sa/ikev1/tasks/aggressive_mode.c | 2 +- src/libcharon/sa/ikev1/tasks/main_mode.c | 2 +- src/libcharon/sa/ikev2/tasks/ike_init.c | 4 ++-- 5 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/libcharon/config/ike_cfg.c b/src/libcharon/config/ike_cfg.c index 5d73157b0..44bccd5f5 100644 --- a/src/libcharon/config/ike_cfg.c +++ b/src/libcharon/config/ike_cfg.c @@ -318,7 +318,7 @@ METHOD(ike_cfg_t, add_proposal, void, } METHOD(ike_cfg_t, get_proposals, linked_list_t*, - private_ike_cfg_t *this) + private_ike_cfg_t *this, bool log) { enumerator_t *enumerator; proposal_t *current; @@ -333,8 +333,10 @@ METHOD(ike_cfg_t, get_proposals, linked_list_t*, } enumerator->destroy(enumerator); - DBG2(DBG_CFG, "configured proposals: %#P", proposals); - + if (log) + { + DBG2(DBG_CFG, "configured proposals: %#P", proposals); + } return proposals; } diff --git a/src/libcharon/config/ike_cfg.h b/src/libcharon/config/ike_cfg.h index 9c1581576..200ee0729 100644 --- a/src/libcharon/config/ike_cfg.h +++ b/src/libcharon/config/ike_cfg.h @@ -178,9 +178,10 @@ struct ike_cfg_t { * * Returned list and its proposals must be destroyed after use. * + * @param log whether to log the configured proposals * @return list containing all the proposals */ - linked_list_t* (*get_proposals) (ike_cfg_t *this); + linked_list_t *(*get_proposals)(ike_cfg_t *this, bool log); /** * Select a proposal from a list of supplied proposals. diff --git a/src/libcharon/sa/ikev1/tasks/aggressive_mode.c b/src/libcharon/sa/ikev1/tasks/aggressive_mode.c index d86c95178..681c8a12f 100644 --- a/src/libcharon/sa/ikev1/tasks/aggressive_mode.c +++ b/src/libcharon/sa/ikev1/tasks/aggressive_mode.c @@ -240,7 +240,7 @@ METHOD(task_t, build_i, status_t, FALSE); } this->lifetime += this->peer_cfg->get_over_time(this->peer_cfg); - proposals = ike_cfg->get_proposals(ike_cfg); + proposals = ike_cfg->get_proposals(ike_cfg, TRUE); sa_payload = sa_payload_create_from_proposals_v1(proposals, this->lifetime, 0, this->method, MODE_NONE, ENCAP_NONE, 0); diff --git a/src/libcharon/sa/ikev1/tasks/main_mode.c b/src/libcharon/sa/ikev1/tasks/main_mode.c index e8ddff9ab..936e05c36 100644 --- a/src/libcharon/sa/ikev1/tasks/main_mode.c +++ b/src/libcharon/sa/ikev1/tasks/main_mode.c @@ -271,7 +271,7 @@ METHOD(task_t, build_i, status_t, FALSE); } this->lifetime += this->peer_cfg->get_over_time(this->peer_cfg); - proposals = ike_cfg->get_proposals(ike_cfg); + proposals = ike_cfg->get_proposals(ike_cfg, TRUE); sa_payload = sa_payload_create_from_proposals_v1(proposals, this->lifetime, 0, this->method, MODE_NONE, ENCAP_NONE, 0); diff --git a/src/libcharon/sa/ikev2/tasks/ike_init.c b/src/libcharon/sa/ikev2/tasks/ike_init.c index b7083917a..a28996225 100644 --- a/src/libcharon/sa/ikev2/tasks/ike_init.c +++ b/src/libcharon/sa/ikev2/tasks/ike_init.c @@ -367,7 +367,7 @@ static bool build_payloads(private_ike_init_t *this, message_t *message) if (this->initiator) { - proposal_list = ike_cfg->get_proposals(ike_cfg); + proposal_list = ike_cfg->get_proposals(ike_cfg, TRUE); other_ke_methods = linked_list_create(); enumerator = proposal_list->create_enumerator(proposal_list); while (enumerator->enumerate(enumerator, (void**)&proposal)) @@ -1216,7 +1216,7 @@ static void raise_alerts(private_ike_init_t *this, notify_type_t type) { case NO_PROPOSAL_CHOSEN: ike_cfg = this->ike_sa->get_ike_cfg(this->ike_sa); - list = ike_cfg->get_proposals(ike_cfg); + list = ike_cfg->get_proposals(ike_cfg, FALSE); charon->bus->alert(charon->bus, ALERT_PROPOSAL_MISMATCH_IKE, list); list->destroy_offset(list, offsetof(proposal_t, destroy)); break; From c70ab8836323e3920f12d988443aba38f42cd86d Mon Sep 17 00:00:00 2001 From: Mathijs Smit Date: Wed, 20 May 2026 13:45:55 +0200 Subject: [PATCH 3/4] vici: Include proposals in connection listings Signed-off-by: Mathijs Smit --- src/libcharon/plugins/vici/README.md | 10 +++++++- src/libcharon/plugins/vici/vici_query.c | 31 +++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/src/libcharon/plugins/vici/README.md b/src/libcharon/plugins/vici/README.md index 01c3f858c..aeb2832d9 100644 --- a/src/libcharon/plugins/vici/README.md +++ b/src/libcharon/plugins/vici/README.md @@ -893,7 +893,9 @@ _list-conns_ command. version = reauth_time = rekey_time = - + proposals = [ + + ] local*, remote* = { # multiple local and remote auth sections class = eap-type = @@ -921,6 +923,12 @@ _list-conns_ command. rekey_time = rekey_bytes = rekey_packets = + esp_proposals = [ + + ] + ah_proposals = [ + + ] local-ts = [ ] diff --git a/src/libcharon/plugins/vici/vici_query.c b/src/libcharon/plugins/vici/vici_query.c index 98a09fa4a..a2ea5bc1f 100644 --- a/src/libcharon/plugins/vici/vici_query.c +++ b/src/libcharon/plugins/vici/vici_query.c @@ -208,6 +208,28 @@ static void list_label(vici_builder_t *b, child_sa_t *child, child_cfg_t *cfg) } } +/** + * List proposals for a config + */ +static void list_proposals(vici_builder_t *b, linked_list_t *proposals, + char *label, protocol_id_t protocol) +{ + enumerator_t *enumerator; + proposal_t *proposal; + + b->begin_list(b, label); + enumerator = proposals->create_enumerator(proposals); + while (enumerator->enumerate(enumerator, &proposal)) + { + if (proposal->get_protocol(proposal) == protocol) + { + b->add_li(b, "%P", proposal); + } + } + enumerator->destroy(enumerator); + b->end_list(b); +} + /** * List additional key exchanges */ @@ -1006,6 +1028,10 @@ CALLBACK(list_conns, vici_message_t*, b->add_kv(b, "unique", "%N", unique_policy_names, peer_cfg->get_unique_policy(peer_cfg)); + list = ike_cfg->get_proposals(ike_cfg, FALSE); + list_proposals(b, list, "proposals", PROTO_IKE); + list->destroy_offset(list, offsetof(proposal_t, destroy)); + dpd_delay = peer_cfg->get_dpd(peer_cfg); if (dpd_delay) { @@ -1052,6 +1078,11 @@ CALLBACK(list_conns, vici_message_t*, b->add_kv(b, "close_action", "%N", action_names, child_cfg->get_close_action(child_cfg)); + list = child_cfg->get_proposals(child_cfg, FALSE, FALSE); + list_proposals(b, list, "esp_proposals", PROTO_ESP); + list_proposals(b, list, "ah_proposals", PROTO_AH); + list->destroy_offset(list, offsetof(proposal_t, destroy)); + b->begin_list(b, "local-ts"); list = child_cfg->get_traffic_selectors(child_cfg, TRUE, NULL); selectors = list->create_enumerator(list); From b3ef007d28bc92929753079d75d8f7331a1e0da4 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Wed, 27 May 2026 08:27:15 +0200 Subject: [PATCH 4/4] 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). --- src/libcharon/plugins/vici/README.md | 27 +++++++---- src/libcharon/plugins/vici/vici_query.c | 59 +++++++++++++++++++++++-- 2 files changed, 74 insertions(+), 12 deletions(-) diff --git a/src/libcharon/plugins/vici/README.md b/src/libcharon/plugins/vici/README.md index aeb2832d9..925aca24d 100644 --- a/src/libcharon/plugins/vici/README.md +++ b/src/libcharon/plugins/vici/README.md @@ -893,9 +893,18 @@ _list-conns_ command. version = reauth_time = rekey_time = - proposals = [ - - ] + proposals = { # numbered (zero-based) sub-sections for IKE proposal + = { # lists with NAME[_KEYSIZE] for each transform type in proposal + encr = [ ] + integ = [ ] + prf = [ ] + ke = [ ] + ake1 = [ ] + ... + ake7 = [ ] + sn = [ ] + } + } local*, remote* = { # multiple local and remote auth sections class = eap-type = @@ -923,12 +932,12 @@ _list-conns_ command. rekey_time = rekey_bytes = rekey_packets = - esp_proposals = [ - - ] - ah_proposals = [ - - ] + esp_proposals = { + + } + ah_proposals = { + + } local-ts = [ ] diff --git a/src/libcharon/plugins/vici/vici_query.c b/src/libcharon/plugins/vici/vici_query.c index a2ea5bc1f..b5c84d4a9 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); } /**