diff options
Diffstat (limited to 'src/libcharon/sa/ike_sa_manager.c')
-rw-r--r-- | src/libcharon/sa/ike_sa_manager.c | 474 |
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, ¤t)) { 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**)¤t, 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**)¤t, &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, ¤t)) { 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**)¤t, entry->my_id, entry->other_id) == SUCCESS) + (void**)¤t, 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, ¤t)) { - 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**)¤t, me, other) == SUCCESS) + (void**)¤t, 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; |