diff options
Diffstat (limited to 'src/libstrongswan')
-rw-r--r-- | src/libstrongswan/ipsec/ipsec_types.h | 4 | ||||
-rw-r--r-- | src/libstrongswan/selectors/traffic_selector.c | 121 | ||||
-rw-r--r-- | src/libstrongswan/selectors/traffic_selector.h | 19 | ||||
-rw-r--r-- | src/libstrongswan/tests/Makefile.am | 1 | ||||
-rw-r--r-- | src/libstrongswan/tests/suites/test_traffic_selector.c | 279 | ||||
-rw-r--r-- | src/libstrongswan/tests/tests.h | 1 |
6 files changed, 389 insertions, 36 deletions
diff --git a/src/libstrongswan/ipsec/ipsec_types.h b/src/libstrongswan/ipsec/ipsec_types.h index c1465e097..fa122af30 100644 --- a/src/libstrongswan/ipsec/ipsec_types.h +++ b/src/libstrongswan/ipsec/ipsec_types.h @@ -169,9 +169,9 @@ struct mark_t { }; /** - * Special mark value that uses the reqid of the CHILD_SA as mark + * Special mark value that uses a unique mark for each CHILD_SA */ -#define MARK_REQID (0xFFFFFFFF) +#define MARK_UNIQUE (0xFFFFFFFF) /** * Try to parse a mark_t from the given string of the form mark[/mask]. diff --git a/src/libstrongswan/selectors/traffic_selector.c b/src/libstrongswan/selectors/traffic_selector.c index 94b77467a..3b7f8c5a0 100644 --- a/src/libstrongswan/selectors/traffic_selector.c +++ b/src/libstrongswan/selectors/traffic_selector.c @@ -449,41 +449,9 @@ METHOD(traffic_selector_t, get_subset, traffic_selector_t*, } METHOD(traffic_selector_t, equals, bool, - private_traffic_selector_t *this, traffic_selector_t *other_public) + private_traffic_selector_t *this, traffic_selector_t *other) { - private_traffic_selector_t *other; - - other = (private_traffic_selector_t*)other_public; - if (this->type != other->type) - { - return FALSE; - } - if (!(this->from_port == other->from_port && - this->to_port == other->to_port && - this->protocol == other->protocol)) - { - return FALSE; - } - switch (this->type) - { - case TS_IPV4_ADDR_RANGE: - if (memeq(this->from4, other->from4, sizeof(this->from4)) && - memeq(this->to4, other->to4, sizeof(this->to4))) - { - return TRUE; - } - break; - case TS_IPV6_ADDR_RANGE: - if (memeq(this->from6, other->from6, sizeof(this->from6)) && - memeq(this->to6, other->to6, sizeof(this->to6))) - { - return TRUE; - } - break; - default: - break; - } - return FALSE; + return traffic_selector_cmp(&this->public, other, NULL) == 0; } METHOD(traffic_selector_t, get_from_address, chunk_t, @@ -717,12 +685,96 @@ METHOD(traffic_selector_t, clone_, traffic_selector_t*, } } +METHOD(traffic_selector_t, hash, u_int, + private_traffic_selector_t *this, u_int hash) +{ + return chunk_hash_inc(get_from_address(this), + chunk_hash_inc(get_to_address(this), + chunk_hash_inc(chunk_from_thing(this->from_port), + chunk_hash_inc(chunk_from_thing(this->to_port), + chunk_hash_inc(chunk_from_thing(this->protocol), + hash))))); +} + METHOD(traffic_selector_t, destroy, void, private_traffic_selector_t *this) { free(this); } +/** + * Compare two integers + */ +static int compare_int(int a, int b) +{ + return a - b; +} + +/* + * See header + */ +int traffic_selector_cmp(traffic_selector_t *a_pub, traffic_selector_t *b_pub, + void *opts) +{ + private_traffic_selector_t *a, *b; + int res; + + a = (private_traffic_selector_t*)a_pub; + b = (private_traffic_selector_t*)b_pub; + + /* IPv4 before IPv6 */ + res = compare_int(a->type, b->type); + if (res) + { + return res; + } + switch (a->type) + { + case TS_IPV4_ADDR_RANGE: + /* lower starting subnets first */ + res = memcmp(a->from4, b->from4, sizeof(a->from4)); + if (res) + { + return res; + } + /* larger subnets first */ + res = memcmp(b->to4, a->to4, sizeof(a->to4)); + if (res) + { + return res; + } + break; + case TS_IPV6_ADDR_RANGE: + res = memcmp(a->from6, b->from6, sizeof(a->from6)); + if (res) + { + return res; + } + res = memcmp(b->to6, a->to6, sizeof(a->to6)); + if (res) + { + return res; + } + break; + default: + return 1; + } + /* lower protocols first */ + res = compare_int(a->protocol, b->protocol); + if (res) + { + return res; + } + /* lower starting ports first */ + res = compare_int(a->from_port, b->from_port); + if (res) + { + return res; + } + /* larger port ranges first */ + return compare_int(b->to_port, a->to_port); +} + /* * see header */ @@ -933,6 +985,7 @@ static private_traffic_selector_t *traffic_selector_create(u_int8_t protocol, .set_address = _set_address, .to_subnet = _to_subnet, .clone = _clone_, + .hash = _hash, .destroy = _destroy, }, .from_port = from_port, diff --git a/src/libstrongswan/selectors/traffic_selector.h b/src/libstrongswan/selectors/traffic_selector.h index ab6813acc..cf9a2861b 100644 --- a/src/libstrongswan/selectors/traffic_selector.h +++ b/src/libstrongswan/selectors/traffic_selector.h @@ -221,6 +221,14 @@ struct traffic_selector_t { bool (*to_subnet) (traffic_selector_t *this, host_t **net, u_int8_t *mask); /** + * Create a hash value for the traffic selector. + * + * @param inc optional value for incremental hashing + * @return calculated hash value for the traffic selector + */ + u_int (*hash)(traffic_selector_t *this, u_int inc); + + /** * Destroys the ts object */ void (*destroy) (traffic_selector_t *this); @@ -249,6 +257,17 @@ static inline u_int8_t traffic_selector_icmp_code(u_int16_t port) } /** + * Compare two traffic selectors, usable as sort function + * + * @param a first selector to compare + * @param b second selector to compare + * @param opts optional sort options, currently unused + * @return > 0 if a > b, 0 if a == b, < 0 if a < b + */ +int traffic_selector_cmp(traffic_selector_t *a, traffic_selector_t *b, + void *opts); + +/** * Create a new traffic selector using human readable params. * * If protocol is ICMP or ICMPv6 the ports are interpreted as follows: If they diff --git a/src/libstrongswan/tests/Makefile.am b/src/libstrongswan/tests/Makefile.am index 85626cd44..8c081c673 100644 --- a/src/libstrongswan/tests/Makefile.am +++ b/src/libstrongswan/tests/Makefile.am @@ -29,6 +29,7 @@ tests_SOURCES = tests.h tests.c \ suites/test_enum.c \ suites/test_hashtable.c \ suites/test_identification.c \ + suites/test_traffic_selector.c \ suites/test_threading.c \ suites/test_process.c \ suites/test_watcher.c \ diff --git a/src/libstrongswan/tests/suites/test_traffic_selector.c b/src/libstrongswan/tests/suites/test_traffic_selector.c new file mode 100644 index 000000000..bb44bf5a0 --- /dev/null +++ b/src/libstrongswan/tests/suites/test_traffic_selector.c @@ -0,0 +1,279 @@ +/* + * Copyright (C) 2015 Martin Willi + * Copyright (C) 2015 revosec AG + * + * 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 <selectors/traffic_selector.h> + + +static void verify(const char *str, traffic_selector_t *ts) +{ + char buf[512]; + + ck_assert(ts != NULL); + snprintf(buf, sizeof(buf), "%R", ts); + ts->destroy(ts); + ck_assert_str_eq(buf, str); +} + +START_TEST(test_create_from_string) +{ + verify("10.1.0.0/16[tcp/http]", + traffic_selector_create_from_string(IPPROTO_TCP, TS_IPV4_ADDR_RANGE, + "10.1.0.0", 80, "10.1.255.255", 80)); + verify("10.1.0.1..10.1.0.99[udp/1234-1235]", + traffic_selector_create_from_string(IPPROTO_UDP, TS_IPV4_ADDR_RANGE, + "10.1.0.1", 1234, "10.1.0.99", 1235)); + verify("fec1::/64", + traffic_selector_create_from_string(0, TS_IPV6_ADDR_RANGE, + "fec1::", 0, "fec1::ffff:ffff:ffff:ffff", 65535)); +} +END_TEST + +START_TEST(test_create_from_cidr) +{ + verify("10.1.0.0/16", + traffic_selector_create_from_cidr("10.1.0.0/16", 0, 0, 65535)); + verify("10.1.0.1/32[udp/1234-1235]", + traffic_selector_create_from_cidr("10.1.0.1/32", IPPROTO_UDP, + 1234, 1235)); +} +END_TEST + +START_TEST(test_create_from_bytes) +{ + verify("10.1.0.0/16", + traffic_selector_create_from_bytes(0, TS_IPV4_ADDR_RANGE, + chunk_from_chars(0x0a,0x01,0x00,0x00), 0, + chunk_from_chars(0x0a,0x01,0xff,0xff), 65535)); +} +END_TEST + +START_TEST(test_create_from_subnet) +{ + verify("10.1.0.0/16", + traffic_selector_create_from_subnet( + host_create_from_string("10.1.0.0", 0), 16, 0, 0, 65535)); +} +END_TEST + + +START_TEST(test_subset) +{ + traffic_selector_t *a, *b; + + a = traffic_selector_create_from_cidr("10.1.0.0/16", 0, 0, 65535); + b = traffic_selector_create_from_cidr("10.1.5.0/24", 0, 0, 65535); + verify("10.1.5.0/24", a->get_subset(a, b)); + a->destroy(a); + b->destroy(b); +} +END_TEST + +START_TEST(test_subset_port) +{ + traffic_selector_t *a, *b; + + a = traffic_selector_create_from_cidr("10.0.0.0/8", IPPROTO_TCP, 55, 60); + b = traffic_selector_create_from_cidr("10.2.7.16/30", 0, 0, 65535); + verify("10.2.7.16/30[tcp/55-60]", a->get_subset(a, b)); + a->destroy(a); + b->destroy(b); +} +END_TEST + +START_TEST(test_subset_equal) +{ + traffic_selector_t *a, *b; + + a = traffic_selector_create_from_cidr("10.1.0.0/16", IPPROTO_TCP, 80, 80); + b = traffic_selector_create_from_cidr("10.1.0.0/16", IPPROTO_TCP, 80, 80); + verify("10.1.0.0/16[tcp/http]", a->get_subset(a, b)); + a->destroy(a); + b->destroy(b); +} +END_TEST + +START_TEST(test_subset_nonet) +{ + traffic_selector_t *a, *b; + + a = traffic_selector_create_from_cidr("10.1.0.0/16", 0, 0, 65535); + b = traffic_selector_create_from_cidr("10.2.0.0/16", 0, 0, 65535); + ck_assert(a->get_subset(a, b) == NULL); + a->destroy(a); + b->destroy(b); +} +END_TEST + +START_TEST(test_subset_noport) +{ + traffic_selector_t *a, *b; + + a = traffic_selector_create_from_cidr("10.1.0.0/16", 0, 0, 9999); + b = traffic_selector_create_from_cidr("10.1.0.0/16", 0, 10000, 65535); + ck_assert(a->get_subset(a, b) == NULL); + a->destroy(a); + b->destroy(b); +} +END_TEST + +START_TEST(test_subset_noproto) +{ + traffic_selector_t *a, *b; + + a = traffic_selector_create_from_cidr("10.1.0.0/16", IPPROTO_TCP, 0, 65535); + b = traffic_selector_create_from_cidr("10.1.0.0/16", IPPROTO_UDP, 0, 65535); + ck_assert(a->get_subset(a, b) == NULL); + a->destroy(a); + b->destroy(b); +} +END_TEST + +START_TEST(test_subset_nofamily) +{ + traffic_selector_t *a, *b; + + a = traffic_selector_create_from_cidr("0.0.0.0/0", 0, 0, 65535); + b = traffic_selector_create_from_cidr("::/0", 0, 0, 65535); + ck_assert(a->get_subset(a, b) == NULL); + a->destroy(a); + b->destroy(b); +} +END_TEST + +struct { + char *net; + char *host; + bool inc; +} include_tests[] = { + { "0.0.0.0/0", "192.168.1.2", TRUE }, + { "::/0", "fec2::1", TRUE }, + { "fec2::/64", "fec2::afaf", TRUE }, + { "10.1.0.0/16", "10.1.0.1", TRUE }, + { "10.5.6.7/32", "10.5.6.7", TRUE }, + { "0.0.0.0/0", "fec2::1", FALSE }, + { "::/0", "1.2.3.4", FALSE }, + { "10.0.0.0/16", "10.1.0.0", FALSE }, + { "fec2::/64", "fec2:0:0:1::afaf", FALSE }, +}; + +START_TEST(test_includes) +{ + traffic_selector_t *ts; + host_t *h; + + ts = traffic_selector_create_from_cidr(include_tests[_i].net, 0, 0, 65535); + h = host_create_from_string(include_tests[_i].host, 0); + ck_assert(ts->includes(ts, h) == include_tests[_i].inc); + ts->destroy(ts); + h->destroy(h); +} +END_TEST + +struct { + int res; + struct { + char *net; + u_int8_t proto; + u_int16_t from_port; + u_int16_t to_port; + } a, b; +} cmp_tests[] = { + { 0, { "10.0.0.0/8", 0, 0, 65535 }, { "10.0.0.0/8", 0, 0, 65535 }, }, + { 0, { "10.0.0.0/8", 17, 123, 456 }, { "10.0.0.0/8", 17, 123, 456 }, }, + { 0, { "fec2::/64", 0, 0, 65535 }, { "fec2::/64", 0, 0, 65535 }, }, + { 0, { "fec2::/64", 4, 0, 65535 }, { "fec2::/64", 4, 0, 65535 }, }, + + { -1, { "1.0.0.0/8", 0, 0, 65535 }, { "2.0.0.0/8", 0, 0, 65535 }, }, + { 1, { "2.0.0.0/8", 0, 0, 65535 }, { "1.0.0.0/8", 0, 0, 65535 }, }, + { -1, { "1.0.0.0/8", 0, 0, 65535 }, { "1.0.0.0/16", 0, 0, 65535 }, }, + { 1, { "1.0.0.0/16", 0, 0, 65535 }, { "1.0.0.0/8", 0, 0, 65535 }, }, + + { -1, { "10.0.0.0/8", 0, 0, 65535 }, { "fec2::/64", 0, 0, 65535 }, }, + { 1, { "fec2::/64", 0, 0, 65535 }, { "10.0.0.0/8", 0, 0, 65535 }, }, + + { -1, { "10.0.0.0/8", 16, 123, 456 }, { "10.0.0.0/8", 17, 123, 456 }, }, + { 1, { "fec2::/64", 5, 0, 65535 }, { "fec2::/64", 4, 0, 65535 }, }, + + { -1, { "10.0.0.0/8", 17, 111, 456 }, { "10.0.0.0/8", 17, 222, 456 }, }, + { 1, { "fec2::/64", 17, 555, 65535 }, { "fec2::/64", 17, 444, 65535 },}, + + { -1, { "10.0.0.0/8", 17, 55, 65535 }, { "10.0.0.0/8", 17, 55, 666 }, }, + { 1, { "fec2::/64", 17, 55, 111 }, { "fec2::/64", 17, 55, 4567 }, }, + +}; + +START_TEST(test_cmp) +{ + traffic_selector_t *a, *b; + + a = traffic_selector_create_from_cidr( + cmp_tests[_i].a.net, cmp_tests[_i].a.proto, + cmp_tests[_i].a.from_port, cmp_tests[_i].a.to_port); + b = traffic_selector_create_from_cidr( + cmp_tests[_i].b.net, cmp_tests[_i].b.proto, + cmp_tests[_i].b.from_port, cmp_tests[_i].b.to_port); + switch (cmp_tests[_i].res) + { + case 0: + ck_assert(traffic_selector_cmp(a, b, NULL) == 0); + break; + case 1: + ck_assert(traffic_selector_cmp(a, b, NULL) > 0); + break; + case -1: + ck_assert(traffic_selector_cmp(a, b, NULL) < 0); + break; + } + a->destroy(a); + b->destroy(b); +} +END_TEST + +Suite *traffic_selector_suite_create() +{ + Suite *s; + TCase *tc; + + s = suite_create("traffic selector"); + + tc = tcase_create("create"); + tcase_add_test(tc, test_create_from_string); + tcase_add_test(tc, test_create_from_cidr); + tcase_add_test(tc, test_create_from_bytes); + tcase_add_test(tc, test_create_from_subnet); + suite_add_tcase(s, tc); + + tc = tcase_create("subset"); + tcase_add_test(tc, test_subset); + tcase_add_test(tc, test_subset_port); + tcase_add_test(tc, test_subset_equal); + tcase_add_test(tc, test_subset_nonet); + tcase_add_test(tc, test_subset_noport); + tcase_add_test(tc, test_subset_noproto); + tcase_add_test(tc, test_subset_nofamily); + suite_add_tcase(s, tc); + + tc = tcase_create("includes"); + tcase_add_loop_test(tc, test_includes, 0, countof(include_tests)); + suite_add_tcase(s, tc); + + tc = tcase_create("cmp"); + tcase_add_loop_test(tc, test_cmp, 0, countof(cmp_tests)); + suite_add_tcase(s, tc); + + return s; +} diff --git a/src/libstrongswan/tests/tests.h b/src/libstrongswan/tests/tests.h index 440e38a9a..d01158649 100644 --- a/src/libstrongswan/tests/tests.h +++ b/src/libstrongswan/tests/tests.h @@ -23,6 +23,7 @@ TEST_SUITE(linked_list_enumerator_suite_create) TEST_SUITE(hashtable_suite_create) TEST_SUITE(array_suite_create) TEST_SUITE(identification_suite_create) +TEST_SUITE(traffic_selector_suite_create) TEST_SUITE(threading_suite_create) TEST_SUITE(process_suite_create) TEST_SUITE(watcher_suite_create) |