From 32b6500fbfe063f3efb5589facd027f4c6cf08ed Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 31 May 2006 14:23:15 +0000 Subject: [PATCH] job management: moved job code from thread_pool to job, jobs have an "execute" method now added two new jobs: delete_child_sa & rekey_child_sa kernel interface: listens now for ACQUIRE & EXPIRE supports hard and soft lifetimes fires jobs for delete and rekey child sa ike sa manager: can checkout IKE SAs by requid of owned CHILD SAs we have now the infrastructure to do the rekeying... :-) --- src/charon/Makefile.am | 2 + src/charon/encoding/message.c | 26 ++ src/charon/queues/event_queue.c | 2 +- src/charon/queues/job_queue.c | 2 +- src/charon/queues/jobs/delete_child_sa_job.c | 104 +++++ src/charon/queues/jobs/delete_child_sa_job.h | 63 +++ .../jobs/delete_established_ike_sa_job.c | 31 +- .../jobs/delete_established_ike_sa_job.h | 17 - .../queues/jobs/delete_half_open_ike_sa_job.c | 58 ++- .../queues/jobs/delete_half_open_ike_sa_job.h | 17 - src/charon/queues/jobs/incoming_packet_job.c | 147 +++++- src/charon/queues/jobs/incoming_packet_job.h | 17 +- src/charon/queues/jobs/initiate_ike_sa_job.c | 64 ++- src/charon/queues/jobs/initiate_ike_sa_job.h | 15 - src/charon/queues/jobs/job.h | 41 +- src/charon/queues/jobs/rekey_child_sa_job.c | 105 +++++ src/charon/queues/jobs/rekey_child_sa_job.h | 63 +++ .../queues/jobs/retransmit_request_job.c | 98 ++-- .../queues/jobs/retransmit_request_job.h | 45 +- src/charon/sa/child_sa.c | 16 +- src/charon/sa/child_sa.h | 11 + src/charon/sa/ike_sa.c | 34 +- src/charon/sa/ike_sa.h | 15 +- src/charon/sa/ike_sa_manager.c | 95 ++-- src/charon/sa/ike_sa_manager.h | 24 +- src/charon/testing/Makefile.am | 1 + src/charon/testing/kernel_interface_test.c | 10 +- src/charon/testing/testcases.c | 2 +- src/charon/threads/kernel_interface.c | 82 +++- src/charon/threads/kernel_interface.h | 32 +- src/charon/threads/thread_pool.c | 430 +----------------- 31 files changed, 930 insertions(+), 739 deletions(-) create mode 100644 src/charon/queues/jobs/delete_child_sa_job.c create mode 100644 src/charon/queues/jobs/delete_child_sa_job.h create mode 100644 src/charon/queues/jobs/rekey_child_sa_job.c create mode 100644 src/charon/queues/jobs/rekey_child_sa_job.h diff --git a/src/charon/Makefile.am b/src/charon/Makefile.am index 99518b0dd..d49bcd32b 100644 --- a/src/charon/Makefile.am +++ b/src/charon/Makefile.am @@ -38,6 +38,8 @@ queues/jobs/delete_established_ike_sa_job.c queues/jobs/retransmit_request_job.h queues/jobs/incoming_packet_job.c queues/jobs/delete_half_open_ike_sa_job.c \ queues/jobs/delete_established_ike_sa_job.h queues/jobs/delete_half_open_ike_sa_job.h \ queues/jobs/incoming_packet_job.h queues/jobs/retransmit_request_job.c queues/jobs/initiate_ike_sa_job.c \ +queues/jobs/rekey_child_sa_job.c queues/jobs/rekey_child_sa_job.h \ +queues/jobs/delete_child_sa_job.c queues/jobs/delete_child_sa_job.h \ queues/job_queue.c queues/event_queue.c queues/send_queue.h queues/job_queue.h queues/event_queue.h \ queues/send_queue.c threads/kernel_interface.c threads/thread_pool.c threads/scheduler.c threads/sender.c \ threads/sender.h threads/kernel_interface.h threads/scheduler.h threads/receiver.c threads/stroke_interface.c \ diff --git a/src/charon/encoding/message.c b/src/charon/encoding/message.c index 24b4d8e69..8a7998e66 100644 --- a/src/charon/encoding/message.c +++ b/src/charon/encoding/message.c @@ -184,6 +184,32 @@ static payload_rule_t informational_r_payload_rules[] = { {DELETE,0,1,TRUE,FALSE}, }; +/** + * Message rule for CREATE_CHILD_SA from initiator. + */ +static payload_rule_t create_child_sa_r_payload_rules[] = { + {NOTIFY,0,MAX_NOTIFY_PAYLOADS,TRUE,FALSE}, + {SECURITY_ASSOCIATION,1,1,TRUE,FALSE}, + {NONCE,1,1,TRUE,FALSE}, + {KEY_EXCHANGE,0,1,TRUE,FALSE}, + {TRAFFIC_SELECTOR_INITIATOR,0,1,TRUE,FALSE}, + {TRAFFIC_SELECTOR_RESPONDER,0,1,TRUE,FALSE}, + {CONFIGURATION,0,1,TRUE,FALSE}, +}; + +/** + * Message rule for CREATE_CHILD_SA from responder. + */ +static payload_rule_t create_child_sa_i_payload_rules[] = { + {NOTIFY,0,MAX_NOTIFY_PAYLOADS,TRUE,FALSE}, + {SECURITY_ASSOCIATION,1,1,TRUE,FALSE}, + {NONCE,1,1,TRUE,FALSE}, + {KEY_EXCHANGE,0,1,TRUE,FALSE}, + {TRAFFIC_SELECTOR_INITIATOR,0,1,TRUE,FALSE}, + {TRAFFIC_SELECTOR_RESPONDER,0,1,TRUE,FALSE}, + {CONFIGURATION,0,1,TRUE,FALSE}, +}; + /** * Message rules, defines allowed payloads. diff --git a/src/charon/queues/event_queue.c b/src/charon/queues/event_queue.c index 39681928c..eb58ca894 100644 --- a/src/charon/queues/event_queue.c +++ b/src/charon/queues/event_queue.c @@ -306,7 +306,7 @@ static void event_queue_destroy(private_event_queue_t *this) this->list->destroy(this->list); break; } - event->job->destroy_all(event->job); + event->job->destroy(event->job); event->destroy(event); } this->list->destroy(this->list); diff --git a/src/charon/queues/job_queue.c b/src/charon/queues/job_queue.c index 12a781c67..91b992bf0 100644 --- a/src/charon/queues/job_queue.c +++ b/src/charon/queues/job_queue.c @@ -121,7 +121,7 @@ static void job_queue_destroy (private_job_queue_t *this) this->list->destroy(this->list); break; } - job->destroy_all(job); + job->destroy(job); } this->list->destroy(this->list); diff --git a/src/charon/queues/jobs/delete_child_sa_job.c b/src/charon/queues/jobs/delete_child_sa_job.c new file mode 100644 index 000000000..ccad9103a --- /dev/null +++ b/src/charon/queues/jobs/delete_child_sa_job.c @@ -0,0 +1,104 @@ +/** + * @file delete_child_sa_job.c + * + * @brief Implementation of delete_child_sa_job_t. + * + */ + +/* + * Copyright (C) 2006 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "delete_child_sa_job.h" + +#include + + +typedef struct private_delete_child_sa_job_t private_delete_child_sa_job_t; + +/** + * Private data of an delete_child_sa_job_t object. + */ +struct private_delete_child_sa_job_t { + /** + * Public delete_child_sa_job_t interface. + */ + delete_child_sa_job_t public; + + /** + * reqid of the sa to delete. + */ + u_int32_t reqid; + + /** + * Logger ref + */ + logger_t *logger; +}; + +/** + * Implementation of job_t.get_type. + */ +static job_type_t get_type(private_delete_child_sa_job_t *this) +{ + return DELETE_CHILD_SA; +} + +/** + * Implementation of job_t.execute. + */ +static status_t execute(private_delete_child_sa_job_t *this) +{ + ike_sa_t *ike_sa; + status_t status; + + status = charon->ike_sa_manager->checkout_by_reqid(charon->ike_sa_manager, this->reqid, &ike_sa); + if (status != SUCCESS) + { + this->logger->log(this->logger, CONTROL, "CHILD SA didn't exist anymore"); + return DESTROY_ME; + } + + /* TODO */ + + status = charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); + return DESTROY_ME; +} + +/** + * Implementation of job_t.destroy. + */ +static void destroy(private_delete_child_sa_job_t *this) +{ + free(this); +} + +/* + * Described in header + */ +delete_child_sa_job_t *delete_child_sa_job_create(u_int32_t reqid) +{ + private_delete_child_sa_job_t *this = malloc_thing(private_delete_child_sa_job_t); + + /* interface functions */ + this->public.job_interface.get_type = (job_type_t (*) (job_t *)) get_type; + this->public.job_interface.execute = (status_t (*) (job_t *)) execute; + this->public.job_interface.destroy = (void (*)(job_t*)) destroy; + + /* private variables */ + this->reqid = reqid; + this->logger = logger_manager->get_logger(logger_manager, WORKER); + + return &(this->public); +} diff --git a/src/charon/queues/jobs/delete_child_sa_job.h b/src/charon/queues/jobs/delete_child_sa_job.h new file mode 100644 index 000000000..29802403e --- /dev/null +++ b/src/charon/queues/jobs/delete_child_sa_job.h @@ -0,0 +1,63 @@ +/** + * @file delete_child_sa_job.h + * + * @brief Interface of delete_child_sa_job_t. + * + */ + +/* + * Copyright (C) 2006 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#ifndef DELETE_CHILD_SA_JOB_H_ +#define DELETE_CHILD_SA_JOB_H_ + +#include +#include +#include + + +typedef struct delete_child_sa_job_t delete_child_sa_job_t; + +/** + * @brief Class representing an DELETE_CHILD_SA Job. + * + * This job initiates the deletion of an CHILD_SA. The SA + * to delete is specified via the unique reqid used in kernel. + * + * @b Constructors: + * - delete_child_sa_job_create() + * + * @ingroup jobs + */ +struct delete_child_sa_job_t { + /** + * The job_t interface. + */ + job_t job_interface; +}; + +/** + * @brief Creates a job of type DELETE_CHILD_SA. + * + * To find the targeted CHILD_SA, the uniqe reqid used in + * the kernel is used. + * + * @param reqid reqid CHILD_SA to rekey + * + * @ingroup jobs + */ +delete_child_sa_job_t *delete_child_sa_job_create(u_int32_t reqid); + +#endif /* DELETE_CHILD_SA_JOB_H_ */ diff --git a/src/charon/queues/jobs/delete_established_ike_sa_job.c b/src/charon/queues/jobs/delete_established_ike_sa_job.c index 7251e2ca4..78f5c9ed1 100644 --- a/src/charon/queues/jobs/delete_established_ike_sa_job.c +++ b/src/charon/queues/jobs/delete_established_ike_sa_job.c @@ -22,6 +22,7 @@ #include "delete_established_ike_sa_job.h" +#include typedef struct private_delete_established_ike_sa_job_t private_delete_established_ike_sa_job_t; @@ -39,6 +40,11 @@ struct private_delete_established_ike_sa_job_t { * ID of the ike_sa to delete. */ ike_sa_id_t *ike_sa_id; + + /** + * Logger ref + */ + logger_t *logger; }; /** @@ -49,12 +55,21 @@ static job_type_t get_type(private_delete_established_ike_sa_job_t *this) return DELETE_ESTABLISHED_IKE_SA; } + /** - * Implementation of delete_established_ike_sa_job_t.get_ike_sa_id + * Implementation of job_t.execute. */ -static ike_sa_id_t *get_ike_sa_id(private_delete_established_ike_sa_job_t *this) +static status_t execute(private_delete_established_ike_sa_job_t *this) { - return this->ike_sa_id; + ike_sa_t *ike_sa; + status_t status; + + status = charon->ike_sa_manager->delete(charon->ike_sa_manager, this->ike_sa_id); + if (status != SUCCESS) + { + this->logger->log(this->logger, CONTROL, "IKE SA didn't exist anymore"); + } + return DESTROY_ME; } /** @@ -75,16 +90,12 @@ delete_established_ike_sa_job_t *delete_established_ike_sa_job_create(ike_sa_id_ /* interface functions */ this->public.job_interface.get_type = (job_type_t (*) (job_t *)) get_type; - /* same as destroy */ - this->public.job_interface.destroy_all = (void (*) (job_t *)) destroy; + this->public.job_interface.execute = (status_t (*) (job_t *)) execute; this->public.job_interface.destroy = (void (*)(job_t*)) destroy; - - /* public functions */ - this->public.get_ike_sa_id = (ike_sa_id_t * (*)(delete_established_ike_sa_job_t *)) get_ike_sa_id; - this->public.destroy = (void (*)(delete_established_ike_sa_job_t *)) destroy; - + /* private variables */ this->ike_sa_id = ike_sa_id->clone(ike_sa_id); + this->logger = logger_manager->get_logger(logger_manager, WORKER); return &(this->public); } diff --git a/src/charon/queues/jobs/delete_established_ike_sa_job.h b/src/charon/queues/jobs/delete_established_ike_sa_job.h index 762dceae6..030e1aefe 100644 --- a/src/charon/queues/jobs/delete_established_ike_sa_job.h +++ b/src/charon/queues/jobs/delete_established_ike_sa_job.h @@ -46,23 +46,6 @@ struct delete_established_ike_sa_job_t { * The job_t interface. */ job_t job_interface; - - /** - * @brief Returns the currently set ike_sa_id. - * - * @warning Returned object is not copied. - * - * @param this calling delete_established_ike_sa_job_t object - * @return ike_sa_id_t object - */ - ike_sa_id_t * (*get_ike_sa_id) (delete_established_ike_sa_job_t *this); - - /** - * @brief Destroys an delete_established_ike_sa_job_t object (including assigned data). - * - * @param this delete_established_ike_sa_job_t object to destroy - */ - void (*destroy) (delete_established_ike_sa_job_t *this); }; /** diff --git a/src/charon/queues/jobs/delete_half_open_ike_sa_job.c b/src/charon/queues/jobs/delete_half_open_ike_sa_job.c index 610285e20..5de3cb222 100644 --- a/src/charon/queues/jobs/delete_half_open_ike_sa_job.c +++ b/src/charon/queues/jobs/delete_half_open_ike_sa_job.c @@ -22,7 +22,7 @@ #include "delete_half_open_ike_sa_job.h" - +#include typedef struct private_delete_half_open_ike_sa_job_t private_delete_half_open_ike_sa_job_t; @@ -39,6 +39,11 @@ struct private_delete_half_open_ike_sa_job_t { * ID of the ike_sa to delete */ ike_sa_id_t *ike_sa_id; + + /** + * logger ref + */ + logger_t *logger; }; /** @@ -50,11 +55,48 @@ static job_type_t get_type(private_delete_half_open_ike_sa_job_t *this) } /** - * Implements elete_ike_sa_job_t.get_ike_sa_id + * Implementation of job_t.execute. */ -static ike_sa_id_t *get_ike_sa_id(private_delete_half_open_ike_sa_job_t *this) +static status_t execute(private_delete_half_open_ike_sa_job_t *this) { - return this->ike_sa_id; + ike_sa_t *ike_sa; + status_t status; + + status = charon->ike_sa_manager->checkout(charon->ike_sa_manager, this->ike_sa_id, &ike_sa); + if ((status != SUCCESS) && (status != CREATED)) + { + this->logger->log(this->logger, CONTROL | LEVEL3, "IKE SA seems to be already deleted"); + return DESTROY_ME; + } + + switch (ike_sa->get_state(ike_sa)) + { + case INITIATOR_INIT: + case RESPONDER_INIT: + case IKE_SA_INIT_REQUESTED: + case IKE_SA_INIT_RESPONDED: + case IKE_AUTH_REQUESTED: + case DELETE_REQUESTED: + { + /* IKE_SA is half open and gets deleted! */ + status = charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa); + if (status != SUCCESS) + { + this->logger->log(this->logger, ERROR, "Could not checkin and delete checked out IKE_SA!"); + } + return DESTROY_ME; + } + default: + { + /* IKE_SA is established and so is not getting deleted! */ + status = charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); + if (status != SUCCESS) + { + this->logger->log(this->logger, ERROR, "Could not checkin a checked out IKE_SA!"); + } + return DESTROY_ME; + } + } } /** @@ -75,16 +117,12 @@ delete_half_open_ike_sa_job_t *delete_half_open_ike_sa_job_create(ike_sa_id_t *i /* interface functions */ this->public.job_interface.get_type = (job_type_t (*) (job_t *)) get_type; - /* same as destroy */ - this->public.job_interface.destroy_all = (void (*) (job_t *)) destroy; + this->public.job_interface.execute = (status_t (*) (job_t *)) execute; this->public.job_interface.destroy = (void (*)(job_t *)) destroy;; - /* public functions */ - this->public.get_ike_sa_id = (ike_sa_id_t * (*)(delete_half_open_ike_sa_job_t *)) get_ike_sa_id; - this->public.destroy = (void (*)(delete_half_open_ike_sa_job_t *)) destroy; - /* private variables */ this->ike_sa_id = ike_sa_id->clone(ike_sa_id); + this->logger = logger_manager->get_logger(logger_manager, WORKER); return &(this->public); } diff --git a/src/charon/queues/jobs/delete_half_open_ike_sa_job.h b/src/charon/queues/jobs/delete_half_open_ike_sa_job.h index ea42be8f2..b26750cc1 100644 --- a/src/charon/queues/jobs/delete_half_open_ike_sa_job.h +++ b/src/charon/queues/jobs/delete_half_open_ike_sa_job.h @@ -47,23 +47,6 @@ struct delete_half_open_ike_sa_job_t { * The job_t interface. */ job_t job_interface; - - /** - * @brief Returns the currently set ike_sa_id. - * - * @warning Returned object is not copied. - * - * @param this calling delete_half_open_ike_sa_job_t object - * @return ike_sa_id_t object - */ - ike_sa_id_t * (*get_ike_sa_id) (delete_half_open_ike_sa_job_t *this); - - /** - * @brief Destroys an delete_half_open_ike_sa_job_t object (including assigned data). - * - * @param this delete_half_open_ike_sa_job_t object to destroy - */ - void (*destroy) (delete_half_open_ike_sa_job_t *this); }; /** diff --git a/src/charon/queues/jobs/incoming_packet_job.c b/src/charon/queues/jobs/incoming_packet_job.c index fc71f63ea..834b14bb2 100644 --- a/src/charon/queues/jobs/incoming_packet_job.c +++ b/src/charon/queues/jobs/incoming_packet_job.c @@ -23,7 +23,7 @@ #include "incoming_packet_job.h" - +#include typedef struct private_incoming_packet_job_t private_incoming_packet_job_t; @@ -40,6 +40,11 @@ struct private_incoming_packet_job_t { * Assigned packet */ packet_t *packet; + + /** + * logger + */ + logger_t *logger; }; /** @@ -50,32 +55,133 @@ static job_type_t get_type(private_incoming_packet_job_t *this) return INCOMING_PACKET; } +/** + * Implementation of job_t.execute. + */ +static status_t execute(private_incoming_packet_job_t *this) +{ + message_t *message; + ike_sa_t *ike_sa; + ike_sa_id_t *ike_sa_id; + status_t status; + packet_t *packet; + + message = message_create_from_packet(this->packet->clone(this->packet)); + status = message->parse_header(message); + if (status != SUCCESS) + { + this->logger->log(this->logger, ERROR, "Message header could not be verified!"); + message->destroy(message); + return DESTROY_ME; + } + + this->logger->log(this->logger, CONTROL|LEVEL2, "Message is a %s %s", + mapping_find(exchange_type_m, message->get_exchange_type(message)), + message->get_request(message) ? "request" : "reply"); + + if ((message->get_major_version(message) != IKE_MAJOR_VERSION) || + (message->get_minor_version(message) != IKE_MINOR_VERSION)) + { + this->logger->log(this->logger, ERROR | LEVEL2, + "IKE version %d.%d not supported", + message->get_major_version(message), + message->get_minor_version(message)); + if ((message->get_exchange_type(message) == IKE_SA_INIT) && (message->get_request(message))) + { + message_t *response; + message->get_ike_sa_id(message, &ike_sa_id); + ike_sa_id->switch_initiator(ike_sa_id); + response = message_create_notify_reply(message->get_destination(message), + message->get_source(message), + IKE_SA_INIT, FALSE, ike_sa_id, + INVALID_MAJOR_VERSION); + message->destroy(message); + ike_sa_id->destroy(ike_sa_id); + status = response->generate(response, NULL, NULL, &packet); + if (status != SUCCESS) + { + this->logger->log(this->logger, ERROR, "Could not generate packet from message"); + response->destroy(response); + return DESTROY_ME; + } + this->logger->log(this->logger, ERROR, "Send notify reply of type INVALID_MAJOR_VERSION"); + charon->send_queue->add(charon->send_queue, packet); + response->destroy(response); + return DESTROY_ME; + } + message->destroy(message); + return DESTROY_ME; + } + + message->get_ike_sa_id(message, &ike_sa_id); + ike_sa_id->switch_initiator(ike_sa_id); + this->logger->log(this->logger, CONTROL|LEVEL3, "Checking out IKE SA %lld:%lld, role %s", + ike_sa_id->get_initiator_spi(ike_sa_id), + ike_sa_id->get_responder_spi(ike_sa_id), + ike_sa_id->is_initiator(ike_sa_id) ? "initiator" : "responder"); + + status = charon->ike_sa_manager->checkout(charon->ike_sa_manager, ike_sa_id, &ike_sa); + if ((status != SUCCESS) && (status != CREATED)) + { + this->logger->log(this->logger, ERROR, "IKE SA could not be checked out"); + ike_sa_id->destroy(ike_sa_id); + message->destroy(message); + + /* TODO: send notify reply of type INVALID_IKE_SPI if SPI could not be found ? */ + return DESTROY_ME; + } + + if (status == CREATED) + { + job_t *delete_job; + this->logger->log(this->logger, CONTROL|LEVEL3, + "Create Job to delete half open IKE_SA."); + + delete_job = (job_t *) delete_half_open_ike_sa_job_create(ike_sa_id); + charon->event_queue->add_relative(charon->event_queue, delete_job, + charon->configuration->get_half_open_ike_sa_timeout(charon->configuration)); + } + + status = ike_sa->process_message(ike_sa, message); + + this->logger->log(this->logger, CONTROL|LEVEL3, "%s IKE SA %lld:%lld, role %s", + status == DESTROY_ME ? "Checkin and delete" : "Checkin", + ike_sa_id->get_initiator_spi(ike_sa_id), + ike_sa_id->get_responder_spi(ike_sa_id), + ike_sa_id->is_initiator(ike_sa_id) ? "initiator" : "responder"); + ike_sa_id->destroy(ike_sa_id); + + if (status == DESTROY_ME) + { + status = charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa); + } + else + { + status = charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); + } + + if (status != SUCCESS) + { + this->logger->log(this->logger, ERROR, "Checkin of IKE SA failed!"); + } + message->destroy(message); + return DESTROY_ME; +} + /** * Implements incoming_packet_job_t.get_packet. */ -static packet_t *get_packet(private_incoming_packet_job_t *this) +static packet_t* get_packet(private_incoming_packet_job_t *this) { return this->packet; } -/** - * Implements job_t.destroy_all. - */ -static void destroy_all(private_incoming_packet_job_t *this) -{ - if (this->packet != NULL) - { - this->packet->destroy(this->packet); - } - free(this); -} - /** * Implements job_t.destroy. */ -static void destroy(job_t *job) +static void destroy(private_incoming_packet_job_t *this) { - private_incoming_packet_job_t *this = (private_incoming_packet_job_t *) job; + this->packet->destroy(this->packet); free(this); } @@ -88,15 +194,14 @@ incoming_packet_job_t *incoming_packet_job_create(packet_t *packet) /* interface functions */ this->public.job_interface.get_type = (job_type_t (*) (job_t *)) get_type; - this->public.job_interface.destroy_all = (void (*) (job_t *)) destroy_all; - this->public.job_interface.destroy = destroy; + this->public.job_interface.execute = (status_t (*) (job_t *)) execute; + this->public.job_interface.destroy = (void(*)(job_t*))destroy; - /* public functions */ - this->public.get_packet = (packet_t * (*)(incoming_packet_job_t *)) get_packet; - this->public.destroy = (void (*)(incoming_packet_job_t *)) destroy; + this->public.get_packet = (packet_t*(*)(incoming_packet_job_t*)) get_packet; /* private variables */ this->packet = packet; + this->logger = logger_manager->get_logger(logger_manager, WORKER); return &(this->public); } diff --git a/src/charon/queues/jobs/incoming_packet_job.h b/src/charon/queues/jobs/incoming_packet_job.h index e3fb5797e..93d8febc9 100644 --- a/src/charon/queues/jobs/incoming_packet_job.h +++ b/src/charon/queues/jobs/incoming_packet_job.h @@ -48,21 +48,12 @@ struct incoming_packet_job_t { job_t job_interface; /** - * @brief Returns the assigned packet_t object - * - * @warning Returned packet is not cloned and has to get destroyed by the caller. + * @brief Get associated packet. * - * @param this calling incoming_packet_job_t object - * @return assigned packet + * @param this calling object + * @return associated packet */ - packet_t *(*get_packet) (incoming_packet_job_t *this); - - /** - * @brief Destroys an incoming_packet_job_t object. - * - * @param this incoming_packet_job_t object to destroy - */ - void (*destroy) (incoming_packet_job_t *this); + packet_t *(*get_packet)(incoming_packet_job_t *this); }; /** diff --git a/src/charon/queues/jobs/initiate_ike_sa_job.c b/src/charon/queues/jobs/initiate_ike_sa_job.c index ac9ace36c..fa8513659 100644 --- a/src/charon/queues/jobs/initiate_ike_sa_job.c +++ b/src/charon/queues/jobs/initiate_ike_sa_job.c @@ -25,7 +25,7 @@ #include "initiate_ike_sa_job.h" - +#include typedef struct private_initiate_ike_sa_job_t private_initiate_ike_sa_job_t; @@ -42,9 +42,13 @@ struct private_initiate_ike_sa_job_t { * associated connection object to initiate */ connection_t *connection; + + /** + * logger + */ + logger_t *logger; }; - /** * Implements initiate_ike_sa_job_t.get_type. */ @@ -54,20 +58,46 @@ static job_type_t get_type(private_initiate_ike_sa_job_t *this) } /** - * Implements initiate_ike_sa_job_t.get_configuration_name. + * Implementation of job_t.execute. */ -static connection_t *get_connection(private_initiate_ike_sa_job_t *this) +static status_t execute(private_initiate_ike_sa_job_t *this) { - return this->connection; -} + /* + * Initiatie an IKE_SA: + * - is defined by a name of a configuration + * - create an empty IKE_SA via manager + * - call initiate_connection on this sa + */ + ike_sa_t *ike_sa; + status_t status; + job_t *delete_job; + + this->logger->log(this->logger, CONTROL|LEVEL2, "Creating and checking out IKE SA"); + charon->ike_sa_manager->create_and_checkout(charon->ike_sa_manager, &ike_sa); + + status = ike_sa->initiate_connection(ike_sa, this->connection->clone(this->connection)); + if (status != SUCCESS) + { + this->logger->log(this->logger, ERROR, "Initiation returned %s, going to delete IKE_SA.", + mapping_find(status_m, status)); + charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa); + return DESTROY_ME; + } + + this->logger->log(this->logger, CONTROL|LEVEL3, "Create Job to delete half open IKE_SA."); + + delete_job = (job_t *) delete_half_open_ike_sa_job_create(ike_sa->get_id(ike_sa)); + charon->event_queue->add_relative(charon->event_queue, delete_job, + charon->configuration->get_half_open_ike_sa_timeout(charon->configuration)); -/** - * Implements job_t.destroy. - */ -static void destroy_all(private_initiate_ike_sa_job_t *this) -{ - this->connection->destroy(this->connection); - free(this); + this->logger->log(this->logger, CONTROL|LEVEL2, "Checking in IKE SA"); + status = charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); + if (status != SUCCESS) + { + this->logger->log(this->logger, ERROR, "Could not checkin IKE_SA (%s)", + mapping_find(status_m, status)); + } + return DESTROY_ME; } /** @@ -75,6 +105,7 @@ static void destroy_all(private_initiate_ike_sa_job_t *this) */ static void destroy(private_initiate_ike_sa_job_t *this) { + this->connection->destroy(this->connection); free(this); } @@ -87,15 +118,12 @@ initiate_ike_sa_job_t *initiate_ike_sa_job_create(connection_t *connection) /* interface functions */ this->public.job_interface.get_type = (job_type_t (*) (job_t *)) get_type; - this->public.job_interface.destroy_all = (void (*) (job_t *)) destroy_all; + this->public.job_interface.execute = (status_t (*) (job_t *)) execute; this->public.job_interface.destroy = (void (*) (job_t *)) destroy; - /* public functions */ - this->public.get_connection = (connection_t* (*)(initiate_ike_sa_job_t *)) get_connection; - this->public.destroy = (void (*)(initiate_ike_sa_job_t *)) destroy; - /* private variables */ this->connection = connection; + this->logger = logger_manager->get_logger(logger_manager, WORKER); return &(this->public); } diff --git a/src/charon/queues/jobs/initiate_ike_sa_job.h b/src/charon/queues/jobs/initiate_ike_sa_job.h index cee31f07b..24f4a89a7 100644 --- a/src/charon/queues/jobs/initiate_ike_sa_job.h +++ b/src/charon/queues/jobs/initiate_ike_sa_job.h @@ -45,21 +45,6 @@ struct initiate_ike_sa_job_t { * implements job_t interface */ job_t job_interface; - - /** - * @brief Returns the connection_t to initialize - * - * @param this calling initiate_ike_sa_job_t object - * @return connection_t - */ - connection_t *(*get_connection) (initiate_ike_sa_job_t *this); - - /** - * @brief Destroys an initiate_ike_sa_job_t object. - * - * @param this initiate_ike_sa_job_t object to destroy - */ - void (*destroy) (initiate_ike_sa_job_t *this); }; /** diff --git a/src/charon/queues/jobs/job.h b/src/charon/queues/jobs/job.h index eea4da09e..d7531531d 100644 --- a/src/charon/queues/jobs/job.h +++ b/src/charon/queues/jobs/job.h @@ -32,43 +32,57 @@ typedef enum job_type_t job_type_t; /** * @brief Definition of the various job types. * - * @todo add more jobs, such as rekeying. - * * @ingroup jobs */ enum job_type_t { /** * Process an incoming IKEv2-Message. * - * Job is implemented in class type incoming_packet_job_t + * Job is implemented in class incoming_packet_job_t */ INCOMING_PACKET, /** * Retransmit an IKEv2-Message. + * + * Job is implemented in class retransmit_request_job_t */ RETRANSMIT_REQUEST, /** * Establish an ike sa as initiator. * - * Job is implemented in class type initiate_ike_sa_job_t + * Job is implemented in class initiate_ike_sa_job_t */ INITIATE_IKE_SA, /** * Delete an ike sa which is still not established. * - * Job is implemented in class type delete_half_open_ike_sa_job_t + * Job is implemented in class delete_half_open_ike_sa_job_t */ DELETE_HALF_OPEN_IKE_SA, /** * Delete an ike sa which is established. * - * Job is implemented in class type delete_established_ike_sa_job_t + * Job is implemented in class delete_established_ike_sa_job_t */ - DELETE_ESTABLISHED_IKE_SA + DELETE_ESTABLISHED_IKE_SA, + + /** + * Delete a child sa. + * + * Job is implemented in class delete_child_sa_job_t + */ + DELETE_CHILD_SA, + + /** + * Rekey a child sa. + * + * Job is implemented in class rekey_child_sa_job_t + */ + REKEY_CHILD_SA, }; /** @@ -102,11 +116,16 @@ struct job_t { job_type_t (*get_type) (job_t *this); /** - * @brief Destroys a job_t object and all assigned data! + * @brief Execute a job. * - * @param job_t calling object + * Call the internall job routine to process the + * job. If this method returns DESTROY_ME, the job + * must be destroyed by the caller. + * + * @param this calling object + * @return status of job execution */ - void (*destroy_all) (job_t *job); + status_t (*execute) (job_t *this); /** * @brief Destroys a job_t object @@ -117,4 +136,4 @@ struct job_t { }; -#endif /*JOB_H_*/ +#endif /* JOB_H_ */ diff --git a/src/charon/queues/jobs/rekey_child_sa_job.c b/src/charon/queues/jobs/rekey_child_sa_job.c new file mode 100644 index 000000000..69b1342a5 --- /dev/null +++ b/src/charon/queues/jobs/rekey_child_sa_job.c @@ -0,0 +1,105 @@ +/** + * @file rekey_child_sa_job.c + * + * @brief Implementation of rekey_child_sa_job_t. + * + */ + +/* + * Copyright (C) 2006 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "rekey_child_sa_job.h" + +#include + + +typedef struct private_rekey_child_sa_job_t private_rekey_child_sa_job_t; + +/** + * Private data of an rekey_child_sa_job_t object. + */ +struct private_rekey_child_sa_job_t { + /** + * Public rekey_child_sa_job_t interface. + */ + rekey_child_sa_job_t public; + + /** + * reqid of the child sa, as used in the kernel + */ + u_int32_t reqid; + + /** + * Logger ref + */ + logger_t *logger; +}; + +/** + * Implementation of job_t.get_type. + */ +static job_type_t get_type(private_rekey_child_sa_job_t *this) +{ + return REKEY_CHILD_SA; +} + + +/** + * Implementation of job_t.execute. + */ +static status_t execute(private_rekey_child_sa_job_t *this) +{ + ike_sa_t *ike_sa; + status_t status; + + status = charon->ike_sa_manager->checkout_by_reqid(charon->ike_sa_manager, this->reqid, &ike_sa); + if (status != SUCCESS) + { + this->logger->log(this->logger, CONTROL, "CHILD SA didn't exist anymore"); + return DESTROY_ME; + } + + /* TODO */ + + status = charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); + return DESTROY_ME; +} + +/** + * Implementation of job_t.destroy. + */ +static void destroy(private_rekey_child_sa_job_t *this) +{ + free(this); +} + +/* + * Described in header + */ +rekey_child_sa_job_t *rekey_child_sa_job_create(u_int32_t reqid) +{ + private_rekey_child_sa_job_t *this = malloc_thing(private_rekey_child_sa_job_t); + + /* interface functions */ + this->public.job_interface.get_type = (job_type_t (*) (job_t *)) get_type; + this->public.job_interface.execute = (status_t (*) (job_t *)) execute; + this->public.job_interface.destroy = (void (*)(job_t*)) destroy; + + /* private variables */ + this->reqid = reqid; + this->logger = logger_manager->get_logger(logger_manager, WORKER); + + return &(this->public); +} diff --git a/src/charon/queues/jobs/rekey_child_sa_job.h b/src/charon/queues/jobs/rekey_child_sa_job.h new file mode 100644 index 000000000..2492b2b46 --- /dev/null +++ b/src/charon/queues/jobs/rekey_child_sa_job.h @@ -0,0 +1,63 @@ +/** + * @file rekey_child_sa_job.h + * + * @brief Interface of rekey_child_sa_job_t. + * + */ + +/* + * Copyright (C) 2006 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#ifndef REKEY_CHILD_SA_JOB_H_ +#define REKEY_CHILD_SA_JOB_H_ + +#include +#include +#include + + +typedef struct rekey_child_sa_job_t rekey_child_sa_job_t; + +/** + * @brief Class representing an REKEY_CHILD_SA Job. + * + * This job initiates the rekeying of a CHILD SA. + * + * @b Constructors: + * - rekey_child_sa_job_create() + * + * @ingroup jobs + */ +struct rekey_child_sa_job_t { + /** + * The job_t interface. + */ + job_t job_interface; +}; + +/** + * @brief Creates a job of type REKEY_CHILD_SA. + * + * To find the targeted CHILD_SA, the uniqe reqid used in + * the kernel is used. + * + * @param reqid reqid CHILD_SA to rekey + * @return rekey_child_sa_job_t object + * + * @ingroup jobs + */ +rekey_child_sa_job_t *rekey_child_sa_job_create(u_int32_t reqid); + +#endif /* REKEY_CHILD_SA_JOB_H_ */ diff --git a/src/charon/queues/jobs/retransmit_request_job.c b/src/charon/queues/jobs/retransmit_request_job.c index e171df5bd..f89d2adaf 100644 --- a/src/charon/queues/jobs/retransmit_request_job.c +++ b/src/charon/queues/jobs/retransmit_request_job.c @@ -22,8 +22,7 @@ #include "retransmit_request_job.h" - - +#include typedef struct private_retransmit_request_job_t private_retransmit_request_job_t; @@ -50,9 +49,13 @@ struct private_retransmit_request_job_t { * Number of times a request was retransmitted */ u_int32_t retransmit_count; + + /** + * Logger reference + */ + logger_t *logger; }; - /** * Implements job_t.get_type. */ @@ -62,38 +65,64 @@ static job_type_t get_type(private_retransmit_request_job_t *this) } /** - * Implements retransmit_request_job_t.get_ike_sa_id. + * Implementation of job_t.execute. */ -static ike_sa_id_t *get_ike_sa_id(private_retransmit_request_job_t *this) +static status_t execute(private_retransmit_request_job_t *this) { - return this->ike_sa_id; -} + bool stop_retransmitting = FALSE; + u_int32_t timeout; + ike_sa_t *ike_sa; + status_t status; + + this->logger->log(this->logger, CONTROL|LEVEL2, "Checking out IKE SA %lld:%lld, role %s", + this->ike_sa_id->get_initiator_spi(this->ike_sa_id), + this->ike_sa_id->get_responder_spi(this->ike_sa_id), + this->ike_sa_id->is_initiator(this->ike_sa_id) ? "initiator" : "responder"); + + status = charon->ike_sa_manager->checkout(charon->ike_sa_manager, this->ike_sa_id, &ike_sa); + if ((status != SUCCESS) && (status != CREATED)) + { + this->logger->log(this->logger, ERROR|LEVEL1, + "IKE SA could not be checked out. Already deleted?"); + return DESTROY_ME; + } + + status = ike_sa->retransmit_request(ike_sa, this->message_id); + if (status != SUCCESS) + { + this->logger->log(this->logger, CONTROL|LEVEL3, + "Message doesn't have to be retransmitted"); + stop_retransmitting = TRUE; + } + + this->logger->log(this->logger, CONTROL|LEVEL2, "Checkin IKE SA %lld:%lld, role %s", + this->ike_sa_id->get_initiator_spi(this->ike_sa_id), + this->ike_sa_id->get_responder_spi(this->ike_sa_id), + this->ike_sa_id->is_initiator(this->ike_sa_id) ? "initiator" : "responder"); -/** - * Implements retransmit_request_job_t.get_retransmit_count. - */ -static u_int32_t get_retransmit_count(private_retransmit_request_job_t *this) -{ - return this->retransmit_count; -} + status = charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); + if (status != SUCCESS) + { + this->logger->log(this->logger, ERROR, "Checkin of IKE SA failed!"); + } -/** - * Implements retransmit_request_job_t.increase_retransmit_count. - */ -static void increase_retransmit_count(private_retransmit_request_job_t *this) -{ + if (stop_retransmitting) + { + return DESTROY_ME; + } + this->retransmit_count++; + status = charon->configuration->get_retransmit_timeout(charon->configuration, + this->retransmit_count, &timeout); + if (status != SUCCESS) + { + this->logger->log(this->logger, CONTROL|LEVEL2, "Message will not be retransmitted anymore"); + return DESTROY_ME; + } + charon->event_queue->add_relative(charon->event_queue, (job_t *)this, timeout); + return SUCCESS; } -/** - * Implements retransmit_request_job_t.get_message_id. - */ -static u_int32_t get_message_id(private_retransmit_request_job_t *this) -{ - return this->message_id; -} - - /** * Implements job_t.destroy. */ @@ -112,21 +141,14 @@ retransmit_request_job_t *retransmit_request_job_create(u_int32_t message_id,ike /* interface functions */ this->public.job_interface.get_type = (job_type_t (*) (job_t *)) get_type; - /* same as destroy */ - this->public.job_interface.destroy_all = (void (*) (job_t *)) destroy; + this->public.job_interface.execute = (status_t (*) (job_t *)) execute; this->public.job_interface.destroy = (void (*) (job_t *)) destroy; - - /* public functions */ - this->public.get_ike_sa_id = (ike_sa_id_t * (*)(retransmit_request_job_t *)) get_ike_sa_id; - this->public.get_message_id = (u_int32_t (*)(retransmit_request_job_t *)) get_message_id; - this->public.destroy = (void (*)(retransmit_request_job_t *)) destroy; - this->public.get_retransmit_count = (u_int32_t (*)(retransmit_request_job_t *)) get_retransmit_count; - this->public.increase_retransmit_count = (void (*)(retransmit_request_job_t *)) increase_retransmit_count; - + /* private variables */ this->message_id = message_id; this->retransmit_count = 0; this->ike_sa_id = ike_sa_id->clone(ike_sa_id); + this->logger = logger_manager->get_logger(logger_manager, WORKER); return &(this->public); } diff --git a/src/charon/queues/jobs/retransmit_request_job.h b/src/charon/queues/jobs/retransmit_request_job.h index 2349d3f5e..c34484b99 100644 --- a/src/charon/queues/jobs/retransmit_request_job.h +++ b/src/charon/queues/jobs/retransmit_request_job.h @@ -47,48 +47,6 @@ struct retransmit_request_job_t { * The job_t interface. */ job_t job_interface; - - /** - * @brief Returns the retransmit count for a specific request. - * - * @param this calling retransmit_request_job_t object - * @return retransmit count of request - */ - u_int32_t (*get_retransmit_count) (retransmit_request_job_t *this); - - /** - * @brief Increases number of retransmitt attemps. - * - * @param this calling retransmit_request_job_t object - */ - void (*increase_retransmit_count) (retransmit_request_job_t *this); - - /** - * @brief Returns the message_id of the request to be resent - * - * @param this calling retransmit_request_job_t object - * @return message id of the request to resend - */ - u_int32_t (*get_message_id) (retransmit_request_job_t *this); - - /** - * @brief Returns the ike_sa_id_t object of the IKE_SA - * which the request belongs to - * - * @warning returned ike_sa_id_t object is getting destroyed in - * retransmit_request_job_t.destroy. - * - * @param this calling retransmit_request_job_t object - * @return ike_sa_id_t object to identify IKE_SA (gets NOT cloned) - */ - ike_sa_id_t *(*get_ike_sa_id) (retransmit_request_job_t *this); - - /** - * @brief Destroys an retransmit_request_job_t object. - * - * @param this retransmit_request_job_t object to destroy - */ - void (*destroy) (retransmit_request_job_t *this); }; /** @@ -100,6 +58,7 @@ struct retransmit_request_job_t { * * @ingroup jobs */ -retransmit_request_job_t *retransmit_request_job_create(u_int32_t message_id,ike_sa_id_t *ike_sa_id); +retransmit_request_job_t *retransmit_request_job_create(u_int32_t message_id, + ike_sa_id_t *ike_sa_id); #endif /* RESEND_MESSAGE_JOB_H_ */ diff --git a/src/charon/sa/child_sa.c b/src/charon/sa/child_sa.c index 5bb895e7f..b79d07028 100644 --- a/src/charon/sa/child_sa.c +++ b/src/charon/sa/child_sa.c @@ -119,6 +119,14 @@ struct private_child_sa_t { logger_t *logger; }; +/** + * Implements child_sa_t.get_reqid + */ +static u_int32_t get_reqid(private_child_sa_t *this) +{ + return this->reqid; +} + /** * Implements child_sa_t.alloc */ @@ -300,6 +308,7 @@ static status_t install(private_child_sa_t *this, proposal_t *proposal, prf_plus src, dst, spi, protocols[i], this->reqid, + 5, 30, enc_algo, enc_key, int_algo, int_key, mine); /* clean up for next round */ @@ -316,8 +325,6 @@ static status_t install(private_child_sa_t *this, proposal_t *proposal, prf_plus { return FAILED; } - - } } return SUCCESS; @@ -564,10 +571,11 @@ static void destroy(private_child_sa_t *this) */ child_sa_t * child_sa_create(host_t *me, host_t* other) { - static u_int32_t reqid = 0xc0000000; + static u_int32_t reqid = 2000000000; private_child_sa_t *this = malloc_thing(private_child_sa_t); /* public functions */ + this->public.get_reqid = (u_int32_t(*)(child_sa_t*))get_reqid; this->public.alloc = (status_t(*)(child_sa_t*,linked_list_t*))alloc; this->public.add = (status_t(*)(child_sa_t*,proposal_t*,prf_plus_t*))add; this->public.update = (status_t(*)(child_sa_t*,proposal_t*,prf_plus_t*))update; @@ -583,7 +591,7 @@ child_sa_t * child_sa_create(host_t *me, host_t* other) this->my_esp_spi = 0; this->other_ah_spi = 0; this->other_esp_spi = 0; - this->reqid = reqid++; + this->reqid = ++reqid; this->policies = linked_list_create(); return (&this->public); diff --git a/src/charon/sa/child_sa.h b/src/charon/sa/child_sa.h index bb5224f26..d32a56152 100644 --- a/src/charon/sa/child_sa.h +++ b/src/charon/sa/child_sa.h @@ -58,6 +58,17 @@ typedef struct child_sa_t child_sa_t; */ struct child_sa_t { + /** + * @brief Get the unique reqid of the CHILD SA. + * + * Every CHILD_SA has a unique reqid, which is also + * stored down in the kernel. + * + * @param this calling object + * @return reqid of the CHILD SA + */ + u_int32_t (*get_reqid)(child_sa_t *this); + /** * @brief Allocate SPIs for a given proposals. * diff --git a/src/charon/sa/ike_sa.c b/src/charon/sa/ike_sa.c index fdaee7f4c..eae7ad3d1 100644 --- a/src/charon/sa/ike_sa.c +++ b/src/charon/sa/ike_sa.c @@ -886,6 +886,28 @@ static void add_child_sa(private_ike_sa_t *this, child_sa_t *child_sa) this->child_sas->insert_last(this->child_sas, child_sa); } +/** + * Implementation of ike_sa_t.get_child_sa. + */ +static child_sa_t *get_child_sa(private_ike_sa_t *this, u_int32_t reqid) +{ + iterator_t *iterator; + child_sa_t *current, *found = NULL; + + iterator = this->child_sas->create_iterator(this->child_sas, TRUE); + while (iterator->has_next(iterator)) + { + iterator->current(iterator, (void**)¤t); + if (current->get_reqid(current) == reqid) + { + found = current; + break; + } + } + iterator->destroy(iterator); + return found; +} + /** * Implementation of protected_ike_sa_t.reset_message_buffers. */ @@ -929,18 +951,19 @@ static void log_status(private_ike_sa_t *this, logger_t *logger, char *name) return; } } - else - { - name = this->connection->get_name(this->connection); - } - my_host = this->connection->get_my_host(this->connection); other_host = this->connection->get_other_host(this->connection); + /* use policy information, if available */ if (this->policy) { my_id = this->policy->get_my_id(this->policy); other_id = this->policy->get_other_id(this->policy); + name = this->policy->get_name(this->policy); + } + else + { + name = this->connection->get_name(this->connection); } if (logger == NULL) @@ -1116,6 +1139,7 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id) /* Public functions */ this->protected.public.process_message = (status_t(*)(ike_sa_t*, message_t*)) process_message; this->protected.public.initiate_connection = (status_t(*)(ike_sa_t*,connection_t*)) initiate_connection; + this->protected.public.get_child_sa = (child_sa_t*(*)(ike_sa_t*,u_int32_t))get_child_sa; this->protected.public.get_id = (ike_sa_id_t*(*)(ike_sa_t*)) get_id; this->protected.public.get_my_host = (host_t*(*)(ike_sa_t*)) get_my_host; this->protected.public.get_other_host = (host_t*(*)(ike_sa_t*)) get_other_host; diff --git a/src/charon/sa/ike_sa.h b/src/charon/sa/ike_sa.h index 31a5ba8a1..db0c120df 100644 --- a/src/charon/sa/ike_sa.h +++ b/src/charon/sa/ike_sa.h @@ -113,6 +113,19 @@ struct ike_sa_t { */ ike_sa_id_t* (*get_id) (ike_sa_t *this); + /** + * @brief Get the CHILD_SA with the specified reqid. + * + * The reqid is a unique ID for a child SA, which is + * generated on child SA creation. + * Returned child_sa_t object is not cloned! + * + * @param this calling object + * @param reqid reqid of the child SA, as used in the kernel + * @return child_sa, or NULL if not found + */ + child_sa_t* (*get_child_sa) (ike_sa_t *this, u_int32_t reqid); + /** * @brief Get local peer address of the IKE_SA. * @@ -184,7 +197,7 @@ struct ike_sa_t { * @brief Initiates the deletion of an IKE_SA. * * Sends a delete message to the remote peer and waits for - * its response. If the response comes in, or a timeout occur, + * its response. If the response comes in, or a timeout occurs, * the IKE SA gets deleted. * * @param this calling object diff --git a/src/charon/sa/ike_sa_manager.c b/src/charon/sa/ike_sa_manager.c index 9f09a8683..d38987dab 100644 --- a/src/charon/sa/ike_sa_manager.c +++ b/src/charon/sa/ike_sa_manager.c @@ -392,19 +392,19 @@ static status_t checkout(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id, /* we SHOULD have an IKE_SA for these SPIs in the list, * if not, we can't handle the request... */ - ike_sa_entry_t *entry; - /* look for the entry */ - if (this->get_entry_by_id(this, ike_sa_id, &entry) == SUCCESS) - { - /* can we give this ike_sa out to new requesters?*/ - if (entry->driveout_new_threads) - { - this->logger->log(this->logger, CONTROL|LEVEL1, "Drive out new thread for existing IKE_SA"); - /* no we can't */ - retval = NOT_FOUND; - } - else - { + ike_sa_entry_t *entry; + /* look for the entry */ + if (this->get_entry_by_id(this, ike_sa_id, &entry) == SUCCESS) + { + /* can we give this ike_sa out to new requesters?*/ + if (entry->driveout_new_threads) + { + this->logger->log(this->logger, CONTROL|LEVEL1, "Drive out new thread for existing IKE_SA"); + /* no we can't */ + retval = NOT_FOUND; + } + else + { /* is this IKE_SA already checked out ?? * are we welcome to get this SA ? */ while (entry->checked_out && !entry->driveout_waiting_threads) @@ -489,64 +489,55 @@ static status_t checkout(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id, } /** - * Implementation of of ike_sa_manager.checkout_by_hosts. + * Implementation of of ike_sa_manager.checkout_by_reqid. */ -static status_t checkout_by_hosts(private_ike_sa_manager_t *this, host_t *me, host_t *other, ike_sa_t **ike_sa) +static status_t checkout_by_reqid(private_ike_sa_manager_t *this, u_int32_t reqid, ike_sa_t **ike_sa) { iterator_t *iterator; - ike_sa_id_t *ike_sa_id = NULL; + status_t status = NOT_FOUND; pthread_mutex_lock(&(this->mutex)); iterator = this->ike_sa_list->create_iterator(this->ike_sa_list, TRUE); while (iterator->has_next(iterator)) { - ike_sa_entry_t *current; - host_t *sa_me, *sa_other; + ike_sa_entry_t *entry; - iterator->current(iterator, (void**)¤t); - sa_me = current->ike_sa->get_my_host(current->ike_sa); - sa_other = current->ike_sa->get_other_host(current->ike_sa); - - /* one end may be default/any, but not both */ - if (me->is_anyaddr(me)) + iterator->current(iterator, (void**)&entry); + if (entry->driveout_new_threads) { - if (other->is_anyaddr(other)) - { - break; - } - if (other->equals(other, sa_other)) - { - /* other matches */ - ike_sa_id = current->ike_sa_id; - } + /* we are not allowed to get this, get next one */ + continue; } - else if (other->is_anyaddr(other)) + while (entry->checked_out && !entry->driveout_waiting_threads) { - if (me->equals(me, sa_me)) - { - /* ME matches */ - ike_sa_id = current->ike_sa_id; - } + /* so wait until we can get it for us. + * we register us as waiting. */ + entry->waiting_threads++; + pthread_cond_wait(&(entry->condvar), &(this->mutex)); + entry->waiting_threads--; } - else + /* hm, a deletion request forbids us to get this SA, get next one */ + if (entry->driveout_waiting_threads) { - if (me->equals(me, sa_me) && other->equals(other, sa_other)) - { - /* both matches */ - ike_sa_id = current->ike_sa_id; - } + /* we must signal here, others may be waiting on it, too */ + pthread_cond_signal(&(entry->condvar)); + continue; + } + /* ok, access is exclusive for us, check reqid */ + if (entry->ike_sa->get_child_sa(entry->ike_sa, reqid) != NULL) + { + /* match */ + entry->checked_out = TRUE; + *ike_sa = entry->ike_sa; + status = SUCCESS; + break; } } iterator->destroy(iterator); pthread_mutex_unlock(&(this->mutex)); - if (ike_sa_id) - { - /* checkout is done in the checkout function, since its rather complex */ - return checkout(this, ike_sa_id, ike_sa); - } - return NOT_FOUND; + return status; } /** @@ -840,7 +831,7 @@ ike_sa_manager_t *ike_sa_manager_create() this->public.destroy = (void(*)(ike_sa_manager_t*))destroy; this->public.create_and_checkout = (void(*)(ike_sa_manager_t*,ike_sa_t**))create_and_checkout; this->public.checkout = (status_t(*)(ike_sa_manager_t*, ike_sa_id_t*,ike_sa_t**))checkout; - this->public.checkout_by_hosts = (status_t(*)(ike_sa_manager_t*,host_t*,host_t*,ike_sa_t**))checkout_by_hosts; + this->public.checkout_by_reqid = (status_t(*)(ike_sa_manager_t*,u_int32_t,ike_sa_t**))checkout_by_reqid; 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; diff --git a/src/charon/sa/ike_sa_manager.h b/src/charon/sa/ike_sa_manager.h index a608052bd..6982e0852 100644 --- a/src/charon/sa/ike_sa_manager.h +++ b/src/charon/sa/ike_sa_manager.h @@ -81,21 +81,21 @@ struct ike_sa_manager_t { void (*create_and_checkout) (ike_sa_manager_t* this,ike_sa_t **ike_sa); /** - * @brief Check out an IKE_SA, defined be the two peers. - * - * Checking out an IKE_SA by their peer addresses may be necessary - * for kernel traps, status querying and so on... one of the hosts - * may be 0.0.0.0 (defaultroute/any), but not both. - * - * @param this the manager object - * @param me host on local side - * @param other host on remote side + * @brief Check out an IKE_SA by the reqid of one of its CHILD_SAs. + * + * The kernel sends us expire messages for IPsec SAs. To fullfill + * this request, we must check out the IKE SA which contains the + * CHILD_SA the kernel wants to modify. We do this by the reqid, which + * is unique to every CHILD_SA. + * + * @param this the manager object + * @param reqid reqid of the IPsec SA * @param ike_sa[out] checked out SA * @return - * - NOT_FOUND, if no such SA found - * - SUCCESS, if SA found and ike_sa set appropriatly + * - NOT_FOUND, if no IKE SA with such a child found + * - SUCCESS, if ike_sa set */ - status_t (*checkout_by_hosts) (ike_sa_manager_t* this, host_t *me, host_t *other, ike_sa_t **ike_sa); + status_t (*checkout_by_reqid) (ike_sa_manager_t* this, u_int32_t reqid, ike_sa_t **ike_sa); /** * @brief Get a list of all IKE_SA SAs currently set up. diff --git a/src/charon/testing/Makefile.am b/src/charon/testing/Makefile.am index 0957a7096..857ef067b 100644 --- a/src/charon/testing/Makefile.am +++ b/src/charon/testing/Makefile.am @@ -29,6 +29,7 @@ $(top_srcdir)/src/charon/ke_payload.o $(top_srcdir)/src/charon/unknown_payload.o $(top_srcdir)/src/charon/delete_payload.o $(top_srcdir)/src/charon/sa_payload.o $(top_srcdir)/src/charon/certreq_payload.o $(top_srcdir)/src/charon/vendor_id_payload.o \ $(top_srcdir)/src/charon/proposal_substructure.o $(top_srcdir)/src/charon/payload.o $(top_srcdir)/src/charon/message.o $(top_srcdir)/src/charon/generator.o \ $(top_srcdir)/src/charon/parser.o $(top_srcdir)/src/charon/packet.o $(top_srcdir)/src/charon/socket.o $(top_srcdir)/src/charon/job.o \ +$(top_srcdir)/src/charon/delete_child_sa_job.o $(top_srcdir)/src/charon/rekey_child_sa_job.o \ $(top_srcdir)/src/charon/delete_established_ike_sa_job.o $(top_srcdir)/src/charon/incoming_packet_job.o $(top_srcdir)/src/charon/delete_half_open_ike_sa_job.o \ $(top_srcdir)/src/charon/retransmit_request_job.o $(top_srcdir)/src/charon/initiate_ike_sa_job.o $(top_srcdir)/src/charon/job_queue.o $(top_srcdir)/src/charon/event_queue.o \ $(top_srcdir)/src/charon/send_queue.o $(top_srcdir)/src/charon/kernel_interface.o $(top_srcdir)/src/charon/thread_pool.o $(top_srcdir)/src/charon/scheduler.o \ diff --git a/src/charon/testing/kernel_interface_test.c b/src/charon/testing/kernel_interface_test.c index 86553e15e..cf01b0297 100644 --- a/src/charon/testing/kernel_interface_test.c +++ b/src/charon/testing/kernel_interface_test.c @@ -65,20 +65,26 @@ void test_kernel_interface(protected_tester_t *tester) status = kernel_interface->get_spi(kernel_interface, me, other, 50, 1234, &spi); tester->assert_true(tester, status == SUCCESS, "spi get"); - status = kernel_interface->add_sa(kernel_interface, me, other, spi, 50, 1234, ENCR_AES_CBC, enc_key,AUTH_UNDEFINED,inc_key,TRUE); + status = kernel_interface->add_sa(kernel_interface, me, other, spi, 50, 1234, 5, 10, ENCR_AES_CBC, enc_key,AUTH_UNDEFINED,inc_key,TRUE); tester->assert_true(tester, status == SUCCESS, "add sa"); left = host_create(AF_INET, "10.1.0.0", 0); right = host_create(AF_INET, "10.2.0.0", 0); status = kernel_interface->add_policy(kernel_interface, me, other, left, right, 16, 16, XFRM_POLICY_OUT, 0, TRUE, FALSE, 1234); - tester->assert_true(tester, status == SUCCESS, "add policy"); + tester->assert_true(tester, status == SUCCESS, "add policy OUT"); + status = kernel_interface->add_policy(kernel_interface, me, other, left, right, 16, 16, XFRM_POLICY_IN, 0, TRUE, FALSE, 1234); + tester->assert_true(tester, status == SUCCESS, "add policy IN"); + status = kernel_interface->add_policy(kernel_interface, me, other, left, right, 16, 16, XFRM_POLICY_FWD, 0, TRUE, FALSE, 1234); + tester->assert_true(tester, status == SUCCESS, "add policy FWD"); me->destroy(me); other->destroy(other); left->destroy(left); right->destroy(right); + sleep(15); + kernel_interface->destroy(kernel_interface); } diff --git a/src/charon/testing/testcases.c b/src/charon/testing/testcases.c index d91811e09..ebcc01b1a 100644 --- a/src/charon/testing/testcases.c +++ b/src/charon/testing/testcases.c @@ -252,7 +252,7 @@ int main() tester_t *tester = tester_create(test_output, FALSE); //tester->perform_tests(tester,all_tests); - tester->perform_test(tester,&policy_test); + tester->perform_test(tester,&kernel_interface_test); tester->destroy(tester); diff --git a/src/charon/threads/kernel_interface.c b/src/charon/threads/kernel_interface.c index 679cf69ee..d88fa3f29 100644 --- a/src/charon/threads/kernel_interface.c +++ b/src/charon/threads/kernel_interface.c @@ -36,6 +36,8 @@ #include #include +#include +#include #define KERNEL_ESP 50 @@ -101,6 +103,8 @@ struct netlink_message_t { struct xfrm_userpolicy_id policy_id; /** message for policy installation */ struct xfrm_userpolicy_info policy; + /** expire message sent from kernel */ + struct xfrm_user_expire expire; }; u_int8_t data[XFRM_DATA_LENGTH]; }; @@ -205,7 +209,6 @@ mapping_t kernel_integrity_algs_m[] = { {MAPPING_END, NULL} }; - /** * Implementation of kernel_interface_t.get_spi. */ @@ -272,6 +275,8 @@ static status_t add_sa( private_kernel_interface_t *this, u_int32_t spi, int protocol, u_int32_t reqid, + u_int64_t expire_soft, + u_int64_t expire_hard, encryption_algorithm_t enc_alg, chunk_t encryption_key, integrity_algorithm_t int_alg, @@ -296,10 +301,16 @@ static status_t add_sa( private_kernel_interface_t *this, request.sa.mode = TRUE; /* tunnel mode */ request.sa.replay_window = 32; request.sa.reqid = reqid; + /* we currently do not expire SAs by volume/packet count */ request.sa.lft.soft_byte_limit = XFRM_INF; - request.sa.lft.soft_packet_limit = XFRM_INF; request.sa.lft.hard_byte_limit = XFRM_INF; + request.sa.lft.soft_packet_limit = XFRM_INF; request.sa.lft.hard_packet_limit = XFRM_INF; + /* we use lifetimes since added, not since used */ + request.sa.lft.soft_add_expires_seconds = expire_soft; + request.sa.lft.hard_add_expires_seconds = expire_hard; + request.sa.lft.soft_use_expires_seconds = 0; + request.sa.lft.hard_use_expires_seconds = 0; request.hdr.nlmsg_len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(request.sa))); @@ -435,10 +446,15 @@ static status_t add_policy(private_kernel_interface_t *this, request.policy.action = XFRM_POLICY_ALLOW; request.policy.share = XFRM_SHARE_ANY; + /* policies currently don't expire */ request.policy.lft.soft_byte_limit = XFRM_INF; request.policy.lft.soft_packet_limit = XFRM_INF; request.policy.lft.hard_byte_limit = XFRM_INF; request.policy.lft.hard_packet_limit = XFRM_INF; + request.sa.lft.soft_add_expires_seconds = 0; + request.sa.lft.hard_add_expires_seconds = 0; + request.sa.lft.soft_use_expires_seconds = 0; + request.sa.lft.hard_use_expires_seconds = 0; if (esp || ah) { @@ -645,30 +661,58 @@ static void receive_messages(private_kernel_interface_t *this) /* not from kernel. not interested, try another one */ continue; } + /* good message, handle it */ break; } - /* got a valid message. - * requests are handled on our own, - * responses are listed for the requesters + /* we handle ACQUIRE and EXPIRE messages directly */ - if (response.hdr.nlmsg_flags & NLM_F_REQUEST) + if (response.hdr.nlmsg_type == XFRM_MSG_ACQUIRE) { - /* handle request */ + this->logger->log(this->logger, CONTROL, + "Received a XFRM_MSG_ACQUIRE. Ignored"); } - else + else if (response.hdr.nlmsg_type == XFRM_MSG_EXPIRE) { - /* add response to queue */ + job_t *job; + this->logger->log(this->logger, CONTROL|LEVEL1, + "Received a XFRM_MSG_EXPIRE"); + this->logger->log(this->logger, CONTROL|LEVEL0, + "creating %s job for CHILD_SA with reqid %d", + response.expire.hard ? "delete" : "rekey", + response.expire.state.reqid); + if (response.expire.hard) + { + job = (job_t*)delete_child_sa_job_create( + response.expire.state.reqid); + } + else + { + job = (job_t*)rekey_child_sa_job_create( + response.expire.state.reqid); + } + charon->job_queue->add(charon->job_queue, job); + } + /* NLMSG_ERROR is send back for acknowledge (or on error), an + * XFRM_MSG_NEWSA is returned when we alloc spis. + * list these responses for the sender + */ + else if (response.hdr.nlmsg_type == NLMSG_ERROR || + response.hdr.nlmsg_type == XFRM_MSG_NEWSA) + { + /* add response to queue */ listed_response = malloc(sizeof(response)); memcpy(listed_response, &response, sizeof(response)); - + pthread_mutex_lock(&(this->mutex)); this->responses->insert_last(this->responses, (void*)listed_response); pthread_mutex_unlock(&(this->mutex)); /* signal ALL waiting threads */ pthread_cond_broadcast(&(this->condvar)); } - /* get the next one */ + /* we are not interested in anything other. + * anyway, move on to the next message */ + continue; } } @@ -689,11 +733,12 @@ static void destroy(private_kernel_interface_t *this) */ kernel_interface_t *kernel_interface_create() { + struct sockaddr_nl addr; private_kernel_interface_t *this = malloc_thing(private_kernel_interface_t); /* 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,encryption_algorithm_t,chunk_t,integrity_algorithm_t,chunk_t,bool))add_sa; + 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,encryption_algorithm_t,chunk_t,integrity_algorithm_t,chunk_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,bool,bool,u_int32_t))add_policy; this->public.del_sa = (status_t(*)(kernel_interface_t*,host_t*,u_int32_t,protocol_id_t))del_sa; 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; @@ -709,6 +754,8 @@ kernel_interface_t *kernel_interface_create() pthread_mutex_init(&(this->mutex),NULL); pthread_cond_init(&(this->condvar),NULL); this->seq = 0; + + /* open netlink socket */ this->socket = socket(PF_NETLINK, SOCK_RAW, NETLINK_XFRM); if (this->socket <= 0) { @@ -716,6 +763,17 @@ kernel_interface_t *kernel_interface_create() free(this); charon->kill(charon, "Unable to create netlink socket"); } + /* bind the socket and reqister for ACQUIRE & EXPIRE */ + addr.nl_family = AF_NETLINK; + addr.nl_pid = getpid(); + addr.nl_groups = XFRMGRP_ACQUIRE | XFRMGRP_EXPIRE; + if (bind(this->socket, (struct sockaddr*)&addr, sizeof(addr)) != 0) + { + this->responses->destroy(this->responses); + close(this->socket); + free(this); + charon->kill(charon, "Unable to bind netlink socket"); + } if (pthread_create(&(this->thread), NULL, (void*(*)(void*))this->receive_messages, this) != 0) { diff --git a/src/charon/threads/kernel_interface.h b/src/charon/threads/kernel_interface.h index b3ca13faa..6c9a181ed 100644 --- a/src/charon/threads/kernel_interface.h +++ b/src/charon/threads/kernel_interface.h @@ -68,30 +68,34 @@ struct kernel_interface_t { * * add_sa() may update an already allocated * SPI (via get_spi). In this case, the replace - * flag must be set. + * flag must be set. * This function does install a single SA for a * single protocol in one direction. * - * @param this calling object - * @param src source address for this SA - * @param dst destination address for this SA - * @param spi SPI allocated by us or remote peer - * @param protocol protocol for this SA (ESP/AH) - * @param reqid unique ID for this SA - * @param enc_alg Algorithm to use for encryption (ESP only) - * @param enc_key Key to use for encryption - * @param int_alg Algorithm to use for integrity protection - * @param int_key Key for integrity protection - * @param replace Should an already installed SA be updated? + * @param this calling object + * @param src source address for this SA + * @param dst destination address for this SA + * @param spi SPI allocated by us or remote peer + * @param protocol protocol for this SA (ESP/AH) + * @param reqid unique ID for this SA + * @param expire_soft lifetime in seconds before rekeying + * @param expire_hard lieftime in seconds before delete + * @param enc_alg Algorithm to use for encryption (ESP only) + * @param enc_key Key to use for encryption + * @param int_alg Algorithm to use for integrity protection + * @param int_key Key for integrity protection + * @param replace Should an already installed SA be updated? * @return - * - SUCCESS - * - FAILED if kernel comm failed + * - SUCCESS + * - FAILED if kernel comm failed */ status_t (*add_sa)(kernel_interface_t *this, host_t *src, host_t *dst, u_int32_t spi, protocol_id_t protocol, u_int32_t reqid, + u_int64_t expire_soft, + u_int64_t expire_hard, encryption_algorithm_t enc_alg, chunk_t enc_key, integrity_algorithm_t int_alg, diff --git a/src/charon/threads/thread_pool.c b/src/charon/threads/thread_pool.c index 51d29c222..83771ceb5 100644 --- a/src/charon/threads/thread_pool.c +++ b/src/charon/threads/thread_pool.c @@ -48,68 +48,7 @@ struct private_thread_pool_t { * Public thread_pool_t interface. */ thread_pool_t public; - - /** - * @brief Main processing function for worker threads. - * - * Gets a job from the job queue and calls corresponding - * function for processing. - * - * @param this calling object - */ - void (*process_jobs) (private_thread_pool_t *this); - /** - * @brief Process a INCOMING_PACKET job. - * - * @param this calling object - * @param job incoming_packet_job_t object - */ - void (*process_incoming_packet_job) (private_thread_pool_t *this, incoming_packet_job_t *job); - - /** - * @brief Process a INITIATE_IKE_SA job. - * - * @param this calling object - * @param job initiate_ike_sa_job_t object - */ - void (*process_initiate_ike_sa_job) (private_thread_pool_t *this, initiate_ike_sa_job_t *job); - - /** - * @brief Process a DELETE_HALF_OPEN_IKE_SA job. - * - * @param this calling object - * @param job delete__half_open_ike_sa_job_t object - */ - void (*process_delete_half_open_ike_sa_job) (private_thread_pool_t *this, delete_half_open_ike_sa_job_t *job); - - /** - * @brief Process a DELETE_ESTABLISHED_IKE_SA job. - * - * @param this calling object - * @param job delete_established_ike_sa_job_t object - */ - void (*process_delete_established_ike_sa_job) (private_thread_pool_t *this, delete_established_ike_sa_job_t *job); - - /** - * @brief Process a RETRANSMIT_REQUEST job. - * - * @param this calling object - * @param job retransmit_request_job_t object - */ - void (*process_retransmit_request_job) (private_thread_pool_t *this, retransmit_request_job_t *job); - - /** - * Creates a job of type DELETE_HALF_OPEN_IKE_SA. - * - * This job is used to delete IKE_SA's which are still in state INITIATOR_INIT, - * RESPONDER_INIT, IKE_AUTH_REQUESTED, IKE_INIT_REQUESTED or IKE_INIT_RESPONDED. - * - * @param ike_sa_id ID of IKE_SA to delete - * @param delay Delay in ms after a half open IKE_SA gets deleted! - */ - void (*create_delete_half_open_ike_sa_job) (private_thread_pool_t *this,ike_sa_id_t *ike_sa_id, u_int32_t delay); - /** * Number of running threads. */ @@ -137,366 +76,26 @@ struct private_thread_pool_t { static void process_jobs(private_thread_pool_t *this) { job_t *job; - job_type_t job_type; - timeval_t start_time; - timeval_t end_time; + status_t status; /* cancellation disabled by default */ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); this->worker_logger->log(this->worker_logger, CONTROL, "worker thread running, thread_ID: %06d", (int)pthread_self()); - - for (;;) + + while (TRUE) { job = charon->job_queue->get(charon->job_queue); - job_type = job->get_type(job); - this->worker_logger->log(this->worker_logger, CONTROL|LEVEL2, "Process job of type %s", - mapping_find(job_type_m,job_type)); - gettimeofday(&start_time,NULL); - switch (job_type) - { - case INCOMING_PACKET: - { - this->process_incoming_packet_job(this, (incoming_packet_job_t*)job); - job->destroy(job); - break; - } - case INITIATE_IKE_SA: - { - this->process_initiate_ike_sa_job(this, (initiate_ike_sa_job_t*)job); - job->destroy(job); - break; - } - case DELETE_HALF_OPEN_IKE_SA: - { - this->process_delete_half_open_ike_sa_job(this, (delete_half_open_ike_sa_job_t*)job); - job->destroy(job); - break; - } - case DELETE_ESTABLISHED_IKE_SA: - { - this->process_delete_established_ike_sa_job(this, (delete_established_ike_sa_job_t*)job); - job->destroy(job); - break; - } - case RETRANSMIT_REQUEST: - { - this->process_retransmit_request_job(this, (retransmit_request_job_t*)job); - break; - } - default: - { - this->worker_logger->log(this->worker_logger, ERROR, "Job of type %s not supported!", - mapping_find(job_type_m,job_type)); - job->destroy(job); - break; - } - } - gettimeofday(&end_time,NULL); - this->worker_logger->log(this->worker_logger, CONTROL | LEVEL2, "Processed job of type %s in %d us", - mapping_find(job_type_m,job_type), - (((end_time.tv_sec - start_time.tv_sec) * 1000000) + (end_time.tv_usec - start_time.tv_usec))); - - - } -} - -/** - * Implementation of private_thread_pool_t.process_incoming_packet_job. - */ -static void process_incoming_packet_job(private_thread_pool_t *this, incoming_packet_job_t *job) -{ - packet_t *packet; - message_t *message; - ike_sa_t *ike_sa; - ike_sa_id_t *ike_sa_id; - status_t status; - - packet = job->get_packet(job); - - message = message_create_from_packet(packet); - status = message->parse_header(message); - if (status != SUCCESS) - { - this->worker_logger->log(this->worker_logger, ERROR, "Message header could not be verified!"); - message->destroy(message); - return; - } - - this->worker_logger->log(this->worker_logger, CONTROL|LEVEL2, "Message is a %s %s", - mapping_find(exchange_type_m, message->get_exchange_type(message)), - message->get_request(message) ? "request" : "reply"); - - if ((message->get_major_version(message) != IKE_MAJOR_VERSION) || - (message->get_minor_version(message) != IKE_MINOR_VERSION)) - { - this->worker_logger->log(this->worker_logger, ERROR | LEVEL2, - "IKE version %d.%d not supported", - message->get_major_version(message), - message->get_minor_version(message)); - if ((message->get_exchange_type(message) == IKE_SA_INIT) && (message->get_request(message))) - { - message_t *response; - message->get_ike_sa_id(message, &ike_sa_id); - ike_sa_id->switch_initiator(ike_sa_id); - response = message_create_notify_reply(message->get_destination(message), - message->get_source(message), - IKE_SA_INIT, FALSE, ike_sa_id, - INVALID_MAJOR_VERSION); - message->destroy(message); - ike_sa_id->destroy(ike_sa_id); - status = response->generate(response, NULL, NULL, &packet); - if (status != SUCCESS) - { - this->worker_logger->log(this->worker_logger, ERROR, "Could not generate packet from message"); - response->destroy(response); - return; - } - this->worker_logger->log(this->worker_logger, ERROR, "Send notify reply of type INVALID_MAJOR_VERSION"); - charon->send_queue->add(charon->send_queue, packet); - response->destroy(response); - return; - } - message->destroy(message); - return; - } - - message->get_ike_sa_id(message, &ike_sa_id); - - ike_sa_id->switch_initiator(ike_sa_id); - - this->worker_logger->log(this->worker_logger, CONTROL|LEVEL3, "Checking out IKE SA %lld:%lld, role %s", - ike_sa_id->get_initiator_spi(ike_sa_id), - ike_sa_id->get_responder_spi(ike_sa_id), - ike_sa_id->is_initiator(ike_sa_id) ? "initiator" : "responder"); - - status = charon->ike_sa_manager->checkout(charon->ike_sa_manager,ike_sa_id, &ike_sa); - if ((status != SUCCESS) && (status != CREATED)) - { - this->worker_logger->log(this->worker_logger, ERROR, "IKE SA could not be checked out"); - ike_sa_id->destroy(ike_sa_id); - message->destroy(message); + status = job->execute(job); - /* TODO: send notify reply of type INVALID_IKE_SPI if SPI could not be found ? */ - return; - } - - if (status == CREATED) - { - this->worker_logger->log(this->worker_logger, CONTROL|LEVEL3, - "Create Job to delete half open IKE_SA."); - this->create_delete_half_open_ike_sa_job(this,ike_sa_id, - charon->configuration->get_half_open_ike_sa_timeout(charon->configuration)); - } - - status = ike_sa->process_message(ike_sa, message); - - this->worker_logger->log(this->worker_logger, CONTROL|LEVEL3, "%s IKE SA %lld:%lld, role %s", - (status == DESTROY_ME) ? "Checkin and delete" : "Checkin", - ike_sa_id->get_initiator_spi(ike_sa_id), - ike_sa_id->get_responder_spi(ike_sa_id), - ike_sa_id->is_initiator(ike_sa_id) ? "initiator" : "responder"); - ike_sa_id->destroy(ike_sa_id); - - if (status == DESTROY_ME) - { - status = charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa); - } - else - { - status = charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); - } - - if (status != SUCCESS) - { - this->worker_logger->log(this->worker_logger, ERROR, "Checkin of IKE SA failed!"); - } - message->destroy(message); -} - -/** - * Implementation of private_thread_pool_t.process_initiate_ike_sa_job. - */ -static void process_initiate_ike_sa_job(private_thread_pool_t *this, initiate_ike_sa_job_t *job) -{ - /* - * Initiatie an IKE_SA: - * - is defined by a name of a configuration - * - create an empty IKE_SA via manager - * - call initiate_connection on this sa - */ - ike_sa_t *ike_sa; - status_t status; - - - this->worker_logger->log(this->worker_logger, CONTROL|LEVEL2, "Creating and checking out IKE SA"); - charon->ike_sa_manager->create_and_checkout(charon->ike_sa_manager, &ike_sa); - - status = ike_sa->initiate_connection(ike_sa, job->get_connection(job)); - if (status != SUCCESS) - { - this->worker_logger->log(this->worker_logger, ERROR, "Initiation returned %s, going to delete IKE_SA.", - mapping_find(status_m, status)); - charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa); - return; - } - - this->worker_logger->log(this->worker_logger, CONTROL|LEVEL3, "Create Job to delete half open IKE_SA."); - this->create_delete_half_open_ike_sa_job(this,ike_sa->get_id(ike_sa), - charon->configuration->get_half_open_ike_sa_timeout(charon->configuration)); - - this->worker_logger->log(this->worker_logger, CONTROL|LEVEL2, "Checking in IKE SA"); - status = charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); - if (status != SUCCESS) - { - this->worker_logger->log(this->worker_logger, ERROR, "Could not checkin IKE_SA (%s)", - mapping_find(status_m, status)); - } -} - -/** - * Implementation of private_thread_pool_t.process_delete_ike_sa_job. - */ -static void process_delete_half_open_ike_sa_job(private_thread_pool_t *this, delete_half_open_ike_sa_job_t *job) -{ - ike_sa_id_t *ike_sa_id = job->get_ike_sa_id(job); - ike_sa_t *ike_sa; - status_t status; - status = charon->ike_sa_manager->checkout(charon->ike_sa_manager,ike_sa_id, &ike_sa); - if ((status != SUCCESS) && (status != CREATED)) - { - this->worker_logger->log(this->worker_logger, CONTROL | LEVEL3, "IKE SA seems to be already deleted"); - return; - } - - switch (ike_sa->get_state(ike_sa)) - { - case INITIATOR_INIT: - case RESPONDER_INIT: - case IKE_SA_INIT_REQUESTED: - case IKE_SA_INIT_RESPONDED: - case IKE_AUTH_REQUESTED: - case DELETE_REQUESTED: + if (status == DESTROY_ME) { - /* IKE_SA is half open and gets deleted! */ - status = charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa); - if (status != SUCCESS) - { - this->worker_logger->log(this->worker_logger, ERROR, "Could not checkin and delete checked out IKE_SA!"); - } - break; - } - default: - { - /* IKE_SA is established and so is not getting deleted! */ - status = charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); - if (status != SUCCESS) - { - this->worker_logger->log(this->worker_logger, ERROR, "Could not checkin a checked out IKE_SA!"); - } - break; + job->destroy(job); } } } -/** - * Implementation of private_thread_pool_t.process_delete_established_ike_sa_job. - */ -static void process_delete_established_ike_sa_job(private_thread_pool_t *this, delete_established_ike_sa_job_t *job) -{ - ike_sa_id_t *ike_sa_id = job->get_ike_sa_id(job); - ike_sa_t *ike_sa; - status_t status; - status = charon->ike_sa_manager->delete(charon->ike_sa_manager, ike_sa_id); - if (status != SUCCESS) - { - this->worker_logger->log(this->worker_logger, CONTROL, "IKE SA didn't exist anymore"); - return; - } -} - -/** - * Implementation of private_thread_pool_t.process_retransmit_request_job. - */ -static void process_retransmit_request_job(private_thread_pool_t *this, retransmit_request_job_t *job) -{ - - ike_sa_id_t *ike_sa_id = job->get_ike_sa_id(job); - u_int32_t message_id = job->get_message_id(job); - bool stop_retransmitting = FALSE; - u_int32_t timeout; - ike_sa_t *ike_sa; - status_t status; - - this->worker_logger->log(this->worker_logger, CONTROL|LEVEL2, "Checking out IKE SA %lld:%lld, role %s", - ike_sa_id->get_initiator_spi(ike_sa_id), - ike_sa_id->get_responder_spi(ike_sa_id), - ike_sa_id->is_initiator(ike_sa_id) ? "initiator" : "responder"); - - status = charon->ike_sa_manager->checkout(charon->ike_sa_manager,ike_sa_id, &ike_sa); - if ((status != SUCCESS) && (status != CREATED)) - { - job->destroy(job); - this->worker_logger->log(this->worker_logger, ERROR|LEVEL1, "IKE SA could not be checked out. Already deleted?"); - return; - } - - status = ike_sa->retransmit_request(ike_sa, message_id); - - if (status != SUCCESS) - { - this->worker_logger->log(this->worker_logger, CONTROL|LEVEL3, "Message doesn't have to be retransmitted"); - stop_retransmitting = TRUE; - } - - this->worker_logger->log(this->worker_logger, CONTROL|LEVEL2, "Checkin IKE SA %lld:%lld, role %s", - ike_sa_id->get_initiator_spi(ike_sa_id), - ike_sa_id->get_responder_spi(ike_sa_id), - ike_sa_id->is_initiator(ike_sa_id) ? "initiator" : "responder"); - - status = charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); - if (status != SUCCESS) - { - this->worker_logger->log(this->worker_logger, ERROR, "Checkin of IKE SA failed!"); - } - - if (stop_retransmitting) - { - job->destroy(job); - return; - } - - job->increase_retransmit_count(job); - status = charon->configuration->get_retransmit_timeout (charon->configuration,job->get_retransmit_count(job),&timeout); - if (status != SUCCESS) - { - this->worker_logger->log(this->worker_logger, CONTROL | LEVEL2, "Message will not be anymore retransmitted"); - job->destroy(job); - /* - * TODO delete IKE_SA ? - */ - return; - } - charon->event_queue->add_relative(charon->event_queue,(job_t *) job,timeout); -} - - - -/** - * Implementation of private_thread_pool_t.create_delete_half_open_ike_sa_job. - */ -static void create_delete_half_open_ike_sa_job(private_thread_pool_t *this,ike_sa_id_t *ike_sa_id, u_int32_t delay) -{ - job_t *delete_job; - - this->worker_logger->log(this->worker_logger, CONTROL | LEVEL2, "Going to create job to delete half open IKE_SA in %d ms", delay); - - delete_job = (job_t *) delete_half_open_ike_sa_job_create(ike_sa_id); - charon->event_queue->add_relative(charon->event_queue,delete_job, delay); -} - - /** * Implementation of thread_pool_t.get_pool_size. */ @@ -528,7 +127,7 @@ static void destroy(private_thread_pool_t *this) this->pool_logger->log(this->pool_logger, ERROR, "could not terminate worker thread #%d", current+1); } } - + /* free mem */ free(this->threads); free(this); @@ -540,33 +139,22 @@ static void destroy(private_thread_pool_t *this) thread_pool_t *thread_pool_create(size_t pool_size) { int current; - private_thread_pool_t *this = malloc_thing(private_thread_pool_t); /* fill in public fields */ this->public.destroy = (void(*)(thread_pool_t*))destroy; this->public.get_pool_size = (size_t(*)(thread_pool_t*))get_pool_size; - this->process_jobs = process_jobs; - this->process_initiate_ike_sa_job = process_initiate_ike_sa_job; - this->process_delete_half_open_ike_sa_job = process_delete_half_open_ike_sa_job; - this->process_delete_established_ike_sa_job = process_delete_established_ike_sa_job; - this->process_incoming_packet_job = process_incoming_packet_job; - this->process_retransmit_request_job = process_retransmit_request_job; - this->create_delete_half_open_ike_sa_job = create_delete_half_open_ike_sa_job; - + /* initialze memeber */ 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); /* try to create as many threads as possible, up tu pool_size */ for (current = 0; current < pool_size; current++) { - if (pthread_create(&(this->threads[current]), NULL, (void*(*)(void*))this->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); }