diff options
-rw-r--r-- | src/charon/network/packet.c | 18 | ||||
-rw-r--r-- | src/charon/queues/event_queue.c | 75 | ||||
-rw-r--r-- | src/charon/queues/job_queue.c | 18 | ||||
-rw-r--r-- | src/charon/queues/send_queue.c | 47 | ||||
-rw-r--r-- | src/charon/sa/child_sa.c | 73 | ||||
-rw-r--r-- | src/charon/sa/child_sa.h | 32 | ||||
-rw-r--r-- | src/charon/sa/transactions/create_child_sa.c | 121 | ||||
-rw-r--r-- | src/charon/sa/transactions/create_child_sa.h | 36 | ||||
-rw-r--r-- | src/charon/sa/transactions/delete_child_sa.c | 19 | ||||
-rw-r--r-- | src/charon/sa/transactions/transaction.h | 4 | ||||
-rw-r--r-- | src/charon/threads/kernel_interface.c | 13 | ||||
-rw-r--r-- | src/charon/threads/receiver.c | 10 | ||||
-rw-r--r-- | src/charon/threads/scheduler.c | 14 | ||||
-rw-r--r-- | src/charon/threads/sender.c | 20 | ||||
-rw-r--r-- | src/charon/threads/thread_pool.c | 41 |
15 files changed, 312 insertions, 229 deletions
diff --git a/src/charon/network/packet.c b/src/charon/network/packet.c index df054c0c5..6c16a9d8d 100644 --- a/src/charon/network/packet.c +++ b/src/charon/network/packet.c @@ -133,39 +133,23 @@ static void destroy(private_packet_t *this) static packet_t *clone(private_packet_t *this) { private_packet_t *other = (private_packet_t*)packet_create(); - + if (this->destination != NULL) { other->destination = this->destination->clone(this->destination); } - else - { - other->destination = NULL; - } - if (this->source != NULL) { other->source = this->source->clone(this->source); } - else - { - other->source = NULL; - } - - /* only clone existing chunks :-) */ if (this->data.ptr != NULL) { other->data.ptr = clalloc(this->data.ptr,this->data.len); other->data.len = this->data.len; } - else - { - other->data = CHUNK_INITIALIZER; - } return &(other->public); } - /* * Documented in header */ diff --git a/src/charon/queues/event_queue.c b/src/charon/queues/event_queue.c index 9a3419cb2..10f139e7a 100644 --- a/src/charon/queues/event_queue.c +++ b/src/charon/queues/event_queue.c @@ -34,12 +34,9 @@ typedef struct event_t event_t; /** - * @brief Represents an event as it is stored in the event queue. - * - * A event consists of a event time and an assigned job object. - * + * Event containing a job and a schedule time */ -struct event_t{ +struct event_t { /** * Time to fire the event. */ @@ -49,48 +46,12 @@ struct event_t{ * Every event has its assigned job. */ job_t * job; - - /** - * @brief Destroys a event_t object. - * - * @param event_t calling object - */ - void (*destroy) (event_t *event); }; - -/** - * implements event_t.destroy - */ -static void event_destroy(event_t *event) -{ - free(event); -} - -/** - * @brief Creates a event for a specific time - * - * @param time absolute time to fire the event - * @param job job to add to job-queue at specific time - * - * @returns created event_t object - */ -static event_t *event_create(timeval_t time, job_t *job) -{ - event_t *this = malloc_thing(event_t); - - this->destroy = event_destroy; - this->time = time; - this->job = job; - - return this; -} - typedef struct private_event_queue_t private_event_queue_t; /** * Private Variables and Functions of event_queue_t class. - * */ struct private_event_queue_t { /** @@ -155,7 +116,7 @@ static job_t *get(private_event_queue_t *this) pthread_mutex_lock(&(this->mutex)); - while (1) + while (TRUE) { while(this->list->get_count(this->list) == 0) { @@ -170,7 +131,7 @@ static job_t *get(private_event_queue_t *this) pthread_cleanup_pop(0); } - this->list->get_first(this->list,(void **) &next_event); + this->list->get_first(this->list, (void **)&next_event); gettimeofday(¤t_time, NULL); long difference = time_difference(¤t_time,&(next_event->time)); @@ -192,11 +153,9 @@ static job_t *get(private_event_queue_t *this) else { /* event available */ - this->list->remove_first(this->list,(void **) &next_event); - + this->list->remove_first(this->list, (void **)&next_event); job = next_event->job; - - next_event->destroy(next_event); + free(next_event); break; } } @@ -212,9 +171,14 @@ static job_t *get(private_event_queue_t *this) */ static void add_absolute(private_event_queue_t *this, job_t *job, timeval_t time) { - event_t *event = event_create(time,job); + event_t *event; event_t *current_event; status_t status; + + /* create event */ + event = malloc_thing(event_t); + event->time = time; + event->job = job; pthread_mutex_lock(&(this->mutex)); @@ -298,24 +262,15 @@ static void add_relative(event_queue_t *this, job_t *job, u_int32_t ms) */ static void event_queue_destroy(private_event_queue_t *this) { - while (this->list->get_count(this->list) > 0) + event_t *event; + while (this->list->remove_last(this->list, (void**)&event) == SUCCESS) { - event_t *event; - - if (this->list->remove_first(this->list,(void *) &event) != SUCCESS) - { - this->list->destroy(this->list); - break; - } event->job->destroy(event->job); - event->destroy(event); + free(event); } this->list->destroy(this->list); - pthread_mutex_destroy(&(this->mutex)); - pthread_cond_destroy(&(this->condvar)); - free(this); } diff --git a/src/charon/queues/job_queue.c b/src/charon/queues/job_queue.c index c1df42136..d33cd5ae4 100644 --- a/src/charon/queues/job_queue.c +++ b/src/charon/queues/job_queue.c @@ -86,14 +86,14 @@ static job_t *get(private_job_queue_t *this) /* add mutex unlock handler for cancellation, enable cancellation */ pthread_cleanup_push((void(*)(void*))pthread_mutex_unlock, (void*)&(this->mutex)); pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate); - + pthread_cond_wait( &(this->condvar), &(this->mutex)); - + /* reset cancellation, remove mutex-unlock handler (without executing) */ pthread_setcancelstate(oldstate, NULL); pthread_cleanup_pop(0); } - this->list->remove_first(this->list,(void **) &job); + this->list->remove_first(this->list, (void **)&job); pthread_mutex_unlock(&(this->mutex)); return job; } @@ -114,22 +114,14 @@ static void add(private_job_queue_t *this, job_t *job) */ static void job_queue_destroy (private_job_queue_t *this) { - while (this->list->get_count(this->list) > 0) + job_t *job; + while (this->list->remove_last(this->list, (void**)&job) == SUCCESS) { - job_t *job; - if (this->list->remove_first(this->list,(void *) &job) != SUCCESS) - { - this->list->destroy(this->list); - break; - } job->destroy(job); } this->list->destroy(this->list); - pthread_mutex_destroy(&(this->mutex)); - pthread_cond_destroy(&(this->condvar)); - free(this); } diff --git a/src/charon/queues/send_queue.c b/src/charon/queues/send_queue.c index 1112beffb..e92f63043 100644 --- a/src/charon/queues/send_queue.c +++ b/src/charon/queues/send_queue.c @@ -69,9 +69,9 @@ struct private_send_queue_t { static int get_count(private_send_queue_t *this) { int count; - pthread_mutex_lock(&(this->mutex)); + pthread_mutex_lock(&this->mutex); count = this->list->get_count(this->list); - pthread_mutex_unlock(&(this->mutex)); + pthread_mutex_unlock(&this->mutex); return count; } @@ -82,22 +82,23 @@ static packet_t *get(private_send_queue_t *this) { int oldstate; packet_t *packet; - pthread_mutex_lock(&(this->mutex)); - /* go to wait while no packets available */ + pthread_mutex_lock(&this->mutex); + + /* go to wait while no packets available */ while(this->list->get_count(this->list) == 0) { /* add mutex unlock handler for cancellation, enable cancellation */ - pthread_cleanup_push((void(*)(void*))pthread_mutex_unlock, (void*)&(this->mutex)); + pthread_cleanup_push((void(*)(void*))pthread_mutex_unlock, (void*)&this->mutex); pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate); - pthread_cond_wait( &(this->condvar), &(this->mutex)); - + pthread_cond_wait(&this->condvar, &this->mutex); + /* reset cancellation, remove mutex-unlock handler (without executing) */ pthread_setcancelstate(oldstate, NULL); pthread_cleanup_pop(0); } - this->list->remove_first(this->list,(void **)&packet); - pthread_mutex_unlock(&(this->mutex)); + this->list->remove_first(this->list, (void**)&packet); + pthread_mutex_unlock(&this->mutex); return packet; } @@ -114,10 +115,10 @@ static void add(private_send_queue_t *this, packet_t *packet) src->get_address(src), src->get_port(src), dst->get_address(dst), dst->get_port(dst)); - pthread_mutex_lock(&(this->mutex)); - this->list->insert_last(this->list,packet); - pthread_cond_signal( &(this->condvar)); - pthread_mutex_unlock(&(this->mutex)); + pthread_mutex_lock(&this->mutex); + this->list->insert_last(this->list, packet); + pthread_cond_signal(&this->condvar); + pthread_mutex_unlock(&this->mutex); } /** @@ -125,24 +126,14 @@ static void add(private_send_queue_t *this, packet_t *packet) */ static void destroy (private_send_queue_t *this) { - - /* destroy all packets in list before destroying list */ - while (this->list->get_count(this->list) > 0) + packet_t *packet; + while (this->list->remove_last(this->list, (void**)&packet) == SUCCESS) { - packet_t *packet; - if (this->list->remove_first(this->list,(void *) &packet) != SUCCESS) - { - this->list->destroy(this->list); - break; - } packet->destroy(packet); } this->list->destroy(this->list); - pthread_mutex_destroy(&(this->mutex)); - pthread_cond_destroy(&(this->condvar)); - free(this); } @@ -160,9 +151,9 @@ send_queue_t *send_queue_create(void) this->public.destroy = (void(*)(send_queue_t*)) destroy; this->list = linked_list_create(); - pthread_mutex_init(&(this->mutex), NULL); - pthread_cond_init(&(this->condvar), NULL); + pthread_mutex_init(&this->mutex, NULL); + pthread_cond_init(&this->condvar, NULL); this->logger = logger_manager->get_logger(logger_manager, SOCKET); - + return (&this->public); } diff --git a/src/charon/sa/child_sa.c b/src/charon/sa/child_sa.c index 223def9f9..033114154 100644 --- a/src/charon/sa/child_sa.c +++ b/src/charon/sa/child_sa.c @@ -110,9 +110,14 @@ struct private_child_sa_t { u_int32_t hard_lifetime; /** - * has this CHILD_SA been rekeyed? + * transaction which is rekeying this CHILD_SA */ - bool rekeyed; + void *rekeying_transaction; + + /** + * has this child SA been rekeyed/is rekeying? + */ + bool is_rekeying; /** * Specifies if NAT traversal is used @@ -322,7 +327,7 @@ static status_t install(private_child_sa_t *this, proposal_t *proposal, prf_plus prf_plus, natt, mine); this->install_time = time(NULL); - + return status; } @@ -477,11 +482,28 @@ static status_t add_policies(private_child_sa_t *this, linked_list_t *my_ts_list } /** - * Implementation of child_sa_t.set_rekeyed. + * Implementation of child_sa_t.set_rekeying_transaction. + */ +static void set_rekeying_transaction(private_child_sa_t *this, void *transaction) +{ + this->rekeying_transaction = transaction; + this->is_rekeying = TRUE; +} + +/** + * Implementation of child_sa_t.get_rekeying_transaction. */ -static void set_rekeyed(private_child_sa_t *this) +static void* get_rekeying_transaction(private_child_sa_t *this) { - this->rekeyed = TRUE; + return this->rekeying_transaction; +} + +/** + * Implementation of child_sa_t.is_rekeying. + */ +static bool is_rekeying(private_child_sa_t *this) +{ + return this->is_rekeying; } /** @@ -685,16 +707,6 @@ static status_t update_sa_hosts(private_child_sa_t *this, host_t *new_me, host_t if (mine) { - src = this->me.addr; - dst = this->other.addr; - new_src = new_me; - new_dst = new_other; - src_changes = my_changes; - dst_changes = other_changes; - spi = this->me.spi; - } - else - { src = this->other.addr; dst = this->me.addr; new_src = new_other; @@ -703,6 +715,16 @@ static status_t update_sa_hosts(private_child_sa_t *this, host_t *new_me, host_t dst_changes = my_changes; spi = this->other.spi; } + else + { + src = this->me.addr; + dst = this->other.addr; + new_src = new_me; + new_dst = new_other; + src_changes = my_changes; + dst_changes = other_changes; + spi = this->me.spi; + } this->logger->log(this->logger, CONTROL|LEVEL1, "updating %s SA 0x%x, from %s:%d..%s:%d to %s:%d..%s:%d", @@ -783,7 +805,7 @@ static status_t update_policy_hosts(private_child_sa_t *this, host_t *new_me, ho static status_t update_hosts(private_child_sa_t *this, host_t *new_me, host_t *new_other, int my_changes, int other_changes) { - if (!my_changes || !other_changes) + if (!my_changes && !other_changes) { return SUCCESS; } @@ -857,7 +879,7 @@ static void destroy(private_child_sa_t *this) /* delete all policies in the kernel */ while (this->policies->remove_last(this->policies, (void**)&policy) == SUCCESS) { - if (!this->rekeyed) + if (!this->is_rekeying) { /* let rekeyed policies, as they are used by another child_sa */ charon->kernel_interface->del_policy(charon->kernel_interface, @@ -883,7 +905,9 @@ static void destroy(private_child_sa_t *this) free(policy); } this->policies->destroy(this->policies); - + + this->me.addr->destroy(this->me.addr); + this->other.addr->destroy(this->other.addr); free(this); } @@ -907,14 +931,16 @@ child_sa_t * child_sa_create(u_int32_t rekey, host_t *me, host_t* other, this->public.update_hosts = (status_t (*)(child_sa_t*,host_t*,host_t*,int,int))update_hosts; this->public.add_policies = (status_t (*)(child_sa_t*, linked_list_t*,linked_list_t*))add_policies; this->public.get_use_time = (status_t (*)(child_sa_t*,bool,time_t*))get_use_time; - this->public.set_rekeyed = (void (*)(child_sa_t*))set_rekeyed; + this->public.set_rekeying_transaction = (void (*)(child_sa_t*,void*))set_rekeying_transaction; + this->public.get_rekeying_transaction = (void* (*)(child_sa_t*))get_rekeying_transaction; + this->public.is_rekeying = (bool (*)(child_sa_t*))is_rekeying; this->public.log_status = (void (*)(child_sa_t*, logger_t*, char*))log_status; this->public.destroy = (void(*)(child_sa_t*))destroy; /* private data */ this->logger = logger_manager->get_logger(logger_manager, CHILD_SA); - this->me.addr = me; - this->other.addr = other; + this->me.addr = me->clone(me); + this->other.addr = other->clone(other); this->me.spi = 0; this->other.spi = 0; this->alloc_ah_spi = 0; @@ -926,7 +952,8 @@ child_sa_t * child_sa_create(u_int32_t rekey, host_t *me, host_t* other, this->reqid = rekey ? rekey : ++reqid; this->policies = linked_list_create(); this->protocol = PROTO_NONE; - this->rekeyed = FALSE; + this->rekeying_transaction = NULL; + this->is_rekeying = FALSE; return &this->public; } diff --git a/src/charon/sa/child_sa.h b/src/charon/sa/child_sa.h index 6c1ca0177..fba0c73a5 100644 --- a/src/charon/sa/child_sa.h +++ b/src/charon/sa/child_sa.h @@ -39,7 +39,7 @@ typedef struct child_sa_t child_sa_t; /** - * @brief Represents multiple IPsec SAs between two hosts. + * @brief Represents an IPsec SAs between two hosts. * * A child_sa_t contains two SAs. SAs for both * directions are managed in one child_sa_t object. Both @@ -168,15 +168,35 @@ struct child_sa_t { status_t (*get_use_time) (child_sa_t *this, bool inbound, time_t *use_time); /** - * @brief Mark this child_sa as rekeyed. + * @brief Set the transaction which rekeys this CHILD_SA. * - * Since an SA which rekeys a old SA shares the same policy, - * we must mark a child_sa as rekeyed. A so marked SA does - * not remove its policy, as the new SA uses it. + * Since either end may initiate CHILD_SA rekeying, we must detect + * such situations to handle them cleanly. A rekeying transaction + * registers itself to the CHILD_SA, and checks later if another + * transaction is in progress of a rekey. * * @param this calling object */ - void (*set_rekeyed) (child_sa_t *this); + void (*set_rekeying_transaction) (child_sa_t *this, void *transaction); + + /** + * @brief Get the transaction which rekeys this CHILD_SA. + * + * See set_rekeying_transactoin + * + * @param this calling object + */ + void* (*get_rekeying_transaction) (child_sa_t *this); + + /** + * @brief Is the CHILD SA rekeying/in progress of rekeying? + * + * This is a readonly parameter. It is set whenever the + * set_rekeying_transaction() method is called. + * + * @param this calling object + */ + bool (*is_rekeying) (child_sa_t *this); /** * @brief Log the status of a child_sa to a logger. diff --git a/src/charon/sa/transactions/create_child_sa.c b/src/charon/sa/transactions/create_child_sa.c index 6fce5e07b..30ccdef06 100644 --- a/src/charon/sa/transactions/create_child_sa.c +++ b/src/charon/sa/transactions/create_child_sa.c @@ -28,7 +28,6 @@ #include <encoding/payloads/sa_payload.h> #include <encoding/payloads/nonce_payload.h> #include <encoding/payloads/ts_payload.h> -#include <sa/child_sa.h> #include <sa/transactions/delete_child_sa.h> #include <utils/randomizer.h> @@ -116,6 +115,11 @@ struct private_create_child_sa_t { child_sa_t *rekeyed_sa; /** + * Have we lost the simultaneous rekeying nonce compare? + */ + bool lost; + + /** * source of randomness */ randomizer_t *randomizer; @@ -143,7 +147,7 @@ static u_int32_t requested(private_create_child_sa_t *this) } /** - * Implementation of transaction_t.rekeys_child. + * Implementation of create_child_sa_t.rekeys_child. */ static void rekeys_child(private_create_child_sa_t *this, child_sa_t *child_sa) { @@ -151,6 +155,15 @@ static void rekeys_child(private_create_child_sa_t *this, child_sa_t *child_sa) } /** + * Implementation of create_child_sa_t.cancel. + */ +static void cancel(private_create_child_sa_t *this) +{ + this->rekeyed_sa = NULL; + this->lost = TRUE; +} + +/** * Implementation of transaction_t.get_request. */ static status_t get_request(private_create_child_sa_t *this, message_t **result) @@ -158,6 +171,15 @@ static status_t get_request(private_create_child_sa_t *this, message_t **result) message_t *request; host_t *me, *other; + /* check if we are not already rekeying */ + if (this->rekeyed_sa && + this->rekeyed_sa->is_rekeying(this->rekeyed_sa)) + { + this->logger->log(this->logger, ERROR, + "rekeying a CHILD_SA which is already rekeying, aborted"); + return FAILED; + } + /* check if we already have built a message (retransmission) */ if (this->message) { @@ -249,8 +271,8 @@ static status_t get_request(private_create_child_sa_t *this, message_t **result) notify->set_spi(notify, this->rekeyed_sa->get_spi(this->rekeyed_sa, TRUE)); request->add_payload(request, (payload_t*)notify); - /* and mark sa with rekeying-in-progress */ - this->rekeyed_sa->set_rekeyed(this->rekeyed_sa); + /* register us as rekeying to detect multiple rekeying */ + this->rekeyed_sa->set_rekeying_transaction(this->rekeyed_sa, &this->public); } return SUCCESS; @@ -605,12 +627,21 @@ static status_t get_response(private_create_child_sa_t *this, message_t *request ts_response = ts_payload_create_from_traffic_selectors(FALSE, this->tsr); response->add_payload(response, (payload_t*)ts_response); } - /* CHILD_SA successfully created. Now we must check if it rekeys an old one, - * and if so, mark the old as rekeyed. It will get deleted from the other - * peer. */ + /* CHILD_SA successfully created. We set us as the rekeying transaction of + * this SA. If we already initiated rekeying of the same SA, we will detect + * this later in the conclude() call. */ if (this->rekeyed_sa) { - this->rekeyed_sa->set_rekeyed(this->rekeyed_sa); + if (this->rekeyed_sa->is_rekeying(this->rekeyed_sa)) + { + /* rekeying already in progress, register us, too */ + this->rekeyed_sa->set_rekeying_transaction(this->rekeyed_sa, &this->public); + } + else + { + /* no rekeying in progress. mark SA as rekeyed, but not conflicted */ + this->rekeyed_sa->set_rekeying_transaction(this->rekeyed_sa, NULL); + } } return SUCCESS; } @@ -628,6 +659,8 @@ static status_t conclude(private_create_child_sa_t *this, message_t *response, ts_payload_t *tsi_payload = NULL; ts_payload_t *tsr_payload = NULL; status_t status; + child_sa_t *new_child = NULL; + delete_child_sa_t *delete_child_sa; /* check message type */ if (response->get_exchange_type(response) != CREATE_CHILD_SA) @@ -726,6 +759,7 @@ static status_t conclude(private_create_child_sa_t *this, message_t *response, "CHILD_SA creation failed"); return FAILED; } + new_child = this->child_sa; if (install_child_sa(this, TRUE) != SUCCESS) { this->logger->log(this->logger, ERROR, @@ -733,14 +767,73 @@ static status_t conclude(private_create_child_sa_t *this, message_t *response, return FAILED; } } - /* CHILD_SA successfully created. If we have rekeyed an old one, delete it */ + /* CHILD_SA successfully created. If the other peer initiated rekeying + * in the meantime, we detect this by comparing the rekeying_transaction + * of the SA. If it changed, we are not alone. Then we must compare the nonces. + * If no simultaneous rekeying is going on, we just initiate the delete of + * the superseded SA. */ if (this->rekeyed_sa) { - delete_child_sa_t *delete_child_sa; + private_create_child_sa_t *other; + + other = (private_create_child_sa_t*) + this->rekeyed_sa->get_rekeying_transaction(this->rekeyed_sa); - delete_child_sa = delete_child_sa_create(this->ike_sa, - this->message_id + 1); - delete_child_sa->set_child_sa(delete_child_sa, this->rekeyed_sa); + /* we are not rekeying anymore, unregister us */ + this->rekeyed_sa->set_rekeying_transaction(this->rekeyed_sa, NULL); + + if (other != this) + { /* simlutaneous rekeying is going on, not so good */ + chunk_t this_lowest, other_lowest; + + /* check if this has a lower nonce the other */ + if (memcmp(this->nonce_i.ptr, this->nonce_r.ptr, + min(this->nonce_i.len, this->nonce_r.len)) < 0) + { + this_lowest = this->nonce_i; + } + else + { + this_lowest = this->nonce_r; + } + if (memcmp(other->nonce_i.ptr, other->nonce_r.ptr, + min(other->nonce_i.len, other->nonce_r.len)) < 0) + { + other_lowest = other->nonce_i; + } + else + { + other_lowest = other->nonce_r; + } + if (memcmp(this_lowest.ptr, other_lowest.ptr, + min(this_lowest.len, other_lowest.len)) < 0) + { + this->logger->log(this->logger, ERROR, + "detected simultaneous CHILD_SA rekeying, but ours is preferred"); + } + else + { + + this->logger->log(this->logger, ERROR, + "detected simultaneous CHILD_SA rekeying, deleting ours"); + this->lost = TRUE; + } + } + /* delete the old SA if we have won the rekeying nonce compare*/ + if (!this->lost) + { + other->rekeyed_sa->set_rekeying_transaction(other->rekeyed_sa, NULL); + delete_child_sa = delete_child_sa_create(this->ike_sa, this->message_id + 1); + delete_child_sa->set_child_sa(delete_child_sa, this->rekeyed_sa); + *next = (transaction_t*)delete_child_sa; + } + } + if (this->lost) + { + /* we have lost simlutaneous rekeying, delete the CHILD_SA we just have created */ + delete_child_sa = delete_child_sa_create(this->ike_sa, this->message_id + 1); + new_child->set_rekeying_transaction(new_child, NULL); + delete_child_sa->set_child_sa(delete_child_sa, new_child); *next = (transaction_t*)delete_child_sa; } return SUCCESS; @@ -788,6 +881,7 @@ create_child_sa_t *create_child_sa_create(ike_sa_t *ike_sa, u_int32_t message_id /* public functions */ this->public.rekeys_child = (void(*)(create_child_sa_t*,child_sa_t*))rekeys_child; + this->public.cancel = (void(*)(create_child_sa_t*))cancel; /* private data */ this->ike_sa = ike_sa; @@ -799,6 +893,7 @@ create_child_sa_t *create_child_sa_create(ike_sa_t *ike_sa, u_int32_t message_id this->nonce_r = CHUNK_INITIALIZER; this->child_sa = NULL; this->rekeyed_sa = NULL; + this->lost = FALSE; this->proposal = NULL; this->tsi = NULL; this->tsr = NULL; diff --git a/src/charon/sa/transactions/create_child_sa.h b/src/charon/sa/transactions/create_child_sa.h index b2bae7728..d3c05a620 100644 --- a/src/charon/sa/transactions/create_child_sa.h +++ b/src/charon/sa/transactions/create_child_sa.h @@ -20,9 +20,8 @@ * for more details. */ - -#ifndef CREATE_CHILD_SA_ -#define CREATE_CHILD_SA_ +#ifndef CREATE_CHILD_SA_H_ +#define CREATE_CHILD_SA_H_ #include <sa/ike_sa.h> #include <sa/child_sa.h> @@ -37,6 +36,23 @@ typedef struct create_child_sa_t create_child_sa_t; * Rekeying of an CHILD_SA works the same way as creating a new one, * but includes an additional REKEY_SA notify and deletes the old * one (in a separate transaction). + * + * ¦__________ _________¦ + * ¦ Cyq \/ Czq ¦ + * ¦__________/\_________¦ + * detect ¦__________ _________¦ detect + * ¦ Czp \/ Czp ¦ + * compare nonces, won ¦__________/\_________¦ compare nonces, lost + * ¦ ¦ + * delete old ¦__________ ¦ + * ¦ Dxq \__________¦ + * ¦ __________¦ + * ¦__________/ Dxp ¦ + * ¦ __________¦ delete created + * ¦__________/ Dzq ¦ + * ¦__________ ¦ + * ¦ Dzp \__________¦ + * * * @b Constructors: * - create_child_sa_create() @@ -61,6 +77,18 @@ struct create_child_sa_t { * @param child_sa CHILD_SA to rekey */ void (*rekeys_child) (create_child_sa_t* this, child_sa_t *child_sa); + + /** + * @brief Cancel a rekeying request. + * + * Cancelling a rekeying request will set a flag in the transaction. When + * the response for the transaction is received, the created CHILD_SA + * gets deleted afterwards. + * + * @param this calling object + * @param child_sa CHILD_SA to rekey + */ + void (*cancel) (create_child_sa_t* this); }; /** @@ -74,4 +102,4 @@ struct create_child_sa_t { */ create_child_sa_t *create_child_sa_create(ike_sa_t *ike_sa, u_int32_t message_id); -#endif /* CREATE_CHILD_SA_ */ +#endif /* CREATE_CHILD_SA_H_ */ diff --git a/src/charon/sa/transactions/delete_child_sa.c b/src/charon/sa/transactions/delete_child_sa.c index 760105204..621d2ab4c 100644 --- a/src/charon/sa/transactions/delete_child_sa.c +++ b/src/charon/sa/transactions/delete_child_sa.c @@ -24,6 +24,7 @@ #include <daemon.h> #include <encoding/payloads/delete_payload.h> +#include <sa/transactions/create_child_sa.h> typedef struct private_delete_child_sa_t private_delete_child_sa_t; @@ -151,7 +152,7 @@ static status_t process_delete(private_delete_child_sa_t *this, delete_payload_t protocol_id_t protocol; u_int32_t spi; iterator_t *iterator; - delete_payload_t *delete_response; + delete_payload_t *delete_response = NULL; /* get requested CHILD */ protocol = delete_request->get_protocol_id(delete_request); @@ -178,9 +179,23 @@ static status_t process_delete(private_delete_child_sa_t *this, delete_payload_t if (child_sa != NULL) { + create_child_sa_t *rekey; + this->logger->log(this->logger, CONTROL, - "received DELETE for %s CHILD_SA with SPI 0x%x, deleting", + "received DELETE for %s CHILD_SA with SPI 0x%x, deleting", mapping_find(protocol_id_m, protocol), ntohl(spi)); + + rekey = child_sa->get_rekeying_transaction(child_sa); + if (rekey) + { + /* we have received a delete for an SA which we are still rekeying. + * this means we have lost the nonce comparison, and the rekeying + * will fail. We set a flag in the transaction for this special case. + */ + this->logger->log(this->logger, CONTROL, + "DELETE received while rekeying, rekeying cancelled"); + rekey->cancel(rekey); + } /* delete it, with inbound spi */ spi = child_sa->get_spi(child_sa, TRUE); this->ike_sa->destroy_child_sa(this->ike_sa, protocol, spi); diff --git a/src/charon/sa/transactions/transaction.h b/src/charon/sa/transactions/transaction.h index ea84b0394..9bb600fe4 100644 --- a/src/charon/sa/transactions/transaction.h +++ b/src/charon/sa/transactions/transaction.h @@ -23,12 +23,14 @@ #ifndef TRANSACTION_H_ #define TRANSACTION_H_ + +typedef struct transaction_t transaction_t; + #include <types.h> #include <encoding/message.h> #include <sa/ike_sa.h> -typedef struct transaction_t transaction_t; /** * @brief This interface represents a transaction an established IKE_SA can do. diff --git a/src/charon/threads/kernel_interface.c b/src/charon/threads/kernel_interface.c index 9d8463a75..0f4a4735a 100644 --- a/src/charon/threads/kernel_interface.c +++ b/src/charon/threads/kernel_interface.c @@ -29,6 +29,7 @@ #include <sys/socket.h> #include <linux/netlink.h> #include <linux/rtnetlink.h> +#include <linux/udp.h> #include <pthread.h> #include <unistd.h> #include <fcntl.h> @@ -383,10 +384,7 @@ static status_t add_sa(private_kernel_interface_t *this, } struct xfrm_encap_tmpl* encap = (struct xfrm_encap_tmpl*)RTA_DATA(rthdr); - /* UDP_ENCAP_ESPINUDP, see /usr/src/linux/include/linux/udp.h - * we could probably use 3 here (as pluto does) although the - * result is eventually the same. */ - encap->encap_type = 2; + encap->encap_type = UDP_ENCAP_ESPINUDP; encap->encap_sport = ntohs(natt->sport); encap->encap_dport = ntohs(natt->dport); memset(&encap->encap_oa, 0, sizeof (xfrm_address_t)); @@ -440,9 +438,9 @@ static status_t update_sa_hosts( this->logger->log(this->logger, CONTROL|LEVEL2, "getting SA"); struct nlmsghdr *hdr = (struct nlmsghdr*)request; - hdr->nlmsg_flags = NLM_F_REQUEST ; + hdr->nlmsg_flags = NLM_F_REQUEST; hdr->nlmsg_type = XFRM_MSG_GETSA; - hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct xfrm_usersa_info)); + hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct xfrm_usersa_id)); struct xfrm_usersa_id *sa_id = (struct xfrm_usersa_id*)NLMSG_DATA(hdr); sa_id->daddr = dst->get_xfrm_addr(dst); @@ -996,12 +994,11 @@ kernel_interface_t *kernel_interface_create() /* public functions */ this->public.get_spi = (status_t(*)(kernel_interface_t*,host_t*,host_t*,protocol_id_t,u_int32_t,u_int32_t*))get_spi; this->public.add_sa = (status_t(*)(kernel_interface_t *,host_t*,host_t*,u_int32_t,protocol_id_t,u_int32_t,u_int64_t,u_int64_t,algorithm_t*,algorithm_t*,prf_plus_t*,natt_conf_t*,bool))add_sa; - this->public.add_policy = (status_t(*)(kernel_interface_t*,host_t*, host_t*,host_t*,host_t*,u_int8_t,u_int8_t,int,int,protocol_id_t,u_int32_t))add_policy; this->public.update_sa_hosts = (status_t(*)(kernel_interface_t*,host_t*,host_t*,host_t*,host_t*,int,int,u_int32_t,protocol_id_t))update_sa_hosts; 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*,host_t*,host_t*,u_int8_t,u_int8_t,int,int,protocol_id_t,u_int32_t))add_policy; this->public.query_policy = (status_t(*)(kernel_interface_t*,host_t*,host_t*,host_t*,host_t*,u_int8_t,u_int8_t,int,int,time_t*))query_policy; this->public.del_policy = (status_t(*)(kernel_interface_t*,host_t*,host_t*,host_t*,host_t*,u_int8_t,u_int8_t,int,int))del_policy; - this->public.destroy = (void(*)(kernel_interface_t*)) destroy; /* private members */ diff --git a/src/charon/threads/receiver.c b/src/charon/threads/receiver.c index 003569d8a..d60792be9 100644 --- a/src/charon/threads/receiver.c +++ b/src/charon/threads/receiver.c @@ -45,13 +45,6 @@ struct private_receiver_t { * Public part of a receiver_t object. */ receiver_t public; - - /** - * @brief Thread function started at creation of the receiver object. - * - * @param this calling object - */ - void (*receive_packets) (private_receiver_t *this); /** * Assigned thread. @@ -114,11 +107,10 @@ receiver_t * receiver_create() private_receiver_t *this = malloc_thing(private_receiver_t); this->public.destroy = (void(*)(receiver_t*)) destroy; - this->receive_packets = receive_packets; this->logger = logger_manager->get_logger(logger_manager, RECEIVER); - if (pthread_create(&(this->assigned_thread), NULL, (void*(*)(void*))this->receive_packets, this) != 0) + if (pthread_create(&(this->assigned_thread), NULL, (void*(*)(void*))receive_packets, this) != 0) { this->logger->log(this->logger, ERROR, "Receiver thread could not be started"); free(this); diff --git a/src/charon/threads/scheduler.c b/src/charon/threads/scheduler.c index 759a69c83..d3013cb95 100644 --- a/src/charon/threads/scheduler.c +++ b/src/charon/threads/scheduler.c @@ -42,15 +42,6 @@ struct private_scheduler_t { * Public part of a scheduler_t object. */ scheduler_t public; - - /** - * @brief Get events from the event queue and add them to to job queue. - * - * Thread function started at creation of the scheduler object. - * - * @param this calling object - */ - void (*get_events) (private_scheduler_t *this); /** * Assigned thread. @@ -75,7 +66,7 @@ static void get_events(private_scheduler_t * this) this->logger->log(this->logger, CONTROL, "scheduler thread running, thread_ID: %06u", (int)pthread_self()); - for (;;) + while (TRUE) { this->logger->log(this->logger, CONTROL|LEVEL2, "Waiting for next event..."); /* get a job, this block until one is available */ @@ -109,11 +100,10 @@ scheduler_t * scheduler_create() private_scheduler_t *this = malloc_thing(private_scheduler_t); this->public.destroy = (void(*)(scheduler_t*)) destroy; - this->get_events = get_events; this->logger = logger_manager->get_logger(logger_manager, SCHEDULER); - if (pthread_create(&(this->assigned_thread), NULL, (void*(*)(void*))this->get_events, this) != 0) + if (pthread_create(&(this->assigned_thread), NULL, (void*(*)(void*))get_events, this) != 0) { /* thread could not be created */ this->logger->log(this->logger, ERROR, "Scheduler thread could not be created!"); diff --git a/src/charon/threads/sender.c b/src/charon/threads/sender.c index 129c4f360..a705950a1 100644 --- a/src/charon/threads/sender.c +++ b/src/charon/threads/sender.c @@ -50,13 +50,6 @@ struct private_sender_t { pthread_t assigned_thread; /** - * @brief The thread function, sends out packets. - * - * @param this calling object - */ - void (*send_packets) (private_sender_t * this); - - /** * A logger for this sender_t object. */ logger_t *logger; @@ -68,7 +61,7 @@ struct private_sender_t { */ static void send_packets(private_sender_t * this) { - packet_t * current_packet; + packet_t *current_packet; status_t status; /* cancellation disabled by default */ @@ -76,11 +69,11 @@ static void send_packets(private_sender_t * this) this->logger->log(this->logger, CONTROL, "sender thread running, thread_ID: %06u", (int)pthread_self()); - while (1) + while (TRUE) { current_packet = charon->send_queue->get(charon->send_queue); this->logger->log(this->logger, CONTROL|LEVEL1, "Got a packet, sending it"); - status = charon->socket->send(charon->socket,current_packet); + status = charon->socket->send(charon->socket, current_packet); if (status != SUCCESS) { this->logger->log(this->logger, ERROR, "Sending failed, socket returned %s", @@ -97,10 +90,10 @@ static void destroy(private_sender_t *this) { this->logger->log(this->logger, CONTROL | LEVEL1, "Going to terminate sender thread"); pthread_cancel(this->assigned_thread); - + pthread_join(this->assigned_thread, NULL); this->logger->log(this->logger, CONTROL | LEVEL1, "Sender thread terminated"); - + free(this); } @@ -111,12 +104,11 @@ sender_t * sender_create() { private_sender_t *this = malloc_thing(private_sender_t); - this->send_packets = send_packets; this->public.destroy = (void(*)(sender_t*)) destroy; this->logger = logger_manager->get_logger(logger_manager, SENDER); - if (pthread_create(&(this->assigned_thread), NULL, (void*(*)(void*))this->send_packets, this) != 0) + if (pthread_create(&(this->assigned_thread), NULL, (void*(*)(void*))send_packets, this) != 0) { this->logger->log(this->logger, ERROR, "Sender thread could not be created"); free(this); diff --git a/src/charon/threads/thread_pool.c b/src/charon/threads/thread_pool.c index b3f302804..3b2938865 100644 --- a/src/charon/threads/thread_pool.c +++ b/src/charon/threads/thread_pool.c @@ -1,8 +1,8 @@ /** * @file thread_pool.c - * + * * @brief Implementation of thread_pool_t. - * + * */ /* @@ -57,12 +57,7 @@ struct private_thread_pool_t { /** * Logger of the thread pool. */ - logger_t *pool_logger; - - /** - * Logger of the worker threads. - */ - logger_t *worker_logger; + logger_t *logger; } ; /** @@ -76,7 +71,9 @@ static void process_jobs(private_thread_pool_t *this) /* cancellation disabled by default */ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); - this->worker_logger->log(this->worker_logger, CONTROL, "worker thread running, thread_ID: %06u", (int)pthread_self()); + this->logger->log(this->logger, CONTROL, + "worker thread running, thread_ID: %06u", + (int)pthread_self()); while (TRUE) { @@ -107,7 +104,8 @@ static void destroy(private_thread_pool_t *this) int current; /* flag thread for termination */ for (current = 0; current < this->pool_size; current++) { - this->pool_logger->log(this->pool_logger, CONTROL, "cancelling worker thread #%d", current+1); + this->logger->log(this->logger, CONTROL, + "cancelling worker thread #%d", current+1); pthread_cancel(this->threads[current]); } @@ -115,11 +113,13 @@ static void destroy(private_thread_pool_t *this) for (current = 0; current < this->pool_size; current++) { if (pthread_join(this->threads[current], NULL) == 0) { - this->pool_logger->log(this->pool_logger, CONTROL, "worker thread #%d terminated", current+1); + this->logger->log(this->logger, CONTROL, + "worker thread #%d terminated", current+1); } else { - this->pool_logger->log(this->pool_logger, ERROR, "could not terminate worker thread #%d", current+1); + this->logger->log(this->logger, ERROR, + "could not terminate worker thread #%d", current+1); } } @@ -143,32 +143,35 @@ thread_pool_t *thread_pool_create(size_t pool_size) /* initialize member */ this->pool_size = pool_size; this->threads = malloc(sizeof(pthread_t) * pool_size); - this->pool_logger = logger_manager->get_logger(logger_manager, THREAD_POOL); - this->worker_logger = logger_manager->get_logger(logger_manager, WORKER); + this->logger = logger_manager->get_logger(logger_manager, THREAD_POOL); /* try to create as many threads as possible, up to pool_size */ for (current = 0; current < pool_size; current++) { - if (pthread_create(&(this->threads[current]), NULL, (void*(*)(void*))process_jobs, this) == 0) + if (pthread_create(&(this->threads[current]), NULL, + (void*(*)(void*))process_jobs, this) == 0) { - this->pool_logger->log(this->pool_logger, CONTROL, "created worker thread #%d", current+1); + this->logger->log(this->logger, CONTROL, + "created worker thread #%d", current+1); } else { /* creation failed, is it the first one? */ if (current == 0) { - this->pool_logger->log(this->pool_logger, ERROR, "Could not create any thread"); + this->logger->log(this->logger, ERROR, "Could not create any thread"); free(this->threads); free(this); return NULL; } /* not all threads could be created, but at least one :-/ */ - this->pool_logger->log(this->pool_logger, ERROR, "Could only create %d from requested %d threads!", current, pool_size); + this->logger->log(this->logger, ERROR, + "Could only create %d from requested %d threads!", + current, pool_size); this->pool_size = current; return (thread_pool_t*)this; } - } + } return (thread_pool_t*)this; } |