bus: Prevent redundant down event on rekeyed CHILD_SA delete timeout
If a CHILD_SA is rekeyed using a CREATE_CHILD_SA request, a subsequent
DELETE for the old CHILD_SA may time out. Before sending this DELETE,
a CHILD_REKEYED state CHILD_SA set from child_rekey::process_i() is
immediately set to CHILD_DELETING from child_delete::build_i(). If the
IKE_SA dies due to a retransmission timeout of this DELETE, a redundant
child-down event is issued for the rekeyed CHILD_SA that has already seen a
child-rekey event.
A reproducer shows the following log and events:
[CFG] vici rekey CHILD_SA #533
[IKE] establishing CHILD_SA XXX{534} reqid 20
[ENC] generating CREATE_CHILD_SA request 0 [ N(REKEY_SA) SA No KE TSi TSr ]
[ENC] parsed CREATE_CHILD_SA response 0 [ SA No TSi TSr ]
[IKE] rekeyed CHILD_SA XXX{533} with SPIs ca997de6_i cd27d4fe_o with XXX{534} with SPIs ced1cd01_i c460a7c9_o
Event: child-rekey
[OLD SA] state: REKEYING, spi-in: ca997de6
[NEW SA] state: INSTALLED, spi-in: ced1cd01
[IKE] closing CHILD_SA XXX{533} with SPIs ca997de6_i (352 bytes) cd27d4fe_o (264 bytes) and TS 0.0.0.0/0 === 10.11.9.40/29
[IKE] sending DELETE for ESP CHILD_SA with SPI ca997de6
[ENC] generating INFORMATIONAL request 1 [ D ]
[IKE] retransmit 1 of request with message ID 1
[IKE] retransmit 2 of request with message ID 1
[IKE] retransmit 3 of request with message ID 1
[IKE] retransmit 4 of request with message ID 1
[IKE] giving up after 4 retransmits
Event: child-updown
[SA] state: DELETING, spi-in: ca997de6
Event: child-updown
[SA] state: INSTALLED, spi-in: ced1cd01
To prevent the redundant child-down event for the successfully rekeyed CHILD_SA,
check if a DELETING CHILD_SA has already removed its outbound state due to
having been rekeyed before issuing the child-down event.
Add a new exchange test exercising that a delete timeout after rekeying does
not cause a duplicate child-down event.
This commit is contained in:
1 parent
dba2c9935a
commit
3df3af8eb7
2 files changed
+74
-3
No files matched your search
+15
-3
@@ -830,11 +830,23 @@ METHOD(bus_t, ike_updown, void,
|
||||
enumerator = ike_sa->create_child_sa_enumerator(ike_sa);
|
||||
while (enumerator->enumerate(enumerator, (void**)&child_sa))
|
||||
{
|
||||
if (child_sa->get_state(child_sa) != CHILD_REKEYED &&
|
||||
child_sa->get_state(child_sa) != CHILD_DELETED)
|
||||
switch (child_sa->get_state(child_sa))
|
||||
{
|
||||
child_updown(this, child_sa, FALSE);
|
||||
case CHILD_REKEYED:
|
||||
case CHILD_DELETED:
|
||||
continue;
|
||||
case CHILD_DELETING:
|
||||
if (child_sa->get_outbound_state(child_sa) ==
|
||||
CHILD_OUTBOUND_NONE)
|
||||
{
|
||||
/* deleting CHILD_SA has been rekeyed, omit event */
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
child_updown(this, child_sa, FALSE);
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user