diff options
author | Adrian-Ken Rueegsegger <ken@codelabs.ch> | 2012-09-14 14:59:04 +0200 |
---|---|---|
committer | Tobias Brunner <tobias@strongswan.org> | 2013-03-19 15:23:48 +0100 |
commit | 1e13904f457a1d4a97757e695bac7e9cb683b90d (patch) | |
tree | bfb3b24a3fe2a7e0019d9d08f9697220f94449fe /src | |
parent | d1c08227597fe26044abb81709efd193e896e8ce (diff) | |
download | strongswan-1e13904f457a1d4a97757e695bac7e9cb683b90d.tar.bz2 strongswan-1e13904f457a1d4a97757e695bac7e9cb683b90d.tar.xz |
Implement TKM kernel SA database (SAD)
The TKM kernel SAD (security association database) stores information
about CHILD SAs.
Diffstat (limited to 'src')
-rw-r--r-- | src/charon-tkm/src/tkm/tkm_kernel_sad.c | 250 | ||||
-rw-r--r-- | src/charon-tkm/src/tkm/tkm_kernel_sad.h | 78 | ||||
-rw-r--r-- | src/charon-tkm/tests/kernel_sad_tests.c | 122 | ||||
-rw-r--r-- | src/charon-tkm/tests/test_runner.c | 1 | ||||
-rw-r--r-- | src/charon-tkm/tests/test_runner.h | 1 |
5 files changed, 452 insertions, 0 deletions
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 index 000000000..02b6ddc7c --- /dev/null +++ b/src/charon-tkm/src/tkm/tkm_kernel_sad.c @@ -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 **)¤t)) + { + 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 index 000000000..6863584f4 --- /dev/null +++ b/src/charon-tkm/src/tkm/tkm_kernel_sad.h @@ -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 index 000000000..11785602d --- /dev/null +++ b/src/charon-tkm/tests/kernel_sad_tests.c @@ -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; +} diff --git a/src/charon-tkm/tests/test_runner.c b/src/charon-tkm/tests/test_runner.c index 6ab990d92..b716dc633 100644 --- a/src/charon-tkm/tests/test_runner.c +++ b/src/charon-tkm/tests/test_runner.c @@ -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); diff --git a/src/charon-tkm/tests/test_runner.h b/src/charon-tkm/tests/test_runner.h index c8cc0c0db..236a7f2a6 100644 --- a/src/charon-tkm/tests/test_runner.h +++ b/src/charon-tkm/tests/test_runner.h @@ -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_ */ |