ike-sa-manager: Add method to change the initiator SPI of an IKE_SA

This commit is contained in:
Tobias Brunner 2017-08-25 16:45:03 +02:00
parent bd371590ab
commit eaedcf8c00
2 changed files with 99 additions and 4 deletions

View File

@ -1,9 +1,10 @@
/*
* Copyright (C) 2005-2011 Martin Willi
* Copyright (C) 2011 revosec AG
* Copyright (C) 2008-2016 Tobias Brunner
*
* Copyright (C) 2008-2017 Tobias Brunner
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
* HSR Hochschule fuer Technik Rapperswil
*
* 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
@ -1572,6 +1573,88 @@ METHOD(ike_sa_manager_t, checkout_by_name, ike_sa_t*,
return ike_sa;
}
METHOD(ike_sa_manager_t, new_initiator_spi, bool,
private_ike_sa_manager_t *this, ike_sa_t *ike_sa)
{
ike_sa_state_t state;
ike_sa_id_t *ike_sa_id;
entry_t *entry;
u_int segment;
uint64_t new_spi, spi;
state = ike_sa->get_state(ike_sa);
if (state != IKE_CONNECTING)
{
DBG1(DBG_MGR, "unable to change initiator SPI for IKE_SA in state "
"%N", ike_sa_state_names, state);
return FALSE;
}
ike_sa_id = ike_sa->get_id(ike_sa);
if (!ike_sa_id->is_initiator(ike_sa_id))
{
DBG1(DBG_MGR, "unable to change initiator SPI of IKE_SA as responder");
return FALSE;
}
if (ike_sa != charon->bus->get_sa(charon->bus))
{
DBG1(DBG_MGR, "unable to change initiator SPI of IKE_SA not checked "
"out by current thread");
return FALSE;
}
new_spi = get_spi(this);
if (!new_spi)
{
DBG1(DBG_MGR, "unable to allocate new initiator SPI for IKE_SA");
return FALSE;
}
if (get_entry_by_sa(this, ike_sa_id, ike_sa, &entry, &segment) == SUCCESS)
{
if (entry->driveout_waiting_threads && entry->driveout_new_threads)
{ /* it looks like flush() has been called and the SA is being deleted
* anyway, no need for a new SPI */
DBG2(DBG_MGR, "ignored change of initiator SPI during shutdown");
unlock_single_segment(this, segment);
return FALSE;
}
/* threads waiting for this entry do so using the (soon) wrong IKE_SA
* ID and, therefore, likely on the wrong segment, so drive them out */
entry->driveout_waiting_threads = TRUE;
entry->driveout_new_threads = TRUE;
while (entry->waiting_threads)
{
entry->condvar->broadcast(entry->condvar);
entry->condvar->wait(entry->condvar, this->segments[segment].mutex);
}
remove_entry(this, entry);
unlock_single_segment(this, segment);
}
else
{
DBG1(DBG_MGR, "unable to change initiator SPI of IKE_SA, not found");
return FALSE;
}
spi = ike_sa_id->get_initiator_spi(ike_sa_id);
DBG2(DBG_MGR, "change initiator SPI of IKE_SA %s[%u] from %.16"PRIx64" to "
"%.16"PRIx64, ike_sa->get_name(ike_sa), ike_sa->get_unique_id(ike_sa),
be64toh(spi), be64toh(new_spi));
ike_sa_id->set_initiator_spi(ike_sa_id, new_spi);
entry->ike_sa_id->replace_values(entry->ike_sa_id, ike_sa_id);
entry->driveout_waiting_threads = FALSE;
entry->driveout_new_threads = FALSE;
segment = put_entry(this, entry);
unlock_single_segment(this, segment);
return TRUE;
}
CALLBACK(enumerator_filter_wait, bool,
private_ike_sa_manager_t *this, enumerator_t *orig, va_list args)
{
@ -2277,6 +2360,7 @@ ike_sa_manager_t *ike_sa_manager_create()
.checkout_by_config = _checkout_by_config,
.checkout_by_id = _checkout_by_id,
.checkout_by_name = _checkout_by_name,
.new_initiator_spi = _new_initiator_spi,
.check_uniqueness = _check_uniqueness,
.has_contact = _has_contact,
.create_enumerator = _create_enumerator,

View File

@ -1,8 +1,8 @@
/*
* Copyright (C) 2008-2015 Tobias Brunner
* Copyright (C) 2008-2017 Tobias Brunner
* Copyright (C) 2005-2008 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
* HSR Hochschule fuer Technik Rapperswil
*
* 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
@ -108,6 +108,17 @@ struct ike_sa_manager_t {
ike_sa_t* (*checkout_by_config) (ike_sa_manager_t* this,
peer_cfg_t *peer_cfg);
/**
* Reset initiator SPI.
*
* Allocate a new initiator SPI for the given IKE_SA in state IKE_CONNECTING
* and update internal data.
*
* @param ike_sa IKE_SA to update
* @return TRUE if SPI successfully changed
*/
bool (*new_initiator_spi)(ike_sa_manager_t* this, ike_sa_t *ike_sa);
/**
* Check for duplicates of the given IKE_SA.
*