From: Tobias Brunner Date: Fri, 6 Dec 2024 14:02:13 +0000 (+0100) Subject: ha: Destroy incomplete IKE_SAs after de-/activating a segment X-Git-Tag: 6.0.1rc1~11^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=97bd0e2297ed1df69337188168b338ed404b64e0;p=thirdparty%2Fstrongswan.git ha: Destroy incomplete IKE_SAs after de-/activating a segment The node that gets activated usually won't be able to complete the IKE_SA mainly because the IKE keys are now derived delayed, so the key material required to process a message often won't be available (only later IKE_AUTH messages and retransmits of earlier messages that the active node already received and synced the keys for may be decrypted). A second issue affects IKE_SAs with multiple key exchanges. Because the IntAuth value(s) are currently not synced, which are necessary to verify/create the AUTH payloads, the IKE_AUTH exchange couldn't be completed. --- diff --git a/src/libcharon/plugins/ha/ha_segments.c b/src/libcharon/plugins/ha/ha_segments.c index 996b2483e9..afb76b39ea 100644 --- a/src/libcharon/plugins/ha/ha_segments.c +++ b/src/libcharon/plugins/ha/ha_segments.c @@ -135,9 +135,11 @@ static void enable_disable(private_ha_segments_t *this, u_int segment, { ike_sa_t *ike_sa; enumerator_t *enumerator; - ike_sa_state_t old, new; + ike_sa_state_t old, new, cur; ha_message_t *message = NULL; ha_message_type_t type; + array_t *to_destroy; + uint32_t unique_id; bool changes = FALSE; if (segment > this->count) @@ -172,11 +174,13 @@ static void enable_disable(private_ha_segments_t *this, u_int segment, if (changes) { + to_destroy = array_create(sizeof(u_int), 0); enumerator = charon->ike_sa_manager->create_enumerator( charon->ike_sa_manager, TRUE); while (enumerator->enumerate(enumerator, &ike_sa)) { - if (ike_sa->get_state(ike_sa) != old) + cur = ike_sa->get_state(ike_sa); + if (cur != old && cur != IKE_CONNECTING) { continue; } @@ -187,11 +191,34 @@ static void enable_disable(private_ha_segments_t *this, u_int segment, if (this->kernel->get_segment(this->kernel, ike_sa->get_other_host(ike_sa)) == segment) { - ike_sa->set_state(ike_sa, new); + if (cur == IKE_CONNECTING) + { + unique_id = ike_sa->get_unique_id(ike_sa); + array_insert(to_destroy, ARRAY_TAIL, &unique_id); + } + else + { + ike_sa->set_state(ike_sa, new); + } } } enumerator->destroy(enumerator); log_segments(this, enable, segment); + + while (array_remove(to_destroy, ARRAY_HEAD, &unique_id)) + { + ike_sa = charon->ike_sa_manager->checkout_by_id(charon->ike_sa_manager, + unique_id); + if (ike_sa) + { + DBG1(DBG_IKE, "destroying incomplete IKE_SA %s[%d] after " + "%sactivating HA segment %d", ike_sa->get_name(ike_sa), + unique_id, segment, enable ? "" : "de"); + charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, + ike_sa); + } + } + array_destroy(to_destroy); } if (notify)