2007-02-28 14:04:36 +00:00
|
|
|
/*
|
2016-05-25 17:12:53 +00:00
|
|
|
* Copyright (C) 2009-2016 Tobias Brunner
|
2007-02-28 14:04:36 +00:00
|
|
|
* Copyright (C) 2006-2007 Martin Willi
|
2016-05-25 17:12:53 +00:00
|
|
|
* HSR Hochschule fuer Technik Rapperswil
|
2007-02-28 14:04:36 +00:00
|
|
|
*
|
|
|
|
* 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
|
|
|
|
* Free Software Foundation; either version 2 of the License, or (at your
|
|
|
|
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful, but
|
|
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
|
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
|
|
* for more details.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "child_delete.h"
|
|
|
|
|
|
|
|
#include <daemon.h>
|
|
|
|
#include <encoding/payloads/delete_payload.h>
|
2017-03-21 15:03:54 +00:00
|
|
|
#include <processing/jobs/delete_child_sa_job.h>
|
2014-02-27 08:36:46 +00:00
|
|
|
#include <sa/ikev2/tasks/child_create.h>
|
2016-05-25 17:12:53 +00:00
|
|
|
#include <sa/ikev2/tasks/child_rekey.h>
|
2007-02-28 14:04:36 +00:00
|
|
|
|
2017-03-21 15:03:54 +00:00
|
|
|
#ifndef DELETE_REKEYED_DELAY
|
|
|
|
#define DELETE_REKEYED_DELAY 5
|
|
|
|
#endif
|
|
|
|
|
2007-02-28 14:04:36 +00:00
|
|
|
typedef struct private_child_delete_t private_child_delete_t;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Private members of a child_delete_t task.
|
|
|
|
*/
|
|
|
|
struct private_child_delete_t {
|
2009-09-04 11:46:09 +00:00
|
|
|
|
2007-02-28 14:04:36 +00:00
|
|
|
/**
|
|
|
|
* Public methods and task_t interface.
|
|
|
|
*/
|
|
|
|
child_delete_t public;
|
2009-09-04 11:46:09 +00:00
|
|
|
|
2007-02-28 14:04:36 +00:00
|
|
|
/**
|
|
|
|
* Assigned IKE_SA.
|
|
|
|
*/
|
|
|
|
ike_sa_t *ike_sa;
|
2009-09-04 11:46:09 +00:00
|
|
|
|
2007-02-28 14:04:36 +00:00
|
|
|
/**
|
2017-03-21 11:18:12 +00:00
|
|
|
* Whether we are the initiator of the exchange
|
2007-02-28 14:04:36 +00:00
|
|
|
*/
|
|
|
|
bool initiator;
|
2009-09-04 11:46:09 +00:00
|
|
|
|
2008-10-03 16:01:14 +00:00
|
|
|
/**
|
2017-03-21 11:18:12 +00:00
|
|
|
* Protocol of CHILD_SA to delete (as initiator)
|
2008-12-01 18:38:28 +00:00
|
|
|
*/
|
|
|
|
protocol_id_t protocol;
|
2009-09-04 11:46:09 +00:00
|
|
|
|
2008-12-01 18:38:28 +00:00
|
|
|
/**
|
2017-03-21 11:18:12 +00:00
|
|
|
* Inbound SPI of CHILD_SA to delete (as initiator)
|
2008-12-01 18:38:28 +00:00
|
|
|
*/
|
2016-03-22 12:22:01 +00:00
|
|
|
uint32_t spi;
|
2009-09-04 11:46:09 +00:00
|
|
|
|
2008-12-01 18:38:28 +00:00
|
|
|
/**
|
2017-03-21 11:18:12 +00:00
|
|
|
* CHILD_SA already expired (as initiator)
|
2012-01-02 14:40:31 +00:00
|
|
|
*/
|
|
|
|
bool expired;
|
|
|
|
|
2007-02-28 14:04:36 +00:00
|
|
|
/**
|
2017-03-21 11:18:12 +00:00
|
|
|
* CHILD_SAs which get deleted, entry_t*
|
2007-02-28 14:04:36 +00:00
|
|
|
*/
|
|
|
|
linked_list_t *child_sas;
|
|
|
|
};
|
|
|
|
|
2017-03-21 11:18:12 +00:00
|
|
|
/**
|
|
|
|
* Information about a deleted CHILD_SA
|
|
|
|
*/
|
|
|
|
typedef struct {
|
|
|
|
/** Deleted CHILD_SA */
|
|
|
|
child_sa_t *child_sa;
|
|
|
|
/** Whether the CHILD_SA was rekeyed */
|
|
|
|
bool rekeyed;
|
|
|
|
/** Whether to enforce any delete action policy */
|
|
|
|
bool check_delete_action;
|
|
|
|
} entry_t;
|
|
|
|
|
2017-05-16 10:11:24 +00:00
|
|
|
CALLBACK(match_child, bool,
|
|
|
|
entry_t *entry, va_list args)
|
2017-03-21 11:18:12 +00:00
|
|
|
{
|
2017-05-16 10:11:24 +00:00
|
|
|
child_sa_t *child_sa;
|
|
|
|
|
|
|
|
VA_ARGS_VGET(args, child_sa);
|
2017-03-21 11:18:12 +00:00
|
|
|
return entry->child_sa == child_sa;
|
|
|
|
}
|
|
|
|
|
2007-02-28 14:04:36 +00:00
|
|
|
/**
|
|
|
|
* build the delete payloads from the listed child_sas
|
|
|
|
*/
|
|
|
|
static void build_payloads(private_child_delete_t *this, message_t *message)
|
|
|
|
{
|
|
|
|
delete_payload_t *ah = NULL, *esp = NULL;
|
2011-05-19 14:18:30 +00:00
|
|
|
enumerator_t *enumerator;
|
2017-03-21 11:18:12 +00:00
|
|
|
entry_t *entry;
|
|
|
|
protocol_id_t protocol;
|
|
|
|
uint32_t spi;
|
2009-09-04 11:46:09 +00:00
|
|
|
|
2011-05-19 14:18:30 +00:00
|
|
|
enumerator = this->child_sas->create_enumerator(this->child_sas);
|
2017-03-21 11:18:12 +00:00
|
|
|
while (enumerator->enumerate(enumerator, (void**)&entry))
|
2009-09-04 11:46:09 +00:00
|
|
|
{
|
2017-03-21 11:18:12 +00:00
|
|
|
protocol = entry->child_sa->get_protocol(entry->child_sa);
|
|
|
|
spi = entry->child_sa->get_spi(entry->child_sa, TRUE);
|
2008-07-22 17:10:10 +00:00
|
|
|
|
|
|
|
switch (protocol)
|
2007-02-28 14:04:36 +00:00
|
|
|
{
|
|
|
|
case PROTO_ESP:
|
2017-03-21 11:18:12 +00:00
|
|
|
if (!esp)
|
2007-02-28 14:04:36 +00:00
|
|
|
{
|
2013-10-29 09:09:39 +00:00
|
|
|
esp = delete_payload_create(PLV2_DELETE, PROTO_ESP);
|
2007-02-28 14:04:36 +00:00
|
|
|
message->add_payload(message, (payload_t*)esp);
|
|
|
|
}
|
|
|
|
esp->add_spi(esp, spi);
|
2009-09-04 11:46:09 +00:00
|
|
|
DBG1(DBG_IKE, "sending DELETE for %N CHILD_SA with SPI %.8x",
|
2017-03-21 11:18:12 +00:00
|
|
|
protocol_id_names, protocol, ntohl(spi));
|
2007-02-28 14:04:36 +00:00
|
|
|
break;
|
|
|
|
case PROTO_AH:
|
|
|
|
if (ah == NULL)
|
|
|
|
{
|
2013-10-29 09:09:39 +00:00
|
|
|
ah = delete_payload_create(PLV2_DELETE, PROTO_AH);
|
2007-02-28 14:04:36 +00:00
|
|
|
message->add_payload(message, (payload_t*)ah);
|
|
|
|
}
|
|
|
|
ah->add_spi(ah, spi);
|
2009-09-04 11:46:09 +00:00
|
|
|
DBG1(DBG_IKE, "sending DELETE for %N CHILD_SA with SPI %.8x",
|
2017-03-21 11:18:12 +00:00
|
|
|
protocol_id_names, protocol, ntohl(spi));
|
2007-02-28 14:04:36 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2017-03-21 11:18:12 +00:00
|
|
|
entry->child_sa->set_state(entry->child_sa, CHILD_DELETING);
|
2007-02-28 14:04:36 +00:00
|
|
|
}
|
2011-05-19 14:18:30 +00:00
|
|
|
enumerator->destroy(enumerator);
|
2007-02-28 14:04:36 +00:00
|
|
|
}
|
|
|
|
|
2016-05-25 17:12:53 +00:00
|
|
|
/**
|
|
|
|
* 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;
|
|
|
|
}
|
|
|
|
|
2017-03-01 17:02:38 +00:00
|
|
|
/**
|
|
|
|
* Install the outbound CHILD_SA with the given SPI
|
|
|
|
*/
|
|
|
|
static void install_outbound(private_child_delete_t *this,
|
|
|
|
protocol_id_t protocol, uint32_t spi)
|
|
|
|
{
|
|
|
|
child_sa_t *child_sa;
|
|
|
|
linked_list_t *my_ts, *other_ts;
|
|
|
|
status_t status;
|
|
|
|
|
2018-11-06 11:13:35 +00:00
|
|
|
if (!spi)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-03-01 17:02:38 +00:00
|
|
|
child_sa = this->ike_sa->get_child_sa(this->ike_sa, protocol,
|
|
|
|
spi, FALSE);
|
|
|
|
if (!child_sa)
|
|
|
|
{
|
|
|
|
DBG1(DBG_IKE, "CHILD_SA not found after rekeying");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (this->initiator && is_redundant(this, child_sa))
|
|
|
|
{ /* if we won the rekey collision we don't want to install the
|
|
|
|
* redundant SA created by the peer */
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
status = child_sa->install_outbound(child_sa);
|
|
|
|
if (status != SUCCESS)
|
|
|
|
{
|
|
|
|
DBG1(DBG_IKE, "unable to install outbound IPsec SA (SAD) in kernel");
|
|
|
|
charon->bus->alert(charon->bus, ALERT_INSTALL_CHILD_SA_FAILED,
|
|
|
|
child_sa);
|
|
|
|
/* FIXME: delete the new child_sa? */
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
my_ts = linked_list_create_from_enumerator(
|
|
|
|
child_sa->create_ts_enumerator(child_sa, TRUE));
|
|
|
|
other_ts = linked_list_create_from_enumerator(
|
|
|
|
child_sa->create_ts_enumerator(child_sa, FALSE));
|
|
|
|
|
|
|
|
DBG0(DBG_IKE, "outbound CHILD_SA %s{%d} established "
|
|
|
|
"with SPIs %.8x_i %.8x_o and TS %#R === %#R",
|
|
|
|
child_sa->get_name(child_sa),
|
|
|
|
child_sa->get_unique_id(child_sa),
|
|
|
|
ntohl(child_sa->get_spi(child_sa, TRUE)),
|
|
|
|
ntohl(child_sa->get_spi(child_sa, FALSE)),
|
|
|
|
my_ts, other_ts);
|
|
|
|
|
|
|
|
my_ts->destroy(my_ts);
|
|
|
|
other_ts->destroy(other_ts);
|
|
|
|
}
|
|
|
|
|
2007-02-28 14:04:36 +00:00
|
|
|
/**
|
|
|
|
* read in payloads and find the children to delete
|
|
|
|
*/
|
|
|
|
static void process_payloads(private_child_delete_t *this, message_t *message)
|
|
|
|
{
|
2010-08-25 15:00:01 +00:00
|
|
|
enumerator_t *payloads, *spis;
|
2007-02-28 14:04:36 +00:00
|
|
|
payload_t *payload;
|
|
|
|
delete_payload_t *delete_payload;
|
2016-03-22 12:22:01 +00:00
|
|
|
uint32_t spi;
|
2007-02-28 14:04:36 +00:00
|
|
|
protocol_id_t protocol;
|
|
|
|
child_sa_t *child_sa;
|
2017-03-21 11:18:12 +00:00
|
|
|
entry_t *entry;
|
2009-09-04 11:46:09 +00:00
|
|
|
|
2009-04-14 10:34:24 +00:00
|
|
|
payloads = message->create_payload_enumerator(message);
|
|
|
|
while (payloads->enumerate(payloads, &payload))
|
2007-02-28 14:04:36 +00:00
|
|
|
{
|
2013-10-29 09:09:39 +00:00
|
|
|
if (payload->get_type(payload) == PLV2_DELETE)
|
2007-02-28 14:04:36 +00:00
|
|
|
{
|
|
|
|
delete_payload = (delete_payload_t*)payload;
|
|
|
|
protocol = delete_payload->get_protocol_id(delete_payload);
|
|
|
|
if (protocol != PROTO_ESP && protocol != PROTO_AH)
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
2010-08-25 15:00:01 +00:00
|
|
|
spis = delete_payload->create_spi_enumerator(delete_payload);
|
|
|
|
while (spis->enumerate(spis, &spi))
|
2007-02-28 14:04:36 +00:00
|
|
|
{
|
|
|
|
child_sa = this->ike_sa->get_child_sa(this->ike_sa, protocol,
|
2010-08-25 15:00:01 +00:00
|
|
|
spi, FALSE);
|
2017-03-21 11:18:12 +00:00
|
|
|
if (!child_sa)
|
2007-02-28 14:04:36 +00:00
|
|
|
{
|
2017-03-21 11:18:12 +00:00
|
|
|
DBG1(DBG_IKE, "received DELETE for unknown %N CHILD_SA with"
|
|
|
|
" SPI %.8x", protocol_id_names, protocol, ntohl(spi));
|
2007-03-20 16:13:21 +00:00
|
|
|
continue;
|
2007-02-28 14:04:36 +00:00
|
|
|
}
|
2009-09-04 11:46:09 +00:00
|
|
|
DBG1(DBG_IKE, "received DELETE for %N CHILD_SA with SPI %.8x",
|
2010-08-25 15:00:01 +00:00
|
|
|
protocol_id_names, protocol, ntohl(spi));
|
2009-09-04 11:46:09 +00:00
|
|
|
|
2017-05-16 10:11:24 +00:00
|
|
|
if (this->child_sas->find_first(this->child_sas, match_child,
|
|
|
|
NULL, child_sa))
|
2017-03-21 11:18:12 +00:00
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
INIT(entry,
|
|
|
|
.child_sa = child_sa
|
|
|
|
);
|
2007-03-20 16:13:21 +00:00
|
|
|
switch (child_sa->get_state(child_sa))
|
2007-02-28 14:04:36 +00:00
|
|
|
{
|
2016-05-20 08:49:21 +00:00
|
|
|
case CHILD_REKEYED:
|
2017-03-21 11:18:12 +00:00
|
|
|
entry->rekeyed = TRUE;
|
2007-03-20 16:13:21 +00:00
|
|
|
break;
|
2018-03-20 11:43:13 +00:00
|
|
|
case CHILD_DELETED:
|
|
|
|
/* already deleted but not yet destroyed, ignore */
|
2007-03-20 16:13:21 +00:00
|
|
|
case CHILD_DELETING:
|
2017-03-21 11:18:12 +00:00
|
|
|
/* we don't send back a delete if we already initiated
|
|
|
|
* a delete ourself */
|
2007-03-21 07:01:14 +00:00
|
|
|
if (!this->initiator)
|
|
|
|
{
|
2017-03-21 11:18:12 +00:00
|
|
|
free(entry);
|
2007-03-21 07:01:14 +00:00
|
|
|
continue;
|
|
|
|
}
|
2017-03-21 11:18:12 +00:00
|
|
|
break;
|
2016-05-20 08:49:21 +00:00
|
|
|
case CHILD_REKEYING:
|
|
|
|
/* we reply as usual, rekeying will fail */
|
2008-10-03 16:01:14 +00:00
|
|
|
case CHILD_INSTALLED:
|
|
|
|
if (!this->initiator)
|
2016-05-25 17:12:53 +00:00
|
|
|
{
|
|
|
|
if (is_redundant(this, child_sa))
|
|
|
|
{
|
2017-03-21 11:18:12 +00:00
|
|
|
entry->rekeyed = TRUE;
|
2016-05-25 17:12:53 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2017-03-21 11:18:12 +00:00
|
|
|
entry->check_delete_action = TRUE;
|
2016-05-25 17:12:53 +00:00
|
|
|
}
|
2008-10-03 16:01:14 +00:00
|
|
|
}
|
2016-05-20 08:49:21 +00:00
|
|
|
break;
|
2007-03-20 16:13:21 +00:00
|
|
|
default:
|
|
|
|
break;
|
2007-02-28 14:04:36 +00:00
|
|
|
}
|
2017-03-21 11:18:12 +00:00
|
|
|
this->child_sas->insert_last(this->child_sas, entry);
|
2007-02-28 14:04:36 +00:00
|
|
|
}
|
|
|
|
spis->destroy(spis);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
payloads->destroy(payloads);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2008-04-11 08:14:48 +00:00
|
|
|
* destroy the children listed in this->child_sas, reestablish by policy
|
2007-02-28 14:04:36 +00:00
|
|
|
*/
|
2008-04-11 08:14:48 +00:00
|
|
|
static status_t destroy_and_reestablish(private_child_delete_t *this)
|
2007-02-28 14:04:36 +00:00
|
|
|
{
|
2011-05-19 14:18:30 +00:00
|
|
|
enumerator_t *enumerator;
|
2017-03-21 11:18:12 +00:00
|
|
|
entry_t *entry;
|
2007-02-28 14:04:36 +00:00
|
|
|
child_sa_t *child_sa;
|
2008-04-11 08:14:48 +00:00
|
|
|
child_cfg_t *child_cfg;
|
2007-02-28 14:04:36 +00:00
|
|
|
protocol_id_t protocol;
|
2018-11-06 11:13:35 +00:00
|
|
|
uint32_t spi, reqid;
|
2010-06-02 09:41:46 +00:00
|
|
|
action_t action;
|
2008-04-11 08:14:48 +00:00
|
|
|
status_t status = SUCCESS;
|
2017-03-21 15:03:54 +00:00
|
|
|
time_t now, expire;
|
|
|
|
u_int delay;
|
|
|
|
|
|
|
|
now = time_monotonic(NULL);
|
|
|
|
delay = lib->settings->get_int(lib->settings, "%s.delete_rekeyed_delay",
|
|
|
|
DELETE_REKEYED_DELAY, lib->ns);
|
2009-09-04 11:46:09 +00:00
|
|
|
|
2011-05-19 14:18:30 +00:00
|
|
|
enumerator = this->child_sas->create_enumerator(this->child_sas);
|
2017-03-21 11:18:12 +00:00
|
|
|
while (enumerator->enumerate(enumerator, (void**)&entry))
|
2007-02-28 14:04:36 +00:00
|
|
|
{
|
2017-03-21 11:18:12 +00:00
|
|
|
child_sa = entry->child_sa;
|
2018-03-20 11:43:13 +00:00
|
|
|
child_sa->set_state(child_sa, CHILD_DELETED);
|
2016-05-20 08:49:21 +00:00
|
|
|
/* signal child down event if we weren't rekeying */
|
2017-03-01 17:02:38 +00:00
|
|
|
protocol = child_sa->get_protocol(child_sa);
|
2017-03-21 11:18:12 +00:00
|
|
|
if (!entry->rekeyed)
|
2009-07-09 11:35:33 +00:00
|
|
|
{
|
|
|
|
charon->bus->child_updown(charon->bus, child_sa, FALSE);
|
|
|
|
}
|
2017-03-01 17:02:38 +00:00
|
|
|
else
|
|
|
|
{
|
2018-11-06 11:13:35 +00:00
|
|
|
install_outbound(this, protocol, child_sa->get_rekey_spi(child_sa));
|
2017-03-21 15:03:54 +00:00
|
|
|
/* for rekeyed CHILD_SAs we uninstall the outbound SA but don't
|
|
|
|
* immediately destroy it, by default, so we can process delayed
|
|
|
|
* packets */
|
|
|
|
child_sa->remove_outbound(child_sa);
|
|
|
|
expire = child_sa->get_lifetime(child_sa, TRUE);
|
|
|
|
if (delay && (!expire || ((now + delay) < expire)))
|
|
|
|
{
|
|
|
|
lib->scheduler->schedule_job(lib->scheduler,
|
|
|
|
(job_t*)delete_child_sa_job_create_id(
|
|
|
|
child_sa->get_unique_id(child_sa)), delay);
|
|
|
|
continue;
|
|
|
|
}
|
2017-09-04 16:11:39 +00:00
|
|
|
else if (now < expire)
|
2017-03-21 15:03:54 +00:00
|
|
|
{ /* let it expire naturally */
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
/* no delay and no lifetime, destroy it immediately */
|
2017-03-01 17:02:38 +00:00
|
|
|
}
|
2007-02-28 14:04:36 +00:00
|
|
|
spi = child_sa->get_spi(child_sa, TRUE);
|
2013-08-13 08:03:54 +00:00
|
|
|
reqid = child_sa->get_reqid(child_sa);
|
2008-04-11 08:14:48 +00:00
|
|
|
child_cfg = child_sa->get_config(child_sa);
|
|
|
|
child_cfg->get_ref(child_cfg);
|
2010-06-02 09:41:46 +00:00
|
|
|
action = child_sa->get_close_action(child_sa);
|
2017-03-21 15:03:54 +00:00
|
|
|
|
2007-02-28 14:04:36 +00:00
|
|
|
this->ike_sa->destroy_child_sa(this->ike_sa, protocol, spi);
|
2017-03-21 15:03:54 +00:00
|
|
|
|
2017-03-21 11:18:12 +00:00
|
|
|
if (entry->check_delete_action)
|
2008-04-11 08:14:48 +00:00
|
|
|
{ /* enforce child_cfg policy if deleted passively */
|
2010-06-02 09:41:46 +00:00
|
|
|
switch (action)
|
2008-04-11 08:14:48 +00:00
|
|
|
{
|
|
|
|
case ACTION_RESTART:
|
|
|
|
child_cfg->get_ref(child_cfg);
|
2013-06-29 16:47:02 +00:00
|
|
|
status = this->ike_sa->initiate(this->ike_sa, child_cfg,
|
2013-08-13 08:03:54 +00:00
|
|
|
reqid, NULL, NULL);
|
2008-04-11 08:14:48 +00:00
|
|
|
break;
|
2009-09-04 11:46:09 +00:00
|
|
|
case ACTION_ROUTE:
|
2009-05-06 17:48:21 +00:00
|
|
|
charon->traps->install(charon->traps,
|
2017-11-03 10:32:04 +00:00
|
|
|
this->ike_sa->get_peer_cfg(this->ike_sa),
|
|
|
|
child_cfg);
|
2008-04-11 08:14:48 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
child_cfg->destroy(child_cfg);
|
|
|
|
if (status != SUCCESS)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
2007-02-28 14:04:36 +00:00
|
|
|
}
|
2011-05-19 14:18:30 +00:00
|
|
|
enumerator->destroy(enumerator);
|
2008-04-11 08:14:48 +00:00
|
|
|
return status;
|
2007-02-28 14:04:36 +00:00
|
|
|
}
|
|
|
|
|
2007-05-09 12:33:08 +00:00
|
|
|
/**
|
|
|
|
* send closing signals for all CHILD_SAs over the bus
|
|
|
|
*/
|
|
|
|
static void log_children(private_child_delete_t *this)
|
|
|
|
{
|
2013-07-17 08:01:22 +00:00
|
|
|
linked_list_t *my_ts, *other_ts;
|
2011-05-19 14:18:30 +00:00
|
|
|
enumerator_t *enumerator;
|
2017-03-21 11:18:12 +00:00
|
|
|
entry_t *entry;
|
2007-05-09 12:33:08 +00:00
|
|
|
child_sa_t *child_sa;
|
2016-03-22 12:22:01 +00:00
|
|
|
uint64_t bytes_in, bytes_out;
|
2009-09-04 11:46:09 +00:00
|
|
|
|
2011-05-19 14:18:30 +00:00
|
|
|
enumerator = this->child_sas->create_enumerator(this->child_sas);
|
2017-03-21 11:18:12 +00:00
|
|
|
while (enumerator->enumerate(enumerator, (void**)&entry))
|
2007-05-09 12:33:08 +00:00
|
|
|
{
|
2017-03-21 11:18:12 +00:00
|
|
|
child_sa = entry->child_sa;
|
2013-07-17 08:01:22 +00:00
|
|
|
my_ts = linked_list_create_from_enumerator(
|
|
|
|
child_sa->create_ts_enumerator(child_sa, TRUE));
|
|
|
|
other_ts = linked_list_create_from_enumerator(
|
|
|
|
child_sa->create_ts_enumerator(child_sa, FALSE));
|
2012-01-02 14:40:31 +00:00
|
|
|
if (this->expired)
|
|
|
|
{
|
|
|
|
DBG0(DBG_IKE, "closing expired CHILD_SA %s{%d} "
|
2015-10-07 14:25:05 +00:00
|
|
|
"with SPIs %.8x_i %.8x_o and TS %#R === %#R",
|
2014-10-28 09:54:38 +00:00
|
|
|
child_sa->get_name(child_sa), child_sa->get_unique_id(child_sa),
|
2012-01-02 14:40:31 +00:00
|
|
|
ntohl(child_sa->get_spi(child_sa, TRUE)),
|
2013-07-17 08:01:22 +00:00
|
|
|
ntohl(child_sa->get_spi(child_sa, FALSE)), my_ts, other_ts);
|
2012-01-02 14:40:31 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2013-03-13 10:38:02 +00:00
|
|
|
child_sa->get_usestats(child_sa, TRUE, NULL, &bytes_in, NULL);
|
|
|
|
child_sa->get_usestats(child_sa, FALSE, NULL, &bytes_out, NULL);
|
2012-01-02 14:40:31 +00:00
|
|
|
|
|
|
|
DBG0(DBG_IKE, "closing CHILD_SA %s{%d} with SPIs %.8x_i "
|
2015-10-07 14:25:05 +00:00
|
|
|
"(%llu bytes) %.8x_o (%llu bytes) and TS %#R === %#R",
|
2014-10-28 09:54:38 +00:00
|
|
|
child_sa->get_name(child_sa), child_sa->get_unique_id(child_sa),
|
2012-01-02 14:40:31 +00:00
|
|
|
ntohl(child_sa->get_spi(child_sa, TRUE)), bytes_in,
|
|
|
|
ntohl(child_sa->get_spi(child_sa, FALSE)), bytes_out,
|
2013-07-17 08:01:22 +00:00
|
|
|
my_ts, other_ts);
|
2012-01-02 14:40:31 +00:00
|
|
|
}
|
2013-07-17 08:01:22 +00:00
|
|
|
my_ts->destroy(my_ts);
|
|
|
|
other_ts->destroy(other_ts);
|
2007-05-09 12:33:08 +00:00
|
|
|
}
|
2011-05-19 14:18:30 +00:00
|
|
|
enumerator->destroy(enumerator);
|
2007-05-09 12:33:08 +00:00
|
|
|
}
|
|
|
|
|
2011-10-04 06:05:27 +00:00
|
|
|
METHOD(task_t, build_i, status_t,
|
|
|
|
private_child_delete_t *this, message_t *message)
|
2007-02-28 14:04:36 +00:00
|
|
|
{
|
2008-12-01 18:38:28 +00:00
|
|
|
child_sa_t *child_sa;
|
2017-03-21 11:18:12 +00:00
|
|
|
entry_t *entry;
|
2009-09-04 11:46:09 +00:00
|
|
|
|
2008-12-01 18:38:28 +00:00
|
|
|
child_sa = this->ike_sa->get_child_sa(this->ike_sa, this->protocol,
|
|
|
|
this->spi, TRUE);
|
|
|
|
if (!child_sa)
|
2009-08-27 14:16:23 +00:00
|
|
|
{ /* check if it is an outbound sa */
|
|
|
|
child_sa = this->ike_sa->get_child_sa(this->ike_sa, this->protocol,
|
|
|
|
this->spi, FALSE);
|
|
|
|
if (!child_sa)
|
|
|
|
{ /* child does not exist anymore */
|
|
|
|
return SUCCESS;
|
|
|
|
}
|
|
|
|
/* we work only with the inbound SPI */
|
|
|
|
this->spi = child_sa->get_spi(child_sa, TRUE);
|
2008-12-01 18:38:28 +00:00
|
|
|
}
|
2017-03-21 15:03:54 +00:00
|
|
|
|
2018-11-06 11:13:35 +00:00
|
|
|
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));
|
|
|
|
}
|
|
|
|
|
2018-03-20 11:43:13 +00:00
|
|
|
if (child_sa->get_state(child_sa) == CHILD_DELETED)
|
2017-03-21 15:03:54 +00:00
|
|
|
{ /* DELETEs for this CHILD_SA were already exchanged, but it was not yet
|
|
|
|
* destroyed to allow delayed packets to get processed */
|
|
|
|
this->ike_sa->destroy_child_sa(this->ike_sa, this->protocol, this->spi);
|
|
|
|
message->set_exchange_type(message, EXCHANGE_TYPE_UNDEFINED);
|
|
|
|
return SUCCESS;
|
|
|
|
}
|
|
|
|
|
2017-03-21 11:18:12 +00:00
|
|
|
INIT(entry,
|
|
|
|
.child_sa = child_sa,
|
2017-03-21 15:03:54 +00:00
|
|
|
.rekeyed = child_sa->get_state(child_sa) == CHILD_REKEYED,
|
2017-03-21 11:18:12 +00:00
|
|
|
);
|
|
|
|
this->child_sas->insert_last(this->child_sas, entry);
|
2007-05-09 12:33:08 +00:00
|
|
|
log_children(this);
|
2007-02-28 14:04:36 +00:00
|
|
|
build_payloads(this, message);
|
2014-02-27 08:36:46 +00:00
|
|
|
|
2017-03-21 11:18:12 +00:00
|
|
|
if (!entry->rekeyed && this->expired)
|
2014-02-27 08:36:46 +00:00
|
|
|
{
|
|
|
|
child_cfg_t *child_cfg;
|
|
|
|
|
|
|
|
DBG1(DBG_IKE, "scheduling CHILD_SA recreate after hard expire");
|
|
|
|
child_cfg = child_sa->get_config(child_sa);
|
|
|
|
this->ike_sa->queue_task(this->ike_sa, (task_t*)
|
|
|
|
child_create_create(this->ike_sa, child_cfg->get_ref(child_cfg),
|
|
|
|
FALSE, NULL, NULL));
|
|
|
|
}
|
2007-02-28 14:04:36 +00:00
|
|
|
return NEED_MORE;
|
|
|
|
}
|
|
|
|
|
2011-10-04 06:05:27 +00:00
|
|
|
METHOD(task_t, process_i, status_t,
|
|
|
|
private_child_delete_t *this, message_t *message)
|
2007-02-28 14:04:36 +00:00
|
|
|
{
|
|
|
|
process_payloads(this, message);
|
2008-10-14 08:52:13 +00:00
|
|
|
DBG1(DBG_IKE, "CHILD_SA closed");
|
2008-04-11 08:14:48 +00:00
|
|
|
return destroy_and_reestablish(this);
|
2007-02-28 14:04:36 +00:00
|
|
|
}
|
|
|
|
|
2011-10-04 06:05:27 +00:00
|
|
|
METHOD(task_t, process_r, status_t,
|
|
|
|
private_child_delete_t *this, message_t *message)
|
2007-02-28 14:04:36 +00:00
|
|
|
{
|
|
|
|
process_payloads(this, message);
|
2007-05-09 12:33:08 +00:00
|
|
|
log_children(this);
|
2007-02-28 14:04:36 +00:00
|
|
|
return NEED_MORE;
|
|
|
|
}
|
|
|
|
|
2011-10-04 06:05:27 +00:00
|
|
|
METHOD(task_t, build_r, status_t,
|
|
|
|
private_child_delete_t *this, message_t *message)
|
2007-02-28 14:04:36 +00:00
|
|
|
{
|
2016-05-31 08:08:03 +00:00
|
|
|
build_payloads(this, message);
|
2008-10-14 08:52:13 +00:00
|
|
|
DBG1(DBG_IKE, "CHILD_SA closed");
|
2008-04-11 08:14:48 +00:00
|
|
|
return destroy_and_reestablish(this);
|
2007-02-28 14:04:36 +00:00
|
|
|
}
|
|
|
|
|
2011-10-04 06:05:27 +00:00
|
|
|
METHOD(task_t, get_type, task_type_t,
|
|
|
|
private_child_delete_t *this)
|
2007-02-28 14:04:36 +00:00
|
|
|
{
|
2011-11-21 11:18:24 +00:00
|
|
|
return TASK_CHILD_DELETE;
|
2007-02-28 14:04:36 +00:00
|
|
|
}
|
|
|
|
|
2011-10-04 06:05:27 +00:00
|
|
|
METHOD(child_delete_t , get_child, child_sa_t*,
|
|
|
|
private_child_delete_t *this)
|
2007-03-22 07:34:42 +00:00
|
|
|
{
|
|
|
|
child_sa_t *child_sa = NULL;
|
2017-03-21 11:18:12 +00:00
|
|
|
entry_t *entry;
|
|
|
|
|
|
|
|
if (this->child_sas->get_first(this->child_sas, (void**)&entry) == SUCCESS)
|
|
|
|
{
|
|
|
|
child_sa = entry->child_sa;
|
|
|
|
}
|
2007-03-22 07:34:42 +00:00
|
|
|
return child_sa;
|
|
|
|
}
|
|
|
|
|
2011-10-04 06:05:27 +00:00
|
|
|
METHOD(task_t, migrate, void,
|
|
|
|
private_child_delete_t *this, ike_sa_t *ike_sa)
|
2007-02-28 14:04:36 +00:00
|
|
|
{
|
|
|
|
this->ike_sa = ike_sa;
|
2009-09-04 11:46:09 +00:00
|
|
|
|
2017-03-21 11:18:12 +00:00
|
|
|
this->child_sas->destroy_function(this->child_sas, free);
|
2007-02-28 14:04:36 +00:00
|
|
|
this->child_sas = linked_list_create();
|
|
|
|
}
|
|
|
|
|
2011-10-04 06:05:27 +00:00
|
|
|
METHOD(task_t, destroy, void,
|
|
|
|
private_child_delete_t *this)
|
2007-02-28 14:04:36 +00:00
|
|
|
{
|
2017-03-21 11:18:12 +00:00
|
|
|
this->child_sas->destroy_function(this->child_sas, free);
|
2007-02-28 14:04:36 +00:00
|
|
|
free(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Described in header.
|
|
|
|
*/
|
2008-12-01 18:38:28 +00:00
|
|
|
child_delete_t *child_delete_create(ike_sa_t *ike_sa, protocol_id_t protocol,
|
2016-03-22 12:22:01 +00:00
|
|
|
uint32_t spi, bool expired)
|
2007-02-28 14:04:36 +00:00
|
|
|
{
|
2011-10-04 06:05:27 +00:00
|
|
|
private_child_delete_t *this;
|
|
|
|
|
|
|
|
INIT(this,
|
|
|
|
.public = {
|
|
|
|
.task = {
|
|
|
|
.get_type = _get_type,
|
|
|
|
.migrate = _migrate,
|
|
|
|
.destroy = _destroy,
|
|
|
|
},
|
|
|
|
.get_child = _get_child,
|
|
|
|
},
|
|
|
|
.ike_sa = ike_sa,
|
|
|
|
.child_sas = linked_list_create(),
|
|
|
|
.protocol = protocol,
|
|
|
|
.spi = spi,
|
2012-01-02 14:40:31 +00:00
|
|
|
.expired = expired,
|
2011-10-04 06:05:27 +00:00
|
|
|
);
|
2009-09-04 11:46:09 +00:00
|
|
|
|
2008-12-01 18:38:28 +00:00
|
|
|
if (protocol != PROTO_NONE)
|
2007-02-28 14:04:36 +00:00
|
|
|
{
|
2011-10-04 06:05:27 +00:00
|
|
|
this->public.task.build = _build_i;
|
|
|
|
this->public.task.process = _process_i;
|
2007-02-28 14:04:36 +00:00
|
|
|
this->initiator = TRUE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2011-10-04 06:05:27 +00:00
|
|
|
this->public.task.build = _build_r;
|
|
|
|
this->public.task.process = _process_r;
|
2007-02-28 14:04:36 +00:00
|
|
|
this->initiator = FALSE;
|
|
|
|
}
|
|
|
|
return &this->public;
|
|
|
|
}
|