version 1.1.1.1, 2020/06/03 09:46:45
|
version 1.1.1.2, 2021/03/17 00:20:09
|
Line 2
|
Line 2
|
* Copyright (C) 2005-2011 Martin Willi |
* Copyright (C) 2005-2011 Martin Willi |
* Copyright (C) 2011 revosec AG |
* Copyright (C) 2011 revosec AG |
* |
* |
* Copyright (C) 2008-2018 Tobias Brunner | * Copyright (C) 2008-2021 Tobias Brunner |
* Copyright (C) 2005 Jan Hutter |
* Copyright (C) 2005 Jan Hutter |
* HSR Hochschule fuer Technik Rapperswil |
* HSR Hochschule fuer Technik Rapperswil |
* |
* |
Line 29
|
Line 29
|
#include <threading/condvar.h> |
#include <threading/condvar.h> |
#include <threading/mutex.h> |
#include <threading/mutex.h> |
#include <threading/rwlock.h> |
#include <threading/rwlock.h> |
|
#include <collections/array.h> |
#include <collections/linked_list.h> |
#include <collections/linked_list.h> |
#include <crypto/hashers/hasher.h> |
#include <crypto/hashers/hasher.h> |
#include <processing/jobs/delete_ike_sa_job.h> |
#include <processing/jobs/delete_ike_sa_job.h> |
Line 391 struct private_ike_sa_manager_t {
|
Line 392 struct private_ike_sa_manager_t {
|
table_item_t **init_hashes_table; |
table_item_t **init_hashes_table; |
|
|
/** |
/** |
* Segments of the "hashes" hash table. | * Segments of the "hashes" hash table. |
*/ |
*/ |
segment_t *init_hashes_segments; |
segment_t *init_hashes_segments; |
|
|
/** |
/** |
|
* Configs for which an SA is currently being checked out. |
|
*/ |
|
array_t *config_checkouts; |
|
|
|
/** |
|
* Mutex to protect access to configs. |
|
*/ |
|
mutex_t *config_mutex; |
|
|
|
/** |
|
* Condvar to indicate changes in checkout configs. |
|
*/ |
|
condvar_t *config_condvar; |
|
|
|
/** |
* RNG to get random SPIs for our side |
* RNG to get random SPIs for our side |
*/ |
*/ |
rng_t *rng; |
rng_t *rng; |
Line 871 static void remove_half_open(private_ike_sa_manager_t
|
Line 887 static void remove_half_open(private_ike_sa_manager_t
|
lock->unlock(lock); |
lock->unlock(lock); |
} |
} |
|
|
|
/** |
|
* Create an entry and put it into the hash table. |
|
* Note: The caller has to unlock the segment. |
|
*/ |
|
static u_int create_and_put_entry(private_ike_sa_manager_t *this, |
|
ike_sa_t *ike_sa, entry_t **entry) |
|
{ |
|
ike_sa_id_t *ike_sa_id = ike_sa->get_id(ike_sa); |
|
host_t *other = ike_sa->get_other_host(ike_sa); |
|
|
|
*entry = entry_create(); |
|
(*entry)->ike_sa_id = ike_sa_id->clone(ike_sa_id); |
|
(*entry)->ike_sa = ike_sa; |
|
|
|
if (ike_sa->get_state(ike_sa) == IKE_CONNECTING) |
|
{ |
|
(*entry)->half_open = TRUE; |
|
(*entry)->other = other->clone(other); |
|
put_half_open(this, *entry); |
|
} |
|
return put_entry(this, *entry); |
|
} |
|
|
CALLBACK(id_matches, bool, |
CALLBACK(id_matches, bool, |
ike_sa_id_t *a, va_list args) |
ike_sa_id_t *a, va_list args) |
{ |
{ |
Line 1202 METHOD(ike_sa_manager_t, checkout, ike_sa_t*,
|
Line 1241 METHOD(ike_sa_manager_t, checkout, ike_sa_t*,
|
return ike_sa; |
return ike_sa; |
} |
} |
|
|
METHOD(ike_sa_manager_t, checkout_new, ike_sa_t*, | METHOD(ike_sa_manager_t, create_new, ike_sa_t*, |
private_ike_sa_manager_t* this, ike_version_t version, bool initiator) |
private_ike_sa_manager_t* this, ike_version_t version, bool initiator) |
{ |
{ |
ike_sa_id_t *ike_sa_id; |
ike_sa_id_t *ike_sa_id; |
Line 1238 METHOD(ike_sa_manager_t, checkout_new, ike_sa_t*,
|
Line 1277 METHOD(ike_sa_manager_t, checkout_new, ike_sa_t*,
|
return ike_sa; |
return ike_sa; |
} |
} |
|
|
|
METHOD(ike_sa_manager_t, checkout_new, void, |
|
private_ike_sa_manager_t *this, ike_sa_t *ike_sa) |
|
{ |
|
u_int segment; |
|
entry_t *entry; |
|
|
|
segment = create_and_put_entry(this, ike_sa, &entry); |
|
entry->checked_out = thread_current(); |
|
unlock_single_segment(this, segment); |
|
} |
|
|
/** |
/** |
* Get the message ID or message hash to detect early retransmissions |
* Get the message ID or message hash to detect early retransmissions |
*/ |
*/ |
Line 1422 out:
|
Line 1472 out:
|
return ike_sa; |
return ike_sa; |
} |
} |
|
|
|
/** |
|
* Data used to track checkouts by config. |
|
*/ |
|
typedef struct { |
|
/** The peer config for which an IKE_SA is being checked out. */ |
|
peer_cfg_t *cfg; |
|
/** Number of threads checking out SAs for the same config. */ |
|
int threads; |
|
/** A thread is currently creating/finding an SA for this config. */ |
|
bool working; |
|
} config_entry_t; |
|
|
METHOD(ike_sa_manager_t, checkout_by_config, ike_sa_t*, |
METHOD(ike_sa_manager_t, checkout_by_config, ike_sa_t*, |
private_ike_sa_manager_t *this, peer_cfg_t *peer_cfg) |
private_ike_sa_manager_t *this, peer_cfg_t *peer_cfg) |
{ |
{ |
Line 1430 METHOD(ike_sa_manager_t, checkout_by_config, ike_sa_t*
|
Line 1492 METHOD(ike_sa_manager_t, checkout_by_config, ike_sa_t*
|
ike_sa_t *ike_sa = NULL; |
ike_sa_t *ike_sa = NULL; |
peer_cfg_t *current_peer; |
peer_cfg_t *current_peer; |
ike_cfg_t *current_ike; |
ike_cfg_t *current_ike; |
|
config_entry_t *config_entry, *found = NULL; |
u_int segment; |
u_int segment; |
|
int i; |
|
|
DBG2(DBG_MGR, "checkout IKE_SA by config"); |
DBG2(DBG_MGR, "checkout IKE_SA by config"); |
|
|
if (!this->reuse_ikesa && peer_cfg->get_ike_version(peer_cfg) != IKEV1) |
if (!this->reuse_ikesa && peer_cfg->get_ike_version(peer_cfg) != IKEV1) |
{ /* IKE_SA reuse disabled by config (not possible for IKEv1) */ |
{ /* IKE_SA reuse disabled by config (not possible for IKEv1) */ |
ike_sa = checkout_new(this, peer_cfg->get_ike_version(peer_cfg), TRUE); | ike_sa = create_new(this, peer_cfg->get_ike_version(peer_cfg), TRUE); |
| if (ike_sa) |
| { |
| ike_sa->set_peer_cfg(ike_sa, peer_cfg); |
| checkout_new(this, ike_sa); |
| } |
charon->bus->set_sa(charon->bus, ike_sa); |
charon->bus->set_sa(charon->bus, ike_sa); |
goto out; |
goto out; |
} |
} |
|
|
|
this->config_mutex->lock(this->config_mutex); |
|
for (i = 0; i < array_count(this->config_checkouts); i++) |
|
{ |
|
array_get(this->config_checkouts, i, &config_entry); |
|
if (config_entry->cfg->equals(config_entry->cfg, peer_cfg)) |
|
{ |
|
current_ike = config_entry->cfg->get_ike_cfg(config_entry->cfg); |
|
if (current_ike->equals(current_ike, |
|
peer_cfg->get_ike_cfg(peer_cfg))) |
|
{ |
|
found = config_entry; |
|
break; |
|
} |
|
} |
|
} |
|
if (!found) |
|
{ |
|
INIT(found, |
|
.cfg = peer_cfg->get_ref(peer_cfg), |
|
); |
|
array_insert_create(&this->config_checkouts, ARRAY_TAIL, found); |
|
} |
|
found->threads++; |
|
while (found->working) |
|
{ |
|
this->config_condvar->wait(this->config_condvar, this->config_mutex); |
|
} |
|
found->working = TRUE; |
|
this->config_mutex->unlock(this->config_mutex); |
|
|
enumerator = create_table_enumerator(this); |
enumerator = create_table_enumerator(this); |
while (enumerator->enumerate(enumerator, &entry, &segment)) |
while (enumerator->enumerate(enumerator, &entry, &segment)) |
{ |
{ |
Line 1463 METHOD(ike_sa_manager_t, checkout_by_config, ike_sa_t*
|
Line 1562 METHOD(ike_sa_manager_t, checkout_by_config, ike_sa_t*
|
{ |
{ |
entry->checked_out = thread_current(); |
entry->checked_out = thread_current(); |
ike_sa = entry->ike_sa; |
ike_sa = entry->ike_sa; |
DBG2(DBG_MGR, "found existing IKE_SA %u with a '%s' config", | DBG2(DBG_MGR, "found existing IKE_SA %u with config '%s'", |
ike_sa->get_unique_id(ike_sa), |
ike_sa->get_unique_id(ike_sa), |
current_peer->get_name(current_peer)); |
current_peer->get_name(current_peer)); |
break; |
break; |
Line 1475 METHOD(ike_sa_manager_t, checkout_by_config, ike_sa_t*
|
Line 1574 METHOD(ike_sa_manager_t, checkout_by_config, ike_sa_t*
|
enumerator->destroy(enumerator); |
enumerator->destroy(enumerator); |
|
|
if (!ike_sa) |
if (!ike_sa) |
{ /* no IKE_SA using such a config, hand out a new */ | { |
ike_sa = checkout_new(this, peer_cfg->get_ike_version(peer_cfg), TRUE); | ike_sa = create_new(this, peer_cfg->get_ike_version(peer_cfg), TRUE); |
| if (ike_sa) |
| { |
| ike_sa->set_peer_cfg(ike_sa, peer_cfg); |
| checkout_new(this, ike_sa); |
| } |
} |
} |
charon->bus->set_sa(charon->bus, ike_sa); |
charon->bus->set_sa(charon->bus, ike_sa); |
|
|
|
this->config_mutex->lock(this->config_mutex); |
|
found->working = FALSE; |
|
found->threads--; |
|
if (!found->threads) |
|
{ |
|
for (i = 0; i < array_count(this->config_checkouts); i++) |
|
{ |
|
array_get(this->config_checkouts, i, &config_entry); |
|
if (config_entry == found) |
|
{ |
|
array_remove(this->config_checkouts, i, NULL); |
|
found->cfg->destroy(found->cfg); |
|
free(found); |
|
break; |
|
} |
|
} |
|
} |
|
this->config_condvar->signal(this->config_condvar); |
|
this->config_mutex->unlock(this->config_mutex); |
|
|
out: |
out: |
if (!ike_sa) |
if (!ike_sa) |
{ |
{ |
Line 1784 METHOD(ike_sa_manager_t, checkin, void,
|
Line 1908 METHOD(ike_sa_manager_t, checkin, void,
|
} |
} |
else |
else |
{ |
{ |
entry = entry_create(); | segment = create_and_put_entry(this, ike_sa, &entry); |
entry->ike_sa_id = ike_sa_id->clone(ike_sa_id); | |
entry->ike_sa = ike_sa; | |
if (ike_sa->get_state(ike_sa) == IKE_CONNECTING) | |
{ | |
entry->half_open = TRUE; | |
entry->other = other->clone(other); | |
put_half_open(this, entry); | |
} | |
segment = put_entry(this, entry); | |
} |
} |
DBG2(DBG_MGR, "checkin of IKE_SA successful"); |
DBG2(DBG_MGR, "checkin of IKE_SA successful"); |
|
|
Line 2326 METHOD(ike_sa_manager_t, destroy, void,
|
Line 2441 METHOD(ike_sa_manager_t, destroy, void,
|
free(this->connected_peers_segments); |
free(this->connected_peers_segments); |
free(this->init_hashes_segments); |
free(this->init_hashes_segments); |
|
|
|
array_destroy(this->config_checkouts); |
|
this->config_mutex->destroy(this->config_mutex); |
|
this->config_condvar->destroy(this->config_condvar); |
|
|
this->spi_lock->destroy(this->spi_lock); |
this->spi_lock->destroy(this->spi_lock); |
free(this); |
free(this); |
} |
} |
Line 2359 ike_sa_manager_t *ike_sa_manager_create()
|
Line 2478 ike_sa_manager_t *ike_sa_manager_create()
|
|
|
INIT(this, |
INIT(this, |
.public = { |
.public = { |
.checkout = _checkout, | .create_new = _create_new, |
.checkout_new = _checkout_new, |
.checkout_new = _checkout_new, |
|
.checkout = _checkout, |
.checkout_by_message = _checkout_by_message, |
.checkout_by_message = _checkout_by_message, |
.checkout_by_config = _checkout_by_config, |
.checkout_by_config = _checkout_by_config, |
.checkout_by_id = _checkout_by_id, |
.checkout_by_id = _checkout_by_id, |
Line 2448 ike_sa_manager_t *ike_sa_manager_create()
|
Line 2568 ike_sa_manager_t *ike_sa_manager_create()
|
{ |
{ |
this->init_hashes_segments[i].mutex = mutex_create(MUTEX_TYPE_RECURSIVE); |
this->init_hashes_segments[i].mutex = mutex_create(MUTEX_TYPE_RECURSIVE); |
} |
} |
|
|
|
this->config_mutex = mutex_create(MUTEX_TYPE_DEFAULT); |
|
this->config_condvar = condvar_create(CONDVAR_TYPE_DEFAULT); |
|
|
this->reuse_ikesa = lib->settings->get_bool(lib->settings, |
this->reuse_ikesa = lib->settings->get_bool(lib->settings, |
"%s.reuse_ikesa", TRUE, lib->ns); |
"%s.reuse_ikesa", TRUE, lib->ns); |