aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMartin Willi <martin@revosec.ch>2014-10-23 15:42:21 +0200
committerMartin Willi <martin@revosec.ch>2015-02-20 13:34:49 +0100
commite732fb11a915b5e760a8c1fbd1a5f12581912787 (patch)
tree3072c8bac606ae2b354ba6180e0b4cf242c3d490 /src
parent85b238887d01c030a7d9240db2031601211a6283 (diff)
downloadstrongswan-e732fb11a915b5e760a8c1fbd1a5f12581912787.tar.bz2
strongswan-e732fb11a915b5e760a8c1fbd1a5f12581912787.tar.xz
child-sa-manager: Add a global manager storing CHILD_SA relations
To quickly check out IKE_SAs and find associated CHILD_SAs, the child_sa_manager stores relations between CHILD_SAs and IKE_SAs. It provides CHILD_SA specific IKE_SA checkout functions wrapping the ike_sa_manager.
Diffstat (limited to 'src')
-rw-r--r--src/libcharon/Android.mk2
-rw-r--r--src/libcharon/Makefile.am1
-rw-r--r--src/libcharon/daemon.c2
-rw-r--r--src/libcharon/daemon.h6
-rw-r--r--src/libcharon/sa/child_sa_manager.c333
-rw-r--r--src/libcharon/sa/child_sa_manager.h89
6 files changed, 432 insertions, 1 deletions
diff --git a/src/libcharon/Android.mk b/src/libcharon/Android.mk
index 4212ee87a..ab71d4016 100644
--- a/src/libcharon/Android.mk
+++ b/src/libcharon/Android.mk
@@ -72,6 +72,7 @@ sa/ike_sa.c sa/ike_sa.h \
sa/ike_sa_id.c sa/ike_sa_id.h \
sa/keymat.h sa/keymat.c \
sa/ike_sa_manager.c sa/ike_sa_manager.h \
+sa/child_sa_manager.c sa/child_sa_manager.h \
sa/task_manager.h sa/task_manager.c \
sa/shunt_manager.c sa/shunt_manager.h \
sa/trap_manager.c sa/trap_manager.h \
@@ -238,4 +239,3 @@ LOCAL_PRELINK_MODULE := false
LOCAL_SHARED_LIBRARIES += libstrongswan libhydra
include $(BUILD_SHARED_LIBRARY)
-
diff --git a/src/libcharon/Makefile.am b/src/libcharon/Makefile.am
index e98f5e137..e666950f1 100644
--- a/src/libcharon/Makefile.am
+++ b/src/libcharon/Makefile.am
@@ -70,6 +70,7 @@ sa/ike_sa.c sa/ike_sa.h \
sa/ike_sa_id.c sa/ike_sa_id.h \
sa/keymat.h sa/keymat.c \
sa/ike_sa_manager.c sa/ike_sa_manager.h \
+sa/child_sa_manager.c sa/child_sa_manager.h \
sa/task_manager.h sa/task_manager.c \
sa/shunt_manager.c sa/shunt_manager.h \
sa/trap_manager.c sa/trap_manager.h \
diff --git a/src/libcharon/daemon.c b/src/libcharon/daemon.c
index 3ae7c4e6f..f3859f912 100644
--- a/src/libcharon/daemon.c
+++ b/src/libcharon/daemon.c
@@ -480,6 +480,7 @@ static void destroy(private_daemon_t *this)
DESTROY_IF(this->kernel_handler);
DESTROY_IF(this->public.traps);
DESTROY_IF(this->public.shunts);
+ DESTROY_IF(this->public.child_sa_manager);
DESTROY_IF(this->public.ike_sa_manager);
DESTROY_IF(this->public.controller);
DESTROY_IF(this->public.eap);
@@ -606,6 +607,7 @@ METHOD(daemon_t, initialize, bool,
{
return FALSE;
}
+ this->public.child_sa_manager = child_sa_manager_create();
/* Queue start_action job */
lib->processor->queue_job(lib->processor, (job_t*)start_action_job_create());
diff --git a/src/libcharon/daemon.h b/src/libcharon/daemon.h
index 36242bb04..8ec1ec253 100644
--- a/src/libcharon/daemon.h
+++ b/src/libcharon/daemon.h
@@ -158,6 +158,7 @@ typedef struct daemon_t daemon_t;
#include <control/controller.h>
#include <bus/bus.h>
#include <sa/ike_sa_manager.h>
+#include <sa/child_sa_manager.h>
#include <sa/trap_manager.h>
#include <sa/shunt_manager.h>
#include <config/backend_manager.h>
@@ -215,6 +216,11 @@ struct daemon_t {
ike_sa_manager_t *ike_sa_manager;
/**
+ * A child_sa_manager_t instance.
+ */
+ child_sa_manager_t *child_sa_manager;
+
+ /**
* Manager for triggering policies, called traps
*/
trap_manager_t *traps;
diff --git a/src/libcharon/sa/child_sa_manager.c b/src/libcharon/sa/child_sa_manager.c
new file mode 100644
index 000000000..071a119da
--- /dev/null
+++ b/src/libcharon/sa/child_sa_manager.c
@@ -0,0 +1,333 @@
+/*
+ * Copyright (C) 2014 Martin Willi
+ * Copyright (C) 2014 revosec AG
+ *
+ * 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_sa_manager.h"
+
+#include <daemon.h>
+#include <threading/mutex.h>
+#include <collections/hashtable.h>
+
+typedef struct private_child_sa_manager_t private_child_sa_manager_t;
+
+/**
+ * Private data of an child_sa_manager_t object.
+ */
+struct private_child_sa_manager_t {
+
+ /**
+ * Public child_sa_manager_t interface.
+ */
+ child_sa_manager_t public;
+
+ /**
+ * CHILD_SAs by inbound SPI/dst, child_entry_t => child_entry_t
+ */
+ hashtable_t *in;
+
+ /**
+ * CHILD_SAs by outbound SPI/dst, child_entry_t => child_entry_t
+ */
+ hashtable_t *out;
+
+ /**
+ * CHILD_SAs by unique ID, child_entry_t => child_entry_t
+ */
+ hashtable_t *ids;
+
+ /**
+ * Mutex to access any hashtable
+ */
+ mutex_t *mutex;
+};
+
+/**
+ * Hashtable entry for a known CHILD_SA
+ */
+typedef struct {
+ /** the associated IKE_SA */
+ ike_sa_id_t *ike_id;
+ /** unique CHILD_SA identifier */
+ u_int32_t unique_id;
+ /** inbound SPI */
+ u_int32_t spi_in;
+ /** outbound SPI */
+ u_int32_t spi_out;
+ /** inbound host address */
+ host_t *host_in;
+ /** outbound host address and port */
+ host_t *host_out;
+ /** IPsec protocol, AH|ESP */
+ protocol_id_t proto;
+} child_entry_t;
+
+/**
+ * Destroy a CHILD_SA entry
+ */
+static void child_entry_destroy(child_entry_t *entry)
+{
+ entry->ike_id->destroy(entry->ike_id);
+ entry->host_in->destroy(entry->host_in);
+ entry->host_out->destroy(entry->host_out);
+ free(entry);
+}
+
+/**
+ * Hashtable hash function for inbound SAs
+ */
+static u_int hash_in(child_entry_t *entry)
+{
+ return chunk_hash_inc(chunk_from_thing(entry->spi_in),
+ chunk_hash_inc(entry->host_in->get_address(entry->host_in),
+ chunk_hash(chunk_from_thing(entry->proto))));
+}
+
+/**
+ * Hashtable equals function for inbound SAs
+ */
+static bool equals_in(child_entry_t *a, child_entry_t *b)
+{
+ return a->spi_in == b->spi_in &&
+ a->proto == b->proto &&
+ a->host_in->ip_equals(a->host_in, b->host_in);
+}
+
+/**
+ * Hashtable hash function for outbound SAs
+ */
+static u_int hash_out(child_entry_t *entry)
+{
+ return chunk_hash_inc(chunk_from_thing(entry->spi_out),
+ chunk_hash_inc(entry->host_out->get_address(entry->host_out),
+ chunk_hash(chunk_from_thing(entry->proto))));
+}
+
+/**
+ * Hashtable equals function for outbound SAs
+ */
+static bool equals_out(child_entry_t *a, child_entry_t *b)
+{
+ return a->spi_out == b->spi_out &&
+ a->proto == b->proto &&
+ a->host_out->ip_equals(a->host_out, b->host_out);
+}
+
+/**
+ * Hashtable hash function for SAs by unique ID
+ */
+static u_int hash_id(child_entry_t *entry)
+{
+ return chunk_hash(chunk_from_thing(entry->unique_id));
+}
+
+/**
+ * Hashtable equals function for SAs by unique ID
+ */
+static bool equals_id(child_entry_t *a, child_entry_t *b)
+{
+ return a->unique_id == b->unique_id;
+}
+
+METHOD(child_sa_manager_t, add, void,
+ private_child_sa_manager_t *this, child_sa_t *child_sa, ike_sa_t *ike_sa)
+{
+ child_entry_t *entry;
+ host_t *in, *out;
+ ike_sa_id_t *id;
+
+ id = ike_sa->get_id(ike_sa);
+ in = ike_sa->get_my_host(ike_sa);
+ out = ike_sa->get_other_host(ike_sa);
+
+ INIT(entry,
+ .ike_id = id->clone(id),
+ .unique_id = child_sa->get_unique_id(child_sa),
+ .proto = child_sa->get_protocol(child_sa),
+ .spi_in = child_sa->get_spi(child_sa, TRUE),
+ .spi_out = child_sa->get_spi(child_sa, FALSE),
+ .host_in = in->clone(in),
+ .host_out = out->clone(out),
+ );
+
+ this->mutex->lock(this->mutex);
+ if (!this->in->get(this->in, entry) &&
+ !this->out->get(this->out, entry))
+ {
+ this->in->put(this->in, entry, entry);
+ this->out->put(this->out, entry, entry);
+ entry = this->ids->put(this->ids, entry, entry);
+ }
+ this->mutex->unlock(this->mutex);
+
+ if (entry)
+ {
+ child_entry_destroy(entry);
+ }
+}
+
+METHOD(child_sa_manager_t, remove_, void,
+ private_child_sa_manager_t *this, child_sa_t *child_sa)
+{
+ child_entry_t *entry, key = {
+ .unique_id = child_sa->get_unique_id(child_sa),
+ };
+
+ this->mutex->lock(this->mutex);
+ entry = this->ids->remove(this->ids, &key);
+ if (entry)
+ {
+ this->in->remove(this->in, entry);
+ this->out->remove(this->out, entry);
+ }
+ this->mutex->unlock(this->mutex);
+
+ if (entry)
+ {
+ child_entry_destroy(entry);
+ }
+}
+
+/**
+ * Check out an IKE_SA for a given CHILD_SA
+ */
+static ike_sa_t *checkout_ikesa(private_child_sa_manager_t *this,
+ ike_sa_id_t *id, u_int32_t unique_id, child_sa_t **child_sa)
+{
+ enumerator_t *enumerator;
+ child_sa_t *current;
+ ike_sa_t *ike_sa;
+ bool found = FALSE;
+
+ ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager, id);
+ id->destroy(id);
+ if (ike_sa)
+ {
+ enumerator = ike_sa->create_child_sa_enumerator(ike_sa);
+ while (enumerator->enumerate(enumerator, &current))
+ {
+ found = current->get_unique_id(current) == unique_id;
+ if (found)
+ {
+ if (child_sa)
+ {
+ *child_sa = current;
+ }
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+
+ if (found)
+ {
+ return ike_sa;
+ }
+ charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
+ }
+ return NULL;
+}
+
+METHOD(child_sa_manager_t, checkout_by_id, ike_sa_t*,
+ private_child_sa_manager_t *this, u_int32_t unique_id,
+ child_sa_t **child_sa)
+{
+ ike_sa_id_t *id;
+ child_entry_t *entry, key = {
+ .unique_id = unique_id,
+ };
+
+ this->mutex->lock(this->mutex);
+ entry = this->ids->get(this->ids, &key);
+ if (entry)
+ {
+ id = entry->ike_id->clone(entry->ike_id);
+ }
+ this->mutex->unlock(this->mutex);
+
+ if (entry)
+ {
+ return checkout_ikesa(this, id, unique_id, child_sa);
+ }
+ return NULL;
+}
+
+METHOD(child_sa_manager_t, checkout, ike_sa_t*,
+ private_child_sa_manager_t *this, protocol_id_t protocol, u_int32_t spi,
+ host_t *dst, child_sa_t **child_sa)
+{
+ ike_sa_id_t *id;
+ u_int32_t unique_id;
+ child_entry_t *entry, key = {
+ .spi_in = spi,
+ .spi_out = spi,
+ .host_in = dst,
+ .host_out = dst,
+ .proto = protocol,
+ };
+
+ this->mutex->lock(this->mutex);
+ entry = this->in->get(this->in, &key);
+ if (!entry)
+ {
+ entry = this->out->get(this->out, &key);
+ }
+ if (entry)
+ {
+ unique_id = entry->unique_id;
+ id = entry->ike_id->clone(entry->ike_id);
+ }
+ this->mutex->unlock(this->mutex);
+
+ if (entry)
+ {
+ return checkout_ikesa(this, id, unique_id, child_sa);
+ }
+ return NULL;
+}
+
+METHOD(child_sa_manager_t, destroy, void,
+ private_child_sa_manager_t *this)
+{
+ this->in->destroy(this->in);
+ this->out->destroy(this->out);
+ this->ids->destroy(this->ids);
+ this->mutex->destroy(this->mutex);
+ free(this);
+}
+
+/**
+ * See header
+ */
+child_sa_manager_t *child_sa_manager_create()
+{
+ private_child_sa_manager_t *this;
+
+ INIT(this,
+ .public = {
+ .add = _add,
+ .remove = _remove_,
+ .checkout = _checkout,
+ .checkout_by_id = _checkout_by_id,
+ .destroy = _destroy,
+ },
+ .in = hashtable_create((hashtable_hash_t)hash_in,
+ (hashtable_equals_t)equals_in, 8),
+ .out = hashtable_create((hashtable_hash_t)hash_out,
+ (hashtable_equals_t)equals_out, 8),
+ .ids = hashtable_create((hashtable_hash_t)hash_id,
+ (hashtable_equals_t)equals_id, 8),
+ .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
+ );
+
+ return &this->public;
+}
diff --git a/src/libcharon/sa/child_sa_manager.h b/src/libcharon/sa/child_sa_manager.h
new file mode 100644
index 000000000..4d57528e8
--- /dev/null
+++ b/src/libcharon/sa/child_sa_manager.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2014 Martin Willi
+ * Copyright (C) 2014 revosec AG
+ *
+ * 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.
+ */
+
+/**
+ * @defgroup child_sa_manager child_sa_manager
+ * @{ @ingroup sa
+ */
+
+#ifndef CHILD_SA_MANAGER_H_
+#define CHILD_SA_MANAGER_H_
+
+#include <sa/ike_sa.h>
+#include <sa/child_sa.h>
+
+typedef struct child_sa_manager_t child_sa_manager_t;
+
+/**
+ * Handle CHILD_SA to IKE_SA relations
+ */
+struct child_sa_manager_t {
+
+ /**
+ * Register a CHILD_SA/IKE_SA relation.
+ *
+ * @param child_sa CHILD_SA to register
+ * @param ike_sa IKE_SA owning the CHILD_SA
+ */
+ void (*add)(child_sa_manager_t *this, child_sa_t *child_sa, ike_sa_t *ike_sa);
+
+ /**
+ * Unregister a CHILD_SA/IKE_SA relation.
+ *
+ * @param child_sa CHILD_SA to unregister
+ */
+ void (*remove)(child_sa_manager_t *this, child_sa_t *child_sa);
+
+ /**
+ * Find a CHILD_SA and check out the associated IKE_SA by SPI.
+ *
+ * On success, the returned IKE_SA must be checked in after use to
+ * the IKE_SA manager.
+ *
+ * @param protocol IPsec protocol, AH|ESP
+ * @param spi SPI of CHILD_SA to check out
+ * @param dst SA destination host related to SPI
+ * @param child_sa returns CHILD_SA managed by IKE_SA
+ * @return IKE_SA, NULL if not found
+ */
+ ike_sa_t *(*checkout)(child_sa_manager_t *this,
+ protocol_id_t protocol, u_int32_t spi, host_t *dst,
+ child_sa_t **child_sa);
+
+ /**
+ * Find a CHILD_SA and check out the associated IKE_SA by unique_id.
+ *
+ * On success, the returned IKE_SA must be checked in after use to
+ * the IKE_SA manager.
+ *
+ * @param unique_id unique ID of CHILD_SA to check out
+ * @param child_sa returns CHILD_SA managed by IKE_SA
+ * @return IKE_SA, NULL if not found
+ */
+ ike_sa_t *(*checkout_by_id)(child_sa_manager_t *this, u_int32_t unique_id,
+ child_sa_t **child_sa);
+
+ /**
+ * Destroy a child_sa_manager_t.
+ */
+ void (*destroy)(child_sa_manager_t *this);
+};
+
+/**
+ * Create a child_sa_manager instance.
+ */
+child_sa_manager_t *child_sa_manager_create();
+
+#endif /** CHILD_SA_MANAGER_H_ @}*/