aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--configure.ac1
-rw-r--r--man/ipsec.conf.5.in4
-rw-r--r--src/libcharon/config/ike_cfg.c17
-rw-r--r--src/libcharon/plugins/stroke/stroke_config.c40
-rw-r--r--src/libcharon/plugins/vici/vici_attribute.c40
-rw-r--r--src/libhydra/Makefile.am5
-rw-r--r--src/libhydra/attributes/mem_pool.c56
-rw-r--r--src/libhydra/tests/.gitignore1
-rw-r--r--src/libhydra/tests/Makefile.am19
-rw-r--r--src/libhydra/tests/hydra_tests.c53
-rw-r--r--src/libhydra/tests/hydra_tests.h16
-rw-r--r--src/libhydra/tests/suites/test_mem_pool.c230
-rw-r--r--src/libstrongswan/networking/host.c38
-rw-r--r--src/libstrongswan/networking/host.h15
-rw-r--r--src/libstrongswan/tests/suites/test_host.c89
-rw-r--r--src/swanctl/swanctl.opt8
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>.