child-delete: Check if the deleted CHILD_SA is the redundant SA of a collision

This happens if the peer deletes the redundant SA before we are able to
handle the response. The deleted SA will be in state CHILD_INSTALLED but
we don't want to trigger the child_updown() event for it or recreate it.
This commit is contained in:
Tobias Brunner
2016-06-17 18:48:04 +02:00
parent 4f1012b3e1
commit 7a23226c32
+39 -4
View File
@@ -1,6 +1,7 @@
/* /*
* Copyright (C) 2009-2016 Tobias Brunner
* Copyright (C) 2006-2007 Martin Willi * Copyright (C) 2006-2007 Martin Willi
* Hochschule fuer Technik Rapperswil * HSR Hochschule fuer Technik Rapperswil
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the * under the terms of the GNU General Public License as published by the
@@ -18,7 +19,7 @@
#include <daemon.h> #include <daemon.h>
#include <encoding/payloads/delete_payload.h> #include <encoding/payloads/delete_payload.h>
#include <sa/ikev2/tasks/child_create.h> #include <sa/ikev2/tasks/child_create.h>
#include <sa/ikev2/tasks/child_rekey.h>
typedef struct private_child_delete_t private_child_delete_t; typedef struct private_child_delete_t private_child_delete_t;
@@ -118,6 +119,33 @@ static void build_payloads(private_child_delete_t *this, message_t *message)
enumerator->destroy(enumerator); enumerator->destroy(enumerator);
} }
/**
* Check if the given CHILD_SA is the redundant SA created in a rekey collision.
*/
static bool is_redundant(private_child_delete_t *this, child_sa_t *child)
{
enumerator_t *tasks;
task_t *task;
tasks = this->ike_sa->create_task_enumerator(this->ike_sa,
TASK_QUEUE_ACTIVE);
while (tasks->enumerate(tasks, &task))
{
if (task->get_type(task) == TASK_CHILD_REKEY)
{
child_rekey_t *rekey = (child_rekey_t*)task;
if (rekey->is_redundant(rekey, child))
{
tasks->destroy(tasks);
return TRUE;
}
}
}
tasks->destroy(tasks);
return FALSE;
}
/** /**
* read in payloads and find the children to delete * read in payloads and find the children to delete
*/ */
@@ -171,8 +199,15 @@ static void process_payloads(private_child_delete_t *this, message_t *message)
/* we reply as usual, rekeying will fail */ /* we reply as usual, rekeying will fail */
case CHILD_INSTALLED: case CHILD_INSTALLED:
if (!this->initiator) if (!this->initiator)
{ /* reestablish installed children if required */ {
this->check_delete_action = TRUE; if (is_redundant(this, child_sa))
{
this->rekeyed = TRUE;
}
else
{
this->check_delete_action = TRUE;
}
} }
break; break;
default: default: