From 9d2a3554e5ca88b190f95a0616ae2fe05bb4062b Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Fri, 24 Oct 2014 15:40:09 +0200 Subject: [PATCH 1/8] mem-pool: Correctly ignore first and last addresses of subnets and adjust size Previously one more than the first and last address was ignored. And if the base address is not the network ID of the subnet we should not skip it. But we should adjust the size as it does not represent the actual number of IP addresses assignable. --- src/libhydra/attributes/mem_pool.c | 56 ++++++++++++++++++++++++++---- 1 file changed, 49 insertions(+), 7 deletions(-) diff --git a/src/libhydra/attributes/mem_pool.c b/src/libhydra/attributes/mem_pool.c index cc45e5629..225abe383 100644 --- a/src/libhydra/attributes/mem_pool.c +++ b/src/libhydra/attributes/mem_pool.c @@ -46,6 +46,11 @@ struct private_mem_pool_t { */ host_t *base; + /** + * whether base is the network id of the subnet on which the pool is based + */ + bool base_is_network_id; + /** * size of the pool */ @@ -306,7 +311,7 @@ static int get_new(private_mem_pool_t *this, identification_t *id) this->leases->put(this->leases, entry->id, entry); } /* assigning offset, starting by 1 */ - offset = ++this->unused; + offset = ++this->unused + (this->base_is_network_id ? 1 : 0); array_insert(entry->online, ARRAY_TAIL, &offset); DBG1(DBG_CFG, "assigning new lease to '%Y'", id); } @@ -579,19 +584,40 @@ static private_mem_pool_t *create_generic(char *name) return this; } +/** + * Check if the given host is the network ID of a subnet, that is, if hostbits + * are zero. Since we limit pools to 2^31 addresses we only have to check the + * last 4 bytes. + */ +static u_int network_id_diff(host_t *host, int hostbits) +{ + u_int32_t last; + chunk_t addr; + + if (!hostbits) + { + return 0; + } + addr = host->get_address(host); + last = untoh32(addr.ptr + addr.len - sizeof(last)); + hostbits = sizeof(last) * 8 - hostbits; + return (last << hostbits) >> hostbits; +} + /** * Described in header */ mem_pool_t *mem_pool_create(char *name, host_t *base, int bits) { private_mem_pool_t *this; + u_int diff; int addr_bits; this = create_generic(name); if (base) { addr_bits = base->get_family(base) == AF_INET ? 32 : 128; - bits = max(0, min(bits, base->get_family(base) == AF_INET ? 32 : 128)); + bits = max(0, min(bits, addr_bits)); /* net bits -> host bits */ bits = addr_bits - bits; if (bits > POOL_LIMIT) @@ -601,15 +627,31 @@ mem_pool_t *mem_pool_create(char *name, host_t *base, int bits) base, addr_bits - bits); } this->size = 1 << bits; + this->base = base->clone(base); if (this->size > 2) - { /* do not use first and last addresses of a block */ - this->unused++; - this->size -= 2; + { + /* if base is the network id we later skip the first address, + * otherwise adjust the size to represent the actual number + * of assignable addresses */ + diff = network_id_diff(base, bits); + if (!diff) + { + this->base_is_network_id = TRUE; + this->size--; + } + else + { + this->size -= diff; + } + /* skip the last address (broadcast) of the subnet */ + this->size--; + } + else if (network_id_diff(base, bits)) + { /* only serve the second address of the subnet */ + this->size--; } - this->base = base->clone(base); } - return &this->public; } From 385d4486bafbceccb940f7b74e2bb5b00bc2faec Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Fri, 24 Oct 2014 16:47:26 +0200 Subject: [PATCH 2/8] libhydra: Add test runner --- configure.ac | 1 + src/libhydra/Makefile.am | 5 +++ src/libhydra/tests/.gitignore | 1 + src/libhydra/tests/Makefile.am | 18 +++++++++++ src/libhydra/tests/hydra_tests.c | 53 ++++++++++++++++++++++++++++++++ src/libhydra/tests/hydra_tests.h | 14 +++++++++ 6 files changed, 92 insertions(+) create mode 100644 src/libhydra/tests/.gitignore create mode 100644 src/libhydra/tests/Makefile.am create mode 100644 src/libhydra/tests/hydra_tests.c create mode 100644 src/libhydra/tests/hydra_tests.h diff --git a/configure.ac b/configure.ac index 7a3c3281b..7e561edf9 100644 --- a/configure.ac +++ b/configure.ac @@ -1650,6 +1650,7 @@ AC_CONFIG_FILES([ src/libhydra/plugins/kernel_pfkey/Makefile src/libhydra/plugins/kernel_pfroute/Makefile src/libhydra/plugins/resolve/Makefile + src/libhydra/tests/Makefile src/libipsec/Makefile src/libsimaka/Makefile src/libtls/Makefile diff --git a/src/libhydra/Makefile.am b/src/libhydra/Makefile.am index 510f2a124..7334cdc2e 100644 --- a/src/libhydra/Makefile.am +++ b/src/libhydra/Makefile.am @@ -78,3 +78,8 @@ if MONOLITHIC libhydra_la_LIBADD += plugins/resolve/libstrongswan-resolve.la endif endif + +if MONOLITHIC + SUBDIRS += . +endif +SUBDIRS += tests diff --git a/src/libhydra/tests/.gitignore b/src/libhydra/tests/.gitignore new file mode 100644 index 000000000..6870ba524 --- /dev/null +++ b/src/libhydra/tests/.gitignore @@ -0,0 +1 @@ +hydra_tests diff --git a/src/libhydra/tests/Makefile.am b/src/libhydra/tests/Makefile.am new file mode 100644 index 000000000..5acd5c28c --- /dev/null +++ b/src/libhydra/tests/Makefile.am @@ -0,0 +1,18 @@ +TESTS = hydra_tests + +check_PROGRAMS = $(TESTS) + +hydra_tests_SOURCES = \ + hydra_tests.h hydra_tests.c + +hydra_tests_CFLAGS = \ + -I$(top_srcdir)/src/libhydra \ + -I$(top_srcdir)/src/libstrongswan \ + -I$(top_srcdir)/src/libstrongswan/tests \ + @COVERAGE_CFLAGS@ + +hydra_tests_LDFLAGS = @COVERAGE_LDFLAGS@ +hydra_tests_LDADD = \ + $(top_builddir)/src/libhydra/libhydra.la \ + $(top_builddir)/src/libstrongswan/libstrongswan.la \ + $(top_builddir)/src/libstrongswan/tests/libtest.la diff --git a/src/libhydra/tests/hydra_tests.c b/src/libhydra/tests/hydra_tests.c new file mode 100644 index 000000000..90abd8369 --- /dev/null +++ b/src/libhydra/tests/hydra_tests.c @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2014 Tobias Brunner + * 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 . + * + * 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 +#include + +/* declare test suite constructors */ +#define TEST_SUITE(x) test_suite_t* x(); +#define TEST_SUITE_DEPEND(x, ...) TEST_SUITE(x) +#include "hydra_tests.h" +#undef TEST_SUITE +#undef TEST_SUITE_DEPEND + +static test_configuration_t tests[] = { +#define TEST_SUITE(x) \ + { .suite = x, }, +#define TEST_SUITE_DEPEND(x, type, args) \ + { .suite = x, .feature = PLUGIN_DEPENDS(type, args) }, +#include "hydra_tests.h" + { .suite = NULL, } +}; + +static bool test_runner_init(bool init) +{ + if (init) + { + libhydra_init(); + } + else + { + lib->processor->set_threads(lib->processor, 0); + lib->processor->cancel(lib->processor); + libhydra_deinit(); + } + return TRUE; +} + +int main(int argc, char *argv[]) +{ + return test_runner_run("libhydra", tests, test_runner_init); +} diff --git a/src/libhydra/tests/hydra_tests.h b/src/libhydra/tests/hydra_tests.h new file mode 100644 index 000000000..6b213d026 --- /dev/null +++ b/src/libhydra/tests/hydra_tests.h @@ -0,0 +1,14 @@ +/* + * Copyright (C) 2014 Tobias Brunner + * 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 . + * + * 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. + */ From bbe3070aa207afaa8c61867157fd097ef09b2ac4 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Fri, 24 Oct 2014 16:48:34 +0200 Subject: [PATCH 3/8] mem-pool: Add basic unit tests --- src/libhydra/tests/Makefile.am | 1 + src/libhydra/tests/hydra_tests.h | 2 + src/libhydra/tests/suites/test_mem_pool.c | 230 ++++++++++++++++++++++ 3 files changed, 233 insertions(+) create mode 100644 src/libhydra/tests/suites/test_mem_pool.c diff --git a/src/libhydra/tests/Makefile.am b/src/libhydra/tests/Makefile.am index 5acd5c28c..c2377c160 100644 --- a/src/libhydra/tests/Makefile.am +++ b/src/libhydra/tests/Makefile.am @@ -3,6 +3,7 @@ TESTS = hydra_tests check_PROGRAMS = $(TESTS) hydra_tests_SOURCES = \ + suites/test_mem_pool.c \ hydra_tests.h hydra_tests.c hydra_tests_CFLAGS = \ diff --git a/src/libhydra/tests/hydra_tests.h b/src/libhydra/tests/hydra_tests.h index 6b213d026..a73b78dc7 100644 --- a/src/libhydra/tests/hydra_tests.h +++ b/src/libhydra/tests/hydra_tests.h @@ -12,3 +12,5 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ + +TEST_SUITE(mem_pool_suite_create) diff --git a/src/libhydra/tests/suites/test_mem_pool.c b/src/libhydra/tests/suites/test_mem_pool.c new file mode 100644 index 000000000..c47a92f78 --- /dev/null +++ b/src/libhydra/tests/suites/test_mem_pool.c @@ -0,0 +1,230 @@ +/* + * Copyright (C) 2014 Tobias Brunner + * 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 . + * + * 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 "test_suite.h" + +#include + +static void assert_host(char *expected, host_t *host) +{ + if (!expected) + { + ck_assert_msg(!host, "not epxecting IP != %+H", host); + } + else + { + host_t *verifier; + verifier = host_create_from_string(expected, 0); + ck_assert_msg(host, "expected IP %+H != NULL", verifier); + ck_assert_msg(verifier->ip_equals(verifier, host), "expected IP %+H != " + "%+H", verifier, host);; + verifier->destroy(verifier); + } +} + +static void assert_acquire(mem_pool_t *pool, char *requested, char *expected, + mem_pool_op_t operation) +{ + identification_t *id; + host_t *req, *acquired; + + id = identification_create_from_string("tester"); + req = host_create_from_string(requested, 0); + + acquired = pool->acquire_address(pool, id, req, operation); + assert_host(expected, acquired); + DESTROY_IF(acquired); + + req->destroy(req); + id->destroy(id); +} + +static void assert_acquires_new(mem_pool_t *pool, char *pattern, int first) +{ + char expected[16]; + int i; + + for (i = 0; i < pool->get_size(pool); i++) + { + snprintf(expected, sizeof(expected), pattern, first + i); + assert_acquire(pool, "0.0.0.0", expected, MEM_POOL_NEW); + ck_assert_int_eq(i + 1, pool->get_online(pool)); + } + assert_acquire(pool, "0.0.0.0", NULL, MEM_POOL_NEW); +} + +START_TEST(test_config) +{ + mem_pool_t *pool; + + pool = mem_pool_create("test", NULL, 0); + ck_assert_int_eq(0, pool->get_size(pool)); + assert_acquire(pool, "192.168.0.1", "192.168.0.1", MEM_POOL_NEW); + assert_acquire(pool, "10.0.1.1", "10.0.1.1", MEM_POOL_NEW); + assert_acquire(pool, "0.0.0.0", "0.0.0.0", MEM_POOL_NEW); + assert_acquire(pool, "255.255.255.255", "255.255.255.255", MEM_POOL_NEW); + ck_assert_int_eq(0, pool->get_online(pool)); + pool->destroy(pool); +} +END_TEST + +START_TEST(test_cidr) +{ + mem_pool_t *pool; + host_t *base; + + base = host_create_from_string("192.168.0.0", 0); + + pool = mem_pool_create("test", base, 32); + ck_assert_int_eq(1, pool->get_size(pool)); + assert_acquires_new(pool, "192.168.0.%d", 0); + pool->destroy(pool); + + pool = mem_pool_create("test", base, 31); + ck_assert_int_eq(2, pool->get_size(pool)); + assert_acquires_new(pool, "192.168.0.%d", 0); + pool->destroy(pool); + + pool = mem_pool_create("test", base, 30); + ck_assert_int_eq(2, pool->get_size(pool)); + assert_acquires_new(pool, "192.168.0.%d", 1); + pool->destroy(pool); + + pool = mem_pool_create("test", base, 29); + ck_assert_int_eq(6, pool->get_size(pool)); + assert_acquires_new(pool, "192.168.0.%d", 1); + pool->destroy(pool); + + pool = mem_pool_create("test", base, 24); + ck_assert_int_eq(254, pool->get_size(pool)); + assert_acquires_new(pool, "192.168.0.%d", 1); + pool->destroy(pool); + + base->destroy(base); +} +END_TEST + +START_TEST(test_cidr_offset) +{ + mem_pool_t *pool; + host_t *base; + + base = host_create_from_string("192.168.0.1", 0); + pool = mem_pool_create("test", base, 31); + ck_assert_int_eq(1, pool->get_size(pool)); + assert_acquires_new(pool, "192.168.0.%d", 1); + pool->destroy(pool); + + pool = mem_pool_create("test", base, 30); + ck_assert_int_eq(2, pool->get_size(pool)); + assert_acquires_new(pool, "192.168.0.%d", 1); + pool->destroy(pool); + base->destroy(base); + + base = host_create_from_string("192.168.0.2", 0); + pool = mem_pool_create("test", base, 30); + ck_assert_int_eq(1, pool->get_size(pool)); + assert_acquires_new(pool, "192.168.0.%d", 2); + pool->destroy(pool); + + pool = mem_pool_create("test", base, 24); + ck_assert_int_eq(253, pool->get_size(pool)); + assert_acquires_new(pool, "192.168.0.%d", 2); + pool->destroy(pool); + base->destroy(base); + + base = host_create_from_string("192.168.0.254", 0); + pool = mem_pool_create("test", base, 24); + ck_assert_int_eq(1, pool->get_size(pool)); + assert_acquires_new(pool, "192.168.0.%d", 254); + pool->destroy(pool); + base->destroy(base); + + /* due to size == 0 we get the requested IP back */ + base = host_create_from_string("192.168.0.255", 0); + pool = mem_pool_create("test", base, 24); + ck_assert_int_eq(0, pool->get_size(pool)); + assert_acquire(pool, "192.168.0.1", "192.168.0.1", MEM_POOL_NEW); + pool->destroy(pool); + + base->destroy(base); +} +END_TEST + +START_TEST(test_range) +{ + mem_pool_t *pool; + host_t *from, *to; + + from = host_create_from_string("192.168.0.0", 0); + to = host_create_from_string("192.168.0.0", 0); + pool = mem_pool_create_range("test", from, to); + ck_assert_int_eq(1, pool->get_size(pool)); + assert_acquires_new(pool, "192.168.0.%d", 0); + pool->destroy(pool); + + to->destroy(to); + to = host_create_from_string("192.168.0.1", 0); + pool = mem_pool_create_range("test", from, to); + ck_assert_int_eq(2, pool->get_size(pool)); + assert_acquires_new(pool, "192.168.0.%d", 0); + pool->destroy(pool); + + from->destroy(from); + from = host_create_from_string("192.168.0.10", 0); + pool = mem_pool_create_range("test", from, to); + ck_assert(!pool); + + to->destroy(to); + to = host_create_from_string("192.168.0.20", 0); + pool = mem_pool_create_range("test", from, to); + ck_assert_int_eq(11, pool->get_size(pool)); + assert_acquires_new(pool, "192.168.0.%d", 10); + pool->destroy(pool); + + from->destroy(from); + from = host_create_from_string("fec::1", 0); + to->destroy(to); + to = host_create_from_string("fed::1", 0); + pool = mem_pool_create_range("test", from, to); + ck_assert(!pool); + + from->destroy(from); + to->destroy(to); +} +END_TEST + +Suite *mem_pool_suite_create() +{ + Suite *s; + TCase *tc; + + s = suite_create("mem_pool"); + + tc = tcase_create("%config-like pool"); + tcase_add_test(tc, test_config); + suite_add_tcase(s, tc); + + tc = tcase_create("cidr constructor"); + tcase_add_test(tc, test_cidr); + tcase_add_test(tc, test_cidr_offset); + suite_add_tcase(s, tc); + + tc = tcase_create("range constructor"); + tcase_add_test(tc, test_range); + suite_add_tcase(s, tc); + + return s; +} From 82be444eb99b51f42e717bf883a981ae9cd7d77e Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Tue, 28 Oct 2014 18:14:29 +0100 Subject: [PATCH 4/8] host: Add function to create two hosts from a range definition --- src/libstrongswan/networking/host.c | 28 ++++++++ src/libstrongswan/networking/host.h | 13 ++++ src/libstrongswan/tests/suites/test_host.c | 83 ++++++++++++++++++++++ 3 files changed, 124 insertions(+) diff --git a/src/libstrongswan/networking/host.c b/src/libstrongswan/networking/host.c index 8d04a4ec9..95c7390a7 100644 --- a/src/libstrongswan/networking/host.c +++ b/src/libstrongswan/networking/host.c @@ -525,6 +525,34 @@ host_t *host_create_from_chunk(int family, chunk_t address, u_int16_t port) return &this->public; } +/* + * Described in header. + */ +bool host_create_from_range(char *string, host_t **from, host_t **to) +{ + char *pos; + + pos = strchr(string, '-'); + if (!pos) + { + return FALSE; + } + *to = host_create_from_string(pos + 1, 0); + if (!*to) + { + return FALSE; + } + pos = strndup(string, pos - string); + *from = host_create_from_string_and_family(pos, (*to)->get_family(*to), 0); + free(pos); + if (!*from) + { + (*to)->destroy(*to); + return FALSE; + } + return TRUE; +} + /* * Described in header. */ diff --git a/src/libstrongswan/networking/host.h b/src/libstrongswan/networking/host.h index 9c9b5035f..3670768c4 100644 --- a/src/libstrongswan/networking/host.h +++ b/src/libstrongswan/networking/host.h @@ -180,6 +180,19 @@ host_t *host_create_from_chunk(int family, chunk_t address, u_int16_t port); */ host_t *host_create_from_sockaddr(sockaddr_t *sockaddr); +/** + * Parse a range definition (1.2.3.0-1.2.3.5), return the two hosts. + * + * The two hosts are not ordered, from is simply the first, to is the second, + * from is not necessarily smaller. + * + * @param string string to parse + * @param from returns the first address (out) + * @param to returns the second address (out) + * @return TRUE if parsed successfully, FALSE otherwise + */ +bool host_create_from_range(char *string, host_t **from, host_t **to); + /** * Create a host from a CIDR subnet definition (1.2.3.0/24), return bits. * diff --git a/src/libstrongswan/tests/suites/test_host.c b/src/libstrongswan/tests/suites/test_host.c index 63442083a..1f97bff6e 100644 --- a/src/libstrongswan/tests/suites/test_host.c +++ b/src/libstrongswan/tests/suites/test_host.c @@ -399,6 +399,84 @@ START_TEST(test_create_from_subnet_v6) } END_TEST +/******************************************************************************* + * host_create_from_range + */ + +static const chunk_t addr_v4_to = chunk_from_chars(0xc0, 0xa8, 0x00, 0x05); +static const chunk_t addr_v6_to = chunk_from_chars(0xfe, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05); + +static void verify_range(char *str, int family, chunk_t from_addr, + chunk_t to_addr) +{ + host_t *from, *to; + + if (!family) + { + ck_assert(!host_create_from_range(str, &from, &to)); + } + else + { + ck_assert(host_create_from_range(str, &from, &to)); + verify_address(from, from_addr, family, 0); + verify_address(to, to_addr, family, 0); + from->destroy(from); + to->destroy(to); + } +} + +START_TEST(test_create_from_range_v4) +{ + host_t *from, *to; + + ck_assert(host_create_from_range("0.0.0.0-0.0.0.0", &from, &to)); + verify_any(from, AF_INET, 0); + verify_any(to, AF_INET, 0); + from->destroy(from); + to->destroy(to); + + verify_range("192.168.0.1-192.168.0.1", AF_INET, addr_v4, addr_v4); + verify_range("192.168.0.1-192.168.0.5", AF_INET, addr_v4, addr_v4_to); + verify_range("192.168.0.5-192.168.0.1", AF_INET, addr_v4_to, addr_v4); + + verify_range("192.168.0.1", 0, chunk_empty, chunk_empty); + verify_range("192.168.0.1-", 0, chunk_empty, chunk_empty); + verify_range("192.168.0.1-192", 0, chunk_empty, chunk_empty); + verify_range("192.168.0.1-192.168", 0, chunk_empty, chunk_empty); + verify_range("192.168.0.1-192.168.0", 0, chunk_empty, chunk_empty); + verify_range("192.168.0.1 - 192.168.0.5", 0, chunk_empty, chunk_empty); + verify_range("foo.b.a.r", 0, chunk_empty, chunk_empty); + verify_range("foo.b.a.r-b.a.r.f", 0, chunk_empty, chunk_empty); +} +END_TEST + +START_TEST(test_create_from_range_v6) +{ + host_t *from, *to; + + ck_assert(host_create_from_range("::-::", &from, &to)); + verify_any(from, AF_INET6, 0); + verify_any(to, AF_INET6, 0); + from->destroy(from); + to->destroy(to); + + verify_range("fec1::1-fec1::1", AF_INET6, addr_v6, addr_v6); + verify_range("fec1::1-fec1::5", AF_INET6, addr_v6, addr_v6_to); + verify_range("fec1::5-fec1::1", AF_INET6, addr_v6_to, addr_v6); + + verify_range("fec1::1", 0, chunk_empty, chunk_empty); + verify_range("fec1::1-", 0, chunk_empty, chunk_empty); + verify_range("fec1::1-fec1", 0, chunk_empty, chunk_empty); + verify_range("fec1::1 - fec1::5", 0, chunk_empty, chunk_empty); + verify_range("foo::bar", 0, chunk_empty, chunk_empty); + verify_range("foo::bar-bar::foo", 0, chunk_empty, chunk_empty); + + verify_range("fec1::1-192.168.0.1", 0, chunk_empty, chunk_empty); + verify_range("192.168.0.1-fec1::1", 0, chunk_empty, chunk_empty); +} +END_TEST + /******************************************************************************* * host_create_netmask */ @@ -627,6 +705,11 @@ Suite *host_suite_create() tcase_add_test(tc, test_create_from_subnet_v6); suite_add_tcase(s, tc); + tc = tcase_create("host_create_from_range"); + tcase_add_test(tc, test_create_from_range_v4); + tcase_add_test(tc, test_create_from_range_v6); + suite_add_tcase(s, tc); + tc = tcase_create("host_create_netmask"); tcase_add_test(tc, test_create_netmask_v4); tcase_add_test(tc, test_create_netmask_v6); From c355e2b2c7b9e13986036d95bef85eafde1260d0 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Mon, 27 Oct 2014 15:31:46 +0100 Subject: [PATCH 5/8] stroke: Add support for address range definitions of in-memory pools --- man/ipsec.conf.5.in | 4 +- src/libcharon/plugins/stroke/stroke_config.c | 40 ++++++++++++++++---- 2 files changed, 36 insertions(+), 8 deletions(-) diff --git a/man/ipsec.conf.5.in b/man/ipsec.conf.5.in index 32d0b9a27..1c5ac0015 100644 --- a/man/ipsec.conf.5.in +++ b/man/ipsec.conf.5.in @@ -853,13 +853,15 @@ an address of the given address family will be requested explicitly. If an IP address is configured, it will be requested from the responder, which is free to respond with a different address. .TP -.BR rightsourceip " = %config | / | %poolname" +.BR rightsourceip " = %config | / | - | %poolname" Comma separated list of internal source IPs to use in a tunnel for the remote peer. If the value is .B %config on the responder side, the initiator must propose an address which is then echoed back. Also supported are address pools expressed as \fInetwork\fB/\fInetmask\fR +and +\fIfrom\fB-\fIto\fR or the use of an external IP address pool using %\fIpoolname\fR, where \fIpoolname\fR is the name of the IP address pool used for the lookup. .TP diff --git a/src/libcharon/plugins/stroke/stroke_config.c b/src/libcharon/plugins/stroke/stroke_config.c index 62967b006..3e40a7888 100644 --- a/src/libcharon/plugins/stroke/stroke_config.c +++ b/src/libcharon/plugins/stroke/stroke_config.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Tobias Brunner + * Copyright (C) 2012-2014 Tobias Brunner * Copyright (C) 2008 Martin Willi * Hochschule fuer Technik Rapperswil * @@ -666,6 +666,24 @@ static auth_cfg_t *build_auth_cfg(private_stroke_config_t *this, return cfg; } +/** + * build a mem_pool_t from an address range + */ +static mem_pool_t *create_pool_range(char *str) +{ + mem_pool_t *pool; + host_t *from, *to; + + if (!host_create_from_range(str, &from, &to)) + { + return NULL; + } + pool = mem_pool_create_range(str, from, to); + from->destroy(from); + to->destroy(to); + return pool; +} + /** * build a peer_cfg from a stroke msg */ @@ -789,17 +807,25 @@ static peer_cfg_t *build_peer_cfg(private_stroke_config_t *this, } else { - /* in-memory pool, named using CIDR notation */ + /* in-memory pool, using range or CIDR notation */ + mem_pool_t *pool; host_t *base; int bits; - base = host_create_from_subnet(token, &bits); - if (base) + pool = create_pool_range(token); + if (!pool) { - this->attributes->add_pool(this->attributes, - mem_pool_create(token, base, bits)); + base = host_create_from_subnet(token, &bits); + if (base) + { + pool = mem_pool_create(token, base, bits); + base->destroy(base); + } + } + if (pool) + { + this->attributes->add_pool(this->attributes, pool); peer_cfg->add_pool(peer_cfg, token); - base->destroy(base); } else { From 5e92534313ca6dcf60f59968cada8ca27e3f6565 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Mon, 27 Oct 2014 15:50:25 +0100 Subject: [PATCH 6/8] vici: Add support for address range definitions of pools --- src/libcharon/plugins/vici/vici_attribute.c | 40 ++++++++++++++++++--- src/swanctl/swanctl.opt | 8 ++--- 2 files changed, 39 insertions(+), 9 deletions(-) diff --git a/src/libcharon/plugins/vici/vici_attribute.c b/src/libcharon/plugins/vici/vici_attribute.c index 2178116c9..c0ac57344 100644 --- a/src/libcharon/plugins/vici/vici_attribute.c +++ b/src/libcharon/plugins/vici/vici_attribute.c @@ -1,4 +1,7 @@ /* + * Copyright (C) 2014 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * * Copyright (C) 2014 Martin Willi * Copyright (C) 2014 revosec AG * @@ -354,6 +357,24 @@ static vici_message_t* create_reply(char *fmt, ...) return builder->finalize(builder); } +/** + * Parse a range definition of an address pool + */ +static mem_pool_t *create_pool_range(char *name, char *buf) +{ + mem_pool_t *pool; + host_t *from, *to; + + if (!host_create_from_range(buf, &from, &to)) + { + return NULL; + } + pool = mem_pool_create_range(name, from, to); + from->destroy(from); + to->destroy(to); + return pool; +} + /** * Parse callback data, passed to each callback */ @@ -490,7 +511,8 @@ CALLBACK(pool_kv, bool, if (streq(name, "addrs")) { char buf[128]; - host_t *base; + mem_pool_t *pool; + host_t *base = NULL; int bits; if (data->pool->vips) @@ -503,14 +525,22 @@ CALLBACK(pool_kv, bool, data->request->reply = create_reply("invalid addrs value"); return FALSE; } - base = host_create_from_subnet(buf, &bits); - if (!base) + pool = create_pool_range(data->name, buf); + if (!pool) + { + base = host_create_from_subnet(buf, &bits); + if (base) + { + pool = mem_pool_create(data->name, base, bits); + base->destroy(base); + } + } + if (!pool) { data->request->reply = create_reply("invalid addrs value: %s", buf); return FALSE; } - data->pool->vips = mem_pool_create(data->name, base, bits); - base->destroy(base); + data->pool->vips = pool; return TRUE; } data->request->reply = create_reply("invalid attribute: %s", name); diff --git a/src/swanctl/swanctl.opt b/src/swanctl/swanctl.opt index 57835555c..588004562 100644 --- a/src/swanctl/swanctl.opt +++ b/src/swanctl/swanctl.opt @@ -782,11 +782,11 @@ pools. { # } Section defining a single pool with a unique name. pools..addrs = - Subnet defining addresses allocated in pool. + Addresses allocated in pool. - Subnet defining addresses allocated in pool. Accepts a single CIDR subnet - defining the pool to allocate addresses from. Pools must be unique and - non-overlapping. + Subnet or range defining addresses allocated in pool. Accepts a single CIDR + subnet defining the pool to allocate addresses from, or an address range + (-). Pools must be unique and non-overlapping. pools.. = Comma separated list of additional attributes from type . From e0cd3bad3d40c71559adc23d340b6a6b170dabb0 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Tue, 28 Oct 2014 18:23:10 +0100 Subject: [PATCH 7/8] ike-cfg: Use host_create_from_range() helper --- src/libcharon/config/ike_cfg.c | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/src/libcharon/config/ike_cfg.c b/src/libcharon/config/ike_cfg.c index 42a3e9057..9464ceb5d 100644 --- a/src/libcharon/config/ike_cfg.c +++ b/src/libcharon/config/ike_cfg.c @@ -459,27 +459,12 @@ static traffic_selector_t* make_range(char *str) { traffic_selector_t *ts; ts_type_t type; - char *pos; host_t *from, *to; - pos = strchr(str, '-'); - if (!pos) + if (!host_create_from_range(str, &from, &to)) { return NULL; } - to = host_create_from_string(pos + 1, 0); - if (!to) - { - return NULL; - } - str = strndup(str, pos - str); - from = host_create_from_string_and_family(str, to->get_family(to), 0); - free(str); - if (!from) - { - to->destroy(to); - return NULL; - } if (to->get_family(to) == AF_INET) { type = TS_IPV4_ADDR_RANGE; From cd67cd70c842fc2dacd253ba8b07a452269526dc Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Thu, 30 Oct 2014 12:32:16 +0100 Subject: [PATCH 8/8] host: Ignore spaces around - when parsing ranges --- src/libstrongswan/networking/host.c | 20 ++++++++++++++------ src/libstrongswan/networking/host.h | 2 +- src/libstrongswan/tests/suites/test_host.c | 10 ++++++++-- 3 files changed, 23 insertions(+), 9 deletions(-) diff --git a/src/libstrongswan/networking/host.c b/src/libstrongswan/networking/host.c index 95c7390a7..07da3ef3b 100644 --- a/src/libstrongswan/networking/host.c +++ b/src/libstrongswan/networking/host.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2012 Tobias Brunner + * Copyright (C) 2006-2014 Tobias Brunner * Copyright (C) 2006 Daniel Roethlisberger * Copyright (C) 2005-2006 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -530,19 +530,27 @@ host_t *host_create_from_chunk(int family, chunk_t address, u_int16_t port) */ bool host_create_from_range(char *string, host_t **from, host_t **to) { - char *pos; + char *sep, *pos; - pos = strchr(string, '-'); - if (!pos) + sep = strchr(string, '-'); + if (!sep) { return FALSE; } - *to = host_create_from_string(pos + 1, 0); + for (pos = sep+1; *pos && *pos == ' '; pos++) + { + /* trim spaces before to address*/ + } + *to = host_create_from_string(pos, 0); if (!*to) { return FALSE; } - pos = strndup(string, pos - string); + for (pos = sep-1; pos > string && *pos == ' '; pos--) + { + /* trim spaces behind from address */ + } + pos = strndup(string, pos - string + 1); *from = host_create_from_string_and_family(pos, (*to)->get_family(*to), 0); free(pos); if (!*from) diff --git a/src/libstrongswan/networking/host.h b/src/libstrongswan/networking/host.h index 3670768c4..26f23bc99 100644 --- a/src/libstrongswan/networking/host.h +++ b/src/libstrongswan/networking/host.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2009 Tobias Brunner + * Copyright (C) 2006-2014 Tobias Brunner * Copyright (C) 2006 Daniel Roethlisberger * Copyright (C) 2005-2008 Martin Willi * Copyright (C) 2005 Jan Hutter diff --git a/src/libstrongswan/tests/suites/test_host.c b/src/libstrongswan/tests/suites/test_host.c index 1f97bff6e..ec3c83f81 100644 --- a/src/libstrongswan/tests/suites/test_host.c +++ b/src/libstrongswan/tests/suites/test_host.c @@ -438,14 +438,17 @@ START_TEST(test_create_from_range_v4) verify_range("192.168.0.1-192.168.0.1", AF_INET, addr_v4, addr_v4); verify_range("192.168.0.1-192.168.0.5", AF_INET, addr_v4, addr_v4_to); + verify_range("192.168.0.1- 192.168.0.5", AF_INET, addr_v4, addr_v4_to); + verify_range("192.168.0.1 -192.168.0.5", AF_INET, addr_v4, addr_v4_to); + verify_range("192.168.0.1 - 192.168.0.5", AF_INET, addr_v4, addr_v4_to); verify_range("192.168.0.5-192.168.0.1", AF_INET, addr_v4_to, addr_v4); verify_range("192.168.0.1", 0, chunk_empty, chunk_empty); verify_range("192.168.0.1-", 0, chunk_empty, chunk_empty); + verify_range("-192.168.0.1", 0, chunk_empty, chunk_empty); verify_range("192.168.0.1-192", 0, chunk_empty, chunk_empty); verify_range("192.168.0.1-192.168", 0, chunk_empty, chunk_empty); verify_range("192.168.0.1-192.168.0", 0, chunk_empty, chunk_empty); - verify_range("192.168.0.1 - 192.168.0.5", 0, chunk_empty, chunk_empty); verify_range("foo.b.a.r", 0, chunk_empty, chunk_empty); verify_range("foo.b.a.r-b.a.r.f", 0, chunk_empty, chunk_empty); } @@ -463,12 +466,15 @@ START_TEST(test_create_from_range_v6) verify_range("fec1::1-fec1::1", AF_INET6, addr_v6, addr_v6); verify_range("fec1::1-fec1::5", AF_INET6, addr_v6, addr_v6_to); + verify_range("fec1::1- fec1::5", AF_INET6, addr_v6, addr_v6_to); + verify_range("fec1::1 -fec1::5", AF_INET6, addr_v6, addr_v6_to); + verify_range("fec1::1 - fec1::5", AF_INET6, addr_v6, addr_v6_to); verify_range("fec1::5-fec1::1", AF_INET6, addr_v6_to, addr_v6); verify_range("fec1::1", 0, chunk_empty, chunk_empty); verify_range("fec1::1-", 0, chunk_empty, chunk_empty); + verify_range("-fec1::1", 0, chunk_empty, chunk_empty); verify_range("fec1::1-fec1", 0, chunk_empty, chunk_empty); - verify_range("fec1::1 - fec1::5", 0, chunk_empty, chunk_empty); verify_range("foo::bar", 0, chunk_empty, chunk_empty); verify_range("foo::bar-bar::foo", 0, chunk_empty, chunk_empty);