summaryrefslogtreecommitdiff
path: root/src/libcharon/sa/ike_sa_manager.c
diff options
context:
space:
mode:
authorRené Mayrhofer <rene@mayrhofer.eu.org>2011-03-05 09:20:09 +0100
committerRené Mayrhofer <rene@mayrhofer.eu.org>2011-03-05 09:20:09 +0100
commit568905f488e63e28778f87ac0e38d845f45bae79 (patch)
treed9969a147e36413583ff4bc75542d34c955f8823 /src/libcharon/sa/ike_sa_manager.c
parentf73fba54dc8b30c6482e1e8abf15bbf455592fcd (diff)
downloadvyos-strongswan-568905f488e63e28778f87ac0e38d845f45bae79.tar.gz
vyos-strongswan-568905f488e63e28778f87ac0e38d845f45bae79.zip
Imported Upstream version 4.5.1
Diffstat (limited to 'src/libcharon/sa/ike_sa_manager.c')
-rw-r--r--src/libcharon/sa/ike_sa_manager.c474
1 files changed, 254 insertions, 220 deletions
diff --git a/src/libcharon/sa/ike_sa_manager.c b/src/libcharon/sa/ike_sa_manager.c
index fa94bb86d..d695c7f7c 100644
--- a/src/libcharon/sa/ike_sa_manager.c
+++ b/src/libcharon/sa/ike_sa_manager.c
@@ -1,6 +1,7 @@
/*
+ * Copyright (C) 2005-2011 Martin Willi
+ * Copyright (C) 2011 revosec AG
* Copyright (C) 2008 Tobias Brunner
- * Copyright (C) 2005-2008 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
*
@@ -85,7 +86,9 @@ struct entry_t {
chunk_t init_hash;
/**
- * remote host address, required for DoS detection
+ * remote host address, required for DoS detection and duplicate
+ * checking (host with same my_id and other_id is *not* considered
+ * a duplicate if the address family differs)
*/
host_t *other;
@@ -241,6 +244,9 @@ struct connected_peers_t {
/** remote identity */
identification_t *other_id;
+ /** ip address family of peer */
+ int family;
+
/** list of ike_sa_id_t objects of IKE_SAs between the two identities */
linked_list_t *sas;
};
@@ -257,10 +263,12 @@ static void connected_peers_destroy(connected_peers_t *this)
* Function that matches connected_peers_t objects by the given ids.
*/
static bool connected_peers_match(connected_peers_t *connected_peers,
- identification_t *my_id, identification_t *other_id)
+ identification_t *my_id, identification_t *other_id,
+ uintptr_t family)
{
return my_id->equals(my_id, connected_peers->my_id) &&
- other_id->equals(other_id, connected_peers->other_id);
+ other_id->equals(other_id, connected_peers->other_id) &&
+ family == connected_peers->family;
}
typedef struct segment_t segment_t;
@@ -396,7 +404,7 @@ static void lock_all_segments(private_ike_sa_manager_t *this)
{
u_int i;
- for (i = 0; i < this->segment_count; ++i)
+ for (i = 0; i < this->segment_count; i++)
{
this->segments[i].mutex->lock(this->segments[i].mutex);
}
@@ -409,7 +417,7 @@ static void unlock_all_segments(private_ike_sa_manager_t *this)
{
u_int i;
- for (i = 0; i < this->segment_count; ++i)
+ for (i = 0; i < this->segment_count; i++)
{
this->segments[i].mutex->unlock(this->segments[i].mutex);
}
@@ -453,10 +461,8 @@ struct private_enumerator_t {
enumerator_t *current;
};
-/**
- * Implementation of private_enumerator_t.enumerator.enumerate.
- */
-static bool enumerate(private_enumerator_t *this, entry_t **entry, u_int *segment)
+METHOD(enumerator_t, enumerate, bool,
+ private_enumerator_t *this, entry_t **entry, u_int *segment)
{
if (this->entry)
{
@@ -502,10 +508,8 @@ static bool enumerate(private_enumerator_t *this, entry_t **entry, u_int *segmen
return FALSE;
}
-/**
- * Implementation of private_enumerator_t.enumerator.destroy.
- */
-static void enumerator_destroy(private_enumerator_t *this)
+METHOD(enumerator_t, enumerator_destroy, void,
+ private_enumerator_t *this)
{
if (this->entry)
{
@@ -524,16 +528,15 @@ static void enumerator_destroy(private_enumerator_t *this)
*/
static enumerator_t* create_table_enumerator(private_ike_sa_manager_t *this)
{
- private_enumerator_t *enumerator = malloc_thing(private_enumerator_t);
-
- enumerator->enumerator.enumerate = (void*)enumerate;
- enumerator->enumerator.destroy = (void*)enumerator_destroy;
- enumerator->manager = this;
- enumerator->segment = 0;
- enumerator->entry = NULL;
- enumerator->row = 0;
- enumerator->current = NULL;
-
+ private_enumerator_t *enumerator;
+
+ INIT(enumerator,
+ .enumerator = {
+ .enumerate = (void*)_enumerate,
+ .destroy = _enumerator_destroy,
+ },
+ .manager = this,
+ );
return &enumerator->enumerator;
}
@@ -544,11 +547,14 @@ static enumerator_t* create_table_enumerator(private_ike_sa_manager_t *this)
static u_int put_entry(private_ike_sa_manager_t *this, entry_t *entry)
{
linked_list_t *list;
- u_int row = ike_sa_id_hash(entry->ike_sa_id) & this->table_mask;
- u_int segment = row & this->segment_mask;
+ u_int row, segment;
+
+ row = ike_sa_id_hash(entry->ike_sa_id) & this->table_mask;
+ segment = row & this->segment_mask;
lock_single_segment(this, segment);
- if ((list = this->ike_sa_table[row]) == NULL)
+ list = this->ike_sa_table[row];
+ if (!list)
{
list = this->ike_sa_table[row] = linked_list_create();
}
@@ -564,14 +570,17 @@ static u_int put_entry(private_ike_sa_manager_t *this, entry_t *entry)
static void remove_entry(private_ike_sa_manager_t *this, entry_t *entry)
{
linked_list_t *list;
- u_int row = ike_sa_id_hash(entry->ike_sa_id) & this->table_mask;
- u_int segment = row & this->segment_mask;
+ u_int row, segment;
- if ((list = this->ike_sa_table[row]) != NULL)
+ row = ike_sa_id_hash(entry->ike_sa_id) & this->table_mask;
+ segment = row & this->segment_mask;
+ list = this->ike_sa_table[row];
+ if (list)
{
entry_t *current;
+ enumerator_t *enumerator;
- enumerator_t *enumerator = list->create_enumerator(list);
+ enumerator = list->create_enumerator(list);
while (enumerator->enumerate(enumerator, &current))
{
if (current == entry)
@@ -609,11 +618,14 @@ static status_t get_entry_by_match_function(private_ike_sa_manager_t *this,
{
entry_t *current;
linked_list_t *list;
- u_int row = ike_sa_id_hash(ike_sa_id) & this->table_mask;
- u_int seg = row & this->segment_mask;
+ u_int row, seg;
+
+ row = ike_sa_id_hash(ike_sa_id) & this->table_mask;
+ seg = row & this->segment_mask;
lock_single_segment(this, seg);
- if ((list = this->ike_sa_table[row]) != NULL)
+ list = this->ike_sa_table[row];
+ if (list)
{
if (list->find_first(list, match, (void**)&current, p1, p2) == SUCCESS)
{
@@ -697,19 +709,20 @@ static void put_half_open(private_ike_sa_manager_t *this, entry_t *entry)
{
half_open_t *half_open = NULL;
linked_list_t *list;
- chunk_t addr = entry->other->get_address(entry->other);
- u_int row = chunk_hash(addr) & this->table_mask;
- u_int segment = row & this->segment_mask;
+ chunk_t addr;
+ u_int row, segment;
+ rwlock_t *lock;
- rwlock_t *lock = this->half_open_segments[segment].lock;
+ addr = entry->other->get_address(entry->other);
+ row = chunk_hash(addr) & this->table_mask;
+ segment = row & this->segment_mask;
+ lock = this->half_open_segments[segment].lock;
lock->write_lock(lock);
- if ((list = this->half_open_table[row]) == NULL)
- {
- list = this->half_open_table[row] = linked_list_create();
- }
- else
+ list = this->half_open_table[row];
+ if (list)
{
half_open_t *current;
+
if (list->find_first(list, (linked_list_match_t)half_open_match,
(void**)&current, &addr) == SUCCESS)
{
@@ -718,12 +731,17 @@ static void put_half_open(private_ike_sa_manager_t *this, entry_t *entry)
this->half_open_segments[segment].count++;
}
}
+ else
+ {
+ list = this->half_open_table[row] = linked_list_create();
+ }
if (!half_open)
{
- half_open = malloc_thing(half_open_t);
- half_open->other = chunk_clone(addr);
- half_open->count = 1;
+ INIT(half_open,
+ .other = chunk_clone(addr),
+ .count = 1,
+ );
list->insert_last(list, half_open);
this->half_open_segments[segment].count++;
}
@@ -736,16 +754,22 @@ static void put_half_open(private_ike_sa_manager_t *this, entry_t *entry)
static void remove_half_open(private_ike_sa_manager_t *this, entry_t *entry)
{
linked_list_t *list;
- chunk_t addr = entry->other->get_address(entry->other);
- u_int row = chunk_hash(addr) & this->table_mask;
- u_int segment = row & this->segment_mask;
+ chunk_t addr;
+ u_int row, segment;
+ rwlock_t *lock;
- rwlock_t *lock = this->half_open_segments[segment].lock;
+ addr = entry->other->get_address(entry->other);
+ row = chunk_hash(addr) & this->table_mask;
+ segment = row & this->segment_mask;
+ lock = this->half_open_segments[segment].lock;
lock->write_lock(lock);
- if ((list = this->half_open_table[row]) != NULL)
+ list = this->half_open_table[row];
+ if (list)
{
half_open_t *current;
- enumerator_t *enumerator = list->create_enumerator(list);
+ enumerator_t *enumerator;
+
+ enumerator = list->create_enumerator(list);
while (enumerator->enumerate(enumerator, &current))
{
if (half_open_match(current, &addr))
@@ -769,24 +793,26 @@ static void remove_half_open(private_ike_sa_manager_t *this, entry_t *entry)
*/
static void put_connected_peers(private_ike_sa_manager_t *this, entry_t *entry)
{
- linked_list_t *list;
connected_peers_t *connected_peers = NULL;
- chunk_t my_id = entry->my_id->get_encoding(entry->my_id),
- other_id = entry->other_id->get_encoding(entry->other_id);
- u_int row = chunk_hash_inc(other_id, chunk_hash(my_id)) & this->table_mask;
- u_int segment = row & this->segment_mask;
+ chunk_t my_id, other_id;
+ linked_list_t *list;
+ u_int row, segment;
+ rwlock_t *lock;
- rwlock_t *lock = this->connected_peers_segments[segment].lock;
+ my_id = entry->my_id->get_encoding(entry->my_id);
+ other_id = entry->other_id->get_encoding(entry->other_id);
+ row = chunk_hash_inc(other_id, chunk_hash(my_id)) & this->table_mask;
+ segment = row & this->segment_mask;
+ lock = this->connected_peers_segments[segment].lock;
lock->write_lock(lock);
- if ((list = this->connected_peers_table[row]) == NULL)
- {
- list = this->connected_peers_table[row] = linked_list_create();
- }
- else
+ list = this->connected_peers_table[row];
+ if (list)
{
connected_peers_t *current;
+
if (list->find_first(list, (linked_list_match_t)connected_peers_match,
- (void**)&current, entry->my_id, entry->other_id) == SUCCESS)
+ (void**)&current, entry->my_id, entry->other_id,
+ (uintptr_t)entry->other->get_family(entry->other)) == SUCCESS)
{
connected_peers = current;
if (connected_peers->sas->find_first(connected_peers->sas,
@@ -798,13 +824,19 @@ static void put_connected_peers(private_ike_sa_manager_t *this, entry_t *entry)
}
}
}
+ else
+ {
+ list = this->connected_peers_table[row] = linked_list_create();
+ }
if (!connected_peers)
{
- connected_peers = malloc_thing(connected_peers_t);
- connected_peers->my_id = entry->my_id->clone(entry->my_id);
- connected_peers->other_id = entry->other_id->clone(entry->other_id);
- connected_peers->sas = linked_list_create();
+ INIT(connected_peers,
+ .my_id = entry->my_id->clone(entry->my_id),
+ .other_id = entry->other_id->clone(entry->other_id),
+ .family = entry->other->get_family(entry->other),
+ .sas = linked_list_create(),
+ );
list->insert_last(list, connected_peers);
}
connected_peers->sas->insert_last(connected_peers->sas,
@@ -818,24 +850,34 @@ static void put_connected_peers(private_ike_sa_manager_t *this, entry_t *entry)
*/
static void remove_connected_peers(private_ike_sa_manager_t *this, entry_t *entry)
{
+ chunk_t my_id, other_id;
linked_list_t *list;
- chunk_t my_id = entry->my_id->get_encoding(entry->my_id),
- other_id = entry->other_id->get_encoding(entry->other_id);
- u_int row = chunk_hash_inc(other_id, chunk_hash(my_id)) & this->table_mask;
- u_int segment = row & this->segment_mask;
+ u_int row, segment;
+ rwlock_t *lock;
+
+ my_id = entry->my_id->get_encoding(entry->my_id);
+ other_id = entry->other_id->get_encoding(entry->other_id);
+ row = chunk_hash_inc(other_id, chunk_hash(my_id)) & this->table_mask;
+ segment = row & this->segment_mask;
- rwlock_t *lock = this->connected_peers_segments[segment].lock;
+ lock = this->connected_peers_segments[segment].lock;
lock->write_lock(lock);
- if ((list = this->connected_peers_table[row]) != NULL)
+ list = this->connected_peers_table[row];
+ if (list)
{
connected_peers_t *current;
- enumerator_t *enumerator = list->create_enumerator(list);
+ enumerator_t *enumerator;
+
+ enumerator = list->create_enumerator(list);
while (enumerator->enumerate(enumerator, &current))
{
- if (connected_peers_match(current, entry->my_id, entry->other_id))
+ if (connected_peers_match(current, entry->my_id, entry->other_id,
+ (uintptr_t)entry->other->get_family(entry->other)))
{
ike_sa_id_t *ike_sa_id;
- enumerator_t *inner = current->sas->create_enumerator(current->sas);
+ enumerator_t *inner;
+
+ inner = current->sas->create_enumerator(current->sas);
while (inner->enumerate(inner, &ike_sa_id))
{
if (ike_sa_id->equals(ike_sa_id, entry->ike_sa_id))
@@ -861,20 +903,21 @@ static void remove_connected_peers(private_ike_sa_manager_t *this, entry_t *entr
}
/**
- * Implementation of private_ike_sa_manager_t.get_next_spi.
+ * Get a random SPI for new IKE_SAs
*/
-static u_int64_t get_next_spi(private_ike_sa_manager_t *this)
+static u_int64_t get_spi(private_ike_sa_manager_t *this)
{
- u_int64_t spi;
+ u_int64_t spi = 0;
- this->rng->get_bytes(this->rng, sizeof(spi), (u_int8_t*)&spi);
+ if (this->rng)
+ {
+ this->rng->get_bytes(this->rng, sizeof(spi), (u_int8_t*)&spi);
+ }
return spi;
}
-/**
- * Implementation of of ike_sa_manager.checkout.
- */
-static ike_sa_t* checkout(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id)
+METHOD(ike_sa_manager_t, checkout, ike_sa_t*,
+ private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id)
{
ike_sa_t *ike_sa = NULL;
entry_t *entry;
@@ -897,62 +940,46 @@ static ike_sa_t* checkout(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id
return ike_sa;
}
-/**
- * Implementation of of ike_sa_manager.checkout_new.
- */
-static ike_sa_t *checkout_new(private_ike_sa_manager_t* this, bool initiator)
+METHOD(ike_sa_manager_t, checkout_new, ike_sa_t*,
+ private_ike_sa_manager_t* this, bool initiator)
{
ike_sa_id_t *ike_sa_id;
ike_sa_t *ike_sa;
- entry_t *entry;
- u_int segment;
if (initiator)
{
- ike_sa_id = ike_sa_id_create(get_next_spi(this), 0, TRUE);
+ ike_sa_id = ike_sa_id_create(get_spi(this), 0, TRUE);
}
else
{
- ike_sa_id = ike_sa_id_create(0, get_next_spi(this), FALSE);
+ ike_sa_id = ike_sa_id_create(0, get_spi(this), FALSE);
}
ike_sa = ike_sa_create(ike_sa_id);
+ ike_sa_id->destroy(ike_sa_id);
DBG2(DBG_MGR, "created IKE_SA %s[%u]", ike_sa->get_name(ike_sa),
ike_sa->get_unique_id(ike_sa));
- if (!initiator)
- {
- ike_sa_id->destroy(ike_sa_id);
- return ike_sa;
- }
-
- entry = entry_create();
- entry->ike_sa_id = ike_sa_id;
- entry->ike_sa = ike_sa;
- segment = put_entry(this, entry);
- entry->checked_out = TRUE;
- unlock_single_segment(this, segment);
- return entry->ike_sa;
+ return ike_sa;
}
-/**
- * Implementation of of ike_sa_manager.checkout_by_message.
- */
-static ike_sa_t* checkout_by_message(private_ike_sa_manager_t* this,
- message_t *message)
+METHOD(ike_sa_manager_t, checkout_by_message, ike_sa_t*,
+ private_ike_sa_manager_t* this, message_t *message)
{
u_int segment;
entry_t *entry;
ike_sa_t *ike_sa = NULL;
- ike_sa_id_t *id = message->get_ike_sa_id(message);
+ ike_sa_id_t *id;
+ id = message->get_ike_sa_id(message);
id = id->clone(id);
id->switch_initiator(id);
DBG2(DBG_MGR, "checkout IKE_SA by message");
if (message->get_request(message) &&
- message->get_exchange_type(message) == IKE_SA_INIT)
+ message->get_exchange_type(message) == IKE_SA_INIT &&
+ this->hasher)
{
/* IKE_SA_INIT request. Check for an IKE_SA with such a message hash. */
chunk_t data, hash;
@@ -988,7 +1015,7 @@ static ike_sa_t* checkout_by_message(private_ike_sa_manager_t* this,
message->get_exchange_type(message) == IKE_SA_INIT)
{
/* no IKE_SA found, create a new one */
- id->set_responder_spi(id, get_next_spi(this));
+ id->set_responder_spi(id, get_spi(this));
entry = entry_create();
entry->ike_sa = ike_sa_create(id);
entry->ike_sa_id = id->clone(id);
@@ -1048,11 +1075,8 @@ static ike_sa_t* checkout_by_message(private_ike_sa_manager_t* this,
return ike_sa;
}
-/**
- * Implementation of of ike_sa_manager.checkout_by_config.
- */
-static ike_sa_t* checkout_by_config(private_ike_sa_manager_t *this,
- peer_cfg_t *peer_cfg)
+METHOD(ike_sa_manager_t, checkout_by_config, ike_sa_t*,
+ private_ike_sa_manager_t *this, peer_cfg_t *peer_cfg)
{
enumerator_t *enumerator;
entry_t *entry;
@@ -1107,11 +1131,8 @@ static ike_sa_t* checkout_by_config(private_ike_sa_manager_t *this,
return ike_sa;
}
-/**
- * Implementation of of ike_sa_manager.checkout_by_id.
- */
-static ike_sa_t* checkout_by_id(private_ike_sa_manager_t *this, u_int32_t id,
- bool child)
+METHOD(ike_sa_manager_t, checkout_by_id, ike_sa_t*,
+ private_ike_sa_manager_t *this, u_int32_t id, bool child)
{
enumerator_t *enumerator;
iterator_t *children;
@@ -1164,11 +1185,8 @@ static ike_sa_t* checkout_by_id(private_ike_sa_manager_t *this, u_int32_t id,
return ike_sa;
}
-/**
- * Implementation of of ike_sa_manager.checkout_by_name.
- */
-static ike_sa_t* checkout_by_name(private_ike_sa_manager_t *this, char *name,
- bool child)
+METHOD(ike_sa_manager_t, checkout_by_name, ike_sa_t*,
+ private_ike_sa_manager_t *this, char *name, bool child)
{
enumerator_t *enumerator;
iterator_t *children;
@@ -1233,20 +1251,15 @@ static bool enumerator_filter(private_ike_sa_manager_t *this,
return FALSE;
}
-/**
- * Implementation of ike_sa_manager_t.create_enumerator.
- */
-static enumerator_t *create_enumerator(private_ike_sa_manager_t* this)
+METHOD(ike_sa_manager_t, create_enumerator, enumerator_t*,
+ private_ike_sa_manager_t* this)
{
- return enumerator_create_filter(
- create_table_enumerator(this),
- (void*)enumerator_filter, this, NULL);
+ return enumerator_create_filter(create_table_enumerator(this),
+ (void*)enumerator_filter, this, NULL);
}
-/**
- * Implementation of ike_sa_manager_t.checkin.
- */
-static void checkin(private_ike_sa_manager_t *this, ike_sa_t *ike_sa)
+METHOD(ike_sa_manager_t, checkin, void,
+ private_ike_sa_manager_t *this, ike_sa_t *ike_sa)
{
/* to check the SA back in, we look for the pointer of the ike_sa
* in all entries.
@@ -1311,13 +1324,16 @@ static void checkin(private_ike_sa_manager_t *this, ike_sa_t *ike_sa)
segment = put_entry(this, entry);
}
- /* apply identities for duplicate test (only as responder) */
- if (!entry->ike_sa_id->is_initiator(entry->ike_sa_id) &&
- ike_sa->get_state(ike_sa) == IKE_ESTABLISHED &&
+ /* apply identities for duplicate test */
+ if (ike_sa->get_state(ike_sa) == IKE_ESTABLISHED &&
entry->my_id == NULL && entry->other_id == NULL)
{
entry->my_id = my_id->clone(my_id);
entry->other_id = other_id->clone(other_id);
+ if (!entry->other)
+ {
+ entry->other = other->clone(other);
+ }
put_connected_peers(this, entry);
}
@@ -1326,10 +1342,8 @@ static void checkin(private_ike_sa_manager_t *this, ike_sa_t *ike_sa)
charon->bus->set_sa(charon->bus, NULL);
}
-/**
- * Implementation of ike_sa_manager_t.checkin_and_destroy.
- */
-static void checkin_and_destroy(private_ike_sa_manager_t *this, ike_sa_t *ike_sa)
+METHOD(ike_sa_manager_t, checkin_and_destroy, void,
+ private_ike_sa_manager_t *this, ike_sa_t *ike_sa)
{
/* deletion is a bit complex, we must ensure that no thread is waiting for
* this SA.
@@ -1366,8 +1380,7 @@ static void checkin_and_destroy(private_ike_sa_manager_t *this, ike_sa_t *ike_sa
{
remove_half_open(this, entry);
}
- if (!entry->ike_sa_id->is_initiator(entry->ike_sa_id) &&
- entry->my_id && entry->other_id)
+ if (entry->my_id && entry->other_id)
{
remove_connected_peers(this, entry);
}
@@ -1384,11 +1397,8 @@ static void checkin_and_destroy(private_ike_sa_manager_t *this, ike_sa_t *ike_sa
charon->bus->set_sa(charon->bus, NULL);
}
-
-/**
- * Implementation of ike_sa_manager_t.check_uniqueness.
- */
-static bool check_uniqueness(private_ike_sa_manager_t *this, ike_sa_t *ike_sa)
+METHOD(ike_sa_manager_t, check_uniqueness, bool,
+ private_ike_sa_manager_t *this, ike_sa_t *ike_sa, bool force_replace)
{
bool cancel = FALSE;
peer_cfg_t *peer_cfg;
@@ -1402,7 +1412,7 @@ static bool check_uniqueness(private_ike_sa_manager_t *this, ike_sa_t *ike_sa)
peer_cfg = ike_sa->get_peer_cfg(ike_sa);
policy = peer_cfg->get_unique_policy(peer_cfg);
- if (policy == UNIQUE_NO)
+ if (policy == UNIQUE_NO && !force_replace)
{
return FALSE;
}
@@ -1416,12 +1426,16 @@ static bool check_uniqueness(private_ike_sa_manager_t *this, ike_sa_t *ike_sa)
lock = this->connected_peers_segments[segment & this->segment_mask].lock;
lock->read_lock(lock);
- if ((list = this->connected_peers_table[row]) != NULL)
+ list = this->connected_peers_table[row];
+ if (list)
{
connected_peers_t *current;
+ host_t *other_host;
+ other_host = ike_sa->get_other_host(ike_sa);
if (list->find_first(list, (linked_list_match_t)connected_peers_match,
- (void**)&current, me, other) == SUCCESS)
+ (void**)&current, me, other,
+ (uintptr_t)other_host->get_family(other_host)) == SUCCESS)
{
/* clone the list, so we can release the lock */
duplicate_ids = current->sas->clone_offset(current->sas,
@@ -1446,6 +1460,13 @@ static bool check_uniqueness(private_ike_sa_manager_t *this, ike_sa_t *ike_sa)
{
continue;
}
+ if (force_replace)
+ {
+ DBG1(DBG_IKE, "destroying duplicate IKE_SA for peer '%Y', "
+ "received INITIAL_CONTACT", other);
+ checkin_and_destroy(this, duplicate);
+ continue;
+ }
peer_cfg = duplicate->get_peer_cfg(duplicate);
if (peer_cfg && peer_cfg->equals(peer_cfg, ike_sa->get_peer_cfg(ike_sa)))
{
@@ -1490,21 +1511,49 @@ static bool check_uniqueness(private_ike_sa_manager_t *this, ike_sa_t *ike_sa)
return cancel;
}
-/**
- * Implementation of ike_sa_manager_t.get_half_open_count.
- */
-static int get_half_open_count(private_ike_sa_manager_t *this, host_t *ip)
+METHOD(ike_sa_manager_t, has_contact, bool,
+ private_ike_sa_manager_t *this, identification_t *me,
+ identification_t *other, int family)
+{
+ linked_list_t *list;
+ u_int row, segment;
+ rwlock_t *lock;
+ bool found = FALSE;
+
+ row = chunk_hash_inc(other->get_encoding(other),
+ chunk_hash(me->get_encoding(me))) & this->table_mask;
+ segment = row & this->segment_mask;
+ lock = this->connected_peers_segments[segment & this->segment_mask].lock;
+ lock->read_lock(lock);
+ list = this->connected_peers_table[row];
+ if (list)
+ {
+ if (list->find_first(list, (linked_list_match_t)connected_peers_match,
+ NULL, me, other, family) == SUCCESS)
+ {
+ found = TRUE;
+ }
+ }
+ lock->unlock(lock);
+
+ return found;
+}
+
+METHOD(ike_sa_manager_t, get_half_open_count, int,
+ private_ike_sa_manager_t *this, host_t *ip)
{
+ linked_list_t *list;
+ u_int segment, row;
+ rwlock_t *lock;
+ chunk_t addr;
int count = 0;
if (ip)
{
- linked_list_t *list;
- chunk_t addr = ip->get_address(ip);
- u_int row = chunk_hash(addr) & this->table_mask;
- u_int segment = row & this->segment_mask;
-
- rwlock_t *lock = this->half_open_segments[segment & this->segment_mask].lock;
+ addr = ip->get_address(ip);
+ row = chunk_hash(addr) & this->table_mask;
+ segment = row & this->segment_mask;
+ lock = this->half_open_segments[segment & this->segment_mask].lock;
lock->read_lock(lock);
if ((list = this->half_open_table[row]) != NULL)
{
@@ -1520,25 +1569,19 @@ static int get_half_open_count(private_ike_sa_manager_t *this, host_t *ip)
}
else
{
- u_int segment;
-
- for (segment = 0; segment < this->segment_count; ++segment)
+ for (segment = 0; segment < this->segment_count; segment++)
{
- rwlock_t *lock;
lock = this->half_open_segments[segment & this->segment_mask].lock;
lock->read_lock(lock);
count += this->half_open_segments[segment].count;
lock->unlock(lock);
}
}
-
return count;
}
-/**
- * Implementation of ike_sa_manager_t.flush.
- */
-static void flush(private_ike_sa_manager_t *this)
+METHOD(ike_sa_manager_t, flush, void,
+ private_ike_sa_manager_t *this)
{
/* destroy all list entries */
enumerator_t *enumerator;
@@ -1602,8 +1645,7 @@ static void flush(private_ike_sa_manager_t *this)
{
remove_half_open(this, entry);
}
- if (!entry->ike_sa_id->is_initiator(entry->ike_sa_id) &&
- entry->my_id && entry->other_id)
+ if (entry->my_id && entry->other_id)
{
remove_connected_peers(this, entry);
}
@@ -1615,37 +1657,26 @@ static void flush(private_ike_sa_manager_t *this)
unlock_all_segments(this);
this->rng->destroy(this->rng);
+ this->rng = NULL;
this->hasher->destroy(this->hasher);
+ this->hasher = NULL;
}
-/**
- * Implementation of ike_sa_manager_t.destroy.
- */
-static void destroy(private_ike_sa_manager_t *this)
+METHOD(ike_sa_manager_t, destroy, void,
+ private_ike_sa_manager_t *this)
{
u_int i;
- for (i = 0; i < this->table_size; ++i)
+ for (i = 0; i < this->table_size; i++)
{
- linked_list_t *list;
-
- if ((list = this->ike_sa_table[i]) != NULL)
- {
- list->destroy(list);
- }
- if ((list = this->half_open_table[i]) != NULL)
- {
- list->destroy(list);
- }
- if ((list = this->connected_peers_table[i]) != NULL)
- {
- list->destroy(list);
- }
+ DESTROY_IF(this->ike_sa_table[i]);
+ DESTROY_IF(this->half_open_table[i]);
+ DESTROY_IF(this->connected_peers_table[i]);
}
free(this->ike_sa_table);
free(this->half_open_table);
free(this->connected_peers_table);
- for (i = 0; i < this->segment_count; ++i)
+ for (i = 0; i < this->segment_count; i++)
{
this->segments[i].mutex->destroy(this->segments[i].mutex);
this->half_open_segments[i].lock->destroy(this->half_open_segments[i].lock);
@@ -1681,25 +1712,28 @@ static u_int get_nearest_powerof2(u_int n)
*/
ike_sa_manager_t *ike_sa_manager_create()
{
+ private_ike_sa_manager_t *this;
u_int i;
- private_ike_sa_manager_t *this = malloc_thing(private_ike_sa_manager_t);
-
- /* assign public functions */
- this->public.flush = (void(*)(ike_sa_manager_t*))flush;
- this->public.destroy = (void(*)(ike_sa_manager_t*))destroy;
- this->public.checkout = (ike_sa_t*(*)(ike_sa_manager_t*, ike_sa_id_t*))checkout;
- this->public.checkout_new = (ike_sa_t*(*)(ike_sa_manager_t*,bool))checkout_new;
- this->public.checkout_by_message = (ike_sa_t*(*)(ike_sa_manager_t*,message_t*))checkout_by_message;
- this->public.checkout_by_config = (ike_sa_t*(*)(ike_sa_manager_t*,peer_cfg_t*))checkout_by_config;
- this->public.checkout_by_id = (ike_sa_t*(*)(ike_sa_manager_t*,u_int32_t,bool))checkout_by_id;
- this->public.checkout_by_name = (ike_sa_t*(*)(ike_sa_manager_t*,char*,bool))checkout_by_name;
- this->public.check_uniqueness = (bool(*)(ike_sa_manager_t*, ike_sa_t *ike_sa))check_uniqueness;
- this->public.create_enumerator = (enumerator_t*(*)(ike_sa_manager_t*))create_enumerator;
- this->public.checkin = (void(*)(ike_sa_manager_t*,ike_sa_t*))checkin;
- this->public.checkin_and_destroy = (void(*)(ike_sa_manager_t*,ike_sa_t*))checkin_and_destroy;
- this->public.get_half_open_count = (int(*)(ike_sa_manager_t*,host_t*))get_half_open_count;
-
- /* initialize private variables */
+
+ INIT(this,
+ .public = {
+ .checkout = _checkout,
+ .checkout_new = _checkout_new,
+ .checkout_by_message = _checkout_by_message,
+ .checkout_by_config = _checkout_by_config,
+ .checkout_by_id = _checkout_by_id,
+ .checkout_by_name = _checkout_by_name,
+ .check_uniqueness = _check_uniqueness,
+ .has_contact = _has_contact,
+ .create_enumerator = _create_enumerator,
+ .checkin = _checkin,
+ .checkin_and_destroy = _checkin_and_destroy,
+ .get_half_open_count = _get_half_open_count,
+ .flush = _flush,
+ .destroy = _destroy,
+ },
+ );
+
this->hasher = lib->crypto->create_hasher(lib->crypto, HASH_PREFERRED);
if (this->hasher == NULL)
{
@@ -1715,6 +1749,7 @@ ike_sa_manager_t *ike_sa_manager_create()
free(this);
return NULL;
}
+
this->table_size = get_nearest_powerof2(lib->settings->get_int(lib->settings,
"charon.ikesa_table_size", DEFAULT_HASHTABLE_SIZE));
this->table_size = max(1, min(this->table_size, MAX_HASHTABLE_SIZE));
@@ -1724,11 +1759,10 @@ ike_sa_manager_t *ike_sa_manager_create()
"charon.ikesa_table_segments", DEFAULT_SEGMENT_COUNT));
this->segment_count = max(1, min(this->segment_count, this->table_size));
this->segment_mask = this->segment_count - 1;
-
this->ike_sa_table = calloc(this->table_size, sizeof(linked_list_t*));
this->segments = (segment_t*)calloc(this->segment_count, sizeof(segment_t));
- for (i = 0; i < this->segment_count; ++i)
+ for (i = 0; i < this->segment_count; i++)
{
this->segments[i].mutex = mutex_create(MUTEX_TYPE_RECURSIVE);
this->segments[i].count = 0;
@@ -1737,7 +1771,7 @@ ike_sa_manager_t *ike_sa_manager_create()
/* we use the same table parameters for the table to track half-open SAs */
this->half_open_table = calloc(this->table_size, sizeof(linked_list_t*));
this->half_open_segments = calloc(this->segment_count, sizeof(shareable_segment_t));
- for (i = 0; i < this->segment_count; ++i)
+ for (i = 0; i < this->segment_count; i++)
{
this->half_open_segments[i].lock = rwlock_create(RWLOCK_TYPE_DEFAULT);
this->half_open_segments[i].count = 0;
@@ -1746,7 +1780,7 @@ ike_sa_manager_t *ike_sa_manager_create()
/* also for the hash table used for duplicate tests */
this->connected_peers_table = calloc(this->table_size, sizeof(linked_list_t*));
this->connected_peers_segments = calloc(this->segment_count, sizeof(shareable_segment_t));
- for (i = 0; i < this->segment_count; ++i)
+ for (i = 0; i < this->segment_count; i++)
{
this->connected_peers_segments[i].lock = rwlock_create(RWLOCK_TYPE_DEFAULT);
this->connected_peers_segments[i].count = 0;