child-delete: Don't send delete for expired CHILD_SAs that were already rekeyed

The peer might not have seen the CREATE_CHILD_SA response yet, receiving a
DELETE for the SA could then trigger it to abort the rekeying, causing
the deletion of the newly established SA (it can't know whether the
DELETE was sent due to an expire or because the user manually deleted
it).  We just treat this SA as if we received a DELETE for it.  This is
not an ideal situation anyway, as it causes some traffic to get dropped,
so it should usually be avoided by setting appropriate soft and hard limits.

References #2815.
This commit is contained in:
Tobias Brunner
2018-11-22 11:31:53 +01:00
parent a9b9450c54
commit ecba84a06b
2 changed files with 32 additions and 38 deletions
+18 -6
View File
@@ -174,6 +174,11 @@ static void install_outbound(private_child_delete_t *this,
linked_list_t *my_ts, *other_ts;
status_t status;
if (!spi)
{
return;
}
child_sa = this->ike_sa->get_child_sa(this->ike_sa, protocol,
spi, FALSE);
if (!child_sa)
@@ -312,7 +317,7 @@ static status_t destroy_and_reestablish(private_child_delete_t *this)
child_sa_t *child_sa;
child_cfg_t *child_cfg;
protocol_id_t protocol;
uint32_t spi, reqid, rekey_spi;
uint32_t spi, reqid;
action_t action;
status_t status = SUCCESS;
time_t now, expire;
@@ -335,11 +340,7 @@ static status_t destroy_and_reestablish(private_child_delete_t *this)
}
else
{
rekey_spi = child_sa->get_rekey_spi(child_sa);
if (rekey_spi)
{
install_outbound(this, protocol, rekey_spi);
}
install_outbound(this, protocol, child_sa->get_rekey_spi(child_sa));
/* for rekeyed CHILD_SAs we uninstall the outbound SA but don't
* immediately destroy it, by default, so we can process delayed
* packets */
@@ -459,6 +460,17 @@ METHOD(task_t, build_i, status_t,
this->spi = child_sa->get_spi(child_sa, TRUE);
}
if (this->expired && child_sa->get_state(child_sa) == CHILD_REKEYED)
{ /* the peer was expected to delete this SA, but if we send a DELETE
* we might cause a collision there if the CREATE_CHILD_SA response
* is delayed (the peer wouldn't know if we deleted this SA due to an
* expire or because of a forced delete by the user and might then
* ignore the CREATE_CHILD_SA response once it arrives) */
child_sa->set_state(child_sa, CHILD_DELETED);
install_outbound(this, this->protocol,
child_sa->get_rekey_spi(child_sa));
}
if (child_sa->get_state(child_sa) == CHILD_DELETED)
{ /* DELETEs for this CHILD_SA were already exchanged, but it was not yet
* destroyed to allow delayed packets to get processed */