diff options
author | Tobias Brunner <tobias@strongswan.org> | 2012-07-13 13:21:45 +0200 |
---|---|---|
committer | Tobias Brunner <tobias@strongswan.org> | 2012-08-08 15:41:03 +0200 |
commit | 914479370ed23aa420a15ef3f19c2c39dce3b133 (patch) | |
tree | 4f62f594f23065f6a8e2803732a1f8de3b8f44f2 /src/libipsec | |
parent | 9f7e1899a90c2ffbdbac626d4d58945460eca97c (diff) | |
download | strongswan-914479370ed23aa420a15ef3f19c2c39dce3b133.tar.bz2 strongswan-914479370ed23aa420a15ef3f19c2c39dce3b133.tar.xz |
Added IPsec SA manager
Diffstat (limited to 'src/libipsec')
-rw-r--r-- | src/libipsec/Android.mk | 3 | ||||
-rw-r--r-- | src/libipsec/Makefile.am | 3 | ||||
-rw-r--r-- | src/libipsec/ipsec.c | 10 | ||||
-rw-r--r-- | src/libipsec/ipsec.h | 11 | ||||
-rw-r--r-- | src/libipsec/ipsec_sa_mgr.c | 314 | ||||
-rw-r--r-- | src/libipsec/ipsec_sa_mgr.h | 124 |
6 files changed, 458 insertions, 7 deletions
diff --git a/src/libipsec/Android.mk b/src/libipsec/Android.mk index 2c1c1cc93..a5d93dfc3 100644 --- a/src/libipsec/Android.mk +++ b/src/libipsec/Android.mk @@ -6,7 +6,8 @@ LOCAL_SRC_FILES := \ ipsec.c ipsec.h \ esp_context.c esp_context.h \ esp_packet.c esp_packet.h \ -ipsec_sa.c ipsec_sa.h +ipsec_sa.c ipsec_sa.h \ +ipsec_sa_mgr.c ipsec_sa_mgr.h # build libipsec --------------------------------------------------------------- diff --git a/src/libipsec/Makefile.am b/src/libipsec/Makefile.am index 655849632..3de8f82bc 100644 --- a/src/libipsec/Makefile.am +++ b/src/libipsec/Makefile.am @@ -4,7 +4,8 @@ libipsec_la_SOURCES = \ ipsec.c ipsec.h \ esp_context.c esp_context.h \ esp_packet.c esp_packet.h \ -ipsec_sa.c ipsec_sa.h +ipsec_sa.c ipsec_sa.h \ +ipsec_sa_mgr.c ipsec_sa_mgr.h libipsec_la_LIBADD = diff --git a/src/libipsec/ipsec.c b/src/libipsec/ipsec.c index add3b463a..5ae6c74aa 100644 --- a/src/libipsec/ipsec.c +++ b/src/libipsec/ipsec.c @@ -1,4 +1,6 @@ /* + * Copyright (C) 2012 Giuliano Grassi + * Copyright (C) 2012 Ralf Sager * Copyright (C) 2012 Tobias Brunner * Hochschule fuer Technik Rapperswil * @@ -41,6 +43,7 @@ ipsec_t *ipsec; void libipsec_deinit() { private_ipsec_t *this = (private_ipsec_t*)ipsec; + DESTROY_IF(this->public.sas); free(this); ipsec = NULL; } @@ -52,10 +55,7 @@ bool libipsec_init() { private_ipsec_t *this; - INIT(this, - .public = { - }, - ); + INIT(this); ipsec = &this->public; if (lib->integrity && @@ -64,6 +64,8 @@ bool libipsec_init() DBG1(DBG_LIB, "integrity check of libipsec failed"); return FALSE; } + + this->public.sas = ipsec_sa_mgr_create(); return TRUE; } diff --git a/src/libipsec/ipsec.h b/src/libipsec/ipsec.h index 80bef5426..e4055a8bd 100644 --- a/src/libipsec/ipsec.h +++ b/src/libipsec/ipsec.h @@ -1,4 +1,6 @@ /* + * Copyright (C) 2012 Giuliano Grassi + * Copyright (C) 2012 Ralf Sager * Copyright (C) 2012 Tobias Brunner * Hochschule fuer Technik Rapperswil * @@ -23,15 +25,22 @@ #ifndef IPSEC_H_ #define IPSEC_H_ -typedef struct ipsec_t ipsec_t; +#include "ipsec_sa_mgr.h" #include <library.h> +typedef struct ipsec_t ipsec_t; + /** * User space IPsec implementation. */ struct ipsec_t { + /** + * IPsec SA manager instance + */ + ipsec_sa_mgr_t *sas; + }; /** diff --git a/src/libipsec/ipsec_sa_mgr.c b/src/libipsec/ipsec_sa_mgr.c new file mode 100644 index 000000000..74fb2ac7e --- /dev/null +++ b/src/libipsec/ipsec_sa_mgr.c @@ -0,0 +1,314 @@ +/* + * Copyright (C) 2012 Tobias Brunner + * Copyright (C) 2012 Giuliano Grassi + * Copyright (C) 2012 Ralf Sager + * 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 "ipsec_sa_mgr.h" + +#include <debug.h> +#include <library.h> +#include <threading/mutex.h> +#include <utils/hashtable.h> +#include <utils/linked_list.h> + +typedef struct private_ipsec_sa_mgr_t private_ipsec_sa_mgr_t; + +/** + * Private additions to ipsec_sa_mgr_t. + */ +struct private_ipsec_sa_mgr_t { + + /** + * Public members of ipsec_sa_mgr_t. + */ + ipsec_sa_mgr_t public; + + /** + * Installed SAs + */ + linked_list_t *sas; + + /** + * SPIs allocated using get_spi() + */ + hashtable_t *allocated_spis; + + /** + * Mutex used to synchronize access to the SA manager + */ + mutex_t *mutex; + + /** + * RNG used to generate SPIs + */ + rng_t *rng; +}; + +/* + * Used for the hash table of allocated SPIs + */ +static bool spi_equals(u_int32_t *spi, u_int32_t *other_spi) +{ + return *spi == *other_spi; +} + +static u_int spi_hash(u_int32_t *spi) +{ + return chunk_hash(chunk_from_thing(*spi)); +} + +/** + * Flushes all entries + * Must be called with this->mutex held. + */ +static void flush_entries(private_ipsec_sa_mgr_t *this) +{ + enumerator_t *enumerator; + ipsec_sa_t *current; + + DBG2(DBG_ESP, "flushing SAD"); + + enumerator = this->sas->create_enumerator(this->sas); + while (enumerator->enumerate(enumerator, (void**)¤t)) + { + this->sas->remove_at(this->sas, enumerator); + current->destroy(current); + } + enumerator->destroy(enumerator); +} + +/* + * Different match functions to find SAs in the linked list + */ +static bool match_entry_by_spi_inbound(ipsec_sa_t *sa, u_int32_t spi, + bool inbound) +{ + return sa->get_spi(sa) == spi && sa->is_inbound(sa) == inbound; +} + +static bool match_entry_by_spi_src_dst(ipsec_sa_t *sa, u_int32_t spi, + host_t *src, host_t *dst) +{ + return sa->match_by_spi_src_dst(sa, spi, src, dst); +} + +/** + * Remove all allocated SPIs + */ +static void flush_allocated_spis(private_ipsec_sa_mgr_t *this) +{ + enumerator_t *enumerator; + u_int32_t *current; + + DBG2(DBG_ESP, "flushing allocated SPIs"); + enumerator = this->allocated_spis->create_enumerator(this->allocated_spis); + while (enumerator->enumerate(enumerator, NULL, (void**)¤t)) + { + this->allocated_spis->remove_at(this->allocated_spis, enumerator); + DBG2(DBG_ESP, " removed allocated SPI %.8x", ntohl(*current)); + free(current); + } + enumerator->destroy(enumerator); +} + +/** + * Pre-allocate an SPI for an inbound SA + */ +static bool allocate_spi(private_ipsec_sa_mgr_t *this, u_int32_t spi) +{ + u_int32_t *spi_alloc; + + if (this->allocated_spis->get(this->allocated_spis, &spi) || + this->sas->find_first(this->sas, (void*)match_entry_by_spi_inbound, + NULL, spi, TRUE) == SUCCESS) + { + return FALSE; + } + spi_alloc = malloc_thing(u_int32_t); + *spi_alloc = spi; + this->allocated_spis->put(this->allocated_spis, spi_alloc, spi_alloc); + return TRUE; +} + +METHOD(ipsec_sa_mgr_t, get_spi, status_t, + private_ipsec_sa_mgr_t *this, host_t *src, host_t *dst, u_int8_t protocol, + u_int32_t reqid, u_int32_t *spi) +{ + u_int32_t spi_new; + + DBG2(DBG_ESP, "allocating SPI for reqid {%u}", reqid); + + this->mutex->lock(this->mutex); + if (!this->rng) + { + this->rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK); + if (!this->rng) + { + this->mutex->unlock(this->mutex); + DBG1(DBG_ESP, "failed to create RNG for SPI generation"); + return FAILED; + } + } + + do + { + if (!this->rng->get_bytes(this->rng, sizeof(spi_new), + (u_int8_t*)&spi_new)) + { + this->mutex->unlock(this->mutex); + DBG1(DBG_ESP, "failed to allocate SPI for reqid {%u}", reqid); + return FAILED; + } + /* make sure the SPI is valid (not in range 0-255) */ + spi_new |= 0x00000100; + spi_new = htonl(spi_new); + } + while (!allocate_spi(this, spi_new)); + this->mutex->unlock(this->mutex); + + *spi = spi_new; + + DBG2(DBG_ESP, "allocated SPI %.8x for reqid {%u}", ntohl(*spi), reqid); + return SUCCESS; +} + +METHOD(ipsec_sa_mgr_t, add_sa, status_t, + private_ipsec_sa_mgr_t *this, host_t *src, host_t *dst, u_int32_t spi, + u_int8_t protocol, u_int32_t reqid, mark_t mark, u_int32_t tfc, + lifetime_cfg_t *lifetime, u_int16_t enc_alg, chunk_t enc_key, + u_int16_t int_alg, chunk_t int_key, ipsec_mode_t mode, u_int16_t ipcomp, + u_int16_t cpi, bool encap, bool esn, bool inbound, + traffic_selector_t *src_ts, traffic_selector_t *dst_ts) +{ + ipsec_sa_t *sa_new; + + DBG2(DBG_ESP, "adding SAD entry with SPI %.8x and reqid {%u}", + ntohl(spi), reqid); + DBG2(DBG_ESP, " using encryption algorithm %N with key size %d", + encryption_algorithm_names, enc_alg, enc_key.len * 8); + DBG2(DBG_ESP, " using integrity algorithm %N with key size %d", + integrity_algorithm_names, int_alg, int_key.len * 8); + + sa_new = ipsec_sa_create(spi, src, dst, protocol, reqid, mark, tfc, + lifetime, enc_alg, enc_key, int_alg, int_key, mode, + ipcomp, cpi, encap, esn, inbound, src_ts, dst_ts); + if (!sa_new) + { + DBG1(DBG_ESP, "failed to create SAD entry"); + return FAILED; + } + + this->mutex->lock(this->mutex); + + if (inbound) + { /* remove any pre-allocated SPIs */ + u_int32_t *spi_alloc; + + spi_alloc = this->allocated_spis->remove(this->allocated_spis, &spi); + free(spi_alloc); + } + + if (this->sas->find_first(this->sas, (void*)match_entry_by_spi_src_dst, + NULL, spi, src, dst) == SUCCESS) + { + this->mutex->unlock(this->mutex); + DBG1(DBG_ESP, "failed to install SAD entry: already installed"); + sa_new->destroy(sa_new); + return FAILED; + } + this->sas->insert_last(this->sas, sa_new); + this->mutex->unlock(this->mutex); + return SUCCESS; +} + +METHOD(ipsec_sa_mgr_t, del_sa, status_t, + private_ipsec_sa_mgr_t *this, host_t *src, host_t *dst, u_int32_t spi, + u_int8_t protocol, u_int16_t cpi, mark_t mark) +{ + ipsec_sa_t *current, *found = NULL; + enumerator_t *enumerator; + + this->mutex->lock(this->mutex); + enumerator = this->sas->create_enumerator(this->sas); + while (enumerator->enumerate(enumerator, (void**)¤t)) + { + if (match_entry_by_spi_src_dst(current, spi, src, dst)) + { + this->sas->remove_at(this->sas, enumerator); + found = current; + break; + } + } + enumerator->destroy(enumerator); + this->mutex->unlock(this->mutex); + + if (found) + { + DBG2(DBG_ESP, "deleted %sbound SAD entry with SPI %.8x", + found->is_inbound(found) ? "in" : "out", ntohl(spi)); + found->destroy(found); + return SUCCESS; + } + return FAILED; +} + +METHOD(ipsec_sa_mgr_t, flush_sas, status_t, + private_ipsec_sa_mgr_t *this) +{ + this->mutex->lock(this->mutex); + flush_entries(this); + this->mutex->unlock(this->mutex); + return SUCCESS; +} + +METHOD(ipsec_sa_mgr_t, destroy, void, + private_ipsec_sa_mgr_t *this) +{ + this->mutex->lock(this->mutex); + flush_entries(this); + flush_allocated_spis(this); + this->mutex->unlock(this->mutex); + + this->allocated_spis->destroy(this->allocated_spis); + this->sas->destroy(this->sas); + + this->mutex->destroy(this->mutex); + DESTROY_IF(this->rng); + free(this); +} + +/** + * Described in header. + */ +ipsec_sa_mgr_t *ipsec_sa_mgr_create() +{ + private_ipsec_sa_mgr_t *this; + + INIT(this, + .public = { + .get_spi = _get_spi, + .add_sa = _add_sa, + .del_sa = _del_sa, + .flush_sas = _flush_sas, + .destroy = _destroy, + }, + .sas = linked_list_create(), + .mutex = mutex_create(MUTEX_TYPE_DEFAULT), + .allocated_spis = hashtable_create((hashtable_hash_t)spi_hash, + (hashtable_equals_t)spi_equals, 16), + ); + + return &this->public; +} diff --git a/src/libipsec/ipsec_sa_mgr.h b/src/libipsec/ipsec_sa_mgr.h new file mode 100644 index 000000000..0acb0c148 --- /dev/null +++ b/src/libipsec/ipsec_sa_mgr.h @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2012 Tobias Brunner + * Copyright (C) 2012 Giuliano Grassi + * Copyright (C) 2012 Ralf Sager + * 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. + */ + +/** + * @defgroup ipsec_sa_mgr ipsec_sa_mgr + * @{ @ingroup libipsec + */ + +#ifndef IPSEC_SA_MGR_H_ +#define IPSEC_SA_MGR_H_ + +#include "ipsec_sa.h" + +#include <library.h> +#include <ipsec/ipsec_types.h> +#include <selectors/traffic_selector.h> +#include <utils/host.h> + +typedef struct ipsec_sa_mgr_t ipsec_sa_mgr_t; + +/** + * IPsec SA manager + * + * The first methods are modeled after those in kernel_ipsec_t. + */ +struct ipsec_sa_mgr_t { + + /** + * Allocate an SPI for an inbound IPsec SA + * + * @param src source address of the SA + * @param dst destination address of the SA + * @param protocol protocol of the SA (only ESP supported) + * @param reqid reqid for the SA + * @param spi the allocated SPI + * @return SUCCESS of operation successful + */ + status_t (*get_spi)(ipsec_sa_mgr_t *this, host_t *src, host_t *dst, + u_int8_t protocol, u_int32_t reqid, u_int32_t *spi); + + /** + * Add a new SA + * + * @param src source address for this SA (gets cloned) + * @param dst destination address for this SA (gets cloned) + * @param spi SPI for this SA + * @param protocol protocol for this SA (only ESP is supported) + * @param reqid reqid for this SA + * @param mark mark for this SA (ignored) + * @param tfc Traffic Flow Confidentiality (not yet supported) + * @param lifetime lifetime for this SA + * @param enc_alg encryption algorithm for this SA + * @param enc_key encryption key for this SA + * @param int_alg integrity protection algorithm + * @param int_key integrity protection key + * @param mode mode for this SA (only tunnel mode is supported) + * @param ipcomp IPcomp transform (not supported, use IPCOMP_NONE) + * @param cpi CPI for IPcomp (ignored) + * @param encap enable UDP encapsulation (must be TRUE) + * @param esn Extended Sequence Numbers (currently not supported) + * @param inbound TRUE if this is an inbound SA, FALSE otherwise + * @param src_ts source traffic selector + * @param dst_ts destination traffic selector + * @return SUCCESS if operation completed + */ + status_t (*add_sa)(ipsec_sa_mgr_t *this, host_t *src, host_t *dst, + u_int32_t spi, u_int8_t protocol, u_int32_t reqid, + mark_t mark, u_int32_t tfc, lifetime_cfg_t *lifetime, + u_int16_t enc_alg, chunk_t enc_key, u_int16_t int_alg, + chunk_t int_key, ipsec_mode_t mode, u_int16_t ipcomp, + u_int16_t cpi, bool encap, bool esn, bool inbound, + traffic_selector_t *src_ts, traffic_selector_t *dst_ts); + + /** + * Delete a previously added SA + * + * @param spi SPI of the SA + * @param src source address of the SA + * @param dst destination address of the SA + * @param protocol protocol of the SA + * @param cpi CPI for IPcomp + * @param mark optional mark + * @return SUCCESS if operation completed + */ + status_t (*del_sa)(ipsec_sa_mgr_t *this, host_t *src, host_t *dst, + u_int32_t spi, u_int8_t protocol, u_int16_t cpi, + mark_t mark); + + /** + * Flush all SAs + * + * @return SUCCESS if operation completed + */ + status_t (*flush_sas)(ipsec_sa_mgr_t *this); + + /** + * Destroy an ipsec_sa_mgr_t + */ + void (*destroy)(ipsec_sa_mgr_t *this); + +}; + +/** + * Create an ipsec_sa_mgr instance + * + * @return IPsec SA manager instance + */ +ipsec_sa_mgr_t *ipsec_sa_mgr_create(); + +#endif /** IPSEC_SA_MGR_H_ @}*/ |