aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/charon/Makefile.am2
-rw-r--r--src/charon/config/traffic_selector.c24
-rw-r--r--src/charon/config/traffic_selector.h9
-rw-r--r--src/charon/queues/jobs/acquire_job.c104
-rw-r--r--src/charon/queues/jobs/acquire_job.h61
-rw-r--r--src/charon/queues/jobs/delete_child_sa_job.c18
-rw-r--r--src/charon/queues/jobs/delete_child_sa_job.h7
-rw-r--r--src/charon/queues/jobs/job.h14
-rw-r--r--src/charon/queues/jobs/rekey_child_sa_job.c18
-rw-r--r--src/charon/queues/jobs/rekey_child_sa_job.h3
-rw-r--r--src/charon/queues/jobs/route_job.c133
-rw-r--r--src/charon/queues/jobs/route_job.h60
-rw-r--r--src/charon/sa/child_sa.c117
-rw-r--r--src/charon/sa/child_sa.h5
-rw-r--r--src/charon/sa/ike_sa.c348
-rw-r--r--src/charon/sa/ike_sa.h30
-rw-r--r--src/charon/sa/ike_sa_manager.c16
-rw-r--r--src/charon/sa/ike_sa_manager.h11
-rw-r--r--src/charon/threads/kernel_interface.c60
-rwxr-xr-xsrc/charon/threads/stroke_interface.c57
-rwxr-xr-xsrc/ipsec/ipsec.in4
-rw-r--r--src/starter/starterstroke.c6
-rw-r--r--src/stroke/stroke.c34
-rw-r--r--src/stroke/stroke.h10
-rw-r--r--src/stroke/stroke_keywords.h1
-rw-r--r--src/stroke/stroke_keywords.txt1
26 files changed, 1011 insertions, 142 deletions
diff --git a/src/charon/Makefile.am b/src/charon/Makefile.am
index 2a8735f53..c8bd339fc 100644
--- a/src/charon/Makefile.am
+++ b/src/charon/Makefile.am
@@ -46,6 +46,8 @@ 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 \
+queues/jobs/acquire_job.c queues/jobs/acquire_job.h \
queues/job_queue.c queues/event_queue.c queues/send_queue.h queues/job_queue.h queues/event_queue.h \
queues/send_queue.c threads/kernel_interface.c threads/thread_pool.c threads/scheduler.c threads/sender.c \
threads/sender.h threads/kernel_interface.h threads/scheduler.h threads/receiver.c threads/stroke_interface.c \
diff --git a/src/charon/config/traffic_selector.c b/src/charon/config/traffic_selector.c
index 3a9480f77..3d53d9072 100644
--- a/src/charon/config/traffic_selector.c
+++ b/src/charon/config/traffic_selector.c
@@ -248,6 +248,29 @@ static traffic_selector_t *get_subset(private_traffic_selector_t *this, private_
}
/**
+ * implements traffic_selector_t.equals
+ */
+static bool equals(private_traffic_selector_t *this, private_traffic_selector_t *other)
+{
+ if (this->type != other->type)
+ {
+ return FALSE;
+ }
+ if (this->type == TS_IPV4_ADDR_RANGE)
+ {
+ if (this->from_addr_ipv4 == other->from_addr_ipv4 &&
+ this->to_addr_ipv4 == other->to_addr_ipv4 &&
+ this->from_port == other->from_port &&
+ this->to_port == other->to_port &&
+ this->protocol == other->protocol)
+ {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/**
* Implements traffic_selector_t.get_from_address.
*/
static chunk_t get_from_address(private_traffic_selector_t *this)
@@ -518,6 +541,7 @@ static private_traffic_selector_t *traffic_selector_create(u_int8_t protocol, ts
/* public functions */
this->public.get_subset = (traffic_selector_t*(*)(traffic_selector_t*,traffic_selector_t*))get_subset;
+ this->public.equals = (bool(*)(traffic_selector_t*,traffic_selector_t*))equals;
this->public.get_string = (char*(*)(traffic_selector_t*))get_string;
this->public.get_from_address = (chunk_t(*)(traffic_selector_t*))get_from_address;
this->public.get_to_address = (chunk_t(*)(traffic_selector_t*))get_to_address;
diff --git a/src/charon/config/traffic_selector.h b/src/charon/config/traffic_selector.h
index 420f97d0f..90437f92f 100644
--- a/src/charon/config/traffic_selector.h
+++ b/src/charon/config/traffic_selector.h
@@ -184,6 +184,15 @@ struct traffic_selector_t {
char* (*get_string) (traffic_selector_t *this);
/**
+ * @brief Compare two traffic selectors for equality.
+ *
+ * @param this first to compare
+ * @param other second to compare with first
+ * @return pointer to a string.
+ */
+ bool (*equals) (traffic_selector_t *this, traffic_selector_t *other);
+
+ /**
* @brief Destroys the ts object
*
* @param this calling object
diff --git a/src/charon/queues/jobs/acquire_job.c b/src/charon/queues/jobs/acquire_job.c
new file mode 100644
index 000000000..89eccef4a
--- /dev/null
+++ b/src/charon/queues/jobs/acquire_job.c
@@ -0,0 +1,104 @@
+/**
+ * @file acquire_job.c
+ *
+ * @brief Implementation of acquire_job_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2006 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <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 "acquire_job.h"
+
+#include <daemon.h>
+
+
+typedef struct private_acquire_job_t private_acquire_job_t;
+
+/**
+ * Private data of an acquire_job_t object.
+ */
+struct private_acquire_job_t {
+ /**
+ * Public acquire_job_t interface.
+ */
+ acquire_job_t public;
+
+ /**
+ * reqid of the child to rekey
+ */
+ u_int32_t reqid;
+
+ /**
+ * Logger ref
+ */
+ logger_t *logger;
+};
+
+/**
+ * Implementation of job_t.get_type.
+ */
+static job_type_t get_type(private_acquire_job_t *this)
+{
+ return ACQUIRE;
+}
+
+/**
+ * Implementation of job_t.execute.
+ */
+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);
+ if (ike_sa == NULL)
+ {
+ this->logger->log(this->logger, ERROR|LEVEL1,
+ "CHILD_SA not found for acquiring");
+ return DESTROY_ME;
+ }
+ ike_sa->acquire(ike_sa, this->reqid);
+
+ charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
+ return DESTROY_ME;
+}
+
+/**
+ * Implementation of job_t.destroy.
+ */
+static void destroy(private_acquire_job_t *this)
+{
+ free(this);
+}
+
+/*
+ * Described in header
+ */
+acquire_job_t *acquire_job_create(u_int32_t reqid)
+{
+ private_acquire_job_t *this = malloc_thing(private_acquire_job_t);
+
+ /* interface functions */
+ this->public.job_interface.get_type = (job_type_t (*) (job_t *)) get_type;
+ this->public.job_interface.execute = (status_t (*) (job_t *)) execute;
+ this->public.job_interface.destroy = (void (*)(job_t*)) destroy;
+
+ /* private variables */
+ this->reqid = reqid;
+ this->logger = logger_manager->get_logger(logger_manager, WORKER);
+
+ return &(this->public);
+}
diff --git a/src/charon/queues/jobs/acquire_job.h b/src/charon/queues/jobs/acquire_job.h
new file mode 100644
index 000000000..d607c91f8
--- /dev/null
+++ b/src/charon/queues/jobs/acquire_job.h
@@ -0,0 +1,61 @@
+/**
+ * @file acquire_job.h
+ *
+ * @brief Interface of acquire_job_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2006 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <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 ACQUIRE_JOB_H_
+#define ACQUIRE_JOB_H_
+
+#include <types.h>
+#include <queues/jobs/job.h>
+
+
+typedef struct acquire_job_t acquire_job_t;
+
+/**
+ * @brief Class representing an ACQUIRE Job.
+ *
+ * This job initiates a CHILD SA on kernel request.
+ *
+ * @b Constructors:
+ * - acquire_job_create()
+ *
+ * @ingroup jobs
+ */
+struct acquire_job_t {
+ /**
+ * The job_t interface.
+ */
+ job_t job_interface;
+};
+
+/**
+ * @brief Creates a job of type ACQUIRE.
+ *
+ * We use the reqid to find the routed CHILD_SA.
+ *
+ * @param reqid reqid of the CHILD_SA to acquire
+ * @return acquire_job_t object
+ *
+ * @ingroup jobs
+ */
+acquire_job_t *acquire_job_create(u_int32_t reqid);
+
+#endif /* REKEY_CHILD_SA_JOB_H_ */
diff --git a/src/charon/queues/jobs/delete_child_sa_job.c b/src/charon/queues/jobs/delete_child_sa_job.c
index 3cf7060c9..dd39572de 100644
--- a/src/charon/queues/jobs/delete_child_sa_job.c
+++ b/src/charon/queues/jobs/delete_child_sa_job.c
@@ -37,6 +37,11 @@ struct private_delete_child_sa_job_t {
delete_child_sa_job_t public;
/**
+ * reqid of the CHILD_SA
+ */
+ u_int32_t reqid;
+
+ /**
* protocol of the CHILD_SA (ESP/AH)
*/
protocol_id_t protocol;
@@ -66,12 +71,10 @@ static job_type_t get_type(private_delete_child_sa_job_t *this)
static status_t execute(private_delete_child_sa_job_t *this)
{
ike_sa_t *ike_sa;
- status_t status;
- status = charon->ike_sa_manager->checkout_by_child(charon->ike_sa_manager,
- this->protocol, this->spi,
- &ike_sa);
- if (status != SUCCESS)
+ ike_sa = charon->ike_sa_manager->checkout_by_child(charon->ike_sa_manager,
+ this->reqid);
+ if (ike_sa == NULL)
{
this->logger->log(this->logger, ERROR|LEVEL1,
"CHILD_SA not found for delete");
@@ -94,7 +97,9 @@ static void destroy(private_delete_child_sa_job_t *this)
/*
* Described in header
*/
-delete_child_sa_job_t *delete_child_sa_job_create(protocol_id_t protocol, u_int32_t spi)
+delete_child_sa_job_t *delete_child_sa_job_create(u_int32_t reqid,
+ protocol_id_t protocol,
+ u_int32_t spi)
{
private_delete_child_sa_job_t *this = malloc_thing(private_delete_child_sa_job_t);
@@ -104,6 +109,7 @@ delete_child_sa_job_t *delete_child_sa_job_create(protocol_id_t protocol, u_int3
this->public.job_interface.destroy = (void (*)(job_t*)) destroy;
/* private variables */
+ this->reqid = reqid;
this->protocol = protocol;
this->spi = spi;
this->logger = logger_manager->get_logger(logger_manager, WORKER);
diff --git a/src/charon/queues/jobs/delete_child_sa_job.h b/src/charon/queues/jobs/delete_child_sa_job.h
index 2e16ef832..fb87440c4 100644
--- a/src/charon/queues/jobs/delete_child_sa_job.h
+++ b/src/charon/queues/jobs/delete_child_sa_job.h
@@ -51,15 +51,18 @@ struct delete_child_sa_job_t {
/**
* @brief Creates a job of type DELETE_CHILD_SA.
*
- * The CHILD_SA is identified by its protocol (AH/ESP) and its
+ * The CHILD_SA is identified by its reqid, protocol (AH/ESP) and its
* inbound SPI.
*
+ * @param reqid reqid of the CHILD_SA, as used in kernel
* @param protocol protocol of the CHILD_SA
* @param spi security parameter index of the CHILD_SA
* @return delete_child_sa_job_t object
*
* @ingroup jobs
*/
-delete_child_sa_job_t *delete_child_sa_job_create(protocol_id_t protocol, u_int32_t spi);
+delete_child_sa_job_t *delete_child_sa_job_create(u_int32_t reqid,
+ protocol_id_t protocol,
+ u_int32_t spi);
#endif /* DELETE_CHILD_SA_JOB_H_ */
diff --git a/src/charon/queues/jobs/job.h b/src/charon/queues/jobs/job.h
index 6063a2108..86af1a318 100644
--- a/src/charon/queues/jobs/job.h
+++ b/src/charon/queues/jobs/job.h
@@ -58,6 +58,20 @@ enum job_type_t {
INITIATE,
/**
+ * Install SPD entries.
+ *
+ * Job is implemented in class route_job_t
+ */
+ ROUTE,
+
+ /**
+ * React on a acquire message from the kernel (e.g. setup CHILD_SA)
+ *
+ * Job is implemented in class acquire_job_t
+ */
+ ACQUIRE,
+
+ /**
* Delete an ike sa which is still not established.
*
* Job is implemented in class delete_half_open_ike_sa_job_t
diff --git a/src/charon/queues/jobs/rekey_child_sa_job.c b/src/charon/queues/jobs/rekey_child_sa_job.c
index a2b5b095f..e75d1911c 100644
--- a/src/charon/queues/jobs/rekey_child_sa_job.c
+++ b/src/charon/queues/jobs/rekey_child_sa_job.c
@@ -37,6 +37,11 @@ struct private_rekey_child_sa_job_t {
rekey_child_sa_job_t public;
/**
+ * reqid of the child to rekey
+ */
+ u_int32_t reqid;
+
+ /**
* protocol of the CHILD_SA (ESP/AH)
*/
protocol_id_t protocol;
@@ -66,12 +71,10 @@ static job_type_t get_type(private_rekey_child_sa_job_t *this)
static status_t execute(private_rekey_child_sa_job_t *this)
{
ike_sa_t *ike_sa;
- status_t status;
- status = charon->ike_sa_manager->checkout_by_child(charon->ike_sa_manager,
- this->protocol, this->spi,
- &ike_sa);
- if (status != SUCCESS)
+ ike_sa = charon->ike_sa_manager->checkout_by_child(charon->ike_sa_manager,
+ this->reqid);
+ if (ike_sa == NULL)
{
this->logger->log(this->logger, ERROR|LEVEL1,
"CHILD_SA not found for rekeying");
@@ -94,7 +97,9 @@ static void destroy(private_rekey_child_sa_job_t *this)
/*
* Described in header
*/
-rekey_child_sa_job_t *rekey_child_sa_job_create(protocol_id_t protocol, u_int32_t spi)
+rekey_child_sa_job_t *rekey_child_sa_job_create(u_int32_t reqid,
+ protocol_id_t protocol,
+ u_int32_t spi)
{
private_rekey_child_sa_job_t *this = malloc_thing(private_rekey_child_sa_job_t);
@@ -104,6 +109,7 @@ rekey_child_sa_job_t *rekey_child_sa_job_create(protocol_id_t protocol, u_int32_
this->public.job_interface.destroy = (void (*)(job_t*)) destroy;
/* private variables */
+ this->reqid = reqid;
this->protocol = protocol;
this->spi = spi;
this->logger = logger_manager->get_logger(logger_manager, WORKER);
diff --git a/src/charon/queues/jobs/rekey_child_sa_job.h b/src/charon/queues/jobs/rekey_child_sa_job.h
index 87be00c0f..72d75d1e7 100644
--- a/src/charon/queues/jobs/rekey_child_sa_job.h
+++ b/src/charon/queues/jobs/rekey_child_sa_job.h
@@ -54,12 +54,13 @@ struct rekey_child_sa_job_t {
* The CHILD_SA is identified by its protocol (AH/ESP) and its
* inbound SPI.
*
+ * @param reqid reqid of the CHILD_SA to rekey
* @param protocol protocol of the CHILD_SA
* @param spi security parameter index of the CHILD_SA
* @return rekey_child_sa_job_t object
*
* @ingroup jobs
*/
-rekey_child_sa_job_t *rekey_child_sa_job_create(protocol_id_t protocol, u_int32_t spi);
+rekey_child_sa_job_t *rekey_child_sa_job_create(u_int32_t reqid, protocol_id_t protocol, u_int32_t spi);
#endif /* REKEY_CHILD_SA_JOB_H_ */
diff --git a/src/charon/queues/jobs/route_job.c b/src/charon/queues/jobs/route_job.c
new file mode 100644
index 000000000..b6a862691
--- /dev/null
+++ b/src/charon/queues/jobs/route_job.c
@@ -0,0 +1,133 @@
+/**
+ * @file route_job.c
+ *
+ * @brief Implementation of route_job_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-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 <stdlib.h>
+
+#include "route_job.h"
+
+#include <daemon.h>
+
+typedef struct private_route_job_t private_route_job_t;
+
+/**
+ * Private data of an route_job_t Object
+ */
+struct private_route_job_t {
+ /**
+ * public route_job_t interface
+ */
+ route_job_t public;
+
+ /**
+ * associated connection to route
+ */
+ connection_t *connection;
+
+ /**
+ * associated policy to route
+ */
+ policy_t *policy;
+
+ /**
+ * route or unroute?
+ */
+ bool route;
+
+ /**
+ * logger
+ */
+ logger_t *logger;
+};
+
+/**
+ * Implements route_job_t.get_type.
+ */
+static job_type_t get_type(private_route_job_t *this)
+{
+ return ROUTE;
+}
+
+/**
+ * Implementation of job_t.execute.
+ */
+static status_t execute(private_route_job_t *this)
+{
+ ike_sa_t *ike_sa;
+
+ this->logger->log(this->logger, CONTROL|LEVEL2, "getting an IKE SA");
+ ike_sa = charon->ike_sa_manager->checkout_by_ids(charon->ike_sa_manager,
+ this->policy->get_my_id(this->policy),
+ this->policy->get_other_id(this->policy));
+
+ if (this->route)
+ {
+ if (ike_sa->route(ike_sa, this->connection, this->policy) != SUCCESS)
+ {
+ this->logger->log(this->logger, ERROR,
+ "routing failed");
+ }
+ }
+ else
+ {
+ if (ike_sa->unroute(ike_sa, this->policy) == DESTROY_ME)
+ {
+ this->logger->log(this->logger, ERROR,
+ "removing IKE_SA, as last routed CHILD_SA unrouted");
+ charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa);
+ return DESTROY_ME;
+ }
+ }
+ charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
+ return DESTROY_ME;
+}
+
+/**
+ * Implements job_t.destroy.
+ */
+static void destroy(private_route_job_t *this)
+{
+ this->connection->destroy(this->connection);
+ this->policy->destroy(this->policy);
+ free(this);
+}
+
+/*
+ * Described in header
+ */
+route_job_t *route_job_create(connection_t *connection, policy_t *policy, bool route)
+{
+ private_route_job_t *this = malloc_thing(private_route_job_t);
+
+ /* interface functions */
+ this->public.job_interface.get_type = (job_type_t (*) (job_t *)) get_type;
+ this->public.job_interface.execute = (status_t (*) (job_t *)) execute;
+ this->public.job_interface.destroy = (void (*) (job_t *)) destroy;
+
+ /* private variables */
+ this->connection = connection;
+ this->policy = policy;
+ this->route = route;
+ this->logger = logger_manager->get_logger(logger_manager, WORKER);
+
+ return &this->public;
+}
diff --git a/src/charon/queues/jobs/route_job.h b/src/charon/queues/jobs/route_job.h
new file mode 100644
index 000000000..df2648ae2
--- /dev/null
+++ b/src/charon/queues/jobs/route_job.h
@@ -0,0 +1,60 @@
+/**
+ * @file route_job.h
+ *
+ * @brief Interface of route_job_t.
+ */
+
+/*
+ * Copyright (C) 2005-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 ROUTE_JOB_H_
+#define ROUTE_JOB_H_
+
+#include <types.h>
+#include <queues/jobs/job.h>
+#include <config/policies/policy.h>
+#include <config/connections/connection.h>
+
+
+typedef struct route_job_t route_job_t;
+
+/**
+ * @brief Class representing an ROUTE Job.
+ *
+ * @b Constructors:
+ * - route_job_create()
+ *
+ * @ingroup jobs
+ */
+struct route_job_t {
+ /**
+ * implements job_t interface
+ */
+ job_t job_interface;
+};
+
+/**
+ * @brief Creates a job of type ROUTE.
+ *
+ * @param connection connection used for routing
+ * @param policy policy to set up
+ * @param route TRUE to route, FALSE to unroute
+ * @return route_job_t object
+ *
+ * @ingroup jobs
+ */
+route_job_t *route_job_create(connection_t *connection, policy_t *policy, bool route);
+
+#endif /*ROUTE_JOB_H_*/
diff --git a/src/charon/sa/child_sa.c b/src/charon/sa/child_sa.c
index 580599362..d73542163 100644
--- a/src/charon/sa/child_sa.c
+++ b/src/charon/sa/child_sa.c
@@ -33,6 +33,7 @@
mapping_t child_sa_state_m[] = {
{CHILD_CREATED, "CREATED"},
{CHILD_INSTALLED, "INSTALLED"},
+ {CHILD_ROUTED, "ROUTED"},
{CHILD_REKEYING, "REKEYING"},
{CHILD_DELETING, "DELETING"},
{MAPPING_END, NULL}
@@ -502,6 +503,13 @@ static status_t add_policies(private_child_sa_t *this, linked_list_t *my_ts_list
}
my_iter->destroy(my_iter);
other_iter->destroy(other_iter);
+
+ /* switch to routed state if no SAD entry set up */
+ if (this->state == CHILD_CREATED)
+ {
+ this->state = CHILD_ROUTED;
+ }
+
return SUCCESS;
}
@@ -597,65 +605,74 @@ static void log_status(private_child_sa_t *this, logger_t *logger, char* name)
}
now = (u_int32_t)time(NULL);
- /* query SA times */
- status = charon->kernel_interface->query_sa(charon->kernel_interface,
- this->me.addr, this->me.spi, this->protocol, &use_in);
- if (status == SUCCESS && use_in)
- {
- snprintf(use_in_str, sizeof(use_in_str), "%ds", now - use_in);
- }
- status = charon->kernel_interface->query_sa(charon->kernel_interface,
- this->other.addr, this->other.spi, this->protocol, &use_out);
- if (status == SUCCESS && use_out)
- {
- snprintf(use_out_str, sizeof(use_out_str), "%ds", now - use_out);
- }
-
- /* calculate rekey times */
- if (this->soft_lifetime)
+ if (this->state == CHILD_INSTALLED)
{
- rekeying = this->soft_lifetime - (now - this->install_time);
- snprintf(rekey_str, sizeof(rekey_str), "%ds", (int)rekeying);
- }
-
- /* algorithms used */
- if (this->protocol == PROTO_ESP)
- {
- if (this->encryption.key_size)
+ /* query SA times */
+ status = charon->kernel_interface->query_sa(charon->kernel_interface,
+ this->me.addr, this->me.spi, this->protocol, &use_in);
+ if (status == SUCCESS && use_in)
{
- snprintf(enc_str, sizeof(enc_str), "%s-%d,",
- mapping_find(encryption_algorithm_m, this->encryption.algorithm),
- this->encryption.key_size);
+ snprintf(use_in_str, sizeof(use_in_str), "%ds", now - use_in);
+ }
+ status = charon->kernel_interface->query_sa(charon->kernel_interface,
+ this->other.addr, this->other.spi, this->protocol, &use_out);
+ if (status == SUCCESS && use_out)
+ {
+ snprintf(use_out_str, sizeof(use_out_str), "%ds", now - use_out);
+ }
+
+ /* calculate rekey times */
+ if (this->soft_lifetime)
+ {
+ rekeying = this->soft_lifetime - (now - this->install_time);
+ snprintf(rekey_str, sizeof(rekey_str), "%ds", (int)rekeying);
+ }
+
+ /* algorithms used */
+ if (this->protocol == PROTO_ESP)
+ {
+ if (this->encryption.key_size)
+ {
+ snprintf(enc_str, sizeof(enc_str), "%s-%d,",
+ mapping_find(encryption_algorithm_m, this->encryption.algorithm),
+ this->encryption.key_size);
+ }
+ else
+ {
+ snprintf(enc_str, sizeof(enc_str), "%s,",
+ mapping_find(encryption_algorithm_m, this->encryption.algorithm));
+ }
+ }
+ if (this->integrity.key_size)
+ {
+ snprintf(int_str, sizeof(int_str), "%s-%d",
+ mapping_find(integrity_algorithm_m, this->integrity.algorithm),
+ this->integrity.key_size);
}
else
{
- snprintf(enc_str, sizeof(enc_str), "%s,",
- mapping_find(encryption_algorithm_m, this->encryption.algorithm));
+ snprintf(int_str, sizeof(int_str), "%s",
+ mapping_find(integrity_algorithm_m, this->integrity.algorithm));
}
- }
- if (this->integrity.key_size)
- {
- snprintf(int_str, sizeof(int_str), "%s-%d",
- mapping_find(integrity_algorithm_m, this->integrity.algorithm),
- this->integrity.key_size);
+
+ logger->log(logger, CONTROL|LEVEL1,
+ " \"%s\": state: %s, reqid: %d, ",
+ name, mapping_find(child_sa_state_m, this->state), this->reqid);
+ logger->log(logger, CONTROL|LEVEL1,
+ " \"%s\": %s (%s%s), SPIs (in/out): 0x%x/0x%x",
+ name, this->protocol == PROTO_ESP ? "ESP" : "AH",
+ enc_str, int_str,
+ htonl(this->me.spi), htonl(this->other.spi));
+ logger->log(logger, CONTROL|LEVEL1,
+ " \"%s\": rekeying: %s, key age (in/out): %s/%s",
+ name, rekey_str, use_in_str, use_out_str);
}
else
{
- snprintf(int_str, sizeof(int_str), "%s",
- mapping_find(integrity_algorithm_m, this->integrity.algorithm));
- }
-
- logger->log(logger, CONTROL|LEVEL1,
- " \"%s\": %s (%s%s), SPIs (in/out): 0x%x/0x%x, reqid: %d",
- name,
- this->protocol == PROTO_ESP ? "ESP" : "AH",
- enc_str, int_str,
- htonl(this->me.spi), htonl(this->other.spi),
- this->reqid);
- logger->log(logger, CONTROL|LEVEL1,
- " \"%s\": state: %s, rekeying: %s, key age (in/out): %s/%s",
- name, mapping_find(child_sa_state_m, this->state),
- rekey_str, use_in_str, use_out_str);
+ logger->log(logger, CONTROL|LEVEL1, " \"%s\": state: %s, reqid: %d",
+ name, mapping_find(child_sa_state_m, this->state),
+ this->reqid);
+ }
iterator = this->policies->create_iterator(this->policies, TRUE);
while (iterator->has_next(iterator))
diff --git a/src/charon/sa/child_sa.h b/src/charon/sa/child_sa.h
index 2a74a2a44..68015cf07 100644
--- a/src/charon/sa/child_sa.h
+++ b/src/charon/sa/child_sa.h
@@ -49,6 +49,11 @@ enum child_sa_state_t {
CHILD_CREATED,
/**
+ * Installed SPD, but no SAD entries
+ */
+ CHILD_ROUTED,
+
+ /**
* Installed an in-use CHILD_SA
*/
CHILD_INSTALLED,
diff --git a/src/charon/sa/ike_sa.c b/src/charon/sa/ike_sa.c
index bfffdad2f..c3011ecba 100644
--- a/src/charon/sa/ike_sa.c
+++ b/src/charon/sa/ike_sa.c
@@ -329,10 +329,13 @@ static void update_hosts(private_ike_sa_t *this, host_t *me, host_t *other)
child_sa_t *child_sa = NULL;
host_diff_t my_diff, other_diff;
- if (this->my_host == NULL || this->other_host == NULL)
+ if (this->my_host->is_anyaddr(this->my_host) ||
+ this->other_host->is_anyaddr(this->other_host))
{
/* on first received message */
+ this->my_host->destroy(this->my_host);
this->my_host = me->clone(me);
+ this->other_host->destroy(this->other_host);
this->other_host = other->clone(other);
return;
}
@@ -792,9 +795,14 @@ static status_t initiate(private_ike_sa_t *this,
*/
ike_sa_init_t *ike_sa_init;
+ this->logger->log(this->logger, CONTROL,
+ "initiating IKE_SA");
+
set_name(this, connection->get_name(connection));
+ DESTROY_IF(this->my_host);
this->my_host = connection->get_my_host(connection);
this->my_host = this->my_host->clone(this->my_host);
+ DESTROY_IF(this->other_host);
this->other_host = connection->get_other_host(connection);
this->other_host = this->other_host->clone(this->other_host);
@@ -806,6 +814,8 @@ static status_t initiate(private_ike_sa_t *this,
case IKE_DELETING:
{
/* if we are in DELETING, we deny set up of a policy. */
+ this->logger->log(this->logger, CONTROL,
+ "creating CHILD_SA discarded, as IKE_SA is deleting");
policy->destroy(policy);
connection->destroy(connection);
return FAILED;
@@ -820,6 +830,9 @@ static status_t initiate(private_ike_sa_t *this,
*/
create_child_sa_t *create_child;
+ this->logger->log(this->logger, CONTROL,
+ "initiating CHILD_SA");
+
connection->destroy(connection);
create_child = create_child_sa_create(&this->public);
create_child->set_policy(create_child, policy);
@@ -834,33 +847,275 @@ static status_t initiate(private_ike_sa_t *this,
*/
static status_t acquire(private_ike_sa_t *this, u_int32_t reqid)
{
- /* - get TS from child with reqid
- * - get a policy from TS
- * - get connection from policy
- */
+ connection_t *connection;
+ policy_t *policy;
+ iterator_t *iterator;
+ child_sa_t *current, *child_sa = NULL;
+ linked_list_t *my_ts, *other_ts;
+
+ if (this->state == IKE_DELETING)
+ {
+ this->logger->log(this->logger, CONTROL,
+ "acquiring CHILD_SA with reqid %d discarded, as IKE_SA is deleting",
+ reqid);
+ return FAILED;
+ }
+
+
+ /* find CHILD_SA */
+ iterator = this->child_sas->create_iterator(this->child_sas, TRUE);
+ while (iterator->iterate(iterator, (void**)&current))
+ {
+ if (current->get_reqid(current) == reqid)
+ {
+ iterator->remove(iterator);
+ child_sa = current;
+ break;
+ }
+ }
+ iterator->destroy(iterator);
+ if (!child_sa)
+ {
+ this->logger->log(this->logger, ERROR,
+ "CHILD_SA with reqid %d not found, unable to acquire",
+ reqid);
+ return FAILED;
+ }
+ my_ts = child_sa->get_my_traffic_selectors(child_sa);
+ other_ts = child_sa->get_other_traffic_selectors(child_sa);
+
+ policy = charon->policies->get_policy(charon->policies,
+ this->my_id, this->other_id,
+ my_ts, other_ts,
+ this->my_host, this->other_host);
+ child_sa->destroy(child_sa);
+ if (policy == NULL)
+ {
+ this->logger->log(this->logger, ERROR,
+ "no policy found to acquire CHILD_SA with reqid %d",
+ reqid);
+ return FAILED;
+ }
+
switch (this->state)
{
case IKE_CREATED:
- /* ike_sa_init */
+ {
+ ike_sa_init_t *ike_sa_init;
+
+ this->logger->log(this->logger, CONTROL,
+ "acquiring CHILD_SA with reqid %d, IKE_SA setup needed",
+ reqid);
+
+ connection = charon->connections->get_connection_by_hosts(
+ charon->connections, this->my_host, this->other_host);
+
+ if (connection == NULL)
+ {
+ this->logger->log(this->logger, ERROR,
+ "no connection found to acquire IKE_SA for CHILD_SA with reqid %d",
+ reqid);
+ policy->destroy(policy);
+ return FAILED;
+ }
+
+ this->message_id_out = 1;
+ ike_sa_init = ike_sa_init_create(&this->public);
+ ike_sa_init->set_config(ike_sa_init, connection, policy);
+ return queue_transaction(this, (transaction_t*)ike_sa_init, TRUE);
+ }
+ case IKE_CONNECTING:
+ case IKE_ESTABLISHED:
+ {
+ create_child_sa_t *create_child;
+
+ this->logger->log(this->logger, CONTROL,
+ "acquiring CHILD_SA with reqid %d",
+ reqid);
+
+ create_child = create_child_sa_create(&this->public);
+ create_child->set_policy(create_child, policy);
+ return queue_transaction(this, (transaction_t*)create_child, FALSE);
+ }
+ default:
+ break;
+ }
+ return FAILED;
+}
+
+/**
+ * destroy a list of traffic selectors
+ */
+static void ts_list_destroy(linked_list_t *list)
+{
+ traffic_selector_t *ts;
+ while (list->remove_last(list, (void**)&ts) == SUCCESS)
+ {
+ ts->destroy(ts);
+ }
+ list->destroy(list);
+}
+
+/**
+ * compare two lists of traffic selectors for equality
+ */
+static bool ts_list_equals(linked_list_t *l1, linked_list_t *l2)
+{
+ bool equals = TRUE;
+ iterator_t *i1, *i2;
+ traffic_selector_t *t1, *t2;
+
+ i1 = l1->create_iterator(l1, TRUE);
+ i2 = l2->create_iterator(l2, TRUE);
+ while (i1->iterate(i1, (void**)&t1) && i2->iterate(i2, (void**)&t2))
+ {
+ if (!t1->equals(t1, t2))
+ {
+ equals = FALSE;
break;
+ }
+ }
+ /* check if one iterator is not at the end */
+ if (i1->has_next(i1) || i2->has_next(i2))
+ {
+ equals = FALSE;
+ }
+ i1->destroy(i1);
+ i2->destroy(i2);
+ return equals;
+}
+
+/**
+ * Implementation of ike_sa_t.route.
+ */
+static status_t route(private_ike_sa_t *this, connection_t *connection, policy_t *policy)
+{
+ child_sa_t *child_sa = NULL;
+ iterator_t *iterator;
+ linked_list_t *my_ts, *other_ts;
+ status_t status;
+
+ /* check if not already routed*/
+ iterator = this->child_sas->create_iterator(this->child_sas, TRUE);
+ while (iterator->iterate(iterator, (void**)&child_sa))
+ {
+ linked_list_t *my_ts_conf, *other_ts_conf;
+
+ my_ts = child_sa->get_my_traffic_selectors(child_sa);
+ other_ts = child_sa->get_other_traffic_selectors(child_sa);
+
+ my_ts_conf = policy->get_my_traffic_selectors(policy, this->my_host);
+ other_ts_conf = policy->get_other_traffic_selectors(policy, this->other_host);
+
+ if (ts_list_equals(my_ts, my_ts_conf) &&
+ ts_list_equals(other_ts, other_ts_conf))
+ {
+ ts_list_destroy(my_ts_conf);
+ ts_list_destroy(other_ts_conf);
+ iterator->destroy(iterator);
+ this->logger->log(this->logger, CONTROL,
+ "a CHILD_SA with such a policy already routed");
+
+ return FAILED;
+ }
+ ts_list_destroy(my_ts_conf);
+ ts_list_destroy(other_ts_conf);
+ }
+ iterator->destroy(iterator);
+
+ switch (this->state)
+ {
+ case IKE_CREATED:
case IKE_CONNECTING:
+ /* we update IKE_SA information as good as possible,
+ * this allows us to set up the SA later when an acquire comes in. */
+ if (this->my_id->get_type(this->my_id) == ID_ANY)
+ {
+ this->my_id->destroy(this->my_id);
+ this->my_id = policy->get_my_id(policy);
+ this->my_id = this->my_id->clone(this->my_id);
+ }
+ if (this->other_id->get_type(this->other_id) == ID_ANY)
+ {
+ this->other_id->destroy(this->other_id);
+ this->other_id = policy->get_other_id(policy);
+ this->other_id = this->other_id->clone(this->other_id);
+ }
+ if (this->my_host->is_anyaddr(this->my_host))
+ {
+ this->my_host->destroy(this->my_host);
+ this->my_host = connection->get_my_host(connection);
+ this->my_host = this->my_host->clone(this->my_host);
+ }
+ if (this->other_host->is_anyaddr(this->other_host))
+ {
+ this->other_host->destroy(this->other_host);
+ this->other_host = connection->get_other_host(connection);
+ this->other_host = this->other_host->clone(this->other_host);
+ }
+ set_name(this, connection->get_name(connection));
+ break;
case IKE_ESTABLISHED:
- /* queue create_child_sa */
+ /* nothing to do */
break;
case IKE_DELETING:
/* deny */
- break;
+ return FAILED;
}
- return FAILED;
+
+ child_sa = child_sa_create(0, this->my_host, this->other_host, 0, 0, FALSE);
+ my_ts = policy->get_my_traffic_selectors(policy, this->my_host);
+ other_ts = policy->get_other_traffic_selectors(policy, this->other_host);
+ status = child_sa->add_policies(child_sa, my_ts, other_ts);
+ ts_list_destroy(my_ts);
+ ts_list_destroy(other_ts);
+ this->child_sas->insert_last(this->child_sas, child_sa);
+
+ return status;
}
/**
- * Implementation of ike_sa_t.route.
+ * Implementation of ike_sa_t.unroute.
*/
-static status_t route(private_ike_sa_t *this, policy_t *policy)
+static status_t unroute(private_ike_sa_t *this, policy_t *policy)
{
- /* TODO: create CHILD_SA, add policy */
- return FAILED;
+ iterator_t *iterator;
+ child_sa_t *child_sa = NULL;
+ linked_list_t *my_ts, *other_ts, *my_ts_conf, *other_ts_conf;
+
+ /* find CHILD_SA in ROUTED state */
+ iterator = this->child_sas->create_iterator(this->child_sas, TRUE);
+ while (iterator->iterate(iterator, (void**)&child_sa))
+ {
+ if (child_sa->get_state(child_sa) == CHILD_ROUTED)
+ {
+ my_ts = child_sa->get_my_traffic_selectors(child_sa);
+ other_ts = child_sa->get_other_traffic_selectors(child_sa);
+
+ my_ts_conf = policy->get_my_traffic_selectors(policy, this->my_host);
+ other_ts_conf = policy->get_other_traffic_selectors(policy, this->other_host);
+
+ if (ts_list_equals(my_ts, my_ts_conf) &&
+ ts_list_equals(other_ts, other_ts_conf))
+ {
+ iterator->remove(iterator);
+ child_sa->destroy(child_sa);
+ ts_list_destroy(my_ts_conf);
+ ts_list_destroy(other_ts_conf);
+ break;
+ }
+ ts_list_destroy(my_ts_conf);
+ ts_list_destroy(other_ts_conf);
+ }
+ }
+ iterator->destroy(iterator);
+ /* if we are not established, and we have no more routed childs, remove whole SA */
+ if (this->state == IKE_CREATED &&
+ this->child_sas->get_count(this->child_sas) == 0)
+ {
+ return DESTROY_ME;
+ }
+ return SUCCESS;
}
/**
@@ -1218,6 +1473,28 @@ static void add_child_sa(private_ike_sa_t *this, child_sa_t *child_sa)
}
/**
+ * Implementation of protected_ike_sa_t.has_child_sa.
+ */
+static bool has_child_sa(private_ike_sa_t *this, u_int32_t reqid)
+{
+ iterator_t *iterator;
+ child_sa_t *current;
+ bool found = FALSE;
+
+ iterator = this->child_sas->create_iterator(this->child_sas, TRUE);
+ while (iterator->iterate(iterator, (void**)&current))
+ {
+ if (current->get_reqid(current) == reqid)
+ {
+ found = TRUE;
+ break;
+ }
+ }
+ iterator->destroy(iterator);
+ return found;
+}
+
+/**
* Implementation of protected_ike_sa_t.get_child_sa.
*/
static child_sa_t* get_child_sa(private_ike_sa_t *this, protocol_id_t protocol,
@@ -1226,12 +1503,12 @@ static child_sa_t* get_child_sa(private_ike_sa_t *this, protocol_id_t protocol,
iterator_t *iterator;
child_sa_t *current, *found = NULL;
- iterator = this->child_sas->create_iterator(this->child_sas, FALSE);
+ iterator = this->child_sas->create_iterator(this->child_sas, TRUE);
while (iterator->has_next(iterator))
{
iterator->current(iterator, (void**)&current);
if (current->get_spi(current, inbound) == spi &&
- current->get_protocol(current) == protocol)
+ current->get_protocol(current) == protocol)
{
found = current;
}
@@ -1353,17 +1630,28 @@ static void log_status(private_ike_sa_t *this, logger_t *logger, char *name)
*/
static status_t delete_(private_ike_sa_t *this)
{
- delete_ike_sa_t *delete_ike_sa;
- delete_ike_sa = delete_ike_sa_create(&this->public);
-
- if (this->transaction_out)
+ switch (this->state)
{
- /* already a transaction in progress. As this may hang
- * around a while, we don't inform the other peer. */
- return DESTROY_ME;
+ case IKE_CONNECTING:
+ case IKE_ESTABLISHED:
+ {
+ delete_ike_sa_t *delete_ike_sa;
+ delete_ike_sa = delete_ike_sa_create(&this->public);
+ if (this->transaction_out)
+ {
+ /* already a transaction in progress. As this may hang
+ * around a while, we don't inform the other peer. */
+ return DESTROY_ME;
+ }
+ return queue_transaction(this, (transaction_t*)delete_ike_sa, FALSE);
+ }
+ case IKE_CREATED:
+ case IKE_DELETING:
+ default:
+ {
+ return DESTROY_ME;
+ }
}
-
- return queue_transaction(this, (transaction_t*)delete_ike_sa, FALSE);
}
/**
@@ -1483,7 +1771,8 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id)
this->public.set_name = (void(*)(ike_sa_t*,char*))set_name;
this->public.process_message = (status_t(*)(ike_sa_t*, message_t*)) process_message;
this->public.initiate = (status_t(*)(ike_sa_t*,connection_t*,policy_t*)) initiate;
- this->public.route = (status_t(*)(ike_sa_t*,policy_t*)) route;
+ this->public.route = (status_t(*)(ike_sa_t*,connection_t*,policy_t*)) route;
+ this->public.unroute = (status_t(*)(ike_sa_t*,policy_t*)) unroute;
this->public.acquire = (status_t(*)(ike_sa_t*,u_int32_t)) acquire;
this->public.get_id = (ike_sa_id_t*(*)(ike_sa_t*)) get_id;
this->public.get_my_host = (host_t*(*)(ike_sa_t*)) get_my_host;
@@ -1505,6 +1794,7 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id)
this->public.get_prf_auth_r = (prf_t *(*) (ike_sa_t *)) get_prf_auth_r;
this->public.build_transforms = (status_t (*) (ike_sa_t *,proposal_t*,diffie_hellman_t*,chunk_t,chunk_t,bool)) build_transforms;
this->public.add_child_sa = (void (*) (ike_sa_t*,child_sa_t*)) add_child_sa;
+ this->public.has_child_sa = (bool(*)(ike_sa_t*,u_int32_t)) has_child_sa;
this->public.get_child_sa = (child_sa_t* (*)(ike_sa_t*,protocol_id_t,u_int32_t,bool)) get_child_sa;
this->public.rekey_child_sa = (status_t(*)(ike_sa_t*,protocol_id_t,u_int32_t)) rekey_child_sa;
this->public.delete_child_sa = (status_t(*)(ike_sa_t*,protocol_id_t,u_int32_t)) delete_child_sa;
@@ -1517,10 +1807,10 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id)
this->ike_sa_id = ike_sa_id->clone(ike_sa_id);
this->name = strdup("(uninitialized)");
this->child_sas = linked_list_create();
- this->my_host = NULL;
- this->other_host = NULL;
- this->my_id = NULL;
- this->other_id = NULL;
+ this->my_host = host_create(AF_INET, "0.0.0.0", 0);
+ this->other_host = host_create(AF_INET, "0.0.0.0", 0);
+ this->my_id = identification_create_from_encoding(ID_ANY, CHUNK_INITIALIZER);
+ this->other_id = identification_create_from_encoding(ID_ANY, CHUNK_INITIALIZER);
this->crypter_in = NULL;
this->crypter_out = NULL;
this->signer_in = NULL;
diff --git a/src/charon/sa/ike_sa.h b/src/charon/sa/ike_sa.h
index f593e382a..dfd24b049 100644
--- a/src/charon/sa/ike_sa.h
+++ b/src/charon/sa/ike_sa.h
@@ -237,16 +237,27 @@ struct ike_sa_t {
*
* Installs the policies in the kernel. If traffic matches,
* the kernel requests connection setup from the IKE_SA via acquire().
- * The policy is owned by the IKE_SA after the call, so
- * do not modify or destroy it.
*
* @param this calling object
+ * @param connection connection definition used for routing
* @param policy policy to route
* @return
- * - SUCCESS if initialization started
- * - DESTROY_ME if initialization failed and IKE_SA MUST be deleted
+ * - SUCCESS if routed successfully
+ * - FAILED if routing failed
*/
- status_t (*route) (ike_sa_t *this, policy_t *policy);
+ status_t (*route) (ike_sa_t *this, connection_t *connection, policy_t *policy);
+
+ /**
+ * @brief Unroute a policy in the kernel previously routed.
+ *
+ * @param this calling object
+ * @param policy policy to route
+ * @return
+ * - SUCCESS if route removed
+ * - DESTROY_ME if last route was removed from
+ * an IKE_SA which was not established
+ */
+ status_t (*unroute) (ike_sa_t *this, policy_t *policy);
/**
* @brief Acquire connection setup for a policy.
@@ -436,6 +447,15 @@ 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.
*
* @param this calling object
diff --git a/src/charon/sa/ike_sa_manager.c b/src/charon/sa/ike_sa_manager.c
index c8e4d71da..abb9c0fef 100644
--- a/src/charon/sa/ike_sa_manager.c
+++ b/src/charon/sa/ike_sa_manager.c
@@ -554,12 +554,11 @@ static ike_sa_t* checkout(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id
/**
* Implementation of of ike_sa_manager.checkout_by_child.
*/
-static status_t checkout_by_child(private_ike_sa_manager_t *this,
- protocol_id_t protocol, u_int32_t spi,
- ike_sa_t **ike_sa)
+static ike_sa_t* checkout_by_child(private_ike_sa_manager_t *this,
+ u_int32_t reqid)
{
iterator_t *iterator;
- status_t status = NOT_FOUND;
+ ike_sa_t *ike_sa = NULL;
pthread_mutex_lock(&(this->mutex));
@@ -572,12 +571,11 @@ static status_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->get_child_sa(entry->ike_sa, protocol, spi, TRUE) != NULL)
+ if (entry->ike_sa->has_child_sa(entry->ike_sa, reqid))
{
/* match */
entry->checked_out = TRUE;
- *ike_sa = entry->ike_sa;
- status = SUCCESS;
+ ike_sa = entry->ike_sa;
break;
}
}
@@ -585,7 +583,7 @@ static status_t checkout_by_child(private_ike_sa_manager_t *this,
iterator->destroy(iterator);
pthread_mutex_unlock(&(this->mutex));
- return status;
+ return ike_sa;
}
/**
@@ -915,7 +913,7 @@ ike_sa_manager_t *ike_sa_manager_create()
this->public.destroy = (void(*)(ike_sa_manager_t*))destroy;
this->public.checkout_by_ids = (ike_sa_t*(*)(ike_sa_manager_t*,identification_t*,identification_t*))checkout_by_ids;
this->public.checkout = (ike_sa_t*(*)(ike_sa_manager_t*, ike_sa_id_t*))checkout;
- this->public.checkout_by_child = (status_t(*)(ike_sa_manager_t*,protocol_id_t,u_int32_t,ike_sa_t**))checkout_by_child;
+ this->public.checkout_by_child = (ike_sa_t*(*)(ike_sa_manager_t*,u_int32_t))checkout_by_child;
this->public.get_ike_sa_list = (linked_list_t*(*)(ike_sa_manager_t*))get_ike_sa_list;
this->public.get_ike_sa_list_by_name = (linked_list_t*(*)(ike_sa_manager_t*,const char*))get_ike_sa_list_by_name;
this->public.log_status = (void(*)(ike_sa_manager_t*,logger_t*,char*))log_status;
diff --git a/src/charon/sa/ike_sa_manager.h b/src/charon/sa/ike_sa_manager.h
index 1c8dbad16..f327be09c 100644
--- a/src/charon/sa/ike_sa_manager.h
+++ b/src/charon/sa/ike_sa_manager.h
@@ -92,15 +92,12 @@ struct ike_sa_manager_t {
* CHILD_SA the kernel wants to modify.
*
* @param this the manager object
- * @param protocol protocol of the CHILD_SA
- * @param spi SPI of the CHILD_SA
- * @param[out] ike_sa checked out SA
+ * @param reqid reqid of the CHILD_SA
* @return
- * - NOT_FOUND, if no IKE SA with such a child found
- * - SUCCESS, if ike_sa set
+ * - checked out IKE_SA, if found
+ * - NULL, if not found
*/
- status_t (*checkout_by_child) (ike_sa_manager_t* this, protocol_id_t protocol,
- u_int32_t spi, ike_sa_t **ike_sa);
+ ike_sa_t* (*checkout_by_child) (ike_sa_manager_t* this, u_int32_t reqid);
/**
* @brief Get a list of all IKE_SA SAs currently set up.
diff --git a/src/charon/threads/kernel_interface.c b/src/charon/threads/kernel_interface.c
index 4bb9a6cea..9ca821fa2 100644
--- a/src/charon/threads/kernel_interface.c
+++ b/src/charon/threads/kernel_interface.c
@@ -43,6 +43,7 @@
#include <utils/linked_list.h>
#include <queues/jobs/delete_child_sa_job.h>
#include <queues/jobs/rekey_child_sa_job.h>
+#include <queues/jobs/acquire_job.h>
/** kernel level protocol identifiers */
#define KERNEL_ESP 50
@@ -342,44 +343,65 @@ static void receive_messages(private_kernel_interface_t *this)
break;
}
- /* we handle ACQUIRE and EXPIRE messages directly
- */
+ /* we handle ACQUIRE and EXPIRE messages directly */
hdr = (struct nlmsghdr*)response;
if (hdr->nlmsg_type == XFRM_MSG_ACQUIRE)
{
- struct xfrm_user_acquire *acquire;
-
- acquire = (struct xfrm_user_acquire*)NLMSG_DATA(hdr);
- this->logger->log(this->logger, CONTROL,
- "Received a XFRM_MSG_ACQUIRE with index %d. Ignored",
- acquire->policy.index);
-
+ u_int32_t reqid = 0;
+ job_t *job;
+ struct rtattr *rthdr = XFRM_RTA(hdr, struct xfrm_user_acquire);
+ size_t rtsize = XFRM_PAYLOAD(hdr, struct xfrm_user_tmpl);
+ if (RTA_OK(rthdr, rtsize))
+ {
+ if (rthdr->rta_type == XFRMA_TMPL)
+ {
+ struct xfrm_user_tmpl* tmpl = (struct xfrm_user_tmpl*)RTA_DATA(rthdr);
+ reqid = tmpl->reqid;
+ }
+ }
+ if (reqid == 0)
+ {
+ this->logger->log(this->logger, ERROR,
+ "Received a XFRM_MSG_ACQUIRE, but no reqid found");
+ }
+ else
+ {
+ this->logger->log(this->logger, CONTROL|LEVEL1,
+ "Received a XFRM_MSG_ACQUIRE");
+ this->logger->log(this->logger, CONTROL,
+ "creating acquire job for CHILD_SA with reqid %d",
+ reqid);
+ job = (job_t*)acquire_job_create(reqid);
+ charon->job_queue->add(charon->job_queue, job);
+ }
}
else if (hdr->nlmsg_type == XFRM_MSG_EXPIRE)
{
job_t *job;
protocol_id_t protocol;
- u_int32_t spi;
+ u_int32_t spi, reqid;
struct xfrm_user_expire *expire;
expire = (struct xfrm_user_expire*)NLMSG_DATA(hdr);
protocol = expire->state.id.proto == KERNEL_ESP ?
PROTO_ESP : PROTO_AH;
spi = expire->state.id.spi;
+ reqid = expire->state.reqid;
this->logger->log(this->logger, CONTROL|LEVEL1,
"Received a XFRM_MSG_EXPIRE");
this->logger->log(this->logger, CONTROL,
- "creating %s job for %s CHILD_SA 0x%x",
+ "creating %s job for %s CHILD_SA 0x%x (reqid %d)",
expire->hard ? "delete" : "rekey",
- mapping_find(protocol_id_m, protocol), ntohl(spi));
+ mapping_find(protocol_id_m, protocol), ntohl(spi),
+ reqid);
if (expire->hard)
{
- job = (job_t*)delete_child_sa_job_create(protocol, spi);
+ job = (job_t*)delete_child_sa_job_create(reqid, protocol, spi);
}
else
{
- job = (job_t*)rekey_child_sa_job_create(protocol, spi);
+ job = (job_t*)rekey_child_sa_job_create(reqid, protocol, spi);
}
charon->job_queue->add(charon->job_queue, job);
}
@@ -670,7 +692,7 @@ static status_t update_sa(
sa_id->spi = spi;
sa_id->proto = (protocol == PROTO_ESP) ? KERNEL_ESP : KERNEL_AH;
sa_id->family = dst->get_family(dst);
- POS;
+
if (send_message(this, hdr, &update) != SUCCESS)
{
this->logger->log(this->logger, ERROR, "netlink communication failed");
@@ -695,7 +717,6 @@ static status_t update_sa(
free(update);
return FAILED;
}
- POS;
this->logger->log(this->logger, CONTROL|LEVEL2, "updating SA");
update->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
@@ -731,7 +752,7 @@ static status_t update_sa(
rthdr = RTA_NEXT(rthdr, rtsize);
}
}
- POS;
+
if (send_message(this, update, &response) != SUCCESS)
{
this->logger->log(this->logger, ERROR, "netlink communication failed");
@@ -754,8 +775,7 @@ static status_t update_sa(
this->logger->log(this->logger, CONTROL|LEVEL2, "deleting old SA");
status = this->public.del_sa(&this->public, dst, spi, protocol);
}
- POS;
-
+
free(update);
free(response);
return status;
@@ -1052,7 +1072,7 @@ static status_t add_policy(private_kernel_interface_t *this,
struct xfrm_user_tmpl *tmpl = (struct xfrm_user_tmpl*)RTA_DATA(rthdr);
tmpl->reqid = reqid;
- tmpl->id.proto = (protocol == PROTO_ESP) ? KERNEL_ESP : KERNEL_AH;
+ tmpl->id.proto = (protocol == PROTO_AH) ? KERNEL_AH : KERNEL_ESP;
tmpl->aalgos = tmpl->ealgos = tmpl->calgos = ~0;
tmpl->mode = TRUE;
diff --git a/src/charon/threads/stroke_interface.c b/src/charon/threads/stroke_interface.c
index 004e3ec1f..7188a532d 100755
--- a/src/charon/threads/stroke_interface.c
+++ b/src/charon/threads/stroke_interface.c
@@ -38,6 +38,7 @@
#include <daemon.h>
#include <crypto/x509.h>
#include <queues/jobs/initiate_job.h>
+#include <queues/jobs/route_job.h>
#define IKE_PORT 500
#define PATH_BUF 256
@@ -519,6 +520,56 @@ static void stroke_initiate(private_stroke_t *this, stroke_msg_t *msg)
}
/**
+ * route/unroute a policy (install SPD entries)
+ */
+static void stroke_route(private_stroke_t *this, stroke_msg_t *msg, bool route)
+{
+ route_job_t *job;
+ connection_t *connection;
+ policy_t *policy;
+
+ pop_string(msg, &(msg->route.name));
+ this->logger->log(this->logger, CONTROL,
+ "received stroke: %s \"%s\"",
+ route ? "route" : "unroute",
+ msg->route.name);
+
+ /* we wouldn't need a connection, but we only want to route policies
+ * whose connections are keyexchange=ikev2. */
+ connection = charon->connections->get_connection_by_name(charon->connections,
+ msg->route.name);
+ if (connection == NULL)
+ {
+ this->stroke_logger->log(this->stroke_logger, ERROR,
+ "no connection named \"%s\"",
+ msg->route.name);
+ return;
+ }
+ if (!connection->is_ikev2(connection))
+ {
+ connection->destroy(connection);
+ return;
+ }
+
+ policy = charon->policies->get_policy_by_name(charon->policies,
+ msg->route.name);
+ if (policy == NULL)
+ {
+ this->stroke_logger->log(this->stroke_logger, ERROR,
+ "no policy named \"%s\"",
+ msg->route.name);
+ connection->destroy(connection);
+ return;
+ }
+ this->stroke_logger->log(this->stroke_logger, CONTROL,
+ "%s policy \"%s\"",
+ route ? "routing" : "unrouting",
+ msg->route.name);
+ job = route_job_create(connection, policy, route);
+ charon->job_queue->add(charon->job_queue, (job_t*)job);
+}
+
+/**
* terminate a connection by name
*/
static void stroke_terminate(private_stroke_t *this, stroke_msg_t *msg)
@@ -795,6 +846,12 @@ static void stroke_receive(private_stroke_t *this)
case STR_INITIATE:
stroke_initiate(this, msg);
break;
+ case STR_ROUTE:
+ stroke_route(this, msg, TRUE);
+ break;
+ case STR_UNROUTE:
+ stroke_route(this, msg, FALSE);
+ break;
case STR_TERMINATE:
stroke_terminate(this, msg);
break;
diff --git a/src/ipsec/ipsec.in b/src/ipsec/ipsec.in
index 5524ee627..477d345fb 100755
--- a/src/ipsec/ipsec.in
+++ b/src/ipsec/ipsec.in
@@ -174,6 +174,10 @@ route|unroute)
then
$IPSEC_WHACK --name "$1" "--$op"
fi
+ if test -e $IPSEC_CHARON_PID
+ then
+ $IPSEC_STROKE "$op" "$1"
+ fi
exit 0
;;
scencrypt|scdecrypt)
diff --git a/src/starter/starterstroke.c b/src/starter/starterstroke.c
index d17a8508b..68a25df90 100644
--- a/src/starter/starterstroke.c
+++ b/src/starter/starterstroke.c
@@ -159,7 +159,7 @@ int starter_stroke_del_conn(starter_conn_t *conn)
msg.type = STR_DEL_CONN;
msg.length = offsetof(stroke_msg_t, buffer);
- msg.install.name = push_string(&msg, connection_name(conn));
+ msg.del_conn.name = push_string(&msg, connection_name(conn));
return send_stroke_msg(&msg);
}
@@ -167,9 +167,9 @@ int starter_stroke_route_conn(starter_conn_t *conn)
{
stroke_msg_t msg;
- msg.type = STR_INSTALL;
+ msg.type = STR_ROUTE;
msg.length = offsetof(stroke_msg_t, buffer);
- msg.install.name = push_string(&msg, connection_name(conn));
+ msg.route.name = push_string(&msg, connection_name(conn));
return send_stroke_msg(&msg);
}
diff --git a/src/stroke/stroke.c b/src/stroke/stroke.c
index 15661a2ec..e29a58813 100644
--- a/src/stroke/stroke.c
+++ b/src/stroke/stroke.c
@@ -169,6 +169,26 @@ static int terminate_connection(char *name)
return send_stroke_msg(&msg);
}
+static int route_connection(char *name)
+{
+ stroke_msg_t msg;
+
+ msg.type = STR_ROUTE;
+ msg.length = offsetof(stroke_msg_t, buffer);
+ msg.route.name = push_string(&msg, name);
+ return send_stroke_msg(&msg);
+}
+
+static int unroute_connection(char *name)
+{
+ stroke_msg_t msg;
+
+ msg.type = STR_UNROUTE;
+ msg.length = offsetof(stroke_msg_t, buffer);
+ msg.unroute.name = push_string(&msg, name);
+ return send_stroke_msg(&msg);
+}
+
static int show_status(stroke_keyword_t kw, char *connection)
{
stroke_msg_t msg;
@@ -336,6 +356,20 @@ int main(int argc, char *argv[])
}
res = terminate_connection(argv[2]);
break;
+ case STROKE_ROUTE:
+ if (argc < 3)
+ {
+ exit_usage("\"route\" needs a connection name");
+ }
+ res = route_connection(argv[2]);
+ break;
+ case STROKE_UNROUTE:
+ if (argc < 3)
+ {
+ exit_usage("\"unroute\" needs a connection name");
+ }
+ res = unroute_connection(argv[2]);
+ break;
case STROKE_LOGTYPE:
if (argc < 5)
{
diff --git a/src/stroke/stroke.h b/src/stroke/stroke.h
index 9aa4de35f..b71e19921 100644
--- a/src/stroke/stroke.h
+++ b/src/stroke/stroke.h
@@ -99,8 +99,10 @@ struct stroke_msg_t {
enum {
/* initiate a connection */
STR_INITIATE,
- /* install SPD entries for a connection */
- STR_INSTALL,
+ /* install SPD entries for a policy */
+ STR_ROUTE,
+ /* uninstall SPD entries for a policy */
+ STR_UNROUTE,
/* add a connection */
STR_ADD_CONN,
/* delete a connection */
@@ -123,10 +125,10 @@ struct stroke_msg_t {
} type;
union {
- /* data for STR_INITIATE, STR_INSTALL, STR_UP, STR_DOWN, ... */
+ /* data for STR_INITIATE, STR_ROUTE, STR_UP, STR_DOWN, ... */
struct {
char *name;
- } initiate, install, terminate, status, del_conn;
+ } initiate, route, unroute, terminate, status, del_conn;
/* data for STR_ADD_CONN */
struct {
diff --git a/src/stroke/stroke_keywords.h b/src/stroke/stroke_keywords.h
index c40bed3af..6a8dd5359 100644
--- a/src/stroke/stroke_keywords.h
+++ b/src/stroke/stroke_keywords.h
@@ -23,6 +23,7 @@ typedef enum {
STROKE_DEL,
STROKE_DELETE,
STROKE_ROUTE,
+ STROKE_UNROUTE,
STROKE_UP,
STROKE_DOWN,
STROKE_LOGTYPE,
diff --git a/src/stroke/stroke_keywords.txt b/src/stroke/stroke_keywords.txt
index 9b380ae66..d720a7d3a 100644
--- a/src/stroke/stroke_keywords.txt
+++ b/src/stroke/stroke_keywords.txt
@@ -30,6 +30,7 @@ add, STROKE_ADD
del, STROKE_DEL
delete, STROKE_DELETE
route, STROKE_ROUTE
+unroute, STROKE_UNROUTE
up, STROKE_UP
down, STROKE_DOWN
logtype, STROKE_LOGTYPE