diff options
author | Rene Mayrhofer <rene@mayrhofer.eu.org> | 2010-02-23 10:42:46 +0000 |
---|---|---|
committer | Rene Mayrhofer <rene@mayrhofer.eu.org> | 2010-02-23 10:42:46 +0000 |
commit | de6b12502cdf42d5d92118f1c0e38dc31becf7c5 (patch) | |
tree | 0edac9c79f5a43e01913dd7f71c7abc487e5727b /src/charon/sa/connect_manager.c | |
parent | 172642669d4a23e17f1ed411fbc8629dcaa5fb46 (diff) | |
download | vyos-strongswan-de6b12502cdf42d5d92118f1c0e38dc31becf7c5.tar.gz vyos-strongswan-de6b12502cdf42d5d92118f1c0e38dc31becf7c5.zip |
Updated to new upstream release. interfaces Patch is not from upstream.
Diffstat (limited to 'src/charon/sa/connect_manager.c')
-rw-r--r-- | src/charon/sa/connect_manager.c | 663 |
1 files changed, 356 insertions, 307 deletions
diff --git a/src/charon/sa/connect_manager.c b/src/charon/sa/connect_manager.c index f26cf9405..b78ba070d 100644 --- a/src/charon/sa/connect_manager.c +++ b/src/charon/sa/connect_manager.c @@ -18,7 +18,7 @@ #include <math.h> #include <daemon.h> -#include <utils/mutex.h> +#include <threading/mutex.h> #include <utils/linked_list.h> #include <crypto/hashers/hasher.h> @@ -42,7 +42,6 @@ * the first check has succeeded */ #define ME_WAIT_TO_FINISH 1000 /* ms */ - typedef struct private_connect_manager_t private_connect_manager_t; /** @@ -53,24 +52,25 @@ struct private_connect_manager_t { * Public interface of connect_manager_t. */ connect_manager_t public; - + /** * Lock for exclusivly accessing the manager. */ mutex_t *mutex; - + /** * Hasher to generate signatures */ hasher_t *hasher; - + /** * Linked list with initiated mediated connections */ linked_list_t *initiated; - + /** - * Linked list with checklists (hash table with connect ID as key would be better). + * Linked list with checklists (hash table with connect ID as key would + * be better). */ linked_list_t *checklists; }; @@ -93,24 +93,24 @@ typedef struct endpoint_pair_t endpoint_pair_t; struct endpoint_pair_t { /** pair id */ u_int32_t id; - + /** priority */ u_int64_t priority; - + /** local endpoint */ - host_t *local; - - /** remote endpoint */ - host_t *remote; - - /** state */ - check_state_t state; - - /** number of retransmissions */ - u_int32_t retransmitted; - - /** the generated packet */ - packet_t *packet; + host_t *local; + + /** remote endpoint */ + host_t *remote; + + /** state */ + check_state_t state; + + /** number of retransmissions */ + u_int32_t retransmitted; + + /** the generated packet */ + packet_t *packet; }; /** @@ -119,8 +119,8 @@ struct endpoint_pair_t { static void endpoint_pair_destroy(endpoint_pair_t *this) { DESTROY_IF(this->local); - DESTROY_IF(this->remote); - DESTROY_IF(this->packet); + DESTROY_IF(this->remote); + DESTROY_IF(this->packet); free(this); } @@ -131,22 +131,24 @@ static endpoint_pair_t *endpoint_pair_create(endpoint_notify_t *initiator, endpoint_notify_t *responder, bool initiator_is_local) { endpoint_pair_t *this = malloc_thing(endpoint_pair_t); - + this->id = 0; - + u_int32_t pi = initiator->get_priority(initiator); u_int32_t pr = responder->get_priority(responder); this->priority = pow(2, 32) * min(pi, pr) + 2 * max(pi, pr) + (pi > pr ? 1 : 0); - - this->local = initiator_is_local ? initiator->get_base(initiator) : responder->get_base(responder); + + this->local = initiator_is_local ? initiator->get_base(initiator) + : responder->get_base(responder); this->local = this->local->clone(this->local); - this->remote = initiator_is_local ? responder->get_host(responder) : initiator->get_host(initiator); + this->remote = initiator_is_local ? responder->get_host(responder) + : initiator->get_host(initiator); this->remote = this->remote->clone(this->remote); - + this->state = CHECK_WAITING; this->retransmitted = 0; this->packet = NULL; - + return this; } @@ -157,50 +159,50 @@ typedef struct check_list_t check_list_t; * An entry in the linked list. */ struct check_list_t { - + struct { /** initiator's id */ identification_t *id; - + /** initiator's key */ chunk_t key; - + /** initiator's endpoints */ linked_list_t *endpoints; } initiator; - + struct { /** responder's id */ identification_t *id; - + /** responder's key */ chunk_t key; - + /** responder's endpoints */ linked_list_t *endpoints; } responder; - + /** connect id */ chunk_t connect_id; - - /** list of endpoint pairs */ - linked_list_t *pairs; - - /** pairs queued for triggered checks */ - linked_list_t *triggered; - - /** state */ - check_state_t state; - - /** TRUE if this is the initiator */ + + /** list of endpoint pairs */ + linked_list_t *pairs; + + /** pairs queued for triggered checks */ + linked_list_t *triggered; + + /** state */ + check_state_t state; + + /** TRUE if this is the initiator */ bool is_initiator; - + /** TRUE if the initiator is finishing the checks */ bool is_finishing; - + /** the current sender job */ job_t *sender; - + }; /** @@ -210,46 +212,51 @@ static void check_list_destroy(check_list_t *this) { DESTROY_IF(this->initiator.id); DESTROY_IF(this->responder.id); - + chunk_free(&this->connect_id); chunk_free(&this->initiator.key); chunk_free(&this->responder.key); - - DESTROY_OFFSET_IF(this->initiator.endpoints, offsetof(endpoint_notify_t, destroy)); - DESTROY_OFFSET_IF(this->responder.endpoints, offsetof(endpoint_notify_t, destroy)); - + + DESTROY_OFFSET_IF(this->initiator.endpoints, + offsetof(endpoint_notify_t, destroy)); + DESTROY_OFFSET_IF(this->responder.endpoints, + offsetof(endpoint_notify_t, destroy)); + DESTROY_FUNCTION_IF(this->pairs, (void*)endpoint_pair_destroy); - /* this list contains some of the same elements as contained in this->pairs */ - DESTROY_IF(this->triggered); - + /* this list contains some of the elements contained in this->pairs */ + DESTROY_IF(this->triggered); + free(this); } /** * Creates a new checklist */ -static check_list_t *check_list_create(identification_t *initiator, identification_t *responder, - chunk_t connect_id, chunk_t initiator_key, linked_list_t *initiator_endpoints, - bool is_initiator) +static check_list_t *check_list_create(identification_t *initiator, + identification_t *responder, + chunk_t connect_id, + chunk_t initiator_key, + linked_list_t *initiator_endpoints, + bool is_initiator) { check_list_t *this = malloc_thing(check_list_t); - + this->connect_id = chunk_clone(connect_id); - + this->initiator.id = initiator->clone(initiator); this->initiator.key = chunk_clone(initiator_key); this->initiator.endpoints = initiator_endpoints->clone_offset(initiator_endpoints, offsetof(endpoint_notify_t, clone)); - + this->responder.id = responder->clone(responder); this->responder.key = chunk_empty; - this->responder.endpoints = NULL; - - this->pairs = linked_list_create(); - this->triggered = linked_list_create(); - this->state = CHECK_NONE; - this->is_initiator = is_initiator; - this->is_finishing = FALSE; - + this->responder.endpoints = NULL; + + this->pairs = linked_list_create(); + this->triggered = linked_list_create(); + this->state = CHECK_NONE; + this->is_initiator = is_initiator; + this->is_finishing = FALSE; + return this; } @@ -261,10 +268,10 @@ typedef struct initiated_t initiated_t; struct initiated_t { /** my id */ identification_t *id; - + /** peer id */ identification_t *peer_id; - + /** list of mediated sas */ linked_list_t *mediated; }; @@ -276,21 +283,23 @@ static void initiated_destroy(initiated_t *this) { DESTROY_IF(this->id); DESTROY_IF(this->peer_id); - this->mediated->destroy_offset(this->mediated, offsetof(ike_sa_id_t, destroy)); + this->mediated->destroy_offset(this->mediated, + offsetof(ike_sa_id_t, destroy)); free(this); } /** * Creates a queued initiation */ -static initiated_t *initiated_create(identification_t *id, identification_t *peer_id) +static initiated_t *initiated_create(identification_t *id, + identification_t *peer_id) { initiated_t *this = malloc_thing(initiated_t); - + this->id = id->clone(id); this->peer_id = peer_id->clone(peer_id); this->mediated = linked_list_create(); - + return this; } @@ -303,24 +312,24 @@ typedef struct check_t check_t; struct check_t { /** message id */ u_int32_t mid; - + /** source of the connectivity check */ host_t *src; - + /** destination of the connectivity check */ host_t *dst; - + /** connect id */ chunk_t connect_id; - + /** endpoint */ endpoint_notify_t *endpoint; - + /** raw endpoint payload (to verify the signature) */ chunk_t endpoint_raw; - - /** connect auth */ - chunk_t auth; + + /** connect auth */ + chunk_t auth; }; /** @@ -343,16 +352,16 @@ static void check_destroy(check_t *this) static check_t *check_create() { check_t *this = malloc_thing(check_t); - + this->connect_id = chunk_empty; this->auth = chunk_empty; this->endpoint_raw = chunk_empty; this->src = NULL; this->dst = NULL; this->endpoint = NULL; - + this->mid = 0; - + return this; } @@ -364,10 +373,10 @@ typedef struct callback_data_t callback_data_t; struct callback_data_t { /** connect manager */ private_connect_manager_t *connect_manager; - + /** connect id */ chunk_t connect_id; - + /** message (pair) id */ u_int32_t mid; }; @@ -385,9 +394,9 @@ static void callback_data_destroy(callback_data_t *this) * Creates a new callback data object */ static callback_data_t *callback_data_create(private_connect_manager_t *connect_manager, - chunk_t connect_id) + chunk_t connect_id) { - callback_data_t *this = malloc_thing(callback_data_t); + callback_data_t *this = malloc_thing(callback_data_t); this->connect_manager = connect_manager; this->connect_id = chunk_clone(connect_id); this->mid = 0; @@ -398,7 +407,7 @@ static callback_data_t *callback_data_create(private_connect_manager_t *connect_ * Creates a new retransmission data object */ static callback_data_t *retransmit_data_create(private_connect_manager_t *connect_manager, - chunk_t connect_id, u_int32_t mid) + chunk_t connect_id, u_int32_t mid) { callback_data_t *this = callback_data_create(connect_manager, connect_id); this->mid = mid; @@ -413,7 +422,7 @@ typedef struct initiate_data_t initiate_data_t; struct initiate_data_t { /** checklist */ check_list_t *checklist; - + /** waiting mediated connections */ initiated_t *initiated; }; @@ -431,10 +440,11 @@ static void initiate_data_destroy(initiate_data_t *this) /** * Creates a new initiate data object */ -static initiate_data_t *initiate_data_create(check_list_t *checklist, initiated_t *initiated) +static initiate_data_t *initiate_data_create(check_list_t *checklist, + initiated_t *initiated) { initiate_data_t *this = malloc_thing(initiate_data_t); - + this->checklist = checklist; this->initiated = initiated; @@ -445,27 +455,30 @@ static initiate_data_t *initiate_data_create(check_list_t *checklist, initiated_ * Find an initiated connection by the peers' ids */ static bool match_initiated_by_ids(initiated_t *current, identification_t *id, - identification_t *peer_id) + identification_t *peer_id) { return id->equals(id, current->id) && peer_id->equals(peer_id, current->peer_id); } static status_t get_initiated_by_ids(private_connect_manager_t *this, - identification_t *id, identification_t *peer_id, initiated_t **initiated) + identification_t *id, + identification_t *peer_id, + initiated_t **initiated) { return this->initiated->find_first(this->initiated, - (linked_list_match_t)match_initiated_by_ids, - (void**)initiated, id, peer_id); + (linked_list_match_t)match_initiated_by_ids, + (void**)initiated, id, peer_id); } /** * Removes data about initiated connections */ -static void remove_initiated(private_connect_manager_t *this, initiated_t *initiated) +static void remove_initiated(private_connect_manager_t *this, + initiated_t *initiated) { iterator_t *iterator; initiated_t *current; - + iterator = this->initiated->create_iterator(this->initiated, TRUE); while (iterator->iterate(iterator, (void**)¤t)) { @@ -487,21 +500,23 @@ static bool match_checklist_by_id(check_list_t *current, chunk_t *connect_id) } static status_t get_checklist_by_id(private_connect_manager_t *this, - chunk_t connect_id, check_list_t **check_list) + chunk_t connect_id, + check_list_t **check_list) { return this->checklists->find_first(this->checklists, - (linked_list_match_t)match_checklist_by_id, - (void**)check_list, &connect_id); + (linked_list_match_t)match_checklist_by_id, + (void**)check_list, &connect_id); } /** * Removes a checklist */ -static void remove_checklist(private_connect_manager_t *this, check_list_t *checklist) +static void remove_checklist(private_connect_manager_t *this, + check_list_t *checklist) { iterator_t *iterator; check_list_t *current; - + iterator = this->checklists->create_iterator(this->checklists, TRUE); while (iterator->iterate(iterator, (void**)¤t)) { @@ -522,22 +537,23 @@ static bool match_endpoint_by_host(endpoint_notify_t *current, host_t *host) return host->equals(host, current->get_host(current)); } -static status_t endpoints_contain(linked_list_t *endpoints, host_t *host, endpoint_notify_t **endpoint) +static status_t endpoints_contain(linked_list_t *endpoints, host_t *host, + endpoint_notify_t **endpoint) { return endpoints->find_first(endpoints, - (linked_list_match_t)match_endpoint_by_host, - (void**)endpoint, host); + (linked_list_match_t)match_endpoint_by_host, + (void**)endpoint, host); } /** - * Inserts an endpoint pair into the list of pairs ordered by priority (high to low) + * Inserts an endpoint pair into a list of pairs ordered by priority (high to low) */ static void insert_pair_by_priority(linked_list_t *pairs, endpoint_pair_t *pair) { iterator_t *iterator; endpoint_pair_t *current; bool inserted = FALSE; - + iterator = pairs->create_iterator(pairs, TRUE); while (iterator->iterate(iterator, (void**)¤t)) { @@ -549,7 +565,7 @@ static void insert_pair_by_priority(linked_list_t *pairs, endpoint_pair_t *pair) } } iterator->destroy(iterator); - + if (!inserted) { pairs->insert_last(pairs, pair); @@ -559,16 +575,17 @@ static void insert_pair_by_priority(linked_list_t *pairs, endpoint_pair_t *pair) /** * Searches a list of endpoint_pair_t for a pair with specific host_ts */ -static bool match_pair_by_hosts(endpoint_pair_t *current, host_t *local, host_t *remote) +static bool match_pair_by_hosts(endpoint_pair_t *current, host_t *local, + host_t *remote) { return local->equals(local, current->local) && remote->equals(remote, current->remote); } -static status_t get_pair_by_hosts(linked_list_t *pairs, host_t *local, host_t *remote, endpoint_pair_t **pair) +static status_t get_pair_by_hosts(linked_list_t *pairs, host_t *local, + host_t *remote, endpoint_pair_t **pair) { - return pairs->find_first(pairs, - (linked_list_match_t)match_pair_by_hosts, - (void**)pair, local, remote); + return pairs->find_first(pairs, (linked_list_match_t)match_pair_by_hosts, + (void**)pair, local, remote); } static bool match_pair_by_id(endpoint_pair_t *current, u_int32_t *id) @@ -579,11 +596,12 @@ static bool match_pair_by_id(endpoint_pair_t *current, u_int32_t *id) /** * Searches for a pair with a specific id */ -static status_t get_pair_by_id(check_list_t *checklist, u_int32_t id, endpoint_pair_t **pair) +static status_t get_pair_by_id(check_list_t *checklist, u_int32_t id, + endpoint_pair_t **pair) { return checklist->pairs->find_first(checklist->pairs, - (linked_list_match_t)match_pair_by_id, - (void**)pair, &id); + (linked_list_match_t)match_pair_by_id, + (void**)pair, &id); } static bool match_succeeded_pair(endpoint_pair_t *current) @@ -592,13 +610,14 @@ static bool match_succeeded_pair(endpoint_pair_t *current) } /** - * Returns the best pair of state CHECK_SUCCEEDED from a checklist. + * Returns the best pair of state CHECK_SUCCEEDED from a checklist. */ -static status_t get_best_valid_pair(check_list_t *checklist, endpoint_pair_t **pair) +static status_t get_best_valid_pair(check_list_t *checklist, + endpoint_pair_t **pair) { return checklist->pairs->find_first(checklist->pairs, - (linked_list_match_t)match_succeeded_pair, - (void**)pair); + (linked_list_match_t)match_succeeded_pair, + (void**)pair); } static bool match_waiting_pair(endpoint_pair_t *current) @@ -607,19 +626,20 @@ static bool match_waiting_pair(endpoint_pair_t *current) } /** - * Returns and *removes* the first triggered pair in state CHECK_WAITING. + * Returns and *removes* the first triggered pair in state CHECK_WAITING. */ -static status_t get_triggered_pair(check_list_t *checklist, endpoint_pair_t **pair) +static status_t get_triggered_pair(check_list_t *checklist, + endpoint_pair_t **pair) { iterator_t *iterator; endpoint_pair_t *current; status_t status = NOT_FOUND; - + iterator = checklist->triggered->create_iterator(checklist->triggered, TRUE); while (iterator->iterate(iterator, (void**)¤t)) { iterator->remove(iterator); - + if (current->state == CHECK_WAITING) { if (pair) @@ -631,7 +651,7 @@ static status_t get_triggered_pair(check_list_t *checklist, endpoint_pair_t **pa } } iterator->destroy(iterator); - + return status; } @@ -642,13 +662,13 @@ static void print_checklist(check_list_t *checklist) { iterator_t *iterator; endpoint_pair_t *current; - + DBG1(DBG_IKE, "pairs on checklist %#B:", &checklist->connect_id); iterator = checklist->pairs->create_iterator(checklist->pairs, TRUE); while (iterator->iterate(iterator, (void**)¤t)) { DBG1(DBG_IKE, " * %#H - %#H (%d)", current->local, current->remote, - current->priority); + current->priority); } iterator->destroy(iterator); } @@ -662,29 +682,29 @@ static void prune_pairs(linked_list_t *pairs) iterator_t *iterator, *search; endpoint_pair_t *current, *other; u_int32_t id = 0; - + iterator = pairs->create_iterator(pairs, TRUE); search = pairs->create_iterator(pairs, TRUE); while (iterator->iterate(iterator, (void**)¤t)) { current->id = ++id; - + while (search->iterate(search, (void**)&other)) { if (current == other) { continue; } - + if (current->local->equals(current->local, other->local) && - current->remote->equals(current->remote, other->remote)) + current->remote->equals(current->remote, other->remote)) { /* since the list of pairs is sorted by priority in descending * order, and we iterate the list from the beginning, we are * sure that the priority of 'other' is lower than that of * 'current', remove it */ DBG1(DBG_IKE, "pruning endpoint pair %#H - %#H with priority %d", - other->local, other->remote, other->priority); + other->local, other->remote, other->priority); search->remove(search); endpoint_pair_destroy(other); } @@ -703,25 +723,27 @@ static void build_pairs(check_list_t *checklist) /* FIXME: limit endpoints and pairs */ iterator_t *iterator_i, *iterator_r; endpoint_notify_t *initiator, *responder; - - iterator_i = checklist->initiator.endpoints->create_iterator(checklist->initiator.endpoints, TRUE); + + iterator_i = checklist->initiator.endpoints->create_iterator( + checklist->initiator.endpoints, TRUE); while (iterator_i->iterate(iterator_i, (void**)&initiator)) { - iterator_r = checklist->responder.endpoints->create_iterator(checklist->responder.endpoints, TRUE); + iterator_r = checklist->responder.endpoints->create_iterator( + checklist->responder.endpoints, TRUE); while (iterator_r->iterate(iterator_r, (void**)&responder)) { if (initiator->get_family(initiator) != responder->get_family(responder)) { continue; } - - insert_pair_by_priority(checklist->pairs, - endpoint_pair_create(initiator, responder, checklist->is_initiator)); + + insert_pair_by_priority(checklist->pairs, endpoint_pair_create( + initiator, responder, checklist->is_initiator)); } iterator_r->destroy(iterator_r); } iterator_i->destroy(iterator_i); - + print_checklist(checklist); prune_pairs(checklist->pairs); @@ -741,22 +763,24 @@ static status_t process_payloads(message_t *message, check_t *check) if (payload->get_type(payload) != NOTIFY) { DBG1(DBG_IKE, "ignoring payload of type '%N' while processing " - "connectivity check", payload_type_names, payload->get_type(payload)); + "connectivity check", payload_type_names, + payload->get_type(payload)); continue; } - + notify_payload_t *notify = (notify_payload_t*)payload; - + switch (notify->get_notify_type(notify)) { case ME_ENDPOINT: { if (check->endpoint) { - DBG1(DBG_IKE, "connectivity check contains multiple ME_ENDPOINT notifies"); + DBG1(DBG_IKE, "connectivity check contains multiple " + "ME_ENDPOINT notifies"); break; } - + endpoint_notify_t *endpoint = endpoint_notify_create_from_payload(notify); if (!endpoint) { @@ -772,7 +796,8 @@ static status_t process_payloads(message_t *message, check_t *check) { if (check->connect_id.ptr) { - DBG1(DBG_IKE, "connectivity check contains multiple ME_CONNECTID notifies"); + DBG1(DBG_IKE, "connectivity check contains multiple " + "ME_CONNECTID notifies"); break; } check->connect_id = chunk_clone(notify->get_notification_data(notify)); @@ -783,7 +808,8 @@ static status_t process_payloads(message_t *message, check_t *check) { if (check->auth.ptr) { - DBG1(DBG_IKE, "connectivity check contains multiple ME_CONNECTAUTH notifies"); + DBG1(DBG_IKE, "connectivity check contains multiple " + "ME_CONNECTAUTH notifies"); break; } check->auth = chunk_clone(notify->get_notification_data(notify)); @@ -795,38 +821,40 @@ static status_t process_payloads(message_t *message, check_t *check) } } enumerator->destroy(enumerator); - + if (!check->connect_id.ptr || !check->endpoint || !check->auth.ptr) { - DBG1(DBG_IKE, "at least one payload was missing from the connectivity check"); + DBG1(DBG_IKE, "at least one required payload was missing from the " + "connectivity check"); return FAILED; } - + return SUCCESS; } /** * Builds the signature for a connectivity check */ -static chunk_t build_signature(private_connect_manager_t *this, +static chunk_t build_signature(private_connect_manager_t *this, check_list_t *checklist, check_t *check, bool outbound) { u_int32_t mid; chunk_t mid_chunk, key_chunk, sig_chunk; chunk_t sig_hash; - + mid = htonl(check->mid); mid_chunk = chunk_from_thing(mid); - + key_chunk = (checklist->is_initiator && outbound) || (!checklist->is_initiator && !outbound) ? checklist->initiator.key : checklist->responder.key; - + /* signature = SHA1( MID | ME_CONNECTID | ME_ENDPOINT | ME_CONNECTKEY ) */ - sig_chunk = chunk_cat("cccc", mid_chunk, check->connect_id, check->endpoint_raw, key_chunk); + sig_chunk = chunk_cat("cccc", mid_chunk, check->connect_id, + check->endpoint_raw, key_chunk); this->hasher->allocate_hash(this->hasher, sig_chunk, &sig_hash); DBG3(DBG_IKE, "sig_chunk %#B", &sig_chunk); DBG3(DBG_IKE, "sig_hash %#B", &sig_hash); - + chunk_free(&sig_chunk); return sig_hash; } @@ -837,7 +865,7 @@ static void finish_checks(private_connect_manager_t *this, check_list_t *checkli /** * After one of the initiator's pairs has succeeded we finish the checks without - * waiting for all the timeouts + * waiting for all the timeouts */ static job_requeue_t initiator_finish(callback_data_t *data) { @@ -848,23 +876,24 @@ static job_requeue_t initiator_finish(callback_data_t *data) check_list_t *checklist; if (get_checklist_by_id(this, data->connect_id, &checklist) != SUCCESS) { - DBG1(DBG_IKE, "checklist with id '%#B' not found, can't finish connectivity checks", - &data->connect_id); + DBG1(DBG_IKE, "checklist with id '%#B' not found, can't finish " + "connectivity checks", &data->connect_id); this->mutex->unlock(this->mutex); return JOB_REQUEUE_NONE; } - + finish_checks(this, checklist); - + this->mutex->unlock(this->mutex); - + return JOB_REQUEUE_NONE; } /** * Updates the state of the whole checklist */ -static void update_checklist_state(private_connect_manager_t *this, check_list_t *checklist) +static void update_checklist_state(private_connect_manager_t *this, + check_list_t *checklist) { iterator_t *iterator; endpoint_pair_t *current; @@ -891,21 +920,22 @@ static void update_checklist_state(private_connect_manager_t *this, check_list_t } } iterator->destroy(iterator); - + if (checklist->is_initiator && succeeded && !checklist->is_finishing) { /* instead of waiting until all checks have finished (i.e. all * retransmissions have failed) the initiator finishes the checks * right after the first check has succeeded. to allow a probably * better pair to succeed, we still wait a certain time */ - DBG2(DBG_IKE, "fast finishing checks for checklist '%#B'", &checklist->connect_id); - + DBG2(DBG_IKE, "fast finishing checks for checklist '%#B'", + &checklist->connect_id); + callback_data_t *data = callback_data_create(this, checklist->connect_id); job_t *job = (job_t*)callback_job_create((callback_job_cb_t)initiator_finish, data, (callback_job_cleanup_t)callback_data_destroy, NULL); charon->scheduler->schedule_job_ms(charon->scheduler, job, ME_WAIT_TO_FINISH); checklist->is_finishing = TRUE; } - + if (in_progress) { checklist->state = CHECK_IN_PROGRESS; @@ -926,48 +956,48 @@ static void update_checklist_state(private_connect_manager_t *this, check_list_t static job_requeue_t retransmit(callback_data_t *data) { private_connect_manager_t *this = data->connect_manager; - + this->mutex->lock(this->mutex); check_list_t *checklist; if (get_checklist_by_id(this, data->connect_id, &checklist) != SUCCESS) { - DBG1(DBG_IKE, "checklist with id '%#B' not found, can't retransmit connectivity check", - &data->connect_id); + DBG1(DBG_IKE, "checklist with id '%#B' not found, can't retransmit " + "connectivity check", &data->connect_id); this->mutex->unlock(this->mutex); return JOB_REQUEUE_NONE; } - + endpoint_pair_t *pair; if (get_pair_by_id(checklist, data->mid, &pair) != SUCCESS) { - DBG1(DBG_IKE, "pair with id '%d' not found, can't retransmit connectivity check", - data->mid); + DBG1(DBG_IKE, "pair with id '%d' not found, can't retransmit " + "connectivity check", data->mid); goto retransmit_end; } - + if (pair->state != CHECK_IN_PROGRESS) { - DBG2(DBG_IKE, "pair with id '%d' is in wrong state [%d], don't retransmit the connectivity check", - data->mid, pair->state); + DBG2(DBG_IKE, "pair with id '%d' is in wrong state [%d], don't " + "retransmit the connectivity check", data->mid, pair->state); goto retransmit_end; } - + if (++pair->retransmitted > ME_MAX_RETRANS) { DBG2(DBG_IKE, "pair with id '%d' failed after %d retransmissions", - data->mid, ME_MAX_RETRANS); + data->mid, ME_MAX_RETRANS); pair->state = CHECK_FAILED; goto retransmit_end; } - + charon->sender->send(charon->sender, pair->packet->clone(pair->packet)); - + queue_retransmission(this, checklist, pair); retransmit_end: update_checklist_state(this, checklist); - + switch(checklist->state) { case CHECK_SUCCEEDED: @@ -977,9 +1007,9 @@ retransmit_end: default: break; } - + this->mutex->unlock(this->mutex); - + /* we reschedule it manually */ return JOB_REQUEUE_NONE; } @@ -991,15 +1021,16 @@ static void queue_retransmission(private_connect_manager_t *this, check_list_t * { callback_data_t *data = retransmit_data_create(this, checklist->connect_id, pair->id); job_t *job = (job_t*)callback_job_create((callback_job_cb_t)retransmit, data, (callback_job_cleanup_t)callback_data_destroy, NULL); - + u_int32_t retransmission = pair->retransmitted + 1; u_int32_t rto = ME_INTERVAL; if (retransmission > ME_BOOST) { rto = (u_int32_t)(ME_INTERVAL * pow(ME_RETRANS_BASE, retransmission - ME_BOOST)); } - DBG2(DBG_IKE, "scheduling retransmission %d of pair '%d' in %dms", retransmission, pair->id, rto); - + DBG2(DBG_IKE, "scheduling retransmission %d of pair '%d' in %dms", + retransmission, pair->id, rto); + charon->scheduler->schedule_job_ms(charon->scheduler, (job_t*)job, rto); } @@ -1015,28 +1046,28 @@ static void send_check(private_connect_manager_t *this, check_list_t *checklist, message->set_request(message, request); message->set_destination(message, check->dst->clone(check->dst)); message->set_source(message, check->src->clone(check->src)); - + ike_sa_id_t *ike_sa_id = ike_sa_id_create(0, 0, request); message->set_ike_sa_id(message, ike_sa_id); ike_sa_id->destroy(ike_sa_id); message->add_notify(message, FALSE, ME_CONNECTID, check->connect_id); DBG2(DBG_IKE, "send ME_CONNECTID %#B", &check->connect_id); - + notify_payload_t *endpoint = check->endpoint->build_notify(check->endpoint); check->endpoint_raw = chunk_clone(endpoint->get_notification_data(endpoint)); message->add_payload(message, (payload_t*)endpoint); DBG2(DBG_IKE, "send ME_ENDPOINT notify"); - + check->auth = build_signature(this, checklist, check, TRUE); message->add_notify(message, FALSE, ME_CONNECTAUTH, check->auth); DBG2(DBG_IKE, "send ME_CONNECTAUTH %#B", &check->auth); - + packet_t *packet; if (message->generate(message, NULL, NULL, &packet) == SUCCESS) { charon->sender->send(charon->sender, packet->clone(packet)); - + if (request) { DESTROY_IF(pair->packet); @@ -1055,18 +1086,18 @@ static void send_check(private_connect_manager_t *this, check_list_t *checklist, /** * Queues a triggered check */ -static void queue_triggered_check(private_connect_manager_t *this, +static void queue_triggered_check(private_connect_manager_t *this, check_list_t *checklist, endpoint_pair_t *pair) { DBG2(DBG_IKE, "queueing triggered check for pair '%d'", pair->id); - pair->state = CHECK_WAITING; - checklist->triggered->insert_last(checklist->triggered, pair); - - if (!checklist->sender) - { - /* if the sender is not running we restart it */ - schedule_checks(this, checklist, ME_INTERVAL); - } + pair->state = CHECK_WAITING; + checklist->triggered->insert_last(checklist->triggered, pair); + + if (!checklist->sender) + { + /* if the sender is not running we restart it */ + schedule_checks(this, checklist, ME_INTERVAL); + } } /** @@ -1077,26 +1108,27 @@ static job_requeue_t sender(callback_data_t *data) private_connect_manager_t *this = data->connect_manager; this->mutex->lock(this->mutex); - + check_list_t *checklist; if (get_checklist_by_id(this, data->connect_id, &checklist) != SUCCESS) { - DBG1(DBG_IKE, "checklist with id '%#B' not found, can't send connectivity check", - &data->connect_id); + DBG1(DBG_IKE, "checklist with id '%#B' not found, can't send " + "connectivity check", &data->connect_id); this->mutex->unlock(this->mutex); return JOB_REQUEUE_NONE; } - + /* reset the sender */ checklist->sender = NULL; - + endpoint_pair_t *pair; if (get_triggered_pair(checklist, &pair) != SUCCESS) { DBG1(DBG_IKE, "no triggered check queued, sending an ordinary check"); - + if (checklist->pairs->find_first(checklist->pairs, - (linked_list_match_t)match_waiting_pair, (void**)&pair) != SUCCESS) + (linked_list_match_t)match_waiting_pair, + (void**)&pair) != SUCCESS) { this->mutex->unlock(this->mutex); DBG1(DBG_IKE, "no pairs in waiting state, aborting"); @@ -1113,19 +1145,20 @@ static job_requeue_t sender(callback_data_t *data) check->src = pair->local->clone(pair->local); check->dst = pair->remote->clone(pair->remote); check->connect_id = chunk_clone(checklist->connect_id); - check->endpoint = endpoint_notify_create(); - + check->endpoint = endpoint_notify_create_from_host(PEER_REFLEXIVE, NULL, + NULL); + pair->state = CHECK_IN_PROGRESS; - + send_check(this, checklist, check, pair, TRUE); - + check_destroy(check); - + /* schedule this job again */ schedule_checks(this, checklist, ME_INTERVAL); - + this->mutex->unlock(this->mutex); - + /* we reschedule it manually */ return JOB_REQUEUE_NONE; } @@ -1147,7 +1180,7 @@ static job_requeue_t initiate_mediated(initiate_data_t *data) { check_list_t *checklist = data->checklist; initiated_t *initiated = data->initiated; - + endpoint_pair_t *pair; if (get_best_valid_pair(checklist, &pair) == SUCCESS) { @@ -1169,7 +1202,7 @@ static job_requeue_t initiate_mediated(initiate_data_t *data) { /* this should (can?) not happen */ } - + return JOB_REQUEUE_NONE; } @@ -1186,7 +1219,7 @@ static void finish_checks(private_connect_manager_t *this, check_list_t *checkli { remove_checklist(this, checklist); remove_initiated(this, initiated); - + initiate_data_t *data = initiate_data_create(checklist, initiated); job_t *job = (job_t*)callback_job_create((callback_job_cb_t)initiate_mediated, data, (callback_job_cleanup_t)initiate_data_destroy, NULL); charon->processor->queue_job(charon->processor, job); @@ -1194,8 +1227,8 @@ static void finish_checks(private_connect_manager_t *this, check_list_t *checkli } else { - DBG1(DBG_IKE, "there is no mediated connection waiting between '%Y' " - "and '%Y'", checklist->initiator.id, checklist->responder.id); + DBG1(DBG_IKE, "there is no mediated connection waiting between '%Y'" + " and '%Y'", checklist->initiator.id, checklist->responder.id); } } } @@ -1210,28 +1243,30 @@ static void process_response(private_connect_manager_t *this, check_t *check, if (get_pair_by_id(checklist, check->mid, &pair) == SUCCESS) { if (pair->local->equals(pair->local, check->dst) && - pair->remote->equals(pair->remote, check->src)) + pair->remote->equals(pair->remote, check->src)) { - DBG1(DBG_IKE, "endpoint pair '%d' is valid: '%#H' - '%#H'", pair->id, - pair->local, pair->remote); + DBG1(DBG_IKE, "endpoint pair '%d' is valid: '%#H' - '%#H'", + pair->id, pair->local, pair->remote); pair->state = CHECK_SUCCEEDED; } - + linked_list_t *local_endpoints = checklist->is_initiator ? checklist->initiator.endpoints : checklist->responder.endpoints; - + endpoint_notify_t *local_endpoint; if (endpoints_contain(local_endpoints, - check->endpoint->get_host(check->endpoint), &local_endpoint) != SUCCESS) + check->endpoint->get_host(check->endpoint), + &local_endpoint) != SUCCESS) { local_endpoint = endpoint_notify_create_from_host(PEER_REFLEXIVE, check->endpoint->get_host(check->endpoint), pair->local); - local_endpoint->set_priority(local_endpoint, check->endpoint->get_priority(check->endpoint)); + local_endpoint->set_priority(local_endpoint, + check->endpoint->get_priority(check->endpoint)); local_endpoints->insert_last(local_endpoints, local_endpoint); } - + update_checklist_state(this, checklist); - + switch(checklist->state) { case CHECK_SUCCEEDED: @@ -1249,31 +1284,35 @@ static void process_response(private_connect_manager_t *this, check_t *check, } static void process_request(private_connect_manager_t *this, check_t *check, - check_list_t *checklist) + check_list_t *checklist) { linked_list_t *remote_endpoints = checklist->is_initiator ? checklist->responder.endpoints : checklist->initiator.endpoints; - + endpoint_notify_t *peer_reflexive, *remote_endpoint; - peer_reflexive = endpoint_notify_create_from_host(PEER_REFLEXIVE, check->src, NULL); - peer_reflexive->set_priority(peer_reflexive, check->endpoint->get_priority(check->endpoint)); - + peer_reflexive = endpoint_notify_create_from_host(PEER_REFLEXIVE, + check->src, NULL); + peer_reflexive->set_priority(peer_reflexive, + check->endpoint->get_priority(check->endpoint)); + if (endpoints_contain(remote_endpoints, check->src, &remote_endpoint) != SUCCESS) { remote_endpoint = peer_reflexive->clone(peer_reflexive); remote_endpoints->insert_last(remote_endpoints, remote_endpoint); } - + endpoint_pair_t *pair; - if (get_pair_by_hosts(checklist->pairs, check->dst, check->src, &pair) == SUCCESS) + if (get_pair_by_hosts(checklist->pairs, check->dst, check->src, + &pair) == SUCCESS) { switch(pair->state) { case CHECK_IN_PROGRESS: /* prevent retransmissions */ pair->retransmitted = ME_MAX_RETRANS; - /* FIXME: we should wait to the next rto to send the triggered check - * fall-through */ + /* FIXME: we should wait to the next rto to send the triggered + * check */ + /* fall-through */ case CHECK_WAITING: case CHECK_FAILED: queue_triggered_check(this, checklist, pair); @@ -1286,31 +1325,30 @@ static void process_request(private_connect_manager_t *this, check_t *check, else { endpoint_notify_t *local_endpoint = endpoint_notify_create_from_host(HOST, check->dst, NULL); - + endpoint_notify_t *initiator = checklist->is_initiator ? local_endpoint : remote_endpoint; endpoint_notify_t *responder = checklist->is_initiator ? remote_endpoint : local_endpoint; - + pair = endpoint_pair_create(initiator, responder, checklist->is_initiator); pair->id = checklist->pairs->get_count(checklist->pairs) + 1; - + insert_pair_by_priority(checklist->pairs, pair); - + queue_triggered_check(this, checklist, pair); - + local_endpoint->destroy(local_endpoint); } - - + check_t *response = check_create(); - + response->mid = check->mid; response->src = check->dst->clone(check->dst); response->dst = check->src->clone(check->src); response->connect_id = chunk_clone(check->connect_id); response->endpoint = peer_reflexive; - + send_check(this, checklist, response, pair, FALSE); - + check_destroy(response); } @@ -1327,35 +1365,35 @@ static void process_check(private_connect_manager_t *this, message_t *message) message->get_message_id(message)); return; } - + check_t *check = check_create(); check->mid = message->get_message_id(message); check->src = message->get_source(message); check->src = check->src->clone(check->src); check->dst = message->get_destination(message); check->dst = check->dst->clone(check->dst); - + if (process_payloads(message, check) != SUCCESS) { DBG1(DBG_IKE, "invalid connectivity check %s received", - message->get_request(message) ? "request" : "response"); + message->get_request(message) ? "request" : "response"); check_destroy(check); return; } - + this->mutex->lock(this->mutex); - + check_list_t *checklist; if (get_checklist_by_id(this, check->connect_id, &checklist) != SUCCESS) { DBG1(DBG_IKE, "checklist with id '%#B' not found", - &check->connect_id); + &check->connect_id); check_destroy(check); this->mutex->unlock(this->mutex); return; } - - chunk_t sig = build_signature(this, checklist, check, FALSE); + + chunk_t sig = build_signature(this, checklist, check, FALSE); if (!chunk_equals(sig, check->auth)) { DBG1(DBG_IKE, "connectivity check verification failed"); @@ -1365,7 +1403,7 @@ static void process_check(private_connect_manager_t *this, message_t *message) return; } chunk_free(&sig); - + if (message->get_request(message)) { process_request(this, check, checklist); @@ -1374,9 +1412,9 @@ static void process_check(private_connect_manager_t *this, message_t *message) { process_response(this, check, checklist); } - + this->mutex->unlock(this->mutex); - + check_destroy(check); } @@ -1394,16 +1432,19 @@ static bool check_and_register(private_connect_manager_t *this, if (get_initiated_by_ids(this, id, peer_id, &initiated) != SUCCESS) { - DBG2(DBG_IKE, "registered waiting mediated connection with '%Y'", peer_id); + DBG2(DBG_IKE, "registered waiting mediated connection with '%Y'", + peer_id); initiated = initiated_create(id, peer_id); this->initiated->insert_last(this->initiated, initiated); already_there = FALSE; } - - if (initiated->mediated->find_first(initiated->mediated, - (linked_list_match_t)mediated_sa->equals, NULL, mediated_sa) != SUCCESS) + + if (initiated->mediated->find_first(initiated->mediated, + (linked_list_match_t)mediated_sa->equals, + NULL, mediated_sa) != SUCCESS) { - initiated->mediated->insert_last(initiated->mediated, mediated_sa->clone(mediated_sa)); + initiated->mediated->insert_last(initiated->mediated, + mediated_sa->clone(mediated_sa)); } this->mutex->unlock(this->mutex); @@ -1414,8 +1455,9 @@ static bool check_and_register(private_connect_manager_t *this, /** * Implementation of connect_manager_t.check_and_initiate. */ -static void check_and_initiate(private_connect_manager_t *this, ike_sa_id_t *mediation_sa, - identification_t *id, identification_t *peer_id) +static void check_and_initiate(private_connect_manager_t *this, + ike_sa_id_t *mediation_sa, identification_t *id, + identification_t *peer_id) { initiated_t *initiated; @@ -1427,12 +1469,14 @@ static void check_and_initiate(private_connect_manager_t *this, ike_sa_id_t *med this->mutex->unlock(this->mutex); return; } - + ike_sa_id_t *waiting_sa; - iterator_t *iterator = initiated->mediated->create_iterator(initiated->mediated, TRUE); + iterator_t *iterator = initiated->mediated->create_iterator( + initiated->mediated, TRUE); while (iterator->iterate(iterator, (void**)&waiting_sa)) { - job_t *job = (job_t*)reinitiate_mediation_job_create(mediation_sa, waiting_sa); + job_t *job = (job_t*)reinitiate_mediation_job_create(mediation_sa, + waiting_sa); charon->processor->queue_job(charon->processor, job); } iterator->destroy(iterator); @@ -1444,26 +1488,29 @@ static void check_and_initiate(private_connect_manager_t *this, ike_sa_id_t *med * Implementation of connect_manager_t.set_initiator_data. */ static status_t set_initiator_data(private_connect_manager_t *this, - identification_t *initiator, identification_t *responder, - chunk_t connect_id, chunk_t key, linked_list_t *endpoints, bool is_initiator) + identification_t *initiator, + identification_t *responder, + chunk_t connect_id, chunk_t key, + linked_list_t *endpoints, bool is_initiator) { check_list_t *checklist; - - this->mutex->lock(this->mutex); - + + this->mutex->lock(this->mutex); + if (get_checklist_by_id(this, connect_id, NULL) == SUCCESS) { DBG1(DBG_IKE, "checklist with id '%#B' already exists, aborting", - &connect_id); + &connect_id); this->mutex->unlock(this->mutex); return FAILED; } - - checklist = check_list_create(initiator, responder, connect_id, key, endpoints, is_initiator); + + checklist = check_list_create(initiator, responder, connect_id, key, + endpoints, is_initiator); this->checklists->insert_last(this->checklists, checklist); - + this->mutex->unlock(this->mutex); - + return SUCCESS; } @@ -1471,31 +1518,33 @@ static status_t set_initiator_data(private_connect_manager_t *this, * Implementation of connect_manager_t.set_responder_data. */ static status_t set_responder_data(private_connect_manager_t *this, - chunk_t connect_id, chunk_t key, linked_list_t *endpoints) + chunk_t connect_id, chunk_t key, + linked_list_t *endpoints) { check_list_t *checklist; this->mutex->lock(this->mutex); - + if (get_checklist_by_id(this, connect_id, &checklist) != SUCCESS) { DBG1(DBG_IKE, "checklist with id '%#B' not found", - &connect_id); + &connect_id); this->mutex->unlock(this->mutex); return NOT_FOUND; } - + checklist->responder.key = chunk_clone(key); - checklist->responder.endpoints = endpoints->clone_offset(endpoints, offsetof(endpoint_notify_t, clone)); + checklist->responder.endpoints = endpoints->clone_offset(endpoints, + offsetof(endpoint_notify_t, clone)); checklist->state = CHECK_WAITING; - + build_pairs(checklist); - + /* send the first check immediately */ schedule_checks(this, checklist, 0); - + this->mutex->unlock(this->mutex); - + return SUCCESS; } @@ -1507,22 +1556,22 @@ static status_t stop_checks(private_connect_manager_t *this, chunk_t connect_id) check_list_t *checklist; this->mutex->lock(this->mutex); - + if (get_checklist_by_id(this, connect_id, &checklist) != SUCCESS) { DBG1(DBG_IKE, "checklist with id '%#B' not found", - &connect_id); + &connect_id); this->mutex->unlock(this->mutex); return NOT_FOUND; } - + DBG1(DBG_IKE, "removing checklist with id '%#B'", &connect_id); - + remove_checklist(this, checklist); check_list_destroy(checklist); - + this->mutex->unlock(this->mutex); - + return SUCCESS; } @@ -1532,12 +1581,12 @@ static status_t stop_checks(private_connect_manager_t *this, chunk_t connect_id) static void destroy(private_connect_manager_t *this) { this->mutex->lock(this->mutex); - + this->hasher->destroy(this->hasher); this->checklists->destroy_function(this->checklists, (void*)check_list_destroy); this->initiated->destroy_function(this->initiated, (void*)initiated_destroy); - - this->mutex->unlock(this->mutex); + + this->mutex->unlock(this->mutex); this->mutex->destroy(this->mutex); free(this); } @@ -1556,7 +1605,7 @@ connect_manager_t *connect_manager_create() this->public.set_responder_data = (status_t(*)(connect_manager_t*,chunk_t,chunk_t,linked_list_t*))set_responder_data; this->public.process_check = (void(*)(connect_manager_t*,message_t*))process_check; this->public.stop_checks = (status_t(*)(connect_manager_t*,chunk_t))stop_checks; - + this->hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1); if (this->hasher == NULL) { @@ -1564,11 +1613,11 @@ connect_manager_t *connect_manager_create() free(this); return NULL; } - + this->checklists = linked_list_create(); this->initiated = linked_list_create(); - + this->mutex = mutex_create(MUTEX_TYPE_DEFAULT); - + return (connect_manager_t*)this; } |