Annotation of embedaddon/strongswan/src/libstrongswan/tests/suites/test_traffic_selector.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (C) 2015 Tobias Brunner
! 3: * HSR Hochschule fuer Technik Rapperswil
! 4: *
! 5: * Copyright (C) 2015 Martin Willi
! 6: * Copyright (C) 2015 revosec AG
! 7: *
! 8: * This program is free software; you can redistribute it and/or modify it
! 9: * under the terms of the GNU General Public License as published by the
! 10: * Free Software Foundation; either version 2 of the License, or (at your
! 11: * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
! 12: *
! 13: * This program is distributed in the hope that it will be useful, but
! 14: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
! 15: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
! 16: * for more details.
! 17: */
! 18:
! 19: #include "test_suite.h"
! 20:
! 21: #include <selectors/traffic_selector.h>
! 22:
! 23:
! 24: static void verify(const char *str, const char *alt, traffic_selector_t *ts)
! 25: {
! 26: char buf[512];
! 27:
! 28: if (!str)
! 29: {
! 30: ck_assert_msg(!ts, "traffic selector not null: %R", ts);
! 31: return;
! 32: }
! 33: snprintf(buf, sizeof(buf), "%R", ts);
! 34: DESTROY_IF(ts);
! 35: if (!streq(buf, str) && (!alt || !streq(buf, alt)))
! 36: {
! 37: fail("%s != %s or %s", buf, str, alt);
! 38: }
! 39: }
! 40:
! 41: START_TEST(test_create_from_string)
! 42: {
! 43: verify("10.1.0.0/16[tcp/http]", "10.1.0.0/16[6/80]",
! 44: traffic_selector_create_from_string(IPPROTO_TCP, TS_IPV4_ADDR_RANGE,
! 45: "10.1.0.0", 80, "10.1.255.255", 80));
! 46: verify("10.1.0.1..10.1.0.99[udp/1234-1235]",
! 47: "10.1.0.1..10.1.0.99[17/1234-1235]",
! 48: traffic_selector_create_from_string(IPPROTO_UDP, TS_IPV4_ADDR_RANGE,
! 49: "10.1.0.1", 1234, "10.1.0.99", 1235));
! 50: verify("fec1::/64", NULL,
! 51: traffic_selector_create_from_string(0, TS_IPV6_ADDR_RANGE,
! 52: "fec1::", 0, "fec1::ffff:ffff:ffff:ffff", 65535));
! 53: verify("fec1::1..fec1::ffff:ffff:ffff:ffff", NULL,
! 54: traffic_selector_create_from_string(0, TS_IPV6_ADDR_RANGE,
! 55: "fec1::1", 0, "fec1::ffff:ffff:ffff:ffff", 65535));
! 56: verify(NULL, NULL,
! 57: traffic_selector_create_from_string(IPPROTO_TCP, 0,
! 58: "10.1.0.0", 80, "10.1.255.255", 80));
! 59: verify(NULL, NULL,
! 60: traffic_selector_create_from_string(IPPROTO_TCP, TS_IPV4_ADDR_RANGE,
! 61: "a.b.c.d", 80, "10.1.255.255", 80));
! 62: verify(NULL, NULL,
! 63: traffic_selector_create_from_string(IPPROTO_TCP, TS_IPV4_ADDR_RANGE,
! 64: "10.1.0.0", 80, "a.b.c.d", 80));
! 65: }
! 66: END_TEST
! 67:
! 68: START_TEST(test_create_from_cidr)
! 69: {
! 70: verify("10.1.0.0/16", NULL,
! 71: traffic_selector_create_from_cidr("10.1.0.0/16", 0, 0, 65535));
! 72: verify("10.1.0.1/32[udp]", "10.1.0.1/32[17]",
! 73: traffic_selector_create_from_cidr("10.1.0.1/32", IPPROTO_UDP,
! 74: 0, 65535));
! 75: verify("10.1.0.1/32[0/domain]", "10.1.0.1/32[0/53]",
! 76: traffic_selector_create_from_cidr("10.1.0.1/32", 0,
! 77: 53, 53));
! 78: verify("10.1.0.1/32[udp/1234-1235]", "10.1.0.1/32[17/1234-1235]",
! 79: traffic_selector_create_from_cidr("10.1.0.1/32", IPPROTO_UDP,
! 80: 1234, 1235));
! 81: verify("10.1.0.0/16[0/OPAQUE]", NULL,
! 82: traffic_selector_create_from_cidr("10.1.0.0/16", 0, 65535, 0));
! 83:
! 84: verify(NULL, NULL,
! 85: traffic_selector_create_from_cidr("a.b.c.d/16", 0, 0, 65535));
! 86: }
! 87: END_TEST
! 88:
! 89: START_TEST(test_create_from_bytes)
! 90: {
! 91: verify("10.1.0.0/16", NULL,
! 92: traffic_selector_create_from_bytes(0, TS_IPV4_ADDR_RANGE,
! 93: chunk_from_chars(0x0a,0x01,0x00,0x00), 0,
! 94: chunk_from_chars(0x0a,0x01,0xff,0xff), 65535));
! 95: verify(NULL, NULL,
! 96: traffic_selector_create_from_bytes(0, TS_IPV4_ADDR_RANGE,
! 97: chunk_from_chars(0x0a,0x01,0x00,0x00), 0,
! 98: chunk_from_chars(0x0a,0x01,0xff,0xff,0xff), 65535));
! 99: verify(NULL, NULL,
! 100: traffic_selector_create_from_bytes(0, TS_IPV4_ADDR_RANGE,
! 101: chunk_empty, 0,
! 102: chunk_empty, 65535));
! 103: verify(NULL, NULL,
! 104: traffic_selector_create_from_bytes(0, TS_IPV6_ADDR_RANGE,
! 105: chunk_from_chars(0x0a,0x01,0x00,0x00), 0,
! 106: chunk_from_chars(0x0a,0x01,0xff,0xff), 65535));
! 107: verify(NULL, NULL,
! 108: traffic_selector_create_from_bytes(0, 0,
! 109: chunk_from_chars(0x0a,0x01,0x00,0x00), 0,
! 110: chunk_from_chars(0x0a,0x01,0xff,0xff), 65535));
! 111: }
! 112: END_TEST
! 113:
! 114: START_TEST(test_create_from_subnet)
! 115: {
! 116: verify("10.1.0.0/16", NULL,
! 117: traffic_selector_create_from_subnet(
! 118: host_create_from_string("10.1.0.0", 0), 16, 0, 0, 65535));
! 119: }
! 120: END_TEST
! 121:
! 122: struct {
! 123: char *net;
! 124: ts_type_t type;
! 125: chunk_t enc;
! 126: } rfc3779_prefix_tests[] = {
! 127: /* some examples from RFC 3779, for addressPrefix elements we pass the same
! 128: * value twice to the constructor */
! 129: { "10.0.0.0/8", TS_IPV4_ADDR_RANGE, chunk_from_chars(0x00,0x0a), },
! 130: { "10.0.32.0/20", TS_IPV4_ADDR_RANGE, chunk_from_chars(0x04,0x0a,0x00,0x20), },
! 131: { "10.0.64.0/24", TS_IPV4_ADDR_RANGE, chunk_from_chars(0x00,0x0a,0x00,0x40), },
! 132: { "10.1.0.0/16", TS_IPV4_ADDR_RANGE, chunk_from_chars(0x00,0x0a,0x01), },
! 133: { "10.5.0.1/32", TS_IPV4_ADDR_RANGE, chunk_from_chars(0x00,0x0a,0x05,0x00,0x01), },
! 134: { "10.5.0.0/23", TS_IPV4_ADDR_RANGE, chunk_from_chars(0x01,0x0a,0x05,0x00), },
! 135: { "10.64.0.0/12", TS_IPV4_ADDR_RANGE, chunk_from_chars(0x04,0x0a,0x40), },
! 136: { "10.64.0.0/20", TS_IPV4_ADDR_RANGE, chunk_from_chars(0x04,0x0a,0x40,0x00), },
! 137: { "128.0.0.0/4", TS_IPV4_ADDR_RANGE, chunk_from_chars(0x04,0x80), },
! 138: { "172.16.0.0/12", TS_IPV4_ADDR_RANGE, chunk_from_chars(0x04,0xac,0x10), },
! 139: { "0.0.0.0/0", TS_IPV4_ADDR_RANGE, chunk_from_chars(0x00), },
! 140: { NULL, 0, chunk_from_chars(0x00), },
! 141: /* FIXME: not a correct encoding, so we might want to fail here */
! 142: { "0.0.0.0/0", TS_IPV4_ADDR_RANGE, {NULL, 0}, },
! 143: { "2001:0:2::/48", TS_IPV6_ADDR_RANGE, chunk_from_chars(0x00,0x20,0x01,0x00,0x00,0x00,0x02),},
! 144: { "2001:0:200::/39",TS_IPV6_ADDR_RANGE, chunk_from_chars(0x01,0x20,0x01,0x00,0x00,0x02),},
! 145: { "::/0", TS_IPV6_ADDR_RANGE, chunk_from_chars(0x00), },
! 146: /* FIXME: not a correct encoding, so we might want to fail here */
! 147: { "::/0", TS_IPV6_ADDR_RANGE, {NULL, 0}, },
! 148: };
! 149:
! 150: START_TEST(test_create_from_rfc3779_format_prefix)
! 151: {
! 152: verify(rfc3779_prefix_tests[_i].net, NULL,
! 153: traffic_selector_create_from_rfc3779_format(rfc3779_prefix_tests[_i].type,
! 154: rfc3779_prefix_tests[_i].enc, rfc3779_prefix_tests[_i].enc));
! 155: }
! 156: END_TEST
! 157:
! 158: START_TEST(test_create_from_rfc3779_format_range)
! 159: {
! 160: /* addressRange elements encode a from and to address, which may still
! 161: * represent prefixes */
! 162: verify("10.5.0.0/23", NULL,
! 163: traffic_selector_create_from_rfc3779_format(TS_IPV4_ADDR_RANGE,
! 164: chunk_from_chars(0x00,0x0a,0x05),
! 165: chunk_from_chars(0x01,0x0a,0x05,0x00)));
! 166: verify("2001:0:200::/39", NULL,
! 167: traffic_selector_create_from_rfc3779_format(TS_IPV6_ADDR_RANGE,
! 168: chunk_from_chars(0x01,0x20,0x01,0x00,0x00,0x02),
! 169: chunk_from_chars(0x02,0x20,0x01,0x00,0x00,0x00)));
! 170: verify("10.2.48.0..10.2.64.255", NULL,
! 171: traffic_selector_create_from_rfc3779_format(TS_IPV4_ADDR_RANGE,
! 172: chunk_from_chars(0x04,0x0a,0x02,0x30),
! 173: chunk_from_chars(0x00,0x0a,0x02,0x40)));
! 174: verify("129.64.0.0..143.255.255.255", NULL,
! 175: traffic_selector_create_from_rfc3779_format(TS_IPV4_ADDR_RANGE,
! 176: chunk_from_chars(0x06,0x81,0x40),
! 177: chunk_from_chars(0x04,0x80)));
! 178: }
! 179: END_TEST
! 180:
! 181:
! 182: static void verify_address(char *addr_from, char *addr_to, traffic_selector_t *ts)
! 183: {
! 184: host_t *from, *to;
! 185:
! 186: from = host_create_from_string(addr_from, 0);
! 187: to = host_create_from_string(addr_to, 0);
! 188:
! 189: ck_assert_chunk_eq(from->get_address(from), ts->get_from_address(ts));
! 190: ck_assert_chunk_eq(to->get_address(to), ts->get_to_address(ts));
! 191: from->destroy(from);
! 192: to->destroy(to);
! 193: ts->destroy(ts);
! 194: }
! 195:
! 196: START_TEST(test_get_address_range)
! 197: {
! 198: verify_address("10.1.0.1", "10.1.0.10",
! 199: traffic_selector_create_from_string(0, TS_IPV4_ADDR_RANGE,
! 200: "10.1.0.1", 0, "10.1.0.10", 65535));
! 201: /* currently not reordered */
! 202: verify_address("10.1.0.10", "10.1.0.1",
! 203: traffic_selector_create_from_string(0, TS_IPV4_ADDR_RANGE,
! 204: "10.1.0.10", 0, "10.1.0.1", 65535));
! 205: }
! 206: END_TEST
! 207:
! 208: START_TEST(test_get_address_cidr)
! 209: {
! 210: verify_address("10.1.0.0", "10.1.255.255",
! 211: traffic_selector_create_from_cidr("10.1.0.0/16", 0, 0, 65535));
! 212: verify_address("fec1::", "fec1::ffff:ffff:ffff:ffff",
! 213: traffic_selector_create_from_cidr("fec1::/64", 0, 0, 65535));
! 214: }
! 215: END_TEST
! 216:
! 217: struct {
! 218: ts_type_t type;
! 219: char *from;
! 220: char *to;
! 221: char *net;
! 222: uint8_t mask;
! 223: bool exact;
! 224: } to_subnet_tests[] = {
! 225: { TS_IPV4_ADDR_RANGE, "10.0.0.1", "10.0.0.1", "10.0.0.1", 32, TRUE },
! 226: { TS_IPV4_ADDR_RANGE, "10.0.0.0", "10.255.255.255", "10.0.0.0", 8, TRUE },
! 227: { TS_IPV4_ADDR_RANGE, "10.0.0.1", "10.0.0.255", "10.0.0.0", 24, FALSE },
! 228: { TS_IPV4_ADDR_RANGE, "10.0.0.0", "10.0.0.15", "10.0.0.0", 28, TRUE },
! 229: { TS_IPV4_ADDR_RANGE, "10.0.0.1", "10.0.0.15", "10.0.0.0", 28, FALSE },
! 230: { TS_IPV4_ADDR_RANGE, "10.0.0.1", "10.0.0.16", "10.0.0.0", 27, FALSE },
! 231: { TS_IPV6_ADDR_RANGE, "fec1::1", "fec1::1", "fec1::1", 128, TRUE },
! 232: { TS_IPV6_ADDR_RANGE, "fec1::0", "fec1::ffff:ffff:ffff:ffff", "fec1::", 64, TRUE },
! 233: { TS_IPV6_ADDR_RANGE, "fec1::1", "fec1::ffff:ffff:ffff:ffff", "fec1::", 64, FALSE },
! 234: { TS_IPV6_ADDR_RANGE, "fec1::1", "fec1::7fff", "fec1::", 113, FALSE },
! 235: { TS_IPV6_ADDR_RANGE, "fec1::1", "fec1::efff", "fec1::", 112, FALSE },
! 236: };
! 237:
! 238: START_TEST(test_to_subnet)
! 239: {
! 240: traffic_selector_t *ts;
! 241: host_t *net, *exp_net;
! 242: uint8_t mask;
! 243:
! 244: ts = traffic_selector_create_from_string(0, to_subnet_tests[_i].type,
! 245: to_subnet_tests[_i].from, 0, to_subnet_tests[_i].to, 0);
! 246: ck_assert(ts->to_subnet(ts, &net, &mask) == to_subnet_tests[_i].exact);
! 247: exp_net = host_create_from_string(to_subnet_tests[_i].net, 0);
! 248: ck_assert(exp_net->ip_equals(exp_net, net));
! 249: ck_assert_int_eq(to_subnet_tests[_i].mask, mask);
! 250: exp_net->destroy(exp_net);
! 251: net->destroy(net);
! 252: ts->destroy(ts);
! 253: }
! 254: END_TEST
! 255:
! 256: struct {
! 257: char *cidr;
! 258: uint16_t from_port;
! 259: uint16_t to_port;
! 260: uint16_t port;
! 261: } to_subnet_port_tests[] = {
! 262: { "10.0.0.0/8", 0, 0, 0 },
! 263: { "10.0.0.1/32", 80, 80, 80 },
! 264: { "10.0.0.1/32", 123, 465, 0 },
! 265: { "0.0.0.0/0", 0, 65535, 0 },
! 266: { "fec1::/64", 0, 0, 0 },
! 267: { "fec1::1/128", 80, 80, 80 },
! 268: { "fec1::1/128", 123, 465, 0 },
! 269: { "::/0", 0, 65535, 0 },
! 270: };
! 271:
! 272: START_TEST(test_to_subnet_port)
! 273: {
! 274: traffic_selector_t *ts;
! 275: host_t *net, *exp_net;
! 276: uint8_t mask;
! 277: int exp_mask;
! 278:
! 279: ts = traffic_selector_create_from_cidr(to_subnet_port_tests[_i].cidr, 0,
! 280: to_subnet_port_tests[_i].from_port,
! 281: to_subnet_port_tests[_i].to_port);
! 282: ck_assert(ts->to_subnet(ts, &net, &mask));
! 283: exp_net = host_create_from_subnet(to_subnet_port_tests[_i].cidr, &exp_mask);
! 284: ck_assert(exp_net->ip_equals(exp_net, net));
! 285: ck_assert_int_eq(exp_mask, mask);
! 286: ck_assert_int_eq(to_subnet_port_tests[_i].port, net->get_port(net));
! 287: exp_net->destroy(exp_net);
! 288: net->destroy(net);
! 289: ts->destroy(ts);
! 290: }
! 291: END_TEST
! 292:
! 293: START_TEST(test_subset)
! 294: {
! 295: traffic_selector_t *a, *b;
! 296:
! 297: a = traffic_selector_create_from_cidr("10.1.0.0/16", 0, 0, 65535);
! 298: b = traffic_selector_create_from_cidr("10.1.5.0/24", 0, 0, 65535);
! 299: verify("10.1.5.0/24", NULL, a->get_subset(a, b));
! 300: verify("10.1.5.0/24", NULL, b->get_subset(b, a));
! 301: a->destroy(a);
! 302: b->destroy(b);
! 303:
! 304: a = traffic_selector_create_from_cidr("fec1::/64", 0, 0, 65535);
! 305: b = traffic_selector_create_from_cidr("fec1::1/128", 0, 0, 65535);
! 306: verify("fec1::1/128", NULL, a->get_subset(a, b));
! 307: verify("fec1::1/128", NULL, b->get_subset(b, a));
! 308: a->destroy(a);
! 309: b->destroy(b);
! 310: }
! 311: END_TEST
! 312:
! 313: START_TEST(test_subset_port)
! 314: {
! 315: traffic_selector_t *a, *b;
! 316:
! 317: a = traffic_selector_create_from_cidr("10.0.0.0/8", IPPROTO_TCP, 55, 60);
! 318: b = traffic_selector_create_from_cidr("10.2.7.16/30", 0, 0, 65535);
! 319: verify("10.2.7.16/30[tcp/55-60]", "10.2.7.16/30[6/55-60]",
! 320: a->get_subset(a, b));
! 321: a->destroy(a);
! 322: b->destroy(b);
! 323: }
! 324: END_TEST
! 325:
! 326: START_TEST(test_subset_equal)
! 327: {
! 328: traffic_selector_t *a, *b;
! 329:
! 330: a = traffic_selector_create_from_cidr("10.1.0.0/16", IPPROTO_TCP, 80, 80);
! 331: b = traffic_selector_create_from_cidr("10.1.0.0/16", IPPROTO_TCP, 80, 80);
! 332: verify("10.1.0.0/16[tcp/http]", "10.1.0.0/16[6/80]", a->get_subset(a, b));
! 333: a->destroy(a);
! 334: b->destroy(b);
! 335: }
! 336: END_TEST
! 337:
! 338: START_TEST(test_subset_nonet)
! 339: {
! 340: traffic_selector_t *a, *b;
! 341:
! 342: a = traffic_selector_create_from_cidr("10.1.0.0/16", 0, 0, 65535);
! 343: b = traffic_selector_create_from_cidr("10.2.0.0/16", 0, 0, 65535);
! 344: ck_assert(!a->get_subset(a, b));
! 345: a->destroy(a);
! 346: b->destroy(b);
! 347: }
! 348: END_TEST
! 349:
! 350: START_TEST(test_subset_noport)
! 351: {
! 352: traffic_selector_t *a, *b;
! 353:
! 354: a = traffic_selector_create_from_cidr("10.1.0.0/16", 0, 0, 9999);
! 355: b = traffic_selector_create_from_cidr("10.1.0.0/16", 0, 10000, 65535);
! 356: ck_assert(!a->get_subset(a, b));
! 357: a->destroy(a);
! 358: b->destroy(b);
! 359: }
! 360: END_TEST
! 361:
! 362: START_TEST(test_subset_noproto)
! 363: {
! 364: traffic_selector_t *a, *b;
! 365:
! 366: a = traffic_selector_create_from_cidr("10.1.0.0/16", IPPROTO_TCP, 0, 65535);
! 367: b = traffic_selector_create_from_cidr("10.1.0.0/16", IPPROTO_UDP, 0, 65535);
! 368: ck_assert(!a->get_subset(a, b));
! 369: a->destroy(a);
! 370: b->destroy(b);
! 371: }
! 372: END_TEST
! 373:
! 374: START_TEST(test_subset_nofamily)
! 375: {
! 376: traffic_selector_t *a, *b;
! 377:
! 378: a = traffic_selector_create_from_cidr("0.0.0.0/0", 0, 0, 65535);
! 379: b = traffic_selector_create_from_cidr("::/0", 0, 0, 65535);
! 380: ck_assert(!a->get_subset(a, b));
! 381: a->destroy(a);
! 382: b->destroy(b);
! 383: }
! 384: END_TEST
! 385:
! 386: START_TEST(test_subset_dynamic)
! 387: {
! 388: traffic_selector_t *a, *b;
! 389:
! 390: a = traffic_selector_create_dynamic(0, 0, 65535);
! 391: b = traffic_selector_create_from_cidr("10.1.0.0/16", 0, 0, 65535);
! 392: ck_assert(!a->get_subset(a, b));
! 393: ck_assert(!b->get_subset(b, a));
! 394: a->destroy(a);
! 395: b->destroy(b);
! 396: }
! 397: END_TEST
! 398:
! 399: START_TEST(test_subset_opaque)
! 400: {
! 401: traffic_selector_t *a, *b;
! 402:
! 403: a = traffic_selector_create_from_cidr("10.0.0.0/8", 0, 65535, 0);
! 404: b = traffic_selector_create_from_cidr("10.2.7.16/30", IPPROTO_TCP, 80, 80);
! 405: ck_assert(!a->get_subset(a, b));
! 406: ck_assert(!b->get_subset(b, a));
! 407: b->destroy(b);
! 408:
! 409: b = traffic_selector_create_from_cidr("10.2.7.16/30", IPPROTO_TCP, 65535, 0);
! 410: verify("10.2.7.16/30[tcp/OPAQUE]", "10.2.7.16/30[6/OPAQUE]", a->get_subset(a, b));
! 411: verify("10.2.7.16/30[tcp/OPAQUE]", "10.2.7.16/30[6/OPAQUE]", b->get_subset(b, a));
! 412: b->destroy(b);
! 413:
! 414: b = traffic_selector_create_from_cidr("10.2.7.16/30", IPPROTO_TCP, 0, 65535);
! 415: verify("10.2.7.16/30[tcp/OPAQUE]", "10.2.7.16/30[6/OPAQUE]", a->get_subset(a, b));
! 416: verify("10.2.7.16/30[tcp/OPAQUE]", "10.2.7.16/30[6/OPAQUE]", b->get_subset(b, a));
! 417: a->destroy(a);
! 418: b->destroy(b);
! 419: }
! 420: END_TEST
! 421:
! 422: struct {
! 423: char *net;
! 424: char *host;
! 425: bool inc;
! 426: } include_tests[] = {
! 427: { "0.0.0.0/0", "192.168.1.2", TRUE },
! 428: { "::/0", "fec2::1", TRUE },
! 429: { "fec2::/64", "fec2::afaf", TRUE },
! 430: { "10.1.0.0/16", "10.1.0.1", TRUE },
! 431: { "10.5.6.7/32", "10.5.6.7", TRUE },
! 432: { "0.0.0.0/0", "fec2::1", FALSE },
! 433: { "::/0", "1.2.3.4", FALSE },
! 434: { "10.0.0.0/16", "10.1.0.0", FALSE },
! 435: { "10.1.0.0/16", "10.0.255.255", FALSE },
! 436: { "fec2::/64", "fec2:0:0:1::afaf", FALSE },
! 437: };
! 438:
! 439: START_TEST(test_includes)
! 440: {
! 441: traffic_selector_t *ts;
! 442: host_t *h;
! 443:
! 444: ts = traffic_selector_create_from_cidr(include_tests[_i].net, 0, 0, 65535);
! 445: h = host_create_from_string(include_tests[_i].host, 0);
! 446: ck_assert(ts->includes(ts, h) == include_tests[_i].inc);
! 447: ts->destroy(ts);
! 448: h->destroy(h);
! 449: }
! 450: END_TEST
! 451:
! 452: struct {
! 453: bool contained;
! 454: struct {
! 455: char *net;
! 456: uint8_t proto;
! 457: uint16_t from_port;
! 458: uint16_t to_port;
! 459: } a, b;
! 460: } is_contained_in_tests[] = {
! 461: { TRUE, { "10.0.0.0/16", 0, 0, 65535 }, { "10.0.0.0/16", 0, 0, 65535 }, },
! 462: { TRUE, { "10.0.1.0/24", 0, 0, 65535 }, { "10.0.0.0/16", 0, 0, 65535 }, },
! 463: { TRUE, { "10.0.1.0/24", 17, 123, 456 }, { "10.0.0.0/16", 0, 0, 65535 }, },
! 464: { TRUE, { "10.0.1.0/24", 17, 123, 456 }, { "10.0.0.0/16", 17, 123, 456 },},
! 465: { FALSE, { "10.0.0.0/8", 0, 0, 65535 }, { "10.0.0.0/16", 0, 0, 65535 }, },
! 466: { FALSE, { "10.0.1.0/24", 17, 0, 65535 }, { "10.0.0.0/16", 17, 123, 456 },},
! 467: { FALSE, { "fec2::/64", 0, 0, 65535 }, { "10.0.0.0/16", 17, 123, 456 },},
! 468: };
! 469:
! 470: START_TEST(test_is_contained_in)
! 471: {
! 472: traffic_selector_t *a, *b;
! 473:
! 474: a = traffic_selector_create_from_cidr(
! 475: is_contained_in_tests[_i].a.net, is_contained_in_tests[_i].a.proto,
! 476: is_contained_in_tests[_i].a.from_port, is_contained_in_tests[_i].a.to_port);
! 477: b = traffic_selector_create_from_cidr(
! 478: is_contained_in_tests[_i].b.net, is_contained_in_tests[_i].b.proto,
! 479: is_contained_in_tests[_i].b.from_port, is_contained_in_tests[_i].b.to_port);
! 480: ck_assert(a->is_contained_in(a, b) == is_contained_in_tests[_i].contained);
! 481: a->destroy(a);
! 482: b->destroy(b);
! 483: }
! 484: END_TEST
! 485:
! 486: struct {
! 487: char *net;
! 488: char *host;
! 489: bool is_host;
! 490: bool when_null;
! 491: } is_host_tests[] = {
! 492: { "0.0.0.0/0", "192.168.1.2", FALSE, FALSE },
! 493: { "::/0", "fec2::1", FALSE, FALSE },
! 494: { "192.168.1.0/24", "192.168.1.0", FALSE, FALSE },
! 495: { "192.168.1.2/32", "192.168.1.2", TRUE, TRUE },
! 496: { "192.168.1.2/32", "192.168.1.1", FALSE, TRUE },
! 497: { "192.168.1.2/32", "fec2::1", FALSE, TRUE },
! 498: { "fec2::1/128", "fec2::1", TRUE, TRUE },
! 499: { "fec2::1/128", "fec2::2", FALSE, TRUE },
! 500: { "fec2::1/128", "192.168.1.2", FALSE, TRUE },
! 501: };
! 502:
! 503: START_TEST(test_is_host)
! 504: {
! 505: traffic_selector_t *ts;
! 506: host_t *h;
! 507:
! 508: ts = traffic_selector_create_from_cidr(is_host_tests[_i].net, 0, 0, 65535);
! 509: h = host_create_from_string(is_host_tests[_i].host, 0);
! 510: ck_assert(ts->is_host(ts, h) == is_host_tests[_i].is_host);
! 511: ck_assert(ts->is_host(ts, NULL) == is_host_tests[_i].when_null);
! 512: ts->destroy(ts);
! 513: h->destroy(h);
! 514: }
! 515: END_TEST
! 516:
! 517: START_TEST(test_is_host_dynamic)
! 518: {
! 519: traffic_selector_t *ts;
! 520: host_t *h;
! 521:
! 522: ts = traffic_selector_create_dynamic(0, 0, 65535);
! 523: h = host_create_from_string(is_host_tests[_i].host, 0);
! 524: ck_assert(!ts->is_host(ts, h));
! 525: ck_assert(ts->is_host(ts, NULL));
! 526: ts->destroy(ts);
! 527: h->destroy(h);
! 528: }
! 529: END_TEST
! 530:
! 531:
! 532: struct {
! 533: char *orig;
! 534: char *host;
! 535: char *after;
! 536: } set_address_tests[] = {
! 537: { "0.0.0.0/0", "192.168.1.2", "192.168.1.2/32" },
! 538: { "::/0", "fec2::1", "fec2::1/128" },
! 539: { "192.168.1.2/32", "192.168.1.1", "192.168.1.1/32" },
! 540: { "192.168.1.0/24", "192.168.1.1", "192.168.1.1/32" },
! 541: { "192.168.1.2/32", "fec2::1", "fec2::1/128" },
! 542: { "192.168.1.0/24", "fec2::1", "fec2::1/128" },
! 543: { "192.168.1.2/32", "%any", "0.0.0.0/0" },
! 544: { "192.168.1.0/24", "%any", "0.0.0.0/0" },
! 545: { "192.168.1.2/32", "%any6", "::/0" },
! 546: { "192.168.1.0/24", "%any6", "::/0" },
! 547: { "fec2::1/128", "192.168.1.1", "192.168.1.1/32" },
! 548: { "fec2::/64", "192.168.1.1", "192.168.1.1/32" },
! 549: { "fec2::1/128", "fec2::2", "fec2::2/128" },
! 550: { "fec2::/64", "fec2::2", "fec2::2/128" },
! 551: { "fec2::1/128", "%any", "0.0.0.0/0" },
! 552: { "fec2::/64", "%any", "0.0.0.0/0" },
! 553: { "fec2::1/128", "%any6", "::/0" },
! 554: { "fec2::/64", "%any6", "::/0" },
! 555: { NULL, "192.168.1.1", "192.168.1.1/32" },
! 556: { NULL, "fec2::1", "fec2::1/128" },
! 557: { NULL, "%any", "0.0.0.0/0" },
! 558: { NULL, "%any6", "::/0" },
! 559: };
! 560:
! 561: START_TEST(test_set_address)
! 562: {
! 563: traffic_selector_t *ts;
! 564: host_t *h;
! 565:
! 566: if (set_address_tests[_i].orig)
! 567: {
! 568: ts = traffic_selector_create_from_cidr(set_address_tests[_i].orig, 0, 0, 65535);
! 569: ck_assert(!ts->is_dynamic(ts));
! 570: }
! 571: else
! 572: {
! 573: ts = traffic_selector_create_dynamic(0, 0, 65535);
! 574: ck_assert(ts->is_dynamic(ts));
! 575: }
! 576: h = host_create_from_string(set_address_tests[_i].host, 0);
! 577: ts->set_address(ts, h);
! 578: ck_assert(!ts->is_dynamic(ts));
! 579: verify(set_address_tests[_i].after, NULL, ts);
! 580: h->destroy(h);
! 581: }
! 582: END_TEST
! 583:
! 584:
! 585: struct {
! 586: int res;
! 587: struct {
! 588: char *net;
! 589: uint8_t proto;
! 590: uint16_t from_port;
! 591: uint16_t to_port;
! 592: } a, b;
! 593: } cmp_tests[] = {
! 594: { 0, { "10.0.0.0/8", 0, 0, 65535 }, { "10.0.0.0/8", 0, 0, 65535 }, },
! 595: { 0, { "10.0.0.0/8", 17, 123, 456 }, { "10.0.0.0/8", 17, 123, 456 }, },
! 596: { 0, { "fec2::/64", 0, 0, 65535 }, { "fec2::/64", 0, 0, 65535 }, },
! 597: { 0, { "fec2::/64", 4, 0, 65535 }, { "fec2::/64", 4, 0, 65535 }, },
! 598:
! 599: { -1, { "1.0.0.0/8", 0, 0, 65535 }, { "2.0.0.0/8", 0, 0, 65535 }, },
! 600: { 1, { "2.0.0.0/8", 0, 0, 65535 }, { "1.0.0.0/8", 0, 0, 65535 }, },
! 601: { -1, { "1.0.0.0/8", 0, 0, 65535 }, { "1.0.0.0/16", 0, 0, 65535 }, },
! 602: { 1, { "1.0.0.0/16", 0, 0, 65535 }, { "1.0.0.0/8", 0, 0, 65535 }, },
! 603: { -1, { "fec1::/64", 0, 0, 65535 }, { "fec2::/64", 0, 0, 65535 }, },
! 604: { 1, { "fec2::/64", 0, 0, 65535 }, { "fec1::/64", 0, 0, 65535 }, },
! 605: { -1, { "fec1::/48", 0, 0, 65535 }, { "fec1::/64", 0, 0, 65535 }, },
! 606: { 1, { "fec1::/64", 0, 0, 65535 }, { "fec1::/48", 0, 0, 65535 }, },
! 607:
! 608: { -1, { "10.0.0.0/8", 0, 0, 65535 }, { "fec2::/64", 0, 0, 65535 }, },
! 609: { 1, { "fec2::/64", 0, 0, 65535 }, { "10.0.0.0/8", 0, 0, 65535 }, },
! 610:
! 611: { -1, { "10.0.0.0/8", 16, 123, 456 }, { "10.0.0.0/8", 17, 123, 456 }, },
! 612: { 1, { "fec2::/64", 5, 0, 65535 }, { "fec2::/64", 4, 0, 65535 }, },
! 613:
! 614: { -1, { "10.0.0.0/8", 17, 111, 456 }, { "10.0.0.0/8", 17, 222, 456 }, },
! 615: { 1, { "fec2::/64", 17, 555, 65535 }, { "fec2::/64", 17, 444, 65535 },},
! 616:
! 617: { -1, { "10.0.0.0/8", 17, 55, 65535 }, { "10.0.0.0/8", 17, 55, 666 }, },
! 618: { 1, { "fec2::/64", 17, 55, 111 }, { "fec2::/64", 17, 55, 4567 }, },
! 619:
! 620: };
! 621:
! 622: START_TEST(test_cmp)
! 623: {
! 624: traffic_selector_t *a, *b;
! 625:
! 626: a = traffic_selector_create_from_cidr(
! 627: cmp_tests[_i].a.net, cmp_tests[_i].a.proto,
! 628: cmp_tests[_i].a.from_port, cmp_tests[_i].a.to_port);
! 629: b = traffic_selector_create_from_cidr(
! 630: cmp_tests[_i].b.net, cmp_tests[_i].b.proto,
! 631: cmp_tests[_i].b.from_port, cmp_tests[_i].b.to_port);
! 632: switch (cmp_tests[_i].res)
! 633: {
! 634: case 0:
! 635: ck_assert(traffic_selector_cmp(a, b, NULL) == 0);
! 636: ck_assert(a->equals(a, b));
! 637: break;
! 638: case 1:
! 639: ck_assert(traffic_selector_cmp(a, b, NULL) > 0);
! 640: ck_assert(!a->equals(a, b));
! 641: break;
! 642: case -1:
! 643: ck_assert(traffic_selector_cmp(a, b, NULL) < 0);
! 644: ck_assert(!a->equals(a, b));
! 645: break;
! 646: }
! 647: a->destroy(a);
! 648: b->destroy(b);
! 649: }
! 650: END_TEST
! 651:
! 652: static void verify_clone(traffic_selector_t *ts)
! 653: {
! 654: traffic_selector_t *clone;
! 655:
! 656: clone = ts->clone(ts);
! 657: if (!ts->equals(ts, clone))
! 658: {
! 659: fail("%R != %R", ts, clone);
! 660: }
! 661: /* equals() already compares most of these but not all */
! 662: ck_assert(ts->get_type(ts) == clone->get_type(clone));
! 663: ck_assert(ts->get_protocol(ts) == clone->get_protocol(clone));
! 664: ck_assert(ts->get_from_port(ts) == clone->get_from_port(clone));
! 665: ck_assert(ts->get_to_port(ts) == clone->get_to_port(clone));
! 666: ck_assert_chunk_eq(ts->get_from_address(ts), clone->get_from_address(clone));
! 667: ck_assert_chunk_eq(ts->get_to_address(ts), clone->get_to_address(clone));
! 668: ck_assert(ts->is_host(ts, NULL) == clone->is_host(clone, NULL));
! 669: ck_assert(ts->is_dynamic(ts) == clone->is_dynamic(clone));
! 670: clone->destroy(clone);
! 671: ts->destroy(ts);
! 672: }
! 673:
! 674: START_TEST(test_clone)
! 675: {
! 676: traffic_selector_t *ts;
! 677: host_t *h;
! 678:
! 679: ts = traffic_selector_create_dynamic(0, 0, 0);
! 680: verify_clone(ts);
! 681: ts = traffic_selector_create_dynamic(IPPROTO_UDP, 123, 456);
! 682: verify_clone(ts);
! 683: ts = traffic_selector_create_dynamic(IPPROTO_UDP, 0, 65535);
! 684: verify_clone(ts);
! 685:
! 686: h = host_create_from_string("192.168.1.1", 0);
! 687: ts = traffic_selector_create_dynamic(0, 0, 0);
! 688: ts->set_address(ts, h);
! 689: verify_clone(ts);
! 690: ts = traffic_selector_create_dynamic(IPPROTO_UDP, 123, 456);
! 691: ts->set_address(ts, h);
! 692: verify_clone(ts);
! 693: h->destroy(h);
! 694:
! 695: ts = traffic_selector_create_from_string(0, TS_IPV4_ADDR_RANGE, "10.0.0.1", 0, "10.0.0.16", 65535);
! 696: verify_clone(ts);
! 697: ts = traffic_selector_create_from_string(IPPROTO_TCP, TS_IPV6_ADDR_RANGE, "fec1::1", 80, "fec1::1:0000", 80);
! 698: verify_clone(ts);
! 699: ts = traffic_selector_create_from_cidr("10.0.0.0/8", 0, 0, 65535);
! 700: verify_clone(ts);
! 701: ts = traffic_selector_create_from_cidr("fec1::/64", 0, 0, 65535);
! 702: verify_clone(ts);
! 703: }
! 704: END_TEST
! 705:
! 706: START_TEST(test_hash)
! 707: {
! 708: traffic_selector_t *a, *b;
! 709: host_t *h;
! 710:
! 711: a = traffic_selector_create_dynamic(0, 0, 0);
! 712: b = traffic_selector_create_from_cidr("0.0.0.0/0", 0, 0, 0);
! 713: ck_assert(a->hash(a, 0) != a->hash(a, 1));
! 714: ck_assert_int_eq(a->hash(a, 0), b->hash(b, 0));
! 715: ck_assert_int_eq(a->hash(a, 1), b->hash(b, 1));
! 716:
! 717: h = host_create_from_string("192.168.1.1", 0);
! 718: a->set_address(a, h);
! 719: ck_assert(a->hash(a, 0) != b->hash(b, 0));
! 720: h->destroy(h);
! 721:
! 722: a->destroy(a);
! 723: a = traffic_selector_create_from_string(0, TS_IPV4_ADDR_RANGE, "192.168.0.0", 0, "192.168.0.255", 65535);
! 724: ck_assert(a->hash(a, 0) != b->hash(b, 0));
! 725: b->destroy(b);
! 726: b = traffic_selector_create_from_cidr("192.168.0.0/24", 0, 0, 65535);
! 727: ck_assert_int_eq(a->hash(a, 0), b->hash(b, 0));
! 728: b->destroy(b);
! 729: b = traffic_selector_create_from_cidr("192.168.0.0/24", IPPROTO_TCP, 0, 65535);
! 730: ck_assert(a->hash(a, 0) != b->hash(b, 0));
! 731: b->destroy(b);
! 732: b = traffic_selector_create_from_cidr("192.168.0.0/24", 0, 123, 456);
! 733: ck_assert(a->hash(a, 0) != b->hash(b, 0));
! 734: b->destroy(b);
! 735: a->destroy(a);
! 736: }
! 737: END_TEST
! 738:
! 739: struct {
! 740: uint8_t proto;
! 741: uint16_t from_port;
! 742: uint16_t to_port;
! 743: uint8_t from_type;
! 744: uint8_t from_code;
! 745: uint8_t to_type;
! 746: uint8_t to_code;
! 747: char *str;
! 748: char *str_alt;
! 749: } icmp_tests[] = {
! 750: { IPPROTO_ICMP, 0, 0, 0, 0, 0, 0, "dynamic[icmp/0]", "dynamic[1/0]" },
! 751: { IPPROTO_ICMP, 3, 3, 3, 0, 3, 0, "dynamic[icmp/3]", "dynamic[1/3]" },
! 752: { IPPROTO_ICMP, 0x0307, 0x0307, 3, 7, 3, 7, "dynamic[icmp/3(7)]", "dynamic[1/3(7)]" },
! 753: { IPPROTO_ICMP, 0x0300, 0x040f, 3, 0, 4, 15, "dynamic[icmp/3-4(15)]", "dynamic[1/3-4(15)]" },
! 754: { IPPROTO_ICMP, 0x0301, 0x040f, 3, 1, 4, 15, "dynamic[icmp/3(1)-4(15)]", "dynamic[1/3(1)-4(15)]" },
! 755: { IPPROTO_ICMPV6, 0, 0, 0, 0, 0, 0, "dynamic[ipv6-icmp/0]", "dynamic[58/0]" },
! 756: { IPPROTO_ICMPV6, 1, 1, 1, 0, 1, 0, "dynamic[ipv6-icmp/1]", "dynamic[58/1]" },
! 757: { IPPROTO_ICMPV6, 0x0104, 0x0104, 1, 4, 1, 4, "dynamic[ipv6-icmp/1(4)]", "dynamic[58/1(4)]" },
! 758: { IPPROTO_ICMPV6, 0x0100, 0x040f, 1, 0, 4, 15, "dynamic[ipv6-icmp/1-4(15)]", "dynamic[58/1-4(15)]" },
! 759: { IPPROTO_ICMPV6, 0x0101, 0x040f, 1, 1, 4, 15, "dynamic[ipv6-icmp/1(1)-4(15)]", "dynamic[58/1(1)-4(15)]" },
! 760: };
! 761:
! 762: START_TEST(test_icmp)
! 763: {
! 764: traffic_selector_t *ts;
! 765: uint16_t from, to;
! 766:
! 767: ts = traffic_selector_create_dynamic(icmp_tests[_i].proto,
! 768: icmp_tests[_i].from_port, icmp_tests[_i].to_port);
! 769: from = ts->get_from_port(ts);
! 770: to = ts->get_to_port(ts);
! 771: ck_assert_int_eq(icmp_tests[_i].from_type, traffic_selector_icmp_type(from));
! 772: ck_assert_int_eq(icmp_tests[_i].from_code, traffic_selector_icmp_code(from));
! 773: ck_assert_int_eq(icmp_tests[_i].to_type, traffic_selector_icmp_type(to));
! 774: ck_assert_int_eq(icmp_tests[_i].to_code, traffic_selector_icmp_code(to));
! 775: verify(icmp_tests[_i].str, icmp_tests[_i].str_alt, ts);
! 776: }
! 777: END_TEST
! 778:
! 779: static void verify_list(const char *str, const char *alt, linked_list_t *list)
! 780: {
! 781: char buf[512];
! 782:
! 783: snprintf(buf, sizeof(buf), "%#R", list);
! 784: list->destroy_offset(list, offsetof(traffic_selector_t, destroy));
! 785: if (!streq(buf, str) && !streq(buf, alt))
! 786: {
! 787: fail("%s != %s or %s", buf, str, alt);
! 788: }
! 789: }
! 790:
! 791: START_TEST(test_printf_hook_null)
! 792: {
! 793: verify("(null)", NULL, NULL);
! 794: }
! 795: END_TEST
! 796:
! 797: START_TEST(test_printf_hook_hash)
! 798: {
! 799: linked_list_t *list;
! 800:
! 801: list = linked_list_create_with_items(
! 802: traffic_selector_create_from_cidr("10.1.0.0/16", 0, 0, 65535),
! 803: NULL);
! 804: verify_list("10.1.0.0/16", NULL, list);
! 805: list = linked_list_create_with_items(
! 806: traffic_selector_create_from_cidr("10.1.0.0/16", 0, 0, 65535),
! 807: traffic_selector_create_from_cidr("10.1.0.1/32", IPPROTO_UDP, 1234, 1235),
! 808: NULL);
! 809: 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);
! 810: list = linked_list_create_with_items(
! 811: traffic_selector_create_from_cidr("10.1.0.0/16", 0, 0, 65535),
! 812: traffic_selector_create_from_string(IPPROTO_UDP, TS_IPV4_ADDR_RANGE, "10.1.0.1", 1234, "10.1.0.99", 1235),
! 813: NULL);
! 814: 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);
! 815: }
! 816: END_TEST
! 817:
! 818: Suite *traffic_selector_suite_create()
! 819: {
! 820: Suite *s;
! 821: TCase *tc;
! 822:
! 823: s = suite_create("traffic selector");
! 824:
! 825: tc = tcase_create("create");
! 826: tcase_add_test(tc, test_create_from_string);
! 827: tcase_add_test(tc, test_create_from_cidr);
! 828: tcase_add_test(tc, test_create_from_bytes);
! 829: tcase_add_test(tc, test_create_from_subnet);
! 830: tcase_add_loop_test(tc, test_create_from_rfc3779_format_prefix, 0, countof(rfc3779_prefix_tests));
! 831: tcase_add_test(tc, test_create_from_rfc3779_format_range);
! 832: suite_add_tcase(s, tc);
! 833:
! 834: tc = tcase_create("addresses");
! 835: tcase_add_test(tc, test_get_address_range);
! 836: tcase_add_test(tc, test_get_address_cidr);
! 837: suite_add_tcase(s, tc);
! 838:
! 839: tc = tcase_create("to_subnet");
! 840: tcase_add_loop_test(tc, test_to_subnet, 0, countof(to_subnet_tests));
! 841: tcase_add_loop_test(tc, test_to_subnet_port, 0, countof(to_subnet_port_tests));
! 842: suite_add_tcase(s, tc);
! 843:
! 844: tc = tcase_create("subset");
! 845: tcase_add_test(tc, test_subset);
! 846: tcase_add_test(tc, test_subset_port);
! 847: tcase_add_test(tc, test_subset_equal);
! 848: tcase_add_test(tc, test_subset_nonet);
! 849: tcase_add_test(tc, test_subset_noport);
! 850: tcase_add_test(tc, test_subset_noproto);
! 851: tcase_add_test(tc, test_subset_nofamily);
! 852: tcase_add_test(tc, test_subset_dynamic);
! 853: tcase_add_test(tc, test_subset_opaque);
! 854: suite_add_tcase(s, tc);
! 855:
! 856: tc = tcase_create("includes");
! 857: tcase_add_loop_test(tc, test_includes, 0, countof(include_tests));
! 858: suite_add_tcase(s, tc);
! 859:
! 860: tc = tcase_create("is_contained_in");
! 861: tcase_add_loop_test(tc, test_is_contained_in, 0, countof(is_contained_in_tests));
! 862: suite_add_tcase(s, tc);
! 863:
! 864: tc = tcase_create("is_host");
! 865: tcase_add_loop_test(tc, test_is_host, 0, countof(is_host_tests));
! 866: tcase_add_loop_test(tc, test_is_host_dynamic, 0, countof(is_host_tests));
! 867: suite_add_tcase(s, tc);
! 868:
! 869: tc = tcase_create("set_address");
! 870: tcase_add_loop_test(tc, test_set_address, 0, countof(is_host_tests));
! 871: suite_add_tcase(s, tc);
! 872:
! 873: tc = tcase_create("cmp");
! 874: tcase_add_loop_test(tc, test_cmp, 0, countof(cmp_tests));
! 875: suite_add_tcase(s, tc);
! 876:
! 877: tc = tcase_create("clone");
! 878: tcase_add_test(tc, test_clone);
! 879: suite_add_tcase(s, tc);
! 880:
! 881: tc = tcase_create("hash");
! 882: tcase_add_test(tc, test_hash);
! 883: suite_add_tcase(s, tc);
! 884:
! 885: tc = tcase_create("icmp");
! 886: tcase_add_loop_test(tc, test_icmp, 0, countof(icmp_tests));
! 887: suite_add_tcase(s, tc);
! 888:
! 889: tc = tcase_create("printf hook");
! 890: tcase_add_test(tc, test_printf_hook_null);
! 891: tcase_add_test(tc, test_printf_hook_hash);
! 892: suite_add_tcase(s, tc);
! 893:
! 894: return s;
! 895: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>