aboutsummaryrefslogtreecommitdiffstats
path: root/src/libipsec
diff options
context:
space:
mode:
authorTobias Brunner <tobias@strongswan.org>2012-07-13 13:21:45 +0200
committerTobias Brunner <tobias@strongswan.org>2012-08-08 15:41:03 +0200
commit914479370ed23aa420a15ef3f19c2c39dce3b133 (patch)
tree4f62f594f23065f6a8e2803732a1f8de3b8f44f2 /src/libipsec
parent9f7e1899a90c2ffbdbac626d4d58945460eca97c (diff)
downloadstrongswan-914479370ed23aa420a15ef3f19c2c39dce3b133.tar.bz2
strongswan-914479370ed23aa420a15ef3f19c2c39dce3b133.tar.xz
Added IPsec SA manager
Diffstat (limited to 'src/libipsec')
-rw-r--r--src/libipsec/Android.mk3
-rw-r--r--src/libipsec/Makefile.am3
-rw-r--r--src/libipsec/ipsec.c10
-rw-r--r--src/libipsec/ipsec.h11
-rw-r--r--src/libipsec/ipsec_sa_mgr.c314
-rw-r--r--src/libipsec/ipsec_sa_mgr.h124
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**)&current))
+ {
+ 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**)&current))
+ {
+ 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**)&current))
+ {
+ 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_ @}*/