reuse an existing IKE_SA to set up additional CHILD_SAs

This commit is contained in:
Martin Willi
2006-07-20 14:57:49 +00:00
parent 8dfbe71b34
commit c0593835f4
19 changed files with 346 additions and 265 deletions
+2 -2
View File
@@ -38,10 +38,10 @@ encoding/payloads/vendor_id_payload.h encoding/payloads/proposal_substructure.c
encoding/parser.h encoding/message.c encoding/generator.c encoding/message.h encoding/generator.h \ encoding/parser.h encoding/message.c encoding/generator.c encoding/message.h encoding/generator.h \
encoding/parser.c daemon.c daemon.h network/packet.c \ encoding/parser.c daemon.c daemon.h network/packet.c \
network/interfaces.c network/interfaces.h network/socket.c network/packet.h network/socket.h queues/jobs/job.h queues/jobs/job.c \ network/interfaces.c network/interfaces.h network/socket.c network/packet.h network/socket.h queues/jobs/job.h queues/jobs/job.c \
queues/jobs/delete_established_ike_sa_job.c queues/jobs/retransmit_request_job.h queues/jobs/initiate_ike_sa_job.h \ queues/jobs/delete_established_ike_sa_job.c queues/jobs/retransmit_request_job.h queues/jobs/initiate_job.h \
queues/jobs/incoming_packet_job.c queues/jobs/delete_half_open_ike_sa_job.c \ 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/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/incoming_packet_job.h queues/jobs/retransmit_request_job.c queues/jobs/initiate_job.c \
queues/jobs/send_keepalive_job.c queues/jobs/send_keepalive_job.h \ queues/jobs/send_keepalive_job.c queues/jobs/send_keepalive_job.h \
queues/jobs/rekey_child_sa_job.c queues/jobs/rekey_child_sa_job.h \ 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/jobs/delete_child_sa_job.c queues/jobs/delete_child_sa_job.h \
@@ -62,9 +62,10 @@ static status_t execute(private_delete_half_open_ike_sa_job_t *this)
{ {
ike_sa_t *ike_sa; ike_sa_t *ike_sa;
if (charon->ike_sa_manager->checkout(charon->ike_sa_manager, this->ike_sa_id, ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager, this->ike_sa_id);
&ike_sa) != SUCCESS) if (ike_sa == NULL)
{ {
/* hm, somebody was faster ;-) */
return DESTROY_ME; return DESTROY_ME;
} }
+4 -4
View File
@@ -142,8 +142,8 @@ static status_t execute(private_incoming_packet_job_t *this)
ike_sa_id = message->get_ike_sa_id(message); ike_sa_id = message->get_ike_sa_id(message);
ike_sa_id = ike_sa_id->clone(ike_sa_id); ike_sa_id = ike_sa_id->clone(ike_sa_id);
ike_sa_id->switch_initiator(ike_sa_id); ike_sa_id->switch_initiator(ike_sa_id);
status = charon->ike_sa_manager->checkout(charon->ike_sa_manager, ike_sa_id, &ike_sa); ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager, ike_sa_id);
if (status != SUCCESS) if (ike_sa == NULL)
{ {
this->logger->log(this->logger, ERROR, this->logger->log(this->logger, ERROR,
"received packet with SPIs %llx:%llx, but no such IKE_SA", "received packet with SPIs %llx:%llx, but no such IKE_SA",
@@ -158,11 +158,11 @@ static status_t execute(private_incoming_packet_job_t *this)
status = ike_sa->process_message(ike_sa, message); status = ike_sa->process_message(ike_sa, message);
if (status == DESTROY_ME) if (status == DESTROY_ME)
{ {
status = charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa); charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa);
} }
else else
{ {
status = charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
} }
ike_sa_id->destroy(ike_sa_id); ike_sa_id->destroy(ike_sa_id);
message->destroy(message); message->destroy(message);
@@ -1,7 +1,7 @@
/** /**
* @file initiate_ike_sa_job.c * @file initiate_job.c
* *
* @brief Implementation of initiate_ike_sa_job_t. * @brief Implementation of initiate_job_t.
* *
*/ */
@@ -24,21 +24,21 @@
#include <stdlib.h> #include <stdlib.h>
#include "initiate_ike_sa_job.h" #include "initiate_job.h"
#include <daemon.h> #include <daemon.h>
#include <queues/jobs/delete_half_open_ike_sa_job.h> #include <queues/jobs/delete_half_open_ike_sa_job.h>
typedef struct private_initiate_ike_sa_job_t private_initiate_ike_sa_job_t; typedef struct private_initiate_job_t private_initiate_job_t;
/** /**
* Private data of an initiate_ike_sa_job_t Object * Private data of an initiate_job_t Object
*/ */
struct private_initiate_ike_sa_job_t { struct private_initiate_job_t {
/** /**
* public initiate_ike_sa_job_t interface * public initiate_job_t interface
*/ */
initiate_ike_sa_job_t public; initiate_job_t public;
/** /**
* associated connection to initiate * associated connection to initiate
@@ -57,37 +57,31 @@ struct private_initiate_ike_sa_job_t {
}; };
/** /**
* Implements initiate_ike_sa_job_t.get_type. * Implements initiate_job_t.get_type.
*/ */
static job_type_t get_type(private_initiate_ike_sa_job_t *this) static job_type_t get_type(private_initiate_job_t *this)
{ {
return INITIATE_IKE_SA; return INITIATE;
} }
/** /**
* Implementation of job_t.execute. * Implementation of job_t.execute.
*/ */
static status_t execute(private_initiate_ike_sa_job_t *this) static status_t execute(private_initiate_job_t *this)
{ {
/* Initiatie an IKE_SA:
* - is defined by a connection
* - create an empty IKE_SA via manager
* - call initiate() on this IKE_SA
*/
ike_sa_t *ike_sa; ike_sa_t *ike_sa;
status_t status;
this->logger->log(this->logger, CONTROL|LEVEL2, "Creating and checking out IKE SA"); this->logger->log(this->logger, CONTROL|LEVEL2, "getting an IKE SA");
charon->ike_sa_manager->create_and_checkout(charon->ike_sa_manager, &ike_sa); ike_sa = charon->ike_sa_manager->checkout_by_ids(charon->ike_sa_manager,
this->policy->get_my_id(this->policy),
this->policy->get_other_id(this->policy));
this->connection->get_ref(this->connection); this->connection->get_ref(this->connection);
this->policy->get_ref(this->policy); this->policy->get_ref(this->policy);
status = ike_sa->initiate(ike_sa, this->connection, this->policy); if (ike_sa->initiate(ike_sa, this->connection, this->policy) != SUCCESS)
if (status != SUCCESS)
{ {
this->logger->log(this->logger, ERROR, this->logger->log(this->logger, ERROR,
"initiation returned %s, going to delete IKE_SA.", "initiation failed, going to delete IKE_SA");
mapping_find(status_m, status));
charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa); charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa);
return DESTROY_ME; return DESTROY_ME;
} }
@@ -99,7 +93,7 @@ static status_t execute(private_initiate_ike_sa_job_t *this)
/** /**
* Implements job_t.destroy. * Implements job_t.destroy.
*/ */
static void destroy(private_initiate_ike_sa_job_t *this) static void destroy(private_initiate_job_t *this)
{ {
this->connection->destroy(this->connection); this->connection->destroy(this->connection);
this->policy->destroy(this->policy); this->policy->destroy(this->policy);
@@ -109,9 +103,9 @@ static void destroy(private_initiate_ike_sa_job_t *this)
/* /*
* Described in header * Described in header
*/ */
initiate_ike_sa_job_t *initiate_ike_sa_job_create(connection_t *connection, policy_t *policy) initiate_job_t *initiate_job_create(connection_t *connection, policy_t *policy)
{ {
private_initiate_ike_sa_job_t *this = malloc_thing(private_initiate_ike_sa_job_t); private_initiate_job_t *this = malloc_thing(private_initiate_job_t);
/* interface functions */ /* interface functions */
this->public.job_interface.get_type = (job_type_t (*) (job_t *)) get_type; this->public.job_interface.get_type = (job_type_t (*) (job_t *)) get_type;
@@ -1,7 +1,7 @@
/** /**
* @file initiate_ike_sa_job.h * @file initiate_job.h
* *
* @brief Interface of initiate_ike_sa_job_t. * @brief Interface of initiate_job_t.
*/ */
/* /*
@@ -29,7 +29,7 @@
#include <config/policies/policy.h> #include <config/policies/policy.h>
typedef struct initiate_ike_sa_job_t initiate_ike_sa_job_t; typedef struct initiate_job_t initiate_job_t;
/** /**
* @brief Class representing an INITIATE_IKE_SA Job. * @brief Class representing an INITIATE_IKE_SA Job.
@@ -37,11 +37,11 @@ typedef struct initiate_ike_sa_job_t initiate_ike_sa_job_t;
* This job is created if an IKE_SA should be iniated. * This job is created if an IKE_SA should be iniated.
* *
* @b Constructors: * @b Constructors:
* - initiate_ike_sa_job_create() * - initiate_job_create()
* *
* @ingroup jobs * @ingroup jobs
*/ */
struct initiate_ike_sa_job_t { struct initiate_job_t {
/** /**
* implements job_t interface * implements job_t interface
*/ */
@@ -51,13 +51,13 @@ struct initiate_ike_sa_job_t {
/** /**
* @brief Creates a job of type INITIATE_IKE_SA. * @brief Creates a job of type INITIATE_IKE_SA.
* *
* @param connection connection_t to initializes * @param connection connection_t to initialize
* @param policy policy to set up * @param policy policy to set up
* @return initiate_ike_sa_job_t object * @return initiate_job_t object
* *
* @ingroup jobs * @ingroup jobs
*/ */
initiate_ike_sa_job_t *initiate_ike_sa_job_create(connection_t *connection, initiate_job_t *initiate_job_create(connection_t *connection,
policy_t *policy); policy_t *policy);
#endif /*INITIATE_IKE_SA_JOB_H_*/ #endif /*INITIATE_IKE_SA_JOB_H_*/
+1 -1
View File
@@ -28,7 +28,7 @@
mapping_t job_type_m[] = { mapping_t job_type_m[] = {
{INCOMING_PACKET, "INCOMING_PACKET"}, {INCOMING_PACKET, "INCOMING_PACKET"},
{RETRANSMIT_REQUEST, "RETRANSMIT_REQUEST"}, {RETRANSMIT_REQUEST, "RETRANSMIT_REQUEST"},
{INITIATE_IKE_SA, "INITIATE_IKE_SA"}, {INITIATE, "INITIATE"},
{DELETE_HALF_OPEN_IKE_SA, "DELETE_HALF_OPEN_IKE_SA"}, {DELETE_HALF_OPEN_IKE_SA, "DELETE_HALF_OPEN_IKE_SA"},
{DELETE_ESTABLISHED_IKE_SA, "DELETE_ESTABLISHED_IKE_SA"}, {DELETE_ESTABLISHED_IKE_SA, "DELETE_ESTABLISHED_IKE_SA"},
{SEND_KEEPALIVE, "SEND_KEEPALIVE"}, {SEND_KEEPALIVE, "SEND_KEEPALIVE"},
+3 -3
View File
@@ -51,11 +51,11 @@ enum job_type_t {
RETRANSMIT_REQUEST, RETRANSMIT_REQUEST,
/** /**
* Establish an ike sa as initiator. * Set up a CHILD_SA, optional with an IKE_SA.
* *
* Job is implemented in class initiate_ike_sa_job_t * Job is implemented in class initiate_job_t
*/ */
INITIATE_IKE_SA, INITIATE,
/** /**
* Delete an ike sa which is still not established. * Delete an ike sa which is still not established.
@@ -66,10 +66,9 @@ static job_type_t get_type(private_retransmit_request_job_t *this)
static status_t execute(private_retransmit_request_job_t *this) static status_t execute(private_retransmit_request_job_t *this)
{ {
ike_sa_t *ike_sa; ike_sa_t *ike_sa;
status_t status;
status = charon->ike_sa_manager->checkout(charon->ike_sa_manager, this->ike_sa_id, &ike_sa); ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager, this->ike_sa_id);
if (status != SUCCESS) if (ike_sa == NULL)
{ {
this->logger->log(this->logger, ERROR|LEVEL1, this->logger->log(this->logger, ERROR|LEVEL1,
"IKE SA could not be checked out. Already deleted?"); "IKE SA could not be checked out. Already deleted?");
+5 -6
View File
@@ -65,16 +65,15 @@ static job_type_t get_type(private_send_dpd_job_t *this)
static status_t execute(private_send_dpd_job_t *this) static status_t execute(private_send_dpd_job_t *this)
{ {
ike_sa_t *ike_sa; ike_sa_t *ike_sa;
status_t status;
status = charon->ike_sa_manager->checkout(charon->ike_sa_manager, ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
this->ike_sa_id, &ike_sa); this->ike_sa_id);
if (status != SUCCESS) if (ike_sa == NULL)
{ {
return DESTROY_ME; return DESTROY_ME;
} }
status = ike_sa->send_dpd(ike_sa);
if (status == DESTROY_ME) if (ike_sa->send_dpd(ike_sa) == DESTROY_ME)
{ {
charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa); charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa);
} }
+3 -4
View File
@@ -65,11 +65,10 @@ static job_type_t get_type(private_send_keepalive_job_t *this)
static status_t execute(private_send_keepalive_job_t *this) static status_t execute(private_send_keepalive_job_t *this)
{ {
ike_sa_t *ike_sa; ike_sa_t *ike_sa;
status_t status;
status = charon->ike_sa_manager->checkout(charon->ike_sa_manager, ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
this->ike_sa_id, &ike_sa); this->ike_sa_id);
if (status != SUCCESS) if (ike_sa == NULL)
{ {
return DESTROY_ME; return DESTROY_ME;
} }
+47 -1
View File
@@ -110,6 +110,16 @@ struct private_child_sa_t {
*/ */
u_int32_t reqid; u_int32_t reqid;
/**
* encryption algorithm used for this SA
*/
algorithm_t encryption;
/**
* integrity protection algorithm used for this SA
*/
algorithm_t integrity;
/** /**
* time, on which SA was installed * time, on which SA was installed
*/ */
@@ -358,6 +368,8 @@ static status_t install(private_child_sa_t *this, proposal_t *proposal, prf_plus
enc_algo, int_algo, enc_algo, int_algo,
prf_plus, natt, mine); prf_plus, natt, mine);
this->encryption = *enc_algo;
this->integrity = *int_algo;
this->install_time = time(NULL); this->install_time = time(NULL);
return status; return status;
@@ -574,6 +586,8 @@ static void log_status(private_child_sa_t *this, logger_t *logger, char* name)
char use_in_str[12] = "unused"; char use_in_str[12] = "unused";
char use_out_str[12] = "unused"; char use_out_str[12] = "unused";
char rekey_str[12] = "disabled"; char rekey_str[12] = "disabled";
char enc_str[32] = "";
char int_str[32] = "";
u_int32_t use_in, use_out, use_fwd, now, rekeying; u_int32_t use_in, use_out, use_fwd, now, rekeying;
status_t status; status_t status;
@@ -604,10 +618,38 @@ static void log_status(private_child_sa_t *this, logger_t *logger, char* name)
snprintf(rekey_str, sizeof(rekey_str), "%ds", (int)rekeying); snprintf(rekey_str, sizeof(rekey_str), "%ds", (int)rekeying);
} }
/* algorithms used */
if (this->protocol == PROTO_ESP)
{
if (this->encryption.key_size)
{
snprintf(enc_str, sizeof(enc_str), "%s-%d,",
mapping_find(encryption_algorithm_m, this->encryption.algorithm),
this->encryption.key_size);
}
else
{
snprintf(enc_str, sizeof(enc_str), "%s,",
mapping_find(encryption_algorithm_m, this->encryption.algorithm));
}
}
if (this->integrity.key_size)
{
snprintf(int_str, sizeof(int_str), "%s-%d",
mapping_find(integrity_algorithm_m, this->integrity.algorithm),
this->integrity.key_size);
}
else
{
snprintf(int_str, sizeof(int_str), "%s",
mapping_find(integrity_algorithm_m, this->integrity.algorithm));
}
logger->log(logger, CONTROL|LEVEL1, logger->log(logger, CONTROL|LEVEL1,
" \"%s\": using %s, SPIs (in/out): 0x%x/0x%x, reqid: %d", " \"%s\": %s (%s%s), SPIs (in/out): 0x%x/0x%x, reqid: %d",
name, name,
this->protocol == PROTO_ESP ? "ESP" : "AH", this->protocol == PROTO_ESP ? "ESP" : "AH",
enc_str, int_str,
htonl(this->me.spi), htonl(this->other.spi), htonl(this->me.spi), htonl(this->other.spi),
this->reqid); this->reqid);
logger->log(logger, CONTROL|LEVEL1, logger->log(logger, CONTROL|LEVEL1,
@@ -898,6 +940,10 @@ child_sa_t * child_sa_create(u_int32_t rekey, host_t *me, host_t* other,
this->state = CHILD_CREATED; this->state = CHILD_CREATED;
/* reuse old reqid if we are rekeying an existing CHILD_SA */ /* reuse old reqid if we are rekeying an existing CHILD_SA */
this->reqid = rekey ? rekey : ++reqid; this->reqid = rekey ? rekey : ++reqid;
this->encryption.algorithm = ENCR_UNDEFINED;
this->encryption.key_size = 0;
this->integrity.algorithm = AUTH_UNDEFINED;
this->encryption.key_size = 0;
this->policies = linked_list_create(); this->policies = linked_list_create();
this->my_ts = linked_list_create(); this->my_ts = linked_list_create();
this->other_ts = linked_list_create(); this->other_ts = linked_list_create();
+44 -12
View File
@@ -782,23 +782,53 @@ static status_t process_message(private_ike_sa_t *this, message_t *message)
static status_t initiate(private_ike_sa_t *this, static status_t initiate(private_ike_sa_t *this,
connection_t *connection, policy_t *policy) connection_t *connection, policy_t *policy)
{ {
ike_sa_init_t *ike_sa_init; switch (this->state)
{
case IKE_CREATED:
{
/* in state CREATED, we must do the ike_sa_init
* and ike_auth transactions. Along with these,
* a CHILD_SA with the supplied policy is set up.
*/
ike_sa_init_t *ike_sa_init;
set_name(this, connection->get_name(connection)); set_name(this, connection->get_name(connection));
this->my_host = connection->get_my_host(connection);
this->my_host = this->my_host->clone(this->my_host);
this->other_host = connection->get_other_host(connection);
this->other_host = this->other_host->clone(this->other_host);
/* apply hosts from connection */ this->message_id_out = 1;
this->my_host = connection->get_my_host(connection); ike_sa_init = ike_sa_init_create(&this->public);
this->my_host = this->my_host->clone(this->my_host); ike_sa_init->set_config(ike_sa_init, connection, policy);
this->other_host = connection->get_other_host(connection); return queue_transaction(this, (transaction_t*)ike_sa_init, TRUE);
this->other_host = this->other_host->clone(this->other_host); }
case IKE_DELETING:
{
/* if we are in DELETING, we deny set up of a policy. */
policy->destroy(policy);
connection->destroy(connection);
return FAILED;
}
case IKE_CONNECTING:
case IKE_ESTABLISHED:
{
/* if we are ESTABLISHED or CONNECTING,we queue the
* transaction to create the CHILD_SA. It gets processed
* when the IKE_SA is ready to do so. We don't need the
* connection, as the IKE_SA is already established/establishing.
*/
create_child_sa_t *create_child;
this->message_id_out = 1; connection->destroy(connection);
ike_sa_init = ike_sa_init_create(&this->public); create_child = create_child_sa_create(&this->public);
ike_sa_init->set_config(ike_sa_init, connection, policy); create_child->set_policy(create_child, policy);
return queue_transaction(this, (transaction_t*)ike_sa_init, TRUE); return queue_transaction(this, (transaction_t*)create_child, FALSE);
}
}
return FAILED;
} }
/** /**
* Implementation of ike_sa_t.acquire. * Implementation of ike_sa_t.acquire.
*/ */
@@ -990,6 +1020,7 @@ static identification_t* get_my_id(private_ike_sa_t *this)
*/ */
static void set_my_id(private_ike_sa_t *this, identification_t *me) static void set_my_id(private_ike_sa_t *this, identification_t *me)
{ {
DESTROY_IF(this->my_id);
this->my_id = me; this->my_id = me;
} }
@@ -1006,6 +1037,7 @@ static identification_t* get_other_id(private_ike_sa_t *this)
*/ */
static void set_other_id(private_ike_sa_t *this, identification_t *other) static void set_other_id(private_ike_sa_t *this, identification_t *other)
{ {
DESTROY_IF(this->other_id);
this->other_id = other; this->other_id = other;
} }
+127 -105
View File
@@ -333,6 +333,34 @@ static status_t delete_entry(private_ike_sa_manager_t *this, ike_sa_entry_t *ent
return status; return status;
} }
/**
* Wait until no other thread is using an IKE_SA, return FALSE if entry not
* acquireable
*/
static bool wait_for_entry(private_ike_sa_manager_t *this, ike_sa_entry_t *entry)
{
if (entry->driveout_new_threads)
{
/* we are not allowed to get this */
return FALSE;
}
while (entry->checked_out && !entry->driveout_waiting_threads)
{
/* 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--;
}
/* hm, a deletion request forbids us to get this SA, get next one */
if (entry->driveout_waiting_threads)
{
/* we must signal here, others may be waiting on it, too */
pthread_cond_signal(&(entry->condvar));
return FALSE;
}
return TRUE;
}
/** /**
* Implementation of private_ike_sa_manager_t.get_next_spi. * Implementation of private_ike_sa_manager_t.get_next_spi.
@@ -349,48 +377,92 @@ static u_int64_t get_next_spi(private_ike_sa_manager_t *this)
/** /**
* Implementation of of ike_sa_manager.create_and_checkout. * Implementation of of ike_sa_manager.create_and_checkout.
*/ */
static void create_and_checkout(private_ike_sa_manager_t *this,ike_sa_t **ike_sa) static ike_sa_t* checkout_by_ids(private_ike_sa_manager_t *this,
identification_t *my_id,
identification_t *other_id)
{ {
u_int64_t initiator_spi; iterator_t *iterator;
ike_sa_entry_t *new_ike_sa_entry; ike_sa_t *ike_sa = NULL;
ike_sa_id_t *new_ike_sa_id;
initiator_spi = this->get_next_spi(this);
new_ike_sa_id = ike_sa_id_create(0, 0, TRUE);
new_ike_sa_id->set_initiator_spi(new_ike_sa_id, initiator_spi);
/* create entry */
new_ike_sa_entry = ike_sa_entry_create(new_ike_sa_id);
this->logger->log(this->logger, CONTROL|LEVEL2,
"created IKE_SA %llx:%llx, role %s",
new_ike_sa_id->get_initiator_spi(new_ike_sa_id),
new_ike_sa_id->get_responder_spi(new_ike_sa_id),
new_ike_sa_id->is_initiator(new_ike_sa_id) ? "initiator" : "responder");
new_ike_sa_id->destroy(new_ike_sa_id);
/* each access is locked */
pthread_mutex_lock(&(this->mutex)); pthread_mutex_lock(&(this->mutex));
this->ike_sa_list->insert_last(this->ike_sa_list, new_ike_sa_entry); iterator = this->ike_sa_list->create_iterator(this->ike_sa_list, TRUE);
while (iterator->has_next(iterator))
{
ike_sa_entry_t *entry;
identification_t *found_my_id, *found_other_id;
int wc;
/* check ike_sa out */ iterator->current(iterator, (void**)&entry);
this->logger->log(this->logger, CONTROL|LEVEL1, if (!wait_for_entry(this, entry))
"new IKE_SA created and added to list of known IKE_SA's"); {
new_ike_sa_entry->checked_out = TRUE; continue;
*ike_sa = new_ike_sa_entry->ike_sa; }
found_my_id = entry->ike_sa->get_my_id(entry->ike_sa);
found_other_id = entry->ike_sa->get_other_id(entry->ike_sa);
if (!found_my_id || !found_other_id)
{
/* IKE_SA has no IDs yet, so we can't use it */
continue;
}
if (found_my_id->matches(found_my_id, my_id, &wc) &&
found_other_id->matches(found_other_id, other_id, &wc))
{
/* looks good, we take this one */
this->logger->log(this->logger, CONTROL|LEVEL1,
"found an existing IKE_SA for IDs %s - %s",
my_id->get_string(my_id), other_id->get_string(other_id));
entry->checked_out = TRUE;
ike_sa = entry->ike_sa;
}
}
iterator->destroy(iterator);
if (!ike_sa)
{
u_int64_t initiator_spi;
ike_sa_entry_t *new_ike_sa_entry;
ike_sa_id_t *new_ike_sa_id;
initiator_spi = this->get_next_spi(this);
new_ike_sa_id = ike_sa_id_create(0, 0, TRUE);
new_ike_sa_id->set_initiator_spi(new_ike_sa_id, initiator_spi);
/* create entry */
new_ike_sa_entry = ike_sa_entry_create(new_ike_sa_id);
this->logger->log(this->logger, CONTROL|LEVEL2,
"created IKE_SA %llx:%llx, role %s",
new_ike_sa_id->get_initiator_spi(new_ike_sa_id),
new_ike_sa_id->get_responder_spi(new_ike_sa_id),
new_ike_sa_id->is_initiator(new_ike_sa_id) ? "initiator" : "responder");
new_ike_sa_id->destroy(new_ike_sa_id);
this->ike_sa_list->insert_last(this->ike_sa_list, new_ike_sa_entry);
/* check ike_sa out */
this->logger->log(this->logger, CONTROL|LEVEL1,
"new IKE_SA created for IDs %s - %s",
my_id->get_string(my_id), other_id->get_string(other_id));
new_ike_sa_entry->checked_out = TRUE;
ike_sa = new_ike_sa_entry->ike_sa;
}
pthread_mutex_unlock(&(this->mutex)); pthread_mutex_unlock(&(this->mutex));
return ike_sa;
} }
/** /**
* Implementation of of ike_sa_manager.checkout. * Implementation of of ike_sa_manager.checkout.
*/ */
static status_t checkout(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id, ike_sa_t **ike_sa) static ike_sa_t* checkout(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id)
{ {
bool responder_spi_set; bool responder_spi_set;
bool initiator_spi_set; bool initiator_spi_set;
bool original_initiator; bool original_initiator;
status_t retval; ike_sa_t *ike_sa = NULL;
this->logger->log(this->logger, CONTROL|LEVEL2, this->logger->log(this->logger, CONTROL|LEVEL2,
"checkout IKE_SA %llx:%llx, role %s", "checkout IKE_SA %llx:%llx, role %s",
@@ -418,56 +490,25 @@ static status_t checkout(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id,
/* look for the entry */ /* look for the entry */
if (this->get_entry_by_id(this, ike_sa_id, &entry) == SUCCESS) if (this->get_entry_by_id(this, ike_sa_id, &entry) == SUCCESS)
{ {
/* can we give this ike_sa out to new requesters?*/ if (wait_for_entry(this, entry))
if (entry->driveout_new_threads)
{ {
this->logger->log(this->logger, CONTROL|LEVEL1, this->logger->log(this->logger, CONTROL|LEVEL2,
"drive out new thread for existing IKE_SA"); "IKE_SA successfully checked out");
/* no we can't */ /* ok, this IKE_SA is finally ours */
retval = NOT_FOUND; entry->checked_out = TRUE;
ike_sa = entry->ike_sa;
} }
else else
{ {
/* is this IKE_SA already checked out ?? this->logger->log(this->logger, CONTROL|LEVEL2,
* are we welcome to get this SA ? */ "IKE_SA found, but not allowed to check it out");
while (entry->checked_out && !entry->driveout_waiting_threads)
{
/* 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--;
}
/* hm, a deletion request forbids us to get this SA, go home */
if (entry->driveout_waiting_threads)
{
/* we must signal here, others are interested that we leave */
pthread_cond_signal(&(entry->condvar));
this->logger->log(this->logger, CONTROL|LEVEL1,
"drive out waiting thread for existing IKE_SA");
retval = NOT_FOUND;
}
else
{
this->logger->log(this->logger, CONTROL|LEVEL2,
"IKE SA successfully checked out");
/* ok, this IKE_SA is finally ours */
entry->checked_out = TRUE;
*ike_sa = entry->ike_sa;
/* DON'T use return, we must unlock the mutex! */
retval = SUCCESS;
}
} }
} }
else else
{ {
this->logger->log(this->logger, ERROR|LEVEL1, this->logger->log(this->logger, ERROR|LEVEL1,
"IKE SA not stored in known IKE_SA list"); "IKE_SA not stored in list");
/* looks like there is no such IKE_SA, better luck next time... */ /* looks like there is no such IKE_SA, better luck next time... */
/* DON'T use return, we must unlock the mutex! */
retval = NOT_FOUND;
} }
} }
else if ((initiator_spi_set && !responder_spi_set) && (!original_initiator)) else if ((initiator_spi_set && !responder_spi_set) && (!original_initiator))
@@ -496,23 +537,18 @@ static status_t checkout(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id,
/* check ike_sa out */ /* check ike_sa out */
this->logger->log(this->logger, CONTROL|LEVEL1, this->logger->log(this->logger, CONTROL|LEVEL1,
"IKE_SA added to list of known IKE_SA's"); "IKE_SA added to list of known IKE_SAs");
new_ike_sa_entry->checked_out = TRUE; new_ike_sa_entry->checked_out = TRUE;
*ike_sa = new_ike_sa_entry->ike_sa; ike_sa = new_ike_sa_entry->ike_sa;
retval = SUCCESS;
} }
else else
{ {
/* responder set, initiator not: here is something seriously wrong! */ /* responder set, initiator not: here is something seriously wrong! */
this->logger->log(this->logger, ERROR|LEVEL1, "invalid IKE_SA SPI's"); this->logger->log(this->logger, ERROR|LEVEL1, "invalid IKE_SA SPIs");
/* DON'T use return, we must unlock the mutex! */
retval = INVALID_ARG;
} }
pthread_mutex_unlock(&(this->mutex)); pthread_mutex_unlock(&(this->mutex));
/* OK, unlocked... */ return ike_sa;
return retval;
} }
/** /**
@@ -533,34 +569,17 @@ static status_t checkout_by_child(private_ike_sa_manager_t *this,
ike_sa_entry_t *entry; ike_sa_entry_t *entry;
iterator->current(iterator, (void**)&entry); iterator->current(iterator, (void**)&entry);
if (entry->driveout_new_threads) if (wait_for_entry(this, entry))
{ {
/* we are not allowed to get this, get next one */ /* ok, access is exclusive for us, check for child */
continue; if (entry->ike_sa->get_child_sa(entry->ike_sa, protocol, spi, TRUE) != NULL)
} {
while (entry->checked_out && !entry->driveout_waiting_threads) /* match */
{ entry->checked_out = TRUE;
/* so wait until we can get it for us. *ike_sa = entry->ike_sa;
* we register us as waiting. */ status = SUCCESS;
entry->waiting_threads++; break;
pthread_cond_wait(&(entry->condvar), &(this->mutex)); }
entry->waiting_threads--;
}
/* hm, a deletion request forbids us to get this SA, get next one */
if (entry->driveout_waiting_threads)
{
/* we must signal here, others may be waiting on it, too */
pthread_cond_signal(&(entry->condvar));
continue;
}
/* ok, access is exclusive for us, check for child */
if (entry->ike_sa->get_child_sa(entry->ike_sa, protocol, spi, TRUE) != NULL)
{
/* match */
entry->checked_out = TRUE;
*ike_sa = entry->ike_sa;
status = SUCCESS;
break;
} }
} }
iterator->destroy(iterator); iterator->destroy(iterator);
@@ -640,7 +659,10 @@ static void log_status(private_ike_sa_manager_t* this, logger_t* logger, char* n
ike_sa_entry_t *entry; ike_sa_entry_t *entry;
iterator->current(iterator, (void**)&entry); iterator->current(iterator, (void**)&entry);
entry->ike_sa->log_status(entry->ike_sa, logger, name); if (wait_for_entry(this, entry))
{
entry->ike_sa->log_status(entry->ike_sa, logger, name);
}
} }
iterator->destroy(iterator); iterator->destroy(iterator);
@@ -891,8 +913,8 @@ ike_sa_manager_t *ike_sa_manager_create()
/* assign public functions */ /* assign public functions */
this->public.destroy = (void(*)(ike_sa_manager_t*))destroy; 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_by_ids = (ike_sa_t*(*)(ike_sa_manager_t*,identification_t*,identification_t*))checkout_by_ids;
this->public.checkout = (status_t(*)(ike_sa_manager_t*, ike_sa_id_t*,ike_sa_t**))checkout; this->public.checkout = (ike_sa_t*(*)(ike_sa_manager_t*, ike_sa_id_t*))checkout;
this->public.checkout_by_child = (status_t(*)(ike_sa_manager_t*,protocol_id_t,u_int32_t,ike_sa_t**))checkout_by_child; this->public.checkout_by_child = (status_t(*)(ike_sa_manager_t*,protocol_id_t,u_int32_t,ike_sa_t**))checkout_by_child;
this->public.get_ike_sa_list = (linked_list_t*(*)(ike_sa_manager_t*))get_ike_sa_list; this->public.get_ike_sa_list = (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.get_ike_sa_list_by_name = (linked_list_t*(*)(ike_sa_manager_t*,const char*))get_ike_sa_list_by_name;
+17 -14
View File
@@ -52,8 +52,8 @@ struct ike_sa_manager_t {
/** /**
* @brief Checkout an IKE_SA, create it when necesarry. * @brief Checkout an IKE_SA, create it when necesarry.
* *
* Checks out a SA by its ID. An SA will be created, when: * Checks out a SA by its ID. An SA will be created, when the responder
* - Responder SPI is not set (when received an IKE_SA_INIT from initiator) * SPI is not set (when received an IKE_SA_INIT from initiator).
* Management of SPIs is the managers job, he will set it. * Management of SPIs is the managers job, he will set it.
* This function blocks until SA is available for checkout. * This function blocks until SA is available for checkout.
* *
@@ -62,24 +62,27 @@ struct ike_sa_manager_t {
* *
* @param this the manager object * @param this the manager object
* @param[in/out] ike_sa_id the SA identifier, will be updated * @param[in/out] ike_sa_id the SA identifier, will be updated
* @param[out] ike_sa checked out SA
* @returns * @returns
* - SUCCESS if checkout successful * - checked out IKE_SA if found
* - NOT_FOUND when no such SA is available * - NULL, if no such IKE_SA available
* - CREATED if a new IKE_SA got created
*/ */
status_t (*checkout) (ike_sa_manager_t* this, ike_sa_id_t *sa_id, ike_sa_t **ike_sa); ike_sa_t* (*checkout) (ike_sa_manager_t* this, ike_sa_id_t *sa_id);
/** /**
* @brief Create and checkout an IKE_SA as original initator. * @brief Checkout an IKE_SA by two identifications.
* *
* Creates and checks out a SA as initiator. * Allows the lookup of an IKE_SA by two user IDs. It returns the
* Management of SPIs is the managers job, he will set it. * first found occurence, if there are multiple canddates. Supplied IDs
* may contain wildcards. If no IKE_SA is found, a new one is created.
* *
* @param this the manager object * @param this the manager object
* @param[out] ike_sa checked out SA * @param my_id ID used by us
* @param other_id ID used by other
* @return checked out/created IKE_SA
*/ */
void (*create_and_checkout) (ike_sa_manager_t* this,ike_sa_t **ike_sa); ike_sa_t* (*checkout_by_ids) (ike_sa_manager_t* this,
identification_t *my_id,
identification_t *other_id);
/** /**
* @brief Check out an IKE_SA by protocol and SPI of one of its CHILD_SA. * @brief Check out an IKE_SA by protocol and SPI of one of its CHILD_SA.
@@ -102,7 +105,7 @@ struct ike_sa_manager_t {
/** /**
* @brief Get a list of all IKE_SA SAs currently set up. * @brief Get a list of all IKE_SA SAs currently set up.
* *
* The resulting list with all IDs must be destroyd by * The resulting list with all IDs must be destroyed by
* the caller. There is no guarantee an ike_sa with the * the caller. There is no guarantee an ike_sa with the
* corrensponding ID really exists, since it may be deleted * corrensponding ID really exists, since it may be deleted
* in the meantime by another thread. * in the meantime by another thread.
@@ -153,7 +156,7 @@ struct ike_sa_manager_t {
* @brief Delete a SA, which was not checked out. * @brief Delete a SA, which was not checked out.
* *
* If the state allows it, the IKE SA is destroyed immediately. If it is * If the state allows it, the IKE SA is destroyed immediately. If it is
* in the state ike_sa_established or further, a delete message * in the state ESTABLSIHED, a delete message
* is sent to the remote peer, which has to be acknowledged. * is sent to the remote peer, which has to be acknowledged.
* *
* @warning do not use this when the SA is already checked out, this will * @warning do not use this when the SA is already checked out, this will
+1 -1
View File
@@ -228,7 +228,6 @@ static status_t get_request(private_ike_auth_t *this, message_t **result)
{ /* build ID payload */ { /* build ID payload */
my_id_payload = id_payload_create_from_identification(TRUE, my_id); my_id_payload = id_payload_create_from_identification(TRUE, my_id);
request->add_payload(request, (payload_t*)my_id_payload); request->add_payload(request, (payload_t*)my_id_payload);
this->ike_sa->set_my_id(this->ike_sa, my_id->clone(my_id));
} }
{ /* TODO: build certreq payload */ { /* TODO: build certreq payload */
@@ -889,6 +888,7 @@ static status_t conclude(private_ike_auth_t *this, message_t *response,
configured_other_id->get_string(configured_other_id)); configured_other_id->get_string(configured_other_id));
return DESTROY_ME; return DESTROY_ME;
} }
/* update other ID. It was already set, but may contain wildcards */
this->ike_sa->set_other_id(this->ike_sa, other_id); this->ike_sa->set_other_id(this->ike_sa, other_id);
} }
+8
View File
@@ -269,6 +269,7 @@ static status_t get_request(private_ike_sa_init_t *this, message_t **result)
{ {
message_t *request; message_t *request;
host_t *me, *other; host_t *me, *other;
identification_t *my_id, *other_id;
/* check if we already have built a message (retransmission) */ /* check if we already have built a message (retransmission) */
if (this->message) if (this->message)
@@ -280,6 +281,13 @@ static status_t get_request(private_ike_sa_init_t *this, message_t **result)
me = this->connection->get_my_host(this->connection); me = this->connection->get_my_host(this->connection);
other = this->connection->get_other_host(this->connection); other = this->connection->get_other_host(this->connection);
/* we already set up the IDs. Mine is already fully qualified, other
* will be updated in the ike_auth transaction */
my_id = this->policy->get_my_id(this->policy);
other_id = this->policy->get_other_id(this->policy);
this->ike_sa->set_my_id(this->ike_sa, my_id->clone(my_id));
this->ike_sa->set_other_id(this->ike_sa, other_id->clone(other_id));
/* build the request */ /* build the request */
request = message_create(); request = message_create();
request->set_source(request, me->clone(me)); request->set_source(request, me->clone(me));
+21 -43
View File
@@ -37,7 +37,7 @@
#include <types.h> #include <types.h>
#include <daemon.h> #include <daemon.h>
#include <crypto/x509.h> #include <crypto/x509.h>
#include <queues/jobs/initiate_ike_sa_job.h> #include <queues/jobs/initiate_job.h>
#define IKE_PORT 500 #define IKE_PORT 500
#define PATH_BUF 256 #define PATH_BUF 256
@@ -477,11 +477,9 @@ static void stroke_del_conn(private_stroke_t *this, stroke_msg_t *msg)
*/ */
static void stroke_initiate(private_stroke_t *this, stroke_msg_t *msg) static void stroke_initiate(private_stroke_t *this, stroke_msg_t *msg)
{ {
initiate_ike_sa_job_t *job; initiate_job_t *job;
connection_t *connection; connection_t *connection;
policy_t *policy; policy_t *policy;
linked_list_t *ike_sas;
ike_sa_id_t *ike_sa_id;
pop_string(msg, &(msg->initiate.name)); pop_string(msg, &(msg->initiate.name));
this->logger->log(this->logger, CONTROL, this->logger->log(this->logger, CONTROL,
@@ -495,49 +493,29 @@ static void stroke_initiate(private_stroke_t *this, stroke_msg_t *msg)
this->stroke_logger->log(this->stroke_logger, ERROR, this->stroke_logger->log(this->stroke_logger, ERROR,
"no connection named \"%s\"", "no connection named \"%s\"",
msg->initiate.name); msg->initiate.name);
return;
} }
/* only initiate if it is an IKEv2 connection, ignore IKEv1 */ if (!connection->is_ikev2(connection))
else if (connection->is_ikev2(connection))
{
policy = charon->policies->get_policy_by_name(charon->policies,
msg->initiate.name);
if (policy == NULL)
{
this->stroke_logger->log(this->stroke_logger, ERROR,
"no policy named \"%s\"",
msg->initiate.name);
connection->destroy(connection);
return;
}
/* check for already set up IKE_SAs befor initiating */
ike_sas = charon->ike_sa_manager->get_ike_sa_list_by_name(charon->ike_sa_manager,
msg->initiate.name);
if (ike_sas->get_count(ike_sas) > 0)
{
this->stroke_logger->log(this->stroke_logger, CONTROL,
"connection \"%s\" already up",
msg->initiate.name);
/* TODO: setup CHILD_SA with policy */
connection->destroy(connection);
ike_sas->destroy(ike_sas);
return;
}
this->stroke_logger->log(this->stroke_logger, CONTROL,
"initiating connection \"%s\" (see log)...",
msg->initiate.name);
job = initiate_ike_sa_job_create(connection, policy);
charon->job_queue->add(charon->job_queue, (job_t*)job);
while (ike_sas->remove_last(ike_sas, (void**)&ike_sa_id) == SUCCESS)
{
ike_sa_id->destroy(ike_sa_id);
}
ike_sas->destroy(ike_sas);
}
else
{ {
connection->destroy(connection); connection->destroy(connection);
return;
} }
policy = charon->policies->get_policy_by_name(charon->policies,
msg->initiate.name);
if (policy == NULL)
{
this->stroke_logger->log(this->stroke_logger, ERROR,
"no policy named \"%s\"",
msg->initiate.name);
connection->destroy(connection);
return;
}
this->stroke_logger->log(this->stroke_logger, CONTROL,
"initiating connection \"%s\" (see log)...",
msg->initiate.name);
job = initiate_job_create(connection, policy);
charon->job_queue->add(charon->job_queue, (job_t*)job);
} }
/** /**
+14 -14
View File
@@ -31,20 +31,20 @@
* String mappings for encryption_algorithm_t. * String mappings for encryption_algorithm_t.
*/ */
mapping_t encryption_algorithm_m[] = { mapping_t encryption_algorithm_m[] = {
{ENCR_UNDEFINED, "ENCR_UNDEFINED"}, {ENCR_UNDEFINED, "UNDEFINED"},
{ENCR_DES_IV64, "ENCR_DES_IV64"}, {ENCR_DES_IV64, "DES_IV64"},
{ENCR_DES, "ENCR_DES"}, {ENCR_DES, "DES"},
{ENCR_3DES, "ENCR_3DES"}, {ENCR_3DES, "3DES"},
{ENCR_RC5, "ENCR_RC5"}, {ENCR_RC5, "RC5"},
{ENCR_IDEA, "ENCR_IDEA"}, {ENCR_IDEA, "IDEA"},
{ENCR_CAST, "ENCR_CAST"}, {ENCR_CAST, "CAST"},
{ENCR_BLOWFISH, "ENCR_BLOWFISH"}, {ENCR_BLOWFISH, "BLOWFISH"},
{ENCR_3IDEA, "ENCR_3IDEA"}, {ENCR_3IDEA, "3IDEA"},
{ENCR_DES_IV32, "ENCR_DES_IV32"}, {ENCR_DES_IV32, "DES_IV32"},
{ENCR_NULL, "ENCR_NULL"}, {ENCR_NULL, "NULL"},
{ENCR_AES_CBC, "ENCR_AES_CBC"}, {ENCR_AES_CBC, "AES_CBC"},
{ENCR_AES_CTR, "ENCR_AES_CTR"}, {ENCR_AES_CTR, "AES_CTR"},
{MAPPING_END, NULL} {MAPPING_END, NULL}
}; };
/* /*
+6 -6
View File
@@ -29,12 +29,12 @@
* String mappings for integrity_algorithm_t. * String mappings for integrity_algorithm_t.
*/ */
mapping_t integrity_algorithm_m[] = { mapping_t integrity_algorithm_m[] = {
{AUTH_UNDEFINED, "AUTH_UNDEFINED"}, {AUTH_UNDEFINED, "UNDEFINED"},
{AUTH_HMAC_MD5_96, "AUTH_HMAC_MD5_96"}, {AUTH_HMAC_MD5_96, "HMAC_MD5_96"},
{AUTH_HMAC_SHA1_96, "AUTH_HMAC_SHA1_96"}, {AUTH_HMAC_SHA1_96, "HMAC_SHA1_96"},
{AUTH_DES_MAC, "AUTH_DES_MAC"}, {AUTH_DES_MAC, "DES_MAC"},
{AUTH_KPDK_MD5, "AUTH_KPDK_MD5"}, {AUTH_KPDK_MD5, "KPDK_MD5"},
{AUTH_AES_XCBC_96, "AUTH_AES_XCBC_96"}, {AUTH_AES_XCBC_96, "AES_XCBC_96"},
{MAPPING_END, NULL} {MAPPING_END, NULL}
}; };