From 65579569adfa0e2c9602ee250f4554169ba5a87d Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Thu, 11 Jun 2015 15:07:07 +0200 Subject: [PATCH 1/4] host: Properly handle NULL in host_create_from_string[_and_family] --- src/libstrongswan/networking/host.c | 4 ++++ src/libstrongswan/tests/suites/test_host.c | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/src/libstrongswan/networking/host.c b/src/libstrongswan/networking/host.c index 07da3ef3b..2e464b0ad 100644 --- a/src/libstrongswan/networking/host.c +++ b/src/libstrongswan/networking/host.c @@ -354,6 +354,10 @@ host_t *host_create_from_string_and_family(char *string, int family, struct sockaddr_in6 v6; } addr; + if (!string) + { + return NULL; + } if (streq(string, "%any")) { return host_create_any_port(family ? family : AF_INET, port); diff --git a/src/libstrongswan/tests/suites/test_host.c b/src/libstrongswan/tests/suites/test_host.c index 7161b2c5b..5cb8013ff 100644 --- a/src/libstrongswan/tests/suites/test_host.c +++ b/src/libstrongswan/tests/suites/test_host.c @@ -104,6 +104,9 @@ START_TEST(test_create_from_string_v4) { host_t *host; + host = host_create_from_string(NULL, 500); + ck_assert(!host); + host = host_create_from_string("%any", 500); verify_any(host, AF_INET, 500); host->destroy(host); @@ -196,6 +199,7 @@ static void test_create_from_string_and_family_addr(char *string, chunk_t addr, START_TEST(test_create_from_string_and_family_v4) { + test_create_from_string_and_family_any(NULL, AF_INET, AF_UNSPEC); test_create_from_string_and_family_any("%any", AF_INET, AF_INET); test_create_from_string_and_family_any("%any4", AF_INET, AF_INET); test_create_from_string_and_family_any("0.0.0.0", AF_INET, AF_INET); @@ -210,6 +214,7 @@ END_TEST START_TEST(test_create_from_string_and_family_v6) { + test_create_from_string_and_family_any(NULL, AF_INET6, AF_UNSPEC); test_create_from_string_and_family_any("%any", AF_INET6, AF_INET6); test_create_from_string_and_family_any("%any6", AF_INET6, AF_INET6); test_create_from_string_and_family_any("::", AF_INET6, AF_INET6); @@ -224,6 +229,7 @@ END_TEST START_TEST(test_create_from_string_and_family_other) { + test_create_from_string_and_family_any(NULL, AF_UNSPEC, AF_UNSPEC); test_create_from_string_and_family_any("%any", AF_UNSPEC, AF_INET); test_create_from_string_and_family_any("%any4", AF_UNSPEC, AF_INET); test_create_from_string_and_family_any("0.0.0.0", AF_UNSPEC, AF_INET); From 6bfa66069304c1fc1345b4e72762a3b1a80e4338 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Thu, 11 Jun 2015 15:42:54 +0200 Subject: [PATCH 2/4] ike-cfg: Add helper function to determine address family of IP addresses All configured static addresses (hostnames, ranges or subnets are not considered) must be of the same family, otherwise AF_UNSPEC is returned. --- src/libcharon/config/ike_cfg.c | 47 ++++++++++++++++++++++++++++++++++ src/libcharon/config/ike_cfg.h | 13 +++++++++- 2 files changed, 59 insertions(+), 1 deletion(-) diff --git a/src/libcharon/config/ike_cfg.c b/src/libcharon/config/ike_cfg.c index 9464ceb5d..dee9e4c29 100644 --- a/src/libcharon/config/ike_cfg.c +++ b/src/libcharon/config/ike_cfg.c @@ -1,4 +1,5 @@ /* + * Copyright (C) 2012-2015 Tobias Brunner * Copyright (C) 2005-2007 Martin Willi * Copyright (C) 2005 Jan Hutter * Hochschule fuer Technik Rapperswil @@ -510,6 +511,52 @@ static void parse_addresses(char *str, linked_list_t *hosts, enumerator->destroy(enumerator); } +/** + * Described in header. + */ +int ike_cfg_get_family(ike_cfg_t *cfg, bool local) +{ + private_ike_cfg_t *this = (private_ike_cfg_t*)cfg; + enumerator_t *enumerator; + host_t *host; + char *str; + int family = AF_UNSPEC; + + if (local) + { + enumerator = this->my_hosts->create_enumerator(this->my_hosts); + } + else + { + enumerator = this->other_hosts->create_enumerator(this->other_hosts); + } + while (enumerator->enumerate(enumerator, &str)) + { + if (streq(str, "%any")) + { /* ignore %any as its family is undetermined */ + continue; + } + host = host_create_from_string(str, 0); + if (host) + { + if (family == AF_UNSPEC) + { + family = host->get_family(host); + } + else if (family != host->get_family(host)) + { + /* more than one address family defined */ + family = AF_UNSPEC; + host->destroy(host); + break; + } + } + DESTROY_IF(host); + } + enumerator->destroy(enumerator); + return family; +} + /** * Described in header. */ diff --git a/src/libcharon/config/ike_cfg.h b/src/libcharon/config/ike_cfg.h index adfcabf70..62f5b740c 100644 --- a/src/libcharon/config/ike_cfg.h +++ b/src/libcharon/config/ike_cfg.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Tobias Brunner + * Copyright (C) 2012-2015 Tobias Brunner * Copyright (C) 2005-2007 Martin Willi * Copyright (C) 2005 Jan Hutter * Hochschule fuer Technik Rapperswil @@ -254,4 +254,15 @@ ike_cfg_t *ike_cfg_create(ike_version_t version, bool certreq, bool force_encap, char *other, u_int16_t other_port, fragmentation_t fragmentation, u_int8_t dscp); +/** + * Determine the address family of the local or remtoe address(es). If multiple + * families are configured AF_UNSPEC is returned. %any is ignored (%any4|6 are + * not though). + * + * @param local TRUE to check local addresses, FALSE for remote + * @return address family of address(es) if distinct + */ +int ike_cfg_get_family(ike_cfg_t *this, bool local); + + #endif /** IKE_CFG_H_ @}*/ From 834bf7ca5f4dcd68278ea0f6b730f66527be9610 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Thu, 11 Jun 2015 16:10:25 +0200 Subject: [PATCH 3/4] ike-cfg: Add unit tests for ike_cfg_get_family() helper --- src/libcharon/tests/Makefile.am | 1 + src/libcharon/tests/libcharon_tests.h | 1 + src/libcharon/tests/suites/test_ike_cfg.c | 118 ++++++++++++++++++++++ 3 files changed, 120 insertions(+) create mode 100644 src/libcharon/tests/suites/test_ike_cfg.c diff --git a/src/libcharon/tests/Makefile.am b/src/libcharon/tests/Makefile.am index 539e62893..5fd8ca26d 100644 --- a/src/libcharon/tests/Makefile.am +++ b/src/libcharon/tests/Makefile.am @@ -3,6 +3,7 @@ TESTS = libcharon_tests check_PROGRAMS = $(TESTS) libcharon_tests_SOURCES = \ + suites/test_ike_cfg.c \ suites/test_mem_pool.c \ suites/test_message_chapoly.c \ libcharon_tests.h libcharon_tests.c diff --git a/src/libcharon/tests/libcharon_tests.h b/src/libcharon/tests/libcharon_tests.h index a5b37619c..fb82baccb 100644 --- a/src/libcharon/tests/libcharon_tests.h +++ b/src/libcharon/tests/libcharon_tests.h @@ -13,5 +13,6 @@ * for more details. */ +TEST_SUITE(ike_cfg_suite_create) TEST_SUITE(mem_pool_suite_create) TEST_SUITE_DEPEND(message_chapoly_suite_create, AEAD, ENCR_CHACHA20_POLY1305, 32) diff --git a/src/libcharon/tests/suites/test_ike_cfg.c b/src/libcharon/tests/suites/test_ike_cfg.c new file mode 100644 index 000000000..8062179b9 --- /dev/null +++ b/src/libcharon/tests/suites/test_ike_cfg.c @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2015 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_family(int expected, char *addr, bool local) +{ + ike_cfg_t *cfg; + int family; + + cfg = ike_cfg_create(IKEV2, FALSE, FALSE, local ? addr : "%any", 500, + local ? "%any" : addr, 500, FRAGMENTATION_NO, 0); + family = ike_cfg_get_family(cfg, local); + ck_assert_msg(expected == family, "expected family %d != %d (addr: '%s')", + expected, family, addr); + cfg->destroy(cfg); +} + +START_TEST(test_get_address_family_empty) +{ + assert_family(AF_UNSPEC, "", _i); +} +END_TEST + +START_TEST(test_get_address_family_addr) +{ + assert_family(AF_INET, "192.168.1.1", _i); + assert_family(AF_INET6, "fec::1", _i); +} +END_TEST + +START_TEST(test_get_address_family_multi) +{ + assert_family(AF_INET, "192.168.1.1,192.168.2.2", _i); + assert_family(AF_INET6, "fec::1,fec::2", _i); + + assert_family(AF_UNSPEC, "192.168.1.1,fec::1", _i); + assert_family(AF_UNSPEC, "fec::1,192.168.1.1", _i); +} +END_TEST + +START_TEST(test_get_address_family_any) +{ + assert_family(AF_UNSPEC, "%any", _i); + + assert_family(AF_INET, "%any4", _i); + assert_family(AF_INET, "0.0.0.0", _i); + + assert_family(AF_INET6, "%any6", _i); + assert_family(AF_INET6, "::", _i); + + assert_family(AF_INET, "192.168.1.1,%any", _i); + assert_family(AF_INET, "192.168.1.1,%any4", _i); + assert_family(AF_UNSPEC, "192.168.1.1,%any6", _i); + + assert_family(AF_INET6, "fec::1,%any", _i); + assert_family(AF_UNSPEC, "fec::1,%any4", _i); + assert_family(AF_INET6, "fec::1,%any6", _i); +} +END_TEST + +START_TEST(test_get_address_family_other) +{ + assert_family(AF_INET, "192.168.1.0", _i); + assert_family(AF_UNSPEC, "192.168.1.0/24", _i); + assert_family(AF_UNSPEC, "192.168.1.0-192.168.1.10", _i); + + assert_family(AF_INET, "192.168.1.0/24,192.168.2.1", _i); + assert_family(AF_INET, "192.168.1.0-192.168.1.10,192.168.2.1", _i); + assert_family(AF_INET6, "192.168.1.0/24,fec::1", _i); + assert_family(AF_INET6, "192.168.1.0-192.168.1.10,fec::1", _i); + + assert_family(AF_INET6, "fec::", _i); + assert_family(AF_UNSPEC, "fec::/64", _i); + assert_family(AF_UNSPEC, "fec::1-fec::10", _i); + + assert_family(AF_INET6, "fec::/64,fed::1", _i); + assert_family(AF_INET6, "fec::1-fec::10,fec::1", _i); + assert_family(AF_INET, "fec::/64,192.168.1.1", _i); + assert_family(AF_INET, "fec::1-fec::10,192.168.1.1", _i); + + assert_family(AF_UNSPEC, "strongswan.org", _i); + assert_family(AF_INET, "192.168.1.0,strongswan.org", _i); + assert_family(AF_INET6, "fec::1,strongswan.org", _i); +} +END_TEST + +Suite *ike_cfg_suite_create() +{ + Suite *s; + TCase *tc; + + s = suite_create("ike_cfg"); + + tc = tcase_create("ike_cfg_get_address_family"); + tcase_add_loop_test(tc, test_get_address_family_empty, 0, 2); + tcase_add_loop_test(tc, test_get_address_family_addr, 0, 2); + tcase_add_loop_test(tc, test_get_address_family_multi, 0, 2); + tcase_add_loop_test(tc, test_get_address_family_any, 0, 2); + tcase_add_loop_test(tc, test_get_address_family_other, 0, 2); + suite_add_tcase(s, tc); + + return s; +} From a11048adee0aeab8af10259f406363d7cc6beccc Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Thu, 11 Jun 2015 15:10:29 +0200 Subject: [PATCH 4/4] ike: Use address family of local address when resolving remote host If static local addresses are configured we should use their address family as a hint when resolving the remote address. We don't do this if %any is configured as this might break existing configurations (%any4 and %any6 are however used as hint). --- src/libcharon/sa/ike_sa.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/libcharon/sa/ike_sa.c b/src/libcharon/sa/ike_sa.c index 3aafa4c13..0c13c587c 100644 --- a/src/libcharon/sa/ike_sa.c +++ b/src/libcharon/sa/ike_sa.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2014 Tobias Brunner + * Copyright (C) 2006-2015 Tobias Brunner * Copyright (C) 2006 Daniel Roethlisberger * Copyright (C) 2005-2009 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -1200,6 +1200,19 @@ static void resolve_hosts(private_ike_sa_t *this) break; } + /* if an IP address is set locally, use the same family to resolve remote */ + if (family == AF_UNSPEC && !this->remote_host) + { + if (this->local_host) + { + family = this->local_host->get_family(this->local_host); + } + else + { + family = ike_cfg_get_family(this->ike_cfg, TRUE); + } + } + if (this->remote_host) { host = this->remote_host->clone(this->remote_host);