Implement TKM kernel SA database (SAD)
authorAdrian-Ken Rueegsegger <ken@codelabs.ch>
Fri, 14 Sep 2012 12:59:04 +0000 (14:59 +0200)
committerTobias Brunner <tobias@strongswan.org>
Tue, 19 Mar 2013 14:23:48 +0000 (15:23 +0100)
The TKM kernel SAD (security association database) stores information
about CHILD SAs.

src/charon-tkm/src/tkm/tkm_kernel_sad.c [new file with mode: 0644]
src/charon-tkm/src/tkm/tkm_kernel_sad.h [new file with mode: 0644]
src/charon-tkm/tests/kernel_sad_tests.c [new file with mode: 0644]
src/charon-tkm/tests/test_runner.c
src/charon-tkm/tests/test_runner.h

diff --git a/src/charon-tkm/src/tkm/tkm_kernel_sad.c b/src/charon-tkm/src/tkm/tkm_kernel_sad.c
new file mode 100644 (file)
index 0000000..02b6ddc
--- /dev/null
@@ -0,0 +1,250 @@
+/*
+ * Copyright (C) 2012 Reto Buerki
+ * Copyright (C) 2012 Adrian-Ken Rueegsegger
+ * 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 <collections/linked_list.h>
+#include <threading/mutex.h>
+#include <utils/debug.h>
+
+#include "tkm_kernel_sad.h"
+
+typedef struct private_tkm_kernel_sad_t private_tkm_kernel_sad_t;
+
+/**
+ * Private data of tkm_kernel_sad.
+ */
+struct private_tkm_kernel_sad_t {
+
+       /**
+        * Public functions.
+        */
+       tkm_kernel_sad_t public;
+
+       /**
+        * Linked list of SAD entries.
+        */
+       linked_list_t *data;
+
+       /**
+        * Lock used to protect SA data.
+        */
+       mutex_t *mutex;
+
+};
+
+typedef struct sad_entry_t sad_entry_t;
+
+/**
+ * Data structure holding all information of an SAD entry.
+ */
+struct sad_entry_t {
+
+       /**
+        * ESA identifier.
+        */
+       esa_id_type esa_id;
+
+       /**
+        * Source address of CHILD SA.
+        */
+       host_t *src;
+
+       /**
+        * Destination address of CHILD SA.
+        */
+       host_t *dst;
+
+       /**
+        * SPI of CHILD SA.
+        */
+       u_int32_t spi;
+
+       /**
+        * Protocol of CHILD SA (ESP/AH).
+        */
+       u_int8_t proto;
+
+};
+
+/**
+ * Destroy an sad_entry_t object.
+ */
+static void sad_entry_destroy(sad_entry_t *entry)
+{
+       if (entry)
+       {
+               DESTROY_IF(entry->src);
+               DESTROY_IF(entry->dst);
+               free(entry);
+       }
+}
+
+/**
+ * Find a list entry with given src, dst, spi and proto values.
+ */
+static bool sad_entry_match(sad_entry_t * const entry, const host_t * const src,
+                                                       const host_t * const dst, const u_int32_t * const spi,
+                                                       const u_int8_t * const proto)
+{
+       if (entry->src == NULL || entry->dst == NULL)
+       {
+               return FALSE;
+       }
+
+       return src->ip_equals(entry->src, (host_t *)src) &&
+                  dst->ip_equals(entry->dst, (host_t *)dst) &&
+                  entry->spi == *spi && entry->proto == *proto;
+}
+
+/**
+ * Compare two SAD entries for equality.
+ */
+static bool sad_entry_equal(sad_entry_t * const left, sad_entry_t * const right)
+{
+       if (left->src == NULL || left->dst == NULL || right->src == NULL ||
+               right->dst == NULL)
+       {
+               return FALSE;
+       }
+       return left->esa_id == right->esa_id &&
+                  left->src->ip_equals(left->src, right->src) &&
+                  left->dst->ip_equals(left->dst, right->dst) &&
+                  left->spi == right->spi && left->proto == right->proto;
+}
+
+METHOD(tkm_kernel_sad_t, insert, bool,
+       private_tkm_kernel_sad_t * const this, const esa_id_type esa_id,
+       const host_t * const src, const host_t * const dst, const u_int32_t spi,
+       const u_int8_t proto)
+{
+
+       sad_entry_t *new_entry;
+       INIT(new_entry,
+                .esa_id = esa_id,
+                .src = (host_t *)src,
+                .dst = (host_t *)dst,
+                .spi = spi,
+                .proto = proto,
+       );
+
+       this->mutex->lock(this->mutex);
+       const status_t result = this->data->find_first(this->data,
+                                                                                                  (linked_list_match_t)sad_entry_equal,
+                                                                                                  NULL, new_entry);
+       if (result == NOT_FOUND)
+       {
+               DBG3(DBG_KNL, "inserting SAD entry (esa: %llu, src: %H, dst: %H, "
+                        "spi: %x, proto: %u)", esa_id, src, dst, ntohl(spi), proto);
+               new_entry->src = src->clone((host_t *)src);
+               new_entry->dst = dst->clone((host_t *)dst);
+               this->data->insert_last(this->data, new_entry);
+       }
+       else
+       {
+               DBG1(DBG_KNL, "SAD entry with esa id %llu already exists!", esa_id);
+               free(new_entry);
+       }
+       this->mutex->unlock(this->mutex);
+       return result == NOT_FOUND;
+}
+
+METHOD(tkm_kernel_sad_t, get_esa_id, esa_id_type,
+       private_tkm_kernel_sad_t * const this, const host_t * const src,
+       const host_t * const dst, const u_int32_t spi, const u_int8_t proto)
+{
+       esa_id_type id = 0;
+       sad_entry_t *entry = NULL;
+
+       this->mutex->lock(this->mutex);
+       const status_t res = this->data->find_first(this->data,
+                                                                                               (linked_list_match_t)sad_entry_match,
+                                                                                               (void**)&entry, src, dst, &spi,
+                                                                                               &proto);
+       if (res == SUCCESS && entry)
+       {
+               id = entry->esa_id;
+               DBG3(DBG_KNL, "getting ESA id of SAD entry (esa: %llu, src: %H, "
+                        "dst: %H, spi: %x, proto: %u)", id, src, dst, ntohl(spi),
+                        proto);
+       }
+       else
+       {
+               DBG3(DBG_KNL, "no SAD entry found");
+       }
+       this->mutex->unlock(this->mutex);
+       return id;
+}
+
+METHOD(tkm_kernel_sad_t, _remove, bool,
+       private_tkm_kernel_sad_t * const this, const esa_id_type esa_id)
+{
+       sad_entry_t *current;
+       bool removed = FALSE;
+       this->mutex->lock(this->mutex);
+       enumerator_t *enumerator = this->data->create_enumerator(this->data);
+       while (enumerator->enumerate(enumerator, (void **)&current))
+       {
+               if (current->esa_id == esa_id)
+               {
+                       this->data->remove_at(this->data, enumerator);
+                       sad_entry_destroy(current);
+                       removed = TRUE;
+                       break;
+               }
+       }
+       enumerator->destroy(enumerator);
+
+       if (removed)
+       {
+               DBG3(DBG_KNL, "removed SAD entry (esa: %llu)", esa_id);
+       }
+       else
+       {
+               DBG1(DBG_KNL, "no SAD entry with ESA id %llu found!", esa_id);
+       }
+       this->mutex->unlock(this->mutex);
+
+       return removed;
+}
+
+
+METHOD(tkm_kernel_sad_t, destroy, void,
+       private_tkm_kernel_sad_t *this)
+{
+       this->mutex->destroy(this->mutex);
+       this->data->destroy_function(this->data, (void*)sad_entry_destroy);
+       free(this);
+}
+
+/*
+ * see header file
+ */
+tkm_kernel_sad_t *tkm_kernel_sad_create()
+{
+       private_tkm_kernel_sad_t *this;
+
+       INIT(this,
+               .public = {
+                       .insert = _insert,
+                       .get_esa_id = _get_esa_id,
+                       .remove = __remove,
+                       .destroy = _destroy,
+               },
+               .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
+               .data = linked_list_create(),
+       );
+
+       return &this->public;
+}
diff --git a/src/charon-tkm/src/tkm/tkm_kernel_sad.h b/src/charon-tkm/src/tkm/tkm_kernel_sad.h
new file mode 100644 (file)
index 0000000..6863584
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2012 Reto Buerki
+ * Copyright (C) 2012 Adrian-Ken Rueegsegger
+ * 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 TKM_KERNEL_SAD_H_
+#define TKM_KERNEL_SAD_H_
+
+#include <networking/host.h>
+#include <tkm/types.h>
+
+typedef struct tkm_kernel_sad_t tkm_kernel_sad_t;
+
+/**
+ * The TKM kernel SAD (security association database) stores information about
+ * CHILD SAs.
+ */
+struct tkm_kernel_sad_t {
+
+       /**
+        * Insert new SAD entry with specified parameters.
+        *
+        * @param esa_id                ESP SA context identifier
+        * @param src                   source address of CHILD SA
+        * @param dst                   destination address of CHILD SA
+        * @param spi                   SPI of CHILD SA
+        * @param proto                 protocol of CHILD SA (ESP/AH)
+        * @return                              TRUE if entry was inserted, FALSE otherwise
+        */
+       bool (*insert)(tkm_kernel_sad_t * const this, const esa_id_type esa_id,
+                                  const host_t * const src, const host_t * const dst,
+                                  const u_int32_t spi, const u_int8_t proto);
+
+       /**
+        * Get ESA id for entry with given parameters.
+        *
+        * @param src                   source address of CHILD SA
+        * @param dst                   destination address of CHILD SA
+        * @param spi                   SPI of CHILD SA
+        * @param proto                 protocol of CHILD SA (ESP/AH)
+        * @return                              ESA id of entry if found, 0 otherwise
+        */
+       esa_id_type (*get_esa_id)(tkm_kernel_sad_t * const this,
+                                const host_t * const src, const host_t * const dst,
+                                const u_int32_t spi, const u_int8_t proto);
+
+       /**
+        * Remove entry with given ESA id from SAD.
+        *
+        * @param esa_id                ESA identifier of entry to remove
+        * @return                              TRUE if entry was removed, FALSE otherwise
+        */
+       bool (*remove)(tkm_kernel_sad_t * const this, const esa_id_type esa_id);
+
+       /**
+        * Destroy a tkm_kernel_sad instance.
+        */
+       void (*destroy)(tkm_kernel_sad_t *this);
+
+};
+
+/**
+ * Create a TKM kernel SAD instance.
+ */
+tkm_kernel_sad_t *tkm_kernel_sad_create();
+
+#endif /** TKM_KERNEL_SAD_H_ */
diff --git a/src/charon-tkm/tests/kernel_sad_tests.c b/src/charon-tkm/tests/kernel_sad_tests.c
new file mode 100644 (file)
index 0000000..1178560
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2012 Reto Buerki
+ * Copyright (C) 2012 Adrian-Ken Rueegsegger
+ * 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 <check.h>
+
+#include "tkm_kernel_sad.h"
+
+START_TEST(test_sad_creation)
+{
+       tkm_kernel_sad_t *sad = NULL;
+
+       sad = tkm_kernel_sad_create();
+       fail_if(!sad, "Error creating tkm kernel SAD");
+
+       sad->destroy(sad);
+}
+END_TEST
+
+START_TEST(test_insert)
+{
+       host_t *addr = host_create_from_string("127.0.0.1", 1024);
+       tkm_kernel_sad_t *sad = tkm_kernel_sad_create();
+
+       fail_unless(sad->insert(sad, 1, addr, addr, 42, 50),
+                               "Error inserting SAD entry");
+
+       sad->destroy(sad);
+       addr->destroy(addr);
+}
+END_TEST
+
+START_TEST(test_insert_duplicate)
+{
+       host_t *addr = host_create_from_string("127.0.0.1", 1024);
+       tkm_kernel_sad_t *sad = tkm_kernel_sad_create();
+
+       fail_unless(sad->insert(sad, 1, addr, addr, 42, 50),
+                               "Error inserting SAD entry");
+       fail_if(sad->insert(sad, 1, addr, addr, 42, 50),
+                       "Expected error inserting duplicate entry");
+
+       sad->destroy(sad);
+       addr->destroy(addr);
+}
+END_TEST
+
+START_TEST(test_get_esa_id)
+{
+       host_t *addr = host_create_from_string("127.0.0.1", 1024);
+       tkm_kernel_sad_t *sad = tkm_kernel_sad_create();
+       fail_unless(sad->insert(sad, 23, addr, addr, 42, 50),
+                               "Error inserting SAD entry");
+       fail_unless(sad->get_esa_id(sad, addr, addr, 42, 50) == 23,
+                               "Error getting esa id");
+       sad->destroy(sad);
+       addr->destroy(addr);
+}
+END_TEST
+
+START_TEST(test_get_esa_id_nonexistent)
+{
+       host_t *addr = host_create_from_string("127.0.0.1", 1024);
+       tkm_kernel_sad_t *sad = tkm_kernel_sad_create();
+       fail_unless(sad->get_esa_id(sad, addr, addr, 42, 50) == 0,
+                               "Got esa id for nonexistent SAD entry");
+       sad->destroy(sad);
+       addr->destroy(addr);
+}
+END_TEST
+
+START_TEST(test_remove)
+{
+       host_t *addr = host_create_from_string("127.0.0.1", 1024);
+       tkm_kernel_sad_t *sad = tkm_kernel_sad_create();
+       fail_unless(sad->insert(sad, 23, addr, addr, 42, 50),
+                               "Error inserting SAD entry");
+       fail_unless(sad->get_esa_id(sad, addr, addr, 42, 50) == 23,
+                               "Error getting esa id");
+       fail_unless(sad->remove(sad, 23),
+                               "Error removing SAD entry");
+       fail_unless(sad->get_esa_id(sad, addr, addr, 42, 50) == 0,
+                               "Got esa id for removed SAD entry");
+       sad->destroy(sad);
+       addr->destroy(addr);
+}
+END_TEST
+
+START_TEST(test_remove_nonexistent)
+{
+       tkm_kernel_sad_t *sad = tkm_kernel_sad_create();
+       fail_if(sad->remove(sad, 1),
+                       "Expected error removing nonexistent SAD entry");
+       sad->destroy(sad);
+}
+END_TEST
+
+TCase *make_kernel_sad_tests(void)
+{
+       TCase *tc = tcase_create("Kernel SAD tests");
+       tcase_add_test(tc, test_sad_creation);
+       tcase_add_test(tc, test_insert);
+       tcase_add_test(tc, test_insert_duplicate);
+       tcase_add_test(tc, test_get_esa_id);
+       tcase_add_test(tc, test_get_esa_id_nonexistent);
+       tcase_add_test(tc, test_remove);
+       tcase_add_test(tc, test_remove_nonexistent);
+
+       return tc;
+}
index 6ab990d..b716dc6 100644 (file)
@@ -33,6 +33,7 @@ int main(void)
        suite_add_tcase(s, make_nonceg_tests());
        suite_add_tcase(s, make_diffie_hellman_tests());
        suite_add_tcase(s, make_keymat_tests());
+       suite_add_tcase(s, make_kernel_sad_tests());
 
        SRunner *sr = srunner_create(s);
 
index c8cc0c0..236a7f2 100644 (file)
@@ -25,5 +25,6 @@ TCase *make_utility_tests(void);
 TCase *make_nonceg_tests(void);
 TCase *make_diffie_hellman_tests(void);
 TCase *make_keymat_tests(void);
+TCase *make_kernel_sad_tests(void);
 
 #endif /** TEST_RUNNER_H_ */