From f67199378df96b330ec5dbf35abd44a0cfb5efa1 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Tue, 31 May 2016 14:41:19 +0200 Subject: [PATCH] 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. --- src/libcharon/sa/ikev2/tasks/ike_rekey.c | 42 +++++++++++++++--------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/src/libcharon/sa/ikev2/tasks/ike_rekey.c b/src/libcharon/sa/ikev2/tasks/ike_rekey.c index d7f81e1de2..dadf872df0 100644 --- a/src/libcharon/sa/ikev2/tasks/ike_rekey.c +++ b/src/libcharon/sa/ikev2/tasks/ike_rekey.c @@ -261,6 +261,28 @@ METHOD(task_t, build_r, status_t, 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, 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)); 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)) { case FAILED: /* rekeying failed, fallback to old SA */ - if (!this->collision || - this->collision->get_type(this->collision) != TASK_IKE_DELETE) + if (!conclude_undetected_collision(this)) { schedule_delayed_rekey(this); } @@ -385,15 +401,9 @@ METHOD(ike_rekey_t, collide, void, switch (other->get_type(other)) { case TASK_IKE_DELETE: - if (this->collision && - this->collision->get_type(this->collision) == TASK_IKE_REKEY) - { - DBG1(DBG_IKE, "peer did not notice IKE_SA rekey collision"); - other->destroy(other); - establish_new((private_ike_rekey_t*)this->collision); - return; - } - break; + conclude_undetected_collision(this); + other->destroy(other); + return; case TASK_IKE_REKEY: { private_ike_rekey_t *rekey = (private_ike_rekey_t*)other; -- 2.47.2