merged tasking branch into trunk
This commit is contained in:
@@ -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
@@ -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 \
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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: */
|
||||
|
||||
|
||||
@@ -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: */
|
||||
|
||||
|
||||
@@ -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**)¤t))
|
||||
{
|
||||
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;
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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_*/
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
|
||||
ENUM(job_type_names, INCOMING_PACKET, SEND_DPD,
|
||||
"INCOMING_PACKET",
|
||||
"RETRANSMIT_REQUEST",
|
||||
"RETRANSMIT",
|
||||
"INITIATE",
|
||||
"ROUTE",
|
||||
"ACQUIRE",
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
+29
-30
@@ -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;
|
||||
}
|
||||
+15
-15
@@ -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_ */
|
||||
@@ -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
@@ -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
@@ -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
File diff suppressed because it is too large
Load Diff
+126
-103
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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_ */
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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_ */
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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_ */
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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_ */
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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_ */
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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_ */
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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_ */
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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_ */
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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_ */
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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_ */
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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_ */
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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_ */
|
||||
@@ -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",
|
||||
);
|
||||
@@ -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_ */
|
||||
@@ -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
@@ -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
@@ -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_ */
|
||||
@@ -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*)¬ify_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;
|
||||
}
|
||||
@@ -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 */
|
||||
@@ -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**)¤t))
|
||||
{
|
||||
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**)¤t))
|
||||
{
|
||||
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;
|
||||
}
|
||||
@@ -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
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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_*/
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user