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.
This commit is contained in:
Tobias Brunner 2024-12-06 15:02:13 +01:00
parent fd6ac87fc3
commit 97bd0e2297

View File

@ -135,9 +135,11 @@ static void enable_disable(private_ha_segments_t *this, u_int segment,
{ {
ike_sa_t *ike_sa; ike_sa_t *ike_sa;
enumerator_t *enumerator; enumerator_t *enumerator;
ike_sa_state_t old, new; ike_sa_state_t old, new, cur;
ha_message_t *message = NULL; ha_message_t *message = NULL;
ha_message_type_t type; ha_message_type_t type;
array_t *to_destroy;
uint32_t unique_id;
bool changes = FALSE; bool changes = FALSE;
if (segment > this->count) if (segment > this->count)
@ -172,11 +174,13 @@ static void enable_disable(private_ha_segments_t *this, u_int segment,
if (changes) if (changes)
{ {
to_destroy = array_create(sizeof(u_int), 0);
enumerator = charon->ike_sa_manager->create_enumerator( enumerator = charon->ike_sa_manager->create_enumerator(
charon->ike_sa_manager, TRUE); charon->ike_sa_manager, TRUE);
while (enumerator->enumerate(enumerator, &ike_sa)) 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; continue;
} }
@ -186,12 +190,35 @@ static void enable_disable(private_ha_segments_t *this, u_int segment,
} }
if (this->kernel->get_segment(this->kernel, if (this->kernel->get_segment(this->kernel,
ike_sa->get_other_host(ike_sa)) == segment) ike_sa->get_other_host(ike_sa)) == segment)
{
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); ike_sa->set_state(ike_sa, new);
} }
} }
}
enumerator->destroy(enumerator); enumerator->destroy(enumerator);
log_segments(this, enable, segment); 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) if (notify)