diff options
Diffstat (limited to 'src')
24 files changed, 1527 insertions, 683 deletions
diff --git a/src/libcharon/config/proposal.c b/src/libcharon/config/proposal.c index 4803c7be2..a927a1f75 100644 --- a/src/libcharon/config/proposal.c +++ b/src/libcharon/config/proposal.c @@ -19,7 +19,7 @@ #include "proposal.h" #include <daemon.h> -#include <collections/linked_list.h> +#include <collections/array.h> #include <utils/identification.h> #include <crypto/transform.h> @@ -36,7 +36,6 @@ ENUM(protocol_id_names, PROTO_NONE, PROTO_IPCOMP, ); typedef struct private_proposal_t private_proposal_t; -typedef struct algorithm_t algorithm_t; /** * Private data of an proposal_t object @@ -54,29 +53,9 @@ struct private_proposal_t { protocol_id_t protocol; /** - * priority ordered list of encryption algorithms + * Priority ordered list of transforms, as entry_t */ - linked_list_t *encryption_algos; - - /** - * priority ordered list of integrity algorithms - */ - linked_list_t *integrity_algos; - - /** - * priority ordered list of pseudo random functions - */ - linked_list_t *prf_algos; - - /** - * priority ordered list of dh groups - */ - linked_list_t *dh_groups; - - /** - * priority ordered list of extended sequence number flags - */ - linked_list_t *esns; + array_t *transforms; /** * senders SPI @@ -92,68 +71,47 @@ struct private_proposal_t { /** * Struct used to store different kinds of algorithms. */ -struct algorithm_t { - /** - * Value from an encryption_algorithm_t/integrity_algorithm_t/... - */ - u_int16_t algorithm; - - /** - * the associated key size in bits, or zero if not needed - */ +typedef struct { + /** Type of the transform */ + transform_type_t type; + /** algorithm identifier */ + u_int16_t alg; + /** key size in bits, or zero if not needed */ u_int16_t key_size; -}; - -/** - * Add algorithm/keysize to a algorithm list - */ -static void add_algo(linked_list_t *list, u_int16_t algo, u_int16_t key_size) -{ - algorithm_t *algo_key; - - algo_key = malloc_thing(algorithm_t); - algo_key->algorithm = algo; - algo_key->key_size = key_size; - list->insert_last(list, (void*)algo_key); -} +} entry_t; METHOD(proposal_t, add_algorithm, void, private_proposal_t *this, transform_type_t type, - u_int16_t algo, u_int16_t key_size) + u_int16_t alg, u_int16_t key_size) { - switch (type) - { - case ENCRYPTION_ALGORITHM: - add_algo(this->encryption_algos, algo, key_size); - break; - case INTEGRITY_ALGORITHM: - add_algo(this->integrity_algos, algo, key_size); - break; - case PSEUDO_RANDOM_FUNCTION: - add_algo(this->prf_algos, algo, key_size); - break; - case DIFFIE_HELLMAN_GROUP: - add_algo(this->dh_groups, algo, 0); - break; - case EXTENDED_SEQUENCE_NUMBERS: - add_algo(this->esns, algo, 0); - break; - default: - break; - } + entry_t entry = { + .type = type, + .alg = alg, + .key_size = key_size, + }; + + array_insert(this->transforms, ARRAY_TAIL, &entry); } /** * filter function for peer configs */ -static bool alg_filter(void *null, algorithm_t **in, u_int16_t *alg, +static bool alg_filter(uintptr_t type, entry_t **in, u_int16_t *alg, void **unused, u_int16_t *key_size) { - algorithm_t *algo = *in; - *alg = algo->algorithm; + entry_t *entry = *in; + + if (entry->type != type) + { + return FALSE; + } + if (alg) + { + *alg = entry->alg; + } if (key_size) { - *key_size = algo->key_size; + *key_size = entry->key_size; } return TRUE; } @@ -161,30 +119,9 @@ static bool alg_filter(void *null, algorithm_t **in, u_int16_t *alg, METHOD(proposal_t, create_enumerator, enumerator_t*, private_proposal_t *this, transform_type_t type) { - linked_list_t *list; - - switch (type) - { - case ENCRYPTION_ALGORITHM: - list = this->encryption_algos; - break; - case INTEGRITY_ALGORITHM: - list = this->integrity_algos; - break; - case PSEUDO_RANDOM_FUNCTION: - list = this->prf_algos; - break; - case DIFFIE_HELLMAN_GROUP: - list = this->dh_groups; - break; - case EXTENDED_SEQUENCE_NUMBERS: - list = this->esns; - break; - default: - return NULL; - } - return enumerator_create_filter(list->create_enumerator(list), - (void*)alg_filter, NULL, NULL); + return enumerator_create_filter( + array_create_enumerator(this->transforms), + (void*)alg_filter, (void*)(uintptr_t)type, NULL); } METHOD(proposal_t, get_algorithm, bool, @@ -200,84 +137,91 @@ METHOD(proposal_t, get_algorithm, bool, found = TRUE; } enumerator->destroy(enumerator); + return found; } METHOD(proposal_t, has_dh_group, bool, private_proposal_t *this, diffie_hellman_group_t group) { - bool result = FALSE; + bool found = FALSE, any = FALSE; + enumerator_t *enumerator; + u_int16_t current; - if (this->dh_groups->get_count(this->dh_groups)) + enumerator = create_enumerator(this, DIFFIE_HELLMAN_GROUP); + while (enumerator->enumerate(enumerator, ¤t, NULL)) { - algorithm_t *current; - enumerator_t *enumerator; - - enumerator = this->dh_groups->create_enumerator(this->dh_groups); - while (enumerator->enumerate(enumerator, (void**)¤t)) + any = TRUE; + if (current == group) { - if (current->algorithm == group) - { - result = TRUE; - break; - } + found = TRUE; + break; } - enumerator->destroy(enumerator); } - else if (group == MODP_NONE) + enumerator->destroy(enumerator); + + if (!any && group == MODP_NONE) { - result = TRUE; + found = TRUE; } - return result; + return found; } METHOD(proposal_t, strip_dh, void, private_proposal_t *this, diffie_hellman_group_t keep) { enumerator_t *enumerator; - algorithm_t *alg; + entry_t *entry; - enumerator = this->dh_groups->create_enumerator(this->dh_groups); - while (enumerator->enumerate(enumerator, (void**)&alg)) + enumerator = array_create_enumerator(this->transforms); + while (enumerator->enumerate(enumerator, &entry)) { - if (alg->algorithm != keep) + if (entry->type == DIFFIE_HELLMAN_GROUP && + entry->alg != keep) { - this->dh_groups->remove_at(this->dh_groups, enumerator); - free(alg); + array_remove_at(this->transforms, enumerator); } } enumerator->destroy(enumerator); } /** - * Find a matching alg/keysize in two linked lists + * Select a matching proposal from this and other, insert into selected. */ -static bool select_algo(linked_list_t *first, linked_list_t *second, bool priv, - bool *add, u_int16_t *alg, size_t *key_size) +static bool select_algo(private_proposal_t *this, proposal_t *other, + proposal_t *selected, transform_type_t type, bool priv) { enumerator_t *e1, *e2; - algorithm_t *alg1, *alg2; + u_int16_t alg1, alg2, ks1, ks2; + bool found = FALSE; - /* if in both are zero algorithms specified, we HAVE a match */ - if (first->get_count(first) == 0 && second->get_count(second) == 0) + if (type == INTEGRITY_ALGORITHM && + selected->get_algorithm(selected, ENCRYPTION_ALGORITHM, &alg1, NULL) && + encryption_algorithm_is_aead(alg1)) { - *add = FALSE; + /* no integrity algorithm required, we have an AEAD */ return TRUE; } - e1 = first->create_enumerator(first); - e2 = second->create_enumerator(second); + e1 = create_enumerator(this, type); + e2 = other->create_enumerator(other, type); + if (!e1->enumerate(e1, NULL, NULL) && !e2->enumerate(e2, NULL, NULL)) + { + found = TRUE; + } + + e1->destroy(e1); + e1 = create_enumerator(this, type); /* compare algs, order of algs in "first" is preferred */ - while (e1->enumerate(e1, &alg1)) + while (!found && e1->enumerate(e1, &alg1, &ks1)) { e2->destroy(e2); - e2 = second->create_enumerator(second); - while (e2->enumerate(e2, &alg2)) + e2 = other->create_enumerator(other, type); + while (e2->enumerate(e2, &alg2, &ks2)) { - if (alg1->algorithm == alg2->algorithm && - alg1->key_size == alg2->key_size) + if (alg1 == alg2 && ks1 == ks2) { - if (!priv && alg1->algorithm >= 1024) + if (!priv && alg1 >= 1024) { /* accept private use algorithms only if requested */ DBG1(DBG_CFG, "an algorithm from private space would match, " @@ -285,132 +229,52 @@ static bool select_algo(linked_list_t *first, linked_list_t *second, bool priv, continue; } /* ok, we have an algorithm */ - *alg = alg1->algorithm; - *key_size = alg1->key_size; - *add = TRUE; - e1->destroy(e1); - e2->destroy(e2); - return TRUE; + selected->add_algorithm(selected, type, alg1, ks1); + found = TRUE; + break; } } } /* no match in all comparisons */ e1->destroy(e1); e2->destroy(e2); - return FALSE; + + if (!found) + { + DBG2(DBG_CFG, " no acceptable %N found", transform_type_names, type); + } + return found; } METHOD(proposal_t, select_proposal, proposal_t*, - private_proposal_t *this, proposal_t *other_pub, bool private) + private_proposal_t *this, proposal_t *other, bool private) { - private_proposal_t *other = (private_proposal_t*)other_pub; proposal_t *selected; - u_int16_t algo; - size_t key_size; - bool add; DBG2(DBG_CFG, "selecting proposal:"); - /* check protocol */ - if (this->protocol != other->protocol) + if (this->protocol != other->get_protocol(other)) { DBG2(DBG_CFG, " protocol mismatch, skipping"); return NULL; } - selected = proposal_create(this->protocol, other->number); + selected = proposal_create(this->protocol, other->get_number(other)); - /* select encryption algorithm */ - if (select_algo(this->encryption_algos, other->encryption_algos, private, - &add, &algo, &key_size)) - { - if (add) - { - selected->add_algorithm(selected, ENCRYPTION_ALGORITHM, - algo, key_size); - } - } - else - { - selected->destroy(selected); - DBG2(DBG_CFG, " no acceptable %N found", - transform_type_names, ENCRYPTION_ALGORITHM); - return NULL; - } - /* select integrity algorithm */ - if (!encryption_algorithm_is_aead(algo)) - { - if (select_algo(this->integrity_algos, other->integrity_algos, private, - &add, &algo, &key_size)) - { - if (add) - { - selected->add_algorithm(selected, INTEGRITY_ALGORITHM, - algo, key_size); - } - } - else - { - selected->destroy(selected); - DBG2(DBG_CFG, " no acceptable %N found", - transform_type_names, INTEGRITY_ALGORITHM); - return NULL; - } - } - /* select prf algorithm */ - if (select_algo(this->prf_algos, other->prf_algos, private, - &add, &algo, &key_size)) - { - if (add) - { - selected->add_algorithm(selected, PSEUDO_RANDOM_FUNCTION, - algo, key_size); - } - } - else - { - selected->destroy(selected); - DBG2(DBG_CFG, " no acceptable %N found", - transform_type_names, PSEUDO_RANDOM_FUNCTION); - return NULL; - } - /* select a DH-group */ - if (select_algo(this->dh_groups, other->dh_groups, private, - &add, &algo, &key_size)) - { - if (add) - { - selected->add_algorithm(selected, DIFFIE_HELLMAN_GROUP, algo, 0); - } - } - else + if (!select_algo(this, other, selected, ENCRYPTION_ALGORITHM, private) || + !select_algo(this, other, selected, PSEUDO_RANDOM_FUNCTION, private) || + !select_algo(this, other, selected, INTEGRITY_ALGORITHM, private) || + !select_algo(this, other, selected, DIFFIE_HELLMAN_GROUP, private) || + !select_algo(this, other, selected, EXTENDED_SEQUENCE_NUMBERS, private)) { selected->destroy(selected); - DBG2(DBG_CFG, " no acceptable %N found", - transform_type_names, DIFFIE_HELLMAN_GROUP); - return NULL; - } - /* select if we use ESNs (has no private use space) */ - if (select_algo(this->esns, other->esns, TRUE, &add, &algo, &key_size)) - { - if (add) - { - selected->add_algorithm(selected, EXTENDED_SEQUENCE_NUMBERS, algo, 0); - } - } - else - { - selected->destroy(selected); - DBG2(DBG_CFG, " no acceptable %N found", - transform_type_names, EXTENDED_SEQUENCE_NUMBERS); return NULL; } + DBG2(DBG_CFG, " proposal matches"); - /* apply SPI from "other" */ - selected->set_spi(selected, other->spi); + selected->set_spi(selected, other->get_spi(other)); - /* everything matched, return new proposal */ return selected; } @@ -433,50 +297,39 @@ METHOD(proposal_t, get_spi, u_int64_t, } /** - * Clone a algorithm list - */ -static void clone_algo_list(linked_list_t *list, linked_list_t *clone_list) -{ - algorithm_t *algo, *clone_algo; - enumerator_t *enumerator; - - enumerator = list->create_enumerator(list); - while (enumerator->enumerate(enumerator, &algo)) - { - clone_algo = malloc_thing(algorithm_t); - memcpy(clone_algo, algo, sizeof(algorithm_t)); - clone_list->insert_last(clone_list, (void*)clone_algo); - } - enumerator->destroy(enumerator); -} - -/** - * check if an algorithm list equals + * Check if two proposals have the same algorithms for a given transform type */ -static bool algo_list_equals(linked_list_t *l1, linked_list_t *l2) +static bool algo_list_equals(private_proposal_t *this, proposal_t *other, + transform_type_t type) { enumerator_t *e1, *e2; - algorithm_t *alg1, *alg2; + u_int16_t alg1, alg2, ks1, ks2; bool equals = TRUE; - if (l1->get_count(l1) != l2->get_count(l2)) + e1 = create_enumerator(this, type); + e2 = other->create_enumerator(other, type); + while (e1->enumerate(e1, &alg1, &ks1)) { - return FALSE; - } - - e1 = l1->create_enumerator(l1); - e2 = l2->create_enumerator(l2); - while (e1->enumerate(e1, &alg1) && e2->enumerate(e2, &alg2)) - { - if (alg1->algorithm != alg2->algorithm || - alg1->key_size != alg2->key_size) + if (!e2->enumerate(e2, &alg2, &ks2)) { + /* this has more algs */ equals = FALSE; break; } + if (alg1 != alg2 || ks1 != ks2) + { + equals = FALSE; + break; + } + } + if (e2->enumerate(e2, &alg2, ks2)) + { + /* other has more algs */ + equals = FALSE; } e1->destroy(e1); e2->destroy(e2); + return equals; } @@ -487,33 +340,35 @@ METHOD(proposal_t, get_number, u_int, } METHOD(proposal_t, equals, bool, - private_proposal_t *this, proposal_t *other_pub) + private_proposal_t *this, proposal_t *other) { - private_proposal_t *other = (private_proposal_t*)other_pub; - - if (this == other) + if (&this->public == other) { return TRUE; } return ( - algo_list_equals(this->encryption_algos, other->encryption_algos) && - algo_list_equals(this->integrity_algos, other->integrity_algos) && - algo_list_equals(this->prf_algos, other->prf_algos) && - algo_list_equals(this->dh_groups, other->dh_groups) && - algo_list_equals(this->esns, other->esns)); + algo_list_equals(this, other, ENCRYPTION_ALGORITHM) && + algo_list_equals(this, other, INTEGRITY_ALGORITHM) && + algo_list_equals(this, other, PSEUDO_RANDOM_FUNCTION) && + algo_list_equals(this, other, DIFFIE_HELLMAN_GROUP) && + algo_list_equals(this, other, EXTENDED_SEQUENCE_NUMBERS)); } METHOD(proposal_t, clone_, proposal_t*, private_proposal_t *this) { private_proposal_t *clone; + enumerator_t *enumerator; + entry_t *entry; clone = (private_proposal_t*)proposal_create(this->protocol, 0); - clone_algo_list(this->encryption_algos, clone->encryption_algos); - clone_algo_list(this->integrity_algos, clone->integrity_algos); - clone_algo_list(this->prf_algos, clone->prf_algos); - clone_algo_list(this->dh_groups, clone->dh_groups); - clone_algo_list(this->esns, clone->esns); + + enumerator = array_create_enumerator(this->transforms); + while (enumerator->enumerate(enumerator, &entry)) + { + array_insert(clone->transforms, ARRAY_TAIL, entry); + } + enumerator->destroy(enumerator); clone->spi = this->spi; clone->number = this->number; @@ -544,34 +399,40 @@ static const struct { static void check_proposal(private_proposal_t *this) { enumerator_t *e; - algorithm_t *alg; + entry_t *entry; + u_int16_t alg, ks; bool all_aead = TRUE; int i; - if (this->protocol == PROTO_IKE && - this->prf_algos->get_count(this->prf_algos) == 0) - { /* No explicit PRF found. We assume the same algorithm as used - * for integrity checking */ - e = this->integrity_algos->create_enumerator(this->integrity_algos); - while (e->enumerate(e, &alg)) + if (this->protocol == PROTO_IKE) + { + e = create_enumerator(this, PSEUDO_RANDOM_FUNCTION); + if (!e->enumerate(e, &alg, &ks)) { - for (i = 0; i < countof(integ_prf_map); i++) + /* No explicit PRF found. We assume the same algorithm as used + * for integrity checking */ + e->destroy(e); + e = create_enumerator(this, INTEGRITY_ALGORITHM); + while (e->enumerate(e, &alg, &ks)) { - if (alg->algorithm == integ_prf_map[i].integ) + for (i = 0; i < countof(integ_prf_map); i++) { - add_algorithm(this, PSEUDO_RANDOM_FUNCTION, - integ_prf_map[i].prf, 0); - break; + if (alg == integ_prf_map[i].integ) + { + add_algorithm(this, PSEUDO_RANDOM_FUNCTION, + integ_prf_map[i].prf, 0); + break; + } } } } e->destroy(e); } - e = this->encryption_algos->create_enumerator(this->encryption_algos); - while (e->enumerate(e, &alg)) + e = create_enumerator(this, ENCRYPTION_ALGORITHM); + while (e->enumerate(e, &alg, &ks)) { - if (!encryption_algorithm_is_aead(alg->algorithm)) + if (!encryption_algorithm_is_aead(alg)) { all_aead = FALSE; break; @@ -581,24 +442,30 @@ static void check_proposal(private_proposal_t *this) if (all_aead) { - /* if all encryption algorithms in the proposal are authenticated encryption - * algorithms we MUST NOT propose any integrity algorithms */ - while (this->integrity_algos->remove_last(this->integrity_algos, - (void**)&alg) == SUCCESS) + /* if all encryption algorithms in the proposal are AEADs, + * we MUST NOT propose any integrity algorithms */ + e = array_create_enumerator(this->transforms); + while (e->enumerate(e, &entry)) { - free(alg); + if (entry->type == INTEGRITY_ALGORITHM) + { + array_remove_at(this->transforms, e); + } } + e->destroy(e); } if (this->protocol == PROTO_AH || this->protocol == PROTO_ESP) { - e = this->esns->create_enumerator(this->esns); - if (!e->enumerate(e, &alg)) + e = create_enumerator(this, EXTENDED_SEQUENCE_NUMBERS); + if (!e->enumerate(e, NULL, NULL)) { /* ESN not specified, assume not supported */ add_algorithm(this, EXTENDED_SEQUENCE_NUMBERS, NO_EXT_SEQ_NUMBERS, 0); } e->destroy(e); } + + array_compress(this->transforms); } /** @@ -704,11 +571,7 @@ int proposal_printf_hook(printf_hook_data_t *data, printf_hook_spec_t *spec, METHOD(proposal_t, destroy, void, private_proposal_t *this) { - this->encryption_algos->destroy_function(this->encryption_algos, free); - this->integrity_algos->destroy_function(this->integrity_algos, free); - this->prf_algos->destroy_function(this->prf_algos, free); - this->dh_groups->destroy_function(this->dh_groups, free); - this->esns->destroy_function(this->esns, free); + array_destroy(this->transforms); free(this); } @@ -737,11 +600,7 @@ proposal_t *proposal_create(protocol_id_t protocol, u_int number) }, .protocol = protocol, .number = number, - .encryption_algos = linked_list_create(), - .integrity_algos = linked_list_create(), - .prf_algos = linked_list_create(), - .dh_groups = linked_list_create(), - .esns = linked_list_create(), + .transforms = array_create(sizeof(entry_t), 0), ); return &this->public; diff --git a/src/libcharon/plugins/farp/farp_listener.c b/src/libcharon/plugins/farp/farp_listener.c index 81d5d2405..87c84359c 100644 --- a/src/libcharon/plugins/farp/farp_listener.c +++ b/src/libcharon/plugins/farp/farp_listener.c @@ -58,19 +58,30 @@ METHOD(listener_t, child_updown, bool, bool up) { enumerator_t *enumerator; + traffic_selector_t *ts; entry_t *entry; if (up) { INIT(entry, - .local = child_sa->get_traffic_selectors(child_sa, TRUE), - .remote = child_sa->get_traffic_selectors(child_sa, FALSE), + .local = linked_list_create(), + .remote = linked_list_create(), .reqid = child_sa->get_reqid(child_sa), ); - entry->local = entry->local->clone_offset(entry->local, - offsetof(traffic_selector_t, clone)); - entry->remote = entry->remote->clone_offset(entry->remote, - offsetof(traffic_selector_t, clone)); + + enumerator = child_sa->create_ts_enumerator(child_sa, TRUE); + while (enumerator->enumerate(enumerator, &ts)) + { + entry->local->insert_last(entry->local, ts->clone(ts)); + } + enumerator->destroy(enumerator); + + enumerator = child_sa->create_ts_enumerator(child_sa, FALSE); + while (enumerator->enumerate(enumerator, &ts)) + { + entry->remote->insert_last(entry->remote, ts->clone(ts)); + } + enumerator->destroy(enumerator); this->lock->write_lock(this->lock); this->entries->insert_last(this->entries, entry); @@ -160,4 +171,3 @@ farp_listener_t *farp_listener_create() return &this->public; } - diff --git a/src/libcharon/plugins/ha/ha_child.c b/src/libcharon/plugins/ha/ha_child.c index 707add94d..c166d72ac 100644 --- a/src/libcharon/plugins/ha/ha_child.c +++ b/src/libcharon/plugins/ha/ha_child.c @@ -103,18 +103,22 @@ METHOD(listener_t, child_keys, bool, chunk_clear(&secret); } - local_ts = child_sa->get_traffic_selectors(child_sa, TRUE); - enumerator = local_ts->create_enumerator(local_ts); + local_ts = linked_list_create(); + remote_ts = linked_list_create(); + + enumerator = child_sa->create_ts_enumerator(child_sa, TRUE); while (enumerator->enumerate(enumerator, &ts)) { m->add_attribute(m, HA_LOCAL_TS, ts); + local_ts->insert_last(local_ts, ts); } enumerator->destroy(enumerator); - remote_ts = child_sa->get_traffic_selectors(child_sa, FALSE); - enumerator = remote_ts->create_enumerator(remote_ts); + + enumerator = child_sa->create_ts_enumerator(child_sa, FALSE); while (enumerator->enumerate(enumerator, &ts)) { m->add_attribute(m, HA_REMOTE_TS, ts); + remote_ts->insert_last(remote_ts, ts); } enumerator->destroy(enumerator); @@ -128,6 +132,9 @@ METHOD(listener_t, child_keys, bool, seg_i, this->segments->is_active(this->segments, seg_i) ? "*" : "", seg_o, this->segments->is_active(this->segments, seg_o) ? "*" : ""); + local_ts->destroy(local_ts); + remote_ts->destroy(remote_ts); + this->socket->push(this->socket, m); m->destroy(m); @@ -195,4 +202,3 @@ ha_child_t *ha_child_create(ha_socket_t *socket, ha_tunnel_t *tunnel, return &this->public; } - diff --git a/src/libcharon/plugins/smp/smp.c b/src/libcharon/plugins/smp/smp.c index d13b82216..123608819 100644 --- a/src/libcharon/plugins/smp/smp.c +++ b/src/libcharon/plugins/smp/smp.c @@ -165,8 +165,10 @@ static void write_childend(xmlTextWriterPtr writer, child_sa_t *child, bool loca xmlTextWriterWriteFormatElement(writer, "spi", "%x", htonl(child->get_spi(child, local))); - list = child->get_traffic_selectors(child, local); + list = linked_list_create_from_enumerator( + child->create_ts_enumerator(child, local)); write_networks(writer, "networks", list); + list->destroy(list); } /** diff --git a/src/libcharon/plugins/stroke/stroke_list.c b/src/libcharon/plugins/stroke/stroke_list.c index e76afec68..e81f3fc32 100644 --- a/src/libcharon/plugins/stroke/stroke_list.c +++ b/src/libcharon/plugins/stroke/stroke_list.c @@ -207,8 +207,10 @@ static void log_child_sa(FILE *out, child_sa_t *child_sa, bool all) time_t use_in, use_out, rekey, now; u_int64_t bytes_in, bytes_out, packets_in, packets_out; proposal_t *proposal; - child_cfg_t *config = child_sa->get_config(child_sa); + linked_list_t *my_ts, *other_ts; + child_cfg_t *config; + config = child_sa->get_config(child_sa); now = time_monotonic(NULL); fprintf(out, "%12s{%d}: %N, %N%s", @@ -319,10 +321,15 @@ static void log_child_sa(FILE *out, child_sa_t *child_sa, bool all) fprintf(out, ", expires in %V", &now, &rekey); } + 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)); fprintf(out, "\n%12s{%d}: %#R=== %#R\n", child_sa->get_name(child_sa), child_sa->get_reqid(child_sa), - child_sa->get_traffic_selectors(child_sa, TRUE), - child_sa->get_traffic_selectors(child_sa, FALSE)); + my_ts, other_ts); + my_ts->destroy(my_ts); + other_ts->destroy(other_ts); } /** diff --git a/src/libcharon/plugins/uci/uci_control.c b/src/libcharon/plugins/uci/uci_control.c index 53221b786..cebc389e7 100644 --- a/src/libcharon/plugins/uci/uci_control.c +++ b/src/libcharon/plugins/uci/uci_control.c @@ -72,6 +72,7 @@ static void write_fifo(private_uci_control_t *this, char *format, ...) static void status(private_uci_control_t *this, char *name) { enumerator_t *configs, *sas, *children; + linked_list_t *list; ike_sa_t *ike_sa; child_sa_t *child_sa; peer_cfg_t *peer_cfg; @@ -108,8 +109,10 @@ static void status(private_uci_control_t *this, char *name) children = ike_sa->create_child_sa_enumerator(ike_sa); while (children->enumerate(children, (void**)&child_sa)) { - fprintf(out, "%#R", - child_sa->get_traffic_selectors(child_sa, FALSE)); + list = linked_list_create_from_enumerator( + child_sa->create_ts_enumerator(child_sa, FALSE)); + fprintf(out, "%#R", list); + list->destroy(list); } children->destroy(children); fprintf(out, "\n"); @@ -296,4 +299,3 @@ uci_control_t *uci_control_create() } return &this->public; } - diff --git a/src/libcharon/sa/child_sa.c b/src/libcharon/sa/child_sa.c index 1069b2d91..46e4b6f7b 100644 --- a/src/libcharon/sa/child_sa.c +++ b/src/libcharon/sa/child_sa.c @@ -25,6 +25,7 @@ #include <hydra.h> #include <daemon.h> +#include <collections/array.h> ENUM(child_sa_state_names, CHILD_CREATED, CHILD_DESTROYING, "CREATED", @@ -79,14 +80,14 @@ struct private_child_sa_t { u_int16_t other_cpi; /** - * List for local traffic selectors + * Array for local traffic selectors */ - linked_list_t *my_ts; + array_t *my_ts; /** - * List for remote traffic selectors + * Array for remote traffic selectors */ - linked_list_t *other_ts; + array_t *other_ts; /** * Protocol used to protect this SA, ESP|AH @@ -331,10 +332,14 @@ METHOD(child_sa_t, set_proposal, void, this->proposal = proposal->clone(proposal); } -METHOD(child_sa_t, get_traffic_selectors, linked_list_t*, - private_child_sa_t *this, bool local) +METHOD(child_sa_t, create_ts_enumerator, enumerator_t*, + private_child_sa_t *this, bool local) { - return local ? this->my_ts : this->other_ts; + if (local) + { + return array_create_enumerator(this->my_ts); + } + return array_create_enumerator(this->other_ts); } typedef struct policy_enumerator_t policy_enumerator_t; @@ -349,8 +354,8 @@ struct policy_enumerator_t { enumerator_t *mine; /** enumerator over others TS */ enumerator_t *other; - /** list of others TS, to recreate enumerator */ - linked_list_t *list; + /** array of others TS, to recreate enumerator */ + array_t *array; /** currently enumerating TS for "me" side */ traffic_selector_t *ts; }; @@ -366,7 +371,7 @@ METHOD(enumerator_t, policy_enumerate, bool, if (!this->other->enumerate(this->other, &other_ts)) { /* end of others list, restart with new of mine */ this->other->destroy(this->other); - this->other = this->list->create_enumerator(this->list); + this->other = array_create_enumerator(this->array); this->ts = NULL; continue; } @@ -405,9 +410,9 @@ METHOD(child_sa_t, create_policy_enumerator, enumerator_t*, .enumerate = (void*)_policy_enumerate, .destroy = _policy_destroy, }, - .mine = this->my_ts->create_enumerator(this->my_ts), - .other = this->other_ts->create_enumerator(this->other_ts), - .list = this->other_ts, + .mine = array_create_enumerator(this->my_ts), + .other = array_create_enumerator(this->other_ts), + .array = this->other_ts, .ts = NULL, ); @@ -772,13 +777,13 @@ METHOD(child_sa_t, add_policies, status_t, enumerator = my_ts_list->create_enumerator(my_ts_list); while (enumerator->enumerate(enumerator, &my_ts)) { - this->my_ts->insert_last(this->my_ts, my_ts->clone(my_ts)); + array_insert(this->my_ts, ARRAY_TAIL, my_ts->clone(my_ts)); } enumerator->destroy(enumerator); enumerator = other_ts_list->create_enumerator(other_ts_list); while (enumerator->enumerate(enumerator, &other_ts)) { - this->other_ts->insert_last(this->other_ts, other_ts->clone(other_ts)); + array_insert(this->other_ts, ARRAY_TAIL, other_ts->clone(other_ts)); } enumerator->destroy(enumerator); @@ -1069,8 +1074,8 @@ METHOD(child_sa_t, destroy, void, enumerator->destroy(enumerator); } - this->my_ts->destroy_offset(this->my_ts, offsetof(traffic_selector_t, destroy)); - this->other_ts->destroy_offset(this->other_ts, offsetof(traffic_selector_t, destroy)); + array_destroy_offset(this->my_ts, offsetof(traffic_selector_t, destroy)); + array_destroy_offset(this->other_ts, offsetof(traffic_selector_t, destroy)); this->my_addr->destroy(this->my_addr); this->other_addr->destroy(this->other_addr); DESTROY_IF(this->proposal); @@ -1079,6 +1084,41 @@ METHOD(child_sa_t, destroy, void, } /** + * Get proxy address for one side, if any + */ +static host_t* get_proxy_addr(child_cfg_t *config, host_t *ike, bool local) +{ + host_t *host = NULL; + u_int8_t mask; + enumerator_t *enumerator; + linked_list_t *ts_list, *list; + traffic_selector_t *ts; + + list = linked_list_create_with_items(ike, NULL); + ts_list = config->get_traffic_selectors(config, local, NULL, list); + list->destroy(list); + + enumerator = ts_list->create_enumerator(ts_list); + while (enumerator->enumerate(enumerator, &ts)) + { + if (ts->is_host(ts, NULL) && ts->to_subnet(ts, &host, &mask)) + { + DBG1(DBG_CHD, "%s address: %H is a transport mode proxy for %H", + local ? "my" : "other", ike, host); + break; + } + } + enumerator->destroy(enumerator); + ts_list->destroy_offset(ts_list, offsetof(traffic_selector_t, destroy)); + + if (!host) + { + host = ike->clone(ike); + } + return host; +} + +/** * Described in header. */ child_sa_t * child_sa_create(host_t *me, host_t* other, @@ -1117,17 +1157,15 @@ child_sa_t * child_sa_create(host_t *me, host_t* other, .install = _install, .update = _update, .add_policies = _add_policies, - .get_traffic_selectors = _get_traffic_selectors, + .create_ts_enumerator = _create_ts_enumerator, .create_policy_enumerator = _create_policy_enumerator, .destroy = _destroy, }, - .my_addr = me->clone(me), - .other_addr = other->clone(other), .encap = encap, .ipcomp = IPCOMP_NONE, .state = CHILD_CREATED, - .my_ts = linked_list_create(), - .other_ts = linked_list_create(), + .my_ts = array_create(0, 0), + .other_ts = array_create(0, 0), .protocol = PROTO_NONE, .mode = MODE_TUNNEL, .close_action = config->get_close_action(config), @@ -1170,62 +1208,15 @@ child_sa_t * child_sa_create(host_t *me, host_t* other, if (config->get_mode(config) == MODE_TRANSPORT && config->use_proxy_mode(config)) { - ts_type_t type; - int family; - chunk_t addr; - host_t *host; - enumerator_t *enumerator; - linked_list_t *my_ts_list, *other_ts_list, *list; - traffic_selector_t *my_ts, *other_ts; - this->mode = MODE_TRANSPORT; - list = linked_list_create_with_items(me, NULL); - my_ts_list = config->get_traffic_selectors(config, TRUE, NULL, list); - list->destroy(list); - enumerator = my_ts_list->create_enumerator(my_ts_list); - if (enumerator->enumerate(enumerator, &my_ts)) - { - if (my_ts->is_host(my_ts, NULL) && - !my_ts->is_host(my_ts, this->my_addr)) - { - type = my_ts->get_type(my_ts); - family = (type == TS_IPV4_ADDR_RANGE) ? AF_INET : AF_INET6; - addr = my_ts->get_from_address(my_ts); - host = host_create_from_chunk(family, addr, 0); - free(addr.ptr); - DBG1(DBG_CHD, "my address: %H is a transport mode proxy for %H", - this->my_addr, host); - this->my_addr->destroy(this->my_addr); - this->my_addr = host; - } - } - enumerator->destroy(enumerator); - my_ts_list->destroy_offset(my_ts_list, offsetof(traffic_selector_t, destroy)); - - list = linked_list_create_with_items(other, NULL); - other_ts_list = config->get_traffic_selectors(config, FALSE, NULL, list); - list->destroy(list); - enumerator = other_ts_list->create_enumerator(other_ts_list); - if (enumerator->enumerate(enumerator, &other_ts)) - { - if (other_ts->is_host(other_ts, NULL) && - !other_ts->is_host(other_ts, this->other_addr)) - { - type = other_ts->get_type(other_ts); - family = (type == TS_IPV4_ADDR_RANGE) ? AF_INET : AF_INET6; - addr = other_ts->get_from_address(other_ts); - host = host_create_from_chunk(family, addr, 0); - free(addr.ptr); - DBG1(DBG_CHD, "other address: %H is a transport mode proxy for %H", - this->other_addr, host); - this->other_addr->destroy(this->other_addr); - this->other_addr = host; - } - } - enumerator->destroy(enumerator); - other_ts_list->destroy_offset(other_ts_list, offsetof(traffic_selector_t, destroy)); + this->my_addr = get_proxy_addr(config, me, TRUE); + this->other_addr = get_proxy_addr(config, other, FALSE); + } + else + { + this->my_addr = me->clone(me); + this->other_addr = other->clone(other); } - return &this->public; } diff --git a/src/libcharon/sa/child_sa.h b/src/libcharon/sa/child_sa.h index aa44dbfad..44c529391 100644 --- a/src/libcharon/sa/child_sa.h +++ b/src/libcharon/sa/child_sa.h @@ -284,17 +284,20 @@ struct child_sa_t { mark_t (*get_mark)(child_sa_t *this, bool inbound); /** - * Get the traffic selectors list added for one side. + * Create an enumerator over traffic selectors of one side. * - * @param local TRUE for own traffic selectors, FALSE for remote - * @return list of traffic selectors + * @param local TRUE for own traffic selectors, FALSE for remote. + * @return enumerator over traffic_selector_t* */ - linked_list_t* (*get_traffic_selectors) (child_sa_t *this, bool local); + enumerator_t* (*create_ts_enumerator)(child_sa_t *this, bool local); /** * Create an enumerator over installed policies. * - * @return enumerator over pairs of traffic selectors. + * The enumerated traffic selectors is a full mesh of compatible local + * and remote traffic selectors. + * + * @return enumerator over a pair of traffic_selector_t* */ enumerator_t* (*create_policy_enumerator)(child_sa_t *this); diff --git a/src/libcharon/sa/ike_sa.c b/src/libcharon/sa/ike_sa.c index 19c6248ec..50d969430 100644 --- a/src/libcharon/sa/ike_sa.c +++ b/src/libcharon/sa/ike_sa.c @@ -26,7 +26,7 @@ #include <library.h> #include <hydra.h> #include <daemon.h> -#include <collections/linked_list.h> +#include <collections/array.h> #include <utils/lexparser.h> #include <processing/jobs/retransmit_job.h> #include <processing/jobs/delete_ike_sa_job.h> @@ -95,24 +95,24 @@ struct private_ike_sa_t { peer_cfg_t *peer_cfg; /** - * currently used authentication ruleset, local (as auth_cfg_t) + * currently used authentication ruleset, local */ auth_cfg_t *my_auth; /** - * list of completed local authentication rounds + * currently used authentication constraints, remote */ - linked_list_t *my_auths; + auth_cfg_t *other_auth; /** - * list of completed remote authentication rounds + * Array of completed local authentication rounds (as auth_cfg_t) */ - linked_list_t *other_auths; + array_t *my_auths; /** - * currently used authentication constraints, remote (as auth_cfg_t) + * Array of completed remote authentication rounds (as auth_cfg_t) */ - auth_cfg_t *other_auth; + array_t *other_auths; /** * Selected IKE proposal @@ -172,9 +172,9 @@ struct private_ike_sa_t { ike_condition_t conditions; /** - * Linked List containing the child sa's of the current IKE_SA. + * Array containing the child sa's of the current IKE_SA. */ - linked_list_t *child_sas; + array_t *child_sas; /** * keymat of this IKE_SA @@ -184,22 +184,22 @@ struct private_ike_sa_t { /** * Virtual IPs on local host */ - linked_list_t *my_vips; + array_t *my_vips; /** * Virtual IPs on remote host */ - linked_list_t *other_vips; + array_t *other_vips; /** * List of configuration attributes (attribute_entry_t) */ - linked_list_t *attributes; + array_t *attributes; /** * list of peer's addresses, additional ones transmitted via MOBIKE */ - linked_list_t *peer_addresses; + array_t *peer_addresses; /** * previously value of received DESTINATION_IP hash @@ -282,7 +282,8 @@ static time_t get_use_time(private_ike_sa_t* this, bool inbound) { use_time = this->stats[STAT_OUTBOUND]; } - enumerator = this->child_sas->create_enumerator(this->child_sas); + + enumerator = array_create_enumerator(this->child_sas); while (enumerator->enumerate(enumerator, &child_sa)) { child_sa->get_usestats(child_sa, inbound, ¤t, NULL, NULL); @@ -389,11 +390,11 @@ METHOD(ike_sa_t, add_auth_cfg, void, { if (local) { - this->my_auths->insert_last(this->my_auths, cfg); + array_insert(this->my_auths, ARRAY_TAIL, cfg); } else { - this->other_auths->insert_last(this->other_auths, cfg); + array_insert(this->other_auths, ARRAY_TAIL, cfg); } } @@ -402,9 +403,9 @@ METHOD(ike_sa_t, create_auth_cfg_enumerator, enumerator_t*, { if (local) { - return this->my_auths->create_enumerator(this->my_auths); + return array_create_enumerator(this->my_auths); } - return this->other_auths->create_enumerator(this->other_auths); + return array_create_enumerator(this->other_auths); } /** @@ -417,13 +418,11 @@ static void flush_auth_cfgs(private_ike_sa_t *this) this->my_auth->purge(this->my_auth, FALSE); this->other_auth->purge(this->other_auth, FALSE); - while (this->my_auths->remove_last(this->my_auths, - (void**)&cfg) == SUCCESS) + while (array_remove(this->my_auths, ARRAY_TAIL, &cfg)) { cfg->destroy(cfg); } - while (this->other_auths->remove_last(this->other_auths, - (void**)&cfg) == SUCCESS) + while (array_remove(this->other_auths, ARRAY_TAIL, &cfg)) { cfg->destroy(cfg); } @@ -750,7 +749,7 @@ METHOD(ike_sa_t, add_virtual_ip, void, if (hydra->kernel_interface->add_ip(hydra->kernel_interface, ip, -1, iface) == SUCCESS) { - this->my_vips->insert_last(this->my_vips, ip->clone(ip)); + array_insert_create(&this->my_vips, ARRAY_TAIL, ip->clone(ip)); } else { @@ -765,7 +764,7 @@ METHOD(ike_sa_t, add_virtual_ip, void, } else { - this->other_vips->insert_last(this->other_vips, ip->clone(ip)); + array_insert_create(&this->other_vips, ARRAY_TAIL, ip->clone(ip)); } } @@ -773,14 +772,15 @@ METHOD(ike_sa_t, add_virtual_ip, void, METHOD(ike_sa_t, clear_virtual_ips, void, private_ike_sa_t *this, bool local) { - linked_list_t *vips = local ? this->my_vips : this->other_vips; + array_t *vips; host_t *vip; - if (!local && vips->get_count(vips)) + vips = local ? this->my_vips : this->other_vips; + if (!local && array_count(vips)) { charon->bus->assign_vips(charon->bus, &this->public, FALSE); } - while (vips->remove_first(vips, (void**)&vip) == SUCCESS) + while (array_remove(vips, ARRAY_HEAD, &vip)) { if (local) { @@ -796,23 +796,23 @@ METHOD(ike_sa_t, create_virtual_ip_enumerator, enumerator_t*, { if (local) { - return this->my_vips->create_enumerator(this->my_vips); + return array_create_enumerator(this->my_vips); } - return this->other_vips->create_enumerator(this->other_vips); + return array_create_enumerator(this->other_vips); } METHOD(ike_sa_t, add_peer_address, void, private_ike_sa_t *this, host_t *host) { - this->peer_addresses->insert_last(this->peer_addresses, host); + array_insert_create(&this->peer_addresses, ARRAY_TAIL, host); } METHOD(ike_sa_t, create_peer_address_enumerator, enumerator_t*, private_ike_sa_t *this) { - if (this->peer_addresses->get_count(this->peer_addresses)) + if (this->peer_addresses) { - return this->peer_addresses->create_enumerator(this->peer_addresses); + return array_create_enumerator(this->peer_addresses); } /* in case we don't have MOBIKE */ return enumerator_create_single(this->other_host, NULL); @@ -821,17 +821,8 @@ METHOD(ike_sa_t, create_peer_address_enumerator, enumerator_t*, METHOD(ike_sa_t, clear_peer_addresses, void, private_ike_sa_t *this) { - enumerator_t *enumerator; - host_t *host; - - enumerator = this->peer_addresses->create_enumerator(this->peer_addresses); - while (enumerator->enumerate(enumerator, (void**)&host)) - { - this->peer_addresses->remove_at(this->peer_addresses, - enumerator); - host->destroy(host); - } - enumerator->destroy(enumerator); + array_destroy_offset(this->peer_addresses, offsetof(host_t, destroy)); + this->peer_addresses = NULL; } METHOD(ike_sa_t, has_mapping_changed, bool, @@ -927,13 +918,16 @@ METHOD(ike_sa_t, update_hosts, void, { enumerator_t *enumerator; child_sa_t *child_sa; + linked_list_t *vips; - enumerator = this->child_sas->create_enumerator(this->child_sas); - while (enumerator->enumerate(enumerator, (void**)&child_sa)) + vips = linked_list_create_from_enumerator( + array_create_enumerator(this->my_vips)); + + enumerator = array_create_enumerator(this->child_sas); + while (enumerator->enumerate(enumerator, &child_sa)) { - if (child_sa->update(child_sa, this->my_host, - this->other_host, this->my_vips, - has_condition(this, COND_NAT_ANY)) == NOT_SUPPORTED) + if (child_sa->update(child_sa, this->my_host, this->other_host, + vips, has_condition(this, COND_NAT_ANY)) == NOT_SUPPORTED) { this->public.rekey_child_sa(&this->public, child_sa->get_protocol(child_sa), @@ -941,6 +935,8 @@ METHOD(ike_sa_t, update_hosts, void, } } enumerator->destroy(enumerator); + + vips->destroy(vips); } } @@ -1326,7 +1322,7 @@ METHOD(ike_sa_t, get_other_eap_id, identification_t*, enumerator_t *enumerator; auth_cfg_t *cfg; - enumerator = this->other_auths->create_enumerator(this->other_auths); + enumerator = array_create_enumerator(this->other_auths); while (enumerator->enumerate(enumerator, &cfg)) { /* prefer EAP-Identity of last round */ @@ -1363,7 +1359,7 @@ METHOD(ike_sa_t, set_other_id, void, METHOD(ike_sa_t, add_child_sa, void, private_ike_sa_t *this, child_sa_t *child_sa) { - this->child_sas->insert_last(this->child_sas, child_sa); + array_insert_create(&this->child_sas, ARRAY_TAIL, child_sa); } METHOD(ike_sa_t, get_child_sa, child_sa_t*, @@ -1372,7 +1368,7 @@ METHOD(ike_sa_t, get_child_sa, child_sa_t*, enumerator_t *enumerator; child_sa_t *current, *found = NULL; - enumerator = this->child_sas->create_enumerator(this->child_sas); + enumerator = array_create_enumerator(this->child_sas); while (enumerator->enumerate(enumerator, (void**)¤t)) { if (current->get_spi(current, inbound) == spi && @@ -1388,19 +1384,19 @@ METHOD(ike_sa_t, get_child_sa, child_sa_t*, METHOD(ike_sa_t, get_child_count, int, private_ike_sa_t *this) { - return this->child_sas->get_count(this->child_sas); + return array_count(this->child_sas); } METHOD(ike_sa_t, create_child_sa_enumerator, enumerator_t*, private_ike_sa_t *this) { - return this->child_sas->create_enumerator(this->child_sas); + return array_create_enumerator(this->child_sas); } METHOD(ike_sa_t, remove_child_sa, void, private_ike_sa_t *this, enumerator_t *enumerator) { - this->child_sas->remove_at(this->child_sas, enumerator); + array_remove_at(this->child_sas, enumerator); } METHOD(ike_sa_t, rekey_child_sa, status_t, @@ -1433,13 +1429,13 @@ METHOD(ike_sa_t, destroy_child_sa, status_t, child_sa_t *child_sa; status_t status = NOT_FOUND; - enumerator = this->child_sas->create_enumerator(this->child_sas); + enumerator = array_create_enumerator(this->child_sas); while (enumerator->enumerate(enumerator, (void**)&child_sa)) { if (child_sa->get_protocol(child_sa) == protocol && child_sa->get_spi(child_sa, TRUE) == spi) { - this->child_sas->remove_at(this->child_sas, enumerator); + array_remove_at(this->child_sas, enumerator); child_sa->destroy(child_sa); status = SUCCESS; break; @@ -1506,7 +1502,7 @@ METHOD(ike_sa_t, reauth, status_t, if (!has_condition(this, COND_ORIGINAL_INITIATOR)) { DBG1(DBG_IKE, "initiator did not reauthenticate as requested"); - if (this->other_vips->get_count(this->other_vips) != 0 || + if (array_count(this->other_vips) != 0 || has_condition(this, COND_XAUTH_AUTHENTICATED) || has_condition(this, COND_EAP_AUTHENTICATED) #ifdef ME @@ -1553,7 +1549,7 @@ METHOD(ike_sa_t, reestablish, status_t, if (has_condition(this, COND_REAUTHENTICATING)) { /* only reauthenticate if we have children */ - if (this->child_sas->get_count(this->child_sas) == 0 + if (array_count(this->child_sas) == 0 #ifdef ME /* allow reauth of mediation connections without CHILD_SAs */ && !this->peer_cfg->is_mediation(this->peer_cfg) @@ -1570,7 +1566,7 @@ METHOD(ike_sa_t, reestablish, status_t, } else { /* check if we have children to keep up at all */ - enumerator = this->child_sas->create_enumerator(this->child_sas); + enumerator = array_create_enumerator(this->child_sas); while (enumerator->enumerate(enumerator, (void**)&child_sa)) { if (this->state == IKE_DELETING) @@ -1611,7 +1607,7 @@ METHOD(ike_sa_t, reestablish, status_t, /* check if we are able to reestablish this IKE_SA */ if (!has_condition(this, COND_ORIGINAL_INITIATOR) && - (this->other_vips->get_count(this->other_vips) != 0 || + (array_count(this->other_vips) != 0 || has_condition(this, COND_EAP_AUTHENTICATED) #ifdef ME || this->is_mediation_server @@ -1634,7 +1630,7 @@ METHOD(ike_sa_t, reestablish, status_t, host = this->my_host; new->set_my_host(new, host->clone(host)); /* if we already have a virtual IP, we reuse it */ - enumerator = this->my_vips->create_enumerator(this->my_vips); + enumerator = array_create_enumerator(this->my_vips); while (enumerator->enumerate(enumerator, &host)) { new->add_virtual_ip(new, TRUE, host); @@ -1649,7 +1645,7 @@ METHOD(ike_sa_t, reestablish, status_t, else #endif /* ME */ { - enumerator = this->child_sas->create_enumerator(this->child_sas); + enumerator = array_create_enumerator(this->child_sas); while (enumerator->enumerate(enumerator, (void**)&child_sa)) { if (has_condition(this, COND_REAUTHENTICATING)) @@ -1658,7 +1654,7 @@ METHOD(ike_sa_t, reestablish, status_t, { case CHILD_ROUTED: { /* move routed child directly */ - this->child_sas->remove_at(this->child_sas, enumerator); + array_remove_at(this->child_sas, enumerator); new->add_child_sa(new, child_sa); action = ACTION_NONE; break; @@ -1789,7 +1785,7 @@ METHOD(ike_sa_t, set_auth_lifetime, status_t, * We send the notify in IKE_AUTH if not yet ESTABLISHED. */ send_update = this->state == IKE_ESTABLISHED && this->version == IKEV2 && !has_condition(this, COND_ORIGINAL_INITIATOR) && - (this->other_vips->get_count(this->other_vips) != 0 || + (array_count(this->other_vips) != 0 || has_condition(this, COND_EAP_AUTHENTICATED)); if (lifetime < diff) @@ -1963,13 +1959,12 @@ METHOD(ike_sa_t, add_configuration_attribute, void, private_ike_sa_t *this, attribute_handler_t *handler, configuration_attribute_type_t type, chunk_t data) { - attribute_entry_t *entry = malloc_thing(attribute_entry_t); - - entry->handler = handler; - entry->type = type; - entry->data = chunk_clone(data); - - this->attributes->insert_last(this->attributes, entry); + attribute_entry_t entry = { + .handler = handler, + .type = type, + .data = chunk_clone(data), + }; + array_insert(this->attributes, ARRAY_TAIL, &entry); } METHOD(ike_sa_t, create_task_enumerator, enumerator_t*, @@ -1995,8 +1990,8 @@ METHOD(ike_sa_t, inherit, void, { private_ike_sa_t *other = (private_ike_sa_t*)other_public; child_sa_t *child_sa; - attribute_entry_t *entry; enumerator_t *enumerator; + attribute_entry_t entry; auth_cfg_t *cfg; host_t *vip; @@ -2011,35 +2006,33 @@ METHOD(ike_sa_t, inherit, void, this->other_id = other->other_id->clone(other->other_id); /* apply assigned virtual IPs... */ - while (other->my_vips->remove_last(other->my_vips, (void**)&vip) == SUCCESS) + while (array_remove(other->my_vips, ARRAY_HEAD, &vip)) { - this->my_vips->insert_first(this->my_vips, vip); + array_insert_create(&this->my_vips, ARRAY_TAIL, vip); } - while (other->other_vips->remove_last(other->other_vips, - (void**)&vip) == SUCCESS) + while (array_remove(other->other_vips, ARRAY_HEAD, &vip)) { - this->other_vips->insert_first(this->other_vips, vip); + array_insert_create(&this->other_vips, ARRAY_TAIL, vip); } /* authentication information */ - enumerator = other->my_auths->create_enumerator(other->my_auths); + enumerator = array_create_enumerator(other->my_auths); while (enumerator->enumerate(enumerator, &cfg)) { - this->my_auths->insert_last(this->my_auths, cfg->clone(cfg)); + array_insert(this->my_auths, ARRAY_TAIL, cfg->clone(cfg)); } enumerator->destroy(enumerator); - enumerator = other->other_auths->create_enumerator(other->other_auths); + enumerator = array_create_enumerator(other->other_auths); while (enumerator->enumerate(enumerator, &cfg)) { - this->other_auths->insert_last(this->other_auths, cfg->clone(cfg)); + array_insert(this->other_auths, ARRAY_TAIL, cfg->clone(cfg)); } enumerator->destroy(enumerator); /* ... and configuration attributes */ - while (other->attributes->remove_last(other->attributes, - (void**)&entry) == SUCCESS) + while (array_remove(other->attributes, ARRAY_HEAD, &entry)) { - this->attributes->insert_first(this->attributes, entry); + array_insert(this->attributes, ARRAY_TAIL, &entry); } /* inherit all conditions */ @@ -2062,10 +2055,9 @@ METHOD(ike_sa_t, inherit, void, #endif /* ME */ /* adopt all children */ - while (other->child_sas->remove_last(other->child_sas, - (void**)&child_sa) == SUCCESS) + while (array_remove(other->child_sas, ARRAY_HEAD, &child_sa)) { - this->child_sas->insert_first(this->child_sas, (void*)child_sa); + array_insert_create(&this->child_sas, ARRAY_TAIL, child_sa); } /* move pending tasks to the new IKE_SA */ @@ -2092,7 +2084,7 @@ METHOD(ike_sa_t, inherit, void, METHOD(ike_sa_t, destroy, void, private_ike_sa_t *this) { - attribute_entry_t *entry; + attribute_entry_t entry; host_t *vip; charon->bus->set_sa(charon->bus, &this->public); @@ -2101,25 +2093,22 @@ METHOD(ike_sa_t, destroy, void, DESTROY_IF(this->task_manager); /* remove attributes first, as we pass the IKE_SA to the handler */ - while (this->attributes->remove_last(this->attributes, - (void**)&entry) == SUCCESS) + while (array_remove(this->attributes, ARRAY_TAIL, &entry)) { - hydra->attributes->release(hydra->attributes, entry->handler, - this->other_id, entry->type, entry->data); - free(entry->data.ptr); - free(entry); + hydra->attributes->release(hydra->attributes, entry.handler, + this->other_id, entry.type, entry.data); + free(entry.data.ptr); } - while (this->my_vips->remove_last(this->my_vips, (void**)&vip) == SUCCESS) + while (array_remove(this->my_vips, ARRAY_TAIL, &vip)) { hydra->kernel_interface->del_ip(hydra->kernel_interface, vip, -1, TRUE); vip->destroy(vip); } - if (this->other_vips->get_count(this->other_vips)) + if (array_count(this->other_vips)) { charon->bus->assign_vips(charon->bus, &this->public, FALSE); } - while (this->other_vips->remove_last(this->other_vips, - (void**)&vip) == SUCCESS) + while (array_remove(this->other_vips, ARRAY_TAIL, &vip)) { if (this->peer_cfg) { @@ -2138,13 +2127,12 @@ METHOD(ike_sa_t, destroy, void, /* unset SA after here to avoid usage by the listeners */ charon->bus->set_sa(charon->bus, NULL); - this->child_sas->destroy_offset(this->child_sas, offsetof(child_sa_t, destroy)); + array_destroy_offset(this->child_sas, offsetof(child_sa_t, destroy)); DESTROY_IF(this->keymat); - this->attributes->destroy(this->attributes); - this->my_vips->destroy(this->my_vips); - this->other_vips->destroy(this->other_vips); - this->peer_addresses->destroy_offset(this->peer_addresses, - offsetof(host_t, destroy)); + array_destroy(this->attributes); + array_destroy(this->my_vips); + array_destroy(this->other_vips); + array_destroy_offset(this->peer_addresses, offsetof(host_t, destroy)); #ifdef ME if (this->is_mediation_server) { @@ -2168,10 +2156,8 @@ METHOD(ike_sa_t, destroy, void, DESTROY_IF(this->proposal); this->my_auth->destroy(this->my_auth); this->other_auth->destroy(this->other_auth); - this->my_auths->destroy_offset(this->my_auths, - offsetof(auth_cfg_t, destroy)); - this->other_auths->destroy_offset(this->other_auths, - offsetof(auth_cfg_t, destroy)); + array_destroy_offset(this->my_auths, offsetof(auth_cfg_t, destroy)); + array_destroy_offset(this->other_auths, offsetof(auth_cfg_t, destroy)); this->ike_sa_id->destroy(this->ike_sa_id); free(this); @@ -2283,7 +2269,6 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id, bool initiator, }, .ike_sa_id = ike_sa_id->clone(ike_sa_id), .version = version, - .child_sas = linked_list_create(), .my_host = host_create_any(AF_INET), .other_host = host_create_any(AF_INET), .my_id = identification_create_from_encoding(ID_ANY, chunk_empty), @@ -2294,13 +2279,10 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id, bool initiator, .stats[STAT_OUTBOUND] = time_monotonic(NULL), .my_auth = auth_cfg_create(), .other_auth = auth_cfg_create(), - .my_auths = linked_list_create(), - .other_auths = linked_list_create(), + .my_auths = array_create(0, 0), + .other_auths = array_create(0, 0), + .attributes = array_create(sizeof(attribute_entry_t), 0), .unique_id = ref_get(&unique_id), - .peer_addresses = linked_list_create(), - .my_vips = linked_list_create(), - .other_vips = linked_list_create(), - .attributes = linked_list_create(), .keepalive_interval = lib->settings->get_time(lib->settings, "%s.keep_alive", KEEPALIVE_INTERVAL, charon->name), .retry_initiate_interval = lib->settings->get_time(lib->settings, diff --git a/src/libcharon/sa/ikev1/task_manager_v1.c b/src/libcharon/sa/ikev1/task_manager_v1.c index 709033cb5..bfa6fc81e 100644 --- a/src/libcharon/sa/ikev1/task_manager_v1.c +++ b/src/libcharon/sa/ikev1/task_manager_v1.c @@ -1753,21 +1753,22 @@ METHOD(task_manager_t, queue_child, void, /** * Check if two CHILD_SAs have the same traffic selector */ -static bool have_equal_ts(child_sa_t *a, child_sa_t *b, bool local) +static bool have_equal_ts(child_sa_t *child1, child_sa_t *child2, bool local) { - linked_list_t *list; - traffic_selector_t *ts_a, *ts_b; + enumerator_t *e1, *e2; + traffic_selector_t *ts1, *ts2; + bool equal = FALSE; - list = a->get_traffic_selectors(a, local); - if (list->get_first(list, (void**)&ts_a) == SUCCESS) + e1 = child1->create_ts_enumerator(child1, local); + e2 = child2->create_ts_enumerator(child2, local); + if (e1->enumerate(e1, &ts1) && e2->enumerate(e2, &ts2)) { - list = b->get_traffic_selectors(b, local); - if (list->get_first(list, (void**)&ts_b) == SUCCESS) - { - return ts_a->equals(ts_a, ts_b); - } + equal = ts1->equals(ts1, ts2); } - return FALSE; + e1->destroy(e1); + e1->destroy(e1); + + return equal; } /** @@ -1806,14 +1807,13 @@ static bool is_redundant(private_task_manager_t *this, child_sa_t *child_sa) static traffic_selector_t* get_first_ts(child_sa_t *child_sa, bool local) { traffic_selector_t *ts = NULL; - linked_list_t *list; + enumerator_t *enumerator; - list = child_sa->get_traffic_selectors(child_sa, local); - if (list->get_first(list, (void**)&ts) == SUCCESS) - { - return ts; - } - return NULL; + enumerator = child_sa->create_ts_enumerator(child_sa, local); + enumerator->enumerate(enumerator, &ts); + enumerator->destroy(enumerator); + + return ts; } METHOD(task_manager_t, queue_child_rekey, void, diff --git a/src/libcharon/sa/ikev1/tasks/quick_delete.c b/src/libcharon/sa/ikev1/tasks/quick_delete.c index e9f06cbe3..5b3e35ed3 100644 --- a/src/libcharon/sa/ikev1/tasks/quick_delete.c +++ b/src/libcharon/sa/ikev1/tasks/quick_delete.c @@ -69,6 +69,7 @@ static bool delete_child(private_quick_delete_t *this, { u_int64_t bytes_in, bytes_out; child_sa_t *child_sa; + linked_list_t *my_ts, *other_ts; bool rekeyed; child_sa = this->ike_sa->get_child_sa(this->ike_sa, protocol, spi, TRUE); @@ -85,15 +86,17 @@ static bool delete_child(private_quick_delete_t *this, rekeyed = child_sa->get_state(child_sa) == CHILD_REKEYING; child_sa->set_state(child_sa, CHILD_DELETING); + 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)); if (this->expired) { DBG0(DBG_IKE, "closing expired CHILD_SA %s{%d} " "with SPIs %.8x_i %.8x_o and TS %#R=== %#R", child_sa->get_name(child_sa), child_sa->get_reqid(child_sa), ntohl(child_sa->get_spi(child_sa, TRUE)), - ntohl(child_sa->get_spi(child_sa, FALSE)), - child_sa->get_traffic_selectors(child_sa, TRUE), - child_sa->get_traffic_selectors(child_sa, FALSE)); + ntohl(child_sa->get_spi(child_sa, FALSE)), my_ts, other_ts); } else { @@ -105,9 +108,10 @@ static bool delete_child(private_quick_delete_t *this, child_sa->get_name(child_sa), child_sa->get_reqid(child_sa), ntohl(child_sa->get_spi(child_sa, TRUE)), bytes_in, ntohl(child_sa->get_spi(child_sa, FALSE)), bytes_out, - child_sa->get_traffic_selectors(child_sa, TRUE), - child_sa->get_traffic_selectors(child_sa, FALSE)); + my_ts, other_ts); } + my_ts->destroy(my_ts); + other_ts->destroy(other_ts); if (!rekeyed) { diff --git a/src/libcharon/sa/ikev1/tasks/quick_mode.c b/src/libcharon/sa/ikev1/tasks/quick_mode.c index 52ea34b1a..92df0f0f8 100644 --- a/src/libcharon/sa/ikev1/tasks/quick_mode.c +++ b/src/libcharon/sa/ikev1/tasks/quick_mode.c @@ -259,7 +259,7 @@ static bool install(private_quick_mode_t *this) { status_t status, status_i, status_o; chunk_t encr_i, encr_r, integ_i, integ_r; - linked_list_t *tsi, *tsr; + linked_list_t *tsi, *tsr, *my_ts, *other_ts; child_sa_t *old = NULL; this->child_sa->set_proposal(this->child_sa, this->proposal); @@ -362,14 +362,20 @@ static bool install(private_quick_mode_t *this) this->child_sa->set_state(this->child_sa, CHILD_INSTALLED); this->ike_sa->add_child_sa(this->ike_sa, this->child_sa); + my_ts = linked_list_create_from_enumerator( + this->child_sa->create_ts_enumerator(this->child_sa, TRUE)); + other_ts = linked_list_create_from_enumerator( + this->child_sa->create_ts_enumerator(this->child_sa, FALSE)); + DBG0(DBG_IKE, "CHILD_SA %s{%d} established " "with SPIs %.8x_i %.8x_o and TS %#R=== %#R", this->child_sa->get_name(this->child_sa), this->child_sa->get_reqid(this->child_sa), ntohl(this->child_sa->get_spi(this->child_sa, TRUE)), - ntohl(this->child_sa->get_spi(this->child_sa, FALSE)), - this->child_sa->get_traffic_selectors(this->child_sa, TRUE), - this->child_sa->get_traffic_selectors(this->child_sa, FALSE)); + ntohl(this->child_sa->get_spi(this->child_sa, FALSE)), my_ts, other_ts); + + my_ts->destroy(my_ts); + other_ts->destroy(other_ts); if (this->rekey) { diff --git a/src/libcharon/sa/ikev2/task_manager_v2.c b/src/libcharon/sa/ikev2/task_manager_v2.c index 839bdb990..79a9aa5a0 100644 --- a/src/libcharon/sa/ikev2/task_manager_v2.c +++ b/src/libcharon/sa/ikev2/task_manager_v2.c @@ -18,6 +18,7 @@ #include <math.h> +#include <collections/array.h> #include <daemon.h> #include <sa/ikev2/tasks/ike_init.h> #include <sa/ikev2/tasks/ike_natd.h> @@ -122,19 +123,19 @@ struct private_task_manager_t { } initiating; /** - * List of queued tasks not yet in action + * Array of queued tasks not yet in action */ - linked_list_t *queued_tasks; + array_t *queued_tasks; /** - * List of active tasks, initiated by ourselve + * Array of active tasks, initiated by ourselve */ - linked_list_t *active_tasks; + array_t *active_tasks; /** - * List of tasks initiated by peer + * Array of tasks initiated by peer */ - linked_list_t *passive_tasks; + array_t *passive_tasks; /** * the task manager has been reset @@ -160,24 +161,24 @@ struct private_task_manager_t { METHOD(task_manager_t, flush_queue, void, private_task_manager_t *this, task_queue_t queue) { - linked_list_t *list; + array_t *array; task_t *task; switch (queue) { case TASK_QUEUE_ACTIVE: - list = this->active_tasks; + array = this->active_tasks; break; case TASK_QUEUE_PASSIVE: - list = this->passive_tasks; + array = this->passive_tasks; break; case TASK_QUEUE_QUEUED: - list = this->queued_tasks; + array = this->queued_tasks; break; default: return; } - while (list->remove_last(list, (void**)&task) == SUCCESS) + while (array_remove(array, ARRAY_TAIL, &task)) { task->destroy(task); } @@ -202,14 +203,14 @@ static bool activate_task(private_task_manager_t *this, task_type_t type) task_t *task; bool found = FALSE; - enumerator = this->queued_tasks->create_enumerator(this->queued_tasks); + enumerator = array_create_enumerator(this->queued_tasks); while (enumerator->enumerate(enumerator, (void**)&task)) { if (task->get_type(task) == type) { DBG2(DBG_IKE, " activating %N task", task_type_names, type); - this->queued_tasks->remove_at(this->queued_tasks, enumerator); - this->active_tasks->insert_last(this->active_tasks, task); + array_remove_at(this->queued_tasks, enumerator); + array_insert(this->active_tasks, ARRAY_TAIL, task); found = TRUE; break; } @@ -231,7 +232,7 @@ METHOD(task_manager_t, retransmit, status_t, ike_mobike_t *mobike = NULL; /* check if we are retransmitting a MOBIKE routability check */ - enumerator = this->active_tasks->create_enumerator(this->active_tasks); + enumerator = array_create_enumerator(this->active_tasks); while (enumerator->enumerate(enumerator, (void*)&task)) { if (task->get_type(task) == TASK_IKE_MOBIKE) @@ -319,7 +320,7 @@ METHOD(task_manager_t, initiate, status_t, return SUCCESS; } - if (this->active_tasks->get_count(this->active_tasks) == 0) + if (array_count(this->active_tasks) == 0) { DBG2(DBG_IKE, "activating new tasks"); switch (this->ike_sa->get_state(this->ike_sa)) @@ -414,8 +415,8 @@ METHOD(task_manager_t, initiate, status_t, else { DBG2(DBG_IKE, "reinitiating already active tasks"); - enumerator = this->active_tasks->create_enumerator(this->active_tasks); - while (enumerator->enumerate(enumerator, (void**)&task)) + enumerator = array_create_enumerator(this->active_tasks); + while (enumerator->enumerate(enumerator, &task)) { DBG2(DBG_IKE, " %N task", task_type_names, task->get_type(task)); switch (task->get_type(task)) @@ -460,14 +461,14 @@ METHOD(task_manager_t, initiate, status_t, this->initiating.type = exchange; this->initiating.retransmitted = 0; - enumerator = this->active_tasks->create_enumerator(this->active_tasks); - while (enumerator->enumerate(enumerator, (void*)&task)) + enumerator = array_create_enumerator(this->active_tasks); + while (enumerator->enumerate(enumerator, &task)) { switch (task->build(task, message)) { case SUCCESS: /* task completed, remove it */ - this->active_tasks->remove_at(this->active_tasks, enumerator); + array_remove_at(this->active_tasks, enumerator); task->destroy(task); break; case NEED_MORE: @@ -507,6 +508,9 @@ METHOD(task_manager_t, initiate, status_t, } message->destroy(message); + array_compress(this->active_tasks); + array_compress(this->queued_tasks); + return retransmit(this, this->initiating.mid); } @@ -530,14 +534,14 @@ static status_t process_response(private_task_manager_t *this, /* catch if we get resetted while processing */ this->reset = FALSE; - enumerator = this->active_tasks->create_enumerator(this->active_tasks); - while (enumerator->enumerate(enumerator, (void*)&task)) + enumerator = array_create_enumerator(this->active_tasks); + while (enumerator->enumerate(enumerator, &task)) { switch (task->process(task, message)) { case SUCCESS: /* task completed, remove it */ - this->active_tasks->remove_at(this->active_tasks, enumerator); + array_remove_at(this->active_tasks, enumerator); task->destroy(task); break; case NEED_MORE: @@ -549,7 +553,7 @@ static status_t process_response(private_task_manager_t *this, /* FALL */ case DESTROY_ME: /* critical failure, destroy IKE_SA */ - this->active_tasks->remove_at(this->active_tasks, enumerator); + array_remove_at(this->active_tasks, enumerator); enumerator->destroy(enumerator); task->destroy(task); return DESTROY_ME; @@ -568,6 +572,8 @@ static status_t process_response(private_task_manager_t *this, this->initiating.packet->destroy(this->initiating.packet); this->initiating.packet = NULL; + array_compress(this->active_tasks); + return initiate(this); } @@ -588,8 +594,8 @@ static bool handle_collisions(private_task_manager_t *this, task_t *task) type == TASK_IKE_REAUTH) { /* find an exchange collision, and notify these tasks */ - enumerator = this->active_tasks->create_enumerator(this->active_tasks); - while (enumerator->enumerate(enumerator, (void**)&active)) + enumerator = array_create_enumerator(this->active_tasks); + while (enumerator->enumerate(enumerator, &active)) { switch (active->get_type(active)) { @@ -646,14 +652,14 @@ static status_t build_response(private_task_manager_t *this, message_t *request) message->set_message_id(message, this->responding.mid); message->set_request(message, FALSE); - enumerator = this->passive_tasks->create_enumerator(this->passive_tasks); + enumerator = array_create_enumerator(this->passive_tasks); while (enumerator->enumerate(enumerator, (void*)&task)) { switch (task->build(task, message)) { case SUCCESS: /* task completed, remove it */ - this->passive_tasks->remove_at(this->passive_tasks, enumerator); + array_remove_at(this->passive_tasks, enumerator); if (!handle_collisions(this, task)) { task->destroy(task); @@ -663,8 +669,7 @@ static status_t build_response(private_task_manager_t *this, message_t *request) /* processed, but task needs another exchange */ if (handle_collisions(this, task)) { - this->passive_tasks->remove_at(this->passive_tasks, - enumerator); + array_remove_at(this->passive_tasks, enumerator); } break; case FAILED: @@ -721,6 +726,9 @@ static status_t build_response(private_task_manager_t *this, message_t *request) } return DESTROY_ME; } + + array_compress(this->passive_tasks); + return SUCCESS; } @@ -736,37 +744,37 @@ static status_t process_request(private_task_manager_t *this, notify_payload_t *notify; delete_payload_t *delete; - if (this->passive_tasks->get_count(this->passive_tasks) == 0) + if (array_count(this->passive_tasks) == 0) { /* create tasks depending on request type, if not already some queued */ switch (message->get_exchange_type(message)) { case IKE_SA_INIT: { task = (task_t*)ike_vendor_create(this->ike_sa, FALSE); - this->passive_tasks->insert_last(this->passive_tasks, task); + array_insert(this->passive_tasks, ARRAY_TAIL, task); task = (task_t*)ike_init_create(this->ike_sa, FALSE, NULL); - this->passive_tasks->insert_last(this->passive_tasks, task); + array_insert(this->passive_tasks, ARRAY_TAIL, task); task = (task_t*)ike_natd_create(this->ike_sa, FALSE); - this->passive_tasks->insert_last(this->passive_tasks, task); + array_insert(this->passive_tasks, ARRAY_TAIL, task); task = (task_t*)ike_cert_pre_create(this->ike_sa, FALSE); - this->passive_tasks->insert_last(this->passive_tasks, task); + array_insert(this->passive_tasks, ARRAY_TAIL, task); #ifdef ME task = (task_t*)ike_me_create(this->ike_sa, FALSE); - this->passive_tasks->insert_last(this->passive_tasks, task); + array_insert(this->passive_tasks, ARRAY_TAIL, task); #endif /* ME */ task = (task_t*)ike_auth_create(this->ike_sa, FALSE); - this->passive_tasks->insert_last(this->passive_tasks, task); + array_insert(this->passive_tasks, ARRAY_TAIL, task); task = (task_t*)ike_cert_post_create(this->ike_sa, FALSE); - this->passive_tasks->insert_last(this->passive_tasks, task); + array_insert(this->passive_tasks, ARRAY_TAIL, task); task = (task_t*)ike_config_create(this->ike_sa, FALSE); - this->passive_tasks->insert_last(this->passive_tasks, task); + array_insert(this->passive_tasks, ARRAY_TAIL, task); task = (task_t*)child_create_create(this->ike_sa, NULL, FALSE, NULL, NULL); - this->passive_tasks->insert_last(this->passive_tasks, task); + array_insert(this->passive_tasks, ARRAY_TAIL, task); task = (task_t*)ike_auth_lifetime_create(this->ike_sa, FALSE); - this->passive_tasks->insert_last(this->passive_tasks, task); + array_insert(this->passive_tasks, ARRAY_TAIL, task); task = (task_t*)ike_mobike_create(this->ike_sa, FALSE); - this->passive_tasks->insert_last(this->passive_tasks, task); + array_insert(this->passive_tasks, ARRAY_TAIL, task); break; } case CREATE_CHILD_SA: @@ -817,7 +825,7 @@ static status_t process_request(private_task_manager_t *this, { task = (task_t*)ike_rekey_create(this->ike_sa, FALSE); } - this->passive_tasks->insert_last(this->passive_tasks, task); + array_insert(this->passive_tasks, ARRAY_TAIL, task); break; } case INFORMATIONAL: @@ -889,14 +897,14 @@ static status_t process_request(private_task_manager_t *this, { task = (task_t*)ike_dpd_create(FALSE); } - this->passive_tasks->insert_last(this->passive_tasks, task); + array_insert(this->passive_tasks, ARRAY_TAIL, task); break; } #ifdef ME case ME_CONNECT: { task = (task_t*)ike_me_create(this->ike_sa, FALSE); - this->passive_tasks->insert_last(this->passive_tasks, task); + array_insert(this->passive_tasks, ARRAY_TAIL, task); } #endif /* ME */ default: @@ -905,14 +913,14 @@ static status_t process_request(private_task_manager_t *this, } /* let the tasks process the message */ - enumerator = this->passive_tasks->create_enumerator(this->passive_tasks); + enumerator = array_create_enumerator(this->passive_tasks); while (enumerator->enumerate(enumerator, (void*)&task)) { switch (task->process(task, message)) { case SUCCESS: /* task completed, remove it */ - this->passive_tasks->remove_at(this->passive_tasks, enumerator); + array_remove_at(this->passive_tasks, enumerator); task->destroy(task); break; case NEED_MORE: @@ -924,7 +932,7 @@ static status_t process_request(private_task_manager_t *this, /* FALL */ case DESTROY_ME: /* critical failure, destroy IKE_SA */ - this->passive_tasks->remove_at(this->passive_tasks, enumerator); + array_remove_at(this->passive_tasks, enumerator); enumerator->destroy(enumerator); task->destroy(task); return DESTROY_ME; @@ -1230,8 +1238,8 @@ METHOD(task_manager_t, queue_task, void, enumerator_t *enumerator; task_t *current; - enumerator = this->queued_tasks->create_enumerator(this->queued_tasks); - while (enumerator->enumerate(enumerator, (void**)¤t)) + enumerator = array_create_enumerator(this->queued_tasks); + while (enumerator->enumerate(enumerator, ¤t)) { if (current->get_type(current) == TASK_IKE_MOBIKE) { @@ -1243,7 +1251,7 @@ METHOD(task_manager_t, queue_task, void, enumerator->destroy(enumerator); } DBG2(DBG_IKE, "queueing %N task", task_type_names, task->get_type(task)); - this->queued_tasks->insert_last(this->queued_tasks, task); + array_insert(this->queued_tasks, ARRAY_TAIL, task); } /** @@ -1255,7 +1263,7 @@ static bool has_queued(private_task_manager_t *this, task_type_t type) bool found = FALSE; task_t *task; - enumerator = this->queued_tasks->create_enumerator(this->queued_tasks); + enumerator = array_create_enumerator(this->queued_tasks); while (enumerator->enumerate(enumerator, &task)) { if (task->get_type(task) == type) @@ -1410,19 +1418,18 @@ METHOD(task_manager_t, adopt_tasks, void, task_t *task; /* move queued tasks from other to this */ - while (other->queued_tasks->remove_last(other->queued_tasks, - (void**)&task) == SUCCESS) + while (array_remove(other->queued_tasks, ARRAY_TAIL, &task)) { DBG2(DBG_IKE, "migrating %N task", task_type_names, task->get_type(task)); task->migrate(task, this->ike_sa); - this->queued_tasks->insert_first(this->queued_tasks, task); + array_insert(this->queued_tasks, ARRAY_HEAD, task); } } METHOD(task_manager_t, busy, bool, private_task_manager_t *this) { - return (this->active_tasks->get_count(this->active_tasks) > 0); + return array_count(this->active_tasks) > 0; } METHOD(task_manager_t, reset, void, @@ -1447,7 +1454,7 @@ METHOD(task_manager_t, reset, void, this->initiating.type = EXCHANGE_TYPE_UNDEFINED; /* reset queued tasks */ - enumerator = this->queued_tasks->create_enumerator(this->queued_tasks); + enumerator = array_create_enumerator(this->queued_tasks); while (enumerator->enumerate(enumerator, &task)) { task->migrate(task, this->ike_sa); @@ -1455,11 +1462,10 @@ METHOD(task_manager_t, reset, void, enumerator->destroy(enumerator); /* reset active tasks */ - while (this->active_tasks->remove_last(this->active_tasks, - (void**)&task) == SUCCESS) + while (array_remove(this->active_tasks, ARRAY_TAIL, &task)) { task->migrate(task, this->ike_sa); - this->queued_tasks->insert_first(this->queued_tasks, task); + array_insert(this->queued_tasks, ARRAY_HEAD, task); } this->reset = TRUE; @@ -1471,11 +1477,11 @@ METHOD(task_manager_t, create_task_enumerator, enumerator_t*, switch (queue) { case TASK_QUEUE_ACTIVE: - return this->active_tasks->create_enumerator(this->active_tasks); + return array_create_enumerator(this->active_tasks); case TASK_QUEUE_PASSIVE: - return this->passive_tasks->create_enumerator(this->passive_tasks); + return array_create_enumerator(this->passive_tasks); case TASK_QUEUE_QUEUED: - return this->queued_tasks->create_enumerator(this->queued_tasks); + return array_create_enumerator(this->queued_tasks); default: return enumerator_create_empty(); } @@ -1486,9 +1492,9 @@ METHOD(task_manager_t, destroy, void, { flush(this); - this->active_tasks->destroy(this->active_tasks); - this->queued_tasks->destroy(this->queued_tasks); - this->passive_tasks->destroy(this->passive_tasks); + array_destroy(this->active_tasks); + array_destroy(this->queued_tasks); + array_destroy(this->passive_tasks); DESTROY_IF(this->responding.packet); DESTROY_IF(this->initiating.packet); @@ -1529,9 +1535,9 @@ task_manager_v2_t *task_manager_v2_create(ike_sa_t *ike_sa) }, .ike_sa = ike_sa, .initiating.type = EXCHANGE_TYPE_UNDEFINED, - .queued_tasks = linked_list_create(), - .active_tasks = linked_list_create(), - .passive_tasks = linked_list_create(), + .queued_tasks = array_create(0, 0), + .active_tasks = array_create(0, 0), + .passive_tasks = array_create(0, 0), .retransmit_tries = lib->settings->get_int(lib->settings, "%s.retransmit_tries", RETRANSMIT_TRIES, charon->name), .retransmit_timeout = lib->settings->get_double(lib->settings, diff --git a/src/libcharon/sa/ikev2/tasks/child_create.c b/src/libcharon/sa/ikev2/tasks/child_create.c index dd3813e85..8ae36af84 100644 --- a/src/libcharon/sa/ikev2/tasks/child_create.c +++ b/src/libcharon/sa/ikev2/tasks/child_create.c @@ -673,6 +673,22 @@ static status_t select_and_install(private_child_create_t *this, { /* a rekeyed SA uses the same reqid, no need for a new job */ schedule_inactivity_timeout(this); } + + my_ts = linked_list_create_from_enumerator( + this->child_sa->create_ts_enumerator(this->child_sa, TRUE)); + other_ts = linked_list_create_from_enumerator( + this->child_sa->create_ts_enumerator(this->child_sa, FALSE)); + + DBG0(DBG_IKE, "CHILD_SA %s{%d} established " + "with SPIs %.8x_i %.8x_o and TS %#R=== %#R", + this->child_sa->get_name(this->child_sa), + this->child_sa->get_reqid(this->child_sa), + ntohl(this->child_sa->get_spi(this->child_sa, TRUE)), + ntohl(this->child_sa->get_spi(this->child_sa, FALSE)), my_ts, other_ts); + + my_ts->destroy(my_ts); + other_ts->destroy(other_ts); + return SUCCESS; } @@ -1245,15 +1261,6 @@ METHOD(task_t, build_r, status_t, build_payloads(this, message); - DBG0(DBG_IKE, "CHILD_SA %s{%d} established " - "with SPIs %.8x_i %.8x_o and TS %#R=== %#R", - this->child_sa->get_name(this->child_sa), - this->child_sa->get_reqid(this->child_sa), - ntohl(this->child_sa->get_spi(this->child_sa, TRUE)), - ntohl(this->child_sa->get_spi(this->child_sa, FALSE)), - this->child_sa->get_traffic_selectors(this->child_sa, TRUE), - this->child_sa->get_traffic_selectors(this->child_sa, FALSE)); - if (!this->rekey) { /* invoke the child_up() hook if we are not rekeying */ charon->bus->child_updown(charon->bus, this->child_sa, TRUE); @@ -1431,15 +1438,6 @@ METHOD(task_t, process_i, status_t, if (select_and_install(this, no_dh, ike_auth) == SUCCESS) { - DBG0(DBG_IKE, "CHILD_SA %s{%d} established " - "with SPIs %.8x_i %.8x_o and TS %#R=== %#R", - this->child_sa->get_name(this->child_sa), - this->child_sa->get_reqid(this->child_sa), - ntohl(this->child_sa->get_spi(this->child_sa, TRUE)), - ntohl(this->child_sa->get_spi(this->child_sa, FALSE)), - this->child_sa->get_traffic_selectors(this->child_sa, TRUE), - this->child_sa->get_traffic_selectors(this->child_sa, FALSE)); - if (!this->rekey) { /* invoke the child_up() hook if we are not rekeying */ charon->bus->child_updown(charon->bus, this->child_sa, TRUE); diff --git a/src/libcharon/sa/ikev2/tasks/child_delete.c b/src/libcharon/sa/ikev2/tasks/child_delete.c index 9f12d7385..eaaca2039 100644 --- a/src/libcharon/sa/ikev2/tasks/child_delete.c +++ b/src/libcharon/sa/ikev2/tasks/child_delete.c @@ -249,6 +249,7 @@ static status_t destroy_and_reestablish(private_child_delete_t *this) */ static void log_children(private_child_delete_t *this) { + linked_list_t *my_ts, *other_ts; enumerator_t *enumerator; child_sa_t *child_sa; u_int64_t bytes_in, bytes_out; @@ -256,15 +257,17 @@ static void log_children(private_child_delete_t *this) enumerator = this->child_sas->create_enumerator(this->child_sas); while (enumerator->enumerate(enumerator, (void**)&child_sa)) { + 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)); if (this->expired) { DBG0(DBG_IKE, "closing expired CHILD_SA %s{%d} " "with SPIs %.8x_i %.8x_o and TS %#R=== %#R", child_sa->get_name(child_sa), child_sa->get_reqid(child_sa), ntohl(child_sa->get_spi(child_sa, TRUE)), - ntohl(child_sa->get_spi(child_sa, FALSE)), - child_sa->get_traffic_selectors(child_sa, TRUE), - child_sa->get_traffic_selectors(child_sa, FALSE)); + ntohl(child_sa->get_spi(child_sa, FALSE)), my_ts, other_ts); } else { @@ -276,9 +279,10 @@ static void log_children(private_child_delete_t *this) child_sa->get_name(child_sa), child_sa->get_reqid(child_sa), ntohl(child_sa->get_spi(child_sa, TRUE)), bytes_in, ntohl(child_sa->get_spi(child_sa, FALSE)), bytes_out, - child_sa->get_traffic_selectors(child_sa, TRUE), - child_sa->get_traffic_selectors(child_sa, FALSE)); + my_ts, other_ts); } + my_ts->destroy(my_ts); + other_ts->destroy(other_ts); } enumerator->destroy(enumerator); } diff --git a/src/libstrongswan/Android.mk b/src/libstrongswan/Android.mk index 75b501fdd..dc533a38b 100644 --- a/src/libstrongswan/Android.mk +++ b/src/libstrongswan/Android.mk @@ -6,6 +6,7 @@ LOCAL_SRC_FILES := \ library.c \ asn1/asn1.c asn1/asn1_parser.c asn1/oid.c bio/bio_reader.c bio/bio_writer.c \ collections/blocking_queue.c collections/enumerator.c collections/hashtable.c \ +collections/array.c \ collections/linked_list.c crypto/crypters/crypter.c crypto/hashers/hasher.c \ crypto/proposal/proposal_keywords.c crypto/proposal/proposal_keywords_static.c \ crypto/prfs/prf.c crypto/prfs/mac_prf.c crypto/pkcs5.c \ @@ -110,4 +111,3 @@ LOCAL_PRELINK_MODULE := false LOCAL_SHARED_LIBRARIES += libdl libvstr include $(BUILD_SHARED_LIBRARY) - diff --git a/src/libstrongswan/Makefile.am b/src/libstrongswan/Makefile.am index 567bdfe6f..bde5f710a 100644 --- a/src/libstrongswan/Makefile.am +++ b/src/libstrongswan/Makefile.am @@ -4,6 +4,7 @@ libstrongswan_la_SOURCES = \ library.c \ asn1/asn1.c asn1/asn1_parser.c asn1/oid.c bio/bio_reader.c bio/bio_writer.c \ collections/blocking_queue.c collections/enumerator.c collections/hashtable.c \ +collections/array.c \ collections/linked_list.c crypto/crypters/crypter.c crypto/hashers/hasher.c \ crypto/proposal/proposal_keywords.c crypto/proposal/proposal_keywords_static.c \ crypto/prfs/prf.c crypto/prfs/mac_prf.c crypto/pkcs5.c \ @@ -39,7 +40,7 @@ nobase_strongswan_include_HEADERS = \ library.h \ asn1/asn1.h asn1/asn1_parser.h asn1/oid.h bio/bio_reader.h bio/bio_writer.h \ collections/blocking_queue.h collections/enumerator.h collections/hashtable.h \ -collections/linked_list.h \ +collections/linked_list.h collections/array.h \ crypto/crypters/crypter.h crypto/hashers/hasher.h crypto/mac.h \ crypto/proposal/proposal_keywords.h crypto/proposal/proposal_keywords_static.h \ crypto/prfs/prf.h crypto/prfs/mac_prf.h crypto/rngs/rng.h crypto/nonce_gen.h \ diff --git a/src/libstrongswan/collections/array.c b/src/libstrongswan/collections/array.c new file mode 100644 index 000000000..d92eaacfe --- /dev/null +++ b/src/libstrongswan/collections/array.c @@ -0,0 +1,416 @@ +/* + * Copyright (C) 2013 Martin Willi + * Copyright (C) 2013 revosec AG + * + * 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 "array.h" + +/** + * Data is an allocated block, with potentially unused head and tail: + * + * "esize" each (or sizeof(void*) if esize = 0) + * /-\ /-\ /-\ /-\ /-\ /-\ + * + * +---------------+-------------------------------+---------------+ + * | h | e | a | d | e | l | e | m | e | n | t | s | t | a | i | l | + * +---------------+-------------------------------+---------------+ + * + * \--------------/ \-----------------------------/ \-------------/ + * unused used unused + * "head" "count" "tail" + * + */ +struct array_t { + /** number of elements currently in array (not counting head/tail) */ + u_int32_t count; + /** size of each element, 0 for a pointer based array */ + u_int16_t esize; + /** allocated but unused elements at array front */ + u_int8_t head; + /** allocated but unused elements at array end */ + u_int8_t tail; + /** array elements */ + void *data; +}; + +/** maximum number of unused head/tail elements before cleanup */ +#define ARRAY_MAX_UNUSED 32 + +/** + * Get the actual size of a number of elements + */ +static size_t get_size(array_t *array, int num) +{ + if (array->esize) + { + return array->esize * num; + } + return sizeof(void*) * num; +} + +/** + * Increase allocated but unused tail room to at least "room" + */ +static void make_tail_room(array_t *array, u_int8_t room) +{ + if (array->tail < room) + { + array->data = realloc(array->data, + get_size(array, array->count + array->head + room)); + array->tail = room; + } +} + +/** + * Increase allocated but unused head room to at least "room" + */ +static void make_head_room(array_t *array, u_int8_t room) +{ + if (array->head < room) + { + u_int8_t increase = room - array->head; + + array->data = realloc(array->data, + get_size(array, array->count + array->tail + room)); + memmove(array->data + get_size(array, increase), array->data, + get_size(array, array->count + array->tail + array->head)); + array->head = room; + } +} + +/** + * Make space for an item at index using tail room + */ +static void insert_tail(array_t *array, int idx) +{ + make_tail_room(array, 1); + /* move up all elements after idx by one */ + memmove(array->data + get_size(array, array->head + idx + 1), + array->data + get_size(array, array->head + idx), + get_size(array, array->count - idx)); + + array->tail--; + array->count++; +} + +/** + * Make space for an item at index using head room + */ +static void insert_head(array_t *array, int idx) +{ + make_head_room(array, 1); + /* move down all elements before idx by one */ + memmove(array->data + get_size(array, array->head - 1), + array->data + get_size(array, array->head), + get_size(array, idx)); + + array->head--; + array->count++; +} + +/** + * Remove an item, increase tail + */ +static void remove_tail(array_t *array, int idx) +{ + /* move all items after idx one down */ + memmove(array->data + get_size(array, idx + array->head), + array->data + get_size(array, idx + array->head + 1), + get_size(array, array->count - idx)); + array->count--; + array->tail++; +} + +/** + * Remove an item, increase head + */ +static void remove_head(array_t *array, int idx) +{ + /* move all items before idx one up */ + memmove(array->data + get_size(array, array->head + 1), + array->data + get_size(array, array->head), get_size(array, idx)); + array->count--; + array->head++; +} + +array_t *array_create(u_int esize, u_int8_t reserve) +{ + array_t *array; + + INIT(array, + .esize = esize, + .tail = reserve, + ); + if (array->tail) + { + array->data = malloc(array->tail * array->esize); + } + return array; +} + +int array_count(array_t *array) +{ + if (array) + { + return array->count; + } + return 0; +} + +void array_compress(array_t *array) +{ + if (array) + { + u_int32_t tail; + + tail = array->tail; + if (array->head) + { + memmove(array->data, array->data + get_size(array, array->head), + get_size(array, array->count + array->tail)); + tail += array->head; + array->head = 0; + } + if (tail) + { + array->data = realloc(array->data, get_size(array, array->count)); + array->tail = 0; + } + } +} + +typedef struct { + /** public enumerator interface */ + enumerator_t public; + /** enumerated array */ + array_t *array; + /** current index +1, initialized at 0 */ + int idx; +} array_enumerator_t; + +METHOD(enumerator_t, enumerate, bool, + array_enumerator_t *this, void **out) +{ + void *pos; + + if (this->idx >= this->array->count) + { + return FALSE; + } + + pos = this->array->data + + get_size(this->array, this->idx + this->array->head); + if (this->array->esize) + { + /* for element based arrays we return a pointer to the element */ + *out = pos; + } + else + { + /* for pointer based arrays we return the pointer directly */ + *out = *(void**)pos; + } + this->idx++; + return TRUE; +} + +enumerator_t* array_create_enumerator(array_t *array) +{ + array_enumerator_t *enumerator; + + if (!array) + { + return enumerator_create_empty(); + } + + INIT(enumerator, + .public = { + .enumerate = (void*)_enumerate, + .destroy = (void*)free, + }, + .array = array, + ); + return &enumerator->public; +} + +void array_remove_at(array_t *array, enumerator_t *public) +{ + array_enumerator_t *enumerator = (array_enumerator_t*)public; + + if (enumerator->idx) + { + array_remove(array, --enumerator->idx, NULL); + } +} + +void array_insert_create(array_t **array, int idx, void *ptr) +{ + if (*array == NULL) + { + *array = array_create(0, 0); + } + array_insert(*array, idx, ptr); +} + +void array_insert_enumerator(array_t *array, int idx, enumerator_t *enumerator) +{ + void *ptr; + + while (enumerator->enumerate(enumerator, &ptr)) + { + array_insert(array, idx, ptr); + } + enumerator->destroy(enumerator); +} + +void array_insert(array_t *array, int idx, void *data) +{ + if (idx < 0 || idx <= array_count(array)) + { + void *pos; + + if (idx < 0) + { + idx = array_count(array); + } + + if (array->head && !array->tail) + { + insert_head(array, idx); + } + else if (array->tail && !array->head) + { + insert_tail(array, idx); + } + else if (idx > array_count(array) / 2) + { + insert_tail(array, idx); + } + else + { + insert_head(array, idx); + } + + pos = array->data + get_size(array, array->head + idx); + if (array->esize) + { + memcpy(pos, data, get_size(array, 1)); + } + else + { + /* pointer based array, copy pointer value */ + *(void**)pos = data; + } + } +} + +bool array_remove(array_t *array, int idx, void *data) +{ + if (!array) + { + return FALSE; + } + if (idx >= 0 && idx >= array_count(array)) + { + return FALSE; + } + if (idx < 0) + { + if (array_count(array) == 0) + { + return FALSE; + } + idx = array_count(array) - 1; + } + if (data) + { + memcpy(data, array->data + get_size(array, array->head + idx), + get_size(array, 1)); + } + if (idx > array_count(array) / 2) + { + remove_tail(array, idx); + } + else + { + remove_head(array, idx); + } + if (array->head + array->tail > ARRAY_MAX_UNUSED) + { + array_compress(array); + } + return TRUE; +} + +void array_invoke(array_t *array, array_callback_t cb, void *user) +{ + if (array) + { + void *obj; + int i; + + for (i = array->head; i < array->count + array->head; i++) + { + obj = array->data + get_size(array, i); + if (!array->esize) + { + /* dereference if we store store pointers */ + obj = *(void**)obj; + } + cb(obj, i - array->head, user); + } + } +} + +void array_invoke_offset(array_t *array, size_t offset) +{ + if (array) + { + void (*method)(void *data); + void *obj; + int i; + + for (i = array->head; i < array->count + array->head; i++) + { + obj = array->data + get_size(array, i); + if (!array->esize) + { + /* dereference if we store store pointers */ + obj = *(void**)obj; + } + method = *(void**)(obj + offset); + method(obj); + } + } +} + +void array_destroy(array_t *array) +{ + if (array) + { + free(array->data); + free(array); + } +} + +void array_destroy_function(array_t *array, array_callback_t cb, void *user) +{ + array_invoke(array, cb, user); + array_destroy(array); +} + +void array_destroy_offset(array_t *array, size_t offset) +{ + array_invoke_offset(array, offset); + array_destroy(array); +} diff --git a/src/libstrongswan/collections/array.h b/src/libstrongswan/collections/array.h new file mode 100644 index 000000000..3e6180b54 --- /dev/null +++ b/src/libstrongswan/collections/array.h @@ -0,0 +1,194 @@ +/* + * Copyright (C) 2013 Martin Willi + * Copyright (C) 2013 revosec AG + * + * 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. + */ + +/** + * @defgroup array array + * @{ @ingroup collections + */ + +#ifndef ARRAY_H_ +#define ARRAY_H_ + +#include <collections/enumerator.h> + +/** + * Variable sized array with fixed size elements. + * + * An array is a primitive object with associated functions to avoid the + * overhead of an object with methods. It is efficient in memory usage, but + * less effecient than a linked list in manipulating elements. + */ +typedef struct array_t array_t; + +typedef enum array_idx_t array_idx_t; + +/** + * Special array index values for insert/remove. + */ +enum array_idx_t { + ARRAY_HEAD = 0, + ARRAY_TAIL = -1, +}; + +/** + * Callback function invoked for each array element. + * + * Data is a pointer to the array element. If this is a pointer based array, + * (esize is zero), data is the pointer itself. + * + * @param data pointer to array data, or the pointer itself + * @param idx array index + * @param user user data passed with callback + */ +typedef void (*array_callback_t)(void *data, int idx, void *user); + +/** + * Create a array instance. + * + * Elements get tight packed to each other. If any alignment is required, pass + * appropriate padding to each element. The reserved space does not affect + * array_count(), but just preallocates buffer space. + * + * @param esize element size for this array, use 0 for a pointer array + * @param reserve number of items to allocate space for + * @return array instance + */ +array_t *array_create(u_int esize, u_int8_t reserve); + +/** + * Get the number of elements currently in the array. + * + * @return number of elements + */ +int array_count(array_t *array); + +/** + * Compress an array, remove unused head/tail space. + * + * @param array array to compress, or NULL + */ +void array_compress(array_t *array); + +/** + * Create an enumerator over an array. + * + * The enumerater enumerates directly over the array element (pass a pointer to + * element types), unless the array is pointer based. If zero is passed as + * element size during construction, the enumerator enumerates over the + * deferenced pointer values. + * + * @param array array to create enumerator for, or NULL + * @return enumerator, over elements or pointers + */ +enumerator_t* array_create_enumerator(array_t *array); + +/** + * Remove an element at enumerator position. + * + * @param array array to remove element in + * @param enumerator enumerator position, from array_create_enumerator() + */ +void array_remove_at(array_t *array, enumerator_t *enumerator); + +/** + * Insert an element to an array. + * + * If the array is pointer based (esize = 0), the pointer itself is appended. + * Otherwise the element gets copied from the pointer. + * The idx must be either within array_count() or one above to append the item. + * Passing -1 has the same effect as passing array_count(), i.e. appends the + * item. It is always valid to pass idx 0 to prepend the item. + * + * @param array array to append element to + * @param idx index to insert item at + * @param data pointer to array element to copy + */ +void array_insert(array_t *array, int idx, void *data); + +/** + * Create an pointer based array if it does not exist, insert pointer. + * + * This is a convenience function for insert a pointer and implicitly + * create a pointer based array if array is NULL. Array is set the the newly + * created array, if any. + * + * @param array pointer to array reference, potentially NULL + * @param idx index to insert item at + * @param ptr pointer to append + */ +void array_insert_create(array_t **array, int idx, void *ptr); + +/** + * Insert all items from an enumerator to an array. + * + * @param array array to add items to + * @param idx index to insert each item with + * @param enumerator enumerator over void*, gets destroyed + */ +void array_insert_enumerator(array_t *array, int idx, enumerator_t *enumerator); + +/** + * Remove an element from the array end. + * + * If data is given, the element is copied to that position. + * + * @param array array to remove element from, or NULL + * @param data data to copy element to, or NULL + * @return TRUE if idx existed and item removed + */ +bool array_remove(array_t *array, int idx, void *data); + +/** + * Invoke a callback for all array members. + * + * @param array array to traverse, or NULL + * @param cb callback function to invoke each element with + * @param user user data to pass to callback + */ +void array_invoke(array_t *array, array_callback_t cb, void *user); + +/** + * Invoke a method of each element defined with offset. + * + * @param array array to traverse, or NULL + * @param offset offset of element method, use offsetof() + */ +void array_invoke_offset(array_t *array, size_t offset); + +/** + * Destroy an array. + * + * @param array array to destroy, or NULL + */ +void array_destroy(array_t *array); + +/** + * Destroy an array, call a function to clean up all elements. + * + * @param array array to destroy, or NULL + * @param cb callback function to free element data + * @param user user data to pass to callback + */ +void array_destroy_function(array_t *array, array_callback_t cb, void *user); + +/** + * Destroy an array, call element method defined with offset. + * + * @param array array to destroy, or NULL + * @param offset offset of element method, use offsetof() + */ +void array_destroy_offset(array_t *array, size_t offset); + +#endif /** ARRAY_H_ @}*/ diff --git a/src/libstrongswan/credentials/auth_cfg.c b/src/libstrongswan/credentials/auth_cfg.c index d2d0a7d72..2203519e2 100644 --- a/src/libstrongswan/credentials/auth_cfg.c +++ b/src/libstrongswan/credentials/auth_cfg.c @@ -18,7 +18,7 @@ #include <library.h> #include <utils/debug.h> -#include <collections/linked_list.h> +#include <collections/array.h> #include <utils/identification.h> #include <eap/eap.h> #include <credentials/certificates/certificate.h> @@ -109,9 +109,9 @@ struct private_auth_cfg_t { auth_cfg_t public; /** - * list of entry_t + * Array of entry_t */ - linked_list_t *entries; + array_t *entries; }; typedef struct entry_t entry_t; @@ -184,18 +184,16 @@ METHOD(auth_cfg_t, create_enumerator, enumerator_t*, .enumerate = (void*)enumerate, .destroy = (void*)entry_enumerator_destroy, }, - .inner = this->entries->create_enumerator(this->entries), + .inner = array_create_enumerator(this->entries), ); return &enumerator->public; } /** - * Create an entry from the given arguments. + * Initialize an entry. */ -static entry_t *entry_create(auth_rule_t type, va_list args) +static void init_entry(entry_t *this, auth_rule_t type, va_list args) { - entry_t *this = malloc_thing(entry_t); - this->type = type; switch (type) { @@ -233,7 +231,6 @@ static entry_t *entry_create(auth_rule_t type, va_list args) this->value = NULL; break; } - return this; } /** @@ -481,21 +478,21 @@ METHOD(auth_cfg_t, get, void*, */ static void add(private_auth_cfg_t *this, auth_rule_t type, ...) { - entry_t *entry; + entry_t entry; va_list args; va_start(args, type); - entry = entry_create(type, args); + init_entry(&entry, type, args); va_end(args); if (is_multi_value_rule(type)) { /* insert rules that may occur multiple times at the end */ - this->entries->insert_last(this->entries, entry); + array_insert(this->entries, ARRAY_TAIL, &entry); } else { /* insert rules we expect only once at the front (get() will return * the latest value) */ - this->entries->insert_first(this->entries, entry); + array_insert(this->entries, ARRAY_HEAD, &entry); } } @@ -917,13 +914,13 @@ static void merge(private_auth_cfg_t *this, private_auth_cfg_t *other, bool copy } else { - entry_t *entry; + entry_t entry; - while (other->entries->remove_first(other->entries, - (void**)&entry) == SUCCESS) + while (array_remove(other->entries, ARRAY_HEAD, &entry)) { - this->entries->insert_last(this->entries, entry); + array_insert(this->entries, ARRAY_TAIL, &entry); } + array_compress(other->entries); } } @@ -938,12 +935,12 @@ static bool auth_cfg_equals(private_auth_cfg_t *this, private_auth_cfg_t *other) /* the rule count does not have to be equal for the two, as we only compare * the first value found for some rules */ - e1 = this->entries->create_enumerator(this->entries); + e1 = array_create_enumerator(this->entries); while (e1->enumerate(e1, &i1)) { found = FALSE; - e2 = other->entries->create_enumerator(other->entries); + e2 = array_create_enumerator(other->entries); while (e2->enumerate(e2, &i2)) { if (entry_equals(i1, i2)) @@ -984,27 +981,21 @@ static bool equals(private_auth_cfg_t *this, private_auth_cfg_t *other) METHOD(auth_cfg_t, purge, void, private_auth_cfg_t *this, bool keep_ca) { + enumerator_t *enumerator; entry_t *entry; - linked_list_t *cas; - cas = linked_list_create(); - while (this->entries->remove_last(this->entries, (void**)&entry) == SUCCESS) + enumerator = array_create_enumerator(this->entries); + while (enumerator->enumerate(enumerator, &entry)) { - if (keep_ca && entry->type == AUTH_RULE_CA_CERT) - { - cas->insert_first(cas, entry); - } - else + if (!keep_ca || entry->type != AUTH_RULE_CA_CERT) { + array_remove_at(this->entries, enumerator); destroy_entry_value(entry); - free(entry); } } - while (cas->remove_last(cas, (void**)&entry) == SUCCESS) - { - this->entries->insert_first(this->entries, entry); - } - cas->destroy(cas); + enumerator->destroy(enumerator); + + array_compress(this->entries); } METHOD(auth_cfg_t, clone_, auth_cfg_t*, @@ -1074,7 +1065,7 @@ METHOD(auth_cfg_t, destroy, void, private_auth_cfg_t *this) { purge(this, FALSE); - this->entries->destroy(this->entries); + array_destroy(this->entries); free(this); } @@ -1098,7 +1089,7 @@ auth_cfg_t *auth_cfg_create() .clone = _clone_, .destroy = _destroy, }, - .entries = linked_list_create(), + .entries = array_create(sizeof(entry_t), 0), ); return &this->public; diff --git a/src/libstrongswan/tests/Makefile.am b/src/libstrongswan/tests/Makefile.am index ca0a8c1ed..f175aa4a7 100644 --- a/src/libstrongswan/tests/Makefile.am +++ b/src/libstrongswan/tests/Makefile.am @@ -7,7 +7,7 @@ test_runner_SOURCES = \ test_linked_list.c test_enumerator.c test_linked_list_enumerator.c \ test_bio_reader.c test_bio_writer.c test_chunk.c test_enum.c test_hashtable.c \ test_identification.c test_threading.c test_utils.c test_vectors.c \ - test_ecdsa.c test_rsa.c + test_array.c test_ecdsa.c test_rsa.c test_runner_CFLAGS = \ -I$(top_srcdir)/src/libstrongswan \ diff --git a/src/libstrongswan/tests/test_array.c b/src/libstrongswan/tests/test_array.c new file mode 100644 index 000000000..2220d5a2b --- /dev/null +++ b/src/libstrongswan/tests/test_array.c @@ -0,0 +1,360 @@ +/* + * Copyright (C) 2013 Martin Willi + * Copyright (C) 2013 revosec AG + * + * 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 "test_suite.h" + +#include <collections/array.h> + +START_TEST(test_append_ptr) +{ + array_t *array; + uintptr_t x; + int i; + + array = array_create(0, 0); + + for (i = 0; i < 4; i++) + { + ck_assert_int_eq(array_count(array), 0); + + array_insert(array, ARRAY_HEAD, (void*)(uintptr_t)3); + array_insert(array, ARRAY_TAIL, (void*)(uintptr_t)4); + ck_assert_int_eq(array_count(array), 2); + + /* 3, 4 */ + + array_insert(array, ARRAY_HEAD, (void*)(uintptr_t)1); + array_insert(array, 1, (void*)(uintptr_t)2); + ck_assert_int_eq(array_count(array), 4); + + /* 1, 2, 3, 4 */ + + array_insert(array, ARRAY_TAIL, (void*)(uintptr_t)5); + array_insert(array, ARRAY_HEAD, (void*)(uintptr_t)0); + ck_assert_int_eq(array_count(array), 6); + + /* 0, 1, 2, 3, 4, 5 */ + + ck_assert(array_remove(array, ARRAY_TAIL, &x)); + ck_assert_int_eq(x, 5); + ck_assert(array_remove(array, 4, &x)); + ck_assert_int_eq(x, 4); + + if (i < 3) + { + array_compress(array); + } + + /* 0, 1, 2, 3 */ + + ck_assert(array_remove(array, 1, &x)); + ck_assert_int_eq(x, 1); + ck_assert(array_remove(array, ARRAY_HEAD, &x)); + ck_assert_int_eq(x, 0); + + if (i < 2) + { + array_compress(array); + } + + /* 2, 3 */ + + ck_assert(array_remove(array, ARRAY_TAIL, &x)); + ck_assert_int_eq(x, 3); + ck_assert(array_remove(array, ARRAY_TAIL, &x)); + ck_assert_int_eq(x, 2); + + if (i < 1) + { + array_compress(array); + } + + ck_assert_int_eq(array_count(array), 0); + + ck_assert(array_remove(array, ARRAY_HEAD, NULL) == FALSE); + ck_assert(array_remove(array, ARRAY_TAIL, NULL) == FALSE); + } + + array_destroy(array); +} +END_TEST + +START_TEST(test_append_obj) +{ + array_t *array; + int i, x, y[6] = {0, 1, 2, 3, 4, 5}; + + array = array_create(sizeof(y[0]), 0); + + for (i = 0; i < 4; i++) + { + ck_assert_int_eq(array_count(array), 0); + + array_insert(array, ARRAY_HEAD, &y[3]); + array_insert(array, ARRAY_TAIL, &y[4]); + ck_assert_int_eq(array_count(array), 2);; + + /* 3, 4 */ + + array_insert(array, ARRAY_HEAD, &y[1]); + array_insert(array, 1, &y[2]); + ck_assert_int_eq(array_count(array), 4); + + /* 1, 2, 3, 4 */ + + array_insert(array, ARRAY_TAIL, &y[5]); + array_insert(array, ARRAY_HEAD, &y[0]); + ck_assert_int_eq(array_count(array), 6); + + /* 0, 1, 2, 3, 4, 5 */ + + ck_assert(array_remove(array, ARRAY_TAIL, &x)); + ck_assert_int_eq(x, 5); + ck_assert(array_remove(array, 4, &x)); + ck_assert_int_eq(x, 4); + + if (i < 3) + { + array_compress(array); + } + + /* 0, 1, 2, 3 */ + + ck_assert(array_remove(array, ARRAY_HEAD, &x)); + ck_assert_int_eq(x, 0); + ck_assert(array_remove(array, ARRAY_HEAD, &x)); + ck_assert_int_eq(x, 1); + + if (i < 2) + { + array_compress(array); + } + + /* 2, 3 */ + + ck_assert(array_remove(array, ARRAY_TAIL, &x)); + ck_assert_int_eq(x, 3); + ck_assert(array_remove(array, ARRAY_HEAD, &x)); + ck_assert_int_eq(x, 2); + + if (i < 1) + { + array_compress(array); + } + + ck_assert_int_eq(array_count(array), 0); + + ck_assert(array_remove(array, ARRAY_HEAD, NULL) == FALSE); + ck_assert(array_remove(array, ARRAY_TAIL, NULL) == FALSE); + } + + array_destroy(array); +} +END_TEST + +START_TEST(test_enumerate) +{ + array_t *array; + int i, *x, y[6] = {0, 1, 2, 3, 4, 5}; + enumerator_t *enumerator; + + array = array_create(sizeof(y[0]), 0); + + array_insert(array, ARRAY_TAIL, &y[0]); + array_insert(array, ARRAY_TAIL, &y[1]); + array_insert(array, ARRAY_TAIL, &y[2]); + array_insert(array, ARRAY_TAIL, &y[3]); + array_insert(array, ARRAY_TAIL, &y[4]); + array_insert(array, ARRAY_TAIL, &y[5]); + + ck_assert_int_eq(array_count(array), 6); + + /* 0, 1, 2, 3, 4, 5 */ + + i = 0; + enumerator = array_create_enumerator(array); + while (enumerator->enumerate(enumerator, &x)) + { + ck_assert_int_eq(*x, y[i]); + i++; + } + enumerator->destroy(enumerator); + ck_assert_int_eq(i, 6); + + i = 0; + enumerator = array_create_enumerator(array); + while (enumerator->enumerate(enumerator, &x)) + { + ck_assert_int_eq(*x, y[i]); + if (i == 0 || i == 3 || i == 5) + { + array_remove_at(array, enumerator); + } + i++; + } + enumerator->destroy(enumerator); + ck_assert_int_eq(i, 6); + ck_assert_int_eq(array_count(array), 3); + + /* 1, 2, 4 */ + + i = 0; + enumerator = array_create_enumerator(array); + while (enumerator->enumerate(enumerator, &x)) + { + switch (i++) + { + case 0: + ck_assert_int_eq(*x, y[1]); + break; + case 1: + ck_assert_int_eq(*x, y[2]); + break; + case 2: + ck_assert_int_eq(*x, y[4]); + break; + default: + ck_assert(0); + } + } + enumerator->destroy(enumerator); + + array_compress(array); + + i = 0; + enumerator = array_create_enumerator(array); + while (enumerator->enumerate(enumerator, &x)) + { + switch (i++) + { + case 0: + ck_assert_int_eq(*x, y[1]); + break; + case 1: + ck_assert_int_eq(*x, y[2]); + break; + case 2: + ck_assert_int_eq(*x, y[4]); + break; + default: + ck_assert(0); + } + } + enumerator->destroy(enumerator); + + array_destroy(array); +} +END_TEST + +static void invoke(void *data, int idx, void *user) +{ + int *y = user, *x = data; + + ck_assert(idx < 3); + + ck_assert_int_eq(y[idx], *x); + y[idx] = 0; +} + +START_TEST(test_invoke) +{ + array_t *array; + int y[] = {1, 2, 3}; + + array = array_create(sizeof(y[0]), 0); + + array_insert(array, ARRAY_TAIL, &y[0]); + array_insert(array, ARRAY_TAIL, &y[1]); + array_insert(array, ARRAY_TAIL, &y[2]); + + array_invoke(array, invoke, y); + + ck_assert_int_eq(y[0], 0); + ck_assert_int_eq(y[0], 0); + ck_assert_int_eq(y[0], 0); + + array_destroy(array); +} +END_TEST + +typedef struct obj_t obj_t; + +struct obj_t { + void (*fun)(obj_t *obj); + int x; + int *counter; +}; + +static void fun(obj_t *obj) +{ + ck_assert(obj->x == (*obj->counter)++); +} + +START_TEST(test_invoke_offset) +{ + array_t *array; + obj_t objs[5]; + int i, counter = 0; + + array = array_create(0, 0); + + for (i = 0; i < countof(objs); i++) + { + objs[i].x = i; + objs[i].counter = &counter; + objs[i].fun = fun; + + array_insert(array, ARRAY_TAIL, &objs[i]); + } + + ck_assert_int_eq(countof(objs), array_count(array)); + + array_invoke_offset(array, offsetof(obj_t, fun)); + + ck_assert_int_eq(counter, countof(objs)); + + array_destroy(array); +} +END_TEST + +Suite *array_suite_create() +{ + Suite *s; + TCase *tc; + + s = suite_create("array"); + + tc = tcase_create("add/remove ptr"); + tcase_add_test(tc, test_append_ptr); + suite_add_tcase(s, tc); + + tc = tcase_create("add/remove obj"); + tcase_add_test(tc, test_append_obj); + suite_add_tcase(s, tc); + + tc = tcase_create("enumerate"); + tcase_add_test(tc, test_enumerate); + suite_add_tcase(s, tc); + + tc = tcase_create("invoke"); + tcase_add_test(tc, test_invoke); + suite_add_tcase(s, tc); + + tc = tcase_create("invoke offset"); + tcase_add_test(tc, test_invoke_offset); + suite_add_tcase(s, tc); + + return s; +} diff --git a/src/libstrongswan/tests/test_runner.c b/src/libstrongswan/tests/test_runner.c index 2f9e4dc0a..b9e1901b0 100644 --- a/src/libstrongswan/tests/test_runner.c +++ b/src/libstrongswan/tests/test_runner.c @@ -78,6 +78,7 @@ int main() srunner_add_suite(sr, linked_list_suite_create()); srunner_add_suite(sr, linked_list_enumerator_suite_create()); srunner_add_suite(sr, hashtable_suite_create()); + srunner_add_suite(sr, array_suite_create()); srunner_add_suite(sr, identification_suite_create()); srunner_add_suite(sr, threading_suite_create()); srunner_add_suite(sr, utils_suite_create()); diff --git a/src/libstrongswan/tests/test_runner.h b/src/libstrongswan/tests/test_runner.h index 5c60588e9..34aa0cf18 100644 --- a/src/libstrongswan/tests/test_runner.h +++ b/src/libstrongswan/tests/test_runner.h @@ -26,6 +26,7 @@ Suite *enumerator_suite_create(); Suite *linked_list_suite_create(); Suite *linked_list_enumerator_suite_create(); Suite *hashtable_suite_create(); +Suite *array_suite_create(); Suite *identification_suite_create(); Suite *threading_suite_create(); Suite *utils_suite_create(); |