From: Tobias Brunner Date: Tue, 25 Mar 2025 11:43:26 +0000 (+0100) Subject: traffic-selector-list: Add helper class to manage a collection of TS X-Git-Tag: 6.0.2dr1~6^2~6 X-Git-Url: http://git.ipfire.org/gitweb/gitweb.cgi?a=commitdiff_plain;h=4b468126ca17b26bc2ed5271c9c0fda1599729c2;p=thirdparty%2Fstrongswan.git traffic-selector-list: Add helper class to manage a collection of TS Provides functions to optionally resolve dynamic TS and to narrow them based on a list of supplied TS. --- diff --git a/src/libstrongswan/Android.mk b/src/libstrongswan/Android.mk index 1f2d0af521..ce78233d5c 100644 --- a/src/libstrongswan/Android.mk +++ b/src/libstrongswan/Android.mk @@ -42,7 +42,7 @@ networking/streams/stream_tcp.c networking/streams/stream_service_tcp.c \ pen/pen.c plugins/plugin_loader.c plugins/plugin_feature.c processing/jobs/job.c \ processing/jobs/callback_job.c processing/processor.c processing/scheduler.c \ processing/watcher.c resolver/resolver_manager.c resolver/rr_set.c \ -selectors/sec_label.c selectors/traffic_selector.c \ +selectors/sec_label.c selectors/traffic_selector.c selectors/traffic_selector_list.c \ settings/settings.c settings/settings_types.c \ settings/settings_parser.c settings/settings_lexer.c utils/cpu_feature.c \ utils/utils.c utils/chunk.c utils/debug.c utils/enum.c utils/identification.c \ diff --git a/src/libstrongswan/Makefile.am b/src/libstrongswan/Makefile.am index 8d3c869bd9..79d94be9b8 100644 --- a/src/libstrongswan/Makefile.am +++ b/src/libstrongswan/Makefile.am @@ -40,7 +40,7 @@ networking/streams/stream_tcp.c networking/streams/stream_service_tcp.c \ pen/pen.c plugins/plugin_loader.c plugins/plugin_feature.c processing/jobs/job.c \ processing/jobs/callback_job.c processing/processor.c processing/scheduler.c \ processing/watcher.c resolver/resolver_manager.c resolver/rr_set.c \ -selectors/sec_label.c selectors/traffic_selector.c \ +selectors/sec_label.c selectors/traffic_selector.c selectors/traffic_selector_list.c \ settings/settings.c settings/settings_types.c \ settings/settings_parser.y settings/settings_lexer.l utils/cpu_feature.c \ utils/utils.c utils/chunk.c utils/debug.c utils/enum.c utils/identification.c \ @@ -125,7 +125,7 @@ resolver/rr.h resolver/resolver_manager.h \ plugins/plugin_loader.h plugins/plugin.h plugins/plugin_feature.h \ processing/jobs/job.h processing/jobs/callback_job.h processing/processor.h \ processing/scheduler.h processing/watcher.h \ -selectors/sec_label.h selectors/traffic_selector.h \ +selectors/sec_label.h selectors/traffic_selector.h selectors/traffic_selector_list.h \ settings/settings.h settings/settings_parser.h threading/thread_value.h \ threading/thread.h threading/windows/thread.h \ threading/mutex.h threading/condvar.h threading/spinlock.h threading/semaphore.h \ diff --git a/src/libstrongswan/selectors/traffic_selector_list.c b/src/libstrongswan/selectors/traffic_selector_list.c new file mode 100644 index 0000000000..71c83fb678 --- /dev/null +++ b/src/libstrongswan/selectors/traffic_selector_list.c @@ -0,0 +1,292 @@ +/* + * Copyright (C) 2008-2025 Tobias Brunner + * Copyright (C) 2005-2007 Martin Willi + * + * Copyright (C) secunet Security Networks 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 . + * + * 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 "traffic_selector_list.h" + +#include + +typedef struct private_traffic_selector_list_t private_traffic_selector_list_t; + +/** + * Private data. + */ +struct private_traffic_selector_list_t { + + /** + * Public interface. + */ + traffic_selector_list_t public; + + /** + * List of managed traffic selectors. + */ + linked_list_t *ts; +}; + +METHOD(traffic_selector_list_t, add, void, + private_traffic_selector_list_t *this, traffic_selector_t *ts) +{ + this->ts->insert_last(this->ts, ts); +} + +METHOD(traffic_selector_list_t, create_enumerator, enumerator_t*, + private_traffic_selector_list_t *this) +{ + return this->ts->create_enumerator(this->ts); +} + +/** + * Create a copy of the traffic selectors in the given list, while resolving + * "dynamic" traffic selectors using the given hosts, if any. When not narrowing + * as initiator, we also replace TS in transport mode. + */ +static linked_list_t *resolve_dynamic_ts(private_traffic_selector_list_t *this, + linked_list_t *hosts, bool narrowing, + bool force_dynamic) +{ + enumerator_t *e1, *e2; + traffic_selector_t *ts1, *ts2; + linked_list_t *result; + host_t *host; + + if (!hosts || !hosts->get_count(hosts)) + { + return this->ts->clone_offset(this->ts, + offsetof(traffic_selector_t, clone)); + } + + result = linked_list_create(); + e1 = this->ts->create_enumerator(this->ts); + while (e1->enumerate(e1, &ts1)) + { + /* set hosts if TS is dynamic or if forced as initiator in + * transport mode */ + bool dynamic = ts1->is_dynamic(ts1); + if (!dynamic && !force_dynamic) + { + result->insert_last(result, ts1->clone(ts1)); + continue; + } + e2 = hosts->create_enumerator(hosts); + while (e2->enumerate(e2, &host)) + { + if (!dynamic && !host->is_anyaddr(host) && + !ts1->includes(ts1, host)) + { /* for transport mode, we skip TS that don't match + * specific IPs */ + continue; + } + ts2 = ts1->clone(ts1); + if (dynamic || !host->is_anyaddr(host)) + { /* don't make regular TS larger than they were */ + ts2->set_address(ts2, host); + } + result->insert_last(result, ts2); + } + e2->destroy(e2); + } + e1->destroy(e1); + return result; +} + +/** + * Remove duplicate traffic selectors in the given list. + */ +static void remove_duplicate_ts(linked_list_t *list) +{ + enumerator_t *e1, *e2; + traffic_selector_t *ts1, *ts2; + + e1 = list->create_enumerator(list); + e2 = list->create_enumerator(list); + while (e1->enumerate(e1, &ts1)) + { + while (e2->enumerate(e2, &ts2)) + { + if (ts1 != ts2) + { + if (ts2->is_contained_in(ts2, ts1)) + { + list->remove_at(list, e2); + ts2->destroy(ts2); + list->reset_enumerator(list, e1); + break; + } + if (ts1->is_contained_in(ts1, ts2)) + { + list->remove_at(list, e1); + ts1->destroy(ts1); + break; + } + } + } + list->reset_enumerator(list, e2); + } + e1->destroy(e1); + e2->destroy(e2); +} + +METHOD(traffic_selector_list_t, get, linked_list_t*, + private_traffic_selector_list_t *this, linked_list_t *hosts, + bool force_dynamic) +{ + linked_list_t *result; + + result = resolve_dynamic_ts(this, hosts, FALSE, force_dynamic); + remove_duplicate_ts(result); + return result; +} + +METHOD(traffic_selector_list_t, select_, linked_list_t*, + private_traffic_selector_list_t *this, linked_list_t *supplied, + linked_list_t *hosts, bool force_dynamic, bool *narrowed) +{ + enumerator_t *e1, *e2; + traffic_selector_t *ts1, *ts2, *selected; + linked_list_t *resolved, *result; + + result = linked_list_create(); + resolved = resolve_dynamic_ts(this, hosts, supplied != NULL, force_dynamic); + + if (!supplied) + { + while (resolved->remove_first(resolved, (void**)&ts1) == SUCCESS) + { + DBG2(DBG_CFG, " %R", ts1); + result->insert_last(result, ts1); + } + } + else + { + e1 = resolved->create_enumerator(resolved); + e2 = supplied->create_enumerator(supplied); + /* enumerate all configured/resolved selectors */ + while (e1->enumerate(e1, &ts1)) + { + /* enumerate all supplied traffic selectors */ + while (e2->enumerate(e2, &ts2)) + { + selected = ts1->get_subset(ts1, ts2); + if (selected) + { + DBG2(DBG_CFG, " config: %R, received: %R => match: %R", + ts1, ts2, selected); + result->insert_last(result, selected); + } + else + { + DBG2(DBG_CFG, " config: %R, received: %R => no match", + ts1, ts2); + } + } + supplied->reset_enumerator(supplied, e2); + } + e1->destroy(e1); + e2->destroy(e2); + + if (narrowed) + { + *narrowed = FALSE; + + e1 = resolved->create_enumerator(resolved); + e2 = result->create_enumerator(result); + while (e1->enumerate(e1, &ts1)) + { + if (!e2->enumerate(e2, &ts2) || !ts1->equals(ts1, ts2)) + { + *narrowed = TRUE; + break; + } + } + e1->destroy(e1); + e2->destroy(e2); + } + } + resolved->destroy_offset(resolved, offsetof(traffic_selector_t, destroy)); + remove_duplicate_ts(result); + return result; +} + +METHOD(traffic_selector_list_t, equals, bool, + private_traffic_selector_list_t *this, traffic_selector_list_t *other_pub) +{ + private_traffic_selector_list_t *other = (private_traffic_selector_list_t*)other_pub; + return this->ts->equals_offset(this->ts, other->ts, + offsetof(traffic_selector_t, equals)); +} + +METHOD(traffic_selector_list_t, destroy, void, + private_traffic_selector_list_t *this) +{ + this->ts->destroy_offset(this->ts, offsetof(traffic_selector_t, destroy)); + free(this); +} + +METHOD(traffic_selector_list_t, clone_, traffic_selector_list_t*, + private_traffic_selector_list_t *this) +{ + return traffic_selector_list_create_from_list( + this->ts->clone_offset(this->ts, offsetof(traffic_selector_t, clone))); +} + +/* + * Described in header + */ +traffic_selector_list_t *traffic_selector_list_create_from_list(linked_list_t *list) +{ + private_traffic_selector_list_t *this; + + INIT(this, + .public = { + .add = _add, + .create_enumerator = _create_enumerator, + .get = _get, + .select = _select_, + .equals = _equals, + .clone = _clone_, + .destroy = _destroy, + }, + .ts = list, + ); + return &this->public; +} + +/* + * Described in header + */ +traffic_selector_list_t *traffic_selector_list_create() +{ + return traffic_selector_list_create_from_list(linked_list_create()); +} + +/* + * Described in header + */ +traffic_selector_list_t *traffic_selector_list_create_from_enumerator( + enumerator_t *enumerator) +{ + traffic_selector_list_t *this = traffic_selector_list_create(); + traffic_selector_t *ts; + + while (enumerator->enumerate(enumerator, &ts)) + { + add((private_traffic_selector_list_t*)this, ts->clone(ts)); + } + enumerator->destroy(enumerator); + + return this; +} diff --git a/src/libstrongswan/selectors/traffic_selector_list.h b/src/libstrongswan/selectors/traffic_selector_list.h new file mode 100644 index 0000000000..30fd60704d --- /dev/null +++ b/src/libstrongswan/selectors/traffic_selector_list.h @@ -0,0 +1,155 @@ +/* + * Copyright (C) 2025 Tobias Brunner + * + * Copyright (C) secunet Security Networks 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 . + * + * 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. + */ + +/** + * @defgroup traffic_selector_list traffic_selector_list + * @{ @ingroup selectors + */ + +#ifndef TRAFFIC_SELECTOR_LIST_H_ +#define TRAFFIC_SELECTOR_LIST_H_ + +typedef struct traffic_selector_list_t traffic_selector_list_t; + +#include "traffic_selector.h" + +/** + * Collection of traffic selectors that can be narrowed to a new set of + * traffic selectors. + */ +struct traffic_selector_list_t { + + /** + * Add a traffic selector to the collection. + * + * @param ts traffic_selector to add (adopted) + */ + void (*add)(traffic_selector_list_t *this, traffic_selector_t *ts); + + /** + * Enumerate all traffic selectors in the collection. + * + * Similar to calling get() without \p hosts, but does not clone the traffic + * selectors and duplicates are not removed. + * + * @return enumerator over traffic_selector_t* + */ + enumerator_t *(*create_enumerator)(traffic_selector_list_t *this); + + /** + * Get a list of traffic selectors contained in the collection. + * + * Some traffic selectors may be "dynamic", meaning they are narrowed down + * to a specific address (host-to-host or virtual-IP setups). Use the + * \p hosts parameter to narrow such traffic selectors to an address. If + * \p force_dynamic is also passed, even non-dynamic traffic selectors that + * match are replaced using the IPs in \p hosts (useful as initiator with + * transport mode). + * + * If \p hosts is not passed, the list of traffic selectors is returned as + * configured, except that exact duplicates are removed. However, note that + * "dynamic" traffic selectors are not considered duplicates. + * + * Returned list and its traffic selectors must be destroyed after use. + * + * Note that this method does not log anything. If logging is required, use + * select() without passing supplied traffic selectors. + * + * @param hosts addresses to use for narrowing "dynamic" TS, host_t + * @param force_dynamic TRUE to replace non-"dynamic" TS with \p hosts as + * initiator in transport mode + * @return list containing the traffic selectors + */ + linked_list_t *(*get)(traffic_selector_list_t *this, linked_list_t *hosts, + bool force_dynamic); + + /** + * Select a list of traffic selectors contained in the collection. + * + * If a list with traffic selectors is supplied, these are used to narrow + * down the traffic selectors to the greatest common subset. + * + * Some traffic selectors may be "dynamic", meaning they are narrowed down + * to a specific address (host-to-host or virtual-IP setups). Use the + * \p hosts parameter to narrow such traffic selectors to an address. If + * \p force_dynamic is also passed, even non-dynamic traffic selectors that + * match are replaced using the IPs in \p hosts (useful as initiator with + * transport mode). + * + * Details about the selection of each individual traffic selector are + * logged. + * + * Returned list and its traffic selectors must be destroyed after use. + * + * @param supplied list with TS to select from, or NULL + * @param hosts addresses to use for narrowing "dynamic" TS', host_t + * @param force_dynamic TRUE to replace non-"dynamic" TS with \p hosts as + * initiator in transport mode + * @param narrowed[out] optional flag that indicates if any TS were narrowed + * @return list containing the traffic selectors + */ + linked_list_t *(*select)(traffic_selector_list_t *this, + linked_list_t *supplied, linked_list_t *hosts, + bool force_dynamic, bool *narrowed); + + /** + * Compare two collections of traffic selectors. + * + * @param other collection to compare with this + * @return TRUE if equal, FALSE otherwise + */ + bool (*equals)(traffic_selector_list_t *this, traffic_selector_list_t *other); + + /** + * Clone this collection of traffic selectors. + * + * @return cloned collection + */ + traffic_selector_list_t *(*clone)(traffic_selector_list_t *this); + + /** + * Destroys this collection. + */ + void (*destroy)(traffic_selector_list_t *this); +}; + +/** + * Create an empty traffic selector collection. + * + * @return created object + */ +traffic_selector_list_t *traffic_selector_list_create(); + +/** + * Create a collection with traffic selectors from the given list (adopted). + * + * @param list list of traffic_selector_t (adopted) + * @return created object + */ +traffic_selector_list_t *traffic_selector_list_create_from_list( + linked_list_t *list); + +/** + * Create a collection with traffic selectors from the given enumerator (objects + * are cloned, the enumerator is destroyed). + * + * @param enumerator enumerator over traffic_selector_t (cloned/destroyed) + * @return created object + */ +traffic_selector_list_t *traffic_selector_list_create_from_enumerator( + enumerator_t *enumerator); + +#endif /** TRAFFIC_SELECTOR_LIST_H_ @}*/ diff --git a/src/libstrongswan/tests/suites/test_traffic_selector.c b/src/libstrongswan/tests/suites/test_traffic_selector.c index cbcc0c08d3..45daa90828 100644 --- a/src/libstrongswan/tests/suites/test_traffic_selector.c +++ b/src/libstrongswan/tests/suites/test_traffic_selector.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015 Tobias Brunner + * Copyright (C) 2015-2025 Tobias Brunner * Copyright (C) 2015 Martin Willi * * Copyright (C) secunet Security Networks AG @@ -18,6 +18,7 @@ #include "test_suite.h" #include +#include static void verify(const char *str, const char *alt, traffic_selector_t *ts) @@ -814,6 +815,199 @@ START_TEST(test_printf_hook_hash) } END_TEST +/** + * Create a linked list of either traffic selectors or hosts from a + * comma-separated list. + */ +static linked_list_t *create_list(char *str, bool hosts) +{ + linked_list_t *list = linked_list_create(); + enumerator_t *enumerator; + char *item; + void *obj; + + enumerator = enumerator_create_token(str, " ", ""); + while (enumerator->enumerate(enumerator, &item)) + { + if (hosts) + { + obj = host_create_from_string(item, 0); + } + else if (streq(item, "dynamic")) + { + obj = traffic_selector_create_dynamic(0, 0, 65535); + } + else + { + obj = traffic_selector_create_from_cidr(item, 0, 0, 65535); + } + list->insert_last(list, obj); + } + enumerator->destroy(enumerator); + return list; +} + +struct { + char *ts; + char *hosts; + char *get; + char *get_force; +} list_get_tests[] = { + { "dynamic", NULL, "dynamic", "dynamic" }, + { "dynamic", "10.0.1.1", "10.0.1.1/32", "10.0.1.1/32" }, + { "dynamic", "10.0.1.1 192.168.0.1", + "10.0.1.1/32 192.168.0.1/32", "10.0.1.1/32 192.168.0.1/32" }, + { "0.0.0.0/0", "10.0.1.1", "0.0.0.0/0", "10.0.1.1/32" }, + { "0.0.0.0/0", "10.0.1.1 192.168.0.1", + "0.0.0.0/0", "10.0.1.1/32 192.168.0.1/32" }, + { "10.0.1.0/24", "10.0.1.1", "10.0.1.0/24", "10.0.1.1/32" }, + { "10.0.2.0/24", "10.0.1.1", "10.0.2.0/24", "" }, + { "10.0.2.0/24", "10.0.1.1 10.0.2.1", "10.0.2.0/24", "10.0.2.1/32" }, + /* two dynamic TS are not treated as duplicates */ + { "dynamic dynamic", NULL, "dynamic dynamic", "dynamic dynamic" }, + { "dynamic dynamic", "10.0.1.1", "10.0.1.1/32", "10.0.1.1/32" }, + { "dynamic dynamic", "10.0.1.1 192.168.0.1", + "10.0.1.1/32 192.168.0.1/32", "10.0.1.1/32 192.168.0.1/32" }, + { "0.0.0.0/0 0.0.0.0/0", "10.0.1.1", "0.0.0.0/0", "10.0.1.1/32" }, + { "0.0.0.0/0 0.0.0.0/0", "10.0.1.1 192.168.0.1", + "0.0.0.0/0", "10.0.1.1/32 192.168.0.1/32" }, + { "10.0.1.0/24 10.0.1.0/24", NULL, "10.0.1.0/24", "10.0.1.0/24" }, + { "10.0.1.1/32 10.0.1.0/24", NULL, "10.0.1.0/24", "10.0.1.0/24" }, + { "10.0.1.0/24 10.0.1.1/32", NULL, "10.0.1.0/24", "10.0.1.0/24" }, + { "10.0.1.0/24 10.0.2.0/24", NULL, + "10.0.1.0/24 10.0.2.0/24", "10.0.1.0/24 10.0.2.0/24" }, + { "10.0.1.0/24 10.0.2.0/24", "10.0.1.1", + "10.0.1.0/24 10.0.2.0/24", "10.0.1.1/32" }, + { "10.0.1.0/24 10.0.2.0/24", "10.0.1.1 10.0.2.1", + "10.0.1.0/24 10.0.2.0/24", "10.0.1.1/32 10.0.2.1/32" }, +}; + +START_TEST(test_list_get) +{ + traffic_selector_list_t *ts; + linked_list_t *list, *hosts, *result; + + list = create_list(list_get_tests[_i].ts, FALSE); + ts = traffic_selector_list_create_from_enumerator(list->create_enumerator(list)); + hosts = list_get_tests[_i].hosts ? create_list(list_get_tests[_i].hosts, TRUE) : NULL; + + result = ts->get(ts, hosts, FALSE); + verify_list(list_get_tests[_i].get, NULL, result); + + result = ts->get(ts, hosts, TRUE); + verify_list(list_get_tests[_i].get_force, NULL, result); + + DESTROY_OFFSET_IF(hosts, offsetof(host_t, destroy)); + list->destroy_offset(list, offsetof(traffic_selector_t, destroy)); + ts->destroy(ts); +} +END_TEST + +struct { + char *ts; + char *hosts; + char *supplied; + char *select; + char *select_force; + bool narrowed; +} list_select_tests[] = { + { "dynamic", NULL, NULL, "dynamic", "dynamic", FALSE }, + { "dynamic", NULL, "10.0.1.0/24", "", "", TRUE }, + { "dynamic", "10.0.1.1", "0.0.0.0/0", "10.0.1.1/32", "10.0.1.1/32", FALSE }, + { "dynamic", "10.0.1.1", "10.0.1.1/32", "10.0.1.1/32", "10.0.1.1/32", FALSE }, + { "dynamic", "10.0.1.1 192.168.0.1", "10.0.1.0/24", + "10.0.1.1/32", "10.0.1.1/32", TRUE }, + { "dynamic", "10.0.1.1 192.168.0.1", "10.0.1.0/24 192.168.0.0/24", + "10.0.1.1/32 192.168.0.1/32", "10.0.1.1/32 192.168.0.1/32", FALSE }, + { "0.0.0.0/0", NULL, "0.0.0.0/0", "0.0.0.0/0", "0.0.0.0/0", FALSE }, + { "0.0.0.0/0", "10.0.1.1", "0.0.0.0/0", "0.0.0.0/0", "10.0.1.1/32", FALSE }, + { "0.0.0.0/0", NULL, "10.0.1.0/24", "10.0.1.0/24", "10.0.1.0/24", TRUE }, + { "0.0.0.0/0", NULL, "10.0.1.0/24 10.0.2.0/24", + "10.0.1.0/24 10.0.2.0/24", "10.0.1.0/24 10.0.2.0/24", TRUE }, + { "0.0.0.0/0", NULL, "10.0.2.0/24 10.0.1.0/24", + "10.0.2.0/24 10.0.1.0/24", "10.0.2.0/24 10.0.1.0/24", TRUE }, + { "10.0.1.0/24", NULL, "0.0.0.0/0", "10.0.1.0/24", "10.0.1.0/24", FALSE }, + { "10.0.1.0/24", "10.0.1.1", "0.0.0.0/0", "10.0.1.0/24", "10.0.1.1/32", FALSE }, + { "10.0.1.0/24 10.0.2.0/24", NULL, "0.0.0.0/0", + "10.0.1.0/24 10.0.2.0/24", "10.0.1.0/24 10.0.2.0/24", FALSE }, + { "10.0.2.0/24 10.0.1.0/24", NULL, "0.0.0.0/0", + "10.0.2.0/24 10.0.1.0/24", "10.0.2.0/24 10.0.1.0/24", FALSE }, + { "10.0.1.0/24 10.0.2.0/24", NULL, "10.0.2.0/24 10.0.1.0/24", + "10.0.1.0/24 10.0.2.0/24", "10.0.1.0/24 10.0.2.0/24", FALSE }, + { "10.0.1.0/24 10.0.2.0/24", NULL, "10.0.1.1/32 10.0.1.0/24", + "10.0.1.0/24", "10.0.1.0/24", TRUE }, + { "10.0.1.0/24 10.0.2.0/24", NULL, "10.0.2.1/32 10.0.1.0/24", + "10.0.1.0/24 10.0.2.1/32", "10.0.1.0/24 10.0.2.1/32", TRUE }, +}; + +START_TEST(test_list_select) +{ + traffic_selector_list_t *ts; + linked_list_t *list, *hosts, *supplied, *result; + bool narrowed = FALSE; + + list = create_list(list_select_tests[_i].ts, FALSE); + ts = traffic_selector_list_create_from_enumerator(list->create_enumerator(list)); + hosts = list_select_tests[_i].hosts ? create_list(list_select_tests[_i].hosts, TRUE) : NULL; + supplied = list_select_tests[_i].supplied ? create_list(list_select_tests[_i].supplied, FALSE) : NULL; + + result = ts->select(ts, supplied, hosts, FALSE, &narrowed); + verify_list(list_select_tests[_i].select, NULL, result); + ck_assert(narrowed == list_select_tests[_i].narrowed); + + result = ts->select(ts, supplied, hosts, TRUE, &narrowed); + verify_list(list_select_tests[_i].select_force, NULL, result); + ck_assert(narrowed == list_select_tests[_i].narrowed); + + DESTROY_OFFSET_IF(hosts, offsetof(host_t, destroy)); + DESTROY_OFFSET_IF(supplied, offsetof(traffic_selector_t, destroy)); + list->destroy_offset(list, offsetof(traffic_selector_t, destroy)); + ts->destroy(ts); +} +END_TEST + +START_TEST(test_list_equals) +{ + traffic_selector_list_t *ts1, *ts2; + + ts1 = traffic_selector_list_create(); + ts2 = traffic_selector_list_create(); + ck_assert(ts1->equals(ts1, ts2)); + + ts1->add(ts1, traffic_selector_create_from_cidr("10.0.1.0/24", 0, 0, 65535)); + ck_assert(!ts1->equals(ts1, ts2)); + + ts2->add(ts2, traffic_selector_create_from_cidr("10.0.1.0/24", 0, 0, 65535)); + ck_assert(ts1->equals(ts1, ts2)); + + ts1->destroy(ts1); + ts2->destroy(ts2); +} +END_TEST + +START_TEST(test_list_clone) +{ + traffic_selector_list_t *ts1, *ts2; + + ts1 = traffic_selector_list_create(); + ts2 = ts1->clone(ts1); + ck_assert(ts1->equals(ts1, ts2)); + ts2->destroy(ts2); + + ts1->add(ts1, traffic_selector_create_from_cidr("10.0.1.0/24", 0, 0, 65535)); + ts2 = ts1->clone(ts1); + ck_assert(ts1->equals(ts1, ts2)); + ts2->destroy(ts2); + + ts1->add(ts1, traffic_selector_create_from_cidr("10.0.1.0/24", 0, 0, 65535)); + ts2 = ts1->clone(ts1); + ck_assert(ts1->equals(ts1, ts2)); + + ts1->destroy(ts1); + ts2->destroy(ts2); +} +END_TEST + Suite *traffic_selector_suite_create() { Suite *s; @@ -890,5 +1084,12 @@ Suite *traffic_selector_suite_create() tcase_add_test(tc, test_printf_hook_hash); suite_add_tcase(s, tc); + tc = tcase_create("list"); + tcase_add_loop_test(tc, test_list_get, 0, 0/*countof(list_get_tests)*/); + tcase_add_loop_test(tc, test_list_select, 0, countof(list_select_tests)); + tcase_add_test(tc, test_list_equals); + tcase_add_test(tc, test_list_clone); + suite_add_tcase(s, tc); + return s; }