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.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 \
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/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/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 \
@@ -62,9 +62,10 @@ static status_t execute(private_delete_half_open_ike_sa_job_t *this)
{
ike_sa_t *ike_sa;
if (charon->ike_sa_manager->checkout(charon->ike_sa_manager, this->ike_sa_id,
&ike_sa) != SUCCESS)
ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager, this->ike_sa_id);
if (ike_sa == NULL)
{
/* hm, somebody was faster ;-) */
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 = ike_sa_id->clone(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);
if (status != SUCCESS)
ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager, ike_sa_id);
if (ike_sa == NULL)
{
this->logger->log(this->logger, ERROR,
"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);
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
{
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);
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 "initiate_ike_sa_job.h"
#include "initiate_job.h"
#include <daemon.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
@@ -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.
*/
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;
status_t status;
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);
this->logger->log(this->logger, CONTROL|LEVEL2, "getting an 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->policy->get_ref(this->policy);
status = ike_sa->initiate(ike_sa, this->connection, this->policy);
if (status != SUCCESS)
if (ike_sa->initiate(ike_sa, this->connection, this->policy) != SUCCESS)
{
this->logger->log(this->logger, ERROR,
"initiation returned %s, going to delete IKE_SA.",
mapping_find(status_m, status));
"initiation failed, going to delete IKE_SA");
charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa);
return DESTROY_ME;
}
@@ -99,7 +93,7 @@ static status_t execute(private_initiate_ike_sa_job_t *this)
/**
* 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->policy->destroy(this->policy);
@@ -109,9 +103,9 @@ static void destroy(private_initiate_ike_sa_job_t *this)
/*
* 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 */
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>
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.
@@ -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.
*
* @b Constructors:
* - initiate_ike_sa_job_create()
* - initiate_job_create()
*
* @ingroup jobs
*/
struct initiate_ike_sa_job_t {
struct initiate_job_t {
/**
* implements job_t interface
*/
@@ -51,13 +51,13 @@ struct initiate_ike_sa_job_t {
/**
* @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
* @return initiate_ike_sa_job_t object
* @return initiate_job_t object
*
* @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);
#endif /*INITIATE_IKE_SA_JOB_H_*/
+1 -1
View File
@@ -28,7 +28,7 @@
mapping_t job_type_m[] = {
{INCOMING_PACKET, "INCOMING_PACKET"},
{RETRANSMIT_REQUEST, "RETRANSMIT_REQUEST"},
{INITIATE_IKE_SA, "INITIATE_IKE_SA"},
{INITIATE, "INITIATE"},
{DELETE_HALF_OPEN_IKE_SA, "DELETE_HALF_OPEN_IKE_SA"},
{DELETE_ESTABLISHED_IKE_SA, "DELETE_ESTABLISHED_IKE_SA"},
{SEND_KEEPALIVE, "SEND_KEEPALIVE"},
+3 -3
View File
@@ -51,11 +51,11 @@ enum job_type_t {
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.
@@ -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)
{
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)
ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager, this->ike_sa_id);
if (ike_sa == NULL)
{
this->logger->log(this->logger, ERROR|LEVEL1,
"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)
{
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)
ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
this->ike_sa_id);
if (ike_sa == NULL)
{
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);
}
+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)
{
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)
ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
this->ike_sa_id);
if (ike_sa == NULL)
{
return DESTROY_ME;
}
+47 -1
View File
@@ -110,6 +110,16 @@ struct private_child_sa_t {
*/
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
*/
@@ -358,6 +368,8 @@ static status_t install(private_child_sa_t *this, proposal_t *proposal, prf_plus
enc_algo, int_algo,
prf_plus, natt, mine);
this->encryption = *enc_algo;
this->integrity = *int_algo;
this->install_time = time(NULL);
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_out_str[12] = "unused";
char rekey_str[12] = "disabled";
char enc_str[32] = "";
char int_str[32] = "";
u_int32_t use_in, use_out, use_fwd, now, rekeying;
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);
}
/* 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,
" \"%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,
this->protocol == PROTO_ESP ? "ESP" : "AH",
enc_str, int_str,
htonl(this->me.spi), htonl(this->other.spi),
this->reqid);
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;
/* reuse old reqid if we are rekeying an existing CHILD_SA */
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->my_ts = linked_list_create();
this->other_ts = linked_list_create();
+47 -15
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,
connection_t *connection, policy_t *policy)
{
ike_sa_init_t *ike_sa_init;
set_name(this, connection->get_name(connection));
/* apply hosts from 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);
this->message_id_out = 1;
ike_sa_init = ike_sa_init_create(&this->public);
ike_sa_init->set_config(ike_sa_init, connection, policy);
return queue_transaction(this, (transaction_t*)ike_sa_init, TRUE);
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));
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);
this->message_id_out = 1;
ike_sa_init = ike_sa_init_create(&this->public);
ike_sa_init->set_config(ike_sa_init, connection, policy);
return queue_transaction(this, (transaction_t*)ike_sa_init, TRUE);
}
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;
connection->destroy(connection);
create_child = create_child_sa_create(&this->public);
create_child->set_policy(create_child, policy);
return queue_transaction(this, (transaction_t*)create_child, FALSE);
}
}
return FAILED;
}
/**
* 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)
{
DESTROY_IF(this->my_id);
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)
{
DESTROY_IF(this->other_id);
this->other_id = other;
}
+131 -109
View File
@@ -333,6 +333,34 @@ static status_t delete_entry(private_ike_sa_manager_t *this, ike_sa_entry_t *ent
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.
@@ -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.
*/
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;
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);
/* each access is locked */
iterator_t *iterator;
ike_sa_t *ike_sa = NULL;
pthread_mutex_lock(&(this->mutex));
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 and added to list of known IKE_SA's");
new_ike_sa_entry->checked_out = TRUE;
*ike_sa = new_ike_sa_entry->ike_sa;
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;
iterator->current(iterator, (void**)&entry);
if (!wait_for_entry(this, entry))
{
continue;
}
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));
return ike_sa;
}
/**
* 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 initiator_spi_set;
bool original_initiator;
status_t retval;
ike_sa_t *ike_sa = NULL;
this->logger->log(this->logger, CONTROL|LEVEL2,
"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 */
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)
if (wait_for_entry(this, entry))
{
this->logger->log(this->logger, CONTROL|LEVEL1,
"drive out new thread for existing IKE_SA");
/* no we can't */
retval = NOT_FOUND;
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;
}
else
{
/* is this IKE_SA already checked out ??
* are we welcome to get this SA ? */
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;
}
this->logger->log(this->logger, CONTROL|LEVEL2,
"IKE_SA found, but not allowed to check it out");
}
}
else
{
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... */
/* DON'T use return, we must unlock the mutex! */
retval = NOT_FOUND;
}
}
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 */
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;
*ike_sa = new_ike_sa_entry->ike_sa;
retval = SUCCESS;
ike_sa = new_ike_sa_entry->ike_sa;
}
else
{
/* responder set, initiator not: here is something seriously wrong! */
this->logger->log(this->logger, ERROR|LEVEL1, "invalid IKE_SA SPI's");
/* DON'T use return, we must unlock the mutex! */
retval = INVALID_ARG;
this->logger->log(this->logger, ERROR|LEVEL1, "invalid IKE_SA SPIs");
}
pthread_mutex_unlock(&(this->mutex));
/* OK, unlocked... */
return retval;
return ike_sa;
}
/**
@@ -533,34 +569,17 @@ static status_t checkout_by_child(private_ike_sa_manager_t *this,
ike_sa_entry_t *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 */
continue;
}
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));
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;
/* 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);
@@ -638,9 +657,12 @@ static void log_status(private_ike_sa_manager_t* this, logger_t* logger, char* n
while (iterator->has_next(iterator))
{
ike_sa_entry_t *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);
@@ -891,8 +913,8 @@ ike_sa_manager_t *ike_sa_manager_create()
/* assign public functions */
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_ids = (ike_sa_t*(*)(ike_sa_manager_t*,identification_t*,identification_t*))checkout_by_ids;
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.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;
+19 -16
View File
@@ -52,8 +52,8 @@ struct ike_sa_manager_t {
/**
* @brief Checkout an IKE_SA, create it when necesarry.
*
* Checks out a SA by its ID. An SA will be created, when:
* - Responder SPI is not set (when received an IKE_SA_INIT from initiator)
* Checks out a SA by its ID. An SA will be created, when the responder
* SPI is not set (when received an IKE_SA_INIT from initiator).
* Management of SPIs is the managers job, he will set it.
* This function blocks until SA is available for checkout.
*
@@ -62,24 +62,27 @@ struct ike_sa_manager_t {
*
* @param this the manager object
* @param[in/out] ike_sa_id the SA identifier, will be updated
* @param[out] ike_sa checked out SA
* @returns
* - SUCCESS if checkout successful
* - NOT_FOUND when no such SA is available
* - CREATED if a new IKE_SA got created
* - checked out IKE_SA if found
* - NULL, if no such IKE_SA available
*/
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.
*
* Creates and checks out a SA as initiator.
* Management of SPIs is the managers job, he will set it.
*
* @brief Checkout an IKE_SA by two identifications.
*
* Allows the lookup of an IKE_SA by two user IDs. It returns the
* 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[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.
@@ -102,7 +105,7 @@ struct ike_sa_manager_t {
/**
* @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
* corrensponding ID really exists, since it may be deleted
* in the meantime by another thread.
@@ -153,7 +156,7 @@ struct ike_sa_manager_t {
* @brief Delete a SA, which was not checked out.
*
* 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.
*
* @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 */
my_id_payload = id_payload_create_from_identification(TRUE, my_id);
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 */
@@ -889,6 +888,7 @@ static status_t conclude(private_ike_auth_t *this, message_t *response,
configured_other_id->get_string(configured_other_id));
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);
}
+8
View File
@@ -269,6 +269,7 @@ static status_t get_request(private_ike_sa_init_t *this, message_t **result)
{
message_t *request;
host_t *me, *other;
identification_t *my_id, *other_id;
/* check if we already have built a message (retransmission) */
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);
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 */
request = message_create();
request->set_source(request, me->clone(me));
+21 -43
View File
@@ -37,7 +37,7 @@
#include <types.h>
#include <daemon.h>
#include <crypto/x509.h>
#include <queues/jobs/initiate_ike_sa_job.h>
#include <queues/jobs/initiate_job.h>
#define IKE_PORT 500
#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)
{
initiate_ike_sa_job_t *job;
initiate_job_t *job;
connection_t *connection;
policy_t *policy;
linked_list_t *ike_sas;
ike_sa_id_t *ike_sa_id;
pop_string(msg, &(msg->initiate.name));
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,
"no connection named \"%s\"",
msg->initiate.name);
return;
}
/* only initiate if it is an IKEv2 connection, ignore IKEv1 */
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
if (!connection->is_ikev2(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.
*/
mapping_t encryption_algorithm_m[] = {
{ENCR_UNDEFINED, "ENCR_UNDEFINED"},
{ENCR_DES_IV64, "ENCR_DES_IV64"},
{ENCR_DES, "ENCR_DES"},
{ENCR_3DES, "ENCR_3DES"},
{ENCR_RC5, "ENCR_RC5"},
{ENCR_IDEA, "ENCR_IDEA"},
{ENCR_CAST, "ENCR_CAST"},
{ENCR_BLOWFISH, "ENCR_BLOWFISH"},
{ENCR_3IDEA, "ENCR_3IDEA"},
{ENCR_DES_IV32, "ENCR_DES_IV32"},
{ENCR_NULL, "ENCR_NULL"},
{ENCR_AES_CBC, "ENCR_AES_CBC"},
{ENCR_AES_CTR, "ENCR_AES_CTR"},
{MAPPING_END, NULL}
{ENCR_UNDEFINED, "UNDEFINED"},
{ENCR_DES_IV64, "DES_IV64"},
{ENCR_DES, "DES"},
{ENCR_3DES, "3DES"},
{ENCR_RC5, "RC5"},
{ENCR_IDEA, "IDEA"},
{ENCR_CAST, "CAST"},
{ENCR_BLOWFISH, "BLOWFISH"},
{ENCR_3IDEA, "3IDEA"},
{ENCR_DES_IV32, "DES_IV32"},
{ENCR_NULL, "NULL"},
{ENCR_AES_CBC, "AES_CBC"},
{ENCR_AES_CTR, "AES_CTR"},
{MAPPING_END, NULL}
};
/*
+6 -6
View File
@@ -29,12 +29,12 @@
* String mappings for integrity_algorithm_t.
*/
mapping_t integrity_algorithm_m[] = {
{AUTH_UNDEFINED, "AUTH_UNDEFINED"},
{AUTH_HMAC_MD5_96, "AUTH_HMAC_MD5_96"},
{AUTH_HMAC_SHA1_96, "AUTH_HMAC_SHA1_96"},
{AUTH_DES_MAC, "AUTH_DES_MAC"},
{AUTH_KPDK_MD5, "AUTH_KPDK_MD5"},
{AUTH_AES_XCBC_96, "AUTH_AES_XCBC_96"},
{AUTH_UNDEFINED, "UNDEFINED"},
{AUTH_HMAC_MD5_96, "HMAC_MD5_96"},
{AUTH_HMAC_SHA1_96, "HMAC_SHA1_96"},
{AUTH_DES_MAC, "DES_MAC"},
{AUTH_KPDK_MD5, "KPDK_MD5"},
{AUTH_AES_XCBC_96, "AES_XCBC_96"},
{MAPPING_END, NULL}
};