/* * Copyright (C) 2015 Tobias Brunner * HSR Hochschule fuer Technik Rapperswil * * 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 . * * 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 verify(const char *str, const char *alt, traffic_selector_t *ts) { char buf[512]; if (!str) { ck_assert_msg(!ts, "traffic selector not null: %R", ts); return; } snprintf(buf, sizeof(buf), "%R", ts); DESTROY_IF(ts); if (!streq(buf, str) && (!alt || !streq(buf, alt))) { fail("%s != %s or %s", buf, str, alt); } } START_TEST(test_create_from_string) { verify("10.1.0.0/16[tcp/http]", "10.1.0.0/16[6/80]", 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]", "10.1.0.1..10.1.0.99[17/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", NULL, traffic_selector_create_from_string(0, TS_IPV6_ADDR_RANGE, "fec1::", 0, "fec1::ffff:ffff:ffff:ffff", 65535)); verify("fec1::1..fec1::ffff:ffff:ffff:ffff", NULL, traffic_selector_create_from_string(0, TS_IPV6_ADDR_RANGE, "fec1::1", 0, "fec1::ffff:ffff:ffff:ffff", 65535)); verify(NULL, NULL, traffic_selector_create_from_string(IPPROTO_TCP, 0, "10.1.0.0", 80, "10.1.255.255", 80)); verify(NULL, NULL, traffic_selector_create_from_string(IPPROTO_TCP, TS_IPV4_ADDR_RANGE, "a.b.c.d", 80, "10.1.255.255", 80)); verify(NULL, NULL, traffic_selector_create_from_string(IPPROTO_TCP, TS_IPV4_ADDR_RANGE, "10.1.0.0", 80, "a.b.c.d", 80)); } END_TEST START_TEST(test_create_from_cidr) { verify("10.1.0.0/16", NULL, traffic_selector_create_from_cidr("10.1.0.0/16", 0, 0, 65535)); verify("10.1.0.1/32[udp]", "10.1.0.1/32[17]", traffic_selector_create_from_cidr("10.1.0.1/32", IPPROTO_UDP, 0, 65535)); verify("10.1.0.1/32[0/domain]", "10.1.0.1/32[0/53]", traffic_selector_create_from_cidr("10.1.0.1/32", 0, 53, 53)); verify("10.1.0.1/32[udp/1234-1235]", "10.1.0.1/32[17/1234-1235]", traffic_selector_create_from_cidr("10.1.0.1/32", IPPROTO_UDP, 1234, 1235)); verify("10.1.0.0/16[0/OPAQUE]", NULL, traffic_selector_create_from_cidr("10.1.0.0/16", 0, 65535, 0)); verify(NULL, NULL, traffic_selector_create_from_cidr("a.b.c.d/16", 0, 0, 65535)); } END_TEST START_TEST(test_create_from_bytes) { verify("10.1.0.0/16", NULL, 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)); verify(NULL, NULL, 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,0xff), 65535)); verify(NULL, NULL, traffic_selector_create_from_bytes(0, TS_IPV4_ADDR_RANGE, chunk_empty, 0, chunk_empty, 65535)); verify(NULL, NULL, traffic_selector_create_from_bytes(0, TS_IPV6_ADDR_RANGE, chunk_from_chars(0x0a,0x01,0x00,0x00), 0, chunk_from_chars(0x0a,0x01,0xff,0xff), 65535)); verify(NULL, NULL, traffic_selector_create_from_bytes(0, 0, 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", NULL, traffic_selector_create_from_subnet( host_create_from_string("10.1.0.0", 0), 16, 0, 0, 65535)); } END_TEST struct { char *net; ts_type_t type; chunk_t enc; } rfc3779_prefix_tests[] = { /* some examples from RFC 3779, for addressPrefix elements we pass the same * value twice to the constructor */ { "10.0.0.0/8", TS_IPV4_ADDR_RANGE, chunk_from_chars(0x00,0x0a), }, { "10.0.32.0/20", TS_IPV4_ADDR_RANGE, chunk_from_chars(0x04,0x0a,0x00,0x20), }, { "10.0.64.0/24", TS_IPV4_ADDR_RANGE, chunk_from_chars(0x00,0x0a,0x00,0x40), }, { "10.1.0.0/16", TS_IPV4_ADDR_RANGE, chunk_from_chars(0x00,0x0a,0x01), }, { "10.5.0.1/32", TS_IPV4_ADDR_RANGE, chunk_from_chars(0x00,0x0a,0x05,0x00,0x01), }, { "10.5.0.0/23", TS_IPV4_ADDR_RANGE, chunk_from_chars(0x01,0x0a,0x05,0x00), }, { "10.64.0.0/12", TS_IPV4_ADDR_RANGE, chunk_from_chars(0x04,0x0a,0x40), }, { "10.64.0.0/20", TS_IPV4_ADDR_RANGE, chunk_from_chars(0x04,0x0a,0x40,0x00), }, { "128.0.0.0/4", TS_IPV4_ADDR_RANGE, chunk_from_chars(0x04,0x80), }, { "172.16.0.0/12", TS_IPV4_ADDR_RANGE, chunk_from_chars(0x04,0xac,0x10), }, { "0.0.0.0/0", TS_IPV4_ADDR_RANGE, chunk_from_chars(0x00), }, { NULL, 0, chunk_from_chars(0x00), }, /* FIXME: not a correct encoding, so we might want to fail here */ { "0.0.0.0/0", TS_IPV4_ADDR_RANGE, {NULL, 0}, }, { "2001:0:2::/48", TS_IPV6_ADDR_RANGE, chunk_from_chars(0x00,0x20,0x01,0x00,0x00,0x00,0x02),}, { "2001:0:200::/39",TS_IPV6_ADDR_RANGE, chunk_from_chars(0x01,0x20,0x01,0x00,0x00,0x02),}, { "::/0", TS_IPV6_ADDR_RANGE, chunk_from_chars(0x00), }, /* FIXME: not a correct encoding, so we might want to fail here */ { "::/0", TS_IPV6_ADDR_RANGE, {NULL, 0}, }, }; START_TEST(test_create_from_rfc3779_format_prefix) { verify(rfc3779_prefix_tests[_i].net, NULL, traffic_selector_create_from_rfc3779_format(rfc3779_prefix_tests[_i].type, rfc3779_prefix_tests[_i].enc, rfc3779_prefix_tests[_i].enc)); } END_TEST START_TEST(test_create_from_rfc3779_format_range) { /* addressRange elements encode a from and to address, which may still * represent prefixes */ verify("10.5.0.0/23", NULL, traffic_selector_create_from_rfc3779_format(TS_IPV4_ADDR_RANGE, chunk_from_chars(0x00,0x0a,0x05), chunk_from_chars(0x01,0x0a,0x05,0x00))); verify("2001:0:200::/39", NULL, traffic_selector_create_from_rfc3779_format(TS_IPV6_ADDR_RANGE, chunk_from_chars(0x01,0x20,0x01,0x00,0x00,0x02), chunk_from_chars(0x02,0x20,0x01,0x00,0x00,0x00))); verify("10.2.48.0..10.2.64.255", NULL, traffic_selector_create_from_rfc3779_format(TS_IPV4_ADDR_RANGE, chunk_from_chars(0x04,0x0a,0x02,0x30), chunk_from_chars(0x00,0x0a,0x02,0x40))); verify("129.64.0.0..143.255.255.255", NULL, traffic_selector_create_from_rfc3779_format(TS_IPV4_ADDR_RANGE, chunk_from_chars(0x06,0x81,0x40), chunk_from_chars(0x04,0x80))); } END_TEST static void verify_address(char *addr_from, char *addr_to, traffic_selector_t *ts) { host_t *from, *to; from = host_create_from_string(addr_from, 0); to = host_create_from_string(addr_to, 0); ck_assert_chunk_eq(from->get_address(from), ts->get_from_address(ts)); ck_assert_chunk_eq(to->get_address(to), ts->get_to_address(ts)); from->destroy(from); to->destroy(to); ts->destroy(ts); } START_TEST(test_get_address_range) { verify_address("10.1.0.1", "10.1.0.10", traffic_selector_create_from_string(0, TS_IPV4_ADDR_RANGE, "10.1.0.1", 0, "10.1.0.10", 65535)); /* currently not reordered */ verify_address("10.1.0.10", "10.1.0.1", traffic_selector_create_from_string(0, TS_IPV4_ADDR_RANGE, "10.1.0.10", 0, "10.1.0.1", 65535)); } END_TEST START_TEST(test_get_address_cidr) { verify_address("10.1.0.0", "10.1.255.255", traffic_selector_create_from_cidr("10.1.0.0/16", 0, 0, 65535)); verify_address("fec1::", "fec1::ffff:ffff:ffff:ffff", traffic_selector_create_from_cidr("fec1::/64", 0, 0, 65535)); } END_TEST struct { ts_type_t type; char *from; char *to; char *net; uint8_t mask; bool exact; } to_subnet_tests[] = { { TS_IPV4_ADDR_RANGE, "10.0.0.1", "10.0.0.1", "10.0.0.1", 32, TRUE }, { TS_IPV4_ADDR_RANGE, "10.0.0.0", "10.255.255.255", "10.0.0.0", 8, TRUE }, { TS_IPV4_ADDR_RANGE, "10.0.0.1", "10.0.0.255", "10.0.0.0", 24, FALSE }, { TS_IPV4_ADDR_RANGE, "10.0.0.0", "10.0.0.15", "10.0.0.0", 28, TRUE }, { TS_IPV4_ADDR_RANGE, "10.0.0.1", "10.0.0.15", "10.0.0.0", 28, FALSE }, { TS_IPV4_ADDR_RANGE, "10.0.0.1", "10.0.0.16", "10.0.0.0", 27, FALSE }, { TS_IPV6_ADDR_RANGE, "fec1::1", "fec1::1", "fec1::1", 128, TRUE }, { TS_IPV6_ADDR_RANGE, "fec1::0", "fec1::ffff:ffff:ffff:ffff", "fec1::", 64, TRUE }, { TS_IPV6_ADDR_RANGE, "fec1::1", "fec1::ffff:ffff:ffff:ffff", "fec1::", 64, FALSE }, { TS_IPV6_ADDR_RANGE, "fec1::1", "fec1::7fff", "fec1::", 113, FALSE }, { TS_IPV6_ADDR_RANGE, "fec1::1", "fec1::efff", "fec1::", 112, FALSE }, }; START_TEST(test_to_subnet) { traffic_selector_t *ts; host_t *net, *exp_net; uint8_t mask; ts = traffic_selector_create_from_string(0, to_subnet_tests[_i].type, to_subnet_tests[_i].from, 0, to_subnet_tests[_i].to, 0); ck_assert(ts->to_subnet(ts, &net, &mask) == to_subnet_tests[_i].exact); exp_net = host_create_from_string(to_subnet_tests[_i].net, 0); ck_assert(exp_net->ip_equals(exp_net, net)); ck_assert_int_eq(to_subnet_tests[_i].mask, mask); exp_net->destroy(exp_net); net->destroy(net); ts->destroy(ts); } END_TEST struct { char *cidr; uint16_t from_port; uint16_t to_port; uint16_t port; } to_subnet_port_tests[] = { { "10.0.0.0/8", 0, 0, 0 }, { "10.0.0.1/32", 80, 80, 80 }, { "10.0.0.1/32", 123, 465, 0 }, { "0.0.0.0/0", 0, 65535, 0 }, { "fec1::/64", 0, 0, 0 }, { "fec1::1/128", 80, 80, 80 }, { "fec1::1/128", 123, 465, 0 }, { "::/0", 0, 65535, 0 }, }; START_TEST(test_to_subnet_port) { traffic_selector_t *ts; host_t *net, *exp_net; uint8_t mask; int exp_mask; ts = traffic_selector_create_from_cidr(to_subnet_port_tests[_i].cidr, 0, to_subnet_port_tests[_i].from_port, to_subnet_port_tests[_i].to_port); ck_assert(ts->to_subnet(ts, &net, &mask)); exp_net = host_create_from_subnet(to_subnet_port_tests[_i].cidr, &exp_mask); ck_assert(exp_net->ip_equals(exp_net, net)); ck_assert_int_eq(exp_mask, mask); ck_assert_int_eq(to_subnet_port_tests[_i].port, net->get_port(net)); exp_net->destroy(exp_net); net->destroy(net); ts->destroy(ts); } 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", NULL, a->get_subset(a, b)); verify("10.1.5.0/24", NULL, b->get_subset(b, a)); a->destroy(a); b->destroy(b); a = traffic_selector_create_from_cidr("fec1::/64", 0, 0, 65535); b = traffic_selector_create_from_cidr("fec1::1/128", 0, 0, 65535); verify("fec1::1/128", NULL, a->get_subset(a, b)); verify("fec1::1/128", NULL, b->get_subset(b, a)); 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]", "10.2.7.16/30[6/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]", "10.1.0.0/16[6/80]", 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)); 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)); 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)); 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)); a->destroy(a); b->destroy(b); } END_TEST START_TEST(test_subset_dynamic) { traffic_selector_t *a, *b; a = traffic_selector_create_dynamic(0, 0, 65535); b = traffic_selector_create_from_cidr("10.1.0.0/16", 0, 0, 65535); ck_assert(!a->get_subset(a, b)); ck_assert(!b->get_subset(b, a)); a->destroy(a); b->destroy(b); } END_TEST START_TEST(test_subset_opaque) { traffic_selector_t *a, *b; a = traffic_selector_create_from_cidr("10.0.0.0/8", 0, 65535, 0); b = traffic_selector_create_from_cidr("10.2.7.16/30", IPPROTO_TCP, 80, 80); ck_assert(!a->get_subset(a, b)); ck_assert(!b->get_subset(b, a)); b->destroy(b); b = traffic_selector_create_from_cidr("10.2.7.16/30", IPPROTO_TCP, 65535, 0); verify("10.2.7.16/30[tcp/OPAQUE]", "10.2.7.16/30[6/OPAQUE]", a->get_subset(a, b)); verify("10.2.7.16/30[tcp/OPAQUE]", "10.2.7.16/30[6/OPAQUE]", b->get_subset(b, a)); b->destroy(b); b = traffic_selector_create_from_cidr("10.2.7.16/30", IPPROTO_TCP, 0, 65535); verify("10.2.7.16/30[tcp/OPAQUE]", "10.2.7.16/30[6/OPAQUE]", a->get_subset(a, b)); verify("10.2.7.16/30[tcp/OPAQUE]", "10.2.7.16/30[6/OPAQUE]", b->get_subset(b, a)); 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 }, { "10.1.0.0/16", "10.0.255.255", 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 { bool contained; struct { char *net; uint8_t proto; uint16_t from_port; uint16_t to_port; } a, b; } is_contained_in_tests[] = { { TRUE, { "10.0.0.0/16", 0, 0, 65535 }, { "10.0.0.0/16", 0, 0, 65535 }, }, { TRUE, { "10.0.1.0/24", 0, 0, 65535 }, { "10.0.0.0/16", 0, 0, 65535 }, }, { TRUE, { "10.0.1.0/24", 17, 123, 456 }, { "10.0.0.0/16", 0, 0, 65535 }, }, { TRUE, { "10.0.1.0/24", 17, 123, 456 }, { "10.0.0.0/16", 17, 123, 456 },}, { FALSE, { "10.0.0.0/8", 0, 0, 65535 }, { "10.0.0.0/16", 0, 0, 65535 }, }, { FALSE, { "10.0.1.0/24", 17, 0, 65535 }, { "10.0.0.0/16", 17, 123, 456 },}, { FALSE, { "fec2::/64", 0, 0, 65535 }, { "10.0.0.0/16", 17, 123, 456 },}, }; START_TEST(test_is_contained_in) { traffic_selector_t *a, *b; a = traffic_selector_create_from_cidr( is_contained_in_tests[_i].a.net, is_contained_in_tests[_i].a.proto, is_contained_in_tests[_i].a.from_port, is_contained_in_tests[_i].a.to_port); b = traffic_selector_create_from_cidr( is_contained_in_tests[_i].b.net, is_contained_in_tests[_i].b.proto, is_contained_in_tests[_i].b.from_port, is_contained_in_tests[_i].b.to_port); ck_assert(a->is_contained_in(a, b) == is_contained_in_tests[_i].contained); a->destroy(a); b->destroy(b); } END_TEST struct { char *net; char *host; bool is_host; bool when_null; } is_host_tests[] = { { "0.0.0.0/0", "192.168.1.2", FALSE, FALSE }, { "::/0", "fec2::1", FALSE, FALSE }, { "192.168.1.0/24", "192.168.1.0", FALSE, FALSE }, { "192.168.1.2/32", "192.168.1.2", TRUE, TRUE }, { "192.168.1.2/32", "192.168.1.1", FALSE, TRUE }, { "192.168.1.2/32", "fec2::1", FALSE, TRUE }, { "fec2::1/128", "fec2::1", TRUE, TRUE }, { "fec2::1/128", "fec2::2", FALSE, TRUE }, { "fec2::1/128", "192.168.1.2", FALSE, TRUE }, }; START_TEST(test_is_host) { traffic_selector_t *ts; host_t *h; ts = traffic_selector_create_from_cidr(is_host_tests[_i].net, 0, 0, 65535); h = host_create_from_string(is_host_tests[_i].host, 0); ck_assert(ts->is_host(ts, h) == is_host_tests[_i].is_host); ck_assert(ts->is_host(ts, NULL) == is_host_tests[_i].when_null); ts->destroy(ts); h->destroy(h); } END_TEST START_TEST(test_is_host_dynamic) { traffic_selector_t *ts; host_t *h; ts = traffic_selector_create_dynamic(0, 0, 65535); h = host_create_from_string(is_host_tests[_i].host, 0); ck_assert(!ts->is_host(ts, h)); ck_assert(ts->is_host(ts, NULL)); ts->destroy(ts); h->destroy(h); } END_TEST struct { char *orig; char *host; char *after; } set_address_tests[] = { { "0.0.0.0/0", "192.168.1.2", "192.168.1.2/32" }, { "::/0", "fec2::1", "fec2::1/128" }, { "192.168.1.2/32", "192.168.1.1", "192.168.1.1/32" }, { "192.168.1.0/24", "192.168.1.1", "192.168.1.1/32" }, { "192.168.1.2/32", "fec2::1", "fec2::1/128" }, { "192.168.1.0/24", "fec2::1", "fec2::1/128" }, { "192.168.1.2/32", "%any", "0.0.0.0/0" }, { "192.168.1.0/24", "%any", "0.0.0.0/0" }, { "192.168.1.2/32", "%any6", "::/0" }, { "192.168.1.0/24", "%any6", "::/0" }, { "fec2::1/128", "192.168.1.1", "192.168.1.1/32" }, { "fec2::/64", "192.168.1.1", "192.168.1.1/32" }, { "fec2::1/128", "fec2::2", "fec2::2/128" }, { "fec2::/64", "fec2::2", "fec2::2/128" }, { "fec2::1/128", "%any", "0.0.0.0/0" }, { "fec2::/64", "%any", "0.0.0.0/0" }, { "fec2::1/128", "%any6", "::/0" }, { "fec2::/64", "%any6", "::/0" }, { NULL, "192.168.1.1", "192.168.1.1/32" }, { NULL, "fec2::1", "fec2::1/128" }, { NULL, "%any", "0.0.0.0/0" }, { NULL, "%any6", "::/0" }, }; START_TEST(test_set_address) { traffic_selector_t *ts; host_t *h; if (set_address_tests[_i].orig) { ts = traffic_selector_create_from_cidr(set_address_tests[_i].orig, 0, 0, 65535); ck_assert(!ts->is_dynamic(ts)); } else { ts = traffic_selector_create_dynamic(0, 0, 65535); ck_assert(ts->is_dynamic(ts)); } h = host_create_from_string(set_address_tests[_i].host, 0); ts->set_address(ts, h); ck_assert(!ts->is_dynamic(ts)); verify(set_address_tests[_i].after, NULL, ts); h->destroy(h); } END_TEST struct { int res; struct { char *net; uint8_t proto; uint16_t from_port; uint16_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, { "fec1::/64", 0, 0, 65535 }, { "fec2::/64", 0, 0, 65535 }, }, { 1, { "fec2::/64", 0, 0, 65535 }, { "fec1::/64", 0, 0, 65535 }, }, { -1, { "fec1::/48", 0, 0, 65535 }, { "fec1::/64", 0, 0, 65535 }, }, { 1, { "fec1::/64", 0, 0, 65535 }, { "fec1::/48", 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); ck_assert(a->equals(a, b)); break; case 1: ck_assert(traffic_selector_cmp(a, b, NULL) > 0); ck_assert(!a->equals(a, b)); break; case -1: ck_assert(traffic_selector_cmp(a, b, NULL) < 0); ck_assert(!a->equals(a, b)); break; } a->destroy(a); b->destroy(b); } END_TEST static void verify_clone(traffic_selector_t *ts) { traffic_selector_t *clone; clone = ts->clone(ts); if (!ts->equals(ts, clone)) { fail("%R != %R", ts, clone); } /* equals() already compares most of these but not all */ ck_assert(ts->get_type(ts) == clone->get_type(clone)); ck_assert(ts->get_protocol(ts) == clone->get_protocol(clone)); ck_assert(ts->get_from_port(ts) == clone->get_from_port(clone)); ck_assert(ts->get_to_port(ts) == clone->get_to_port(clone)); ck_assert_chunk_eq(ts->get_from_address(ts), clone->get_from_address(clone)); ck_assert_chunk_eq(ts->get_to_address(ts), clone->get_to_address(clone)); ck_assert(ts->is_host(ts, NULL) == clone->is_host(clone, NULL)); ck_assert(ts->is_dynamic(ts) == clone->is_dynamic(clone)); clone->destroy(clone); ts->destroy(ts); } START_TEST(test_clone) { traffic_selector_t *ts; host_t *h; ts = traffic_selector_create_dynamic(0, 0, 0); verify_clone(ts); ts = traffic_selector_create_dynamic(IPPROTO_UDP, 123, 456); verify_clone(ts); ts = traffic_selector_create_dynamic(IPPROTO_UDP, 0, 65535); verify_clone(ts); h = host_create_from_string("192.168.1.1", 0); ts = traffic_selector_create_dynamic(0, 0, 0); ts->set_address(ts, h); verify_clone(ts); ts = traffic_selector_create_dynamic(IPPROTO_UDP, 123, 456); ts->set_address(ts, h); verify_clone(ts); h->destroy(h); ts = traffic_selector_create_from_string(0, TS_IPV4_ADDR_RANGE, "10.0.0.1", 0, "10.0.0.16", 65535); verify_clone(ts); ts = traffic_selector_create_from_string(IPPROTO_TCP, TS_IPV6_ADDR_RANGE, "fec1::1", 80, "fec1::1:0000", 80); verify_clone(ts); ts = traffic_selector_create_from_cidr("10.0.0.0/8", 0, 0, 65535); verify_clone(ts); ts = traffic_selector_create_from_cidr("fec1::/64", 0, 0, 65535); verify_clone(ts); } END_TEST START_TEST(test_hash) { traffic_selector_t *a, *b; host_t *h; a = traffic_selector_create_dynamic(0, 0, 0); b = traffic_selector_create_from_cidr("0.0.0.0/0", 0, 0, 0); ck_assert(a->hash(a, 0) != a->hash(a, 1)); ck_assert_int_eq(a->hash(a, 0), b->hash(b, 0)); ck_assert_int_eq(a->hash(a, 1), b->hash(b, 1)); h = host_create_from_string("192.168.1.1", 0); a->set_address(a, h); ck_assert(a->hash(a, 0) != b->hash(b, 0)); h->destroy(h); a->destroy(a); a = traffic_selector_create_from_string(0, TS_IPV4_ADDR_RANGE, "192.168.0.0", 0, "192.168.0.255", 65535); ck_assert(a->hash(a, 0) != b->hash(b, 0)); b->destroy(b); b = traffic_selector_create_from_cidr("192.168.0.0/24", 0, 0, 65535); ck_assert_int_eq(a->hash(a, 0), b->hash(b, 0)); b->destroy(b); b = traffic_selector_create_from_cidr("192.168.0.0/24", IPPROTO_TCP, 0, 65535); ck_assert(a->hash(a, 0) != b->hash(b, 0)); b->destroy(b); b = traffic_selector_create_from_cidr("192.168.0.0/24", 0, 123, 456); ck_assert(a->hash(a, 0) != b->hash(b, 0)); b->destroy(b); a->destroy(a); } END_TEST struct { uint8_t proto; uint16_t from_port; uint16_t to_port; uint8_t from_type; uint8_t from_code; uint8_t to_type; uint8_t to_code; char *str; char *str_alt; } icmp_tests[] = { { IPPROTO_ICMP, 0, 0, 0, 0, 0, 0, "dynamic[icmp/0]", "dynamic[1/0]" }, { IPPROTO_ICMP, 3, 3, 3, 0, 3, 0, "dynamic[icmp/3]", "dynamic[1/3]" }, { IPPROTO_ICMP, 0x0307, 0x0307, 3, 7, 3, 7, "dynamic[icmp/3(7)]", "dynamic[1/3(7)]" }, { IPPROTO_ICMP, 0x0300, 0x040f, 3, 0, 4, 15, "dynamic[icmp/3-4(15)]", "dynamic[1/3-4(15)]" }, { IPPROTO_ICMP, 0x0301, 0x040f, 3, 1, 4, 15, "dynamic[icmp/3(1)-4(15)]", "dynamic[1/3(1)-4(15)]" }, { IPPROTO_ICMPV6, 0, 0, 0, 0, 0, 0, "dynamic[ipv6-icmp/0]", "dynamic[58/0]" }, { IPPROTO_ICMPV6, 1, 1, 1, 0, 1, 0, "dynamic[ipv6-icmp/1]", "dynamic[58/1]" }, { IPPROTO_ICMPV6, 0x0104, 0x0104, 1, 4, 1, 4, "dynamic[ipv6-icmp/1(4)]", "dynamic[58/1(4)]" }, { IPPROTO_ICMPV6, 0x0100, 0x040f, 1, 0, 4, 15, "dynamic[ipv6-icmp/1-4(15)]", "dynamic[58/1-4(15)]" }, { IPPROTO_ICMPV6, 0x0101, 0x040f, 1, 1, 4, 15, "dynamic[ipv6-icmp/1(1)-4(15)]", "dynamic[58/1(1)-4(15)]" }, }; START_TEST(test_icmp) { traffic_selector_t *ts; uint16_t from, to; ts = traffic_selector_create_dynamic(icmp_tests[_i].proto, icmp_tests[_i].from_port, icmp_tests[_i].to_port); from = ts->get_from_port(ts); to = ts->get_to_port(ts); ck_assert_int_eq(icmp_tests[_i].from_type, traffic_selector_icmp_type(from)); ck_assert_int_eq(icmp_tests[_i].from_code, traffic_selector_icmp_code(from)); ck_assert_int_eq(icmp_tests[_i].to_type, traffic_selector_icmp_type(to)); ck_assert_int_eq(icmp_tests[_i].to_code, traffic_selector_icmp_code(to)); verify(icmp_tests[_i].str, icmp_tests[_i].str_alt, ts); } END_TEST static void verify_list(const char *str, const char *alt, linked_list_t *list) { char buf[512]; snprintf(buf, sizeof(buf), "%#R", list); list->destroy_offset(list, offsetof(traffic_selector_t, destroy)); if (!streq(buf, str) && !streq(buf, alt)) { fail("%s != %s or %s", buf, str, alt); } } START_TEST(test_printf_hook_null) { verify("(null)", NULL, NULL); } END_TEST START_TEST(test_printf_hook_hash) { linked_list_t *list; list = linked_list_create_with_items( traffic_selector_create_from_cidr("10.1.0.0/16", 0, 0, 65535), NULL); verify_list("10.1.0.0/16", NULL, list); list = linked_list_create_with_items( traffic_selector_create_from_cidr("10.1.0.0/16", 0, 0, 65535), traffic_selector_create_from_cidr("10.1.0.1/32", IPPROTO_UDP, 1234, 1235), NULL); verify_list("10.1.0.0/16 10.1.0.1/32[udp/1234-1235]", "10.1.0.0/16 10.1.0.1/32[17/1234-1235]", list); list = linked_list_create_with_items( traffic_selector_create_from_cidr("10.1.0.0/16", 0, 0, 65535), traffic_selector_create_from_string(IPPROTO_UDP, TS_IPV4_ADDR_RANGE, "10.1.0.1", 1234, "10.1.0.99", 1235), NULL); verify_list("10.1.0.0/16 10.1.0.1..10.1.0.99[udp/1234-1235]", "10.1.0.0/16 10.1.0.1..10.1.0.99[17/1234-1235]", list); } 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); tcase_add_loop_test(tc, test_create_from_rfc3779_format_prefix, 0, countof(rfc3779_prefix_tests)); tcase_add_test(tc, test_create_from_rfc3779_format_range); suite_add_tcase(s, tc); tc = tcase_create("addresses"); tcase_add_test(tc, test_get_address_range); tcase_add_test(tc, test_get_address_cidr); suite_add_tcase(s, tc); tc = tcase_create("to_subnet"); tcase_add_loop_test(tc, test_to_subnet, 0, countof(to_subnet_tests)); tcase_add_loop_test(tc, test_to_subnet_port, 0, countof(to_subnet_port_tests)); 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); tcase_add_test(tc, test_subset_dynamic); tcase_add_test(tc, test_subset_opaque); 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("is_contained_in"); tcase_add_loop_test(tc, test_is_contained_in, 0, countof(is_contained_in_tests)); suite_add_tcase(s, tc); tc = tcase_create("is_host"); tcase_add_loop_test(tc, test_is_host, 0, countof(is_host_tests)); tcase_add_loop_test(tc, test_is_host_dynamic, 0, countof(is_host_tests)); suite_add_tcase(s, tc); tc = tcase_create("set_address"); tcase_add_loop_test(tc, test_set_address, 0, countof(is_host_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); tc = tcase_create("clone"); tcase_add_test(tc, test_clone); suite_add_tcase(s, tc); tc = tcase_create("hash"); tcase_add_test(tc, test_hash); suite_add_tcase(s, tc); tc = tcase_create("icmp"); tcase_add_loop_test(tc, test_icmp, 0, countof(icmp_tests)); suite_add_tcase(s, tc); tc = tcase_create("printf hook"); tcase_add_test(tc, test_printf_hook_null); tcase_add_test(tc, test_printf_hook_hash); suite_add_tcase(s, tc); return s; }