ike-rekey: Handle undetected collisions also if delete is delayed
If the peer does not detect the rekey collision and deletes the old IKE_SA and then receives the colliding rekey request it will respond with TEMPORARY_FAILURE. That notify may arrive before the DELETE does, in which case we may just conclude the rekeying initiated by the peer. Also, since the IKE_SA is destroyed in any case when we receive a delete there is no point in storing the delete task in collide() as process_i() in the ike-rekey task will never be called.
This commit is contained in:
@@ -261,6 +261,28 @@ METHOD(task_t, build_r, status_t,
|
|||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Conclude any undetected rekey collision.
|
||||||
|
*
|
||||||
|
* If the peer does not detect the collision it will delete this IKE_SA.
|
||||||
|
* Depending on when our request reaches the peer and we receive the delete
|
||||||
|
* this may get called at different times.
|
||||||
|
*
|
||||||
|
* Returns TRUE if there was a collision, FALSE otherwise.
|
||||||
|
*/
|
||||||
|
static bool conclude_undetected_collision(private_ike_rekey_t *this)
|
||||||
|
{
|
||||||
|
if (this->collision &&
|
||||||
|
this->collision->get_type(this->collision) == TASK_IKE_REKEY)
|
||||||
|
{
|
||||||
|
DBG1(DBG_IKE, "peer did not notice IKE_SA rekey collision, abort "
|
||||||
|
"active rekeying");
|
||||||
|
establish_new((private_ike_rekey_t*)this->collision);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
METHOD(task_t, process_i, status_t,
|
METHOD(task_t, process_i, status_t,
|
||||||
private_ike_rekey_t *this, message_t *message)
|
private_ike_rekey_t *this, message_t *message)
|
||||||
{
|
{
|
||||||
@@ -274,18 +296,12 @@ METHOD(task_t, process_i, status_t,
|
|||||||
this->ike_sa->get_id(this->ike_sa), TRUE));
|
this->ike_sa->get_id(this->ike_sa), TRUE));
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
}
|
}
|
||||||
if (message->get_notify(message, TEMPORARY_FAILURE))
|
|
||||||
{
|
|
||||||
schedule_delayed_rekey(this);
|
|
||||||
return SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (this->ike_init->task.process(&this->ike_init->task, message))
|
switch (this->ike_init->task.process(&this->ike_init->task, message))
|
||||||
{
|
{
|
||||||
case FAILED:
|
case FAILED:
|
||||||
/* rekeying failed, fallback to old SA */
|
/* rekeying failed, fallback to old SA */
|
||||||
if (!this->collision ||
|
if (!conclude_undetected_collision(this))
|
||||||
this->collision->get_type(this->collision) != TASK_IKE_DELETE)
|
|
||||||
{
|
{
|
||||||
schedule_delayed_rekey(this);
|
schedule_delayed_rekey(this);
|
||||||
}
|
}
|
||||||
@@ -385,15 +401,9 @@ METHOD(ike_rekey_t, collide, void,
|
|||||||
switch (other->get_type(other))
|
switch (other->get_type(other))
|
||||||
{
|
{
|
||||||
case TASK_IKE_DELETE:
|
case TASK_IKE_DELETE:
|
||||||
if (this->collision &&
|
conclude_undetected_collision(this);
|
||||||
this->collision->get_type(this->collision) == TASK_IKE_REKEY)
|
other->destroy(other);
|
||||||
{
|
return;
|
||||||
DBG1(DBG_IKE, "peer did not notice IKE_SA rekey collision");
|
|
||||||
other->destroy(other);
|
|
||||||
establish_new((private_ike_rekey_t*)this->collision);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case TASK_IKE_REKEY:
|
case TASK_IKE_REKEY:
|
||||||
{
|
{
|
||||||
private_ike_rekey_t *rekey = (private_ike_rekey_t*)other;
|
private_ike_rekey_t *rekey = (private_ike_rekey_t*)other;
|
||||||
|
|||||||
Reference in New Issue
Block a user