diff options
author | Martin Willi <martin@revosec.ch> | 2014-10-23 15:42:21 +0200 |
---|---|---|
committer | Martin Willi <martin@revosec.ch> | 2015-02-20 13:34:49 +0100 |
commit | e732fb11a915b5e760a8c1fbd1a5f12581912787 (patch) | |
tree | 3072c8bac606ae2b354ba6180e0b4cf242c3d490 /src | |
parent | 85b238887d01c030a7d9240db2031601211a6283 (diff) | |
download | strongswan-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.mk | 2 | ||||
-rw-r--r-- | src/libcharon/Makefile.am | 1 | ||||
-rw-r--r-- | src/libcharon/daemon.c | 2 | ||||
-rw-r--r-- | src/libcharon/daemon.h | 6 | ||||
-rw-r--r-- | src/libcharon/sa/child_sa_manager.c | 333 | ||||
-rw-r--r-- | src/libcharon/sa/child_sa_manager.h | 89 |
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, ¤t)) + { + 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_ @}*/ |