diff options
-rw-r--r-- | src/charon/config/policies/policy.h | 2 | ||||
-rw-r--r-- | src/charon/config/traffic_selector.c | 1 | ||||
-rw-r--r-- | src/charon/queues/jobs/incoming_packet_job.c | 4 | ||||
-rw-r--r-- | src/charon/sa/child_sa.c | 26 | ||||
-rw-r--r-- | src/charon/sa/ike_sa.c | 39 | ||||
-rw-r--r-- | src/charon/sa/ike_sa_manager.c | 273 | ||||
-rw-r--r-- | src/charon/sa/ike_sa_manager.h | 32 | ||||
-rw-r--r-- | src/charon/sa/transactions/ike_sa_init.c | 24 | ||||
-rw-r--r-- | src/charon/sa/transactions/rekey_ike_sa.c | 2 | ||||
-rw-r--r-- | src/charon/threads/kernel_interface.c | 21 | ||||
-rw-r--r-- | src/charon/threads/kernel_interface.h | 3 | ||||
-rwxr-xr-x | src/charon/threads/stroke_interface.c | 50 |
12 files changed, 256 insertions, 221 deletions
diff --git a/src/charon/config/policies/policy.h b/src/charon/config/policies/policy.h index 18e6ad0fc..48d9f70e7 100644 --- a/src/charon/config/policies/policy.h +++ b/src/charon/config/policies/policy.h @@ -52,7 +52,7 @@ enum dpd_action_t { /** * String mappings for dpd_action_t */ -mapping_t dpd_action_m[]; +extern mapping_t dpd_action_m[]; typedef struct policy_t policy_t; diff --git a/src/charon/config/traffic_selector.c b/src/charon/config/traffic_selector.c index d8293b808..e567c6eca 100644 --- a/src/charon/config/traffic_selector.c +++ b/src/charon/config/traffic_selector.c @@ -24,6 +24,7 @@ #include <arpa/inet.h> #include <string.h> #include <netdb.h> +#include <stdio.h> #include "traffic_selector.h" diff --git a/src/charon/queues/jobs/incoming_packet_job.c b/src/charon/queues/jobs/incoming_packet_job.c index f773a57f4..ec8163da8 100644 --- a/src/charon/queues/jobs/incoming_packet_job.c +++ b/src/charon/queues/jobs/incoming_packet_job.c @@ -152,7 +152,9 @@ static status_t execute(private_incoming_packet_job_t *this) ike_sa_id->get_responder_spi(ike_sa_id)); if (message->get_request(message)) { - send_notify_response(this, message, INVALID_IKE_SPI); + /* TODO: send notify if we have NULL crypters, + * see todo in send_notify_response + send_notify_response(this, message, INVALID_IKE_SPI); */ } ike_sa_id->destroy(ike_sa_id); message->destroy(message); diff --git a/src/charon/sa/child_sa.c b/src/charon/sa/child_sa.c index 8a7e64ac4..79cff7ae1 100644 --- a/src/charon/sa/child_sa.c +++ b/src/charon/sa/child_sa.c @@ -24,6 +24,7 @@ #include "child_sa.h" +#include <stdio.h> #include <string.h> #include <daemon.h> @@ -182,8 +183,14 @@ static char *get_name(private_child_sa_t *this) */ static void set_name(private_child_sa_t *this, char* name) { - free(this->name); - this->name = strdup(name); + char buffer[64]; + + if (snprintf(buffer, sizeof(buffer), "%s[%d]", + name, this->reqid - REQID_START) > 0) + { + free(this->name); + this->name = strdup(buffer); + } } /** @@ -468,6 +475,8 @@ static status_t add_policies(private_child_sa_t *this, linked_list_t *my_ts_list { iterator_t *my_iter, *other_iter; traffic_selector_t *my_ts, *other_ts; + /* use low prio for ROUTED policies */ + bool high_prio = (this->state != CHILD_CREATED); /* iterate over both lists */ my_iter = my_ts_list->create_iterator(my_ts_list, TRUE); @@ -503,15 +512,15 @@ static status_t add_policies(private_child_sa_t *this, linked_list_t *my_ts_list /* install 3 policies: out, in and forward */ status = charon->kernel_interface->add_policy(charon->kernel_interface, this->me.addr, this->other.addr, my_ts, other_ts, - POLICY_OUT, this->protocol, this->reqid, FALSE); + POLICY_OUT, this->protocol, this->reqid, high_prio, FALSE); status |= charon->kernel_interface->add_policy(charon->kernel_interface, this->other.addr, this->me.addr, other_ts, my_ts, - POLICY_IN, this->protocol, this->reqid, FALSE); + POLICY_IN, this->protocol, this->reqid, high_prio, FALSE); status |= charon->kernel_interface->add_policy(charon->kernel_interface, this->other.addr, this->me.addr, other_ts, my_ts, - POLICY_FWD, this->protocol, this->reqid, FALSE); + POLICY_FWD, this->protocol, this->reqid, high_prio, FALSE); if (status != SUCCESS) { @@ -805,6 +814,7 @@ static status_t update_policy_hosts(private_child_sa_t *this, host_t *new_me, ho iterator_t *iterator; sa_policy_t *policy; status_t status; + /* we always use high priorities, as hosts getting updated are INSTALLED */ iterator = this->policies->create_iterator(this->policies, TRUE); while (iterator->iterate(iterator, (void**)&policy)) @@ -813,19 +823,19 @@ static status_t update_policy_hosts(private_child_sa_t *this, host_t *new_me, ho charon->kernel_interface, new_me, new_other, policy->my_ts, policy->other_ts, - POLICY_OUT, this->protocol, this->reqid, TRUE); + POLICY_OUT, this->protocol, this->reqid, TRUE, TRUE); status |= charon->kernel_interface->add_policy( charon->kernel_interface, new_other, new_me, policy->other_ts, policy->my_ts, - POLICY_IN, this->protocol, this->reqid, TRUE); + POLICY_IN, this->protocol, this->reqid, TRUE, TRUE); status |= charon->kernel_interface->add_policy( charon->kernel_interface, new_other, new_me, policy->other_ts, policy->my_ts, - POLICY_FWD, this->protocol, this->reqid, TRUE); + POLICY_FWD, this->protocol, this->reqid, TRUE, TRUE); if (status != SUCCESS) { diff --git a/src/charon/sa/ike_sa.c b/src/charon/sa/ike_sa.c index c5d3a63cd..55c3302ca 100644 --- a/src/charon/sa/ike_sa.c +++ b/src/charon/sa/ike_sa.c @@ -920,8 +920,6 @@ static status_t initiate(private_ike_sa_t *this, this->logger->log(this->logger, CONTROL, "initiating IKE_SA"); - - set_name(this, connection->get_name(connection)); DESTROY_IF(this->my_host); this->my_host = connection->get_my_host(connection); this->my_host = this->my_host->clone(this->my_host); @@ -1130,27 +1128,30 @@ static status_t route(private_ike_sa_t *this, connection_t *connection, policy_t iterator = this->child_sas->create_iterator(this->child_sas, TRUE); while (iterator->iterate(iterator, (void**)&child_sa)) { - linked_list_t *my_ts_conf, *other_ts_conf; - - my_ts = child_sa->get_my_traffic_selectors(child_sa); - other_ts = child_sa->get_other_traffic_selectors(child_sa); - - my_ts_conf = policy->get_my_traffic_selectors(policy, this->my_host); - other_ts_conf = policy->get_other_traffic_selectors(policy, this->other_host); - - if (ts_list_equals(my_ts, my_ts_conf) && - ts_list_equals(other_ts, other_ts_conf)) + if (child_sa->get_state(child_sa) == CHILD_ROUTED) { + linked_list_t *my_ts_conf, *other_ts_conf; + + my_ts = child_sa->get_my_traffic_selectors(child_sa); + other_ts = child_sa->get_other_traffic_selectors(child_sa); + + my_ts_conf = policy->get_my_traffic_selectors(policy, this->my_host); + other_ts_conf = policy->get_other_traffic_selectors(policy, this->other_host); + + if (ts_list_equals(my_ts, my_ts_conf) && + ts_list_equals(other_ts, other_ts_conf)) + { + ts_list_destroy(my_ts_conf); + ts_list_destroy(other_ts_conf); + iterator->destroy(iterator); + this->logger->log(this->logger, CONTROL, + "a CHILD_SA with such a policy already routed"); + + return FAILED; + } ts_list_destroy(my_ts_conf); ts_list_destroy(other_ts_conf); - iterator->destroy(iterator); - this->logger->log(this->logger, CONTROL, - "a CHILD_SA with such a policy already routed"); - - return FAILED; } - ts_list_destroy(my_ts_conf); - ts_list_destroy(other_ts_conf); } iterator->destroy(iterator); diff --git a/src/charon/sa/ike_sa_manager.c b/src/charon/sa/ike_sa_manager.c index 46bf3a1bb..7984aa9af 100644 --- a/src/charon/sa/ike_sa_manager.c +++ b/src/charon/sa/ike_sa_manager.c @@ -134,58 +134,7 @@ struct private_ike_sa_manager_t { * Public interface of ike_sa_manager_t. */ ike_sa_manager_t public; - - /** - * @brief Get next spi. - * - * We give out SPIs from a pseudo random source - * - * @param this the ike_sa_manager - * @return the next spi - */ - u_int64_t (*get_next_spi) (private_ike_sa_manager_t *this); - - /** - * @brief Find the ike_sa_entry_t object in the list by SPIs. - * - * This function simply iterates over the linked list. A hash-table - * would be more efficient when storing a lot of IKE_SAs... - * - * @param this calling object - * @param ike_sa_id id of the ike_sa, containing SPIs - * @param[out] entry pointer to set to the found entry - * @return - * - SUCCESS when found, - * - NOT_FOUND when no such ike_sa_id in list - */ - status_t (*get_entry_by_id) (private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id, ike_sa_entry_t **entry); - - /** - * @brief Find the ike_sa_entry_t in the list by pointer to SA. - * - * This function simply iterates over the linked list. A hash-table - * would be more efficient when storing a lot of IKE_SAs... - * - * @param this calling object - * @param ike_sa pointer to the ike_sa - * @param[out] entry pointer to set to the found entry - * @return - * - SUCCESS when found, - * - NOT_FOUND when no such ike_sa_id in list - */ - status_t (*get_entry_by_sa) (private_ike_sa_manager_t *this, ike_sa_t *ike_sa, ike_sa_entry_t **entry); - - /** - * @brief Delete an entry from the linked list. - * - * @param this calling object - * @param entry entry to delete - * @return - * - SUCCESS when found, - * - NOT_FOUND when no such ike_sa_id in list - */ - status_t (*delete_entry) (private_ike_sa_manager_t *this, ike_sa_entry_t *entry); - + /** * Lock for exclusivly accessing the manager. */ @@ -321,6 +270,17 @@ static status_t delete_entry(private_ike_sa_manager_t *this, ike_sa_entry_t *ent iterator->current(iterator, (void**)¤t); if (current == entry) { + /* mark it, so now new threads can get this entry */ + entry->driveout_new_threads = TRUE; + /* wait until all workers have done their work */ + while (entry->waiting_threads) + { + /* wake up all */ + pthread_cond_broadcast(&(entry->condvar)); + /* they will wake us again when their work is done */ + pthread_cond_wait(&(entry->condvar), &(this->mutex)); + } + this->logger->log(this->logger, CONTROL|LEVEL2, "found entry by pointer. Going to delete it"); iterator->remove(iterator); @@ -440,7 +400,7 @@ static ike_sa_t* checkout_by_id(private_ike_sa_manager_t *this, ike_sa_entry_t *new_ike_sa_entry; ike_sa_id_t *new_ike_sa_id; - initiator_spi = this->get_next_spi(this); + initiator_spi = get_next_spi(this); new_ike_sa_id = ike_sa_id_create(0, 0, TRUE); new_ike_sa_id->set_initiator_spi(new_ike_sa_id, initiator_spi); @@ -501,7 +461,7 @@ static ike_sa_t* checkout(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id */ ike_sa_entry_t *entry; /* look for the entry */ - if (this->get_entry_by_id(this, ike_sa_id, &entry) == SUCCESS) + if (get_entry_by_id(this, ike_sa_id, &entry) == SUCCESS) { if (wait_for_entry(this, entry)) { @@ -537,7 +497,7 @@ static ike_sa_t* checkout(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id ike_sa_entry_t *new_ike_sa_entry; /* set SPIs, we are the responder */ - responder_spi = this->get_next_spi(this); + responder_spi = get_next_spi(this); /* we also set arguments spi, so its still valid */ ike_sa_id->set_responder_spi(ike_sa_id, responder_spi); @@ -558,7 +518,7 @@ static ike_sa_t* checkout(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id /* checkout of a new and unused IKE_SA, used for rekeying */ ike_sa_entry_t *new_ike_sa_entry; - ike_sa_id->set_initiator_spi(ike_sa_id, this->get_next_spi(this)); + ike_sa_id->set_initiator_spi(ike_sa_id, get_next_spi(this)); /* create entry */ new_ike_sa_entry = ike_sa_entry_create(ike_sa_id); this->logger->log(this->logger, CONTROL|LEVEL2, @@ -621,7 +581,7 @@ static ike_sa_t* checkout_by_child(private_ike_sa_manager_t *this, /** * Implementation of ike_sa_manager_t.get_ike_sa_list. */ -linked_list_t *get_ike_sa_list(private_ike_sa_manager_t* this) +static linked_list_t *get_ike_sa_list(private_ike_sa_manager_t* this) { linked_list_t *list; iterator_t *iterator; @@ -643,32 +603,6 @@ linked_list_t *get_ike_sa_list(private_ike_sa_manager_t* this) } /** - * Implementation of ike_sa_manager_t.get_ike_sa_list_by_name. - */ -linked_list_t *get_ike_sa_list_by_name(private_ike_sa_manager_t* this, const char *name) -{ - linked_list_t *list; - iterator_t *iterator; - ike_sa_entry_t *entry; - - pthread_mutex_lock(&(this->mutex)); - - list = linked_list_create(); - iterator = this->ike_sa_list->create_iterator(this->ike_sa_list, TRUE); - while (iterator->iterate(iterator, (void**)&entry)) - { - if (strcmp(name, entry->ike_sa->get_name(entry->ike_sa)) == 0) - { - list->insert_last(list, (void*)entry->ike_sa_id->clone(entry->ike_sa_id)); - } - } - iterator->destroy(iterator); - - pthread_mutex_unlock(&(this->mutex)); - return list; -} - -/** * Implementation of ike_sa_manager_t.log_status. */ static void log_status(private_ike_sa_manager_t* this, logger_t* logger, char* name) @@ -724,7 +658,7 @@ static status_t checkin(private_ike_sa_manager_t *this, ike_sa_t *ike_sa) pthread_mutex_lock(&(this->mutex)); /* look for the entry */ - if (this->get_entry_by_sa(this, ike_sa, &entry) == SUCCESS) + if (get_entry_by_sa(this, ike_sa, &entry) == SUCCESS) { /* ike_sa_id must be updated */ entry->ike_sa_id->replace_values(entry->ike_sa_id, ike_sa->get_id(ike_sa)); @@ -772,23 +706,13 @@ static status_t checkin_and_destroy(private_ike_sa_manager_t *this, ike_sa_t *ik pthread_mutex_lock(&(this->mutex)); - if (this->get_entry_by_sa(this, ike_sa, &entry) == SUCCESS) + if (get_entry_by_sa(this, ike_sa, &entry) == SUCCESS) { - /* mark it, so now new threads can acquire this SA */ - entry->driveout_new_threads = TRUE; - /* additionaly, drive out waiting threads */ + /* drive out waiting threads, as we are in hurry */ entry->driveout_waiting_threads = TRUE; - - /* wait until all workers have done their work */ - while (entry->waiting_threads) - { - /* let the other threads leave the manager */ - pthread_cond_broadcast(&(entry->condvar)); - /* and the nice thing, they will wake us again when their work is done */ - pthread_cond_wait(&(entry->condvar), &(this->mutex)); - } - /* ok, we are alone now, no threads waiting in the entry's condvar */ - this->delete_entry(this, entry); + + delete_entry(this, entry); + this->logger->log(this->logger, CONTROL|LEVEL1, "check-in and destroy of IKE_SA successful"); retval = SUCCESS; @@ -825,7 +749,7 @@ static status_t delete_(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id) pthread_mutex_lock(&(this->mutex)); - if (this->get_entry_by_id(this, ike_sa_id, &entry) == SUCCESS) + if (get_entry_by_id(this, ike_sa_id, &entry) == SUCCESS) { /* we try a delete. If it succeeds, our job is done here. The * other peer will reply, and the IKE SA gets the finally deleted... @@ -837,25 +761,10 @@ static status_t delete_(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id) } /* but if the IKE SA is not in a state where the deletion is * negotiated with the other peer, we can destroy the IKE SA on our own. - * For this, we must be sure that really NO other threads are - * waiting for this SA... */ else { - /* mark it, so now new threads can acquire this SA */ - entry->driveout_new_threads = TRUE; - /* wait until all workers have done their work */ - while (entry->waiting_threads) - { - /* wake up all */ - pthread_cond_broadcast(&(entry->condvar)); - /* and the nice thing, they will wake us again when their work - * is done */ - pthread_cond_wait(&(entry->condvar), &(this->mutex)); - } - /* ok, we are alone now, no threads waiting in the entry's condvar */ - this->delete_entry(this, entry); - this->logger->log(this->logger, CONTROL|LEVEL1, "destroyed IKE_SA"); + } retval = SUCCESS; } @@ -871,6 +780,125 @@ static status_t delete_(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id) } /** + * Implementation of ike_sa_manager_t.delete_by_name. + */ +static status_t delete_by_name(private_ike_sa_manager_t *this, char *name) +{ + iterator_t *iterator; + iterator_t *child_iter; + ike_sa_entry_t *entry; + size_t name_len = strlen(name); + + pthread_mutex_lock(&(this->mutex)); + + iterator = this->ike_sa_list->create_iterator(this->ike_sa_list, TRUE); + while (iterator->iterate(iterator, (void**)&entry)) + { + if (wait_for_entry(this, entry)) + { + /* delete ike_sa if: + * name{x} matches completely + * name{} matches by name + * name matches by name + */ + bool del = FALSE; + char *ike_name; + char *child_name; + child_sa_t *child_sa; + + ike_name = entry->ike_sa->get_name(entry->ike_sa); + /* check if "name{x}" matches completely */ + if (strcmp(name, ike_name) == 0) + { + del = TRUE; + } + /* check if name is in form of "name{}" and matches to ike_name */ + else if (name_len > 1 && + name[name_len - 2] == '{' && name[name_len - 1] == '}' && + strlen(ike_name) > name_len && + ike_name[name_len - 2] == '{' && + strncmp(name, ike_name, name_len - 2) == 0) + { + del = TRUE; + } + /* finally, check if name is "name" and matches ike_name */ + else if (name_len == strchr(ike_name, '{') - ike_name && + strncmp(name, ike_name, name_len) == 0) + { + del = TRUE; + } + + if (del) + { + if (entry->ike_sa->delete(entry->ike_sa) == DESTROY_ME) + { + delete_entry(this, entry); + iterator->reset(iterator); + } + /* no need to check children, as we delete all */ + continue; + } + + /* and now the same game for all children. delete child_sa if: + * name[x] matches completely + * name[] matches by name + * name matches by name + */ + child_iter = entry->ike_sa->create_child_sa_iterator(entry->ike_sa); + while (child_iter->iterate(child_iter, (void**)&child_sa)) + { + /* skip ROUTED children, they have their "unroute" command */ + if (child_sa->get_state(child_sa) == CHILD_ROUTED) + { + continue; + } + + child_name = child_sa->get_name(child_sa); + del = FALSE; + /* check if "name[x]" matches completely */ + if (strcmp(name, child_name) == 0) + { + del = TRUE; + } + /* check if name is in form of "name[]" and matches to child_name */ + else if (name_len > 1 && + name[name_len - 2] == '[' && name[name_len - 1] == ']' && + strlen(child_name) > name_len && + child_name[name_len - 2] == '[' && + strncmp(name, child_name, name_len - 2) == 0) + { + del = TRUE; + } + /* finally, check if name is "name" and matches child_name */ + else if (name_len == strchr(child_name, '[') - child_name && + strncmp(name, child_name, name_len) == 0) + { + del = TRUE; + } + if (del) + { + if (entry->ike_sa->delete_child_sa(entry->ike_sa, + child_sa->get_protocol(child_sa), + child_sa->get_spi(child_sa, TRUE)) == DESTROY_ME) + { + /* when a fatal error occurs, we are responsible to + * remove the IKE_SA */ + delete_entry(this, entry); + iterator->reset(iterator); + break; + } + } + } + child_iter->destroy(child_iter); + } + } + iterator->destroy(iterator); + pthread_mutex_unlock(&(this->mutex)); + + return SUCCESS; +} + +/** * Implementation of ike_sa_manager_t.destroy. */ static void destroy(private_ike_sa_manager_t *this) @@ -921,10 +949,9 @@ static void destroy(private_ike_sa_manager_t *this) this->logger->log(this->logger, CONTROL|LEVEL2, "destroy all entries"); /* Step 4: destroy all entries */ - while (list->get_count(list) > 0) + while (list->remove_last(list, (void**)&entry) == SUCCESS) { - list->get_first(list, (void**)&entry); - this->delete_entry(this, entry); + entry->destroy(entry); } list->destroy(list); pthread_mutex_unlock(&(this->mutex)); @@ -947,18 +974,12 @@ ike_sa_manager_t *ike_sa_manager_create() this->public.checkout = (ike_sa_t*(*)(ike_sa_manager_t*, ike_sa_id_t*))checkout; this->public.checkout_by_child = (ike_sa_t*(*)(ike_sa_manager_t*,u_int32_t))checkout_by_child; this->public.get_ike_sa_list = (linked_list_t*(*)(ike_sa_manager_t*))get_ike_sa_list; - this->public.get_ike_sa_list_by_name = (linked_list_t*(*)(ike_sa_manager_t*,const char*))get_ike_sa_list_by_name; this->public.log_status = (void(*)(ike_sa_manager_t*,logger_t*,char*))log_status; this->public.checkin = (status_t(*)(ike_sa_manager_t*,ike_sa_t*))checkin; this->public.delete = (status_t(*)(ike_sa_manager_t*,ike_sa_id_t*))delete_; + this->public.delete_by_name = (status_t(*)(ike_sa_manager_t*,char*))delete_by_name; this->public.checkin_and_destroy = (status_t(*)(ike_sa_manager_t*,ike_sa_t*))checkin_and_destroy; - /* initialize private functions */ - this->get_next_spi = get_next_spi; - this->get_entry_by_sa = get_entry_by_sa; - this->get_entry_by_id = get_entry_by_id; - this->delete_entry = delete_entry; - /* initialize private variables */ this->logger = logger_manager->get_logger(logger_manager, IKE_SA_MANAGER); diff --git a/src/charon/sa/ike_sa_manager.h b/src/charon/sa/ike_sa_manager.h index f0c90f38f..db2efe541 100644 --- a/src/charon/sa/ike_sa_manager.h +++ b/src/charon/sa/ike_sa_manager.h @@ -117,15 +117,6 @@ struct ike_sa_manager_t { linked_list_t *(*get_ike_sa_list) (ike_sa_manager_t* this); /** - * @brief Get a list of all IKE_SA SAs currently set up specified - * by the connections name. - * - * @param this the manager object - * @return a list with ike_sa_id_t s - */ - linked_list_t *(*get_ike_sa_list_by_name) (ike_sa_manager_t* this, const char *name); - - /** * @brief Log the status of the IKE_SA's in the manager. * * A informational log is done to the supplied logger. If logger is @@ -172,6 +163,29 @@ struct ike_sa_manager_t { status_t (*delete) (ike_sa_manager_t* this, ike_sa_id_t *ike_sa_id); /** + * @brief Delete a SA identified by its name, which was not checked out. + * + * Using delete_by_name allows the delete of IKE_SAs and CHILD_SAs. + * The supplied name may have one of the following format: + * + * name{x} => delete IKE_SA with "name" and unique id "x" + * name{} => delete all IKE_SAs with "name" + * name[x] => delete CHILD_SA with "name" and unique id "x" + * name[] => delete all CHILD_SAs with "name" + * name => delete all CHILD_SAs or IKE_SAs with "name" + * + * @warning do not use this when the SA is already checked out, this will + * deadlock! + * + * @param this the manager object + * @param name name in one of the format described above + * @returns + * - SUCCESS if found + * - NOT_FOUND when no such SA is available + */ + status_t (*delete_by_name) (ike_sa_manager_t* this, char *name); + + /** * @brief Destroy a checked out SA. * * The IKE SA is destroyed without notification of the remote peer. diff --git a/src/charon/sa/transactions/ike_sa_init.c b/src/charon/sa/transactions/ike_sa_init.c index 7a7866970..b14a0743b 100644 --- a/src/charon/sa/transactions/ike_sa_init.c +++ b/src/charon/sa/transactions/ike_sa_init.c @@ -111,6 +111,11 @@ struct private_ike_sa_init_t { u_int32_t reqid; /** + * Unique ID for to enumerate all IKE_SAs in its name + */ + u_int32_t unique_id; + + /** * Randomizer to generate nonces */ randomizer_t *randomizer; @@ -281,6 +286,7 @@ static status_t get_request(private_ike_sa_init_t *this, message_t **result) message_t *request; host_t *me, *other; identification_t *my_id, *other_id; + char name[64]; /* check if we already have built a message (retransmission) */ if (this->message) @@ -298,6 +304,12 @@ static status_t get_request(private_ike_sa_init_t *this, message_t **result) other_id = this->policy->get_other_id(this->policy); this->ike_sa->set_my_id(this->ike_sa, my_id->clone(my_id)); this->ike_sa->set_other_id(this->ike_sa, other_id->clone(other_id)); + if (snprintf(name, sizeof(name), "%s{%d}", + this->connection->get_name(this->connection), + this->unique_id) > 0) + { + this->ike_sa->set_name(this->ike_sa, name); + } /* build the request */ request = message_create(); @@ -516,6 +528,7 @@ static status_t get_response(private_ike_sa_init_t *this, nonce_payload_t *nonce_request = NULL; ike_sa_id_t *ike_sa_id; u_int32_t timeout; + char name[64]; /* check if we already have built a response (retransmission) */ if (this->message) @@ -561,8 +574,13 @@ static status_t get_response(private_ike_sa_init_t *this, me->get_string(me), other->get_string(other)); return DESTROY_ME; } - this->ike_sa->set_name(this->ike_sa, - this->connection->get_name(this->connection)); + + if (snprintf(name, sizeof(name), "%s{%d}", + this->connection->get_name(this->connection), + this->unique_id) > 0) + { + this->ike_sa->set_name(this->ike_sa, name); + } /* Precompute NAT-D hashes for incoming NAT notify comparison */ ike_sa_id = request->get_ike_sa_id(request); @@ -1077,6 +1095,7 @@ static void destroy(private_ike_sa_init_t *this) */ ike_sa_init_t *ike_sa_init_create(ike_sa_t *ike_sa) { + static u_int unique_id = 0; private_ike_sa_init_t *this = malloc_thing(private_ike_sa_init_t); /* transaction interface functions */ @@ -1103,6 +1122,7 @@ ike_sa_init_t *ike_sa_init_create(ike_sa_t *ike_sa) this->connection = NULL; this->policy = NULL; this->proposal = NULL; + this->unique_id = ++unique_id; this->reqid = 0; this->randomizer = randomizer_create(); this->nat_hasher = hasher_create(HASH_SHA1); diff --git a/src/charon/sa/transactions/rekey_ike_sa.c b/src/charon/sa/transactions/rekey_ike_sa.c index d35d2c245..8f0b869e9 100644 --- a/src/charon/sa/transactions/rekey_ike_sa.c +++ b/src/charon/sa/transactions/rekey_ike_sa.c @@ -376,7 +376,7 @@ static status_t switchto_new_sa(private_rekey_ike_sa_t* this, bool initiator) other_id = this->ike_sa->get_other_id(this->ike_sa); my_host = this->ike_sa->get_my_host(this->ike_sa); other_host = this->ike_sa->get_other_host(this->ike_sa); - name = this->connection->get_name(this->connection); + name = this->ike_sa->get_name(this->ike_sa); this->new_sa->set_my_id(this->new_sa, my_id->clone(my_id)); this->new_sa->set_other_id(this->new_sa, other_id->clone(other_id)); diff --git a/src/charon/threads/kernel_interface.c b/src/charon/threads/kernel_interface.c index 796cd04a8..c74cf8f27 100644 --- a/src/charon/threads/kernel_interface.c +++ b/src/charon/threads/kernel_interface.c @@ -50,7 +50,8 @@ #define KERNEL_AH 51 /** default priority of installed policies */ -#define SPD_PRIORITY 1024 +#define PRIO_LOW 3000 +#define PRIO_HIGH 2000 #define BUFFER_SIZE 1024 @@ -979,7 +980,7 @@ static status_t add_policy(private_kernel_interface_t *this, traffic_selector_t *src_ts, traffic_selector_t *dst_ts, policy_dir_t direction, protocol_id_t protocol, - u_int32_t reqid, bool update) + u_int32_t reqid, bool high_prio, bool update) { iterator_t *iterator; kernel_policy_t *current, *policy; @@ -1011,6 +1012,14 @@ static status_t add_policy(private_kernel_interface_t *this, current->refcount++; this->logger->log(this->logger, CONTROL|LEVEL1, "policy already exists, increasing refcount"); + if (!high_prio) + { + /* if added policy is for a ROUTED child_sa, do not + * overwrite existing INSTALLED policy */ + iterator->destroy(iterator); + pthread_mutex_unlock(&this->pol_mutex); + return SUCCESS; + } } policy = current; found = TRUE; @@ -1035,7 +1044,11 @@ static status_t add_policy(private_kernel_interface_t *this, policy_info = (struct xfrm_userpolicy_info*)NLMSG_DATA(hdr); policy_info->sel = policy->sel; policy_info->dir = policy->direction; - policy_info->priority = SPD_PRIORITY; + /* calculate priority based on source selector size, small size = high prio */ + policy_info->priority = high_prio ? PRIO_HIGH : PRIO_LOW; + policy_info->priority -= policy->sel.prefixlen_s * 10; + policy_info->priority -= policy->sel.proto ? 2 : 0; + policy_info->priority -= policy->sel.sport_mask ? 1 : 0; policy_info->action = XFRM_POLICY_ALLOW; policy_info->share = XFRM_SHARE_ANY; pthread_mutex_unlock(&this->pol_mutex); @@ -1272,7 +1285,7 @@ kernel_interface_t *kernel_interface_create() this->public.update_sa = (status_t(*)(kernel_interface_t*,host_t*,u_int32_t,protocol_id_t,host_t*,host_t*,host_diff_t,host_diff_t))update_sa; this->public.query_sa = (status_t(*)(kernel_interface_t*,host_t*,u_int32_t,protocol_id_t,u_int32_t*))query_sa; this->public.del_sa = (status_t(*)(kernel_interface_t*,host_t*,u_int32_t,protocol_id_t))del_sa; - this->public.add_policy = (status_t(*)(kernel_interface_t*,host_t*,host_t*,traffic_selector_t*,traffic_selector_t*,policy_dir_t,protocol_id_t,u_int32_t,bool))add_policy; + this->public.add_policy = (status_t(*)(kernel_interface_t*,host_t*,host_t*,traffic_selector_t*,traffic_selector_t*,policy_dir_t,protocol_id_t,u_int32_t,bool,bool))add_policy; this->public.query_policy = (status_t(*)(kernel_interface_t*,traffic_selector_t*,traffic_selector_t*,policy_dir_t,u_int32_t*))query_policy; this->public.del_policy = (status_t(*)(kernel_interface_t*,traffic_selector_t*,traffic_selector_t*,policy_dir_t))del_policy; this->public.destroy = (void(*)(kernel_interface_t*)) destroy; diff --git a/src/charon/threads/kernel_interface.h b/src/charon/threads/kernel_interface.h index bafb1a6d1..4370e8253 100644 --- a/src/charon/threads/kernel_interface.h +++ b/src/charon/threads/kernel_interface.h @@ -207,6 +207,7 @@ struct kernel_interface_t { * @param direction direction of traffic, POLICY_IN, POLICY_OUT, POLICY_FWD * @param protocol protocol to use to protect traffic (AH/ESP) * @param reqid uniqe ID of an SA to use to enforce policy + * @param high_prio if TRUE, uses a higher priority than any with FALSE * @param update update an existing policy, if TRUE * @return * - SUCCESS @@ -217,7 +218,7 @@ struct kernel_interface_t { traffic_selector_t *src_ts, traffic_selector_t *dst_ts, policy_dir_t direction, protocol_id_t protocol, - u_int32_t reqid, bool update); + u_int32_t reqid, bool high_prio, bool update); /** * @brief Query the use time of a policy. diff --git a/src/charon/threads/stroke_interface.c b/src/charon/threads/stroke_interface.c index b8bdd5a99..3a39990a9 100755 --- a/src/charon/threads/stroke_interface.c +++ b/src/charon/threads/stroke_interface.c @@ -601,58 +601,10 @@ static void stroke_route(private_stroke_t *this, stroke_msg_t *msg, bool route) */ static void stroke_terminate(private_stroke_t *this, stroke_msg_t *msg) { - linked_list_t *ike_sas; - iterator_t *iterator; - int instances = 0; - connection_t *conn; - pop_string(msg, &(msg->terminate.name)); this->logger->log(this->logger, CONTROL, "received stroke: terminate \"%s\"", msg->terminate.name); - /* we have to do tricky tricks to give the most comprehensive output to the user. - * There are different cases: - * 1. Connection is available, but IKEv1: - * => just ignore it, let pluto print it - * 2. Connection is not available, but instances of a deleted connection template: - * => terminate them, and print their termination - * 3. Connection is not available, and and no instances are there: - * => show error about bad connection name - * 4. An IKEv2 connection is available, and may contain instances: - * => terminate and print, simple - */ - conn = charon->connections->get_connection_by_name(charon->connections, msg->terminate.name); - if (conn == NULL || conn->is_ikev2(conn)) - { - ike_sas = charon->ike_sa_manager->get_ike_sa_list_by_name(charon->ike_sa_manager, msg->terminate.name); - - iterator = ike_sas->create_iterator(ike_sas, TRUE); - while (iterator->has_next(iterator)) - { - ike_sa_id_t *ike_sa_id; - iterator->current(iterator, (void**)&ike_sa_id); - charon->ike_sa_manager->delete(charon->ike_sa_manager, ike_sa_id); - ike_sa_id->destroy(ike_sa_id); - instances++; - } - iterator->destroy(iterator); - ike_sas->destroy(ike_sas); - if (conn == NULL && instances == 0) - { - this->stroke_logger->log(this->stroke_logger, CONTROL, - "no connection named \"%s\"", - msg->terminate.name); - } - else - { - this->stroke_logger->log(this->stroke_logger, CONTROL, - "terminated %d instances of \"%s\"", - instances, msg->terminate.name); - } - } - if (conn) - { - conn->destroy(conn); - } + charon->ike_sa_manager->delete_by_name(charon->ike_sa_manager, msg->terminate.name); } /** |