diff options
-rw-r--r-- | configure.ac | 1 | ||||
-rw-r--r-- | man/ipsec.conf.5.in | 4 | ||||
-rw-r--r-- | src/libcharon/config/ike_cfg.c | 17 | ||||
-rw-r--r-- | src/libcharon/plugins/stroke/stroke_config.c | 40 | ||||
-rw-r--r-- | src/libcharon/plugins/vici/vici_attribute.c | 40 | ||||
-rw-r--r-- | src/libhydra/Makefile.am | 5 | ||||
-rw-r--r-- | src/libhydra/attributes/mem_pool.c | 56 | ||||
-rw-r--r-- | src/libhydra/tests/.gitignore | 1 | ||||
-rw-r--r-- | src/libhydra/tests/Makefile.am | 19 | ||||
-rw-r--r-- | src/libhydra/tests/hydra_tests.c | 53 | ||||
-rw-r--r-- | src/libhydra/tests/hydra_tests.h | 16 | ||||
-rw-r--r-- | src/libhydra/tests/suites/test_mem_pool.c | 230 | ||||
-rw-r--r-- | src/libstrongswan/networking/host.c | 38 | ||||
-rw-r--r-- | src/libstrongswan/networking/host.h | 15 | ||||
-rw-r--r-- | src/libstrongswan/tests/suites/test_host.c | 89 | ||||
-rw-r--r-- | src/swanctl/swanctl.opt | 8 |
16 files changed, 590 insertions, 42 deletions
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/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 | <network>/<netmask> | %poolname" +.BR rightsourceip " = %config | <network>/<netmask> | <from>-<to> | %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/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,25 +459,10 @@ 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) - { - 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) + if (!host_create_from_range(str, &from, &to)) { - to->destroy(to); return NULL; } if (to->get_family(to) == AF_INET) 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 * @@ -667,6 +667,24 @@ static auth_cfg_t *build_auth_cfg(private_stroke_config_t *this, } /** + * 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 */ static peer_cfg_t *build_peer_cfg(private_stroke_config_t *this, @@ -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) + { + 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, - mem_pool_create(token, base, bits)); + this->attributes->add_pool(this->attributes, pool); peer_cfg->add_pool(peer_cfg, token); - base->destroy(base); } else { 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 * @@ -355,6 +358,24 @@ static vici_message_t* create_reply(char *fmt, ...) } /** + * 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 */ typedef struct { @@ -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/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/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 @@ -47,6 +47,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 */ u_int size; @@ -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); } @@ -580,18 +585,39 @@ static private_mem_pool_t *create_generic(char *name) } /** + * 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; } 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..c2377c160 --- /dev/null +++ b/src/libhydra/tests/Makefile.am @@ -0,0 +1,19 @@ +TESTS = hydra_tests + +check_PROGRAMS = $(TESTS) + +hydra_tests_SOURCES = \ + suites/test_mem_pool.c \ + 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 <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 <test_runner.h> +#include <hydra.h> + +/* 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..a73b78dc7 --- /dev/null +++ b/src/libhydra/tests/hydra_tests.h @@ -0,0 +1,16 @@ +/* + * 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 <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. + */ + +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 <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 "test_suite.h" + +#include <attributes/mem_pool.h> + +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; +} diff --git a/src/libstrongswan/networking/host.c b/src/libstrongswan/networking/host.c index 8d04a4ec9..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 @@ -528,6 +528,42 @@ host_t *host_create_from_chunk(int family, chunk_t address, u_int16_t port) /* * Described in header. */ +bool host_create_from_range(char *string, host_t **from, host_t **to) +{ + char *sep, *pos; + + sep = strchr(string, '-'); + if (!sep) + { + return FALSE; + } + for (pos = sep+1; *pos && *pos == ' '; pos++) + { + /* trim spaces before to address*/ + } + *to = host_create_from_string(pos, 0); + if (!*to) + { + return FALSE; + } + 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) + { + (*to)->destroy(*to); + return FALSE; + } + return TRUE; +} + +/* + * Described in header. + */ host_t *host_create_from_subnet(char *string, int *bits) { char *pos, buf[64]; diff --git a/src/libstrongswan/networking/host.h b/src/libstrongswan/networking/host.h index 9c9b5035f..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 @@ -181,6 +181,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. * * @param string string to parse diff --git a/src/libstrongswan/tests/suites/test_host.c b/src/libstrongswan/tests/suites/test_host.c index 63442083a..ec3c83f81 100644 --- a/src/libstrongswan/tests/suites/test_host.c +++ b/src/libstrongswan/tests/suites/test_host.c @@ -400,6 +400,90 @@ 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.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("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::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("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 +711,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); 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.<name> { # } Section defining a single pool with a unique name. pools.<name>.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 + (<from>-<to>). Pools must be unique and non-overlapping. pools.<name>.<attr> = Comma separated list of additional attributes from type <attr>. |