merged tasking branch into trunk

This commit is contained in:
Martin Willi
2007-02-28 14:04:36 +00:00
parent a7a5e834e3
commit c60c7694d2
96 changed files with 8409 additions and 8332 deletions
+6
View File
@@ -45,6 +45,12 @@ AC_ARG_WITH(
[AC_DEFINE_UNQUOTED(DEV_RANDOM, "$withval")],
[AC_DEFINE_UNQUOTED(DEV_RANDOM, "/dev/random")]
)
AC_ARG_WITH(
[resolv-conf],
AS_HELP_STRING([--with-resolv-conf=file],[set the file to store DNS server information other than "sysconfdir/resolv.conf"]),
[AC_DEFINE_UNQUOTED(RESOLV_CONF, "$withval")],
[AC_DEFINE_UNQUOTED(RESOLV_CONF, "${sysconfdir}/resolv.conf")]
)
AC_ARG_WITH(
[urandom-device],
+18 -14
View File
@@ -17,21 +17,25 @@ config/policies/local_policy_store.c config/policies/policy_store.h config/polic
config/credentials/local_credential_store.c config/credentials/local_credential_store.h \
config/credentials/credential_store.h config/traffic_selector.c config/traffic_selector.h \
config/proposal.c config/proposal.h config/configuration.c config/configuration.h \
sa/transactions/transaction.h sa/transactions/transaction.c \
sa/transactions/ike_sa_init.h sa/transactions/ike_sa_init.c \
sa/transactions/ike_auth.h sa/transactions/ike_auth.c \
sa/transactions/create_child_sa.h sa/transactions/create_child_sa.c \
sa/transactions/delete_child_sa.h sa/transactions/delete_child_sa.c \
sa/transactions/dead_peer_detection.h sa/transactions/dead_peer_detection.c \
sa/transactions/delete_ike_sa.h sa/transactions/delete_ike_sa.c \
sa/transactions/rekey_ike_sa.h sa/transactions/rekey_ike_sa.c \
sa/authenticators/authenticator.h sa/authenticators/authenticator.c \
sa/authenticators/rsa_authenticator.h sa/authenticators/rsa_authenticator.c \
sa/authenticators/psk_authenticator.h sa/authenticators/psk_authenticator.c \
sa/authenticators/eap_authenticator.h sa/authenticators/eap_authenticator.c \
sa/authenticators/eap/eap_method.h sa/authenticators/eap/eap_method.c \
sa/child_sa.c sa/child_sa.h sa/ike_sa.c sa/ike_sa.h sa/ike_sa_manager.c sa/ike_sa_manager.h \
sa/ike_sa_id.c sa/ike_sa_id.h encoding/payloads/encryption_payload.c \
sa/ike_sa_id.c sa/ike_sa_id.h sa/tasks/task.c sa/tasks/task.h \
sa/tasks/ike_init.c sa/tasks/ike_init.h \
sa/tasks/ike_natd.c sa/tasks/ike_natd.h \
sa/tasks/ike_auth.c sa/tasks/ike_auth.h \
sa/tasks/ike_config.c sa/tasks/ike_config.h \
sa/tasks/ike_cert.c sa/tasks/ike_cert.h \
sa/tasks/ike_rekey.c sa/tasks/ike_rekey.h \
sa/tasks/ike_delete.c sa/tasks/ike_delete.h \
sa/tasks/ike_dpd.c sa/tasks/ike_dpd.h \
sa/tasks/child_create.c sa/tasks/child_create.h \
sa/tasks/child_delete.c sa/tasks/child_delete.h \
sa/tasks/child_rekey.c sa/tasks/child_rekey.h \
sa/authenticators/authenticator.c sa/authenticators/authenticator.h \
sa/authenticators/rsa_authenticator.c sa/authenticators/rsa_authenticator.h \
sa/authenticators/psk_authenticator.c sa/authenticators/psk_authenticator.h \
sa/task_manager.c sa/task_manager.h encoding/payloads/encryption_payload.c \
encoding/payloads/cert_payload.c encoding/payloads/payload.h encoding/payloads/traffic_selector_substructure.c \
encoding/payloads/configuration_attribute.h encoding/payloads/proposal_substructure.h \
encoding/payloads/transform_attribute.c encoding/payloads/transform_attribute.h \
@@ -51,10 +55,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/socket.c network/packet.h network/socket.h queues/jobs/job.h queues/jobs/job.c \
queues/jobs/retransmit_request_job.h queues/jobs/initiate_job.h \
queues/jobs/retransmit_job.h queues/jobs/initiate_job.h \
queues/jobs/incoming_packet_job.h queues/jobs/incoming_packet_job.c \
queues/jobs/delete_ike_sa_job.c queues/jobs/delete_ike_sa_job.h \
queues/jobs/retransmit_request_job.c queues/jobs/initiate_job.c \
queues/jobs/retransmit_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 \
queues/jobs/send_dpd_job.c queues/jobs/send_dpd_job.h queues/jobs/route_job.c queues/jobs/route_job.h \
+7 -2
View File
@@ -180,7 +180,7 @@ static int get_thread_number(private_bus_t *this)
static void add_listener(private_bus_t *this, bus_listener_t *listener)
{
pthread_mutex_lock(&this->mutex);
this->listeners->insert_last(this->listeners, (void*)listener);
this->listeners->insert_last(this->listeners, listener);
pthread_mutex_unlock(&this->mutex);
}
@@ -301,7 +301,12 @@ static void vsignal(private_bus_t *this, signal_t signal, level_t level,
va_list args_copy;
va_copy(args_copy, args);
listener->signal(listener, signal, level, thread, ike_sa, format, args_copy);
if (!listener->signal(listener, signal, level, thread,
ike_sa, format, args_copy))
{
/* unregister listener if requested */
iterator->remove(iterator);
}
va_end(args_copy);
}
iterator->destroy(iterator);
+4 -1
View File
@@ -224,6 +224,8 @@ struct bus_listener_t {
* an additional informational or error message with a printf() like
* variable argument list. This is in the va_list form, as forwarding
* a "..." parameters to functions is not (cleanly) possible.
* The implementing signal function returns TRUE to stay registered
* to the bus, or FALSE to unregister itself.
*
* @param this listener
* @param singal kind of the signal (up, down, rekeyed, ...)
@@ -232,8 +234,9 @@ struct bus_listener_t {
* @param ike_sa IKE_SA associated to the event
* @param format printf() style format string
* @param args vprintf() style va_list argument list
" @return TRUE to stay registered, FALSE to unregister
*/
void (*signal) (bus_listener_t *this, signal_t signal, level_t level,
bool (*signal) (bus_listener_t *this, signal_t signal, level_t level,
int thread, ike_sa_t *ike_sa, char* format, va_list args);
};
+4 -2
View File
@@ -53,7 +53,7 @@ struct private_file_logger_t {
/**
* Implementation of bus_listener_t.signal.
*/
static void signal_(private_file_logger_t *this, signal_t signal, level_t level,
static bool signal_(private_file_logger_t *this, signal_t signal, level_t level,
int thread, ike_sa_t* ike_sa, char *format, va_list args)
{
if (level <= this->levels[SIG_TYPE(signal)])
@@ -76,6 +76,8 @@ static void signal_(private_file_logger_t *this, signal_t signal, level_t level,
current = next;
}
}
/* always stay registered */
return TRUE;
}
/**
@@ -114,7 +116,7 @@ file_logger_t *file_logger_create(FILE *out)
private_file_logger_t *this = malloc_thing(private_file_logger_t);
/* public functions */
this->public.listener.signal = (void(*)(bus_listener_t*,signal_t,level_t,int,ike_sa_t*,char*,va_list))signal_;
this->public.listener.signal = (bool(*)(bus_listener_t*,signal_t,level_t,int,ike_sa_t*,char*,va_list))signal_;
this->public.set_level = (void(*)(file_logger_t*,signal_t,level_t))set_level;
this->public.destroy = (void(*)(file_logger_t*))destroy;
+4 -2
View File
@@ -54,7 +54,7 @@ struct private_sys_logger_t {
/**
* Implementation of bus_listener_t.signal.
*/
static void signal_(private_sys_logger_t *this, signal_t signal, level_t level,
static bool signal_(private_sys_logger_t *this, signal_t signal, level_t level,
int thread, ike_sa_t* ike_sa, char *format, va_list args)
{
if (level <= this->levels[SIG_TYPE(signal)])
@@ -78,6 +78,8 @@ static void signal_(private_sys_logger_t *this, signal_t signal, level_t level,
current = next;
}
}
/* always stay registered */
return TRUE;
}
/**
@@ -117,7 +119,7 @@ sys_logger_t *sys_logger_create(int facility)
private_sys_logger_t *this = malloc_thing(private_sys_logger_t);
/* public functions */
this->public.listener.signal = (void(*)(bus_listener_t*,signal_t,level_t,int,ike_sa_t*,char*,va_list))signal_;
this->public.listener.signal = (bool(*)(bus_listener_t*,signal_t,level_t,int,ike_sa_t*,char*,va_list))signal_;
this->public.set_level = (void(*)(sys_logger_t*,signal_t,level_t))set_level;
this->public.destroy = (void(*)(sys_logger_t*))destroy;
+10 -40
View File
@@ -33,25 +33,11 @@
#define HALF_OPEN_IKE_SA_TIMEOUT 30000
/**
* The retransmission algorithm uses a multiple sequences.
* Each sequence contains multiple retransmits. Those retransmits
* are sent using a exponential backoff algorithm. The sequences
* are retried with linear timings:
* Retransmission uses a backoff algorithm. The timeout is calculated using
* TIMEOUT * (BASE ** try).
* When try reaches TRIES, retransmission is given up.
*
* <------sequence---------><------sequence---------><------sequence--------->
*
* T-R---R-----R---------R--R-R---R-----R---------R--R-R---R-----R---------R--X
*
* T = first transmit
* R = retransmit
* X = giving up, peer is dead
*
* if (retransmit >= TRIES * sequences)
* => abort
* TIMEOUT * (BASE ** (try % TRIES))
*
* Using an initial TIMEOUT of 4s, a BASE of 1.8, 5 TRIES
* per sequnce and 3 sequences, this gives us:
* Using an initial TIMEOUT of 4s, a BASE of 1.8, and 5 TRIES gives us:
*
* | relative | absolute
* ---------------------------------------------------------
@@ -61,22 +47,8 @@
* 4s * (1.8 ** (3 % 5)) = 23s 47s
* 4s * (1.8 ** (4 % 5)) = 42s 89s
* 4s * (1.8 ** (5 % 5)) = 76s 165s
* 4s * (1.8 ** (6 % 5)) = 4s 169s
* 4s * (1.8 ** (7 % 5)) = 7s 176s
* 4s * (1.8 ** (8 % 5)) = 13s 189s
* 4s * (1.8 ** (9 % 5)) = 23s 212s
* 4s * (1.8 ** (10 % 5)) = 42s 254s
* 4s * (1.8 ** (11 % 5)) = 76s 330s
* 4s * (1.8 ** (12 % 5)) = 4s 334
* 4s * (1.8 ** (13 % 5)) = 7s 341s
* 4s * (1.8 ** (14 % 5)) = 13s 354s
* 4s * (1.8 ** (15 % 5)) = 23s 377s
* 4s * (1.8 ** (16 % 5)) = 42s 419s
* 4s * (1.8 ** (17 % 5)) = 76s 495s
*
* If the configuration uses 1 sequence, the peer is considered dead
* after 2min 45s when no reply comes in. If it uses 3 sequences, after
* 8min 15s the DPD action is executed...
* The peer is considered dead after 2min 45s when no reply comes in.
*/
/**
@@ -119,17 +91,15 @@ struct private_configuration_t {
* Implementation of configuration_t.get_retransmit_timeout.
*/
static u_int32_t get_retransmit_timeout (private_configuration_t *this,
u_int32_t retransmit_count,
u_int32_t max_sequences)
u_int32_t retransmit_count)
{
if (max_sequences != 0 &&
retransmit_count >= RETRANSMIT_TRIES * max_sequences)
if (retransmit_count > RETRANSMIT_TRIES)
{
/* give up */
return 0;
}
return (u_int32_t)(RETRANSMIT_TIMEOUT *
pow(RETRANSMIT_BASE, retransmit_count % RETRANSMIT_TRIES));
return (u_int32_t)
(RETRANSMIT_TIMEOUT * pow(RETRANSMIT_BASE, retransmit_count));
}
/**
@@ -165,7 +135,7 @@ configuration_t *configuration_create()
/* public functions */
this->public.destroy = (void(*)(configuration_t*))destroy;
this->public.get_retransmit_timeout = (u_int32_t (*) (configuration_t*,u_int32_t,u_int32_t))get_retransmit_timeout;
this->public.get_retransmit_timeout = (u_int32_t (*) (configuration_t*,u_int32_t))get_retransmit_timeout;
this->public.get_half_open_ike_sa_timeout = (u_int32_t (*) (configuration_t*)) get_half_open_ike_sa_timeout;
this->public.get_keepalive_interval = (u_int32_t (*) (configuration_t*)) get_keepalive_interval;
+4 -8
View File
@@ -40,19 +40,15 @@ struct configuration_t {
/**
* @brief Returns the retransmit timeout.
*
* A return value of zero means the request should not be retransmitted again.
* The retransmission algorithm uses sequences of retransmits, in which
* every sequence contains exponential delayed retransmits. These
* sequences are compareable to the keyingtries mechanism used in pluto.
* A return value of zero means the request should not be
* retransmitted again.
*
* @param this calling object
* @param retransmitted number of times a message was retransmitted so far
* @param max_sequences maximum number of retransmission sequences to allow
* @return time in milliseconds, when to schedule next retransmit
* @return time in milliseconds, when to do next retransmit
*/
u_int32_t (*get_retransmit_timeout) (configuration_t *this,
u_int32_t retransmitted,
u_int32_t max_sequences);
u_int32_t retransmitted);
/**
* @brief Returns the timeout for an half open IKE_SA in ms.
+52 -11
View File
@@ -78,6 +78,16 @@ struct private_policy_t {
*/
identification_t *other_id;
/**
* virtual IP to use locally
*/
host_t *my_virtual_ip;
/**
* virtual IP to use remotly
*/
host_t *other_virtual_ip;
/**
* Method to use for own authentication data
*/
@@ -209,7 +219,8 @@ static eap_type_t get_eap_type(private_policy_t *this)
/**
* Get traffic selectors, with wildcard-address update
*/
static linked_list_t *get_traffic_selectors(private_policy_t *this, linked_list_t *list, host_t *host)
static linked_list_t *get_traffic_selectors(private_policy_t *this,
linked_list_t *list, host_t *host)
{
iterator_t *iterator;
traffic_selector_t *current;
@@ -222,7 +233,10 @@ static linked_list_t *get_traffic_selectors(private_policy_t *this, linked_list_
/* we make a copy of the TS, this allows us to update wildcard
* addresses in it. We won't pollute the shared policy. */
current = current->clone(current);
current->update_address_range(current, host);
if (host)
{
current->update_address_range(current, host);
}
result->insert_last(result, (void*)current);
}
@@ -269,7 +283,10 @@ static linked_list_t *select_traffic_selectors(private_policy_t *this,
/* we make a copy of the TS, this allows us to update wildcard
* addresses in it. We won't pollute the shared policy. */
stored_ts = stored_ts->clone(stored_ts);
stored_ts->update_address_range(stored_ts, host);
if (host)
{
stored_ts->update_address_range(stored_ts, host);
}
supplied_iter->reset(supplied_iter);
/* iterate over all supplied traffic selectors */
@@ -456,6 +473,30 @@ static mode_t get_mode(private_policy_t *this)
return this->mode;
}
/**
* Implementation of policy_t.get_virtual_ip.
*/
static host_t* get_virtual_ip(private_policy_t *this, host_t *suggestion)
{
if (suggestion == NULL)
{
if (this->my_virtual_ip)
{
return this->my_virtual_ip->clone(this->my_virtual_ip);
}
return NULL;
}
if (this->other_virtual_ip)
{
return this->other_virtual_ip->clone(this->other_virtual_ip);
}
if (suggestion->is_anyaddr(suggestion))
{
return NULL;
}
return suggestion->clone(suggestion);
}
/**
* Implements policy_t.get_ref.
*/
@@ -477,14 +518,8 @@ static void destroy(private_policy_t *this)
this->other_ts->destroy_offset(this->other_ts, offsetof(traffic_selector_t, destroy));
/* delete certification authorities */
if (this->my_ca)
{
this->my_ca->destroy(this->my_ca);
}
if (this->other_ca)
{
this->other_ca->destroy(this->other_ca);
}
DESTROY_IF(this->my_ca);
DESTROY_IF(this->other_ca);
/* delete updown script */
if (this->updown)
@@ -495,6 +530,8 @@ static void destroy(private_policy_t *this)
/* delete ids */
this->my_id->destroy(this->my_id);
this->other_id->destroy(this->other_id);
DESTROY_IF(this->my_virtual_ip);
DESTROY_IF(this->other_virtual_ip);
free(this->name);
free(this);
@@ -505,6 +542,7 @@ static void destroy(private_policy_t *this)
* Described in header-file
*/
policy_t *policy_create(char *name, identification_t *my_id, identification_t *other_id,
host_t *my_virtual_ip, host_t *other_virtual_ip,
auth_method_t auth_method, eap_type_t eap_type,
u_int32_t hard_lifetime, u_int32_t soft_lifetime,
u_int32_t jitter, char *updown, bool hostaccess,
@@ -536,6 +574,7 @@ policy_t *policy_create(char *name, identification_t *my_id, identification_t *o
this->public.get_soft_lifetime = (u_int32_t (*) (policy_t *))get_soft_lifetime;
this->public.get_hard_lifetime = (u_int32_t (*) (policy_t *))get_hard_lifetime;
this->public.get_mode = (mode_t (*) (policy_t *))get_mode;
this->public.get_virtual_ip = (host_t* (*)(policy_t*,host_t*))get_virtual_ip;
this->public.get_ref = (void (*) (policy_t*))get_ref;
this->public.destroy = (void (*) (policy_t*))destroy;
@@ -543,6 +582,8 @@ policy_t *policy_create(char *name, identification_t *my_id, identification_t *o
this->name = strdup(name);
this->my_id = my_id;
this->other_id = other_id;
this->my_virtual_ip = my_virtual_ip;
this->other_virtual_ip = other_virtual_ip;
this->auth_method = auth_method;
this->eap_type = eap_type;
this->hard_lifetime = hard_lifetime;
+24
View File
@@ -328,6 +328,25 @@ struct policy_t {
*/
mode_t (*get_mode) (policy_t *this);
/**
* @brief Get a virtual IP for the local or the remote host.
*
* By supplying NULL as IP, an IP for the local host is requested. It
* may be %any or specific.
* By supplying %any as host, an IP from the pool is selected to be
* served to the peer.
* If a specified host is supplied, it is checked if this address
* is acceptable to serve to the peer. If so, it is returned. Otherwise,
* an alternative IP is returned.
* In any mode, this call may return NULL indicating virtual IP should
* not be used.
*
* @param this policy
* @param suggestion NULL, %any or specific, see description
* @return clone of an IP to use, or NULL
*/
host_t* (*get_virtual_ip) (policy_t *this, host_t *suggestion);
/**
* @brief Get a new reference.
*
@@ -356,6 +375,8 @@ struct policy_t {
* @brief Create a configuration object for IKE_AUTH and later.
*
* name-string gets cloned, ID's not.
* Virtual IPs are used if they are != NULL. A %any host means the virtual
* IP should be obtained from the other peer.
* Lifetimes are in seconds. To prevent to peers to start rekeying at the
* same time, a jitter may be specified. Rekeying of an SA starts at
* (soft_lifetime - random(0, jitter)). After a successful rekeying,
@@ -366,6 +387,8 @@ struct policy_t {
* @param name name of the policy
* @param my_id identification_t for ourselves
* @param other_id identification_t for the remote guy
* @param my_virtual_ip virtual IP for local host, or NULL
* @param other_virtual_ip virtual IP for remote host, or NULL
* @param auth_method Authentication method to use for our(!) auth data
* @param eap_type EAP type to use for peer authentication
* @param hard_lifetime lifetime before deleting an SA
@@ -381,6 +404,7 @@ struct policy_t {
*/
policy_t *policy_create(char *name,
identification_t *my_id, identification_t *other_id,
host_t *my_virtual_ip, host_t *other_virtual_ip,
auth_method_t auth_method, eap_type_t eap_type,
u_int32_t hard_lifetime, u_int32_t soft_lifetime,
u_int32_t jitter, char *updown, bool hostaccess,
+25
View File
@@ -6,6 +6,7 @@
*/
/*
* Copyright (C) 2007 Tobias Brunner
* Copyright (C) 2005-2006 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
@@ -493,6 +494,26 @@ static void update_address_range(private_traffic_selector_t *this, host_t *host)
}
}
/**
* Implements traffic_selector_t.includes.
*/
static bool includes(private_traffic_selector_t *this, host_t *host)
{
chunk_t addr;
int family = host->get_family(host);
if ((family == AF_INET && this->type == TS_IPV4_ADDR_RANGE) ||
(family == AF_INET6 && this->type == TS_IPV6_ADDR_RANGE))
{
addr = host->get_address(host);
return memcmp(this->from, addr.ptr, addr.len) <= 0 &&
memcmp(this->to, addr.ptr, addr.len) >= 0;
}
return FALSE;
}
/**
* Implements traffic_selector_t.clone.
*/
@@ -698,6 +719,7 @@ static private_traffic_selector_t *traffic_selector_create(u_int8_t protocol, ts
this->public.get_type = (ts_type_t(*)(traffic_selector_t*))get_type;
this->public.get_protocol = (u_int8_t(*)(traffic_selector_t*))get_protocol;
this->public.is_host = (bool(*)(traffic_selector_t*,host_t*))is_host;
this->public.includes = (bool(*)(traffic_selector_t*,host_t*))includes;
this->public.update_address_range = (void(*)(traffic_selector_t*,host_t*))update_address_range;
this->public.clone = (traffic_selector_t*(*)(traffic_selector_t*))clone_;
this->public.destroy = (void(*)(traffic_selector_t*))destroy;
@@ -709,3 +731,6 @@ static private_traffic_selector_t *traffic_selector_create(u_int8_t protocol, ts
return this;
}
/* vim: set ts=4 sw=4 noet: */
+21 -9
View File
@@ -6,6 +6,7 @@
*/
/*
* Copyright (C) 2007 Tobias Brunner
* Copyright (C) 2005-2006 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
@@ -105,7 +106,7 @@ struct traffic_selector_t {
*
* Chunk is in network order gets allocated.
*
* @param this calling object
* @param this called object
* @return chunk containing the address
*/
chunk_t (*get_from_address) (traffic_selector_t *this);
@@ -115,7 +116,7 @@ struct traffic_selector_t {
*
* Chunk is in network order gets allocated.
*
* @param this calling object
* @param this called object
* @return chunk containing the address
*/
chunk_t (*get_to_address) (traffic_selector_t *this);
@@ -126,7 +127,7 @@ struct traffic_selector_t {
* Port is in host order, since the parser converts it.
* Size depends on protocol.
*
* @param this calling object
* @param this called object
* @return port
*/
u_int16_t (*get_from_port) (traffic_selector_t *this);
@@ -137,7 +138,7 @@ struct traffic_selector_t {
* Port is in host order, since the parser converts it.
* Size depends on protocol.
*
* @param this calling object
* @param this called object
* @return port
*/
u_int16_t (*get_to_port) (traffic_selector_t *this);
@@ -145,7 +146,7 @@ struct traffic_selector_t {
/**
* @brief Get the type of the traffic selector.
*
* @param this calling obect
* @param this called object
* @return ts_type_t specifying the type
*/
ts_type_t (*get_type) (traffic_selector_t *this);
@@ -153,7 +154,7 @@ struct traffic_selector_t {
/**
* @brief Get the protocol id of this ts.
*
* @param this calling obect
* @param this called object
* @return protocol id
*/
u_int8_t (*get_protocol) (traffic_selector_t *this);
@@ -167,7 +168,7 @@ struct traffic_selector_t {
* If host is NULL, the traffic selector is checked if it is a single host,
* but not a specific one.
*
* @param this calling obect
* @param this called object
* @param host host_t specifying the address range
*/
bool (*is_host) (traffic_selector_t *this, host_t* host);
@@ -180,7 +181,7 @@ struct traffic_selector_t {
* starts from the supplied address and also ends there
* (which means it is a one-host-address-range ;-).
*
* @param this calling obect
* @param this called object
* @param host host_t specifying the address range
*/
void (*update_address_range) (traffic_selector_t *this, host_t* host);
@@ -193,11 +194,19 @@ struct traffic_selector_t {
* @return pointer to a string.
*/
bool (*equals) (traffic_selector_t *this, traffic_selector_t *other);
/**
* @brief Check if a specific host is included in the address range of this traffic selector.
*
* @param this called object
* @param host the host to check
*/
bool (*includes) (traffic_selector_t *this, host_t *host);
/**
* @brief Destroys the ts object
*
* @param this calling object
* @param this called object
*/
void (*destroy) (traffic_selector_t *this);
};
@@ -269,3 +278,6 @@ traffic_selector_t *traffic_selector_create_from_subnet(
u_int8_t protocol, u_int16_t port);
#endif /* TRAFFIC_SELECTOR_H_ */
/* vim: set ts=4 sw=4 noet: */
+56 -2
View File
@@ -345,6 +345,7 @@ static status_t get_payload_rule(private_message_t *this, payload_type_t payload
*/
static void set_ike_sa_id (private_message_t *this,ike_sa_id_t *ike_sa_id)
{
DESTROY_IF(this->ike_sa_id);
this->ike_sa_id = ike_sa_id->clone(ike_sa_id);
}
@@ -489,6 +490,29 @@ static void add_payload(private_message_t *this, payload_t *payload)
payload_type_names, payload->get_type(payload));
}
/**
* Implementation of message_t.add_notify.
*/
static void add_notify(private_message_t *this, bool flush, notify_type_t type,
chunk_t data)
{
notify_payload_t *notify;
payload_t *payload;
if (flush)
{
while (this->payloads->remove_last(this->payloads,
(void**)&payload) == SUCCESS)
{
payload->destroy(payload);
}
}
notify = notify_payload_create();
notify->set_notify_type(notify, type);
notify->set_notification_data(notify, data);
add_payload(this, (payload_t*)notify);
}
/**
* Implementation of message_t.set_source.
*/
@@ -522,13 +546,34 @@ static host_t * get_destination(private_message_t *this)
}
/**
* Implementation of message_t.get_destination.
* Implementation of message_t.get_payload_iterator.
*/
static iterator_t *get_payload_iterator(private_message_t *this)
{
return this->payloads->create_iterator(this->payloads, TRUE);
}
/**
* Implementation of message_t.get_payload.
*/
static payload_t *get_payload(private_message_t *this, payload_type_t type)
{
payload_t *current, *found = NULL;
iterator_t *iterator;
iterator = this->payloads->create_iterator(this->payloads, TRUE);
while (iterator->iterate(iterator, (void**)&current))
{
if (current->get_type(current) == type)
{
found = current;
break;
}
}
iterator->destroy(iterator);
return found;
}
/**
* output handler in printf()
*/
@@ -786,6 +831,10 @@ static status_t generate(private_message_t *this, crypter_t *crypter, signer_t*
*/
static packet_t *get_packet (private_message_t *this)
{
if (this->packet == NULL)
{
return NULL;
}
return this->packet->clone(this->packet);
}
@@ -794,6 +843,10 @@ static packet_t *get_packet (private_message_t *this)
*/
static chunk_t get_packet_data (private_message_t *this)
{
if (this->packet == NULL)
{
return chunk_empty;
}
return chunk_clone(this->packet->get_data(this->packet));
}
@@ -1147,7 +1200,6 @@ static status_t parse_body(private_message_t *this, crypter_t *crypter, signer_t
status = verify(this);
if (status != SUCCESS)
{
DBG1(DBG_ENC, "verification of message failed");
return status;
}
@@ -1191,12 +1243,14 @@ message_t *message_create_from_packet(packet_t *packet)
this->public.set_request = (void(*)(message_t*, bool))set_request;
this->public.get_request = (bool(*)(message_t*))get_request;
this->public.add_payload = (void(*)(message_t*,payload_t*))add_payload;
this->public.add_notify = (void(*)(message_t*,bool,notify_type_t,chunk_t))add_notify;
this->public.generate = (status_t (*) (message_t *,crypter_t*,signer_t*,packet_t**)) generate;
this->public.set_source = (void (*) (message_t*,host_t*)) set_source;
this->public.get_source = (host_t * (*) (message_t*)) get_source;
this->public.set_destination = (void (*) (message_t*,host_t*)) set_destination;
this->public.get_destination = (host_t * (*) (message_t*)) get_destination;
this->public.get_payload_iterator = (iterator_t * (*) (message_t *)) get_payload_iterator;
this->public.get_payload = (payload_t * (*) (message_t *, payload_type_t)) get_payload;
this->public.parse_header = (status_t (*) (message_t *)) parse_header;
this->public.parse_body = (status_t (*) (message_t *,crypter_t*,signer_t*)) parse_body;
this->public.get_packet = (packet_t * (*) (message_t*)) get_packet;
+26
View File
@@ -183,6 +183,21 @@ struct message_t {
*/
void (*add_payload) (message_t *this, payload_t *payload);
/**
* @brief Build a notify payload and add it to the message.
*
* This is a helper method to create notify messages or add
* notify payload to messages. The flush parameter specifies if existing
* payloads should get removed before appending the notify.
*
* @param this message_t object
* @param flush TRUE to remove existing payloads
* @param type type of the notify
* @param data a chunk of data to add to the notify, gets cloned
*/
void (*add_notify) (message_t *this, bool flush, notify_type_t type,
chunk_t data);
/**
* @brief Parses header of message.
*
@@ -303,6 +318,17 @@ struct message_t {
*/
iterator_t * (*get_payload_iterator) (message_t *this);
/**
* @brief Find a payload of a spicific type.
*
* Returns the first occurance.
*
* @param this message_t object
* @param type type of the payload to find
* @return payload, or NULL if no such payload found
*/
payload_t* (*get_payload) (message_t *this, payload_type_t type);
/**
* @brief Returns a clone of the internal stored packet_t object.
*
+1 -1
View File
@@ -270,7 +270,7 @@ cert_payload_t *cert_payload_create()
/* private variables */
this->critical = FALSE;
this->next_payload = NO_PAYLOAD;
this->payload_length =CERT_PAYLOAD_HEADER_LENGTH;
this->payload_length = CERT_PAYLOAD_HEADER_LENGTH;
this->cert_data = chunk_empty;
return (&(this->public));
@@ -306,7 +306,10 @@ certreq_payload_t *certreq_payload_create_from_cacerts(void)
int count = iterator->get_count(iterator);
if (count == 0)
{
iterator->destroy(iterator);
return NULL;
}
this = certreq_payload_create();
keyids = chunk_alloc(count * HASH_SIZE_SHA1);
@@ -27,6 +27,7 @@
#include <encoding/payloads/encodings.h>
#include <library.h>
#include <daemon.h>
typedef struct private_configuration_attribute_t private_configuration_attribute_t;
@@ -50,7 +51,6 @@ struct private_configuration_attribute_t {
* Length of the attribute.
*/
u_int16_t attribute_length;
/**
* Attribute value as chunk.
@@ -58,7 +58,7 @@ struct private_configuration_attribute_t {
chunk_t attribute_value;
};
ENUM_BEGIN(configuration_attribute_type_name, INTERNAL_IP4_ADDRESS, INTERNAL_IP6_ADDRESS,
ENUM_BEGIN(configuration_attribute_type_names, INTERNAL_IP4_ADDRESS, INTERNAL_IP6_ADDRESS,
"INTERNAL_IP4_ADDRESS",
"INTERNAL_IP4_NETMASK",
"INTERNAL_IP4_DNS",
@@ -67,14 +67,14 @@ ENUM_BEGIN(configuration_attribute_type_name, INTERNAL_IP4_ADDRESS, INTERNAL_IP6
"INTERNAL_IP4_DHCP",
"APPLICATION_VERSION",
"INTERNAL_IP6_ADDRESS");
ENUM_NEXT(configuration_attribute_type_name, INTERNAL_IP6_DNS, INTERNAL_IP6_SUBNET, INTERNAL_IP6_ADDRESS,
ENUM_NEXT(configuration_attribute_type_names, INTERNAL_IP6_DNS, INTERNAL_IP6_SUBNET, INTERNAL_IP6_ADDRESS,
"INTERNAL_IP6_DNS",
"INTERNAL_IP6_NBNS",
"INTERNAL_IP6_DHCP",
"INTERNAL_IP4_SUBNET",
"SUPPORTED_ATTRIBUTES",
"INTERNAL_IP6_SUBNET");
ENUM_END(configuration_attribute_type_name, INTERNAL_IP6_SUBNET);
ENUM_END(configuration_attribute_type_names, INTERNAL_IP6_SUBNET);
/**
* Encoding rules to parse or generate a configuration attribute.
@@ -111,6 +111,14 @@ encoding_rule_t configuration_attribute_encodings[] = {
*/
static status_t verify(private_configuration_attribute_t *this)
{
bool failed = FALSE;
if (this->attribute_length != this->attribute_value.len)
{
DBG1(DBG_ENC, "invalid attribute length");
return FAILED;
}
switch (this->attribute_type)
{
case INTERNAL_IP4_ADDRESS:
@@ -119,27 +127,54 @@ static status_t verify(private_configuration_attribute_t *this)
case INTERNAL_IP4_NBNS:
case INTERNAL_ADDRESS_EXPIRY:
case INTERNAL_IP4_DHCP:
case APPLICATION_VERSION:
if (this->attribute_length != 0 && this->attribute_length != 4)
{
failed = TRUE;
}
break;
case INTERNAL_IP4_SUBNET:
if (this->attribute_length != 0 && this->attribute_length != 8)
{
failed = TRUE;
}
break;
case INTERNAL_IP6_ADDRESS:
case INTERNAL_IP6_SUBNET:
if (this->attribute_length != 0 && this->attribute_length != 17)
{
failed = TRUE;
}
break;
case INTERNAL_IP6_DNS:
case INTERNAL_IP6_NBNS:
case INTERNAL_IP6_DHCP:
case INTERNAL_IP4_SUBNET:
if (this->attribute_length != 0 && this->attribute_length != 16)
{
failed = TRUE;
}
break;
case SUPPORTED_ATTRIBUTES:
case INTERNAL_IP6_SUBNET:
{
/* Attribute types are not checked in here */
if (this->attribute_length % 2)
{
failed = TRUE;
}
break;
case APPLICATION_VERSION:
/* any length acceptable */
break;
}
default:
DBG1(DBG_ENC, "unknown attribute type %N",
configuration_attribute_type_names, this->attribute_type);
return FAILED;
}
if (this->attribute_length != this->attribute_value.len)
if (failed)
{
DBG1(DBG_ENC, "invalid attribute length %d for %N",
this->attribute_length, configuration_attribute_type_names,
this->attribute_type);
return FAILED;
}
return SUCCESS;
}
@@ -208,9 +243,8 @@ static chunk_t get_value (private_configuration_attribute_t *this)
return this->attribute_value;
}
/**
* Implementation of configuration_attribute_t.set_attribute_type.
* Implementation of configuration_attribute_t.set_type.
*/
static void set_attribute_type (private_configuration_attribute_t *this, u_int16_t type)
{
@@ -218,7 +252,7 @@ static void set_attribute_type (private_configuration_attribute_t *this, u_int16
}
/**
* Implementation of configuration_attribute_t.get_attribute_type.
* Implementation of configuration_attribute_t.get_type.
*/
static u_int16_t get_attribute_type (private_configuration_attribute_t *this)
{
@@ -226,7 +260,7 @@ static u_int16_t get_attribute_type (private_configuration_attribute_t *this)
}
/**
* Implementation of configuration_attribute_t.get_attribute_length.
* Implementation of configuration_attribute_t.get_length.
*/
static u_int16_t get_attribute_length (private_configuration_attribute_t *this)
{
@@ -265,9 +299,9 @@ configuration_attribute_t *configuration_attribute_create()
/* public functions */
this->public.set_value = (void (*) (configuration_attribute_t *,chunk_t)) set_value;
this->public.get_value = (chunk_t (*) (configuration_attribute_t *)) get_value;
this->public.set_attribute_type = (void (*) (configuration_attribute_t *,u_int16_t type)) set_attribute_type;
this->public.get_attribute_type = (u_int16_t (*) (configuration_attribute_t *)) get_attribute_type;
this->public.get_attribute_length = (u_int16_t (*) (configuration_attribute_t *)) get_attribute_length;
this->public.set_type = (void (*) (configuration_attribute_t *,u_int16_t type)) set_attribute_type;
this->public.get_type = (u_int16_t (*) (configuration_attribute_t *)) get_attribute_type;
this->public.get_length = (u_int16_t (*) (configuration_attribute_t *)) get_attribute_length;
this->public.destroy = (void (*) (configuration_attribute_t *)) destroy;
/* set default values of the fields */
@@ -109,7 +109,7 @@ struct configuration_attribute_t {
* @param this calling configuration_attribute_t object
* @param type type to set (most significant bit is set to zero)
*/
void (*set_attribute_type) (configuration_attribute_t *this, u_int16_t type);
void (*set_type) (configuration_attribute_t *this, u_int16_t type);
/**
* @brief get the type of the attribute.
@@ -117,7 +117,7 @@ struct configuration_attribute_t {
* @param this calling configuration_attribute_t object
* @return type of the value
*/
u_int16_t (*get_attribute_type) (configuration_attribute_t *this);
u_int16_t (*get_type) (configuration_attribute_t *this);
/**
* @brief get the length of an attribute.
@@ -125,7 +125,7 @@ struct configuration_attribute_t {
* @param this calling configuration_attribute_t object
* @return type of the value
*/
u_int16_t (*get_attribute_length) (configuration_attribute_t *this);
u_int16_t (*get_length) (configuration_attribute_t *this);
/**
* @brief Destroys an configuration_attribute_t object.
+3 -3
View File
@@ -204,9 +204,9 @@ static size_t get_length(private_cp_payload_t *this)
/**
* Implementation of cp_payload_t.create_configuration_attribute_iterator.
*/
static iterator_t *create_configuration_attribute_iterator (private_cp_payload_t *this,bool forward)
static iterator_t *create_attribute_iterator (private_cp_payload_t *this)
{
return this->attributes->create_iterator(this->attributes,forward);
return this->attributes->create_iterator(this->attributes, TRUE);
}
/**
@@ -261,7 +261,7 @@ cp_payload_t *cp_payload_create()
this->public.payload_interface.destroy = (void (*) (payload_t *))destroy;
/* public functions */
this->public.create_configuration_attribute_iterator = (iterator_t* (*) (cp_payload_t *,bool)) create_configuration_attribute_iterator;
this->public.create_attribute_iterator = (iterator_t* (*) (cp_payload_t *)) create_attribute_iterator;
this->public.add_configuration_attribute = (void (*) (cp_payload_t *,configuration_attribute_t *)) add_configuration_attribute;
this->public.set_config_type = (void (*) (cp_payload_t *, config_type_t)) set_config_type;
this->public.get_config_type = (config_type_t (*) (cp_payload_t *)) get_config_type;
+5 -9
View File
@@ -77,23 +77,19 @@ struct cp_payload_t {
/**
* @brief Creates an iterator of stored configuration_attribute_t objects.
*
* @warning The created iterator has to get destroyed by the caller!
*
* @warning When deleting an attribute using this iterator,
* the length of this configuration_attribute_t has to be refreshed
* by calling get_length()!
* When deleting an attribute using this iterator, the length of this
* configuration_attribute_t has to be refreshed by calling get_length()!
*
* @param this calling cp_payload_t object
* @param[in] forward iterator direction (TRUE: front to end)
* @return created iterator_t object
*/
iterator_t *(*create_configuration_attribute_iterator) (cp_payload_t *this, bool forward);
iterator_t *(*create_attribute_iterator) (cp_payload_t *this);
/**
* @brief Adds a configuration_attribute_t object to this object.
*
* @warning The added configuration_attribute_t object is
* getting destroyed in destroy function of cp_payload_t.
* The added configuration_attribute_t object is getting destroyed in
* destroy function of cp_payload_t.
*
* @param this calling cp_payload_t object
* @param attribute configuration_attribute_t object to add
@@ -209,6 +209,9 @@ static status_t verify(private_notify_payload_t *this)
diffie_hellman_group_t dh_group;
if (this->notification_data.len != 2)
{
DBG1(DBG_ENC, "invalid notify data length for %N (%d)",
notify_type_names, this->notify_type,
this->notification_data.len);
return FAILED;
}
dh_group = ntohs(*((u_int16_t*)this->notification_data.ptr));
@@ -403,7 +406,10 @@ static chunk_t get_notification_data(private_notify_payload_t *this)
static status_t set_notification_data(private_notify_payload_t *this, chunk_t notification_data)
{
chunk_free(&this->notification_data);
this->notification_data = chunk_clone(notification_data);
if (notification_data.len > 0)
{
this->notification_data = chunk_clone(notification_data);
}
compute_length(this);
return SUCCESS;
}
+2 -8
View File
@@ -58,10 +58,7 @@ struct private_packet_t {
*/
static void set_source(private_packet_t *this, host_t *source)
{
if (this->source)
{
this->source->destroy(this->source);
}
DESTROY_IF(this->source);
this->source = source;
}
@@ -70,10 +67,7 @@ static void set_source(private_packet_t *this, host_t *source)
*/
static void set_destination(private_packet_t *this, host_t *destination)
{
if (this->destination)
{
this->destination->destroy(this->destination);
}
DESTROY_IF(this->destination);
this->destination = destination;
}
+2 -2
View File
@@ -57,8 +57,8 @@ static status_t execute(private_acquire_job_t *this)
{
ike_sa_t *ike_sa;
ike_sa = charon->ike_sa_manager->checkout_by_child(charon->ike_sa_manager,
this->reqid);
ike_sa = charon->ike_sa_manager->checkout_by_id(charon->ike_sa_manager,
this->reqid, TRUE);
if (ike_sa == NULL)
{
DBG2(DBG_JOB, "CHILD_SA with reqid %d not found for acquiring",
+2 -2
View File
@@ -68,8 +68,8 @@ static status_t execute(private_delete_child_sa_job_t *this)
{
ike_sa_t *ike_sa;
ike_sa = charon->ike_sa_manager->checkout_by_child(charon->ike_sa_manager,
this->reqid);
ike_sa = charon->ike_sa_manager->checkout_by_id(charon->ike_sa_manager,
this->reqid, TRUE);
if (ike_sa == NULL)
{
DBG1(DBG_JOB, "CHILD_SA with reqid %d not found for delete",
+22 -25
View File
@@ -62,41 +62,38 @@ static status_t execute(private_delete_ike_sa_job_t *this)
{
ike_sa_t *ike_sa;
if (this->delete_if_established)
ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
this->ike_sa_id);
if (ike_sa)
{
if (charon->ike_sa_manager->delete(charon->ike_sa_manager,
this->ike_sa_id) != SUCCESS)
if (this->delete_if_established)
{
DBG2(DBG_JOB, "IKE SA didn't exist anymore");
}
return DESTROY_ME;
}
else
{
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;
}
switch (ike_sa->get_state(ike_sa))
{
case IKE_ESTABLISHED:
if (ike_sa->delete(ike_sa) == DESTROY_ME)
{
charon->ike_sa_manager->checkin_and_destroy(
charon->ike_sa_manager, ike_sa);
}
else
{
/* IKE_SA is established and so is not getting destroyed */
charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
return DESTROY_ME;
}
default:
}
else
{
/* destroy only if not ESTABLISHED */
if (ike_sa->get_state(ike_sa) == IKE_ESTABLISHED)
{
charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
}
else
{
/* IKE_SA is half open and gets destroyed */
DBG1(DBG_JOB, "deleting half open IKE_SA after timeout");
charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa);
return DESTROY_ME;
charon->ike_sa_manager->checkin_and_destroy(
charon->ike_sa_manager, ike_sa);
}
}
}
return DESTROY_ME;
}
/**
+20 -14
View File
@@ -64,6 +64,13 @@ static void send_notify_response(private_incoming_packet_job_t *this,
packet_t *packet;
ike_sa_id_t *ike_sa_id;
if (request->get_exchange_type(request) != IKE_SA_INIT)
{
/* TODO: Use transforms implementing the "NULL" algorithm,
we are unable to generate message otherwise */
return;
}
ike_sa_id = request->get_ike_sa_id(request);
ike_sa_id = ike_sa_id->clone(ike_sa_id);
ike_sa_id->switch_initiator(ike_sa_id);
@@ -80,8 +87,6 @@ static void send_notify_response(private_incoming_packet_job_t *this,
ike_sa_id->destroy(ike_sa_id);
notify = notify_payload_create_from_protocol_and_type(PROTO_NONE, type);
response->add_payload(response, (payload_t *)notify);
/* generation may fail, as most messages need a crypter/signer.
* TODO: Use transforms implementing the "NULL" algorithm */
if (response->generate(response, NULL, NULL, &packet) != SUCCESS)
{
response->destroy(response);
@@ -107,12 +112,12 @@ static status_t execute(private_incoming_packet_job_t *this)
message = message_create_from_packet(this->packet->clone(this->packet));
src = message->get_source(message);
dst = message->get_destination(message);
DBG1(DBG_NET, "received packet: from %#H to %#H", src, dst);
status = message->parse_header(message);
if (status != SUCCESS)
{
DBG1(DBG_NET, "received message with invalid IKE header, ignored");
DBG1(DBG_NET, "received message from %H with invalid IKE header, "
"ignored", src);
message->destroy(message);
return DESTROY_ME;
}
@@ -120,11 +125,12 @@ static status_t execute(private_incoming_packet_job_t *this)
if ((message->get_major_version(message) != IKE_MAJOR_VERSION) ||
(message->get_minor_version(message) != IKE_MINOR_VERSION))
{
DBG1(DBG_NET,
"received a packet with 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)))
DBG1(DBG_NET, "received message from %H with unsupported IKE "
"version %d.%d, ignored", src, message->get_major_version(message),
message->get_minor_version(message));
if (message->get_exchange_type(message) == IKE_SA_INIT &&
message->get_request(message))
{
send_notify_response(this, message, INVALID_MAJOR_VERSION);
}
@@ -138,19 +144,19 @@ static status_t execute(private_incoming_packet_job_t *this)
ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager, ike_sa_id);
if (ike_sa == NULL)
{
DBG1(DBG_NET, "received packet for IKE_SA: %J, but no such IKE_SA",
ike_sa_id);
DBG1(DBG_NET, "received packet from %#H for IKE_SA: %J, but no such "
"IKE_SA", src, ike_sa_id);
if (message->get_request(message))
{
/* TODO: send notify if we have NULL crypters,
* see todo in send_notify_response
send_notify_response(this, message, INVALID_IKE_SPI); */
send_notify_response(this, message, INVALID_IKE_SPI);
}
ike_sa_id->destroy(ike_sa_id);
message->destroy(message);
return DESTROY_ME;
}
DBG1(DBG_NET, "received packet: from %#H to %#H", src, dst);
status = ike_sa->process_message(ike_sa, message);
if (status == DESTROY_ME)
{
+3 -18
View File
@@ -44,11 +44,6 @@ struct private_initiate_job_t {
*/
connection_t *connection;
/**
* host to connect to, use NULL to use connections one
*/
host_t *other;
/**
* associated policy to initiate
*/
@@ -70,19 +65,12 @@ static status_t execute(private_initiate_job_t *this)
{
ike_sa_t *ike_sa;
ike_sa = charon->ike_sa_manager->checkout_by_id(charon->ike_sa_manager,
ike_sa = charon->ike_sa_manager->checkout_by_peer(charon->ike_sa_manager,
this->connection->get_my_host(this->connection),
this->connection->get_other_host(this->connection),
this->policy->get_my_id(this->policy),
this->policy->get_other_id(this->policy));
if (this->other)
{
ike_sa->set_other_host(ike_sa, this->other->clone(this->other));
}
this->connection->get_ref(this->connection);
this->policy->get_ref(this->policy);
if (ike_sa->initiate(ike_sa, this->connection, this->policy) != SUCCESS)
{
DBG1(DBG_JOB, "initiation failed, going to delete IKE_SA");
@@ -101,15 +89,13 @@ static void destroy(private_initiate_job_t *this)
{
this->connection->destroy(this->connection);
this->policy->destroy(this->policy);
DESTROY_IF(this->other);
free(this);
}
/*
* Described in header
*/
initiate_job_t *initiate_job_create(connection_t *connection, host_t *other,
policy_t *policy)
initiate_job_t *initiate_job_create(connection_t *connection, policy_t *policy)
{
private_initiate_job_t *this = malloc_thing(private_initiate_job_t);
@@ -121,7 +107,6 @@ initiate_job_t *initiate_job_create(connection_t *connection, host_t *other,
/* private variables */
this->connection = connection;
this->policy = policy;
this->other = other;
return &this->public;
}
+1 -3
View File
@@ -51,13 +51,11 @@ struct initiate_job_t {
* @brief Creates a job of type INITIATE_IKE_SA.
*
* @param connection connection_t to initialize
* @param other another host to initiate to, NULL to use connections one
* @param policy policy to set up
* @return initiate_job_t object
*
* @ingroup jobs
*/
initiate_job_t *initiate_job_create(connection_t *connection, host_t *other,
policy_t *policy);
initiate_job_t *initiate_job_create(connection_t *connection, policy_t *policy);
#endif /*INITIATE_IKE_SA_JOB_H_*/
+1 -1
View File
@@ -26,7 +26,7 @@
ENUM(job_type_names, INCOMING_PACKET, SEND_DPD,
"INCOMING_PACKET",
"RETRANSMIT_REQUEST",
"RETRANSMIT",
"INITIATE",
"ROUTE",
"ACQUIRE",
+2 -2
View File
@@ -45,9 +45,9 @@ enum job_type_t {
/**
* Retransmit an IKEv2-Message.
*
* Job is implemented in class retransmit_request_job_t
* Job is implemented in class retransmit_job_t
*/
RETRANSMIT_REQUEST,
RETRANSMIT,
/**
* Set up a CHILD_SA, optional with an IKE_SA.
+2 -2
View File
@@ -67,8 +67,8 @@ static status_t execute(private_rekey_child_sa_job_t *this)
{
ike_sa_t *ike_sa;
ike_sa = charon->ike_sa_manager->checkout_by_child(charon->ike_sa_manager,
this->reqid);
ike_sa = charon->ike_sa_manager->checkout_by_id(charon->ike_sa_manager,
this->reqid, TRUE);
if (ike_sa == NULL)
{
DBG2(DBG_JOB, "CHILD_SA with reqid %d not found for rekeying",
+2 -2
View File
@@ -61,7 +61,7 @@ static job_type_t get_type(private_rekey_ike_sa_job_t *this)
static status_t execute(private_rekey_ike_sa_job_t *this)
{
ike_sa_t *ike_sa;
status_t status;
status_t status = SUCCESS;
ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
this->ike_sa_id);
@@ -73,7 +73,7 @@ static status_t execute(private_rekey_ike_sa_job_t *this)
if (this->reauth)
{
status = ike_sa->reauth(ike_sa);
ike_sa->reestablish(ike_sa);
}
else
{
@@ -1,12 +1,12 @@
/**
* @file retransmit_request_job.c
* @file retransmit_job.c
*
* @brief Implementation of retransmit_request_job_t.
* @brief Implementation of retransmit_job_t.
*
*/
/*
* Copyright (C) 2005-2006 Martin Willi
* Copyright (C) 2005-2007 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
*
@@ -21,20 +21,20 @@
* for more details.
*/
#include "retransmit_request_job.h"
#include "retransmit_job.h"
#include <daemon.h>
typedef struct private_retransmit_request_job_t private_retransmit_request_job_t;
typedef struct private_retransmit_job_t private_retransmit_job_t;
/**
* Private data of an retransmit_request_job_t Object.
* Private data of an retransmit_job_t Object.
*/
struct private_retransmit_request_job_t {
struct private_retransmit_job_t {
/**
* Public retransmit_request_job_t interface.
* Public retransmit_job_t interface.
*/
retransmit_request_job_t public;
retransmit_job_t public;
/**
* Message ID of the request to resend.
@@ -50,33 +50,32 @@ struct private_retransmit_request_job_t {
/**
* Implements job_t.get_type.
*/
static job_type_t get_type(private_retransmit_request_job_t *this)
static job_type_t get_type(private_retransmit_job_t *this)
{
return RETRANSMIT_REQUEST;
return RETRANSMIT;
}
/**
* Implementation of job_t.execute.
*/
static status_t execute(private_retransmit_request_job_t *this)
static status_t execute(private_retransmit_job_t *this)
{
ike_sa_t *ike_sa;
ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager, this->ike_sa_id);
if (ike_sa == NULL)
ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
this->ike_sa_id);
if (ike_sa)
{
DBG2(DBG_JOB, "IKE SA could not be checked out. Already deleted?");
return DESTROY_ME;
}
if (ike_sa->retransmit_request(ike_sa, this->message_id) == DESTROY_ME)
{
/* retransmission hopeless, kill SA */
charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa);
}
else
{
charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
if (ike_sa->retransmit(ike_sa, this->message_id) == DESTROY_ME)
{
/* retransmitted to many times, giving up */
charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager,
ike_sa);
}
else
{
charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
}
}
return DESTROY_ME;
}
@@ -84,7 +83,7 @@ static status_t execute(private_retransmit_request_job_t *this)
/**
* Implements job_t.destroy.
*/
static void destroy(private_retransmit_request_job_t *this)
static void destroy(private_retransmit_job_t *this)
{
this->ike_sa_id->destroy(this->ike_sa_id);
free(this);
@@ -93,9 +92,9 @@ static void destroy(private_retransmit_request_job_t *this)
/*
* Described in header.
*/
retransmit_request_job_t *retransmit_request_job_create(u_int32_t message_id,ike_sa_id_t *ike_sa_id)
retransmit_job_t *retransmit_job_create(u_int32_t message_id,ike_sa_id_t *ike_sa_id)
{
private_retransmit_request_job_t *this = malloc_thing(private_retransmit_request_job_t);
private_retransmit_job_t *this = malloc_thing(private_retransmit_job_t);
/* interface functions */
this->public.job_interface.get_type = (job_type_t (*) (job_t *)) get_type;
@@ -106,5 +105,5 @@ retransmit_request_job_t *retransmit_request_job_create(u_int32_t message_id,ike
this->message_id = message_id;
this->ike_sa_id = ike_sa_id->clone(ike_sa_id);
return &(this->public);
return &this->public;
}
@@ -1,12 +1,12 @@
/**
* @file retransmit_request_job.h
* @file retransmit_job.h
*
* @brief Interface of retransmit_request_job_t.
* @brief Interface of retransmit_job_t.
*
*/
/*
* Copyright (C) 2005-2006 Martin Willi
* Copyright (C) 2005-2007 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
*
@@ -21,28 +21,28 @@
* for more details.
*/
#ifndef RESEND_MESSAGE_JOB_H_
#define RESEND_MESSAGE_JOB_H_
#ifndef RETRANSMIT_JOB_H_
#define RETRANSMIT_JOB_H_
typedef struct retransmit_request_job_t retransmit_request_job_t;
typedef struct retransmit_job_t retransmit_job_t;
#include <library.h>
#include <queues/jobs/job.h>
#include <sa/ike_sa_id.h>
/**
* @brief Class representing an RETRANSMIT_REQUEST Job.
* @brief Class representing an retransmit Job.
*
* This job is scheduled every time a request is sent over the
* wire. If the response to the request is not received at schedule
* time, the retransmission will be initiated.
*
* @b Constructors:
* - retransmit_request_job_create()
* - retransmit_job_create()
*
* @ingroup jobs
*/
struct retransmit_request_job_t {
struct retransmit_job_t {
/**
* The job_t interface.
*/
@@ -50,15 +50,15 @@ struct retransmit_request_job_t {
};
/**
* @brief Creates a job of type RETRANSMIT_REQUEST.
* @brief Creates a job of type retransmit.
*
* @param message_id message_id of the request to resend
* @param ike_sa_id identification of the ike_sa as ike_sa_id_t object (gets cloned)
* @return retransmit_request_job_t object
* @param ike_sa_id identification of the ike_sa as ike_sa_id_t
* @return retransmit_job_t object
*
* @ingroup jobs
*/
retransmit_request_job_t *retransmit_request_job_create(u_int32_t message_id,
ike_sa_id_t *ike_sa_id);
retransmit_job_t *retransmit_job_create(u_int32_t message_id,
ike_sa_id_t *ike_sa_id);
#endif /* RESEND_MESSAGE_JOB_H_ */
#endif /* RETRANSMIT_JOB_H_ */
+1 -1
View File
@@ -69,7 +69,7 @@ static status_t execute(private_route_job_t *this)
{
ike_sa_t *ike_sa;
ike_sa = charon->ike_sa_manager->checkout_by_id(charon->ike_sa_manager,
ike_sa = charon->ike_sa_manager->checkout_by_peer(charon->ike_sa_manager,
this->connection->get_my_host(this->connection),
this->connection->get_other_host(this->connection),
this->policy->get_my_id(this->policy),
+49 -98
View File
@@ -6,8 +6,8 @@
*/
/*
* Copyright (C) 2005-2007 Martin Willi
* Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger
* Copyright (C) 2005-2006 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
*
@@ -69,11 +69,6 @@ struct private_child_sa_t {
*/
child_sa_t public;
/**
* Name of the policy used by this CHILD_SA
*/
char *name;
struct {
/** address of peer */
host_t *addr;
@@ -133,35 +128,10 @@ struct private_child_sa_t {
*/
time_t install_time;
/**
* Lifetime before rekeying
*/
u_int32_t soft_lifetime;
/**
* Lifetime before delete
*/
u_int32_t hard_lifetime;
/**
* state of the CHILD_SA
*/
child_sa_state_t state;
/**
* transaction which is rekeying this CHILD_SA
*/
transaction_t *rekeying_transaction;
/**
* Updown script
*/
char *script;
/**
* Allow host access
*/
bool hostaccess;
/**
* Specifies if NAT traversal is used
@@ -172,6 +142,11 @@ struct private_child_sa_t {
* mode this SA uses, tunnel/transport
*/
mode_t mode;
/**
* policy used to create this child
*/
policy_t *policy;
};
/**
@@ -179,22 +154,7 @@ struct private_child_sa_t {
*/
static char *get_name(private_child_sa_t *this)
{
return this->name;
}
/**
* Implementation of child_sa_t.set_name.
*/
static void set_name(private_child_sa_t *this, char* name)
{
char buffer[64];
if (snprintf(buffer, sizeof(buffer), "%s[%d]",
name, this->reqid - REQID_START) > 0)
{
free(this->name);
this->name = strdup(buffer);
}
return this->policy->get_name(this->policy);;
}
/**
@@ -233,6 +193,14 @@ static child_sa_state_t get_state(private_child_sa_t *this)
return this->state;
}
/**
* Implements child_sa_t.get_policy
*/
static policy_t* get_policy(private_child_sa_t *this)
{
return this->policy;
}
/**
* Run the up/down script
*/
@@ -240,8 +208,11 @@ static void updown(private_child_sa_t *this, bool up)
{
sa_policy_t *policy;
iterator_t *iterator;
char *script;
if (this->script == NULL)
script = this->policy->get_updown(this->policy);
if (script == NULL)
{
return;
}
@@ -307,7 +278,7 @@ static void updown(private_child_sa_t *this, bool up)
policy->my_ts->is_host(policy->my_ts,
this->me.addr) ? "-host" : "-client",
this->me.addr->get_family(this->me.addr) == AF_INET ? "" : "-ipv6",
this->name,
this->policy->get_name(this->policy),
ifname,
this->reqid,
this->me.addr,
@@ -322,8 +293,8 @@ static void updown(private_child_sa_t *this, bool up)
other_client, other_client_mask,
policy->other_ts->get_from_port(policy->other_ts),
policy->other_ts->get_protocol(policy->other_ts),
this->hostaccess? "PLUTO_HOST_ACCESS='1' " : "",
this->script);
this->policy->get_hostaccess(this->policy) ?
"PLUTO_HOST_ACCESS='1' " : "", script);
free(ifname);
free(my_client);
free(other_client);
@@ -332,7 +303,7 @@ static void updown(private_child_sa_t *this, bool up)
if (shell == NULL)
{
DBG1(DBG_CHD, "could not execute updown script '%s'", this->script);
DBG1(DBG_CHD, "could not execute updown script '%s'", script);
return;
}
@@ -447,7 +418,7 @@ static status_t alloc(private_child_sa_t *this, linked_list_t *proposals)
static status_t install(private_child_sa_t *this, proposal_t *proposal,
mode_t mode, prf_plus_t *prf_plus, bool mine)
{
u_int32_t spi;
u_int32_t spi, soft, hard;;
algorithm_t *enc_algo, *int_algo;
algorithm_t enc_algo_none = {ENCR_UNDEFINED, 0};
algorithm_t int_algo_none = {AUTH_UNDEFINED, 0};
@@ -532,16 +503,15 @@ static status_t install(private_child_sa_t *this, proposal_t *proposal,
natt = NULL;
}
soft = this->policy->get_soft_lifetime(this->policy);
hard = this->policy->get_hard_lifetime(this->policy);
/* send SA down to the kernel */
DBG2(DBG_CHD, " SPI 0x%.8x, src %H dst %H", ntohl(spi), src, dst);
status = charon->kernel_interface->add_sa(charon->kernel_interface,
src, dst,
spi, this->protocol,
this->reqid,
mine ? this->soft_lifetime : 0,
this->hard_lifetime,
enc_algo, int_algo,
src, dst, spi, this->protocol,
this->reqid, mine ? soft : 0,
hard, enc_algo, int_algo,
prf_plus, natt, mode, mine);
this->encryption = *enc_algo;
@@ -704,22 +674,6 @@ static linked_list_t *get_other_traffic_selectors(private_child_sa_t *this)
return this->other_ts;
}
/**
* Implementation of child_sa_t.set_rekeying_transaction.
*/
static void set_rekeying_transaction(private_child_sa_t *this, transaction_t *transaction)
{
this->rekeying_transaction = transaction;
}
/**
* Implementation of child_sa_t.get_rekeying_transaction.
*/
static transaction_t* get_rekeying_transaction(private_child_sa_t *this)
{
return this->rekeying_transaction;
}
/**
* Implementation of child_sa_t.get_use_time
*/
@@ -769,7 +723,7 @@ static int print(FILE *stream, const struct printf_info *info,
private_child_sa_t *this = *((private_child_sa_t**)(args[0]));
iterator_t *iterator;
sa_policy_t *policy;
u_int32_t now, rekeying;
u_int32_t now, rekeying, soft;
u_int32_t use, use_in, use_fwd;
status_t status;
size_t written = 0;
@@ -781,8 +735,9 @@ static int print(FILE *stream, const struct printf_info *info,
now = (u_int32_t)time(NULL);
written += fprintf(stream, "%12s: %N, reqid: %d, %N", this->name,
child_sa_state_names, this->state, this->reqid,
written += fprintf(stream, "%12s{%d}: %N, %N",
this->policy->get_name(this->policy), this->reqid,
child_sa_state_names, this->state,
mode_names, this->mode);
if (this->state == CHILD_INSTALLED)
@@ -793,7 +748,9 @@ static int print(FILE *stream, const struct printf_info *info,
if (info->alt)
{
written += fprintf(stream, "\n%12s: ", this->name);
written += fprintf(stream, "\n%12s{%d}: ",
this->policy->get_name(this->policy),
this->reqid);
if (this->protocol == PROTO_ESP)
{
@@ -815,10 +772,11 @@ static int print(FILE *stream, const struct printf_info *info,
}
written += fprintf(stream, ", rekeying ");
soft = this->policy->get_soft_lifetime(this->policy);
/* calculate rekey times */
if (this->soft_lifetime)
if (soft)
{
rekeying = this->soft_lifetime - (now - this->install_time);
rekeying = soft - (now - this->install_time);
written += fprintf(stream, "in %ds", rekeying);
}
else
@@ -830,8 +788,9 @@ static int print(FILE *stream, const struct printf_info *info,
iterator = this->policies->create_iterator(this->policies, TRUE);
while (iterator->iterate(iterator, (void**)&policy))
{
written += fprintf(stream, "\n%12s: %R===%R, last use: ",
this->name, policy->my_ts, policy->other_ts);
written += fprintf(stream, "\n%12s{%d}: %R===%R, last use: ",
this->policy->get_name(this->policy), this->reqid,
policy->my_ts, policy->other_ts);
/* query time of last policy use */
@@ -1074,25 +1033,22 @@ static void destroy(private_child_sa_t *this)
this->other.addr->destroy(this->other.addr);
this->me.id->destroy(this->me.id);
this->other.id->destroy(this->other.id);
free(this->name);
free(this->script);
this->policy->destroy(this->policy);
free(this);
}
/*
* Described in header.
*/
child_sa_t * child_sa_create(u_int32_t rekey, host_t *me, host_t* other,
child_sa_t * child_sa_create(host_t *me, host_t* other,
identification_t *my_id, identification_t *other_id,
u_int32_t soft_lifetime, u_int32_t hard_lifetime,
char *script, bool hostaccess, bool use_natt)
policy_t *policy, u_int32_t rekey, bool use_natt)
{
static u_int32_t reqid = REQID_START;
static u_int32_t reqid = 0;
private_child_sa_t *this = malloc_thing(private_child_sa_t);
/* public functions */
this->public.get_name = (char*(*)(child_sa_t*))get_name;
this->public.set_name = (void(*)(child_sa_t*,char*))set_name;
this->public.get_reqid = (u_int32_t(*)(child_sa_t*))get_reqid;
this->public.get_spi = (u_int32_t(*)(child_sa_t*, bool))get_spi;
this->public.get_protocol = (protocol_id_t(*)(child_sa_t*))get_protocol;
@@ -1104,14 +1060,12 @@ child_sa_t * child_sa_create(u_int32_t rekey, host_t *me, host_t* other,
this->public.get_my_traffic_selectors = (linked_list_t*(*)(child_sa_t*))get_my_traffic_selectors;
this->public.get_other_traffic_selectors = (linked_list_t*(*)(child_sa_t*))get_other_traffic_selectors;
this->public.get_use_time = (status_t (*)(child_sa_t*,bool,time_t*))get_use_time;
this->public.set_rekeying_transaction = (void (*)(child_sa_t*,transaction_t*))set_rekeying_transaction;
this->public.get_rekeying_transaction = (transaction_t* (*)(child_sa_t*))get_rekeying_transaction;
this->public.set_state = (void(*)(child_sa_t*,child_sa_state_t))set_state;
this->public.get_state = (child_sa_state_t(*)(child_sa_t*))get_state;
this->public.get_policy = (policy_t*(*)(child_sa_t*))get_policy;
this->public.destroy = (void(*)(child_sa_t*))destroy;
/* private data */
this->name = strdup("(uninitialized)");
this->me.addr = me->clone(me);
this->other.addr = other->clone(other);
this->me.id = my_id->clone(my_id);
@@ -1120,11 +1074,7 @@ child_sa_t * child_sa_create(u_int32_t rekey, host_t *me, host_t* other,
this->other.spi = 0;
this->alloc_ah_spi = 0;
this->alloc_esp_spi = 0;
this->script = script ? strdup(script) : NULL;
this->hostaccess = hostaccess;
this->use_natt = use_natt;
this->soft_lifetime = soft_lifetime;
this->hard_lifetime = hard_lifetime;
this->state = CHILD_CREATED;
/* reuse old reqid if we are rekeying an existing CHILD_SA */
this->reqid = rekey ? rekey : ++reqid;
@@ -1137,7 +1087,8 @@ child_sa_t * child_sa_create(u_int32_t rekey, host_t *me, host_t* other,
this->other_ts = linked_list_create();
this->protocol = PROTO_NONE;
this->mode = MODE_TUNNEL;
this->rekeying_transaction = NULL;
this->policy = policy;
policy->get_ref(policy);
return &this->public;
}
+13 -36
View File
@@ -6,8 +6,8 @@
*/
/*
* Copyright (C) 2006-2007 Martin Willi
* Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger
* Copyright (C) 2006 Martin Willi
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
@@ -32,7 +32,7 @@ typedef struct child_sa_t child_sa_t;
#include <crypto/prf_plus.h>
#include <encoding/payloads/proposal_substructure.h>
#include <config/proposal.h>
#include <sa/transactions/transaction.h>
#include <config/policies/policy.h>
/**
* Where we should start with reqid enumeration
@@ -109,18 +109,10 @@ struct child_sa_t {
char* (*get_name) (child_sa_t *this);
/**
* @brief Set the name of the policy this IKE_SA uses.
*
* @param this calling object
* @param name name, gets cloned
*/
void (*set_name) (child_sa_t *this, char* name);
/**
* @brief Get the unique reqid of the CHILD SA.
* @brief Get the reqid of the CHILD SA.
*
* Every CHILD_SA has a unique reqid, which is also
* stored down in the kernel.
* Every CHILD_SA has a reqid. The kernel uses this ID to
* identify it.
*
* @param this calling object
* @return reqid of the CHILD SA
@@ -259,23 +251,12 @@ struct child_sa_t {
void (*set_state) (child_sa_t *this, child_sa_state_t state);
/**
* @brief Set the transaction which rekeys this CHILD_SA.
*
* Since either end may initiate CHILD_SA rekeying, we must detect
* such situations to handle them cleanly. A rekeying transaction
* registers itself to the CHILD_SA, and checks later if another
* transaction is in progress of a rekey.
* @brief Get the policy used to set up this child sa.
*
* @param this calling object
*/
void (*set_rekeying_transaction) (child_sa_t *this, transaction_t *transaction);
/**
* @brief Get the transaction which rekeys this CHILD_SA.
*
* @param this calling object
*/
transaction_t* (*get_rekeying_transaction) (child_sa_t *this);
* @return policy
*/
policy_t* (*get_policy) (child_sa_t *this);
/**
* @brief Destroys a child_sa.
@@ -288,23 +269,19 @@ struct child_sa_t {
/**
* @brief Constructor to create a new child_sa_t.
*
* @param rekey_reqid reqid of old CHILD_SA when rekeying, 0 otherwise
* @param me own address
* @param other remote address
* @param my_id id of own peer
* @param other_id id of remote peer
* @param soft_lifetime time before rekeying
* @param hard_lifteime time before delete
* @param script updown script to use when calling child_sa_t.script()
* @param hostaccess allow host access (needed by updown script)
* @param policy policy this CHILD_SA instantiates
* @param reqid reqid of old CHILD_SA when rekeying, 0 otherwise
* @param use_natt TRUE if NAT traversal is used
* @return child_sa_t object
*
* @ingroup sa
*/
child_sa_t * child_sa_create(u_int32_t rekey_reqid, host_t *me, host_t *other,
child_sa_t * child_sa_create(host_t *me, host_t *other,
identification_t *my_id, identification_t* other_id,
u_int32_t soft_lifetime, u_int32_t hard_lifetime,
char *script, bool hostaccess, bool use_natt);
policy_t *policy, u_int32_t reqid, bool use_natt);
#endif /*CHILD_SA_H_*/
+700 -860
View File
File diff suppressed because it is too large Load Diff
+126 -103
View File
@@ -33,7 +33,7 @@ typedef struct ike_sa_t ike_sa_t;
#include <encoding/payloads/proposal_substructure.h>
#include <sa/ike_sa_id.h>
#include <sa/child_sa.h>
#include <sa/transactions/transaction.h>
#include <sa/tasks/task.h>
#include <config/configuration.h>
#include <utils/randomizer.h>
#include <crypto/prfs/prf.h>
@@ -121,7 +121,7 @@ extern enum_name_t *ike_sa_state_names;
* An IKE_SA contains crypto information related to a connection
* with a peer. It contains multiple IPsec CHILD_SA, for which
* it is responsible. All traffic is handled by an IKE_SA, using
* transactions.
* the task manager and its tasks.
*
* @b Constructors:
* - ike_sa_create()
@@ -140,6 +140,14 @@ struct ike_sa_t {
*/
ike_sa_id_t* (*get_id) (ike_sa_t *this);
/**
* @brief Get the numerical ID uniquely defining this IKE_SA.
*
* @param this calling object
* @return unique ID
*/
u_int32_t (*get_unique_id) (ike_sa_t *this);
/**
* @brief Get the state of the IKE_SA.
*
@@ -164,14 +172,6 @@ struct ike_sa_t {
*/
char* (*get_name) (ike_sa_t *this);
/**
* @brief Set the name of the connection this IKE_SA uses.
*
* @param this calling object
* @param name name, gets cloned
*/
void (*set_name) (ike_sa_t *this, char* name);
/**
* @brief Get the own host address.
*
@@ -235,6 +235,38 @@ struct ike_sa_t {
* @param other identification
*/
void (*set_other_id) (ike_sa_t *this, identification_t *other);
/**
* @brief Get the connection used by this IKE_SA.
*
* @param this calling object
* @return connection
*/
connection_t* (*get_connection) (ike_sa_t *this);
/**
* @brief Set the connection to use with this IKE_SA.
*
* @param this calling object
* @param connection connection to use
*/
void (*set_connection) (ike_sa_t *this, connection_t* connection);
/**
* @brief Get the policy used by this IKE_SA.
*
* @param this calling object
* @return policy
*/
policy_t* (*get_policy) (ike_sa_t *this);
/**
* @brief Set the policy to use with this IKE_SA.
*
* @param this calling object
* @param policy policy to use
*/
void (*set_policy) (ike_sa_t *this, policy_t *policy);
/**
* @brief Initiate a new connection.
@@ -308,17 +340,6 @@ struct ike_sa_t {
*/
status_t (*delete) (ike_sa_t *this);
/**
* @brief Retransmits a request.
*
* @param this calling object
* @param message_id ID of the request to retransmit
* @return
* - SUCCESS
* - NOT_FOUND if request doesn't have to be retransmited
*/
status_t (*retransmit_request) (ike_sa_t *this, u_int32_t message_id);
/**
* @brief Processes a incoming IKEv2-Message.
*
@@ -327,7 +348,7 @@ struct ike_sa_t {
* destroy the IKE_SA immediatly, as it is unusable.
*
* @param this calling object
* @param[in] message message to process
* @param message message to process
* @return
* - SUCCESS
* - FAILED
@@ -336,44 +357,33 @@ struct ike_sa_t {
status_t (*process_message) (ike_sa_t *this, message_t *message);
/**
* @brief Get the next message ID for a request.
*
* @brief Generate a IKE message to send it to the peer.
*
* This method generates all payloads in the message and encrypts/signs
* the packet.
*
* @param this calling object
* @return the next message id
* @param message message to generate
* @param packet generated output packet
* @return
* - SUCCESS
* - FAILED
* - DESTROY_ME if this IKE_SA MUST be deleted
*/
u_int32_t (*get_next_message_id) (ike_sa_t *this);
status_t (*generate_message) (ike_sa_t *this, message_t *message,
packet_t **packet);
/**
* @brief Check if NAT traversal is enabled for this IKE_SA.
*
* @param this calling object
* @return TRUE if NAT traversal enabled
*/
bool (*is_natt_enabled) (ike_sa_t *this);
/**
* @brief Enable NAT detection for this IKE_SA.
*
* If a Network address translation is detected with
* NAT_DETECTION notifys, a SA must switch to ports
* 4500. To enable this behavior, call enable_natt().
* It is relevant which peer is NATted, this is specified
* with the "local" parameter. Call it twice when both
* are NATted.
*
* @param this calling object
* @param local TRUE, if we are NATted, FALSE if other
*/
void (*enable_natt) (ike_sa_t *this, bool local);
/**
* @brief Apply connection parameters for this IKE_SA.
* @brief Retransmits a request.
*
* @param this calling object
* @param connection connection definition
* @param this calling object
* @param message_id ID of the request to retransmit
* @return
* - SUCCESS
* - NOT_FOUND if request doesn't have to be retransmited
*/
void (*apply_connection) (ike_sa_t *this, connection_t *connection);
status_t (*retransmit) (ike_sa_t *this, u_int32_t message_id);
/**
* @brief Sends a DPD request to the peer.
*
@@ -399,6 +409,29 @@ struct ike_sa_t {
* @param this calling object
*/
void (*send_keepalive) (ike_sa_t *this);
/**
* @brief Check if NAT traversal is enabled for this IKE_SA.
*
* @param this calling object
* @return TRUE if NAT traversal enabled
*/
bool (*is_natt_enabled) (ike_sa_t *this);
/**
* @brief Enable NAT detection for this IKE_SA.
*
* If a Network address translation is detected with
* NAT_DETECTION notifys, a SA must switch to ports
* 4500. To enable this behavior, call enable_natt().
* It is relevant which peer is NATted, this is specified
* with the "local" parameter. Call it twice when both
* are NATted.
*
* @param this calling object
* @param local TRUE, if we are NATted, FALSE if other
*/
void (*enable_natt) (ike_sa_t *this, bool local);
/**
* @brief Derive all keys and create the transforms for IKE communication.
@@ -411,15 +444,14 @@ struct ike_sa_t {
*
* @param this calling object
* @param proposal proposal which contains algorithms to use
* @param dh diffie hellman object with shared secret
* @param secret secret derived from DH exchange, gets freed
* @param nonce_i initiators nonce
* @param nonce_r responders nonce
* @param initiator TRUE if initiator, FALSE otherwise
* @param child_prf PRF with SK_d key when rekeying, NULL otherwise
* @param old_prf general purpose PRF of old SA when rekeying
*/
status_t (*derive_keys)(ike_sa_t *this, proposal_t* proposal,
diffie_hellman_t *dh,
status_t (*derive_keys)(ike_sa_t *this, proposal_t* proposal, chunk_t secret,
chunk_t nonce_i, chunk_t nonce_r,
bool initiator, prf_t *child_prf, prf_t *old_prf);
@@ -463,15 +495,6 @@ struct ike_sa_t {
*/
void (*add_child_sa) (ike_sa_t *this, child_sa_t *child_sa);
/**
* @brief Check if an IKE_SA has one or more CHILD_SAs with a given reqid.
*
* @param this calling object
* @param reqid reqid of the CHILD
* @return TRUE if it has such a CHILD, FALSE if not
*/
bool (*has_child_sa) (ike_sa_t *this, u_int32_t reqid);
/**
* @brief Get a CHILD_SA identified by protocol and SPI.
*
@@ -536,22 +559,6 @@ struct ike_sa_t {
*/
status_t (*destroy_child_sa) (ike_sa_t *this, protocol_id_t protocol, u_int32_t spi);
/**
* @brief Set lifetimes of an IKE_SA.
*
* Two lifetimes are specified. The soft_lifetime says, when rekeying should
* be initiated. The hard_lifetime says, when the IKE_SA has been expired
* and must be deleted. Normally, hard_lifetime > soft_lifetime, and
* hard_lifetime is only reached when rekeying at soft_lifetime fails.
*
* @param this calling object
* @param reauth use full reauthentication instead of rekeying.
* @param soft_lifetime soft_lifetime
* @param hard_lifetime hard_lifetime
*/
void (*set_lifetimes) (ike_sa_t *this, bool reauth,
u_int32_t soft_lifetime, u_int32_t hard_lifetime);
/**
* @brief Rekey the IKE_SA.
*
@@ -563,42 +570,60 @@ struct ike_sa_t {
status_t (*rekey) (ike_sa_t *this);
/**
* @brief Reauthentication the IKE_SA.
* @brief Restablish the IKE_SA.
*
* Create a completely new IKE_SA with authentication, recreates all children
* within the IKE_SA and shuts the old SA down.
* within the IKE_SA, but lets the old IKE_SA untouched.
*
* @param this calling object
* @return - SUCCESS, if IKE_SA rekeying initiated
*/
status_t (*reauth) (ike_sa_t *this);
void (*reestablish) (ike_sa_t *this);
/**
* @brief Get the transaction which rekeys this IKE_SA.
* @brief Set the virtual IP to use for this IKE_SA and its children.
*
* The virtual IP is assigned per IKE_SA, not per CHILD_SA. It has the same
* lifetime as the IKE_SA.
*
* @param this calling object
* @return rekey_ike_sa_t transaction or NULL
*/
transaction_t* (*get_rekeying_transaction) (ike_sa_t *this);
void (*set_virtual_ip) (ike_sa_t *this, bool local, host_t *ip);
/**
* @brief Set the transaction which rekeys this IKE_SA.
* @brief Get the virtual IP configured.
*
* @param this calling object
* @param rekey rekey_ike_sa_t transaction or NULL
* @param local TRUE to get local virtual IP, FALSE for remote
*/
void (*set_rekeying_transaction) (ike_sa_t *this, transaction_t *rekey);
host_t* (*get_virtual_ip) (ike_sa_t *this, bool local);
/**
* @brief Move all children from other IKE_SA to this IKE_SA.
* @brief Add a DNS server to the system.
*
* After rekeying completes, all children are switched over to the
* newly created IKE_SA.
* An IRAS may send a DNS server. To use it, it is installed on the
* system. The DNS entry has a lifetime until the IKE_SA gets closed.
*
* @param this stepfather
* @param other deceased (rekeyed) IKE_SA
* @param this calling object
* @param dns DNS server to install on the system
*/
void (*adopt_children) (ike_sa_t *this, ike_sa_t *other);
void (*add_dns_server) (ike_sa_t *this, host_t *dns);
/**
* @brief Inherit all attributes of other to this after rekeying.
*
* When rekeying is completed, all CHILD_SAs, the virtual IP and all
* outstanding tasks are moved from other to this.
*
* @param this calling object
*/
void (*inherit) (ike_sa_t *this, ike_sa_t *other);
/**
* @brief Reset the IKE_SA, useable when initiating fails
*
* @param this calling object
*/
void (*reset) (ike_sa_t *this);
/**
* @brief Destroys a ike_sa_t object.
@@ -611,8 +636,6 @@ struct ike_sa_t {
/**
* @brief Creates an ike_sa_t object with a specific ID.
*
* The ID gets cloned internally.
*
* @param ike_sa_id ike_sa_id_t object to associate with new IKE_SA
* @return ike_sa_t object
*
+224 -293
View File
@@ -296,14 +296,135 @@ static u_int64_t get_next_spi(private_ike_sa_manager_t *this)
return spi;
}
/**
* Implementation of of ike_sa_manager.checkout.
*/
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;
ike_sa_t *ike_sa = NULL;
DBG2(DBG_MGR, "checkout IKE_SA: %J", ike_sa_id);
DBG2(DBG_MGR, "%d IKE_SAs in manager",
this->ike_sa_list->get_count(this->ike_sa_list));
/* each access is locked */
pthread_mutex_lock(&(this->mutex));
responder_spi_set = ike_sa_id->get_responder_spi(ike_sa_id);
initiator_spi_set = ike_sa_id->get_initiator_spi(ike_sa_id);
original_initiator = ike_sa_id->is_initiator(ike_sa_id);
if ((initiator_spi_set && responder_spi_set) ||
((initiator_spi_set && !responder_spi_set) && (original_initiator)))
{
/* we SHOULD have an IKE_SA for these SPIs in the list,
* if not, we can't handle the request...
*/
entry_t *entry;
/* look for the entry */
if (get_entry_by_id(this, ike_sa_id, &entry) == SUCCESS)
{
if (wait_for_entry(this, entry))
{
DBG2(DBG_MGR, "IKE_SA successfully checked out");
/* ok, this IKE_SA is finally ours */
entry->checked_out = TRUE;
ike_sa = entry->ike_sa;
/* update responder SPI when it's not set */
if (entry->ike_sa_id->get_responder_spi(entry->ike_sa_id) == 0)
{
ike_sa_id_t *ike_sa_ike_sa_id = ike_sa->get_id(ike_sa);
u_int64_t spi = ike_sa_id->get_responder_spi(ike_sa_id);
ike_sa_ike_sa_id->set_responder_spi(ike_sa_ike_sa_id, spi);
entry->ike_sa_id->set_responder_spi(entry->ike_sa_id, spi);
}
}
else
{
DBG2(DBG_MGR, "IKE_SA found, but not allowed to check it out");
}
}
else
{
DBG2(DBG_MGR, "IKE_SA not stored in list");
/* looks like there is no such IKE_SA, better luck next time... */
}
}
else if ((initiator_spi_set && !responder_spi_set) && (!original_initiator))
{
/* an IKE_SA_INIT from an another endpoint,
* he is the initiator.
* For simplicity, we do NOT check for retransmitted
* IKE_SA_INIT-Requests here, so EVERY single IKE_SA_INIT-
* Request (even a retransmitted one) will result in a
* IKE_SA. This could be improved...
*/
u_int64_t responder_spi;
entry_t *new_entry;
/* set SPIs, we are the responder */
responder_spi = get_next_spi(this);
/* we also set arguments spi, so its still valid */
ike_sa_id->set_responder_spi(ike_sa_id, responder_spi);
/* create entry */
new_entry = entry_create(ike_sa_id);
this->ike_sa_list->insert_last(this->ike_sa_list, new_entry);
/* check ike_sa out */
DBG2(DBG_MGR, "IKE_SA added to list of known IKE_SAs");
new_entry->checked_out = TRUE;
ike_sa = new_entry->ike_sa;
}
else if (!initiator_spi_set && !responder_spi_set)
{
/* checkout of a new and unused IKE_SA, used for rekeying */
entry_t *new_entry;
if (original_initiator)
{
ike_sa_id->set_initiator_spi(ike_sa_id, get_next_spi(this));
}
else
{
ike_sa_id->set_responder_spi(ike_sa_id, get_next_spi(this));
}
/* create entry */
new_entry = entry_create(ike_sa_id);
DBG2(DBG_MGR, "created IKE_SA: %J", ike_sa_id);
this->ike_sa_list->insert_last(this->ike_sa_list, new_entry);
/* check ike_sa out */
new_entry->checked_out = TRUE;
ike_sa = new_entry->ike_sa;
}
else
{
/* responder set, initiator not: here is something seriously wrong! */
DBG2(DBG_MGR, "invalid IKE_SA SPIs");
}
pthread_mutex_unlock(&(this->mutex));
charon->bus->set_sa(charon->bus, ike_sa);
return ike_sa;
}
/**
* Implementation of of ike_sa_manager.checkout_by_id.
*/
static ike_sa_t* checkout_by_id(private_ike_sa_manager_t *this,
host_t *my_host,
host_t *other_host,
identification_t *my_id,
identification_t *other_id)
static ike_sa_t* checkout_by_peer(private_ike_sa_manager_t *this,
host_t *my_host, host_t *other_host,
identification_t *my_id,
identification_t *other_id)
{
iterator_t *iterator;
entry_t *entry;
@@ -387,120 +508,15 @@ static ike_sa_t* checkout_by_id(private_ike_sa_manager_t *this,
}
/**
* Implementation of of ike_sa_manager.checkout.
* Implementation of of ike_sa_manager.checkout_by_id.
*/
static ike_sa_t* checkout(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id)
static ike_sa_t* checkout_by_id(private_ike_sa_manager_t *this, u_int32_t id,
bool child)
{
bool responder_spi_set;
bool initiator_spi_set;
bool original_initiator;
ike_sa_t *ike_sa = NULL;
DBG2(DBG_MGR, "checkout IKE_SA: %J", ike_sa_id);
DBG2(DBG_MGR, "%d IKE_SAs in manager",
this->ike_sa_list->get_count(this->ike_sa_list));
/* each access is locked */
pthread_mutex_lock(&(this->mutex));
responder_spi_set = ike_sa_id->get_responder_spi(ike_sa_id);
initiator_spi_set = ike_sa_id->get_initiator_spi(ike_sa_id);
original_initiator = ike_sa_id->is_initiator(ike_sa_id);
if ((initiator_spi_set && responder_spi_set) ||
((initiator_spi_set && !responder_spi_set) && (original_initiator)))
{
/* we SHOULD have an IKE_SA for these SPIs in the list,
* if not, we can't handle the request...
*/
entry_t *entry;
/* look for the entry */
if (get_entry_by_id(this, ike_sa_id, &entry) == SUCCESS)
{
if (wait_for_entry(this, entry))
{
DBG2(DBG_MGR, "IKE_SA successfully checked out");
/* ok, this IKE_SA is finally ours */
entry->checked_out = TRUE;
ike_sa = entry->ike_sa;
}
else
{
DBG2(DBG_MGR, "IKE_SA found, but not allowed to check it out");
}
}
else
{
DBG2(DBG_MGR, "IKE_SA not stored in list");
/* looks like there is no such IKE_SA, better luck next time... */
}
}
else if ((initiator_spi_set && !responder_spi_set) && (!original_initiator))
{
/* an IKE_SA_INIT from an another endpoint,
* he is the initiator.
* For simplicity, we do NOT check for retransmitted
* IKE_SA_INIT-Requests here, so EVERY single IKE_SA_INIT-
* Request (even a retransmitted one) will result in a
* IKE_SA. This could be improved...
*/
u_int64_t responder_spi;
entry_t *new_entry;
/* set SPIs, we are the responder */
responder_spi = get_next_spi(this);
/* we also set arguments spi, so its still valid */
ike_sa_id->set_responder_spi(ike_sa_id, responder_spi);
/* create entry */
new_entry = entry_create(ike_sa_id);
this->ike_sa_list->insert_last(this->ike_sa_list, new_entry);
/* check ike_sa out */
DBG2(DBG_MGR, "IKE_SA added to list of known IKE_SAs");
new_entry->checked_out = TRUE;
ike_sa = new_entry->ike_sa;
}
else if (!initiator_spi_set && !responder_spi_set && original_initiator)
{
/* checkout of a new and unused IKE_SA, used for rekeying */
entry_t *new_entry;
ike_sa_id->set_initiator_spi(ike_sa_id, get_next_spi(this));
/* create entry */
new_entry = entry_create(ike_sa_id);
DBG2(DBG_MGR, "created IKE_SA: %J", ike_sa_id);
this->ike_sa_list->insert_last(this->ike_sa_list, new_entry);
/* check ike_sa out */
new_entry->checked_out = TRUE;
ike_sa = new_entry->ike_sa;
}
else
{
/* responder set, initiator not: here is something seriously wrong! */
DBG2(DBG_MGR, "invalid IKE_SA SPIs");
}
pthread_mutex_unlock(&(this->mutex));
charon->bus->set_sa(charon->bus, ike_sa);
return ike_sa;
}
/**
* Implementation of of ike_sa_manager.checkout_by_child.
*/
static ike_sa_t* checkout_by_child(private_ike_sa_manager_t *this,
u_int32_t reqid)
{
iterator_t *iterator;
iterator_t *iterator, *children;
entry_t *entry;
ike_sa_t *ike_sa = NULL;
child_sa_t *child_sa;
pthread_mutex_lock(&(this->mutex));
@@ -509,12 +525,85 @@ static ike_sa_t* checkout_by_child(private_ike_sa_manager_t *this,
{
if (wait_for_entry(this, entry))
{
/* ok, access is exclusive for us, check for child */
if (entry->ike_sa->has_child_sa(entry->ike_sa, reqid))
/* look for a child with such a reqid ... */
if (child)
{
children = entry->ike_sa->create_child_sa_iterator(entry->ike_sa);
while (children->iterate(children, (void**)&child_sa))
{
if (child_sa->get_reqid(child_sa) == id)
{
ike_sa = entry->ike_sa;
break;
}
}
children->destroy(children);
}
else /* ... or for a IKE_SA with such a unique id */
{
if (entry->ike_sa->get_unique_id(entry->ike_sa) == id)
{
ike_sa = entry->ike_sa;
}
}
/* got one, return */
if (ike_sa)
{
entry->checked_out = TRUE;
break;
}
}
}
iterator->destroy(iterator);
pthread_mutex_unlock(&(this->mutex));
charon->bus->set_sa(charon->bus, ike_sa);
return ike_sa;
}
/**
* Implementation of of ike_sa_manager.checkout_by_name.
*/
static ike_sa_t* checkout_by_name(private_ike_sa_manager_t *this, char *name,
bool child)
{
iterator_t *iterator, *children;
entry_t *entry;
ike_sa_t *ike_sa = NULL;
child_sa_t *child_sa;
pthread_mutex_lock(&(this->mutex));
iterator = this->ike_sa_list->create_iterator(this->ike_sa_list, TRUE);
while (iterator->iterate(iterator, (void**)&entry))
{
if (wait_for_entry(this, entry))
{
/* look for a child with such a policy name ... */
if (child)
{
children = entry->ike_sa->create_child_sa_iterator(entry->ike_sa);
while (children->iterate(children, (void**)&child_sa))
{
if (streq(child_sa->get_name(child_sa), name))
{
ike_sa = entry->ike_sa;
break;
}
}
children->destroy(children);
}
else /* ... or for a IKE_SA with such a connection name */
{
if (streq(entry->ike_sa->get_name(entry->ike_sa), name))
{
ike_sa = entry->ike_sa;
}
}
/* got one, return */
if (ike_sa)
{
/* match */
entry->checked_out = TRUE;
ike_sa = entry->ike_sa;
break;
}
}
@@ -529,9 +618,16 @@ static ike_sa_t* checkout_by_child(private_ike_sa_manager_t *this,
/**
* Iterator hook for iterate, gets ike_sas instead of entries
*/
static void* iterator_hook(void *value)
static bool iterator_hook(private_ike_sa_manager_t* this, entry_t *in,
ike_sa_t **out)
{
return ((entry_t*)value)->ike_sa;
/* check out entry */
if (wait_for_entry(this, in))
{
*out = in->ike_sa;
return TRUE;
}
return FALSE;
}
/**
@@ -540,9 +636,9 @@ static void* iterator_hook(void *value)
static iterator_t *create_iterator(private_ike_sa_manager_t* this)
{
iterator_t *iterator = this->ike_sa_list->create_iterator_locked(
this->ike_sa_list, &this->mutex);
this->ike_sa_list, &this->mutex);
/* register hook to iterator over ike_sas, not entries */
iterator->set_iterator_hook(iterator, iterator_hook);
iterator->set_iterator_hook(iterator, (iterator_hook_t*)iterator_hook, this);
return iterator;
}
@@ -633,170 +729,6 @@ static status_t checkin_and_destroy(private_ike_sa_manager_t *this, ike_sa_t *ik
return retval;
}
/**
* Implementation of ike_sa_manager_t.delete.
*/
static status_t delete_(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id)
{
/* deletion is a bit complex, we must garant that no thread is waiting for
* this SA.
* We take this SA from the list, and start signaling while threads
* are in the condvar.
*/
entry_t *entry;
status_t retval;
DBG2(DBG_MGR, "delete IKE_SA: %J", ike_sa_id);
pthread_mutex_lock(&(this->mutex));
if (get_entry_by_id(this, ike_sa_id, &entry) == SUCCESS)
{
/* we try a delete. If it succeeds, our job is done here. The
* other peer will reply, and the IKE SA gets the finally deleted...
*/
if (entry->ike_sa->delete(entry->ike_sa) == SUCCESS)
{
DBG2(DBG_MGR, "initiated delete for IKE_SA");
}
/* but if the IKE SA is not in a state where the deletion is
* negotiated with the other peer, we can destroy the IKE SA on our own.
*/
else
{
}
retval = SUCCESS;
}
else
{
DBG2(DBG_MGR, "tried to delete nonexisting IKE_SA");
retval = NOT_FOUND;
}
pthread_mutex_unlock(&(this->mutex));
return retval;
}
/**
* Implementation of ike_sa_manager_t.delete_by_name.
*/
static status_t delete_by_name(private_ike_sa_manager_t *this, char *name)
{
iterator_t *iterator;
iterator_t *child_iter;
entry_t *entry;
size_t name_len = strlen(name);
pthread_mutex_lock(&(this->mutex));
iterator = this->ike_sa_list->create_iterator(this->ike_sa_list, TRUE);
while (iterator->iterate(iterator, (void**)&entry))
{
if (wait_for_entry(this, entry))
{
/* delete ike_sa if:
* name{x} matches completely
* name{} matches by name
* name matches by name
*/
bool del = FALSE;
char *ike_name;
char *child_name;
child_sa_t *child_sa;
ike_name = entry->ike_sa->get_name(entry->ike_sa);
/* check if "name{x}" matches completely */
if (strcmp(name, ike_name) == 0)
{
del = TRUE;
}
/* check if name is in form of "name{}" and matches to ike_name */
else if (name_len > 1 &&
name[name_len - 2] == '{' && name[name_len - 1] == '}' &&
strlen(ike_name) > name_len &&
ike_name[name_len - 2] == '{' &&
strncmp(name, ike_name, name_len - 2) == 0)
{
del = TRUE;
}
/* finally, check if name is "name" and matches ike_name */
else if (name_len == strchr(ike_name, '{') - ike_name &&
strncmp(name, ike_name, name_len) == 0)
{
del = TRUE;
}
if (del)
{
if (entry->ike_sa->delete(entry->ike_sa) == DESTROY_ME)
{
delete_entry(this, entry);
iterator->reset(iterator);
}
/* no need to check children, as we delete all */
continue;
}
/* and now the same game for all children. delete child_sa if:
* name[x] matches completely
* name[] matches by name
* name matches by name
*/
child_iter = entry->ike_sa->create_child_sa_iterator(entry->ike_sa);
while (child_iter->iterate(child_iter, (void**)&child_sa))
{
/* skip ROUTED children, they have their "unroute" command */
if (child_sa->get_state(child_sa) == CHILD_ROUTED)
{
continue;
}
child_name = child_sa->get_name(child_sa);
del = FALSE;
/* check if "name[x]" matches completely */
if (strcmp(name, child_name) == 0)
{
del = TRUE;
}
/* check if name is in form of "name[]" and matches to child_name */
else if (name_len > 1 &&
name[name_len - 2] == '[' && name[name_len - 1] == ']' &&
strlen(child_name) > name_len &&
child_name[name_len - 2] == '[' &&
strncmp(name, child_name, name_len - 2) == 0)
{
del = TRUE;
}
/* finally, check if name is "name" and matches child_name */
else if (name_len == strchr(child_name, '[') - child_name &&
strncmp(name, child_name, name_len) == 0)
{
del = TRUE;
}
if (del)
{
if (entry->ike_sa->delete_child_sa(entry->ike_sa,
child_sa->get_protocol(child_sa),
child_sa->get_spi(child_sa, TRUE)) == DESTROY_ME)
{
/* when a fatal error occurs, we are responsible to
* remove the IKE_SA */
delete_entry(this, entry);
iterator->reset(iterator);
break;
}
}
}
child_iter->destroy(child_iter);
}
}
iterator->destroy(iterator);
pthread_mutex_unlock(&(this->mutex));
return SUCCESS;
}
/**
* Implementation of ike_sa_manager_t.destroy.
*/
@@ -859,19 +791,18 @@ ike_sa_manager_t *ike_sa_manager_create()
/* assign public functions */
this->public.destroy = (void(*)(ike_sa_manager_t*))destroy;
this->public.checkout_by_id = (ike_sa_t*(*)(ike_sa_manager_t*,host_t*,host_t*,identification_t*,identification_t*))checkout_by_id;
this->public.checkout = (ike_sa_t*(*)(ike_sa_manager_t*, ike_sa_id_t*))checkout;
this->public.checkout_by_child = (ike_sa_t*(*)(ike_sa_manager_t*,u_int32_t))checkout_by_child;
this->public.checkout_by_peer = (ike_sa_t*(*)(ike_sa_manager_t*,host_t*,host_t*,identification_t*,identification_t*))checkout_by_peer;
this->public.checkout_by_id = (ike_sa_t*(*)(ike_sa_manager_t*,u_int32_t,bool))checkout_by_id;
this->public.checkout_by_name = (ike_sa_t*(*)(ike_sa_manager_t*,char*,bool))checkout_by_name;
this->public.create_iterator = (iterator_t*(*)(ike_sa_manager_t*))create_iterator;
this->public.checkin = (status_t(*)(ike_sa_manager_t*,ike_sa_t*))checkin;
this->public.delete = (status_t(*)(ike_sa_manager_t*,ike_sa_id_t*))delete_;
this->public.delete_by_name = (status_t(*)(ike_sa_manager_t*,char*))delete_by_name;
this->public.checkin_and_destroy = (status_t(*)(ike_sa_manager_t*,ike_sa_t*))checkin_and_destroy;
/* initialize private variables */
this->ike_sa_list = linked_list_create();
pthread_mutex_init(&(this->mutex), NULL);
pthread_mutex_init(&this->mutex, NULL);
this->randomizer = randomizer_create();
return (ike_sa_manager_t*)this;
return &this->public;
}
+32 -54
View File
@@ -59,7 +59,7 @@ struct ike_sa_manager_t {
* result in a deadlock!
*
* @param this the manager object
* @param[in/out] ike_sa_id the SA identifier, will be updated
* @param ike_sa_id the SA identifier, will be updated
* @returns
* - checked out IKE_SA if found
* - NULL, if no such IKE_SA available
@@ -82,25 +82,44 @@ struct ike_sa_manager_t {
* @param other_id ID used by remote
* @return checked out/created IKE_SA
*/
ike_sa_t* (*checkout_by_id) (ike_sa_manager_t* this,
host_t *my_host, host_t* other_host,
identification_t *my_id,
identification_t *other_id);
ike_sa_t* (*checkout_by_peer) (ike_sa_manager_t* this,
host_t *my_host, host_t* other_host,
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 a unique ID.
*
* 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.
* Every IKE_SA and every CHILD_SA is uniquely identified by an ID.
* These checkout function uses, depending
* on the child parameter, the unique ID of the IKE_SA or the reqid
* of one of a IKE_SAs CHILD_SA.
*
* @param this the manager object
* @param reqid reqid of the CHILD_SA
* @param id unique ID of the object
* @param child TRUE to use CHILD, FALSE to use IKE_SA
* @return
* - checked out IKE_SA, if found
* - NULL, if not found
*/
ike_sa_t* (*checkout_by_child) (ike_sa_manager_t* this, u_int32_t reqid);
ike_sa_t* (*checkout_by_id) (ike_sa_manager_t* this, u_int32_t id,
bool child);
/**
* @brief Check out an IKE_SA by the policy/connection name.
*
* Check out the IKE_SA by the connections name or by a CHILD_SAs policy
* name.
*
* @param this the manager object
* @param name name of the connection/policy
* @param child TRUE to use policy name, FALSE to use conn name
* @return
* - checked out IKE_SA, if found
* - NULL, if not found
*/
ike_sa_t* (*checkout_by_name) (ike_sa_manager_t* this, char *name,
bool child);
/**
* @brief Create an iterator over all stored IKE_SAs.
@@ -121,55 +140,14 @@ struct ike_sa_manager_t {
* The SA must be checked out again!
*
* @param this the manager object
* @param[in/out] ike_sa_id the SA identifier, will be updated
* @param[out] ike_sa checked out SA
* @param ike_sa_id the SA identifier, will be updated
* @param ike_sa checked out SA
* @returns
* - SUCCESS if checked in
* - NOT_FOUND when not found (shouldn't happen!)
*/
status_t (*checkin) (ike_sa_manager_t* this, ike_sa_t *ike_sa);
/**
* @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 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
* deadlock!
*
* @param this the manager object
* @param[in/out] ike_sa_id the SA identifier
* @returns
* - SUCCESS if found
* - NOT_FOUND when no such SA is available
*/
status_t (*delete) (ike_sa_manager_t* this, ike_sa_id_t *ike_sa_id);
/**
* @brief Delete a SA identified by its name, which was not checked out.
*
* Using delete_by_name allows the delete of IKE_SAs and CHILD_SAs.
* The supplied name may have one of the following format:
*
* name{x} => delete IKE_SA with "name" and unique id "x"
* name{} => delete all IKE_SAs with "name"
* name[x] => delete CHILD_SA with "name" and unique id "x"
* name[] => delete all CHILD_SAs with "name"
* name => delete all CHILD_SAs or IKE_SAs with "name"
*
* @warning do not use this when the SA is already checked out, this will
* deadlock!
*
* @param this the manager object
* @param name name in one of the format described above
* @returns
* - SUCCESS if found
* - NOT_FOUND when no such SA is available
*/
status_t (*delete_by_name) (ike_sa_manager_t* this, char *name);
/**
* @brief Destroy a checked out SA.
*
+780
View File
@@ -0,0 +1,780 @@
/**
* @file task_manager.c
*
* @brief Implementation of task_manager_t.
*
*/
/*
* Copyright (C) 2007 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 <http://www.fsf.org/copyleft/gpl.txt>.
*
* 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 "task_manager.h"
#include <daemon.h>
#include <sa/tasks/ike_init.h>
#include <sa/tasks/ike_natd.h>
#include <sa/tasks/ike_auth.h>
#include <sa/tasks/ike_cert.h>
#include <sa/tasks/ike_rekey.h>
#include <sa/tasks/ike_delete.h>
#include <sa/tasks/ike_config.h>
#include <sa/tasks/ike_dpd.h>
#include <sa/tasks/child_create.h>
#include <sa/tasks/child_rekey.h>
#include <sa/tasks/child_delete.h>
#include <encoding/payloads/delete_payload.h>
#include <queues/jobs/retransmit_job.h>
typedef struct exchange_t exchange_t;
/**
* An exchange in the air, used do detect and handle retransmission
*/
struct exchange_t {
/**
* Message ID used for this transaction
*/
u_int32_t mid;
/**
* generated packet for retransmission
*/
packet_t *packet;
};
typedef struct private_task_manager_t private_task_manager_t;
/**
* private data of the task manager
*/
struct private_task_manager_t {
/**
* public functions
*/
task_manager_t public;
/**
* associated IKE_SA we are serving
*/
ike_sa_t *ike_sa;
/**
* Exchange we are currently handling as responder
*/
struct {
/**
* Message ID of the exchange
*/
u_int32_t mid;
/**
* packet for retransmission
*/
packet_t *packet;
} responding;
/**
* Exchange we are currently handling as initiator
*/
struct {
/**
* Message ID of the exchange
*/
u_int32_t mid;
/**
* how many times we have retransmitted so far
*/
u_int retransmitted;
/**
* packet for retransmission
*/
packet_t *packet;
/**
* type of the initated exchange
*/
exchange_type_t type;
} initiating;
/**
* List of queued tasks not yet in action
*/
linked_list_t *queued_tasks;
/**
* List of active tasks, initiated by ourselve
*/
linked_list_t *active_tasks;
/**
* List of tasks initiated by peer
*/
linked_list_t *passive_tasks;
/**
* ike_sa_init message we sent, stored here for later authentication
*/
packet_t *ike_sa_init;
};
/**
* move a task of a specific type from the queue to the active list
*/
static bool activate_task(private_task_manager_t *this, task_type_t type)
{
iterator_t *iterator;
task_t *task;
bool found = FALSE;
iterator = this->queued_tasks->create_iterator(this->queued_tasks, TRUE);
while (iterator->iterate(iterator, (void**)&task))
{
if (task->get_type(task) == type)
{
DBG2(DBG_IKE, " activating %N task", task_type_names, type);
iterator->remove(iterator);
this->active_tasks->insert_last(this->active_tasks, task);
found = TRUE;
break;
}
}
iterator->destroy(iterator);
return found;
}
/**
* Implementation of task_manager_t.retransmit
*/
static status_t retransmit(private_task_manager_t *this, u_int32_t message_id)
{
if (message_id == this->initiating.mid)
{
u_int32_t timeout;
job_t *job;
timeout = charon->configuration->get_retransmit_timeout(
charon->configuration, this->initiating.retransmitted);
if (timeout == 0)
{
DBG1(DBG_IKE, "giving up after %d retransmits",
this->initiating.retransmitted - 1);
return DESTROY_ME;
}
if (this->initiating.retransmitted)
{
DBG1(DBG_IKE, "retransmit %d of request with message ID %d",
this->initiating.retransmitted, message_id);
}
this->initiating.retransmitted++;
charon->send_queue->add(charon->send_queue,
this->initiating.packet->clone(this->initiating.packet));
job = (job_t*)retransmit_job_create(this->initiating.mid,
this->ike_sa->get_id(this->ike_sa));
charon->event_queue->add_relative(charon->event_queue, job, timeout);
}
return SUCCESS;
}
/**
* build a request using the active task list
* Implementation of task_manager_t.initiate
*/
static status_t build_request(private_task_manager_t *this)
{
iterator_t *iterator;
task_t *task;
message_t *message;
status_t status;
exchange_type_t exchange = 0;
if (this->active_tasks->get_count(this->active_tasks) == 0)
{
DBG2(DBG_IKE, "activating new tasks");
switch (this->ike_sa->get_state(this->ike_sa))
{
case IKE_CREATED:
if (activate_task(this, IKE_INIT))
{
exchange = IKE_SA_INIT;
activate_task(this, IKE_NATD);
activate_task(this, IKE_CERT);
activate_task(this, IKE_AUTHENTICATE);
activate_task(this, IKE_CONFIG);
activate_task(this, CHILD_CREATE);
}
break;
case IKE_ESTABLISHED:
if (activate_task(this, CHILD_CREATE))
{
exchange = CREATE_CHILD_SA;
activate_task(this, IKE_CONFIG);
break;
}
if (activate_task(this, CHILD_DELETE))
{
exchange = INFORMATIONAL;
break;
}
if (activate_task(this, CHILD_REKEY))
{
exchange = CREATE_CHILD_SA;
break;
}
if (activate_task(this, IKE_DELETE))
{
exchange = INFORMATIONAL;
break;
}
if (activate_task(this, IKE_REKEY))
{
exchange = CREATE_CHILD_SA;
break;
}
if (activate_task(this, IKE_DEADPEER))
{
exchange = INFORMATIONAL;
break;
}
case IKE_REKEYING:
if (activate_task(this, IKE_DELETE))
{
exchange = INFORMATIONAL;
break;
}
case IKE_DELETING:
default:
break;
}
}
else
{
DBG2(DBG_IKE, "reinitiating already active tasks");
iterator = this->active_tasks->create_iterator(this->active_tasks, TRUE);
while (iterator->iterate(iterator, (void**)&task))
{
DBG2(DBG_IKE, " %N task", task_type_names, task->get_type(task));
switch (task->get_type(task))
{
case IKE_INIT:
exchange = IKE_SA_INIT;
break;
case IKE_AUTHENTICATE:
exchange = IKE_AUTH;
break;
default:
continue;
}
break;
}
iterator->destroy(iterator);
}
if (exchange == 0)
{
DBG2(DBG_IKE, "nothing to initiate");
/* nothing to do yet... */
return SUCCESS;
}
message = message_create();
message->set_message_id(message, this->initiating.mid);
message->set_exchange_type(message, exchange);
this->initiating.type = exchange;
this->initiating.retransmitted = 0;
iterator = this->active_tasks->create_iterator(this->active_tasks, TRUE);
while (iterator->iterate(iterator, (void*)&task))
{
switch (task->build(task, message))
{
case SUCCESS:
/* task completed, remove it */
iterator->remove(iterator);
task->destroy(task);
break;
case NEED_MORE:
/* processed, but task needs another exchange */
break;
case FAILED:
default:
/* critical failure, destroy IKE_SA */
iterator->destroy(iterator);
message->destroy(message);
return DESTROY_ME;
}
}
iterator->destroy(iterator);
DESTROY_IF(this->initiating.packet);
status = this->ike_sa->generate_message(this->ike_sa, message,
&this->initiating.packet);
message->destroy(message);
if (status != SUCCESS)
{
/* message generation failed. There is nothing more to do than to
* close the SA */
return DESTROY_ME;
}
return retransmit(this, this->initiating.mid);
}
/**
* handle an incoming response message
*/
static status_t process_response(private_task_manager_t *this,
message_t *message)
{
iterator_t *iterator;
task_t *task;
if (message->get_exchange_type(message) != this->initiating.type)
{
DBG1(DBG_IKE, "received %N response, but expected %N",
exchange_type_names, message->get_exchange_type(message),
exchange_type_names, this->initiating.type);
return DESTROY_ME;
}
iterator = this->active_tasks->create_iterator(this->active_tasks, TRUE);
while (iterator->iterate(iterator, (void*)&task))
{
switch (task->process(task, message))
{
case SUCCESS:
/* task completed, remove it */
iterator->remove(iterator);
task->destroy(task);
break;
case NEED_MORE:
/* processed, but task needs another exchange */
break;
case FAILED:
default:
/* critical failure, destroy IKE_SA */
iterator->destroy(iterator);
return DESTROY_ME;
}
}
iterator->destroy(iterator);
this->initiating.mid++;
return build_request(this);
}
/**
* build a response depending on the "passive" task list
*/
static status_t build_response(private_task_manager_t *this,
exchange_type_t exchange)
{
iterator_t *iterator;
task_t *task;
message_t *message;
bool delete = FALSE;
status_t status;
message = message_create();
message->set_exchange_type(message, exchange);
message->set_message_id(message, this->responding.mid);
message->set_request(message, FALSE);
iterator = this->passive_tasks->create_iterator(this->passive_tasks, TRUE);
while (iterator->iterate(iterator, (void*)&task))
{
switch (task->build(task, message))
{
case SUCCESS:
/* task completed, remove it */
iterator->remove(iterator);
task->destroy(task);
break;
case NEED_MORE:
/* processed, but task needs another exchange */
break;
case FAILED:
default:
/* destroy IKE_SA, but SEND response first */
delete = TRUE;
break;
}
if (delete)
{
break;
}
}
iterator->destroy(iterator);
/* message complete, send it */
DESTROY_IF(this->responding.packet);
status = this->ike_sa->generate_message(this->ike_sa, message,
&this->responding.packet);
message->destroy(message);
if (status != SUCCESS)
{
return DESTROY_ME;
}
charon->send_queue->add(charon->send_queue,
this->responding.packet->clone(this->responding.packet));
if (delete)
{
return DESTROY_ME;
}
return SUCCESS;
}
/**
* handle an incoming request message
*/
static status_t process_request(private_task_manager_t *this,
message_t *message)
{
iterator_t *iterator;
task_t *task = NULL;
exchange_type_t exchange;
payload_t *payload;
notify_payload_t *notify;
exchange = message->get_exchange_type(message);
/* create tasks depending on request type */
switch (exchange)
{
case IKE_SA_INIT:
{
task = (task_t*)ike_init_create(this->ike_sa, FALSE, NULL);
this->passive_tasks->insert_last(this->passive_tasks, task);
task = (task_t*)ike_natd_create(this->ike_sa, FALSE);
this->passive_tasks->insert_last(this->passive_tasks, task);
task = (task_t*)ike_cert_create(this->ike_sa, FALSE);
this->passive_tasks->insert_last(this->passive_tasks, task);
task = (task_t*)ike_config_create(this->ike_sa, NULL);
this->passive_tasks->insert_last(this->passive_tasks, task);
task = (task_t*)ike_auth_create(this->ike_sa, FALSE);
this->passive_tasks->insert_last(this->passive_tasks, task);
task = (task_t*)child_create_create(this->ike_sa, NULL);
this->passive_tasks->insert_last(this->passive_tasks, task);
break;
}
case CREATE_CHILD_SA:
{
bool notify_found = FALSE, ts_found = FALSE;
iterator = message->get_payload_iterator(message);
while (iterator->iterate(iterator, (void**)&payload))
{
switch (payload->get_type(payload))
{
case NOTIFY:
{
/* if we find a rekey notify, its CHILD_SA rekeying */
notify = (notify_payload_t*)payload;
if (notify->get_notify_type(notify) == REKEY_SA &&
(notify->get_protocol_id(notify) == PROTO_AH ||
notify->get_protocol_id(notify) == PROTO_ESP))
{
notify_found = TRUE;
}
break;
}
case TRAFFIC_SELECTOR_INITIATOR:
case TRAFFIC_SELECTOR_RESPONDER:
{
/* if we don't find a TS, its IKE rekeying */
ts_found = TRUE;
break;
}
default:
break;
}
}
iterator->destroy(iterator);
if (ts_found)
{
if (notify_found)
{
task = (task_t*)child_rekey_create(this->ike_sa, NULL);
}
else
{
task = (task_t*)child_create_create(this->ike_sa, NULL);
}
}
else
{
task = (task_t*)ike_rekey_create(this->ike_sa, FALSE);
}
this->passive_tasks->insert_last(this->passive_tasks, task);
break;
}
case INFORMATIONAL:
{
delete_payload_t *delete;
delete = (delete_payload_t*)message->get_payload(message, DELETE);
if (delete)
{
if (delete->get_protocol_id(delete) == PROTO_IKE)
{
task = (task_t*)ike_delete_create(this->ike_sa, FALSE);
this->passive_tasks->insert_last(this->passive_tasks, task);
}
else
{
task = (task_t*)child_delete_create(this->ike_sa, NULL);
this->passive_tasks->insert_last(this->passive_tasks, task);
}
}
else
{
task = (task_t*)ike_dpd_create(FALSE);
this->passive_tasks->insert_last(this->passive_tasks, task);
}
break;
}
default:
break;
}
/* let the tasks process the message */
iterator = this->passive_tasks->create_iterator(this->passive_tasks, TRUE);
while (iterator->iterate(iterator, (void*)&task))
{
switch (task->process(task, message))
{
case SUCCESS:
/* task completed, remove it */
iterator->remove(iterator);
task->destroy(task);
break;
case NEED_MORE:
/* processed, but task needs at least another call to build() */
break;
case FAILED:
default:
/* critical failure, destroy IKE_SA */
iterator->destroy(iterator);
return DESTROY_ME;
}
}
iterator->destroy(iterator);
return build_response(this, exchange);
}
/**
* Implementation of task_manager_t.process_message
*/
static status_t process_message(private_task_manager_t *this, message_t *msg)
{
u_int32_t mid = msg->get_message_id(msg);
if (msg->get_request(msg))
{
if (mid == this->responding.mid)
{
if (process_request(this, msg) != SUCCESS)
{
return DESTROY_ME;
}
this->responding.mid++;
}
else if ((mid == this->responding.mid - 1) && this->responding.packet)
{
DBG1(DBG_IKE, "received retransmit of request with ID %d, "
"retransmitting response", mid);
charon->send_queue->add(charon->send_queue,
this->responding.packet->clone(
this->responding.packet));
}
else
{
DBG1(DBG_IKE, "received message ID %d, excepted %d. Ignored",
mid, this->responding.mid);
}
}
else
{
if (mid == this->initiating.mid)
{
if (process_response(this, msg) != SUCCESS)
{
return DESTROY_ME;
}
}
else
{
DBG1(DBG_IKE, "received message ID %d, excepted %d. Ignored",
mid, this->initiating.mid);
return SUCCESS;
}
}
return SUCCESS;
}
/**
* Implementation of task_manager_t.queue_task
*/
static void queue_task(private_task_manager_t *this, task_t *task)
{
DBG2(DBG_IKE, "queueing %N task", task_type_names, task->get_type(task));
this->queued_tasks->insert_last(this->queued_tasks, task);
}
/**
* Implementation of task_manager_t.adopt_tasks
*/
static void adopt_tasks(private_task_manager_t *this, private_task_manager_t *other)
{
task_t *task;
/* move queued tasks from other to this */
while (other->queued_tasks->remove_last(other->queued_tasks,
(void**)&task) == SUCCESS)
{
task->migrate(task, this->ike_sa);
this->queued_tasks->insert_first(this->queued_tasks, task);
}
/* reset active tasks and move them to others queued tasks */
while (other->active_tasks->remove_last(other->active_tasks,
(void**)&task) == SUCCESS)
{
task->migrate(task, this->ike_sa);
this->queued_tasks->insert_first(this->queued_tasks, task);
}
}
/**
* Implementation of task_manager_t.busy
*/
static bool busy(private_task_manager_t *this)
{
return (this->active_tasks->get_count(this->active_tasks) > 0);
}
/**
* Implementation of task_manager_t.reset
*/
static void reset(private_task_manager_t *this)
{
task_t *task;
/* reset message counters and retransmit packets */
DESTROY_IF(this->responding.packet);
DESTROY_IF(this->initiating.packet);
DESTROY_IF(this->ike_sa_init);
this->responding.packet = NULL;
this->initiating.packet = NULL;
this->ike_sa_init = NULL;
this->responding.mid = 0;
this->initiating.mid = -1;
/* reset active tasks */
while (this->active_tasks->remove_last(this->active_tasks,
(void**)&task) == SUCCESS)
{
task->migrate(task, this->ike_sa);
this->queued_tasks->insert_first(this->queued_tasks, task);
}
}
/**
* Implementation of task_manager_t.destroy
*/
static void destroy(private_task_manager_t *this)
{
task_t *task;
this->queued_tasks->destroy_offset(this->queued_tasks,
offsetof(task_t, destroy));
this->passive_tasks->destroy_offset(this->passive_tasks,
offsetof(task_t, destroy));
/* emmit outstanding signals for tasks */
while (this->active_tasks->remove_last(this->active_tasks,
(void**)&task) == SUCCESS)
{
switch (task->get_type(task))
{
case IKE_AUTH:
SIG(IKE_UP_FAILED, "establishing IKE_SA failed");
break;
case IKE_DELETE:
SIG(IKE_DOWN_FAILED, "deleteing IKE_SA properly failed");
break;
case IKE_REKEY:
SIG(IKE_REKEY_FAILED, "rekeying IKE_SA failed");
break;
case CHILD_CREATE:
SIG(CHILD_UP_FAILED, "establishing CHILD_SA failed");
break;
case CHILD_DELETE:
SIG(CHILD_DOWN_FAILED, "deleting CHILD_SA failed");
break;
case CHILD_REKEY:
SIG(IKE_REKEY_FAILED, "rekeying CHILD_SA failed");
break;
default:
break;
}
task->destroy(task);
}
this->active_tasks->destroy(this->active_tasks);
DESTROY_IF(this->responding.packet);
DESTROY_IF(this->initiating.packet);
DESTROY_IF(this->ike_sa_init);
free(this);
}
/*
* see header file
*/
task_manager_t *task_manager_create(ike_sa_t *ike_sa)
{
private_task_manager_t *this = malloc_thing(private_task_manager_t);
this->public.process_message = (status_t(*)(task_manager_t*,message_t*))process_message;
this->public.queue_task = (void(*)(task_manager_t*,task_t*))queue_task;
this->public.initiate = (status_t(*)(task_manager_t*))build_request;
this->public.retransmit = (status_t(*)(task_manager_t*,u_int32_t))retransmit;
this->public.reset = (void(*)(task_manager_t*))reset;
this->public.adopt_tasks = (void(*)(task_manager_t*,task_manager_t*))adopt_tasks;
this->public.busy = (bool(*)(task_manager_t*))busy;
this->public.destroy = (void(*)(task_manager_t*))destroy;
this->ike_sa = ike_sa;
this->responding.packet = NULL;
this->initiating.packet = NULL;
this->responding.mid = 0;
this->initiating.mid = 0;
this->queued_tasks = linked_list_create();
this->active_tasks = linked_list_create();
this->passive_tasks = linked_list_create();
this->ike_sa_init = NULL;
return &this->public;
}
+144
View File
@@ -0,0 +1,144 @@
/**
* @file task_manager.h
*
* @brief Interface of task_manager_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 <http://www.fsf.org/copyleft/gpl.txt>.
*
* 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 TASK_MANAGER_H_
#define TASK_MANAGER_H_
typedef struct task_manager_t task_manager_t;
#include <library.h>
#include <encoding/message.h>
#include <sa/ike_sa.h>
#include <sa/tasks/task.h>
/**
* @brief The task manager, juggles task and handles message exchanges.
*
* On incoming requests, the task manager creates new tasks on demand and
* juggles the request through all available tasks. Each task inspects the
* request and adds payloads as necessary to the response.
* On outgoing requests, the task manager delivers the request through the tasks
* to build it, the response gets processed by each task to complete.
* The task manager has an internal Queue to store task which should get
* completed.
* For the initial IKE_SA setup, several tasks are queued: One for the
* unauthenticated IKE_SA setup, one for authentication, one for CHILD_SA setup
* and maybe one for virtual IP assignement.
*
* @b Constructors:
* - task_manager_create()
*
* @ingroup sa
*/
struct task_manager_t {
/**
* @brief Process an incoming message.
*
* @param this calling object
* @param message message to add payloads to
* @return
* - DESTROY_ME if IKE_SA must be closed
* - SUCCESS otherwise
*/
status_t (*process_message) (task_manager_t *this, message_t *message);
/**
* @brief Initiate an exchange with the currently queued tasks.
*
* @param this calling object
*/
status_t (*initiate) (task_manager_t *this);
/**
* @brief Queue a task in the manager.
*
* @param this calling object
* @param task task to queue
*/
void (*queue_task) (task_manager_t *this, task_t *task);
/**
* @brief Retransmit a request if it hasn't been acknowledged yet.
*
* A return value of INVALID_STATE means that the message was already
* acknowledged and has not to be retransmitted. A return value of SUCCESS
* means retransmission was required and the message has been resent.
*
* @param this calling object
* @param message_id ID of the message to retransmit
* @return
* - INVALID_STATE if retransmission not required
* - SUCCESS if retransmission sent
*/
status_t (*retransmit) (task_manager_t *this, u_int32_t message_id);
/**
* @brief Migrate all tasks from other to this.
*
* To rekey or reestablish an IKE_SA completely, all queued or active
* tasks should get migrated to the new IKE_SA.
*
* @param this manager which gets all tasks
* @param other manager which gives away its tasks
*/
void (*adopt_tasks) (task_manager_t *this, task_manager_t *other);
/**
* @brief Reset message ID counters of the task manager.
*
* The IKEv2 protocol requires to restart exchanges with message IDs
* reset to zero (INVALID_KE_PAYLOAD, COOKIES, ...). The reset() method
* resets the message IDs and resets all active tasks using the migrate()
* method.
*
* @param this calling object
* @param other manager which gives away its tasks
*/
void (*reset) (task_manager_t *this);
/**
* @brief Check if we are currently waiting for a reply.
*
* @param this calling object
* @return TRUE if we are waiting, FALSE otherwise
*/
bool (*busy) (task_manager_t *this);
/**
* @brief Destroy the task_manager_t.
*
* @param this calling object
*/
void (*destroy) (task_manager_t *this);
};
/**
* @brief Create an instance of the task manager.
*
* @param ike_sa IKE_SA to manage.
*
* @ingroup sa
*/
task_manager_t *task_manager_create(ike_sa_t *ike_sa);
#endif /* TASK_MANAGER_H_ */
+718
View File
@@ -0,0 +1,718 @@
/**
* @file child_create.c
*
* @brief Implementation of the child_create task.
*
*/
/*
* Copyright (C) 2005-2007 Martin Willi
* Copyright (C) 2005 Jan Hutter
* 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 <http://www.fsf.org/copyleft/gpl.txt>.
*
* 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 "child_create.h"
#include <daemon.h>
#include <crypto/diffie_hellman.h>
#include <encoding/payloads/sa_payload.h>
#include <encoding/payloads/ts_payload.h>
#include <encoding/payloads/nonce_payload.h>
#include <encoding/payloads/notify_payload.h>
typedef struct private_child_create_t private_child_create_t;
/**
* Private members of a child_create_t task.
*/
struct private_child_create_t {
/**
* Public methods and task_t interface.
*/
child_create_t public;
/**
* Assigned IKE_SA.
*/
ike_sa_t *ike_sa;
/**
* Are we the initiator?
*/
bool initiator;
/**
* nonce chosen by us
*/
chunk_t my_nonce;
/**
* nonce chosen by peer
*/
chunk_t other_nonce;
/**
* policy to create the CHILD_SA from
*/
policy_t *policy;
/**
* list of proposal candidates
*/
linked_list_t *proposals;
/**
* selected proposal to use for CHILD_SA
*/
proposal_t *proposal;
/**
* traffic selectors for initiators side
*/
linked_list_t *tsi;
/**
* traffic selectors for responders side
*/
linked_list_t *tsr;
/**
* mode the new CHILD_SA uses (transport/tunnel/beet)
*/
mode_t mode;
/**
* reqid to use if we are rekeying
*/
u_int32_t reqid;
/**
* CHILD_SA which gets established
*/
child_sa_t *child_sa;
};
/**
* get the nonce from a message
*/
static status_t get_nonce(message_t *message, chunk_t *nonce)
{
nonce_payload_t *payload;
payload = (nonce_payload_t*)message->get_payload(message, NONCE);
if (payload == NULL)
{
return FAILED;
}
*nonce = payload->get_nonce(payload);
return NEED_MORE;
}
/**
* generate a new nonce to include in a CREATE_CHILD_SA message
*/
static status_t generate_nonce(chunk_t *nonce)
{
status_t status;
randomizer_t *randomizer = randomizer_create();
status = randomizer->allocate_pseudo_random_bytes(randomizer, NONCE_SIZE,
nonce);
randomizer->destroy(randomizer);
if (status != SUCCESS)
{
DBG1(DBG_IKE, "error generating random nonce value");
return FAILED;
}
return SUCCESS;
}
/**
* Check a list of traffic selectors if any selector belongs to host
*/
static bool ts_list_is_host(linked_list_t *list, host_t *host)
{
traffic_selector_t *ts;
bool is_host = TRUE;
iterator_t *iterator = list->create_iterator(list, TRUE);
while (is_host && iterator->iterate(iterator, (void**)&ts))
{
is_host = is_host && ts->is_host(ts, host);
}
iterator->destroy(iterator);
return is_host;
}
/**
* Install a CHILD_SA for usage
*/
static status_t select_and_install(private_child_create_t *this)
{
prf_plus_t *prf_plus;
status_t status;
chunk_t nonce_i, nonce_r, seed;
linked_list_t *my_ts, *other_ts;
host_t *me, *other, *other_vip, *my_vip;
if (this->proposals == NULL || this->tsi == NULL || this->tsr == NULL)
{
SIG(CHILD_UP_FAILED, "SA/TS payloads missing in message");
return FAILED;
}
if (this->initiator)
{
nonce_i = this->my_nonce;
nonce_r = this->other_nonce;
my_ts = this->tsi;
other_ts = this->tsr;
}
else
{
nonce_r = this->my_nonce;
nonce_i = this->other_nonce;
my_ts = this->tsr;
other_ts = this->tsi;
}
me = this->ike_sa->get_my_host(this->ike_sa);
other = this->ike_sa->get_other_host(this->ike_sa);
my_vip = this->ike_sa->get_virtual_ip(this->ike_sa, TRUE);
other_vip = this->ike_sa->get_virtual_ip(this->ike_sa, FALSE);
this->proposal = this->policy->select_proposal(this->policy, this->proposals);
if (this->initiator && my_vip)
{ /* if we have a virtual IP, shorten our TS to the minimum */
my_ts = this->policy->select_my_traffic_selectors(this->policy, my_ts,
my_vip);
}
else
{ /* shorten in the host2host case only */
my_ts = this->policy->select_my_traffic_selectors(this->policy,
my_ts, me);
}
if (other_vip)
{ /* if other has a virtual IP, shorten it's traffic selectors to it */
other_ts = this->policy->select_other_traffic_selectors(this->policy,
other_ts, other_vip);
}
else
{ /* use his host for the host2host case */
other_ts = this->policy->select_other_traffic_selectors(this->policy,
other_ts, other);
}
this->tsr->destroy_offset(this->tsr, offsetof(traffic_selector_t, destroy));
this->tsi->destroy_offset(this->tsi, offsetof(traffic_selector_t, destroy));
if (this->initiator)
{
this->tsi = my_ts;
this->tsr = other_ts;
}
else
{
this->tsr = my_ts;
this->tsi = other_ts;
}
if (this->proposal == NULL ||
this->tsi->get_count(this->tsi) == 0 ||
this->tsr->get_count(this->tsr) == 0)
{
SIG(CHILD_UP_FAILED, "no acceptable proposal found");
return FAILED;
}
if (!this->initiator)
{
/* check if requested mode is acceptable, downgrade if required */
switch (this->mode)
{
case MODE_TRANSPORT:
if (!ts_list_is_host(this->tsi, other) ||
!ts_list_is_host(this->tsr, me))
{
this->mode = MODE_TUNNEL;
DBG1(DBG_IKE, "not using tranport mode, not host-to-host");
}
else if (this->ike_sa->is_natt_enabled(this->ike_sa))
{
this->mode = MODE_TUNNEL;
DBG1(DBG_IKE, "not using tranport mode, connection NATed");
}
break;
case MODE_BEET:
if (!ts_list_is_host(this->tsi, NULL) ||
!ts_list_is_host(this->tsr, NULL))
{
this->mode = MODE_TUNNEL;
DBG1(DBG_IKE, "not using BEET mode, not host-to-host");
}
break;
default:
break;
}
}
seed = chunk_cata("cc", nonce_i, nonce_r);
prf_plus = prf_plus_create(this->ike_sa->get_child_prf(this->ike_sa), seed);
if (this->initiator)
{
status = this->child_sa->update(this->child_sa, this->proposal,
this->mode, prf_plus);
}
else
{
status = this->child_sa->add(this->child_sa, this->proposal,
this->mode, prf_plus);
}
prf_plus->destroy(prf_plus);
if (status != SUCCESS)
{
SIG(CHILD_UP_FAILED, "unable to install IPsec SA (SAD) in kernel");
return status;
}
status = this->child_sa->add_policies(this->child_sa, my_ts, other_ts,
this->mode);
if (status != SUCCESS)
{
SIG(CHILD_UP_FAILED, "unable to install IPsec policies (SPD) in kernel");
return status;
}
/* add to IKE_SA, and remove from task */
this->child_sa->set_state(this->child_sa, CHILD_INSTALLED);
this->ike_sa->add_child_sa(this->ike_sa, this->child_sa);
this->child_sa = NULL;
return SUCCESS;
}
/**
* build the payloads for the message
*/
static void build_payloads(private_child_create_t *this, message_t *message)
{
sa_payload_t *sa_payload;
ts_payload_t *ts_payload;
nonce_payload_t *nonce_payload;
/* add SA payload */
if (this->initiator)
{
sa_payload = sa_payload_create_from_proposal_list(this->proposals);
}
else
{
sa_payload = sa_payload_create_from_proposal(this->proposal);
}
message->add_payload(message, (payload_t*)sa_payload);
/* add TSi/TSr payloads */
ts_payload = ts_payload_create_from_traffic_selectors(TRUE, this->tsi);
message->add_payload(message, (payload_t*)ts_payload);
ts_payload = ts_payload_create_from_traffic_selectors(FALSE, this->tsr);
message->add_payload(message, (payload_t*)ts_payload);
/* add nonce payload if not in IKE_AUTH */
if (message->get_exchange_type(message) == CREATE_CHILD_SA)
{
nonce_payload = nonce_payload_create();
nonce_payload->set_nonce(nonce_payload, this->my_nonce);
message->add_payload(message, (payload_t*)nonce_payload);
}
/* add a notify if we are not in tunnel mode */
switch (this->mode)
{
case MODE_TRANSPORT:
message->add_notify(message, FALSE, USE_TRANSPORT_MODE, chunk_empty);
break;
case MODE_BEET:
message->add_notify(message, FALSE, USE_BEET_MODE, chunk_empty);
break;
default:
break;
}
}
/**
* Read payloads from message
*/
static void process_payloads(private_child_create_t *this, message_t *message)
{
iterator_t *iterator;
payload_t *payload;
sa_payload_t *sa_payload;
ts_payload_t *ts_payload;
notify_payload_t *notify_payload;
/* defaults to TUNNEL mode */
this->mode = MODE_TUNNEL;
iterator = message->get_payload_iterator(message);
while (iterator->iterate(iterator, (void**)&payload))
{
switch (payload->get_type(payload))
{
case SECURITY_ASSOCIATION:
sa_payload = (sa_payload_t*)payload;
this->proposals = sa_payload->get_proposals(sa_payload);
break;
case TRAFFIC_SELECTOR_INITIATOR:
ts_payload = (ts_payload_t*)payload;
this->tsi = ts_payload->get_traffic_selectors(ts_payload);
break;
case TRAFFIC_SELECTOR_RESPONDER:
ts_payload = (ts_payload_t*)payload;
this->tsr = ts_payload->get_traffic_selectors(ts_payload);
break;
case NOTIFY:
notify_payload = (notify_payload_t*)payload;
switch (notify_payload ->get_notify_type(notify_payload ))
{
case USE_TRANSPORT_MODE:
this->mode = MODE_TRANSPORT;
break;
case USE_BEET_MODE:
this->mode = MODE_BEET;
break;
default:
break;
}
break;
default:
break;
}
}
iterator->destroy(iterator);
}
/**
* Implementation of task_t.build for initiator
*/
static status_t build_i(private_child_create_t *this, message_t *message)
{
host_t *me, *other, *vip;
switch (message->get_exchange_type(message))
{
case IKE_SA_INIT:
return get_nonce(message, &this->my_nonce);
case CREATE_CHILD_SA:
if (generate_nonce(&this->my_nonce) != SUCCESS)
{
message->add_notify(message, FALSE, NO_PROPOSAL_CHOSEN, chunk_empty);
return SUCCESS;
}
break;
default:
break;
}
SIG(CHILD_UP_START, "establishing CHILD_SA");
me = this->ike_sa->get_my_host(this->ike_sa);
other = this->ike_sa->get_other_host(this->ike_sa);
vip = this->policy->get_virtual_ip(this->policy, NULL);
if (vip)
{ /* propose a 0.0.0.0/0 subnet when we use virtual ip */
this->tsi = this->policy->get_my_traffic_selectors(this->policy, NULL);
vip->destroy(vip);
}
else
{ /* but shorten a 0.0.0.0/0 subnet to the actual address if host2host */
this->tsi = this->policy->get_my_traffic_selectors(this->policy, me);
}
this->tsr = this->policy->get_other_traffic_selectors(this->policy, other);
this->proposals = this->policy->get_proposals(this->policy);
this->mode = this->policy->get_mode(this->policy);
this->child_sa = child_sa_create(me, other,
this->ike_sa->get_my_id(this->ike_sa),
this->ike_sa->get_other_id(this->ike_sa),
this->policy, this->reqid,
this->ike_sa->is_natt_enabled(this->ike_sa));
if (this->child_sa->alloc(this->child_sa, this->proposals) != SUCCESS)
{
SIG(CHILD_UP_FAILED, "unable to allocate SPIs from kernel");
return FAILED;
}
build_payloads(this, message);
this->tsi->destroy_offset(this->tsi, offsetof(traffic_selector_t, destroy));
this->tsr->destroy_offset(this->tsr, offsetof(traffic_selector_t, destroy));
this->proposals->destroy_offset(this->proposals, offsetof(proposal_t, destroy));
this->tsi = NULL;
this->tsr = NULL;
this->proposals = NULL;
return NEED_MORE;
}
/**
* Implementation of task_t.process for initiator
*/
static status_t process_r(private_child_create_t *this, message_t *message)
{
switch (message->get_exchange_type(message))
{
case IKE_SA_INIT:
return get_nonce(message, &this->other_nonce);
case CREATE_CHILD_SA:
get_nonce(message, &this->other_nonce);
break;
default:
break;
}
process_payloads(this, message);
if (this->tsi == NULL || this->tsr == NULL)
{
DBG1(DBG_IKE, "TS payload missing in message");
return NEED_MORE;
}
this->policy = charon->policies->get_policy(charon->policies,
this->ike_sa->get_my_id(this->ike_sa),
this->ike_sa->get_other_id(this->ike_sa),
this->tsr, this->tsi,
this->ike_sa->get_my_host(this->ike_sa),
this->ike_sa->get_other_host(this->ike_sa));
if (this->policy && this->ike_sa->get_policy(this->ike_sa) == NULL)
{
this->ike_sa->set_policy(this->ike_sa, this->policy);
}
return NEED_MORE;
}
/**
* Implementation of task_t.build for responder
*/
static status_t build_r(private_child_create_t *this, message_t *message)
{
switch (message->get_exchange_type(message))
{
case IKE_SA_INIT:
return get_nonce(message, &this->my_nonce);
case CREATE_CHILD_SA:
if (generate_nonce(&this->my_nonce) != SUCCESS)
{
message->add_notify(message, FALSE, NO_PROPOSAL_CHOSEN, chunk_empty);
return SUCCESS;
}
break;
default:
break;
}
if (this->policy == NULL)
{
SIG(CHILD_UP_FAILED, "received traffic selectors inacceptable");
message->add_notify(message, FALSE, TS_UNACCEPTABLE, chunk_empty);
return SUCCESS;
}
this->child_sa = child_sa_create(this->ike_sa->get_my_host(this->ike_sa),
this->ike_sa->get_other_host(this->ike_sa),
this->ike_sa->get_my_id(this->ike_sa),
this->ike_sa->get_other_id(this->ike_sa),
this->policy, this->reqid,
this->ike_sa->is_natt_enabled(this->ike_sa));
if (select_and_install(this) != SUCCESS)
{
message->add_notify(message, FALSE, NO_PROPOSAL_CHOSEN, chunk_empty);
return SUCCESS;
}
build_payloads(this, message);
SIG(CHILD_UP_SUCCESS, "established CHILD_SA successfully");
return SUCCESS;
}
/**
* Implementation of task_t.process for initiator
*/
static status_t process_i(private_child_create_t *this, message_t *message)
{
iterator_t *iterator;
payload_t *payload;
status_t status;
switch (message->get_exchange_type(message))
{
case IKE_SA_INIT:
return get_nonce(message, &this->other_nonce);
case CREATE_CHILD_SA:
get_nonce(message, &this->other_nonce);
break;
default:
break;
}
/* check for erronous notifies */
iterator = message->get_payload_iterator(message);
while (iterator->iterate(iterator, (void**)&payload))
{
if (payload->get_type(payload) == NOTIFY)
{
notify_payload_t *notify = (notify_payload_t*)payload;
notify_type_t type = notify->get_notify_type(notify);
if (type < 16383)
{
SIG(CHILD_UP_FAILED, "received %N notify error",
notify_type_names, type);
iterator->destroy(iterator);
/* an error in CHILD_SA creation is not critical */
return SUCCESS;
}
}
}
iterator->destroy(iterator);
process_payloads(this, message);
status = select_and_install(this);
SIG(CHILD_UP_SUCCESS, "established CHILD_SA successfully");
return SUCCESS;
}
/**
* Implementation of task_t.get_type
*/
static task_type_t get_type(private_child_create_t *this)
{
return CHILD_CREATE;
}
/**
* Implementation of child_create_t.use_reqid
*/
static void use_reqid(private_child_create_t *this, u_int32_t reqid)
{
this->reqid = reqid;
}
/**
* Implementation of task_t.migrate
*/
static void migrate(private_child_create_t *this, ike_sa_t *ike_sa)
{
chunk_free(&this->my_nonce);
chunk_free(&this->other_nonce);
if (this->tsi)
{
this->tsr->destroy_offset(this->tsr, offsetof(traffic_selector_t, destroy));
}
if (this->tsr)
{
this->tsi->destroy_offset(this->tsi, offsetof(traffic_selector_t, destroy));
}
DESTROY_IF(this->child_sa);
DESTROY_IF(this->proposal);
if (this->proposals)
{
this->proposals->destroy_offset(this->proposals, offsetof(proposal_t, destroy));
}
this->ike_sa = ike_sa;
this->proposals = NULL;
this->tsi = NULL;
this->tsr = NULL;
this->child_sa = NULL;
this->mode = MODE_TUNNEL;
this->reqid = 0;
}
/**
* Implementation of task_t.destroy
*/
static void destroy(private_child_create_t *this)
{
chunk_free(&this->my_nonce);
chunk_free(&this->other_nonce);
if (this->tsi)
{
this->tsr->destroy_offset(this->tsr, offsetof(traffic_selector_t, destroy));
}
if (this->tsr)
{
this->tsi->destroy_offset(this->tsi, offsetof(traffic_selector_t, destroy));
}
DESTROY_IF(this->child_sa);
DESTROY_IF(this->proposal);
if (this->proposals)
{
this->proposals->destroy_offset(this->proposals, offsetof(proposal_t, destroy));
}
DESTROY_IF(this->policy);
free(this);
}
/*
* Described in header.
*/
child_create_t *child_create_create(ike_sa_t *ike_sa, policy_t *policy)
{
private_child_create_t *this = malloc_thing(private_child_create_t);
this->public.use_reqid = (void(*)(child_create_t*,u_int32_t))use_reqid;
this->public.task.get_type = (task_type_t(*)(task_t*))get_type;
this->public.task.migrate = (void(*)(task_t*,ike_sa_t*))migrate;
this->public.task.destroy = (void(*)(task_t*))destroy;
if (policy)
{
this->public.task.build = (status_t(*)(task_t*,message_t*))build_i;
this->public.task.process = (status_t(*)(task_t*,message_t*))process_i;
this->initiator = TRUE;
policy->get_ref(policy);
}
else
{
this->public.task.build = (status_t(*)(task_t*,message_t*))build_r;
this->public.task.process = (status_t(*)(task_t*,message_t*))process_r;
this->initiator = FALSE;
}
this->ike_sa = ike_sa;
this->policy = policy;
this->my_nonce = chunk_empty;
this->other_nonce = chunk_empty;
this->proposals = NULL;
this->proposal = NULL;
this->tsi = NULL;
this->tsr = NULL;
this->child_sa = NULL;
this->mode = MODE_TUNNEL;
this->reqid = 0;
return &this->public;
}
+72
View File
@@ -0,0 +1,72 @@
/**
* @file child_create.h
*
* @brief Interface child_create_t.
*
*/
/*
* Copyright (C) 2007 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 <http://www.fsf.org/copyleft/gpl.txt>.
*
* 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 CHILD_CREATE_H_
#define CHILD_CREATE_H_
typedef struct child_create_t child_create_t;
#include <library.h>
#include <sa/ike_sa.h>
#include <sa/tasks/task.h>
#include <config/policies/policy.h>
/**
* @brief Task of type CHILD_CREATE, established a new CHILD_SA.
*
* This task may be included in the IKE_AUTH message or in a separate
* CREATE_CHILD_SA exchange.
*
* @b Constructors:
* - child_create_create()
*
* @ingroup tasks
*/
struct child_create_t {
/**
* Implements the task_t interface
*/
task_t task;
/**
* @brief Use a specific reqid for the CHILD_SA.
*
* When this task is used for rekeying, the same reqid is used
* for the new CHILD_SA.
*
* @param this calling object
* @param reqid reqid to use
*/
void (*use_reqid) (child_create_t *this, u_int32_t reqid);
};
/**
* @brief Create a new child_create task.
*
* @param ike_sa IKE_SA this task works for
* @param policy policy if task initiator, NULL if responder
* @return child_create task to handle by the task_manager
*/
child_create_t *child_create_create(ike_sa_t *ike_sa, policy_t *policy);
#endif /* CHILD_CREATE_H_ */
+264
View File
@@ -0,0 +1,264 @@
/**
* @file child_delete.c
*
* @brief Implementation of the child_delete task.
*
*/
/*
* Copyright (C) 2006-2007 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 <http://www.fsf.org/copyleft/gpl.txt>.
*
* 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 "child_delete.h"
#include <daemon.h>
#include <encoding/payloads/delete_payload.h>
typedef struct private_child_delete_t private_child_delete_t;
/**
* Private members of a child_delete_t task.
*/
struct private_child_delete_t {
/**
* Public methods and task_t interface.
*/
child_delete_t public;
/**
* Assigned IKE_SA.
*/
ike_sa_t *ike_sa;
/**
* Are we the initiator?
*/
bool initiator;
/**
* CHILD_SAs which get deleted
*/
linked_list_t *child_sas;
};
/**
* build the delete payloads from the listed child_sas
*/
static void build_payloads(private_child_delete_t *this, message_t *message)
{
iterator_t *iterator;
delete_payload_t *ah = NULL, *esp = NULL;
u_int32_t spi;
child_sa_t *child_sa;
iterator = this->child_sas->create_iterator(this->child_sas, TRUE);
while (iterator->iterate(iterator, (void**)&child_sa))
{
spi = child_sa->get_spi(child_sa, TRUE);
switch (child_sa->get_protocol(child_sa))
{
case PROTO_ESP:
if (esp == NULL)
{
esp = delete_payload_create(PROTO_ESP);
message->add_payload(message, (payload_t*)esp);
}
esp->add_spi(esp, spi);
break;
case PROTO_AH:
if (ah == NULL)
{
ah = delete_payload_create(PROTO_AH);
message->add_payload(message, (payload_t*)ah);
}
ah->add_spi(ah, spi);
break;
default:
break;
}
child_sa->set_state(child_sa, CHILD_DELETING);
}
iterator->destroy(iterator);
}
/**
* read in payloads and find the children to delete
*/
static void process_payloads(private_child_delete_t *this, message_t *message)
{
iterator_t *payloads, *spis;
payload_t *payload;
delete_payload_t *delete_payload;
u_int32_t spi;
protocol_id_t protocol;
child_sa_t *child_sa;
payloads = message->get_payload_iterator(message);
while (payloads->iterate(payloads, (void**)&payload))
{
if (payload->get_type(payload) == DELETE)
{
delete_payload = (delete_payload_t*)payload;
protocol = delete_payload->get_protocol_id(delete_payload);
if (protocol != PROTO_ESP && protocol != PROTO_AH)
{
continue;
}
spis = delete_payload->create_spi_iterator(delete_payload);
while (spis->iterate(spis, (void**)&spi))
{
child_sa = this->ike_sa->get_child_sa(this->ike_sa, protocol,
spi, FALSE);
if (child_sa == NULL)
{
DBG1(DBG_IKE, "received DELETE for %N CHILD_SA with SPI 0x%x, "
"but no such SA", protocol_id_names, protocol, ntohl(spi));
break;
}
if (child_sa->get_state(child_sa) == CHILD_REKEYING)
{
/* TODO: handle rekeying */
}
this->child_sas->insert_last(this->child_sas, child_sa);
}
spis->destroy(spis);
}
}
payloads->destroy(payloads);
}
/**
* destroy the children listed in this->child_sas
*/
static void destroy_children(private_child_delete_t *this)
{
iterator_t *iterator;
child_sa_t *child_sa;
protocol_id_t protocol;
u_int32_t spi;
iterator = this->child_sas->create_iterator(this->child_sas, TRUE);
while (iterator->iterate(iterator, (void**)&child_sa))
{
/* TODO: can we do this more cleanly? */
spi = child_sa->get_spi(child_sa, TRUE);
protocol = child_sa->get_protocol(child_sa);
this->ike_sa->destroy_child_sa(this->ike_sa, protocol, spi);
}
iterator->destroy(iterator);
}
/**
* Implementation of task_t.build for initiator
*/
static status_t build_i(private_child_delete_t *this, message_t *message)
{
build_payloads(this, message);
return NEED_MORE;
}
/**
* Implementation of task_t.process for initiator
*/
static status_t process_i(private_child_delete_t *this, message_t *message)
{
/* flush the list before adding new SAs */
this->child_sas->destroy(this->child_sas);
this->child_sas = linked_list_create();
process_payloads(this, message);
destroy_children(this);
return SUCCESS;
}
/**
* Implementation of task_t.process for initiator
*/
static status_t process_r(private_child_delete_t *this, message_t *message)
{
process_payloads(this, message);
return NEED_MORE;
}
/**
* Implementation of task_t.build for responder
*/
static status_t build_r(private_child_delete_t *this, message_t *message)
{
build_payloads(this, message);
destroy_children(this);
return SUCCESS;
}
/**
* Implementation of task_t.get_type
*/
static task_type_t get_type(private_child_delete_t *this)
{
return CHILD_DELETE;
}
/**
* Implementation of task_t.migrate
*/
static void migrate(private_child_delete_t *this, ike_sa_t *ike_sa)
{
this->ike_sa = ike_sa;
this->child_sas->destroy(this->child_sas);
this->child_sas = linked_list_create();
}
/**
* Implementation of task_t.destroy
*/
static void destroy(private_child_delete_t *this)
{
this->child_sas->destroy(this->child_sas);
free(this);
}
/*
* Described in header.
*/
child_delete_t *child_delete_create(ike_sa_t *ike_sa, child_sa_t *child_sa)
{
private_child_delete_t *this = malloc_thing(private_child_delete_t);
this->public.task.get_type = (task_type_t(*)(task_t*))get_type;
this->public.task.migrate = (void(*)(task_t*,ike_sa_t*))migrate;
this->public.task.destroy = (void(*)(task_t*))destroy;
this->ike_sa = ike_sa;
this->child_sas = linked_list_create();
if (child_sa != NULL)
{
this->public.task.build = (status_t(*)(task_t*,message_t*))build_i;
this->public.task.process = (status_t(*)(task_t*,message_t*))process_i;
this->initiator = TRUE;
this->child_sas->insert_last(this->child_sas, child_sa);
}
else
{
this->public.task.build = (status_t(*)(task_t*,message_t*))build_r;
this->public.task.process = (status_t(*)(task_t*,message_t*))process_r;
this->initiator = FALSE;
}
return &this->public;
}
+58
View File
@@ -0,0 +1,58 @@
/**
* @file child_delete.h
*
* @brief Interface child_delete_t.
*
*/
/*
* Copyright (C) 2007 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 <http://www.fsf.org/copyleft/gpl.txt>.
*
* 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 CHILD_DELETE_H_
#define CHILD_DELETE_H_
typedef struct child_delete_t child_delete_t;
#include <library.h>
#include <sa/ike_sa.h>
#include <sa/tasks/task.h>
#include <sa/child_sa.h>
/**
* @brief Task of type child_delete, delete a CHILD_SA.
*
* @b Constructors:
* - child_delete_create()
*
* @ingroup tasks
*/
struct child_delete_t {
/**
* Implements the task_t interface
*/
task_t task;
};
/**
* @brief Create a new child_delete task.
*
* @param ike_sa IKE_SA this task works for
* @param child_sa CHILD_SA to delete, or NULL as responder
* @return child_delete task to handle by the task_manager
*/
child_delete_t *child_delete_create(ike_sa_t *ike_sa, child_sa_t *child_sa);
#endif /* CHILD_DELETE_H_ */
+353
View File
@@ -0,0 +1,353 @@
/**
* @file child_rekey.c
*
* @brief Implementation of the child_rekey task.
*
*/
/*
* Copyright (C) 2005-2007 Martin Willi
* Copyright (C) 2005 Jan Hutter
* 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 <http://www.fsf.org/copyleft/gpl.txt>.
*
* 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 "child_rekey.h"
#include <daemon.h>
#include <crypto/diffie_hellman.h>
#include <encoding/payloads/notify_payload.h>
#include <encoding/payloads/nonce_payload.h>
#include <sa/tasks/child_create.h>
typedef struct private_child_rekey_t private_child_rekey_t;
/**
* Private members of a child_rekey_t task.
*/
struct private_child_rekey_t {
/**
* Public methods and task_t interface.
*/
child_rekey_t public;
/**
* Assigned IKE_SA.
*/
ike_sa_t *ike_sa;
/**
* Are we the initiator?
*/
bool initiator;
/**
* the CHILD_CREATE task which is reused to simplify rekeying
*/
child_create_t *child_create;
/**
* CHILD_SA which gets rekeyed
*/
child_sa_t *child_sa;
/**
* redundandt CHILD_SA created simultaneously
*/
child_sa_t *simultaneous;
/**
* the lowest nonce compared so far
*/
chunk_t nonce;
/**
* TRUE if we have the lower nonce
*/
bool winner;
};
/**
* get the nonce from a message, return TRUE if it was lower than this->nonce
*/
static bool get_nonce(private_child_rekey_t *this, message_t *message)
{
nonce_payload_t *payload;
chunk_t nonce;
payload = (nonce_payload_t*)message->get_payload(message, NONCE);
if (payload == NULL)
{
return FALSE;
}
nonce = payload->get_nonce(payload);
if (this->nonce.ptr && memcmp(nonce.ptr, this->nonce.ptr,
min(nonce.len, this->nonce.len)) > 0)
{
chunk_free(&nonce);
return FALSE;
}
chunk_free(&this->nonce);
this->nonce = nonce;
return TRUE;
}
/**
* find a child using the REKEY_SA notify
*/
static void find_child(private_child_rekey_t *this, message_t *message)
{
iterator_t *iterator;
payload_t *payload;
iterator = message->get_payload_iterator(message);
while (iterator->iterate(iterator, (void**)&payload))
{
notify_payload_t *notify;
u_int32_t spi;
protocol_id_t protocol;
if (payload->get_type(payload) != NOTIFY)
{
continue;
}
notify = (notify_payload_t*)payload;
protocol = notify->get_protocol_id(notify);
spi = notify->get_spi(notify);
if (protocol != PROTO_ESP && protocol != PROTO_AH)
{
continue;
}
this->child_sa = this->ike_sa->get_child_sa(this->ike_sa, protocol,
spi, FALSE);
break;
}
iterator->destroy(iterator);
}
#if 0
/**
* handle a detected simultaneous rekeying situation as responder
*/
static void simultaneous_r(private_child_rekey_t *this, message_t *message)
{
private_child_rekey_t *other = NULL;
task_t *task;
iterator_t *iterator;
this->ike_sa->create_task_iterator(this->ike_sa);
while (iterator->iterate(iterator, (void**)&task))
{
if (task->get_type(task) == CHILD_REKEY)
{
other = (private_child_rekey_t*)task;
break;
}
}
iterator->destroy(iterator);
if (other)
{
other->simultaneous = this->child_create->get_child(this->child_create);
if (!get_nonce(other, message))
{
/* this wins the race, other lost */
other->winner = FALSE;
}
}
}
/**
* was there a simultaneous rekeying, did we win the nonce compare?
*/
static bool simultaneous_i(private_child_rekey_t *this, message_t *message)
{
if (this->winner || get_nonce(this, message))
{
/* we have the lower nonce and win */
return TRUE;
}
return FALSE;
}
#endif
/**
* Implementation of task_t.build for initiator
*/
static status_t build_i(private_child_rekey_t *this, message_t *message)
{
notify_payload_t *notify;
protocol_id_t protocol;
u_int32_t spi, reqid;
/* our CHILD_CREATE task does the hard work for us... */
reqid = this->child_sa->get_reqid(this->child_sa);
this->child_create->use_reqid(this->child_create, reqid);
this->child_create->task.build(&this->child_create->task, message);
get_nonce(this, message);
/* ... we just need the rekey notify */
protocol = this->child_sa->get_protocol(this->child_sa);
spi = this->child_sa->get_spi(this->child_sa, TRUE);
notify = notify_payload_create_from_protocol_and_type(protocol, REKEY_SA);
notify->set_spi(notify, spi);
message->add_payload(message, (payload_t*)notify);
this->child_sa->set_state(this->child_sa, CHILD_REKEYING);
return NEED_MORE;
}
/**
* Implementation of task_t.process for initiator
*/
static status_t process_r(private_child_rekey_t *this, message_t *message)
{
/* let the CHILD_CREATE task process the message */
this->child_create->task.process(&this->child_create->task, message);
get_nonce(this, message);
find_child(this, message);
return NEED_MORE;
}
/**
* Implementation of task_t.build for responder
*/
static status_t build_r(private_child_rekey_t *this, message_t *message)
{
u_int32_t reqid;
if (this->child_sa == NULL ||
this->child_sa->get_state(this->child_sa) == CHILD_DELETING)
{
message->add_notify(message, TRUE, NO_PROPOSAL_CHOSEN, chunk_empty);
return SUCCESS;
}
/* let the CHILD_CREATE task build the response */
reqid = this->child_sa->get_reqid(this->child_sa);
this->child_create->use_reqid(this->child_create, reqid);
this->child_create->task.build(&this->child_create->task, message);
get_nonce(this, message);
if (this->child_sa->get_state(this->child_sa) == CHILD_REKEYING)
{
/* simultaneous_detected(this); */
}
this->child_sa->set_state(this->child_sa, CHILD_REKEYING);
return SUCCESS;
}
/**
* Implementation of task_t.process for initiator
*/
static status_t process_i(private_child_rekey_t *this, message_t *message)
{
protocol_id_t protocol;
u_int32_t spi;
this->child_create->task.process(&this->child_create->task, message);
/*if (!simultaneous_won(this, message))
{
* delete the redundant CHILD_SA, instead of the rekeyed *
this->child_sa = this->create_child->get_child(this->create_child);
}*/
spi = this->child_sa->get_spi(this->child_sa, TRUE);
protocol = this->child_sa->get_protocol(this->child_sa);
/* TODO: don't delete when rekeying failed */
if (this->ike_sa->delete_child_sa(this->ike_sa, protocol, spi) != SUCCESS)
{
return FAILED;
}
return SUCCESS;
}
/**
* Implementation of task_t.get_type
*/
static task_type_t get_type(private_child_rekey_t *this)
{
return CHILD_REKEY;
}
/**
* Implementation of task_t.migrate
*/
static void migrate(private_child_rekey_t *this, ike_sa_t *ike_sa)
{
this->child_create->task.migrate(&this->child_create->task, ike_sa);
chunk_free(&this->nonce);
this->ike_sa = ike_sa;
this->winner = TRUE;
this->simultaneous = NULL;
}
/**
* Implementation of task_t.destroy
*/
static void destroy(private_child_rekey_t *this)
{
this->child_create->task.destroy(&this->child_create->task);
chunk_free(&this->nonce);
free(this);
}
/*
* Described in header.
*/
child_rekey_t *child_rekey_create(ike_sa_t *ike_sa, child_sa_t *child_sa)
{
private_child_rekey_t *this = malloc_thing(private_child_rekey_t);
policy_t *policy;
this->public.task.get_type = (task_type_t(*)(task_t*))get_type;
this->public.task.migrate = (void(*)(task_t*,ike_sa_t*))migrate;
this->public.task.destroy = (void(*)(task_t*))destroy;
if (child_sa != NULL)
{
this->public.task.build = (status_t(*)(task_t*,message_t*))build_i;
this->public.task.process = (status_t(*)(task_t*,message_t*))process_i;
this->initiator = TRUE;
policy = child_sa->get_policy(child_sa);
this->child_create = child_create_create(ike_sa, policy);
}
else
{
this->public.task.build = (status_t(*)(task_t*,message_t*))build_r;
this->public.task.process = (status_t(*)(task_t*,message_t*))process_r;
this->initiator = FALSE;
this->child_create = child_create_create(ike_sa, NULL);
}
this->ike_sa = ike_sa;
this->child_sa = child_sa;
this->nonce = chunk_empty;
this->winner = TRUE;
this->simultaneous = NULL;
return &this->public;
}
+58
View File
@@ -0,0 +1,58 @@
/**
* @file child_rekey.h
*
* @brief Interface child_rekey_t.
*
*/
/*
* Copyright (C) 2007 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 <http://www.fsf.org/copyleft/gpl.txt>.
*
* 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 CHILD_REKEY_H_
#define CHILD_REKEY_H_
typedef struct child_rekey_t child_rekey_t;
#include <library.h>
#include <sa/ike_sa.h>
#include <sa/child_sa.h>
#include <sa/tasks/task.h>
/**
* @brief Task of type CHILD_REKEY, rekey an established CHILD_SA.
*
* @b Constructors:
* - child_rekey_create()
*
* @ingroup tasks
*/
struct child_rekey_t {
/**
* Implements the task_t interface
*/
task_t task;
};
/**
* @brief Create a new CHILD_REKEY task.
*
* @param ike_sa IKE_SA this task works for
* @param child_sa child_sa to rekey, NULL if responder
* @return child_rekey task to handle by the task_manager
*/
child_rekey_t *child_rekey_create(ike_sa_t *ike_sa, child_sa_t *child_sa);
#endif /* CHILD_REKEY_H_ */
+513
View File
@@ -0,0 +1,513 @@
/**
* @file ike_auth.c
*
* @brief Implementation of the ike_auth task.
*
*/
/*
* Copyright (C) 2005-2007 Martin Willi
* Copyright (C) 2005 Jan Hutter
* 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 <http://www.fsf.org/copyleft/gpl.txt>.
*
* 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 "ike_auth.h"
#include <string.h>
#include <daemon.h>
#include <crypto/diffie_hellman.h>
#include <encoding/payloads/id_payload.h>
#include <encoding/payloads/auth_payload.h>
#include <encoding/payloads/nonce_payload.h>
typedef struct private_ike_auth_t private_ike_auth_t;
/**
* Private members of a ike_auth_t task.
*/
struct private_ike_auth_t {
/**
* Public methods and task_t interface.
*/
ike_auth_t public;
/**
* Assigned IKE_SA.
*/
ike_sa_t *ike_sa;
/**
* Are we the initiator?
*/
bool initiator;
/**
* Nonce chosen by us in ike_init
*/
chunk_t my_nonce;
/**
* Nonce chosen by peer in ike_init
*/
chunk_t other_nonce;
/**
* IKE_SA_INIT message sent by us
*/
packet_t *my_packet;
/**
* IKE_SA_INIT message sent by peer
*/
packet_t *other_packet;
/**
* authenticator to authenticate us
*/
authenticator_t *my_auth;
/**
* authenticator to authenticate peer
*/
authenticator_t *other_auth;
/**
* has the peer been authenticated successfully?
*/
bool peer_authenticated;
};
/**
* build the payloads for the message
*/
static status_t build_payloads(private_ike_auth_t *this, message_t *message)
{
authenticator_t *auth;
auth_payload_t *auth_payload;
id_payload_t *id_payload;
chunk_t ike_sa_init;
identification_t *me, *other;
policy_t *policy;
auth_method_t method = AUTH_RSA;
status_t status;
/* add own ID payload */
me = this->ike_sa->get_my_id(this->ike_sa);
other = this->ike_sa->get_other_id(this->ike_sa);
id_payload = id_payload_create_from_identification(this->initiator, me);
message->add_payload(message, (payload_t*)id_payload);
/* as initiator, include other ID if it does not contain wildcards */
if (this->initiator && !other->contains_wildcards(other))
{
id_payload = id_payload_create_from_identification(FALSE, other);
message->add_payload(message, (payload_t*)id_payload);
}
/* create own authenticator and add auth payload */
policy = this->ike_sa->get_policy(this->ike_sa);
if (policy)
{
method = policy->get_auth_method(policy);
}
auth = authenticator_create(this->ike_sa, method);
if (auth == NULL)
{
SIG(IKE_UP_FAILED, "configured authentication method %N not supported",
auth_method_names, method);
return FAILED;
}
ike_sa_init = this->my_packet->get_data(this->my_packet);
status = auth->build(auth, ike_sa_init, this->other_nonce, &auth_payload);
auth->destroy(auth);
if (status != SUCCESS)
{
SIG(IKE_UP_FAILED, "generating authentication data failed");
return FAILED;
}
message->add_payload(message, (payload_t*)auth_payload);
return SUCCESS;
}
/**
* process payloads from message
*/
static void process_payloads(private_ike_auth_t *this, message_t *message)
{
iterator_t *iterator;
payload_t *payload;
payload_type_t type;
identification_t *idi = NULL, *idr = NULL;
auth_payload_t *auth_payload = NULL;
authenticator_t *auth;
auth_method_t auth_method;
status_t status;
iterator = message->get_payload_iterator(message);
while (iterator->iterate(iterator, (void**)&payload))
{
type = payload->get_type(payload);
switch (type)
{
case ID_INITIATOR:
{
id_payload_t *id_payload = (id_payload_t*)payload;
idi = id_payload->get_identification(id_payload);
break;
}
case ID_RESPONDER:
{
id_payload_t *id_payload = (id_payload_t*)payload;
idr = id_payload->get_identification(id_payload);
break;
}
case AUTHENTICATION:
{
auth_payload = (auth_payload_t*)payload;
break;
}
default:
break;
}
}
iterator->destroy(iterator);
/* apply IDs */
if ((this->initiator && idr == NULL) || (!this->initiator && idi == NULL))
{
SIG(IKE_UP_FAILED, "ID payload missing in message");
DESTROY_IF(idr); DESTROY_IF(idi);
return;
}
if (this->initiator)
{
identification_t *other_id = this->ike_sa->get_other_id(this->ike_sa);
if (!idr->matches(idr, other_id, NULL))
{
SIG(IKE_UP_FAILED, "received inacceptable id %D, %D required", idr,
this->ike_sa->get_other_id(this->ike_sa));
DESTROY_IF(idi); DESTROY_IF(idr);
return;
}
this->ike_sa->set_other_id(this->ike_sa, idr);
}
else
{
identification_t *my_id = this->ike_sa->get_other_id(this->ike_sa);
if (idr)
{
if (!idr->matches(idr, my_id, NULL))
{
SIG(IKE_UP_FAILED, "received inacceptable id %D, %D required",
idr, this->ike_sa->get_other_id(this->ike_sa));
DESTROY_IF(idi); DESTROY_IF(idr);
return;
}
this->ike_sa->set_my_id(this->ike_sa, idr);
}
else
{
if (my_id->contains_wildcards(my_id))
{
SIG(IKE_UP_FAILED, "own ID (%D) not defined after exchange",
my_id);
DESTROY_IF(idi);
return;
}
}
this->ike_sa->set_other_id(this->ike_sa, idi);
}
/* verify auth payload */
if (auth_payload == NULL)
{
SIG(IKE_UP_FAILED, "AUTH payload missing in message");
return;
}
auth_method = auth_payload->get_auth_method(auth_payload);
auth = authenticator_create(this->ike_sa, auth_method);
if (auth == NULL)
{
SIG(IKE_UP_FAILED, "authentication method %N used by %D not "
"supported", auth_method_names, auth_method,
this->ike_sa->get_other_id(this->ike_sa));
return;
}
status = auth->verify(auth, this->other_packet->get_data(this->other_packet),
this->my_nonce, auth_payload);
auth->destroy(auth);
if (status != SUCCESS)
{
SIG(IKE_UP_FAILED, "authentication of %D using %N failed",
this->ike_sa->get_other_id(this->ike_sa),
auth_method_names, auth_method);
return;
}
this->peer_authenticated = TRUE;
}
/**
* collect the needed information in the IKE_SA_INIT exchange from our message
*/
static status_t collect_my_init_data(private_ike_auth_t *this, message_t *message)
{
nonce_payload_t *nonce;
/* get the nonce that was generated in ike_init */
nonce = (nonce_payload_t*)message->get_payload(message, NONCE);
if (nonce == NULL)
{
return FAILED;
}
this->my_nonce = nonce->get_nonce(nonce);
/* pre-generate the message, so we can store it for us */
if (this->ike_sa->generate_message(this->ike_sa, message,
&this->my_packet) != SUCCESS)
{
return FAILED;
}
return NEED_MORE;
}
/**
* collect the needed information in the IKE_SA_INIT exchange from others message
*/
static status_t collect_other_init_data(private_ike_auth_t *this, message_t *message)
{
/* we collect the needed information in the IKE_SA_INIT exchange */
nonce_payload_t *nonce;
/* get the nonce that was generated in ike_init */
nonce = (nonce_payload_t*)message->get_payload(message, NONCE);
if (nonce == NULL)
{
return FAILED;
}
this->other_nonce = nonce->get_nonce(nonce);
/* pre-generate the message, so we can store it for us */
this->other_packet = message->get_packet(message);
return NEED_MORE;
}
/**
* Implementation of task_t.build for initiator
*/
static status_t build_i(private_ike_auth_t *this, message_t *message)
{
if (message->get_exchange_type(message) == IKE_SA_INIT)
{
return collect_my_init_data(this, message);
}
if (build_payloads(this, message) == SUCCESS)
{
return NEED_MORE;
}
return FAILED;
}
/**
* Implementation of task_t.process for initiator
*/
static status_t process_r(private_ike_auth_t *this, message_t *message)
{
if (message->get_exchange_type(message) == IKE_SA_INIT)
{
return collect_other_init_data(this, message);
}
process_payloads(this, message);
return NEED_MORE;
}
/**
* Implementation of task_t.build for responder
*/
static status_t build_r(private_ike_auth_t *this, message_t *message)
{
if (message->get_exchange_type(message) == IKE_SA_INIT)
{
return collect_my_init_data(this, message);
}
if (!this->peer_authenticated)
{
message->add_notify(message, TRUE, AUTHENTICATION_FAILED, chunk_empty);
return FAILED;
}
if (build_payloads(this, message) == SUCCESS)
{
this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED);
SIG(IKE_UP_SUCCESS, "IKE_SA established between %D[%H]...[%H]%D",
this->ike_sa->get_my_id(this->ike_sa),
this->ike_sa->get_my_host(this->ike_sa),
this->ike_sa->get_other_host(this->ike_sa),
this->ike_sa->get_other_id(this->ike_sa));
return SUCCESS;
}
return FAILED;
}
/**
* Implementation of task_t.process for initiator
*/
static status_t process_i(private_ike_auth_t *this, message_t *message)
{
iterator_t *iterator;
payload_t *payload;
if (message->get_exchange_type(message) == IKE_SA_INIT)
{
return collect_other_init_data(this, message);
}
iterator = message->get_payload_iterator(message);
while (iterator->iterate(iterator, (void**)&payload))
{
if (payload->get_type(payload) == NOTIFY)
{
notify_payload_t *notify = (notify_payload_t*)payload;
notify_type_t type = notify->get_notify_type(notify);
switch (type)
{
case NO_PROPOSAL_CHOSEN:
case SINGLE_PAIR_REQUIRED:
case NO_ADDITIONAL_SAS:
case INTERNAL_ADDRESS_FAILURE:
case FAILED_CP_REQUIRED:
case TS_UNACCEPTABLE:
case INVALID_SELECTORS:
/* these are errors, but are not critical as only the
* CHILD_SA won't get build, but IKE_SA establishes anyway */
DBG1(DBG_IKE, "received %N notify, no CHILD_SA built",
notify_type_names, type);
iterator->destroy(iterator);
return SUCCESS;
default:
{
if (type < 16383)
{
DBG1(DBG_IKE, "received %N notify error",
notify_type_names, type);
iterator->destroy(iterator);
return FAILED;
}
}
}
}
}
iterator->destroy(iterator);
process_payloads(this, message);
if (this->peer_authenticated)
{
this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED);
SIG(IKE_UP_SUCCESS, "IKE_SA established between %D[%H]...[%H]%D",
this->ike_sa->get_my_id(this->ike_sa),
this->ike_sa->get_my_host(this->ike_sa),
this->ike_sa->get_other_host(this->ike_sa),
this->ike_sa->get_other_id(this->ike_sa));
return SUCCESS;
}
return FAILED;
}
/**
* Implementation of task_t.get_type
*/
static task_type_t get_type(private_ike_auth_t *this)
{
return IKE_AUTHENTICATE;
}
/**
* Implementation of task_t.migrate
*/
static void migrate(private_ike_auth_t *this, ike_sa_t *ike_sa)
{
chunk_free(&this->my_nonce);
chunk_free(&this->other_nonce);
DESTROY_IF(this->my_packet);
DESTROY_IF(this->other_packet);
DESTROY_IF(this->my_auth);
DESTROY_IF(this->other_auth);
this->my_packet = NULL;
this->other_packet = NULL;
this->my_auth = NULL;
this->other_auth = NULL;
this->peer_authenticated = FALSE;
this->ike_sa = ike_sa;
}
/**
* Implementation of task_t.destroy
*/
static void destroy(private_ike_auth_t *this)
{
chunk_free(&this->my_nonce);
chunk_free(&this->other_nonce);
DESTROY_IF(this->my_packet);
DESTROY_IF(this->other_packet);
DESTROY_IF(this->my_auth);
DESTROY_IF(this->other_auth);
free(this);
}
/*
* Described in header.
*/
ike_auth_t *ike_auth_create(ike_sa_t *ike_sa, bool initiator)
{
private_ike_auth_t *this = malloc_thing(private_ike_auth_t);
this->public.task.get_type = (task_type_t(*)(task_t*))get_type;
this->public.task.migrate = (void(*)(task_t*,ike_sa_t*))migrate;
this->public.task.destroy = (void(*)(task_t*))destroy;
if (initiator)
{
this->public.task.build = (status_t(*)(task_t*,message_t*))build_i;
this->public.task.process = (status_t(*)(task_t*,message_t*))process_i;
}
else
{
this->public.task.build = (status_t(*)(task_t*,message_t*))build_r;
this->public.task.process = (status_t(*)(task_t*,message_t*))process_r;
}
this->ike_sa = ike_sa;
this->initiator = initiator;
this->my_nonce = chunk_empty;
this->other_nonce = chunk_empty;
this->my_packet = NULL;
this->other_packet = NULL;
this->my_auth = NULL;
this->other_auth = NULL;
this->peer_authenticated = FALSE;
return &this->public;
}
+60
View File
@@ -0,0 +1,60 @@
/**
* @file ike_auth.h
*
* @brief Interface ike_auth_t.
*
*/
/*
* Copyright (C) 2007 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 <http://www.fsf.org/copyleft/gpl.txt>.
*
* 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 IKE_AUTH_H_
#define IKE_AUTH_H_
typedef struct ike_auth_t ike_auth_t;
#include <library.h>
#include <sa/ike_sa.h>
#include <sa/tasks/task.h>
/**
* @brief Task of type ike_auth, authenticates an IKE_SA authenticators.
*
* The ike_auth task authenticates the IKE_SA using the IKE_AUTH
* exchange.
*
* @b Constructors:
* - ike_auth_create()
*
* @ingroup tasks
*/
struct ike_auth_t {
/**
* Implements the task_t interface
*/
task_t task;
};
/**
* @brief Create a new task of type IKE_AUTHENTICATE.
*
* @param ike_sa IKE_SA this task works for
* @param initiator TRUE if thask is the initator of an exchange
* @return ike_auth task to handle by the task_manager
*/
ike_auth_t *ike_auth_create(ike_sa_t *ike_sa, bool initiator);
#endif /* IKE_AUTH_H_ */
+361
View File
@@ -0,0 +1,361 @@
/**
* @file ike_cert.c
*
* @brief Implementation of the ike_cert task.
*
*/
/*
* Copyright (C) 2006-2007 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 <http://www.fsf.org/copyleft/gpl.txt>.
*
* 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 "ike_cert.h"
#include <daemon.h>
#include <sa/ike_sa.h>
#include <crypto/hashers/hasher.h>
#include <encoding/payloads/cert_payload.h>
#include <encoding/payloads/certreq_payload.h>
typedef struct private_ike_cert_t private_ike_cert_t;
/**
* Private members of a ike_cert_t task.
*/
struct private_ike_cert_t {
/**
* Public methods and task_t interface.
*/
ike_cert_t public;
/**
* Assigned IKE_SA.
*/
ike_sa_t *ike_sa;
/**
* Are we the initiator?
*/
bool initiator;
/**
* list of CA cert hashes requested, items point to 20 byte chunk
*/
linked_list_t *cas;
};
/**
* read certificate requests
*/
static void process_certreqs(private_ike_cert_t *this, message_t *message)
{
iterator_t *iterator;
payload_t *payload;
iterator = message->get_payload_iterator(message);
while (iterator->iterate(iterator, (void**)&payload))
{
if (payload->get_type(payload) == CERTIFICATE_REQUEST)
{
certreq_payload_t *certreq = (certreq_payload_t*)payload;
cert_encoding_t encoding;
chunk_t keyids, keyid;
encoding = certreq->get_cert_encoding(certreq);
if (encoding != CERT_X509_SIGNATURE)
{
DBG1(DBG_IKE, "certreq payload %N not supported, ignored",
cert_encoding_names, encoding);
continue;
}
keyids = certreq->get_data(certreq);
while (keyids.len >= HASH_SIZE_SHA1)
{
keyid = chunk_create(keyids.ptr, HASH_SIZE_SHA1);
keyid = chunk_clone(keyid);
this->cas->insert_last(this->cas, keyid.ptr);
keyids = chunk_skip(keyids, HASH_SIZE_SHA1);
}
}
}
iterator->destroy(iterator);
}
/**
* import certificates
*/
static void process_certs(private_ike_cert_t *this, message_t *message)
{
iterator_t *iterator;
payload_t *payload;
iterator = message->get_payload_iterator(message);
while (iterator->iterate(iterator, (void**)&payload))
{
if (payload->get_type(payload) == CERTIFICATE)
{
cert_encoding_t encoding;
x509_t *cert;
chunk_t cert_data;
bool found;
cert_payload_t *cert_payload = (cert_payload_t*)payload;
encoding = cert_payload->get_cert_encoding(cert_payload);
if (encoding != CERT_X509_SIGNATURE)
{
DBG1(DBG_IKE, "certificate payload %N not supported, ignored",
cert_encoding_names, encoding);
continue;
}
cert_data = cert_payload->get_data_clone(cert_payload);
cert = x509_create_from_chunk(cert_data);
if (cert)
{
if (charon->credentials->verify(charon->credentials,
cert, &found))
{
DBG2(DBG_IKE, "received end entity certificate is trusted, "
"added to store");
if (!found)
{
charon->credentials->add_end_certificate(
charon->credentials, cert);
}
else
{
cert->destroy(cert);
}
}
else
{
DBG1(DBG_IKE, "received end entity certificate is not "
"trusted, discarded");
cert->destroy(cert);
}
}
else
{
DBG1(DBG_IKE, "parsing of received certificate failed, discarded");
chunk_free(&cert_data);
}
}
}
iterator->destroy(iterator);
}
/**
* build certificate requests
*/
static void build_certreqs(private_ike_cert_t *this, message_t *message)
{
connection_t *connection;
policy_t *policy;
identification_t *ca;
certreq_payload_t *certreq;
connection = this->ike_sa->get_connection(this->ike_sa);
if (connection->get_certreq_policy(connection) != CERT_NEVER_SEND)
{
policy = this->ike_sa->get_policy(this->ike_sa);
if (policy)
{
ca = policy->get_other_ca(policy);
if (ca && ca->get_type(ca) != ID_ANY)
{
certreq = certreq_payload_create_from_cacert(ca);
}
else
{
certreq = certreq_payload_create_from_cacerts();
}
}
else
{
certreq = certreq_payload_create_from_cacerts();
}
if (certreq)
{
message->add_payload(message, (payload_t*)certreq);
}
}
}
/**
* add certificates to message
*/
static void build_certs(private_ike_cert_t *this, message_t *message)
{
policy_t *policy;
connection_t *connection;
x509_t *cert;
cert_payload_t *payload;
policy = this->ike_sa->get_policy(this->ike_sa);
connection = this->ike_sa->get_connection(this->ike_sa);
if (policy && policy->get_auth_method(policy) == AUTH_RSA)
{
switch (connection->get_cert_policy(connection))
{
case CERT_NEVER_SEND:
break;
case CERT_SEND_IF_ASKED:
if (this->cas->get_count(this->cas) == 0)
{
break;
}
/* FALL */
case CERT_ALWAYS_SEND:
{
/* TODO: respect CA cert request */
cert = charon->credentials->get_certificate(charon->credentials,
policy->get_my_id(policy));
if (cert)
{
payload = cert_payload_create_from_x509(cert);
message->add_payload(message, (payload_t*)payload);
}
}
}
}
}
/**
* Implementation of task_t.process for initiator
*/
static status_t build_i(private_ike_cert_t *this, message_t *message)
{
if (message->get_exchange_type(message) == IKE_SA_INIT)
{
return NEED_MORE;
}
build_certreqs(this, message);
build_certs(this, message);
return NEED_MORE;
}
/**
* Implementation of task_t.process for responder
*/
static status_t process_r(private_ike_cert_t *this, message_t *message)
{
if (message->get_exchange_type(message) == IKE_SA_INIT)
{
return NEED_MORE;
}
process_certreqs(this, message);
process_certs(this, message);
return NEED_MORE;
}
/**
* Implementation of task_t.build for responder
*/
static status_t build_r(private_ike_cert_t *this, message_t *message)
{
if (message->get_exchange_type(message) == IKE_SA_INIT)
{
build_certreqs(this, message);
return NEED_MORE;
}
build_certs(this, message);
return SUCCESS;
}
/**
* Implementation of task_t.process for initiator
*/
static status_t process_i(private_ike_cert_t *this, message_t *message)
{
if (message->get_exchange_type(message) == IKE_SA_INIT)
{
process_certreqs(this, message);
return NEED_MORE;
}
process_certs(this, message);
return SUCCESS;
}
/**
* Implementation of task_t.get_type
*/
static task_type_t get_type(private_ike_cert_t *this)
{
return IKE_CERT;
}
/**
* Implementation of task_t.migrate
*/
static void migrate(private_ike_cert_t *this, ike_sa_t *ike_sa)
{
this->ike_sa = ike_sa;
this->cas->destroy_function(this->cas, free);
this->cas = linked_list_create();
}
/**
* Implementation of task_t.destroy
*/
static void destroy(private_ike_cert_t *this)
{
this->cas->destroy_function(this->cas, free);
free(this);
}
/*
* Described in header.
*/
ike_cert_t *ike_cert_create(ike_sa_t *ike_sa, bool initiator)
{
private_ike_cert_t *this = malloc_thing(private_ike_cert_t);
this->public.task.get_type = (task_type_t(*)(task_t*))get_type;
this->public.task.migrate = (void(*)(task_t*,ike_sa_t*))migrate;
this->public.task.destroy = (void(*)(task_t*))destroy;
if (initiator)
{
this->public.task.build = (status_t(*)(task_t*,message_t*))build_i;
this->public.task.process = (status_t(*)(task_t*,message_t*))process_i;
}
else
{
this->public.task.build = (status_t(*)(task_t*,message_t*))build_r;
this->public.task.process = (status_t(*)(task_t*,message_t*))process_r;
}
this->ike_sa = ike_sa;
this->initiator = initiator;
this->cas = linked_list_create();
return &this->public;
}
+61
View File
@@ -0,0 +1,61 @@
/**
* @file ike_cert.h
*
* @brief Interface ike_cert_t.
*
*/
/*
* Copyright (C) 2007 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 <http://www.fsf.org/copyleft/gpl.txt>.
*
* 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 IKE_CERT_H_
#define IKE_CERT_H_
typedef struct ike_cert_t ike_cert_t;
#include <library.h>
#include <sa/ike_sa.h>
#include <sa/tasks/task.h>
/**
* @brief Task of type ike_cert, exchanges certificates and
* certificate requests.
*
* @b Constructors:
* - ike_cert_create()
*
* @ingroup tasks
*/
struct ike_cert_t {
/**
* Implements the task_t interface
*/
task_t task;
};
/**
* @brief Create a new ike_cert task.
*
* The initiator parameter means the original initiator, not the initiator
* of the certificate request.
*
* @param ike_sa IKE_SA this task works for
* @param initiator TRUE if thask is the original initator
* @return ike_cert task to handle by the task_manager
*/
ike_cert_t *ike_cert_create(ike_sa_t *ike_sa, bool initiator);
#endif /* IKE_CERT_H_ */
+421
View File
@@ -0,0 +1,421 @@
/**
* @file ike_config.c
*
* @brief Implementation of the ike_config task.
*
*/
/*
* Copyright (C) 2007 Martin Willi
* Copyright (C) 2006-2007 Fabian Hartmann, Noah Heusser
* 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 <http://www.fsf.org/copyleft/gpl.txt>.
*
* 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 "ike_config.h"
#include <daemon.h>
#include <encoding/payloads/cp_payload.h>
typedef struct private_ike_config_t private_ike_config_t;
/**
* Private members of a ike_config_t task.
*/
struct private_ike_config_t {
/**
* Public methods and task_t interface.
*/
ike_config_t public;
/**
* Assigned IKE_SA.
*/
ike_sa_t *ike_sa;
/**
* Are we the initiator?
*/
bool initiator;
/**
* associated policy with virtual IP configuration
*/
policy_t *policy;
/**
* virtual ip
*/
host_t *virtual_ip;
/**
* list of DNS servers
*/
linked_list_t *dns;
};
/**
* build configuration payloads and attributes
*/
static void build_payloads(private_ike_config_t *this, message_t *message,
config_type_t type)
{
cp_payload_t *cp;
configuration_attribute_t *ca;
chunk_t chunk, prefix;
if (!this->virtual_ip)
{
return;
}
cp = cp_payload_create();
cp->set_config_type(cp, type);
ca = configuration_attribute_create();
if (this->virtual_ip->get_family(this->virtual_ip) == AF_INET)
{
ca->set_type(ca, INTERNAL_IP4_ADDRESS);
if (this->virtual_ip->is_anyaddr(this->virtual_ip))
{
chunk = chunk_empty;
}
else
{
chunk = this->virtual_ip->get_address(this->virtual_ip);
}
}
else
{
ca->set_type(ca, INTERNAL_IP6_ADDRESS);
if (this->virtual_ip->is_anyaddr(this->virtual_ip))
{
chunk = chunk_empty;
}
else
{
prefix = chunk_alloca(1);
*prefix.ptr = 64;
chunk = this->virtual_ip->get_address(this->virtual_ip);
chunk = chunk_cata("cc", chunk, prefix);
}
}
ca->set_value(ca, chunk);
cp->add_configuration_attribute(cp, ca);
/* we currently always add a DNS request if we request an IP */
if (this->initiator)
{
ca = configuration_attribute_create();
if (this->virtual_ip->get_family(this->virtual_ip) == AF_INET)
{
ca->set_type(ca, INTERNAL_IP4_DNS);
}
else
{
ca->set_type(ca, INTERNAL_IP6_DNS);
}
cp->add_configuration_attribute(cp, ca);
}
else
{
host_t *ip;
iterator_t *iterator = this->dns->create_iterator(this->dns, TRUE);
while (iterator->iterate(iterator, (void**)&ip))
{
ca = configuration_attribute_create();
if (ip->get_family(ip) == AF_INET)
{
ca->set_type(ca, INTERNAL_IP4_DNS);
}
else
{
ca->set_type(ca, INTERNAL_IP6_DNS);
}
chunk = ip->get_address(ip);
ca->set_value(ca, chunk);
cp->add_configuration_attribute(cp, ca);
}
iterator->destroy(iterator);
}
message->add_payload(message, (payload_t*)cp);
}
/**
* process a single configuration attribute
*/
static void process_attribute(private_ike_config_t *this,
configuration_attribute_t *ca)
{
host_t *ip;
chunk_t addr;
int family = AF_INET6;
switch (ca->get_type(ca))
{
case INTERNAL_IP4_ADDRESS:
family = AF_INET;
/* fall */
case INTERNAL_IP6_ADDRESS:
{
addr = ca->get_value(ca);
if (addr.len == 0)
{
ip = host_create_any(family);
}
else
{
/* skip prefix byte in IPv6 payload*/
if (family == AF_INET6)
{
addr.len--;
}
ip = host_create_from_chunk(family, addr, 0);
}
if (ip && !this->virtual_ip)
{
this->virtual_ip = ip;
}
break;
}
case INTERNAL_IP4_DNS:
family = AF_INET;
/* fall */
case INTERNAL_IP6_DNS:
{
addr = ca->get_value(ca);
if (addr.len == 0)
{
ip = host_create_any(family);
}
else
{
ip = host_create_from_chunk(family, addr, 0);
}
if (ip)
{
this->dns->insert_last(this->dns, ip);
}
break;
}
case INTERNAL_IP4_NBNS:
case INTERNAL_IP6_NBNS:
/* TODO */
default:
DBG1(DBG_IKE, "ignoring %N config attribute",
configuration_attribute_type_names,
ca->get_type(ca));
break;
}
}
/**
* Scan for configuration payloads and attributes
*/
static void process_payloads(private_ike_config_t *this, message_t *message)
{
iterator_t *iterator, *attributes;
payload_t *payload;
iterator = message->get_payload_iterator(message);
while (iterator->iterate(iterator, (void**)&payload))
{
if (payload->get_type(payload) == CONFIGURATION)
{
cp_payload_t *cp = (cp_payload_t*)payload;
configuration_attribute_t *ca;
switch (cp->get_config_type(cp))
{
case CFG_REQUEST:
case CFG_REPLY:
{
attributes = cp->create_attribute_iterator(cp);
while (attributes->iterate(attributes, (void**)&ca))
{
process_attribute(this, ca);
}
attributes->destroy(attributes);
break;
}
default:
DBG1(DBG_IKE, "ignoring %N config payload",
config_type_names, cp->get_config_type(cp));
break;
}
}
}
iterator->destroy(iterator);
}
/**
* Implementation of task_t.process for initiator
*/
static status_t build_i(private_ike_config_t *this, message_t *message)
{
if (message->get_exchange_type(message) != IKE_SA_INIT)
{
this->virtual_ip = this->policy->get_virtual_ip(this->policy, NULL);
build_payloads(this, message, CFG_REQUEST);
}
return NEED_MORE;
}
/**
* Implementation of task_t.process for responder
*/
static status_t process_r(private_ike_config_t *this, message_t *message)
{
if (message->get_exchange_type(message) != IKE_SA_INIT)
{
process_payloads(this, message);
}
return NEED_MORE;
}
/**
* Implementation of task_t.build for responder
*/
static status_t build_r(private_ike_config_t *this, message_t *message)
{
if (message->get_exchange_type(message) != IKE_SA_INIT)
{
this->policy = this->ike_sa->get_policy(this->ike_sa);
if (this->policy && this->virtual_ip)
{
host_t *ip;
DBG1(DBG_IKE, "peer requested virtual IP %H", this->virtual_ip);
ip = this->policy->get_virtual_ip(this->policy, this->virtual_ip);
if (ip == NULL)
{
DBG1(DBG_IKE, "not assigning a virtual IP to peer");
return SUCCESS;
}
DBG1(DBG_IKE, "assigning virtual IP %H to peer", ip);
this->ike_sa->set_virtual_ip(this->ike_sa, FALSE, ip);
this->virtual_ip->destroy(this->virtual_ip);
this->virtual_ip = ip;
/* DNS is for testing only */
if (this->dns->remove_last(this->dns, (void**)&ip) == SUCCESS)
{
ip->destroy(ip);
ip = host_create_from_string("10.3.0.1", 0);
this->dns->insert_last(this->dns, ip);
ip = host_create_from_string("10.3.0.2", 0);
this->dns->insert_last(this->dns, ip);
}
build_payloads(this, message, CFG_REPLY);
}
return SUCCESS;
}
return NEED_MORE;
}
/**
* Implementation of task_t.process for initiator
*/
static status_t process_i(private_ike_config_t *this, message_t *message)
{
if (message->get_exchange_type(message) != IKE_SA_INIT)
{
host_t *ip;
DESTROY_IF(this->virtual_ip);
this->virtual_ip = NULL;
process_payloads(this, message);
if (this->virtual_ip)
{
this->ike_sa->set_virtual_ip(this->ike_sa, TRUE, this->virtual_ip);
while (this->dns->remove_last(this->dns, (void**)&ip) == SUCCESS)
{
this->ike_sa->add_dns_server(this->ike_sa, ip);
ip->destroy(ip);
}
}
return SUCCESS;
}
return NEED_MORE;
}
/**
* Implementation of task_t.get_type
*/
static task_type_t get_type(private_ike_config_t *this)
{
return IKE_CONFIG;
}
/**
* Implementation of task_t.migrate
*/
static void migrate(private_ike_config_t *this, ike_sa_t *ike_sa)
{
DESTROY_IF(this->virtual_ip);
this->dns->destroy_offset(this->dns, offsetof(host_t, destroy));
this->ike_sa = ike_sa;
this->virtual_ip = NULL;
this->dns = linked_list_create();
}
/**
* Implementation of task_t.destroy
*/
static void destroy(private_ike_config_t *this)
{
DESTROY_IF(this->virtual_ip);
this->dns->destroy_offset(this->dns, offsetof(host_t, destroy));
free(this);
}
/*
* Described in header.
*/
ike_config_t *ike_config_create(ike_sa_t *ike_sa, policy_t *policy)
{
private_ike_config_t *this = malloc_thing(private_ike_config_t);
this->public.task.get_type = (task_type_t(*)(task_t*))get_type;
this->public.task.migrate = (void(*)(task_t*,ike_sa_t*))migrate;
this->public.task.destroy = (void(*)(task_t*))destroy;
if (policy)
{
this->public.task.build = (status_t(*)(task_t*,message_t*))build_i;
this->public.task.process = (status_t(*)(task_t*,message_t*))process_i;
this->initiator = TRUE;
}
else
{
this->public.task.build = (status_t(*)(task_t*,message_t*))build_r;
this->public.task.process = (status_t(*)(task_t*,message_t*))process_r;
this->initiator = FALSE;
}
this->ike_sa = ike_sa;
this->policy = policy;
this->virtual_ip = NULL;
this->dns = linked_list_create();
return &this->public;
}
+59
View File
@@ -0,0 +1,59 @@
/**
* @file ike_config.h
*
* @brief Interface ike_config_t.
*
*/
/*
* Copyright (C) 2007 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 <http://www.fsf.org/copyleft/gpl.txt>.
*
* 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 IKE_CONFIG_H_
#define IKE_CONFIG_H_
typedef struct ike_config_t ike_config_t;
#include <library.h>
#include <sa/ike_sa.h>
#include <sa/tasks/task.h>
#include <config/policies/policy.h>
/**
* @brief Task of type IKE_CONFIG, sets up a virtual IP and other
* configurations for an IKE_SA.
*
* @b Constructors:
* - ike_config_create()
*
* @ingroup tasks
*/
struct ike_config_t {
/**
* Implements the task_t interface
*/
task_t task;
};
/**
* @brief Create a new ike_config task.
*
* @param ike_sa IKE_SA this task works for
* @param policy policy for the initiator, NULL for the responder
* @return ike_config task to handle by the task_manager
*/
ike_config_t *ike_config_create(ike_sa_t *ike_sa, policy_t *policy);
#endif /* IKE_CONFIG_H_ */
+169
View File
@@ -0,0 +1,169 @@
/**
* @file ike_delete.c
*
* @brief Implementation of the ike_delete task.
*
*/
/*
* Copyright (C) 2006-2007 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 <http://www.fsf.org/copyleft/gpl.txt>.
*
* 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 "ike_delete.h"
#include <daemon.h>
#include <encoding/payloads/delete_payload.h>
typedef struct private_ike_delete_t private_ike_delete_t;
/**
* Private members of a ike_delete_t task.
*/
struct private_ike_delete_t {
/**
* Public methods and task_t interface.
*/
ike_delete_t public;
/**
* Assigned IKE_SA.
*/
ike_sa_t *ike_sa;
/**
* Are we the initiator?
*/
bool initiator;
/**
* are we responding to a delete, but have initated our own?
*/
bool simultaneous;
};
/**
* Implementation of task_t.build for initiator
*/
static status_t build_i(private_ike_delete_t *this, message_t *message)
{
delete_payload_t *delete_payload;
delete_payload = delete_payload_create(PROTO_IKE);
message->add_payload(message, (payload_t*)delete_payload);
this->ike_sa->set_state(this->ike_sa, IKE_DELETING);
return NEED_MORE;
}
/**
* Implementation of task_t.process for initiator
*/
static status_t process_i(private_ike_delete_t *this, message_t *message)
{
/* completed, delete IKE_SA by returning FAILED */
return FAILED;
}
/**
* Implementation of task_t.process for initiator
*/
static status_t process_r(private_ike_delete_t *this, message_t *message)
{
/* we don't even scan the payloads, as the message wouldn't have
* come so far without being correct */
switch (this->ike_sa->get_state(this->ike_sa))
{
case IKE_DELETING:
this->simultaneous = TRUE;
break;
case IKE_ESTABLISHED:
DBG1(DBG_IKE, "deleting IKE_SA on request");
/* warn only if we are established */
default:
this->ike_sa->set_state(this->ike_sa, IKE_DELETING);
break;
}
return NEED_MORE;
}
/**
* Implementation of task_t.build for responder
*/
static status_t build_r(private_ike_delete_t *this, message_t *message)
{
if (this->simultaneous)
{
/* wait for peers response for our delete request */
return SUCCESS;
}
/* completed, delete IKE_SA by returning FAILED */
return FAILED;
}
/**
* Implementation of task_t.get_type
*/
static task_type_t get_type(private_ike_delete_t *this)
{
return IKE_DELETE;
}
/**
* Implementation of task_t.migrate
*/
static void migrate(private_ike_delete_t *this, ike_sa_t *ike_sa)
{
this->ike_sa = ike_sa;
this->simultaneous = FALSE;
}
/**
* Implementation of task_t.destroy
*/
static void destroy(private_ike_delete_t *this)
{
free(this);
}
/*
* Described in header.
*/
ike_delete_t *ike_delete_create(ike_sa_t *ike_sa, bool initiator)
{
private_ike_delete_t *this = malloc_thing(private_ike_delete_t);
this->public.task.get_type = (task_type_t(*)(task_t*))get_type;
this->public.task.migrate = (void(*)(task_t*,ike_sa_t*))migrate;
this->public.task.destroy = (void(*)(task_t*))destroy;
if (initiator)
{
this->public.task.build = (status_t(*)(task_t*,message_t*))build_i;
this->public.task.process = (status_t(*)(task_t*,message_t*))process_i;
}
else
{
this->public.task.build = (status_t(*)(task_t*,message_t*))build_r;
this->public.task.process = (status_t(*)(task_t*,message_t*))process_r;
}
this->ike_sa = ike_sa;
this->initiator = initiator;
this->simultaneous = FALSE;
return &this->public;
}
+57
View File
@@ -0,0 +1,57 @@
/**
* @file ike_delete.h
*
* @brief Interface ike_delete_t.
*
*/
/*
* Copyright (C) 2007 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 <http://www.fsf.org/copyleft/gpl.txt>.
*
* 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 IKE_DELETE_H_
#define IKE_DELETE_H_
typedef struct ike_delete_t ike_delete_t;
#include <library.h>
#include <sa/ike_sa.h>
#include <sa/tasks/task.h>
/**
* @brief Task of type ike_delete, delete an IKE_SA.
*
* @b Constructors:
* - ike_delete_create()
*
* @ingroup tasks
*/
struct ike_delete_t {
/**
* Implements the task_t interface
*/
task_t task;
};
/**
* @brief Create a new ike_delete task.
*
* @param ike_sa IKE_SA this task works for
* @param initiator TRUE if we initiate the delete
* @return ike_delete task to handle by the task_manager
*/
ike_delete_t *ike_delete_create(ike_sa_t *ike_sa, bool initiator);
#endif /* IKE_DELETE_H_ */
+106
View File
@@ -0,0 +1,106 @@
/**
* @file ike_dpd.c
*
* @brief Implementation of the ike_dpd task.
*
*/
/*
* Copyright (C) 2007 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 <http://www.fsf.org/copyleft/gpl.txt>.
*
* 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 "ike_dpd.h"
#include <daemon.h>
typedef struct private_ike_dpd_t private_ike_dpd_t;
/**
* Private members of a ike_dpd_t task.
*/
struct private_ike_dpd_t {
/**
* Public methods and task_t interface.
*/
ike_dpd_t public;
};
/**
* Implementation of task_t.build for initiator
* Implementation of task_t.process for responder
*/
static status_t return_need_more(private_ike_dpd_t *this, message_t *message)
{
return NEED_MORE;
}
/**
* Implementation of task_t.process for initiator
* Implementation of task_t.build for responder
*/
static status_t return_success(private_ike_dpd_t *this, message_t *message)
{
return SUCCESS;
}
/**
* Implementation of task_t.get_type
*/
static task_type_t get_type(private_ike_dpd_t *this)
{
return IKE_DEADPEER;
}
/**
* Implementation of task_t.migrate
*/
static void migrate(private_ike_dpd_t *this, ike_sa_t *ike_sa)
{
}
/**
* Implementation of task_t.destroy
*/
static void destroy(private_ike_dpd_t *this)
{
free(this);
}
/*
* Described in header.
*/
ike_dpd_t *ike_dpd_create(bool initiator)
{
private_ike_dpd_t *this = malloc_thing(private_ike_dpd_t);
this->public.task.get_type = (task_type_t(*)(task_t*))get_type;
this->public.task.migrate = (void(*)(task_t*,ike_sa_t*))migrate;
this->public.task.destroy = (void(*)(task_t*))destroy;
if (initiator)
{
this->public.task.build = (status_t(*)(task_t*,message_t*))return_need_more;
this->public.task.process = (status_t(*)(task_t*,message_t*))return_success;
}
else
{
this->public.task.build = (status_t(*)(task_t*,message_t*))return_success;
this->public.task.process = (status_t(*)(task_t*,message_t*))return_need_more;
}
return &this->public;
}
+58
View File
@@ -0,0 +1,58 @@
/**
* @file ike_dpd.h
*
* @brief Interface ike_dpd_t.
*
*/
/*
* Copyright (C) 2007 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 <http://www.fsf.org/copyleft/gpl.txt>.
*
* 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 IKE_DPD_H_
#define IKE_DPD_H_
typedef struct ike_dpd_t ike_dpd_t;
#include <library.h>
#include <sa/ike_sa.h>
#include <sa/tasks/task.h>
/**
* @brief Task of type ike_dpd, detects dead peers.
*
* The DPD task actually does nothing, as a DPD has no associated payloads.
*
* @b Constructors:
* - ike_dpd_create()
*
* @ingroup tasks
*/
struct ike_dpd_t {
/**
* Implements the task_t interface
*/
task_t task;
};
/**
* @brief Create a new ike_dpd task.
*
* @param initiator TRUE if thask is the original initator
* @return ike_dpd task to handle by the task_manager
*/
ike_dpd_t *ike_dpd_create(bool initiator);
#endif /* IKE_DPD_H_ */
+536
View File
@@ -0,0 +1,536 @@
/**
* @file ike_init.c
*
* @brief Implementation of the ike_init task.
*
*/
/*
* Copyright (C) 2005-2007 Martin Willi
* Copyright (C) 2005 Jan Hutter
* 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 <http://www.fsf.org/copyleft/gpl.txt>.
*
* 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 "ike_init.h"
#include <string.h>
#include <daemon.h>
#include <crypto/diffie_hellman.h>
#include <encoding/payloads/sa_payload.h>
#include <encoding/payloads/ke_payload.h>
#include <encoding/payloads/nonce_payload.h>
typedef struct private_ike_init_t private_ike_init_t;
/**
* Private members of a ike_init_t task.
*/
struct private_ike_init_t {
/**
* Public methods and task_t interface.
*/
ike_init_t public;
/**
* Assigned IKE_SA.
*/
ike_sa_t *ike_sa;
/**
* Are we the initiator?
*/
bool initiator;
/**
* Connection established by this IKE_SA
*/
connection_t *connection;
/**
* diffie hellman group to use
*/
diffie_hellman_group_t dh_group;
/**
* Diffie hellman object used to generate public DH value.
*/
diffie_hellman_t *diffie_hellman;
/**
* nonce chosen by us
*/
chunk_t my_nonce;
/**
* nonce chosen by peer
*/
chunk_t other_nonce;
/**
* Negotiated proposal used for IKE_SA
*/
proposal_t *proposal;
/**
* Old IKE_SA which gets rekeyed
*/
ike_sa_t *old_sa;
};
/**
* build the payloads for the message
*/
static void build_payloads(private_ike_init_t *this, message_t *message)
{
sa_payload_t *sa_payload;
ke_payload_t *ke_payload;
nonce_payload_t *nonce_payload;
linked_list_t *proposal_list;
ike_sa_id_t *id;
proposal_t *proposal;
iterator_t *iterator;
id = this->ike_sa->get_id(this->ike_sa);
this->connection = this->ike_sa->get_connection(this->ike_sa);
if (this->initiator)
{
proposal_list = this->connection->get_proposals(this->connection);
if (this->old_sa)
{
/* include SPI of new IKE_SA when we are rekeying */
iterator = proposal_list->create_iterator(proposal_list, TRUE);
while (iterator->iterate(iterator, (void**)&proposal))
{
proposal->set_spi(proposal, id->get_initiator_spi(id));
}
iterator->destroy(iterator);
}
sa_payload = sa_payload_create_from_proposal_list(proposal_list);
proposal_list->destroy_offset(proposal_list, offsetof(proposal_t, destroy));
}
else
{
if (this->old_sa)
{
/* include SPI of new IKE_SA when we are rekeying */
this->proposal->set_spi(this->proposal, id->get_responder_spi(id));
}
sa_payload = sa_payload_create_from_proposal(this->proposal);
}
message->add_payload(message, (payload_t*)sa_payload);
ke_payload = ke_payload_create_from_diffie_hellman(this->diffie_hellman);
message->add_payload(message, (payload_t*)ke_payload);
nonce_payload = nonce_payload_create();
nonce_payload->set_nonce(nonce_payload, this->my_nonce);
message->add_payload(message, (payload_t*)nonce_payload);
}
/**
* Read payloads from message
*/
static void process_payloads(private_ike_init_t *this, message_t *message)
{
iterator_t *iterator;
payload_t *payload;
iterator = message->get_payload_iterator(message);
while (iterator->iterate(iterator, (void**)&payload))
{
switch (payload->get_type(payload))
{
case SECURITY_ASSOCIATION:
{
sa_payload_t *sa_payload = (sa_payload_t*)payload;
linked_list_t *proposal_list;
proposal_list = sa_payload->get_proposals(sa_payload);
this->proposal = this->connection->select_proposal(
this->connection, proposal_list);
proposal_list->destroy_offset(proposal_list,
offsetof(proposal_t, destroy));
break;
}
case KEY_EXCHANGE:
{
ke_payload_t *ke_payload = (ke_payload_t*)payload;
diffie_hellman_group_t dh_group;
chunk_t key_data;
dh_group = ke_payload->get_dh_group_number(ke_payload);
if (this->initiator)
{
if (dh_group != this->dh_group)
{
DBG1(DBG_IKE, "received a DH group not requested (%N)",
diffie_hellman_group_names, dh_group);
break;
}
}
else
{
this->dh_group = dh_group;
if (!this->connection->check_dh_group(this->connection,
dh_group))
{
break;
}
this->diffie_hellman = diffie_hellman_create(dh_group);
}
if (this->diffie_hellman)
{
key_data = ke_payload->get_key_exchange_data(ke_payload);
this->diffie_hellman->set_other_public_value(this->diffie_hellman, key_data);
}
break;
}
case NONCE:
{
nonce_payload_t *nonce_payload = (nonce_payload_t*)payload;
this->other_nonce = nonce_payload->get_nonce(nonce_payload);
break;
}
default:
break;
}
}
iterator->destroy(iterator);
}
/**
* Implementation of task_t.process for initiator
*/
static status_t build_i(private_ike_init_t *this, message_t *message)
{
randomizer_t *randomizer;
status_t status;
this->connection = this->ike_sa->get_connection(this->ike_sa);
SIG(IKE_UP_START, "initiating IKE_SA to %H",
this->connection->get_other_host(this->connection));
this->ike_sa->set_state(this->ike_sa, IKE_CONNECTING);
/* if the DH group is set via use_dh_group(), we already have a DH object */
if (!this->diffie_hellman)
{
this->dh_group = this->connection->get_dh_group(this->connection);
this->diffie_hellman = diffie_hellman_create(this->dh_group);
if (this->diffie_hellman == NULL)
{
SIG(IKE_UP_FAILED, "configured DH group %N not supported",
diffie_hellman_group_names, this->dh_group);
return FAILED;
}
}
randomizer = randomizer_create();
status = randomizer->allocate_pseudo_random_bytes(randomizer, NONCE_SIZE,
&this->my_nonce);
randomizer->destroy(randomizer);
if (status != SUCCESS)
{
SIG(IKE_UP_FAILED, "error generating random nonce value");
return FAILED;
}
build_payloads(this, message);
return NEED_MORE;
}
/**
* Implementation of task_t.process for initiator
*/
static status_t process_r(private_ike_init_t *this, message_t *message)
{
randomizer_t *randomizer;
this->connection = this->ike_sa->get_connection(this->ike_sa);
SIG(IKE_UP_FAILED, "%H is initiating an IKE_SA",
message->get_source(message));
this->ike_sa->set_state(this->ike_sa, IKE_CONNECTING);
randomizer = randomizer_create();
if (randomizer->allocate_pseudo_random_bytes(randomizer, NONCE_SIZE,
&this->my_nonce) != SUCCESS)
{
DBG1(DBG_IKE, "error generating random nonce value");
}
randomizer->destroy(randomizer);
process_payloads(this, message);
return NEED_MORE;
}
/**
* Implementation of task_t.build for responder
*/
static status_t build_r(private_ike_init_t *this, message_t *message)
{
chunk_t secret;
status_t status;
/* check if we have everything we need */
if (this->proposal == NULL ||
this->other_nonce.len == 0 || this->my_nonce.len == 0)
{
SIG(IKE_UP_FAILED, "received proposals inacceptable");
message->add_notify(message, TRUE, NO_PROPOSAL_CHOSEN, chunk_empty);
return FAILED;
}
if (this->diffie_hellman == NULL ||
this->diffie_hellman->get_shared_secret(this->diffie_hellman,
&secret) != SUCCESS)
{
chunk_t chunk;
u_int16_t dh_enc;
SIG(IKE_UP_FAILED, "received inacceptable DH group (%N)",
diffie_hellman_group_names, this->dh_group);
this->dh_group = this->connection->get_dh_group(this->connection);
dh_enc = htons(this->dh_group);
chunk.ptr = (u_int8_t*)&dh_enc;
chunk.len = sizeof(dh_enc);
message->add_notify(message, TRUE, INVALID_KE_PAYLOAD, chunk);
DBG1(DBG_IKE, "requesting DH group %N",
diffie_hellman_group_names, this->dh_group);
return FAILED;
}
if (this->old_sa)
{
ike_sa_id_t *id;
prf_t *prf, *child_prf;
/* Apply SPI if we are rekeying */
id = this->ike_sa->get_id(this->ike_sa);
id->set_initiator_spi(id, this->proposal->get_spi(this->proposal));
/* setup crypto keys for the rekeyed SA */
prf = this->old_sa->get_prf(this->old_sa);
child_prf = this->old_sa->get_child_prf(this->old_sa);
status = this->ike_sa->derive_keys(this->ike_sa, this->proposal, secret,
this->other_nonce, this->my_nonce,
FALSE, child_prf, prf);
}
else
{
/* setup crypto keys */
status = this->ike_sa->derive_keys(this->ike_sa, this->proposal, secret,
this->other_nonce, this->my_nonce,
FALSE, NULL, NULL);
}
if (status != SUCCESS)
{
SIG(IKE_UP_FAILED, "key derivation failed");
message->add_notify(message, TRUE, NO_PROPOSAL_CHOSEN, chunk_empty);
return FAILED;
}
build_payloads(this, message);
return SUCCESS;
}
/**
* Implementation of task_t.process for initiator
*/
static status_t process_i(private_ike_init_t *this, message_t *message)
{
chunk_t secret;
status_t status;
iterator_t *iterator;
payload_t *payload;
/* check for erronous notifies */
iterator = message->get_payload_iterator(message);
while (iterator->iterate(iterator, (void**)&payload))
{
if (payload->get_type(payload) == NOTIFY)
{
notify_payload_t *notify = (notify_payload_t*)payload;
notify_type_t type = notify->get_notify_type(notify);
switch (type)
{
case INVALID_KE_PAYLOAD:
{
chunk_t data;
diffie_hellman_group_t old_dh_group;
old_dh_group = this->dh_group;
data = notify->get_notification_data(notify);
this->dh_group = ntohs(*((u_int16_t*)data.ptr));
DBG1(DBG_IKE, "peer didn't accept DH group %N, it requested"
" %N", diffie_hellman_group_names, old_dh_group,
diffie_hellman_group_names, this->dh_group);
if (!this->connection->check_dh_group(this->connection,
this->dh_group))
{
SIG(IKE_UP_FAILED, "requested DH group %N not "
"acceptable, giving up", diffie_hellman_group_names,
this->dh_group);
iterator->destroy(iterator);
return FAILED;
}
this->ike_sa->reset(this->ike_sa);
iterator->destroy(iterator);
return NEED_MORE;
}
default:
{
if (type < 16383)
{
SIG(IKE_UP_FAILED, "received %N notify error",
notify_type_names, type);
iterator->destroy(iterator);
return FAILED;
}
}
}
}
}
iterator->destroy(iterator);
process_payloads(this, message);
/* check if we have everything */
if (this->proposal == NULL ||
this->other_nonce.len == 0 || this->my_nonce.len == 0)
{
SIG(IKE_UP_FAILED, "peers proposal selection invalid");
return FAILED;
}
if (this->diffie_hellman == NULL ||
this->diffie_hellman->get_shared_secret(this->diffie_hellman,
&secret) != SUCCESS)
{
SIG(IKE_UP_FAILED, "peers DH group selection invalid");
return FAILED;
}
/* Apply SPI if we are rekeying */
if (this->old_sa)
{
ike_sa_id_t *id;
prf_t *prf, *child_prf;
id = this->ike_sa->get_id(this->ike_sa);
id->set_responder_spi(id, this->proposal->get_spi(this->proposal));
/* setup crypto keys for the rekeyed SA */
prf = this->old_sa->get_prf(this->old_sa);
child_prf = this->old_sa->get_child_prf(this->old_sa);
status = this->ike_sa->derive_keys(this->ike_sa, this->proposal, secret,
this->my_nonce, this->other_nonce,
TRUE, child_prf, prf);
}
else
{
/* setup crypto keys for a new SA */
status = this->ike_sa->derive_keys(this->ike_sa, this->proposal, secret,
this->my_nonce, this->other_nonce,
TRUE, NULL, NULL);
}
if (status != SUCCESS)
{
SIG(IKE_UP_FAILED, "key derivation failed");
return FAILED;
}
return SUCCESS;
}
/**
* Implementation of task_t.get_type
*/
static task_type_t get_type(private_ike_init_t *this)
{
return IKE_INIT;
}
/**
* Implementation of task_t.migrate
*/
static void migrate(private_ike_init_t *this, ike_sa_t *ike_sa)
{
DESTROY_IF(this->proposal);
DESTROY_IF(this->diffie_hellman);
chunk_free(&this->my_nonce);
chunk_free(&this->other_nonce);
this->ike_sa = ike_sa;
this->proposal = NULL;
this->diffie_hellman = diffie_hellman_create(this->dh_group);
}
/**
* Implementation of task_t.destroy
*/
static void destroy(private_ike_init_t *this)
{
DESTROY_IF(this->proposal);
DESTROY_IF(this->diffie_hellman);
chunk_free(&this->my_nonce);
chunk_free(&this->other_nonce);
free(this);
}
/*
* Described in header.
*/
ike_init_t *ike_init_create(ike_sa_t *ike_sa, bool initiator, ike_sa_t *old_sa)
{
private_ike_init_t *this = malloc_thing(private_ike_init_t);
this->public.task.get_type = (task_type_t(*)(task_t*))get_type;
this->public.task.migrate = (void(*)(task_t*,ike_sa_t*))migrate;
this->public.task.destroy = (void(*)(task_t*))destroy;
if (initiator)
{
this->public.task.build = (status_t(*)(task_t*,message_t*))build_i;
this->public.task.process = (status_t(*)(task_t*,message_t*))process_i;
}
else
{
this->public.task.build = (status_t(*)(task_t*,message_t*))build_r;
this->public.task.process = (status_t(*)(task_t*,message_t*))process_r;
}
this->ike_sa = ike_sa;
this->initiator = initiator;
this->dh_group = MODP_NONE;
this->diffie_hellman = NULL;
this->my_nonce = chunk_empty;
this->other_nonce = chunk_empty;
this->proposal = NULL;
this->connection = NULL;
this->old_sa = old_sa;
return &this->public;
}
+60
View File
@@ -0,0 +1,60 @@
/**
* @file ike_init.h
*
* @brief Interface ike_init_t.
*
*/
/*
* Copyright (C) 2007 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 <http://www.fsf.org/copyleft/gpl.txt>.
*
* 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 IKE_INIT_H_
#define IKE_INIT_H_
typedef struct ike_init_t ike_init_t;
#include <library.h>
#include <sa/ike_sa.h>
#include <sa/tasks/task.h>
/**
* @brief Task of type IKE_INIT, creates an IKE_SA without authentication.
*
* The authentication of is handle in the ike_auth and/or ike_auth_eap task.
*
* @b Constructors:
* - ike_init_create()
*
* @ingroup tasks
*/
struct ike_init_t {
/**
* Implements the task_t interface
*/
task_t task;
};
/**
* @brief Create a new IKE_INIT task.
*
* @param ike_sa IKE_SA this task works for (new one when rekeying)
* @param initiator TRUE if thask is the original initator
* @param old_sa old IKE_SA when we are rekeying
* @return ike_init task to handle by the task_manager
*/
ike_init_t *ike_init_create(ike_sa_t *ike_sa, bool initiator, ike_sa_t *old_sa);
#endif /* IKE_INIT_H_ */
+378
View File
@@ -0,0 +1,378 @@
/**
* @file ike_natd.c
*
* @brief Implementation of the ike_natd task.
*
*/
/*
* Copyright (C) 2006-2007 Martin Willi
* Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger
* 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 <http://www.fsf.org/copyleft/gpl.txt>.
*
* 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 "ike_natd.h"
#include <string.h>
#include <daemon.h>
#include <crypto/hashers/hasher.h>
#include <encoding/payloads/notify_payload.h>
typedef struct private_ike_natd_t private_ike_natd_t;
/**
* Private members of a ike_natd_t task.
*/
struct private_ike_natd_t {
/**
* Public methods and task_t interface.
*/
ike_natd_t public;
/**
* Assigned IKE_SA.
*/
ike_sa_t *ike_sa;
/**
* Are we the initiator?
*/
bool initiator;
/**
* Hasher used to build NAT detection hashes
*/
hasher_t *hasher;
/**
* Did we process any NAT detection notifys for a source address?
*/
bool src_seen;
/**
* Did we process any NAT detection notifys for a destination address?
*/
bool dst_seen;
/**
* Have we found a matching source address NAT hash?
*/
bool src_matched;
/**
* Have we found a matching destination address NAT hash?
*/
bool dst_matched;
};
/**
* Build NAT detection hash for a host
*/
static chunk_t generate_natd_hash(private_ike_natd_t *this,
ike_sa_id_t *ike_sa_id, host_t *host)
{
chunk_t natd_chunk, spi_i_chunk, spi_r_chunk, addr_chunk, port_chunk;
chunk_t natd_hash;
u_int64_t spi_i, spi_r;
u_int16_t port;
/* prepare all requred chunks */
spi_i = ike_sa_id->get_initiator_spi(ike_sa_id);
spi_r = ike_sa_id->get_responder_spi(ike_sa_id);
spi_i_chunk.ptr = (void*)&spi_i;
spi_i_chunk.len = sizeof(spi_i);
spi_r_chunk.ptr = (void*)&spi_r;
spi_r_chunk.len = sizeof(spi_r);
port = htons(host->get_port(host));
port_chunk.ptr = (void*)&port;
port_chunk.len = sizeof(port);
addr_chunk = host->get_address(host);
DBG2(DBG_IKE, "using SPI %J", ike_sa_id);
/* natd_hash = SHA1( spi_i | spi_r | address | port ) */
natd_chunk = chunk_cat("cccc", spi_i_chunk, spi_r_chunk, addr_chunk, port_chunk);
this->hasher->allocate_hash(this->hasher, natd_chunk, &natd_hash);
DBG3(DBG_IKE, "natd_chunk %B", &natd_chunk);
DBG3(DBG_IKE, "natd_hash %B", &natd_hash);
chunk_free(&natd_chunk);
return natd_hash;
}
/**
* Build a NAT detection notify payload.
*/
static notify_payload_t *build_natd_payload(private_ike_natd_t *this,
notify_type_t type, host_t *host)
{
chunk_t hash;
notify_payload_t *notify;
ike_sa_id_t *ike_sa_id;
ike_sa_id = this->ike_sa->get_id(this->ike_sa);
notify = notify_payload_create();
notify->set_notify_type(notify, type);
hash = generate_natd_hash(this, ike_sa_id, host);
notify->set_notification_data(notify, hash);
chunk_free(&hash);
return notify;
}
/**
* read notifys from message and evaluate them
*/
static void process_payloads(private_ike_natd_t *this, message_t *message)
{
iterator_t *iterator;
payload_t *payload;
notify_payload_t *notify;
chunk_t hash, src_hash, dst_hash;
ike_sa_id_t *ike_sa_id;
host_t *me, *other;
/* Precompute NAT-D hashes for incoming NAT notify comparison */
ike_sa_id = message->get_ike_sa_id(message);
me = this->ike_sa->get_my_host(this->ike_sa);
other = this->ike_sa->get_other_host(this->ike_sa);
dst_hash = generate_natd_hash(this, ike_sa_id, me);
src_hash = generate_natd_hash(this, ike_sa_id, other);
DBG2(DBG_IKE, "precalculated src_hash %B", &src_hash);
DBG2(DBG_IKE, "precalculated dst_hash %B", &dst_hash);
iterator = message->get_payload_iterator(message);
while (iterator->iterate(iterator, (void**)&payload))
{
if (payload->get_type(payload) != NOTIFY)
{
continue;
}
notify = (notify_payload_t*)payload;
switch (notify->get_notify_type(notify))
{
case NAT_DETECTION_DESTINATION_IP:
{
this->dst_seen = TRUE;
if (!this->dst_matched)
{
hash = notify->get_notification_data(notify);
DBG2(DBG_IKE, "received dst_hash %B", &hash);
if (chunk_equals(hash, dst_hash))
{
this->dst_matched = TRUE;
}
}
break;
}
case NAT_DETECTION_SOURCE_IP:
{
this->src_seen = TRUE;
if (!this->src_matched)
{
hash = notify->get_notification_data(notify);
DBG2(DBG_IKE, "received src_hash %B", &hash);
if (chunk_equals(hash, src_hash))
{
this->src_matched = TRUE;
}
}
break;
}
default:
break;
}
}
iterator->destroy(iterator);
chunk_free(&src_hash);
chunk_free(&dst_hash);
if (this->src_seen && this->dst_seen)
{
if (!this->dst_matched)
{
this->ike_sa->enable_natt(this->ike_sa, TRUE);
}
if (!this->src_matched)
{
this->ike_sa->enable_natt(this->ike_sa, FALSE);
}
}
}
/**
* Implementation of task_t.process for initiator
*/
static status_t process_i(private_ike_natd_t *this, message_t *message)
{
process_payloads(this, message);
if (this->ike_sa->is_natt_enabled(this->ike_sa))
{
host_t *me, *other;
me = this->ike_sa->get_my_host(this->ike_sa);
me->set_port(me, IKEV2_NATT_PORT);
other = this->ike_sa->get_other_host(this->ike_sa);
other->set_port(other, IKEV2_NATT_PORT);
}
return SUCCESS;
}
/**
* Implementation of task_t.process for initiator
*/
static status_t build_i(private_ike_natd_t *this, message_t *message)
{
notify_payload_t *notify;
linked_list_t *list;
host_t *host;
/* include one notify if our address is defined, all addresses otherwise */
host = this->ike_sa->get_my_host(this->ike_sa);
if (host->is_anyaddr(host))
{
/* TODO: we could get the src address from netlink!? */
list = charon->socket->create_local_address_list(charon->socket);
while (list->remove_first(list, (void**)&host) == SUCCESS)
{
notify = build_natd_payload(this, NAT_DETECTION_SOURCE_IP, host);
host->destroy(host);
message->add_payload(message, (payload_t*)notify);
}
list->destroy(list);
}
else
{
notify = build_natd_payload(this, NAT_DETECTION_SOURCE_IP, host);
message->add_payload(message, (payload_t*)notify);
}
host = this->ike_sa->get_other_host(this->ike_sa);
notify = build_natd_payload(this, NAT_DETECTION_DESTINATION_IP, host);
message->add_payload(message, (payload_t*)notify);
return NEED_MORE;
}
/**
* Implementation of task_t.build for responder
*/
static status_t build_r(private_ike_natd_t *this, message_t *message)
{
notify_payload_t *notify;
host_t *me, *other;
iterator_t *iterator;
u_int count;
/* when only one payload is in the message, an error occured.
* TODO: find a better hack */
iterator = message->get_payload_iterator(message);
count = iterator->get_count(iterator);
iterator->destroy(iterator);
if (count < 3)
{
return NEED_MORE;
}
if (this->src_seen && this->dst_seen)
{
/* initiator seems to support NAT detection, add response */
me = this->ike_sa->get_my_host(this->ike_sa);
notify = build_natd_payload(this, NAT_DETECTION_SOURCE_IP, me);
message->add_payload(message, (payload_t*)notify);
other = this->ike_sa->get_other_host(this->ike_sa);
notify = build_natd_payload(this, NAT_DETECTION_DESTINATION_IP, other);
message->add_payload(message, (payload_t*)notify);
}
return SUCCESS;
}
/**
* Implementation of task_t.process for responder
*/
static status_t process_r(private_ike_natd_t *this, message_t *message)
{
process_payloads(this, message);
return NEED_MORE;
}
/**
* Implementation of task_t.get_type
*/
static task_type_t get_type(private_ike_natd_t *this)
{
return IKE_NATD;
}
/**
* Implementation of task_t.migrate
*/
static void migrate(private_ike_natd_t *this, ike_sa_t *ike_sa)
{
this->ike_sa = ike_sa;
this->src_seen = FALSE;
this->dst_seen = FALSE;
this->src_matched = FALSE;
this->dst_matched = FALSE;
}
/**
* Implementation of task_t.destroy
*/
static void destroy(private_ike_natd_t *this)
{
this->hasher->destroy(this->hasher);
free(this);
}
/*
* Described in header.
*/
ike_natd_t *ike_natd_create(ike_sa_t *ike_sa, bool initiator)
{
private_ike_natd_t *this = malloc_thing(private_ike_natd_t);
this->public.task.get_type = (task_type_t(*)(task_t*))get_type;
this->public.task.migrate = (void(*)(task_t*,ike_sa_t*))migrate;
this->public.task.destroy = (void(*)(task_t*))destroy;
if (initiator)
{
this->public.task.build = (status_t(*)(task_t*,message_t*))build_i;
this->public.task.process = (status_t(*)(task_t*,message_t*))process_i;
}
else
{
this->public.task.build = (status_t(*)(task_t*,message_t*))build_r;
this->public.task.process = (status_t(*)(task_t*,message_t*))process_r;
}
this->ike_sa = ike_sa;
this->initiator = initiator;
this->hasher = hasher_create(HASH_SHA1);
this->src_seen = FALSE;
this->dst_seen = FALSE;
this->src_matched = FALSE;
this->dst_matched = FALSE;
return &this->public;
}
+57
View File
@@ -0,0 +1,57 @@
/**
* @file ike_natd.h
*
* @brief Interface ike_natd_t.
*
*/
/*
* Copyright (C) 2007 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 <http://www.fsf.org/copyleft/gpl.txt>.
*
* 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 IKE_NATD_H_
#define IKE_NATD_H_
typedef struct ike_natd_t ike_natd_t;
#include <library.h>
#include <sa/ike_sa.h>
#include <sa/tasks/task.h>
/**
* @brief Task of type ike_natd, detects NAT situation in IKE_SA_INIT exchange.
*
* @b Constructors:
* - ike_natd_create()
*
* @ingroup tasks
*/
struct ike_natd_t {
/**
* Implements the task_t interface
*/
task_t task;
};
/**
* @brief Create a new ike_natd task.
*
* @param ike_sa IKE_SA this task works for
* @param initiator TRUE if thask is the original initator
* @return ike_natd task to handle by the task_manager
*/
ike_natd_t *ike_natd_create(ike_sa_t *ike_sa, bool initiator);
#endif /* IKE_NATD_H_ */
+232
View File
@@ -0,0 +1,232 @@
/**
* @file ike_rekey.c
*
* @brief Implementation of the ike_rekey task.
*
*/
/*
* Copyright (C) 2005-2007 Martin Willi
* Copyright (C) 2005 Jan Hutter
* 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 <http://www.fsf.org/copyleft/gpl.txt>.
*
* 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 "ike_rekey.h"
#include <daemon.h>
#include <crypto/diffie_hellman.h>
#include <encoding/payloads/notify_payload.h>
#include <encoding/payloads/nonce_payload.h>
#include <sa/tasks/ike_init.h>
#include <queues/jobs/delete_ike_sa_job.h>
typedef struct private_ike_rekey_t private_ike_rekey_t;
/**
* Private members of a ike_rekey_t task.
*/
struct private_ike_rekey_t {
/**
* Public methods and task_t interface.
*/
ike_rekey_t public;
/**
* Assigned IKE_SA.
*/
ike_sa_t *ike_sa;
/**
* New IKE_SA which replaces the current one
*/
ike_sa_t *new_sa;
/**
* Are we the initiator?
*/
bool initiator;
/**
* the IKE_INIT task which is reused to simplify rekeying
*/
ike_init_t *ike_init;
};
/**
* Implementation of task_t.build for initiator
*/
static status_t build_i(private_ike_rekey_t *this, message_t *message)
{
connection_t *connection;
policy_t *policy;
ike_sa_id_t *id;
id = ike_sa_id_create(0, 0, TRUE);
this->new_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager, id);
id->destroy(id);
connection = this->ike_sa->get_connection(this->ike_sa);
policy = this->ike_sa->get_policy(this->ike_sa);
this->new_sa->set_connection(this->new_sa, connection);
this->new_sa->set_policy(this->new_sa, policy);
this->ike_init = ike_init_create(this->new_sa, TRUE, this->ike_sa);
this->ike_init->task.build(&this->ike_init->task, message);
this->ike_sa->set_state(this->ike_sa, IKE_REKEYING);
return NEED_MORE;
}
/**
* Implementation of task_t.process for initiator
*/
static status_t process_r(private_ike_rekey_t *this, message_t *message)
{
connection_t *connection;
policy_t *policy;
ike_sa_id_t *id;
id = ike_sa_id_create(0, 0, FALSE);
this->new_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager, id);
id->destroy(id);
connection = this->ike_sa->get_connection(this->ike_sa);
policy = this->ike_sa->get_policy(this->ike_sa);
this->new_sa->set_connection(this->new_sa, connection);
this->new_sa->set_policy(this->new_sa, policy);
this->ike_init = ike_init_create(this->new_sa, FALSE, this->ike_sa);
this->ike_init->task.process(&this->ike_init->task, message);
return NEED_MORE;
}
/**
* Implementation of task_t.build for responder
*/
static status_t build_r(private_ike_rekey_t *this, message_t *message)
{
if (this->ike_init->task.build(&this->ike_init->task, message) == FAILED)
{
return SUCCESS;
}
this->ike_sa->set_state(this->ike_sa, IKE_REKEYING);
this->new_sa->inherit(this->new_sa, this->ike_sa);
this->new_sa->set_state(this->new_sa, IKE_ESTABLISHED);
charon->ike_sa_manager->checkin(charon->ike_sa_manager, this->new_sa);
this->new_sa = NULL;
return SUCCESS;
}
/**
* Implementation of task_t.process for initiator
*/
static status_t process_i(private_ike_rekey_t *this, message_t *message)
{
job_t *job;
if (this->ike_init->task.process(&this->ike_init->task, message) == FAILED)
{
return SUCCESS;
}
this->new_sa->set_state(this->new_sa, IKE_ESTABLISHED);
this->new_sa->inherit(this->new_sa, this->ike_sa);
charon->ike_sa_manager->checkin(charon->ike_sa_manager, this->new_sa);
this->new_sa = NULL;
job = (job_t*)delete_ike_sa_job_create(this->ike_sa->get_id(this->ike_sa),
TRUE);
charon->job_queue->add(charon->job_queue, job);
return SUCCESS;
}
/**
* Implementation of task_t.get_type
*/
static task_type_t get_type(private_ike_rekey_t *this)
{
return IKE_REKEY;
}
/**
* Implementation of task_t.migrate
*/
static void migrate(private_ike_rekey_t *this, ike_sa_t *ike_sa)
{
if (this->ike_init)
{
this->ike_init->task.destroy(&this->ike_init->task);
}
if (this->new_sa)
{
charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager,
this->new_sa);
}
this->ike_sa = ike_sa;
this->new_sa = NULL;
this->ike_init = NULL;
}
/**
* Implementation of task_t.destroy
*/
static void destroy(private_ike_rekey_t *this)
{
if (this->ike_init)
{
this->ike_init->task.destroy(&this->ike_init->task);
}
if (this->new_sa)
{
charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager,
this->new_sa);
}
free(this);
}
/*
* Described in header.
*/
ike_rekey_t *ike_rekey_create(ike_sa_t *ike_sa, bool initiator)
{
private_ike_rekey_t *this = malloc_thing(private_ike_rekey_t);
this->public.task.get_type = (task_type_t(*)(task_t*))get_type;
this->public.task.migrate = (void(*)(task_t*,ike_sa_t*))migrate;
this->public.task.destroy = (void(*)(task_t*))destroy;
if (initiator)
{
this->public.task.build = (status_t(*)(task_t*,message_t*))build_i;
this->public.task.process = (status_t(*)(task_t*,message_t*))process_i;
}
else
{
this->public.task.build = (status_t(*)(task_t*,message_t*))build_r;
this->public.task.process = (status_t(*)(task_t*,message_t*))process_r;
}
this->ike_sa = ike_sa;
this->new_sa = NULL;
this->ike_init = NULL;
this->initiator = initiator;
return &this->public;
}
+57
View File
@@ -0,0 +1,57 @@
/**
* @file ike_rekey.h
*
* @brief Interface ike_rekey_t.
*
*/
/*
* Copyright (C) 2007 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 <http://www.fsf.org/copyleft/gpl.txt>.
*
* 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 IKE_REKEY_H_
#define IKE_REKEY_H_
typedef struct ike_rekey_t ike_rekey_t;
#include <library.h>
#include <sa/ike_sa.h>
#include <sa/tasks/task.h>
/**
* @brief Task of type IKE_REKEY, rekey an established IKE_SA.
*
* @b Constructors:
* - ike_rekey_create()
*
* @ingroup tasks
*/
struct ike_rekey_t {
/**
* Implements the task_t interface
*/
task_t task;
};
/**
* @brief Create a new IKE_REKEY task.
*
* @param ike_sa IKE_SA this task works for
* @param initiator TRUE for initiator, FALSE for responder
* @return IKE_REKEY task to handle by the task_manager
*/
ike_rekey_t *ike_rekey_create(ike_sa_t *ike_sa, bool initiator);
#endif /* IKE_REKEY_H_ */
+38
View File
@@ -0,0 +1,38 @@
/**
* @file task.c
*
* @brief Enum values for task types
*
*/
/*
* Copyright (C) 2007 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 <http://www.fsf.org/copyleft/gpl.txt>.
*
* 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 "task.h"
ENUM(task_type_names, IKE_INIT, CHILD_REKEY,
"IKE_INIT",
"IKE_NATD",
"IKE_AUTHENTICATE",
"IKE_CERT",
"IKE_CONFIG",
"IKE_DPD",
"IKE_REKEY",
"IKE_DELETE",
"IKE_DEADPEER",
"CHILD_CREATE",
"CHILD_DELETE",
"CHILD_REKEY",
);
+151
View File
@@ -0,0 +1,151 @@
/**
* @file task.h
*
* @brief Interface task_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 <http://www.fsf.org/copyleft/gpl.txt>.
*
* 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 TASK_H_
#define TASK_H_
typedef enum task_type_t task_type_t;
typedef struct task_t task_t;
#include <library.h>
#include <sa/ike_sa.h>
#include <encoding/message.h>
/**
* @brief Different kinds of tasks.
*
* @ingroup tasks
*/
enum task_type_t {
/** establish an unauthenticated IKE_SA */
IKE_INIT,
/** detect NAT situation */
IKE_NATD,
/** authenticate the initiated IKE_SA */
IKE_AUTHENTICATE,
/** exchange certificates and requests */
IKE_CERT,
/** Configuration payloads, virtual IP and such */
IKE_CONFIG,
/** DPD detection */
IKE_DEADPEER,
/** rekey an IKE_SA */
IKE_REKEY,
/** delete an IKE_SA */
IKE_DELETE,
/** liveness check */
IKE_DPD,
/** establish a CHILD_SA within an IKE_SA */
CHILD_CREATE,
/** delete an established CHILD_SA */
CHILD_DELETE,
/** rekey an CHILD_SA */
CHILD_REKEY,
};
/**
* enum names for task_type_t.
*/
extern enum_name_t *task_type_names;
/**
* @brief Interface for a task, an operation handled within exchanges.
*
* A task is an elemantary operation. It may be handled by a single or by
* multiple exchanges. An exchange may even complete multiple tasks.
* A task has a build() and an process() operation. The build() operation
* creates payloads and adds it to the message. The process() operation
* inspects a message and handles its payloads. An initiator of an exchange
* first calls build() to build the request, and processes the response message
* with the process() method.
* A responder does the opposite; it calls process() first to handle an incoming
* request and secondly calls build() to build an appropriate response.
* Both methods return either SUCCESS, NEED_MORE or FAILED. A SUCCESS indicates
* that the task completed, even when the task completed unsuccesfully. The
* manager then removes the task from the list. A NEED_MORE is returned when
* the task needs further build()/process() calls to complete, the manager
* leaves the taks in the queue. A returned FAILED indicates a critical failure.
* The manager closes the IKE_SA whenever a task returns FAILED.
*
* @b Constructors:
* - None, use implementations specific constructors
*
* @ingroup tasks
*/
struct task_t {
/**
* @brief Build a request or response message for this task.
*
* @param this calling object
* @param message message to add payloads to
* @return
* - FAILED if a critical error occured
* - NEED_MORE if another call to build/process needed
* - SUCCESS if task completed
*/
status_t (*build) (task_t *this, message_t *message);
/**
* @brief Process a request or response message for this task.
*
* @param this calling object
* @param message message to read payloads from
* @return
* - FAILED if a critical error occured
* - NEED_MORE if another call to build/process needed
* - SUCCESS if task completed
*/
status_t (*process) (task_t *this, message_t *message);
/**
* @brief Get the type of the task implementation.
*
* @param this calling object
*/
task_type_t (*get_type) (task_t *this);
/**
* @brief Migrate a task to a new IKE_SA.
*
* After migrating a task, it goes back to a state where it can be
* used again to initate an exchange. This is useful when a task
* has to get migrated to a new IKE_SA.
* A special usage is when a INVALID_KE_PAYLOAD is received. A call
* to reset resets the task, but uses another DH group for the next
* try.
* The ike_sa is the new IKE_SA this task belongs to and operates on.
*
* @param this calling object
* @param ike_sa new IKE_SA this task works for
*/
void (*migrate) (task_t *this, ike_sa_t *ike_sa);
/**
* @brief Destroys a task_t object.
*
* @param this calling object
*/
void (*destroy) (task_t *this);
};
#endif /* TASK_H_ */
File diff suppressed because it is too large Load Diff
@@ -1,123 +0,0 @@
/**
* @file create_child_sa.h
*
* @brief Interface of transaction create_child_sa.
*
*/
/*
* 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 <http://www.fsf.org/copyleft/gpl.txt>.
*
* 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 CREATE_CHILD_SA_H_
#define CREATE_CHILD_SA_H_
typedef struct create_child_sa_t create_child_sa_t;
#include <sa/transactions/transaction.h>
#include <sa/ike_sa.h>
#include <sa/child_sa.h>
/**
* @brief A transaction to create a new or rekey an existing CHILD_SA.
*
* If the CHILD_SA is intended to create a new CHILD_SA, set the policy
* with set_policy(). If it is intended to rekey an existing CHILD_SA,
* set the appropriate CHILD_SA with rekeys_child().
*
* Rekeying of an CHILD_SA works the same way as creating a new one,
* but includes an additional REKEY_SA notify and deletes the old
* one (in a separate transaction).
*
* __________ _________
* Cyq \/ Czq
* __________/\_________
* detect __________ _________ detect
* Czp \/ Czp
* compare nonces, won __________/\_________ compare nonces, lost
*
* delete old __________
* Dxq \__________
* __________
* __________/ Dxp
* __________ delete created
* __________/ Dzq
* __________
* Dzp \__________
*
*
* @b Constructors:
* - create_child_sa_create()
* - transaction_create() with the appropriate message
*
* @ingroup transactions
*/
struct create_child_sa_t {
/**
* The transaction_t interface.
*/
transaction_t transaction;
/**
* @brief Set the policy to use for creating a new CHILD_SA.
*
* @param this calling object
* @param policy policy for CHILD_SA
*/
void (*set_policy) (create_child_sa_t* this, policy_t *policy);
/**
* @brief Set the reqid used for CHILD_SA setup.
*
* If we acquire, we must use the same reqid as the
* installed policy.
*
* @param this calling object
* @param reqid reqid to use for the CHILD_SA
*/
void (*set_reqid) (create_child_sa_t* this, u_int32_t reqid);
/**
* @brief Set the CHILD_SA which gets rekeyed by the new one.
*
* @param this calling object
* @param child_sa CHILD_SA to rekey
*/
void (*rekeys_child) (create_child_sa_t* this, child_sa_t *child_sa);
/**
* @brief Cancel the request.
*
* Cancelling the request will set a flag in the transaction. When
* the response for the transaction is received, the created CHILD_SA
* gets deleted afterwards.
*
* @param this calling object
* @param child_sa CHILD_SA to rekey
*/
void (*cancel) (create_child_sa_t* this);
};
/**
* @brief Create a new transaction which creates/rekeys CHILD_SAs.
*
* @param ike_sa assigned IKE_SA
* @return created create_child_sa transaction
*
* @ingroup transactions
*/
create_child_sa_t *create_child_sa_create(ike_sa_t *ike_sa);
#endif /* CREATE_CHILD_SA_H_ */
@@ -1,187 +0,0 @@
/**
* @file dead_peer_detection.c
*
* @brief Implementation of the dead_peer_detection transaction.
*
*/
/*
* 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 <http://www.fsf.org/copyleft/gpl.txt>.
*
* 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 "dead_peer_detection.h"
#include <daemon.h>
typedef struct private_dead_peer_detection_t private_dead_peer_detection_t;
/**
* Private members of a dead_peer_detection_t object..
*/
struct private_dead_peer_detection_t {
/**
* Public methods and transaction_t interface.
*/
dead_peer_detection_t public;
/**
* Assigned IKE_SA.
*/
ike_sa_t *ike_sa;
/**
* Message sent by our peer, if already generated
*/
message_t *message;
/**
* Message ID this transaction uses
*/
u_int32_t message_id;
/**
* Times we did send the request
*/
u_int32_t requested;
};
/**
* Implementation of transaction_t.get_message_id.
*/
static u_int32_t get_message_id(private_dead_peer_detection_t *this)
{
return this->message_id;
}
/**
* Implementation of transaction_t.requested.
*/
static u_int32_t requested(private_dead_peer_detection_t *this)
{
return this->requested++;
}
/**
* Implementation of transaction_t.get_request.
*/
static status_t get_request(private_dead_peer_detection_t *this, message_t **result)
{
message_t *request;
host_t *me, *other;
/* check if we already have built a message (retransmission) */
if (this->message)
{
*result = this->message;
return SUCCESS;
}
me = this->ike_sa->get_my_host(this->ike_sa);
other = this->ike_sa->get_other_host(this->ike_sa);
/* build the request */
request = message_create();
request->set_source(request, me->clone(me));
request->set_destination(request, other->clone(other));
request->set_exchange_type(request, INFORMATIONAL);
request->set_request(request, TRUE);
this->message_id = this->ike_sa->get_next_message_id(this->ike_sa);
request->set_message_id(request, this->message_id);
request->set_ike_sa_id(request, this->ike_sa->get_id(this->ike_sa));
/* apply for caller */
*result = request;
/* store for retransmission */
this->message = request;
return SUCCESS;
}
/**
* Implementation of transaction_t.get_response.
*/
static status_t get_response(private_dead_peer_detection_t *this, message_t *request,
message_t **result, transaction_t **next)
{
host_t *me, *other;
message_t *response;
/* check if we already have built a response (retransmission) */
if (this->message)
{
*result = this->message;
return SUCCESS;
}
me = this->ike_sa->get_my_host(this->ike_sa);
other = this->ike_sa->get_other_host(this->ike_sa);
this->message_id = request->get_message_id(request);
/* set up response */
response = message_create();
response->set_source(response, me->clone(me));
response->set_destination(response, other->clone(other));
response->set_exchange_type(response, INFORMATIONAL);
response->set_request(response, FALSE);
response->set_message_id(response, this->message_id);
response->set_ike_sa_id(response, this->ike_sa->get_id(this->ike_sa));
this->message = response;
*result = response;
return SUCCESS;
}
/**
* Implementation of transaction_t.conclude
*/
static status_t conclude(private_dead_peer_detection_t *this, message_t *response,
transaction_t **transaction)
{
return SUCCESS;
}
/**
* implements transaction_t.destroy
*/
static void destroy(private_dead_peer_detection_t *this)
{
DESTROY_IF(this->message);
free(this);
}
/*
* Described in header.
*/
dead_peer_detection_t *dead_peer_detection_create(ike_sa_t *ike_sa)
{
private_dead_peer_detection_t *this = malloc_thing(private_dead_peer_detection_t);
/* transaction interface functions */
this->public.transaction.get_request = (status_t(*)(transaction_t*,message_t**))get_request;
this->public.transaction.get_response = (status_t(*)(transaction_t*,message_t*,message_t**,transaction_t**))get_response;
this->public.transaction.conclude = (status_t(*)(transaction_t*,message_t*,transaction_t**))conclude;
this->public.transaction.get_message_id = (u_int32_t(*)(transaction_t*))get_message_id;
this->public.transaction.requested = (u_int32_t(*)(transaction_t*))requested;
this->public.transaction.destroy = (void(*)(transaction_t*))destroy;
/* private data */
this->ike_sa = ike_sa;
this->message_id = 0;
this->message = NULL;
this->requested = 0;
return &this->public;
}
@@ -1,58 +0,0 @@
/**
* @file dead_peer_detection.h
*
* @brief Interface of transaction dead_peer_detection.
*
*/
/*
* 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 <http://www.fsf.org/copyleft/gpl.txt>.
*
* 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 DEAD_PEER_DETECTION_H_
#define DEAD_PEER_DETECTION_H_
typedef struct dead_peer_detection_t dead_peer_detection_t;
#include <sa/ike_sa.h>
#include <sa/transactions/transaction.h>
/**
* @brief A transaction used to detect dead peers.
*
* In IKEv2, dead peer detection is done using empty
* informational messages. These must be acknowledged.
*
* @ingroup transactions
*/
struct dead_peer_detection_t {
/**
* The transaction_t interface.
*/
transaction_t transaction;
};
/**
* @brief Create a new transaction which detects dead peers.
*
* @param ike_sa assigned IKE_SA
* @return created dead_peer_detection transaction
*
* @ingroup transactions
*/
dead_peer_detection_t *dead_peer_detection_create(ike_sa_t *ike_sa);
#endif /* DEAD_PEER_DETECTION_H_ */
@@ -1,356 +0,0 @@
/**
* @file delete_child_sa.c
*
* @brief Implementation of the delete_child_sa transaction.
*
*/
/*
* 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 <http://www.fsf.org/copyleft/gpl.txt>.
*
* 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.h"
#include <daemon.h>
#include <encoding/payloads/delete_payload.h>
#include <sa/transactions/create_child_sa.h>
typedef struct private_delete_child_sa_t private_delete_child_sa_t;
/**
* Private members of a delete_child_sa_t object..
*/
struct private_delete_child_sa_t {
/**
* Public methods and transaction_t interface.
*/
delete_child_sa_t public;
/**
* Assigned IKE_SA.
*/
ike_sa_t *ike_sa;
/**
* Message sent by our peer, if already generated
*/
message_t *message;
/**
* Message ID this transaction uses
*/
u_int32_t message_id;
/**
* Times we did send the request
*/
u_int32_t requested;
/**
* CHILD SA to delete
*/
child_sa_t *child_sa;
};
/**
* Implementation of transaction_t.get_message_id.
*/
static u_int32_t get_message_id(private_delete_child_sa_t *this)
{
return this->message_id;
}
/**
* Implementation of transaction_t.requested.
*/
static u_int32_t requested(private_delete_child_sa_t *this)
{
return this->requested++;
}
/**
* Implementation of delete_child_sa_t.set_child_sa.
*/
static void set_child_sa(private_delete_child_sa_t *this, child_sa_t *child_sa)
{
this->child_sa = child_sa;
}
/**
* Implementation of transaction_t.get_request.
*/
static status_t get_request(private_delete_child_sa_t *this, message_t **result)
{
message_t *request;
host_t *me, *other;
/* check if we already have built a message (retransmission) */
if (this->message)
{
*result = this->message;
return SUCCESS;
}
me = this->ike_sa->get_my_host(this->ike_sa);
other = this->ike_sa->get_other_host(this->ike_sa);
/* build the request */
request = message_create();
request->set_source(request, me->clone(me));
request->set_destination(request, other->clone(other));
request->set_exchange_type(request, INFORMATIONAL);
request->set_request(request, TRUE);
this->message_id = this->ike_sa->get_next_message_id(this->ike_sa);
request->set_message_id(request, this->message_id);
request->set_ike_sa_id(request, this->ike_sa->get_id(this->ike_sa));
*result = request;
this->message = request;
{ /* add delete payload */
delete_payload_t *delete_payload;
protocol_id_t protocol;
u_int32_t spi;
protocol = this->child_sa->get_protocol(this->child_sa);
spi = this->child_sa->get_spi(this->child_sa, TRUE);
delete_payload = delete_payload_create(protocol);
DBG1(DBG_IKE, "created DELETE payload for %N CHILD_SA with SPI 0x%x",
protocol_id_names, protocol, htonl(spi));
delete_payload->add_spi(delete_payload, spi);
request->add_payload(request, (payload_t*)delete_payload);
}
this->child_sa->set_state(this->child_sa, CHILD_DELETING);
return SUCCESS;
}
/**
* process a delete payload
*/
static status_t process_delete(private_delete_child_sa_t *this, delete_payload_t *delete_request, message_t *response)
{
protocol_id_t protocol;
u_int32_t spi;
iterator_t *iterator;
delete_payload_t *delete_response = NULL;
/* get requested CHILD */
protocol = delete_request->get_protocol_id(delete_request);
if (protocol != PROTO_ESP && protocol != PROTO_AH)
{
DBG1(DBG_IKE, "CHILD_SA delete response contained unexpected protocol");
return FAILED;
}
/* prepare response payload */
if (response)
{
delete_response = delete_payload_create(protocol);
response->add_payload(response, (payload_t*)delete_response);
}
iterator = delete_request->create_spi_iterator(delete_request);
while (iterator->iterate(iterator, (void**)&spi))
{
child_sa_t *child_sa;
child_sa = this->ike_sa->get_child_sa(this->ike_sa, protocol, spi, FALSE);
if (child_sa != NULL)
{
create_child_sa_t *rekey;
child_sa->set_state(child_sa, CHILD_DELETING);
DBG1(DBG_IKE, "received DELETE for %N CHILD_SA with SPI 0x%x, deleting",
protocol_id_names, protocol, ntohl(spi));
rekey = (create_child_sa_t*)child_sa->get_rekeying_transaction(child_sa);
if (rekey)
{
/* we have received a delete for an SA which we are still rekeying.
* this means we have lost the nonce comparison, and the rekeying
* will fail. We set a flag in the transaction for this special case.
*/
rekey->cancel(rekey);
}
/* delete it, with inbound spi */
spi = child_sa->get_spi(child_sa, TRUE);
this->ike_sa->destroy_child_sa(this->ike_sa, protocol, spi);
/* add delete response to message, if we are responding */
if (response)
{
delete_response->add_spi(delete_response, spi);
}
}
else
{
DBG1(DBG_IKE, "received DELETE for %N CHILD_SA with SPI 0x%x, but no such SA",
protocol_id_names, protocol, ntohl(spi));
}
}
iterator->destroy(iterator);
return SUCCESS;
}
/**
* Implementation of transaction_t.get_response.
*/
static status_t get_response(private_delete_child_sa_t *this, message_t *request,
message_t **result, transaction_t **next)
{
host_t *me, *other;
message_t *response;
iterator_t *payloads;
payload_t *payload;
/* check if we already have built a response (retransmission) */
if (this->message)
{
*result = this->message;
return SUCCESS;
}
me = this->ike_sa->get_my_host(this->ike_sa);
other = this->ike_sa->get_other_host(this->ike_sa);
this->message_id = request->get_message_id(request);
/* set up response */
response = message_create();
response->set_source(response, me->clone(me));
response->set_destination(response, other->clone(other));
response->set_exchange_type(response, INFORMATIONAL);
response->set_request(response, FALSE);
response->set_message_id(response, this->message_id);
response->set_ike_sa_id(response, this->ike_sa->get_id(this->ike_sa));
this->message = response;
*result = response;
if (request->get_exchange_type(request) != INFORMATIONAL)
{
DBG1(DBG_IKE, "INFORMATIONAL response of invalid type, aborting");
return FAILED;
}
/* we can't handle a delete for a CHILD when we are rekeying. There
* is no proper solution for this. We send a empty informational response,
* as described in ikev2-clarifications draft */
if (this->ike_sa->get_state(this->ike_sa) == IKE_REKEYING ||
this->ike_sa->get_state(this->ike_sa) == IKE_DELETING)
{
DBG1(DBG_IKE, "unable to delete CHILD_SA, as rekeying in progress");
return FAILED;
}
/* iterate over all payloads */
payloads = request->get_payload_iterator(request);
while (payloads->iterate(payloads, (void**)&payload))
{
switch (payload->get_type(payload))
{
case DELETE:
{
process_delete(this, (delete_payload_t*)payload, response);
break;
}
default:
{
DBG2(DBG_IKE, "ignoring payload %N",
payload_type_names, payload->get_type(payload));
break;
}
}
}
payloads->destroy(payloads);
return SUCCESS;
}
/**
* Implementation of transaction_t.conclude
*/
static status_t conclude(private_delete_child_sa_t *this, message_t *response,
transaction_t **transaction)
{
iterator_t *payloads;
payload_t *payload;
/* check message type */
if (response->get_exchange_type(response) != INFORMATIONAL)
{
DBG1(DBG_IKE, "INFORMATIONAL response of invalid type, aborting");
return FAILED;
}
/* iterate over all payloads */
payloads = response->get_payload_iterator(response);
while (payloads->iterate(payloads, (void**)&payload))
{
switch (payload->get_type(payload))
{
case DELETE:
{
process_delete(this, (delete_payload_t*)payload, NULL);
break;
}
default:
{
DBG1(DBG_IKE, "ignoring payload %N",
payload_type_names, payload->get_type(payload));
break;
}
}
}
payloads->destroy(payloads);
return SUCCESS;
}
/**
* implements transaction_t.destroy
*/
static void destroy(private_delete_child_sa_t *this)
{
DESTROY_IF(this->message);
free(this);
}
/*
* Described in header.
*/
delete_child_sa_t *delete_child_sa_create(ike_sa_t *ike_sa)
{
private_delete_child_sa_t *this = malloc_thing(private_delete_child_sa_t);
/* transaction interface functions */
this->public.transaction.get_request = (status_t(*)(transaction_t*,message_t**))get_request;
this->public.transaction.get_response = (status_t(*)(transaction_t*,message_t*,message_t**,transaction_t**))get_response;
this->public.transaction.conclude = (status_t(*)(transaction_t*,message_t*,transaction_t**))conclude;
this->public.transaction.get_message_id = (u_int32_t(*)(transaction_t*))get_message_id;
this->public.transaction.requested = (u_int32_t(*)(transaction_t*))requested;
this->public.transaction.destroy = (void(*)(transaction_t*))destroy;
/* publics */
this->public.set_child_sa = (void(*)(delete_child_sa_t*,child_sa_t*))set_child_sa;
/* private data */
this->ike_sa = ike_sa;
this->message_id = 0;
this->message = NULL;
this->requested = 0;
return &this->public;
}
@@ -1,68 +0,0 @@
/**
* @file delete_child_sa.h
*
* @brief Interface of transaction delete_child_sa.
*
*/
/*
* 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 <http://www.fsf.org/copyleft/gpl.txt>.
*
* 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_H_
#define DELETE_CHILD_SA_H_
typedef struct delete_child_sa_t delete_child_sa_t;
#include <sa/ike_sa.h>
#include <sa/transactions/transaction.h>
/**
* @brief A transaction used to delete a CHILD_SA.
*
* @b Constructors:
* - delete_child_sa_create()
* - transaction_create() with the appropriate message
*
* @ingroup transactions
*/
struct delete_child_sa_t {
/**
* The transaction_t interface.
*/
transaction_t transaction;
/**
* @brief Set the CHILD_SA to delete.
*
* @param this calling object
* @param child_sa CHILD_SA to rekey
*/
void (*set_child_sa) (delete_child_sa_t* this, child_sa_t *child_sa);
};
/**
* @brief Create a new transaction which deletes a CHILD_SA.
*
* @param ike_sa assigned IKE_SA
* @return created delete_child_sa transaction
*
* @ingroup transactions
*/
delete_child_sa_t *delete_child_sa_create(ike_sa_t *ike_sa);
#endif /* DELETE_CHILD_SA_H_ */
-284
View File
@@ -1,284 +0,0 @@
/**
* @file delete_ike_sa.c
*
* @brief Implementation of the delete_ike_sa transaction.
*
*/
/*
* 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 <http://www.fsf.org/copyleft/gpl.txt>.
*
* 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_ike_sa.h"
#include <daemon.h>
#include <encoding/payloads/delete_payload.h>
typedef struct private_delete_ike_sa_t private_delete_ike_sa_t;
/**
* Private members of a delete_ike_sa_t object..
*/
struct private_delete_ike_sa_t {
/**
* Public methods and transaction_t interface.
*/
delete_ike_sa_t public;
/**
* Assigned IKE_SA.
*/
ike_sa_t *ike_sa;
/**
* Message sent by our peer, if already generated
*/
message_t *message;
/**
* Message ID this transaction uses
*/
u_int32_t message_id;
/**
* Times we did send the request
*/
u_int32_t requested;
/**
* is the IKE_SA redundant and gets deleted without further notification?
*/
bool redundant;
};
/**
* Implementation of transaction_t.get_message_id.
*/
static u_int32_t get_message_id(private_delete_ike_sa_t *this)
{
return this->message_id;
}
/**
* Implementation of transaction_t.requested.
*/
static u_int32_t requested(private_delete_ike_sa_t *this)
{
return this->requested++;
}
/**
* Implementation of transaction_t.get_request.
*/
static status_t get_request(private_delete_ike_sa_t *this, message_t **result)
{
message_t *request;
host_t *me, *other;
delete_payload_t *delete_payload;
/* check if we already have built a message (retransmission) */
if (this->message)
{
*result = this->message;
return SUCCESS;
}
me = this->ike_sa->get_my_host(this->ike_sa);
other = this->ike_sa->get_other_host(this->ike_sa);
this->redundant = this->ike_sa->get_state(this->ike_sa) == IKE_REKEYING;
if (!this->redundant)
{
SIG(IKE_DOWN_START, "deleting IKE_SA");
}
/* build the request */
request = message_create();
request->set_source(request, me->clone(me));
request->set_destination(request, other->clone(other));
request->set_exchange_type(request, INFORMATIONAL);
request->set_request(request, TRUE);
this->message_id = this->ike_sa->get_next_message_id(this->ike_sa);
request->set_message_id(request, this->message_id);
request->set_ike_sa_id(request, this->ike_sa->get_id(this->ike_sa));
/* apply for caller */
*result = request;
/* store for retransmission */
this->message = request;
delete_payload = delete_payload_create(PROTO_IKE);
request->add_payload(request, (payload_t*)delete_payload);
/* transit to state SA_DELETING */
this->ike_sa->set_state(this->ike_sa, IKE_DELETING);
return SUCCESS;
}
/**
* Implementation of transaction_t.get_response.
*/
static status_t get_response(private_delete_ike_sa_t *this, message_t *request,
message_t **result, transaction_t **next)
{
host_t *me, *other;
message_t *response;
iterator_t *payloads;
payload_t *payload;
delete_payload_t *delete_request = NULL;
/* check if we already have built a response (retransmission)
* this only happens in special simultanous transaction cases,
* as we delete the IKE_SA after the response is sent. */
if (this->message)
{
*result = this->message;
return SUCCESS;
}
me = this->ike_sa->get_my_host(this->ike_sa);
other = this->ike_sa->get_other_host(this->ike_sa);
this->message_id = request->get_message_id(request);
this->redundant = this->ike_sa->get_state(this->ike_sa) == IKE_REKEYING;
if (!this->redundant)
{
SIG(IKE_DOWN_START, "deleting IKE_SA");
}
/* set up response */
response = message_create();
response->set_source(response, me->clone(me));
response->set_destination(response, other->clone(other));
response->set_exchange_type(response, INFORMATIONAL);
response->set_request(response, FALSE);
response->set_message_id(response, this->message_id);
response->set_ike_sa_id(response, this->ike_sa->get_id(this->ike_sa));
this->message = response;
*result = response;
/* check message type */
if (request->get_exchange_type(request) != INFORMATIONAL)
{
if (!this->redundant)
{
SIG(IKE_DOWN_FAILED, "INFORMATIONAL response of invalid type, deleting IKE_SA");
}
return DESTROY_ME;
}
/* iterate over all payloads */
payloads = request->get_payload_iterator(request);
while (payloads->iterate(payloads, (void**)&payload))
{
switch (payload->get_type(payload))
{
case DELETE:
{
delete_request = (delete_payload_t *)payload;
break;
}
default:
{
DBG1(DBG_IKE, "ignoring payload %N",
payload_type_names, payload->get_type(payload));
break;
}
}
}
payloads->destroy(payloads);
if (delete_request &&
delete_request->get_protocol_id(delete_request) == PROTO_IKE)
{
DBG1(DBG_IKE, "DELETE request for IKE_SA received, deleting IKE_SA");
}
else
{
/* should not happen, as we preparsed this at transaction construction */
DBG1(DBG_IKE, "received a weird DELETE request for IKE_SA, deleting anyway");
}
if (this->ike_sa->get_state(this->ike_sa) == IKE_DELETING)
{
/* if we are already deleting an IKE_SA, we do not destroy. We wait
* until we get the response for our initiated delete. */
return SUCCESS;
}
this->ike_sa->set_state(this->ike_sa, IKE_DELETING);
if (!this->redundant)
{
SIG(IKE_DOWN_SUCCESS, "IKE_SA deleted on request");
}
return DESTROY_ME;
}
/**
* Implementation of transaction_t.conclude
*/
static status_t conclude(private_delete_ike_sa_t *this, message_t *response,
transaction_t **transaction)
{
/* check message type */
if (response->get_exchange_type(response) != INFORMATIONAL)
{
if (!this->redundant)
{
SIG(IKE_DOWN_FAILED, "INFORMATIONAL response of invalid type, deleting IKE_SA");
}
return DESTROY_ME;
}
/* this is only an acknowledge. We can't do anything here, but delete
* the IKE_SA. */
if (!this->redundant)
{
SIG(IKE_DOWN_SUCCESS, "IKE_SA deleted");
}
return DESTROY_ME;
}
/**
* implements transaction_t.destroy
*/
static void destroy(private_delete_ike_sa_t *this)
{
DESTROY_IF(this->message);
free(this);
}
/*
* Described in header.
*/
delete_ike_sa_t *delete_ike_sa_create(ike_sa_t *ike_sa)
{
private_delete_ike_sa_t *this = malloc_thing(private_delete_ike_sa_t);
/* transaction interface functions */
this->public.transaction.get_request = (status_t(*)(transaction_t*,message_t**))get_request;
this->public.transaction.get_response = (status_t(*)(transaction_t*,message_t*,message_t**,transaction_t**))get_response;
this->public.transaction.conclude = (status_t(*)(transaction_t*,message_t*,transaction_t**))conclude;
this->public.transaction.get_message_id = (u_int32_t(*)(transaction_t*))get_message_id;
this->public.transaction.requested = (u_int32_t(*)(transaction_t*))requested;
this->public.transaction.destroy = (void(*)(transaction_t*))destroy;
/* private data */
this->ike_sa = ike_sa;
this->message_id = 0;
this->message = NULL;
this->requested = 0;
this->redundant = FALSE;
return &this->public;
}
@@ -1,81 +0,0 @@
/**
* @file delete_ike_sa.h
*
* @brief Interface of transaction delete_ike_sa.
*
*/
/*
* 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 <http://www.fsf.org/copyleft/gpl.txt>.
*
* 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_IKE_SA_H_
#define DELETE_IKE_SA_H_
typedef struct delete_ike_sa_t delete_ike_sa_t;
#include <sa/ike_sa.h>
#include <sa/transactions/transaction.h>
/**
* @brief A transaction used to delete the IKE_SA.
*
* Notation as follows:
* Mx{D} means: Message, with message ID "x", containing a Delete payload
*
* The clarifcation Document says in 5.8, that a IKE_SA delete should not
* be acknowledged with the same delete. This only makes sense for CHILD_SAs,
* as they are paired. IKE_SAs are not, there is only one for both ends.
*
* Normal case:
* ----------------
* Mx{D} -->
* <-- Mx{}
* Delete request is sent, and we wait for the acknowledge.
*
* Special case 1:
* ---------------
* Mx{D} -->
* <-- My{D}
* My{} -->
* <-- Mx{}
* Both initate a delete at the same time. We ack the delete, but wait for
* our delete to be acknowledged.
*
* @b Constructors:
* - delete_ike_sa_create()
* - transaction_create() with the appropriate message
*
* @ingroup transactions
*/
struct delete_ike_sa_t {
/**
* The transaction_t interface.
*/
transaction_t transaction;
};
/**
* @brief Create a new transaction which deletes the IKE_SA.
*
* @param ike_sa assigned IKE_SA
* @return created delete_ike_sa transaction
*
* @ingroup transactions
*/
delete_ike_sa_t *delete_ike_sa_create(ike_sa_t *ike_sa);
#endif /* DELETE_IKE_SA_H_ */
File diff suppressed because it is too large Load Diff
-110
View File
@@ -1,110 +0,0 @@
/**
* @file ike_auth.h
*
* @brief Interface of transaction ike_auth.
*
*/
/*
* 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 <http://www.fsf.org/copyleft/gpl.txt>.
*
* 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 IKE_AUTH_H_
#define IKE_AUTH_H_
typedef struct ike_auth_t ike_auth_t;
#include <sa/ike_sa.h>
#include <sa/transactions/transaction.h>
/**
* @brief A transaction for the second message exchange to authenticate an IKE_SA.
*
* The second transaction is encrypted and authenticates the peers. It also
* sets up a first CHILD_SA.
*
* @b Constructors:
* - ike_auth_create()
* - transaction_create() with the appropriate message
*
* @ingroup transactions
*/
struct ike_auth_t {
/**
* The transaction_t interface.
*/
transaction_t transaction;
/**
* @brief Set the config used for the ike_auth exchange.
*
* The connection definition is used to complete IKE_SA setup, the
* policy defines the CHILD_SA which is created along with the ike_auth
* exchange.
*
* @param this calling object
* @param connection connection definition
* @param policy policy definition
*/
void (*set_config) (ike_auth_t* this,
connection_t *connection, policy_t *policy);
/**
* @brief Set the reqid used for CHILD_SA setup.
*
* The first two message exchanges may set up an associated
* CHILD_SA. If we acquire, we must use the same reqid as the
* installed policy.
*
* @param this calling object
* @param reqid reqid to use for the CHILD_SA
*/
void (*set_reqid) (ike_auth_t* this, u_int32_t reqid);
/**
* @brief Set the nonces used in the previous ike_sa_init transaction.
*
* The nonces are used to create the authentication data.
*
* @param this calling object
* @param nonce_i initiator chosen nonce
* @param nonce_r responder chosen nonce
*/
void (*set_nonces) (ike_auth_t* this, chunk_t nonce_i, chunk_t nonce_r);
/**
* @brief Set the messages used in the previous ike_sa_init transaction.
*
* The messages are used to create the authentication data.
*
* @param this calling object
* @param request encoded request message as a chunk
* @param response encoded response message as a chunk
*/
void (*set_init_messages) (ike_auth_t* this, chunk_t request, chunk_t response);
};
/**
* @brief Create a new transaction which processes IKE_AUTH exchanges.
*
* @param ike_sa assigned IKE_SA
* @return created ike_auth transaction
*
* @ingroup transactions
*/
ike_auth_t *ike_auth_create(ike_sa_t *ike_sa);
#endif /* IKE_AUTH_H_ */
File diff suppressed because it is too large Load Diff
-97
View File
@@ -1,97 +0,0 @@
/**
* @file ike_sa_init.h
*
* @brief Interface of transaction ike_sa_init.
*
*/
/*
* 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 <http://www.fsf.org/copyleft/gpl.txt>.
*
* 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 IKE_SA_INIT_H_
#define IKE_SA_INIT_H_
typedef struct ike_sa_init_t ike_sa_init_t;
#include <sa/ike_sa.h>
#include <sa/transactions/transaction.h>
/**
* @brief A transaction for the first message exchange to set up an IKE_SA.
*
* @b Constructors:
* - ike_sa_init_create()
* - transaction_create() with the appropriate message
*
* @ingroup transactions
*/
struct ike_sa_init_t {
/**
* The transaction_t interface.
*/
transaction_t transaction;
/**
* @brief Set connection & policy to use for initiation.
*
* The policy is not used directly, but forwarded to the
* ike_auth transaction.
*
* @param this calling object
* @param connection connection to use for initiation
* @param policy policy used in ike_auth transaction
*/
void (*set_config) (ike_sa_init_t* this,
connection_t *connection, policy_t *policy);
/**
* @brief Set the reqid used for CHILD_SA setup.
*
* The first two message exchanges may set up an associated
* CHILD_SA. If we acquire, we must use the same reqid as the
* installed policy. This requid is passed to the ike_auth
* transaction which creates the CHILD_AS.
*
* @param this calling object
* @param reqid reqid to use for the CHILD_SA
*/
void (*set_reqid) (ike_sa_init_t* this, u_int32_t reqid);
/**
* @brief Set the Diffie Hellman group to use for initiating.
*
* If a first exchange fails with a INVALID_KE_PAYLOAD, the second
* try uses the DH group proposed by the responder.
*
* @param this calling object
* @param dh_group diffie hellman group to use
* @return FALSE, if DH group not allowed/supported
*/
bool (*use_dh_group) (ike_sa_init_t* this, diffie_hellman_group_t dh_group);
};
/**
* @brief Create a new transaction which processes IKE_SA_INIT exchanges.
*
* @param ike_sa assigned IKE_SA
* @return created ike_sa_init transaction
*
* @ingroup transactions
*/
ike_sa_init_t *ike_sa_init_create(ike_sa_t *ike_sa);
#endif /* IKE_SA_INIT_H_ */
-889
View File
@@ -1,889 +0,0 @@
/**
* @file rekey_ike_sa.c
*
* @brief Implementation of rekey_ike_sa_t transaction.
*
*/
/*
* 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 <http://www.fsf.org/copyleft/gpl.txt>.
*
* 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_ike_sa.h"
#include <string.h>
#include <daemon.h>
#include <encoding/payloads/sa_payload.h>
#include <encoding/payloads/nonce_payload.h>
#include <encoding/payloads/ke_payload.h>
#include <sa/transactions/delete_ike_sa.h>
#include <utils/randomizer.h>
typedef struct private_rekey_ike_sa_t private_rekey_ike_sa_t;
/**
* Private members of a rekey_ike_sa_t object..
*/
struct private_rekey_ike_sa_t {
/**
* Public methods and transaction_t interface.
*/
rekey_ike_sa_t public;
/**
* Assigned IKE_SA.
*/
ike_sa_t *ike_sa;
/**
* Message sent by our peer, if already generated
*/
message_t *message;
/**
* Message ID this transaction uses
*/
u_int32_t message_id;
/**
* Times we did send the request
*/
u_int32_t requested;
/**
* IKE_SA we set up, replaces ike_sa
*/
ike_sa_t *new_sa;
/**
* Connection used to replace IKE_SA
*/
connection_t *connection;
/**
* initiator chosen nonce
*/
chunk_t nonce_i;
/**
* responder chosen nonce
*/
chunk_t nonce_r;
/**
* lower of the nonces of a simultaneus rekeying request
*/
chunk_t nonce_s;
/**
* Diffie hellman to generate new shared secret
*/
diffie_hellman_t *diffie_hellman;
/**
* negotiated proposal to use
*/
proposal_t *proposal;
/**
* Have we lost the simultaneous rekeying nonce compare?
*/
bool lost;
/**
* source of randomness for nonces
*/
randomizer_t *randomizer;
/**
* next transaction processed by the IKE_SA
*/
transaction_t **next;
};
/**
* Implementation of transaction_t.get_message_id.
*/
static u_int32_t get_message_id(private_rekey_ike_sa_t *this)
{
return this->message_id;
}
/**
* Implementation of transaction_t.requested.
*/
static u_int32_t requested(private_rekey_ike_sa_t *this)
{
return this->requested++;
}
/**
* Implementation of rekey_ike_sa_t.use_dh_group.
*/
static void use_dh_group(private_rekey_ike_sa_t *this, diffie_hellman_group_t dh_group)
{
this->diffie_hellman = diffie_hellman_create(dh_group);
}
/**
* Implementation of rekey_ike_sa_t.cancel.
*/
static void cancel(private_rekey_ike_sa_t *this)
{
this->lost = TRUE;
}
/**
* Implementation of transaction_t.get_request.
*/
static status_t get_request(private_rekey_ike_sa_t *this, message_t **result)
{
message_t *request;
host_t *me, *other;
/* check if we already have built a message (retransmission) */
if (this->message)
{
*result = this->message;
return SUCCESS;
}
/* check for correct state, except when retrying with another dh group */
if (this->ike_sa->get_state(this->ike_sa) != IKE_ESTABLISHED &&
!this->diffie_hellman)
{
DBG1(DBG_IKE, "tried to rekey in state %N, aborted",
ike_sa_state_names, this->ike_sa->get_state(this->ike_sa));
return FAILED;
}
me = this->ike_sa->get_my_host(this->ike_sa);
other = this->ike_sa->get_other_host(this->ike_sa);
/* build the request */
request = message_create();
request->set_source(request, me->clone(me));
request->set_destination(request, other->clone(other));
request->set_exchange_type(request, CREATE_CHILD_SA);
request->set_request(request, TRUE);
request->set_ike_sa_id(request, this->ike_sa->get_id(this->ike_sa));
*result = request;
this->message = request;
{ /* build SA payload */
sa_payload_t *sa_payload;
linked_list_t *proposals;
ike_sa_id_t *ike_sa_id;
iterator_t *iterator;
proposal_t *proposal;
u_int64_t spi;
/* get a connection to replace current IKE_SA */
this->connection = charon->connections->get_connection_by_name(
charon->connections,
this->ike_sa->get_name(this->ike_sa));
/* if connection lookup by name fails, try it with the hosts */
if (this->connection == NULL)
{
this->connection = charon->connections->get_connection_by_hosts(
charon->connections,
me, other);
if (this->connection == NULL)
{
DBG1(DBG_IKE, "no connection found to rekey IKE_SA");
return FAILED;
}
}
/* create a new SA */
ike_sa_id = ike_sa_id_create(0, 0, TRUE);
this->new_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
ike_sa_id);
spi = ike_sa_id->get_initiator_spi(ike_sa_id);
ike_sa_id->destroy(ike_sa_id);
proposals = this->connection->get_proposals(this->connection);
iterator = proposals->create_iterator(proposals, TRUE);
while (iterator->iterate(iterator, (void**)&proposal))
{
proposal->set_spi(proposal, spi);
}
iterator->destroy(iterator);
sa_payload = sa_payload_create_from_proposal_list(proposals);
proposals->destroy_offset(proposals, offsetof(proposal_t, destroy));
request->add_payload(request, (payload_t*)sa_payload);
}
{ /* build the NONCE payload for us (initiator) */
nonce_payload_t *nonce_payload;
if (this->randomizer->allocate_pseudo_random_bytes(this->randomizer,
NONCE_SIZE, &this->nonce_i) != SUCCESS)
{
return FAILED;
}
nonce_payload = nonce_payload_create();
nonce_payload->set_nonce(nonce_payload, this->nonce_i);
request->add_payload(request, (payload_t*)nonce_payload);
}
/* if the DH group is set via use_dh_group(), we already have a DH object */
if (!this->diffie_hellman)
{
diffie_hellman_group_t dh_group;
dh_group = this->connection->get_dh_group(this->connection);
this->diffie_hellman = diffie_hellman_create(dh_group);
if (this->diffie_hellman == NULL)
{
DBG1(DBG_IKE, "DH group %N not supported, aborting",
diffie_hellman_group_names, dh_group);
return FAILED;
}
}
{ /* build the KE payload from the DH object */
ke_payload_t *ke_payload;
ke_payload = ke_payload_create_from_diffie_hellman(this->diffie_hellman);
request->add_payload(request, (payload_t*)ke_payload);
}
this->message_id = this->ike_sa->get_next_message_id(this->ike_sa);
request->set_message_id(request, this->message_id);
/* register us as rekeying to detect multiple rekeying */
this->ike_sa->set_state(this->ike_sa, IKE_REKEYING);
this->ike_sa->set_rekeying_transaction(this->ike_sa, &this->public.transaction);
return SUCCESS;
}
/**
* Handle all kind of notifys
*/
static status_t process_notifys(private_rekey_ike_sa_t *this, notify_payload_t *notify_payload)
{
notify_type_t notify_type = notify_payload->get_notify_type(notify_payload);
DBG2(DBG_IKE,"process notify type %N", notify_type_names, notify_type);
switch (notify_type)
{
case NO_PROPOSAL_CHOSEN:
{
DBG1(DBG_IKE, "received a NO_PROPOSAL_CHOSEN notify, IKE_SA rekeying failed");
return FAILED;
}
case INVALID_KE_PAYLOAD:
{
chunk_t notify_data;
diffie_hellman_group_t dh_group, old_dh_group;
rekey_ike_sa_t *retry;
old_dh_group = this->connection->get_dh_group(this->connection);
notify_data = notify_payload->get_notification_data(notify_payload);
dh_group = ntohs(*((u_int16_t*)notify_data.ptr));
DBG1(DBG_IKE, "peer didn't accept DH group %N, it requested %N",
diffie_hellman_group_names, old_dh_group,
diffie_hellman_group_names, dh_group);
if (!this->connection->check_dh_group(this->connection, dh_group))
{
DBG1(DBG_IKE, "requested DH group not acceptable, IKE_SA rekeying failed");
return FAILED;
}
retry = rekey_ike_sa_create(this->ike_sa);
retry->use_dh_group(retry, dh_group);
*this->next = (transaction_t*)retry;
return FAILED;
}
default:
{
if (notify_type < 16383)
{
DBG1(DBG_IKE, "received %N notify error, IKE_SA rekeying failed",
notify_type_names, notify_type);
return FAILED;
}
else
{
DBG1(DBG_IKE, "received %N notify, ignored",
notify_type_names, notify_type);
return SUCCESS;
}
}
}
}
/**
* Switch to the newly created IKE_SA
*/
static status_t switchto_new_sa(private_rekey_ike_sa_t* this, bool initiator)
{
identification_t *my_id, *other_id;
host_t *my_host, *other_host;
char *name;
my_id = this->ike_sa->get_my_id(this->ike_sa);
other_id = this->ike_sa->get_other_id(this->ike_sa);
my_host = this->ike_sa->get_my_host(this->ike_sa);
other_host = this->ike_sa->get_other_host(this->ike_sa);
name = this->ike_sa->get_name(this->ike_sa);
this->new_sa->set_my_id(this->new_sa, my_id->clone(my_id));
this->new_sa->set_other_id(this->new_sa, other_id->clone(other_id));
this->new_sa->set_my_host(this->new_sa, my_host->clone(my_host));
this->new_sa->set_other_host(this->new_sa, other_host->clone(other_host));
this->new_sa->set_name(this->new_sa, name);
if (this->new_sa->derive_keys(this->new_sa, this->proposal,
this->diffie_hellman,
this->nonce_i, this->nonce_r, initiator,
this->ike_sa->get_child_prf(this->ike_sa),
this->ike_sa->get_prf(this->ike_sa)
) != SUCCESS)
{
return FAILED;
}
this->new_sa->apply_connection(this->new_sa, this->connection);
this->new_sa->set_state(this->new_sa, IKE_ESTABLISHED);
this->new_sa->set_lifetimes(this->new_sa,
this->connection->get_reauth(this->connection),
this->connection->get_soft_lifetime(this->connection),
this->connection->get_hard_lifetime(this->connection));
return SUCCESS;
}
/**
* Build a notify message.
*/
static void build_notify(notify_type_t type, chunk_t data, message_t *message, bool flush_message)
{
notify_payload_t *notify;
if (flush_message)
{
payload_t *payload;
iterator_t *iterator = message->get_payload_iterator(message);
while (iterator->iterate(iterator, (void**)&payload))
{
payload->destroy(payload);
iterator->remove(iterator);
}
iterator->destroy(iterator);
}
notify = notify_payload_create();
notify->set_notify_type(notify, type);
notify->set_notification_data(notify, data);
message->add_payload(message, (payload_t*)notify);
}
/**
* Implementation of transaction_t.get_response.
*/
static status_t get_response(private_rekey_ike_sa_t *this, message_t *request,
message_t **result, transaction_t **next)
{
host_t *me, *other;
message_t *response;
status_t status;
iterator_t *payloads, *iterator;
payload_t *payload;
child_sa_t *child_sa;
sa_payload_t *sa_request = NULL;
nonce_payload_t *nonce_request = NULL;
ke_payload_t *ke_request = NULL;
nonce_payload_t *nonce_response;
/* check if we already have built a response (retransmission) */
if (this->message)
{
*result = this->message;
return SUCCESS;
}
me = this->ike_sa->get_my_host(this->ike_sa);
other = this->ike_sa->get_other_host(this->ike_sa);
this->message_id = request->get_message_id(request);
/* set up response */
response = message_create();
response->set_source(response, me->clone(me));
response->set_destination(response, other->clone(other));
response->set_exchange_type(response, CREATE_CHILD_SA);
response->set_request(response, FALSE);
response->set_message_id(response, this->message_id);
response->set_ike_sa_id(response, this->ike_sa->get_id(this->ike_sa));
this->message = response;
*result = response;
/* check message type */
if (request->get_exchange_type(request) != CREATE_CHILD_SA)
{
DBG1(DBG_IKE, "CREATE_CHILD_SA response of invalid type, aborted");
return FAILED;
}
/* if we already initiate a delete, we do not allow rekeying */
if (this->ike_sa->get_state(this->ike_sa) == IKE_DELETING)
{
build_notify(NO_PROPOSAL_CHOSEN, chunk_empty, response, TRUE);
DBG1(DBG_IKE, "unable to rekey, as delete in progress. Sending NO_PROPOSAL_CHOSEN");
return FAILED;
}
/* if we have a CHILD which is "half-open", we do not allow rekeying */
iterator = this->ike_sa->create_child_sa_iterator(this->ike_sa);
while (iterator->iterate(iterator, (void**)&child_sa))
{
child_sa_state_t state = child_sa->get_state(child_sa);
if (state == CHILD_CREATED ||
state == CHILD_REKEYING ||
state == CHILD_DELETING)
{
build_notify(NO_PROPOSAL_CHOSEN, chunk_empty, response, TRUE);
DBG1(DBG_IKE, "unable to rekey, one CHILD_SA is half open. Sending NO_PROPOSAL_CHOSEN");
iterator->destroy(iterator);
return FAILED;
}
}
iterator->destroy(iterator);
/* apply for notify processing */
this->next = next;
/* get a connection to replace current IKE_SA */
this->connection = charon->connections->get_connection_by_name(
charon->connections, this->ike_sa->get_name(this->ike_sa));
/* if connection lookup by name fails, try it with the hosts */
if (this->connection == NULL)
{
this->connection = charon->connections->get_connection_by_hosts(
charon->connections, me, other);
if (this->connection == NULL)
{
DBG1(DBG_IKE, "no connection found to rekey IKE_SA, sending NO_RROPOSAL_CHOSEN");
build_notify(NO_PROPOSAL_CHOSEN, chunk_empty, response, TRUE);
return FAILED;
}
}
/* Iterate over all payloads. */
payloads = request->get_payload_iterator(request);
while (payloads->iterate(payloads, (void**)&payload))
{
switch (payload->get_type(payload))
{
case SECURITY_ASSOCIATION:
sa_request = (sa_payload_t*)payload;
break;
case NONCE:
nonce_request = (nonce_payload_t*)payload;
break;
case KEY_EXCHANGE:
{
ke_request = (ke_payload_t*)payload;
break;
}
case NOTIFY:
{
status = process_notifys(this, (notify_payload_t*)payload);
if (status != SUCCESS)
{
payloads->destroy(payloads);
return status;
}
break;
}
default:
{
DBG1(DBG_IKE, "ignoring %N payload",
payload_type_names, payload->get_type(payload));
break;
}
}
}
payloads->destroy(payloads);
/* check if we have all payloads */
if (!(sa_request && nonce_request && ke_request))
{
build_notify(INVALID_SYNTAX, chunk_empty, response, TRUE);
DBG1(DBG_IKE, "request message incomplete, IKE_SA rekeying failed");
return FAILED;
}
{ /* process nonce payload */
this->nonce_i = nonce_request->get_nonce(nonce_request);
if (this->randomizer->allocate_pseudo_random_bytes(this->randomizer,
NONCE_SIZE, &this->nonce_r) != SUCCESS)
{
build_notify(NO_PROPOSAL_CHOSEN, chunk_empty, response, TRUE);
return FAILED;
}
nonce_response = nonce_payload_create();
nonce_response->set_nonce(nonce_response, this->nonce_r);
}
{ /* process SA payload */
linked_list_t *proposal_list;
sa_payload_t *sa_response;
u_int64_t spi;
ike_sa_id_t *ike_sa_id;
sa_response = sa_payload_create();
/* get proposals from request, and select one with ours */
proposal_list = sa_request->get_proposals(sa_request);
DBG2(DBG_IKE, "selecting proposals:");
this->proposal = this->connection->select_proposal(this->connection, proposal_list);
proposal_list->destroy_offset(proposal_list, offsetof(proposal_t, destroy));
/* do we have a proposal? */
if (this->proposal == NULL)
{
DBG1(DBG_IKE, "no proposals acceptable to rekey IKE_SA, sending NO_PROPOSAL_CHOSEN");
build_notify(NO_PROPOSAL_CHOSEN, chunk_empty, response, TRUE);
return FAILED;
}
/* create IKE_SA with new SPIs */
spi = this->proposal->get_spi(this->proposal);
ike_sa_id = ike_sa_id_create(spi, 0, FALSE);
this->new_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
ike_sa_id);
spi = ike_sa_id->get_responder_spi(ike_sa_id);
ike_sa_id->destroy(ike_sa_id);
this->proposal->set_spi(this->proposal, spi);
sa_response->add_proposal(sa_response, this->proposal);
response->add_payload(response, (payload_t*)sa_response);
/* add nonce after sa payload */
response->add_payload(response, (payload_t *)nonce_response);
}
{ /* process KE payload */
diffie_hellman_group_t used_group;
ke_payload_t *ke_response;
used_group = ke_request->get_dh_group_number(ke_request);
if (!this->connection->check_dh_group(this->connection, used_group) ||
(this->diffie_hellman = diffie_hellman_create(used_group)) == NULL)
{
u_int16_t notify_group;
chunk_t notify_chunk;
notify_group = this->connection->get_dh_group(this->connection);
DBG1(DBG_IKE, "request used inacceptable DH group %N, sending "
"INVALID_KE_PAYLOAD with %N",
diffie_hellman_group_names, used_group,
diffie_hellman_group_names, notify_group);
notify_group = htons(notify_group);
notify_chunk.ptr = (u_int8_t*)&notify_group;
notify_chunk.len = sizeof(notify_group);
build_notify(INVALID_KE_PAYLOAD, notify_chunk, response, TRUE);
return FAILED;
}
this->diffie_hellman->set_other_public_value(this->diffie_hellman,
ke_request->get_key_exchange_data(ke_request));
/* build response */
ke_response = ke_payload_create_from_diffie_hellman(this->diffie_hellman);
response->add_payload(response, (payload_t*)ke_response);
}
status = switchto_new_sa(this, FALSE);
if (status != SUCCESS)
{
return status;
}
/* IKE_SA successfully created. If another transaction is already rekeying
* this SA, our lower nonce must be registered for a later nonce compare. */
{
private_rekey_ike_sa_t *other;
other = (private_rekey_ike_sa_t*)
this->ike_sa->get_rekeying_transaction(this->ike_sa);
if (other)
{
/* store our lower nonce in the simultaneus transaction, we
* will later compare it against his nonces when we calls conclude().
* We do not adopt childrens yet, as we don't know if we'll win
* the race...
*/
if (memcmp(this->nonce_i.ptr, this->nonce_r.ptr,
min(this->nonce_i.len, this->nonce_r.len)) < 0)
{
other->nonce_s = chunk_clone(this->nonce_i);
}
else
{
other->nonce_s = chunk_clone(this->nonce_r);
}
/* overwrite "other" in IKE_SA, allows "other" to access "this" */
this->ike_sa->set_rekeying_transaction(this->ike_sa, &this->public.transaction);
}
else
{
/* if we have no simultaneus transaction, we can safely adopt
* all children and complete. */
this->new_sa->adopt_children(this->new_sa, this->ike_sa);
charon->ike_sa_manager->checkin(charon->ike_sa_manager, this->new_sa);
this->new_sa = NULL;
}
this->ike_sa->set_state(this->ike_sa, IKE_REKEYING);
}
return SUCCESS;
}
/**
* Implementation of transaction_t.conclude
*/
static status_t conclude(private_rekey_ike_sa_t *this, message_t *response,
transaction_t **next)
{
iterator_t *payloads;
payload_t *payload;
host_t *me, *other;
sa_payload_t *sa_payload = NULL;
nonce_payload_t *nonce_payload = NULL;
ke_payload_t *ke_payload = NULL;
private_rekey_ike_sa_t *other_trans;
status_t status;
/* check message type */
if (response->get_exchange_type(response) != CREATE_CHILD_SA)
{
DBG1(DBG_IKE, "CREATE_CHILD_SA response of invalid type, aborting");
return FAILED;
}
me = this->ike_sa->get_my_host(this->ike_sa);
other = this->ike_sa->get_other_host(this->ike_sa);
/* apply for notify processing */
this->next = next;
/* Iterate over all payloads to collect them */
payloads = response->get_payload_iterator(response);
while (payloads->iterate(payloads, (void**)&payload))
{
switch (payload->get_type(payload))
{
case SECURITY_ASSOCIATION:
sa_payload = (sa_payload_t*)payload;
break;
case NONCE:
nonce_payload = (nonce_payload_t*)payload;
break;
case KEY_EXCHANGE:
ke_payload = (ke_payload_t*)payload;
break;
case NOTIFY:
{
status = process_notifys(this, (notify_payload_t*)payload);
if (status != SUCCESS)
{
payloads->destroy(payloads);
return status;
}
break;
}
default:
{
DBG1(DBG_IKE, "ignoring %N payload",
payload_type_names, payload->get_type(payload));
break;
}
}
}
payloads->destroy(payloads);
if (!(sa_payload && nonce_payload && ke_payload))
{
DBG1(DBG_IKE, "response message incomplete, rekeying IKE_SA failed");
return FAILED;
}
{ /* process NONCE payload */
this->nonce_r = nonce_payload->get_nonce(nonce_payload);
}
{ /* process SA payload */
linked_list_t *proposal_list;
ike_sa_id_t *ike_sa_id;
u_int64_t spi;
proposal_list = sa_payload->get_proposals(sa_payload);
/* we have to re-check here if other's selection is valid */
this->proposal = this->connection->select_proposal(this->connection, proposal_list);
proposal_list->destroy_offset(proposal_list, offsetof(proposal_t, destroy));
if (this->proposal == NULL)
{
DBG1(DBG_IKE, "no proposal selected, rekeying IKE_SA failed");
return FAILED;
}
spi = this->proposal->get_spi(this->proposal);
ike_sa_id = this->new_sa->get_id(this->new_sa);
ike_sa_id->set_responder_spi(ike_sa_id, spi);
}
{ /* process KE payload */
this->diffie_hellman->set_other_public_value(this->diffie_hellman,
ke_payload->get_key_exchange_data(ke_payload));
}
if (switchto_new_sa(this, TRUE) != SUCCESS)
{
/* this should not happen. But if, we destroy the new SAs */
this->new_sa->set_state(this->new_sa, IKE_REKEYING);
*next = (transaction_t*)delete_ike_sa_create(this->new_sa);
return FAILED;
}
/* IKE_SA successfully created. If the other peer initiated rekeying
* in the meantime, we detect this by comparing the rekeying_transaction
* of the SA. If it changed, we are not alone. Then we must compare the nonces.
* If no simultaneous rekeying is going on, we just initiate the delete of
* the superseded SA. */
other_trans = (private_rekey_ike_sa_t*)
this->ike_sa->get_rekeying_transaction(this->ike_sa);
this->ike_sa->set_rekeying_transaction(this->ike_sa, NULL);
if (this->nonce_s.ptr)
{ /* simlutaneous rekeying is going on, not so good */
chunk_t this_lowest;
/* first get our lowest nonce */
if (memcmp(this->nonce_i.ptr, this->nonce_r.ptr,
min(this->nonce_i.len, this->nonce_r.len)) < 0)
{
this_lowest = this->nonce_i;
}
else
{
this_lowest = this->nonce_r;
}
/* then compare against other lowest nonce */
if (memcmp(this_lowest.ptr, this->nonce_s.ptr,
min(this_lowest.len, this->nonce_s.len)) < 0)
{
DBG1(DBG_IKE, "detected simultaneous IKE_SA rekeying, deleting ours");
this->lost = TRUE;
}
else
{
DBG1(DBG_IKE, "detected simultaneous IKE_SA rekeying, but ours is preferred");
}
if (this->lost)
{
/* the other has won, he gets our children */
other_trans->new_sa->adopt_children(other_trans->new_sa, this->ike_sa);
/* we have lost simlutaneous rekeying, delete the SA we just have created */
this->new_sa->set_state(this->new_sa, IKE_REKEYING);
*next = (transaction_t*)delete_ike_sa_create(this->new_sa);
}
else
{
other_trans->new_sa->set_state(other_trans->new_sa, IKE_REKEYING);
}
/* other trans' SA is still not checked in, so do it now. It's SA will get
* deleted by remote peer. */
charon->ike_sa_manager->checkin(charon->ike_sa_manager, other_trans->new_sa);
other_trans->new_sa = NULL;
}
if (!this->lost)
{
/* we have won. delete old IKE_SA, and migrate all children */
this->new_sa->adopt_children(this->new_sa, this->ike_sa);
*next = (transaction_t*)delete_ike_sa_create(this->ike_sa);
}
charon->ike_sa_manager->checkin(charon->ike_sa_manager, this->new_sa);
this->new_sa = NULL;
return SUCCESS;
}
/**
* implements transaction_t.destroy
*/
static void destroy(private_rekey_ike_sa_t *this)
{
if (this->new_sa)
{
charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager,
this->new_sa);
}
DESTROY_IF(this->message);
DESTROY_IF(this->connection);
DESTROY_IF(this->diffie_hellman);
DESTROY_IF(this->proposal);
chunk_free(&this->nonce_i);
chunk_free(&this->nonce_r);
chunk_free(&this->nonce_s);
this->randomizer->destroy(this->randomizer);
free(this);
}
/*
* Described in header.
*/
rekey_ike_sa_t *rekey_ike_sa_create(ike_sa_t *ike_sa)
{
private_rekey_ike_sa_t *this = malloc_thing(private_rekey_ike_sa_t);
/* transaction interface functions */
this->public.transaction.get_request = (status_t(*)(transaction_t*,message_t**))get_request;
this->public.transaction.get_response = (status_t(*)(transaction_t*,message_t*,message_t**,transaction_t**))get_response;
this->public.transaction.conclude = (status_t(*)(transaction_t*,message_t*,transaction_t**))conclude;
this->public.transaction.get_message_id = (u_int32_t(*)(transaction_t*))get_message_id;
this->public.transaction.requested = (u_int32_t(*)(transaction_t*))requested;
this->public.transaction.destroy = (void(*)(transaction_t*))destroy;
/* public functions */
this->public.use_dh_group = (void(*)(rekey_ike_sa_t*,diffie_hellman_group_t))use_dh_group;
this->public.cancel = (void(*)(rekey_ike_sa_t*))cancel;
/* private data */
this->ike_sa = ike_sa;
this->message_id = 0;
this->message = NULL;
this->requested = 0;
this->nonce_i = chunk_empty;
this->nonce_r = chunk_empty;
this->nonce_s = chunk_empty;
this->new_sa = NULL;
this->lost = FALSE;
this->connection = NULL;
this->randomizer = randomizer_create();
this->diffie_hellman = NULL;
this->proposal = NULL;
return &this->public;
}
-81
View File
@@ -1,81 +0,0 @@
/**
* @file rekey_ike_sa.h
*
* @brief Interface of transaction rekey_ike_sa.
*
*/
/*
* 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 <http://www.fsf.org/copyleft/gpl.txt>.
*
* 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_IKE_SA_H
#define REKEY_IKE_SA_H
typedef struct rekey_ike_sa_t rekey_ike_sa_t;
#include <sa/ike_sa.h>
#include <sa/transactions/transaction.h>
#include <crypto/diffie_hellman.h>
/**
* @brief A transaction to rekey an established IKE_SA
*
* @b Constructors:
* - rekey_ike_sa_create()
* - transaction_create() with the appropriate message
*
* @ingroup transactions
*/
struct rekey_ike_sa_t {
/**
* The transaction_t interface.
*/
transaction_t transaction;
/**
* @brief Set the Diffie Hellman group to use for initiating.
*
* If a first exchange fails with a INVALID_KE_PAYLOAD, the second
* try uses the DH group proposed by the responder.
*
* @param this calling object
* @param dh_group diffie hellman group to use
*/
void (*use_dh_group) (rekey_ike_sa_t* this, diffie_hellman_group_t dh_group);
/**
* @brief Cancel the request.
*
* Cancelling the request will set a flag in the transaction.
*
* @param this calling object
* @param child_sa CHILD_SA to rekey
*/
void (*cancel) (rekey_ike_sa_t* this);
};
/**
* @brief Create a new transaction to rekey an existing IKE_SA.
*
* @param ike_sa existing IKE_SA
* @return created rekey_ike_sa transaction
*
* @ingroup transactions
*/
rekey_ike_sa_t *rekey_ike_sa_create(ike_sa_t *ike_sa);
#endif /* REKEY_IKE_SA_H */
-167
View File
@@ -1,167 +0,0 @@
/**
* @file transaction.c
*
* @brief Generic contstructor for the different transaction types.
*
*/
/*
* 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 <http://www.fsf.org/copyleft/gpl.txt>.
*
* 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 "transaction.h"
#include <sa/child_sa.h>
#include <sa/transactions/ike_sa_init.h>
#include <sa/transactions/ike_auth.h>
#include <sa/transactions/delete_ike_sa.h>
#include <sa/transactions/create_child_sa.h>
#include <sa/transactions/delete_child_sa.h>
#include <sa/transactions/dead_peer_detection.h>
#include <sa/transactions/rekey_ike_sa.h>
#include <encoding/payloads/ts_payload.h>
#include <encoding/payloads/sa_payload.h>
#include <encoding/payloads/nonce_payload.h>
#include <encoding/payloads/notify_payload.h>
#include <encoding/payloads/delete_payload.h>
/*
* see header file
*/
transaction_t *transaction_create(ike_sa_t *ike_sa, message_t *request)
{
iterator_t *iterator;
payload_t *current;
transaction_t *transaction = NULL;
if (!request->get_request(request))
{
return NULL;
}
switch (request->get_exchange_type(request))
{
case IKE_SA_INIT:
{
if (ike_sa->get_state(ike_sa) == IKE_CREATED)
{
transaction = (transaction_t*)ike_sa_init_create(ike_sa);
}
break;
}
case IKE_AUTH:
{
/* IKE_AUTH is always created in IKE_SA_INIT, it never should
* appear alone */
break;
}
case CREATE_CHILD_SA:
{
if (ike_sa->get_state(ike_sa) < IKE_ESTABLISHED)
{
break;
}
/* check protocol of SA payload */
iterator = request->get_payload_iterator(request);
while (iterator->iterate(iterator, (void**)&current))
{
if (current->get_type(current) == SECURITY_ASSOCIATION)
{
iterator_t *prop_iter;
proposal_substructure_t *prop_struct;
sa_payload_t *sa_payload = (sa_payload_t*)current;
prop_iter = sa_payload->create_proposal_substructure_iterator(sa_payload, TRUE);
if (prop_iter->iterate(prop_iter, (void**)&prop_struct))
{
switch (prop_struct->get_protocol_id(prop_struct))
{
case PROTO_IKE:
transaction = (transaction_t*)
rekey_ike_sa_create(ike_sa);
break;
case PROTO_AH:
case PROTO_ESP:
transaction = (transaction_t*)
create_child_sa_create(ike_sa);
break;
default:
break;
}
}
prop_iter->destroy(prop_iter);
}
if (transaction)
{
break;
}
}
iterator->destroy(iterator);
break;
}
case INFORMATIONAL:
{
if (ike_sa->get_state(ike_sa) < IKE_ESTABLISHED)
{
break;
}
u_int payload_count = 0;
iterator = request->get_payload_iterator(request);
while (iterator->iterate(iterator, (void**)&current))
{
payload_count++;
switch (current->get_type(current))
{
case DELETE:
{
delete_payload_t *delete_payload = (delete_payload_t*)current;
switch (delete_payload->get_protocol_id(delete_payload))
{
case PROTO_IKE:
transaction = (transaction_t*)
delete_ike_sa_create(ike_sa);
break;
case PROTO_AH:
case PROTO_ESP:
transaction = (transaction_t*)
delete_child_sa_create(ike_sa);
break;
default:
break;
}
break;
}
default:
break;
}
if (transaction)
{
break;
}
}
iterator->destroy(iterator);
/* empty informationals are used for dead peer detection in
* IKEv2. We use a special transaction for it. */
if (payload_count == 0)
{
transaction = (transaction_t*)
dead_peer_detection_create(ike_sa);
}
break;
}
default:
break;
}
return transaction;
}
-180
View File
@@ -1,180 +0,0 @@
/**
* @file transaction.h
*
* @brief Interface transaction_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 <http://www.fsf.org/copyleft/gpl.txt>.
*
* 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 TRANSACTION_H_
#define TRANSACTION_H_
typedef struct transaction_t transaction_t;
#include <library.h>
#include <encoding/message.h>
#include <sa/ike_sa.h>
/**
* @brief This interface represents a transaction an established IKE_SA can do.
*
* To every transaction, a message ID is associated. IKEv2 uses strict message
* IDs, which are equal for a request/response pair in a transaction.
* An initiator of a transaction does the following:
* - create the transaction using a specific constructor
* - call request() to get the message for initiaton
* - call conclude() to process received reply
* The other peer does the following:
* - create a transanction using the generic transaction constructor
* - call respond() to get a reply to send
*
* The responder must not destroy the transaction, until the
* initiator initiates another transaction (or a number of transactions
* > window size). This allows us to redo a transaction in case of a
* message loss. The initiator can destroy the the transaction once
* the conclude() function is called.
*
* @b Constructors:
* - transaction_create()
* - ike_sa_init_create()
* - ike_auth_create()
*
* @ingroup transactions
*/
struct transaction_t {
/**
* @brief Get the request to use for initiating the transaction.
*
* A transaction creates a request only once. The request is stored
* internally and may be queried multiple times for retransmission.
* The transaction is not responsible for generating/encrypting the
* message, this is the job of the caller. But it MAY be already
* generated when calling get_request() the second time.
*
* @param this calling object
* @param[out] request resultin request
* @return
* - FAILED if transaction failed
* - DESTROY_ME if transaction failed and IKE SA
* must be deleted
* - SUCCESS
*/
status_t (*get_request) (transaction_t *this, message_t **request);
/**
* @brief Build the response for a received request.
*
* A transaction creates a response only once for a unique request.
* This allows the use of get_response multiple times for retransmission
* purposes.
* The transaction is not responsible for generating/encrypting the
* response, nor is it responsible for decrypting/parsing the request.
* This is the job of the caller. But the response MAY be already
* generated when calling get_request() the second time.
* The initiator waits for a response, so we send one in every case. This
* means response points always to a valid message. This message
* may not be modified or destroyed, it gets destroyed along with the
* transaction.
* The get_response() function may return a next transaction. This allows
* passing of informations from one transaction to a next one.
*
* @param this calling object
* @param request received request
* @param[out] response resulting response
* @param[out] next transaction expected as next, or NULL
* @return
* - FAILED if transaction failed
* - DESTROY_ME if transaction failed and IKE SA
* must be deleted
* - SUCCESS
*/
status_t (*get_response) (transaction_t *this, message_t *request,
message_t **response, transaction_t **next);
/**
* @brief Conclude an initiated transaction with a received response.
*
* The response must be decrypted and parsed. The conclude function
* may return a new transaction. This transaction has to be executed
* next to complete a multi-exchange scenario. It allows a clean
* transaction mechanism, as the transaction knows best whats to do
* after it completes. It must only be executed if conclude returns
* SUCCESS.
*
* @param this calling object
* @param response received response
* @param[out] next transaction to execute as next, or NULL
* @return
* - FAILED if transaction failed
* - DESTROY_ME if transaction failed and IKE SA
* must be deleted
* - SUCCESS
*/
status_t (*conclude) (transaction_t *this, message_t *response,
transaction_t **next);
/**
* @brief Get the message ID associated with this transaction.
*
* Every transaction consists of a message pair with the same
* message ID. This ID can be queried with get_message_id().
*
* @param this calling object
* @return message id
*/
u_int32_t (*get_message_id) (transaction_t *this);
/**
* @brief Times we already sent the request (retransmitted).
*
* The transaction stores an internal counter to see how
* many times we sent the request. This counter is incremented
* each time after a call to requested().
*
* @param this calling object
* @return message id
*/
u_int32_t (*requested) (transaction_t *this);
/**
* @brief Destroys a transaction_t object.
*
* @param this calling object
*/
void (*destroy) (transaction_t *this);
};
/**
* @brief Create a transaction instance based on a received request.
*
* Incoming requests are handled by a transaction. But as we don't
* know what kind of transaction we use for a specific request, we use
* a generic constructor. This constructor decides which instance will
* handle the transaction, and creates it.
*
* @param ike_sa ike_sa associated with this transaction
* @param request received request
* @return
* - created transaction, or
* - NULL no transaction needed
*
* @ingroup transactions
*/
transaction_t *transaction_create(ike_sa_t *ike_sa, message_t* request);
#endif /* TRANSACTION_H_ */
File diff suppressed because it is too large Load Diff
+34
View File
@@ -263,6 +263,40 @@ struct kernel_interface_t {
traffic_selector_t *dst_ts,
policy_dir_t direction);
/**
* @brief Add a virtual IP to an interface.
*
* Virtual IPs are attached to an interface. If an IP is added multiple
* times, the IP is refcounted and not removed until del_ip() was called
* as many times as add_ip().
* The virtual IP is attached to the interface used to reach a specified
* destination host.
*
* @param this calling object
* @param virtual_ip virtual ip address to assign
* @param dst_ip destination host to select outgoing interface
* @return
* - SUCCESS
* - FAILED if kernel comm failed
*/
status_t (*add_ip) (kernel_interface_t *this, host_t *virtual_ip,
host_t *dst_ip);
/**
* @brief Remove a virtual IP from an interface.
*
* The kernel interface uses refcounting, see add_ip().
*
* @param this calling object
* @param virtual_ip virtual ip address to assign
* @param dst_ip destination host to select outgoing interface
* @return
* - SUCCESS
* - FAILED if kernel comm failed
*/
status_t (*del_ip) (kernel_interface_t *this, host_t *virtual_ip,
host_t *dst_ip);
/**
* @brief Destroys a kernel_interface object.
*
+107 -15
View File
@@ -197,6 +197,7 @@ static void stroke_add_conn(stroke_msg_t *msg, FILE *out)
bool my_ca_same = FALSE;
bool other_ca_same =FALSE;
host_t *my_host, *other_host, *my_subnet, *other_subnet;
host_t *my_vip = NULL, *other_vip = NULL;
proposal_t *proposal;
traffic_selector_t *my_ts, *other_ts;
@@ -205,6 +206,8 @@ static void stroke_add_conn(stroke_msg_t *msg, FILE *out)
pop_string(msg, &msg->add_conn.other.address);
pop_string(msg, &msg->add_conn.me.subnet);
pop_string(msg, &msg->add_conn.other.subnet);
pop_string(msg, &msg->add_conn.me.sourceip);
pop_string(msg, &msg->add_conn.other.sourceip);
pop_string(msg, &msg->add_conn.me.id);
pop_string(msg, &msg->add_conn.other.id);
pop_string(msg, &msg->add_conn.me.cert);
@@ -223,6 +226,8 @@ static void stroke_add_conn(stroke_msg_t *msg, FILE *out)
DBG2(DBG_CFG, " right=%s", msg->add_conn.other.address);
DBG2(DBG_CFG, " leftsubnet=%s", msg->add_conn.me.subnet);
DBG2(DBG_CFG, " rightsubnet=%s", msg->add_conn.other.subnet);
DBG2(DBG_CFG, " leftsourceip=%s", msg->add_conn.me.sourceip);
DBG2(DBG_CFG, " rightsourceip=%s", msg->add_conn.other.sourceip);
DBG2(DBG_CFG, " leftid=%s", msg->add_conn.me.id);
DBG2(DBG_CFG, " rightid=%s", msg->add_conn.other.id);
DBG2(DBG_CFG, " leftcert=%s", msg->add_conn.me.cert);
@@ -303,7 +308,13 @@ static void stroke_add_conn(stroke_msg_t *msg, FILE *out)
my_subnet->destroy(my_subnet);
goto destroy_ids;
}
if (msg->add_conn.me.virtual_ip)
{
my_vip = host_create_from_string(msg->add_conn.me.sourceip, 0);
}
other_vip = host_create_from_string(msg->add_conn.other.sourceip, 0);
my_ts = traffic_selector_create_from_subnet(my_subnet,
msg->add_conn.me.subnet ? msg->add_conn.me.subnet_mask : 0,
msg->add_conn.me.protocol, msg->add_conn.me.port);
@@ -429,7 +440,7 @@ static void stroke_add_conn(stroke_msg_t *msg, FILE *out)
connection->add_proposal(connection, proposal);
}
policy = policy_create(msg->add_conn.name, my_id, other_id,
policy = policy_create(msg->add_conn.name, my_id, other_id, my_vip, other_vip,
msg->add_conn.auth_method, msg->add_conn.eap_type,
msg->add_conn.rekey.ipsec_lifetime,
msg->add_conn.rekey.ipsec_lifetime - msg->add_conn.rekey.margin,
@@ -559,16 +570,7 @@ static void stroke_initiate(stroke_msg_t *msg, FILE *out)
return;
}
job = initiate_job_create(connection, NULL, policy);
/*
if (msg->output_verbosity < 0)
{
TODO: detach immediately if verbosity is SILENT. Local credential store
is not threadsave yet, so this would cause crashes!!
charon->job_queue->add(charon->job_queue, (job_t*)job);
return;
}*/
job = initiate_job_create(connection, policy);
charon->bus->set_listen_state(charon->bus, TRUE);
charon->job_queue->add(charon->job_queue, (job_t*)job);
while (TRUE)
@@ -664,10 +666,100 @@ static void stroke_route(stroke_msg_t *msg, FILE *out, bool route)
*/
static void stroke_terminate(stroke_msg_t *msg, FILE *out)
{
pop_string(msg, &(msg->terminate.name));
DBG1(DBG_CFG, "received stroke: terminate '%s'", msg->terminate.name);
char *string, *pos = NULL, *name = NULL;
u_int32_t id = 0;
bool child;
int len;
status_t status = SUCCESS;;
ike_sa_t *ike_sa;
charon->ike_sa_manager->delete_by_name(charon->ike_sa_manager, msg->terminate.name);
pop_string(msg, &(msg->terminate.name));
string = msg->terminate.name;
DBG1(DBG_CFG, "received stroke: terminate '%s'", string);
len = strlen(string);
if (len < 1)
{
DBG1(DBG_CFG, "error parsing string");
return;
}
switch (string[len-1])
{
case '}':
child = TRUE;
pos = strchr(string, '{');
break;
case ']':
child = FALSE;
pos = strchr(string, '[');
break;
default:
name = string;
child = FALSE;
break;
}
if (name)
{ /* must be a single name */
DBG1(DBG_CFG, "check out by single name '%s'", name);
ike_sa = charon->ike_sa_manager->checkout_by_name(charon->ike_sa_manager,
name, child);
}
else if (pos == string + len - 2)
{ /* must be name[] or name{} */
string[len-2] = '\0';
DBG1(DBG_CFG, "check out by name '%s'", string);
ike_sa = charon->ike_sa_manager->checkout_by_name(charon->ike_sa_manager,
string, child);
}
else
{ /* must be name[123] or name{23} */
string[len-1] = '\0';
id = atoi(pos + 1);
if (id == 0)
{
DBG1(DBG_CFG, "error parsing string");
return;
}
DBG1(DBG_CFG, "check out by id '%d'", id);
ike_sa = charon->ike_sa_manager->checkout_by_id(charon->ike_sa_manager,
id, child);
}
if (ike_sa == NULL)
{
DBG1(DBG_CFG, "no such IKE_SA found");
return;
}
if (!child)
{
status = ike_sa->delete(ike_sa);
}
else
{
child_sa_t *child_sa;
iterator_t *iterator = ike_sa->create_child_sa_iterator(ike_sa);
while (iterator->iterate(iterator, (void**)&child_sa))
{
if ((id && id == child_sa->get_reqid(child_sa)) ||
(string && streq(string, child_sa->get_name(child_sa))))
{
u_int32_t spi = child_sa->get_spi(child_sa, TRUE);
protocol_id_t proto = child_sa->get_protocol(child_sa);
status = ike_sa->delete_child_sa(ike_sa, proto, spi);
break;
}
}
iterator->destroy(iterator);
}
if (status == DESTROY_ME)
{
charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager,
ike_sa);
return;
}
charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
}
/**
+31 -2
View File
@@ -6,7 +6,8 @@
*/
/*
* Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger
* Copyright (C) 2006-2007 Tobias Brunner
* Copyright (C) 2006 Daniel Roethlisberger
* Copyright (C) 2005-2006 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
@@ -45,7 +46,7 @@ struct private_host_t {
union {
/** generic type */
struct sockaddr address;
/** maximux sockaddr size */
/** maximum sockaddr size */
struct sockaddr_storage address_max;
/** IPv4 address */
struct sockaddr_in address4;
@@ -495,3 +496,31 @@ host_t *host_create_from_sockaddr(sockaddr_t *sockaddr)
free(this);
return NULL;
}
/*
* Described in header.
*/
host_t *host_create_any(int family)
{
private_host_t *this = host_create_empty();
memset(&this->address_max, 0, sizeof(struct sockaddr_storage));
this->address.sa_family = family;
switch (family)
{
case AF_INET:
{
this->socklen = sizeof(struct sockaddr_in);
return &(this->public);
}
case AF_INET6:
{
this->socklen = sizeof(struct sockaddr_in6);
return &this->public;
}
default:
break;
}
return NULL;
}
+14 -1
View File
@@ -6,7 +6,8 @@
*/
/*
* Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger
* Copyright (C) 2006-2007 Tobias Brunner
* Copyright (C) 2006 Daniel Roethlisberger
* Copyright (C) 2005-2006 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
@@ -216,4 +217,16 @@ host_t *host_create_from_chunk(int family, chunk_t address, u_int16_t port);
*/
host_t *host_create_from_sockaddr(sockaddr_t *sockaddr);
/**
* @brief Create a host without an address, a "any" host.
*
* @param family family of the any host
* @return
* - host_t object
* - NULL, if family not supported.
*
* @ingroup network
*/
host_t *host_create_any(int family);
#endif /*HOST_H_*/
+40 -10
View File
@@ -497,7 +497,10 @@ bool match_dn(chunk_t a, chunk_t b, int *wildcards)
bool next_a, next_b;
/* initialize wildcard counter */
*wildcards = 0;
if (wildcards)
{
*wildcards = 0;
}
/* initialize DN parsing */
if (init_rdn(a, &rdn_a, &attribute_a, &next_a) != SUCCESS
@@ -522,7 +525,10 @@ bool match_dn(chunk_t a, chunk_t b, int *wildcards)
/* does rdn_b contain a wildcard? */
if (value_b.len == 1 && *value_b.ptr == '*')
{
(*wildcards)++;
if (wildcards)
{
(*wildcards)++;
}
continue;
}
/* same lengths for values */
@@ -549,7 +555,10 @@ bool match_dn(chunk_t a, chunk_t b, int *wildcards)
}
/* the two DNs match! */
*wildcards = min(*wildcards, MAX_WILDCARDS);
if (wildcards)
{
*wildcards = min(*wildcards, MAX_WILDCARDS);
}
return TRUE;
}
@@ -750,10 +759,16 @@ static bool matches_binary(private_identification_t *this,
{
if (other->type == ID_ANY)
{
*wildcards = MAX_WILDCARDS;
if (wildcards)
{
*wildcards = MAX_WILDCARDS;
}
return TRUE;
}
*wildcards = 0;
if (wildcards)
{
*wildcards = 0;
}
return this->type == other->type &&
chunk_equals(this->encoded, other->encoded);
}
@@ -769,7 +784,10 @@ static bool matches_string(private_identification_t *this,
if (other->type == ID_ANY)
{
*wildcards = MAX_WILDCARDS;
if (wildcards)
{
*wildcards = MAX_WILDCARDS;
}
return TRUE;
}
@@ -779,7 +797,10 @@ static bool matches_string(private_identification_t *this,
/* try a binary comparison first */
if (equals_binary(this, other))
{
*wildcards = 0;
if (wildcards)
{
*wildcards = 0;
}
return TRUE;
}
@@ -789,7 +810,10 @@ static bool matches_string(private_identification_t *this,
/* check for single wildcard at the head of the string */
if (*other->encoded.ptr == '*')
{
*wildcards = 1;
if (wildcards)
{
*wildcards = 1;
}
/* single asterisk matches any string */
if (len-- == 1)
@@ -809,7 +833,10 @@ static bool matches_string(private_identification_t *this,
static bool matches_any(private_identification_t *this,
private_identification_t *other, int *wildcards)
{
*wildcards = 0;
if (wildcards)
{
*wildcards = 0;
}
return other->type == ID_ANY;
}
@@ -822,7 +849,10 @@ static bool matches_dn(private_identification_t *this,
{
if (other->type == ID_ANY)
{
*wildcards = MAX_WILDCARDS;
if (wildcards)
{
*wildcards = MAX_WILDCARDS;
}
return TRUE;
}
+1 -1
View File
@@ -182,7 +182,7 @@ struct identification_t {
*
* @param this the ID without wildcard
* @param other the ID containing a wildcard
* @param wildcards returns the number of wildcards
* @param wildcards returns the number of wildcards, may be NULL
* @return TRUE if match is found
*/
bool (*matches) (identification_t *this, identification_t *other, int *wildcards);
+16 -1
View File
@@ -24,6 +24,19 @@
#ifndef ITERATOR_H_
#define ITERATOR_H_
#include <library.h>
/**
* @brief Iterator hook function prototype.
*
* @param param user supplied parameter
* @param in the value the hook receives from the iterator
* @param out the value supplied as a result to the iterator
* @return TRUE to return "out", FALSE to skip this value
*/
typedef bool (iterator_hook_t)(void *param, void *in, void **out);
typedef struct iterator_t iterator_t;
/**
@@ -76,8 +89,10 @@ struct iterator_t {
*
* @param this calling object
* @param hook iterator hook which manipulates the iterated value
* @param param user supplied parameter to pass back to the hook
*/
void (*set_iterator_hook) (iterator_t *this, void*(*hook)(void*));
void (*set_iterator_hook) (iterator_t *this, iterator_hook_t *hook,
void *param);
/**
* @brief Inserts a new item before the given iterator position.
+32 -11
View File
@@ -132,7 +132,12 @@ struct private_iterator_t {
/**
* iteration hook
*/
void* (*hook)(void*);
iterator_hook_t *hook;
/**
* user parameter for iterator hook
*/
void *hook_param;
};
/**
@@ -146,23 +151,27 @@ static int get_list_count(private_iterator_t *this)
/**
* default iterator hook which does nothing
*/
static void *iterator_hook(void *value)
static bool iterator_hook(void *param, void *in, void **out)
{
return value;
*out = in;
return TRUE;
}
/**
* Implementation of iterator_t.set_iterator_hook.
*/
static void set_iterator_hook(private_iterator_t *this, void*(*hook)(void*))
static void set_iterator_hook(private_iterator_t *this, iterator_hook_t *hook,
void* param)
{
if (hook == NULL)
{
this->hook = iterator_hook;
this->hook_param = NULL;
}
else
{
this->hook = hook;
this->hook_param = param;
}
}
@@ -178,7 +187,10 @@ static bool iterate(private_iterator_t *this, void** value)
if (this->current == NULL)
{
this->current = (this->forward) ? this->list->first : this->list->last;
*value = this->hook(this->current->value);
if (!this->hook(this->hook_param, this->current->value, value))
{
return iterate(this, value);
}
return TRUE;
}
if (this->forward)
@@ -188,16 +200,21 @@ static bool iterate(private_iterator_t *this, void** value)
return FALSE;
}
this->current = this->current->next;
*value = this->hook(this->current->value);
if (!this->hook(this->hook_param, this->current->value, value))
{
return iterate(this, value);
}
return TRUE;
}
/* backward */
if (this->current->previous == NULL)
{
return FALSE;
}
this->current = this->current->previous;
*value = this->hook(this->current->value);
if (!this->hook(this->hook_param, this->current->value, value))
{
return iterate(this, value);
}
return TRUE;
}
@@ -225,11 +242,15 @@ static status_t remove_(private_iterator_t *this)
{
return NOT_FOUND;
}
/* find out the new iterator position */
if (this->current->previous != NULL)
/* find out the new iterator position, depending on iterator direction */
if (this->forward && this->current->previous != NULL)
{
new_current = this->current->previous;
}
else if (!this->forward && this->current->next != NULL)
{
new_current = this->current->next;
}
else
{
new_current = NULL;
@@ -679,7 +700,7 @@ static iterator_t *create_iterator(private_linked_list_t *linked_list, bool forw
this->public.get_count = (int (*) (iterator_t*)) get_list_count;
this->public.iterate = (bool (*) (iterator_t*, void **value)) iterate;
this->public.set_iterator_hook = (void(*)(iterator_t*, void*(*)(void*)))set_iterator_hook;
this->public.set_iterator_hook = (void(*)(iterator_t*, iterator_hook_t*, void*))set_iterator_hook;
this->public.insert_before = (void (*) (iterator_t*, void *item)) insert_before;
this->public.insert_after = (void (*) (iterator_t*, void *item)) insert_after;
this->public.replace = (status_t (*) (iterator_t*, void **, void *)) replace;
+2 -1
View File
@@ -252,7 +252,8 @@ kw_end(starter_conn_t *conn, starter_end_t *end, kw_token_t token
plog("# natip and sourceip cannot be defined at the same time");
goto err;
}
if (streq(value, "%modeconfig") || streq(value, "%modecfg"))
if (streq(value, "%modeconfig") || streq(value, "%modecfg") ||
streq(value, "%config") || streq(value, "%cfg"))
{
end->modecfg = TRUE;
}
+3
View File
@@ -166,6 +166,9 @@ static void starter_stroke_add_end(stroke_msg_t *msg, stroke_end_t *msg_end, sta
msg_end->hostaccess = conn_end->hostaccess;
msg_end->protocol = conn_end->protocol;
msg_end->port = conn_end->port;
msg_end->virtual_ip = conn_end->modecfg;
ip_address2string(&conn_end->srcip, buffer, sizeof(buffer));
msg_end->sourceip = push_string(msg, buffer);
}
int starter_stroke_add_conn(starter_conn_t *conn)
+4
View File
@@ -127,6 +127,8 @@ static int add_connection(char *name,
msg.add_conn.me.address = push_string(&msg, my_addr);
msg.add_conn.me.subnet = push_string(&msg, my_net);
msg.add_conn.me.subnet_mask = my_netmask;
msg.add_conn.me.sourceip = NULL;
msg.add_conn.me.virtual_ip = 0;
msg.add_conn.me.cert = NULL;
msg.add_conn.me.ca = NULL;
msg.add_conn.me.sendcert = 1;
@@ -138,6 +140,8 @@ static int add_connection(char *name,
msg.add_conn.other.address = push_string(&msg, other_addr);
msg.add_conn.other.subnet = push_string(&msg, other_net);
msg.add_conn.other.subnet_mask = other_netmask;
msg.add_conn.other.sourceip = NULL;
msg.add_conn.other.virtual_ip = 0;
msg.add_conn.other.cert = NULL;
msg.add_conn.other.ca = NULL;
msg.add_conn.other.sendcert = 1;
+2
View File
@@ -100,6 +100,8 @@ struct stroke_end_t {
char *ca;
char *updown;
char *address;
char *sourceip;
u_int8_t virtual_ip;
char *subnet;
int subnet_mask;
int sendcert;