Home | History | Annotate | Line # | Download | only in libnpftest
npf_table_test.c revision 1.9.12.2
      1 /*	$NetBSD: npf_table_test.c,v 1.9.12.2 2019/01/26 22:00:39 pgoyette Exp $	*/
      2 
      3 /*
      4  * NPF tableset tests.
      5  *
      6  * Public Domain.
      7  */
      8 
      9 #ifdef _KERNEL
     10 #include <sys/types.h>
     11 #include <sys/kmem.h>
     12 #endif
     13 
     14 #ifdef __linux__
     15 #include <endian.h>
     16 #else
     17 #include <sys/endian.h>
     18 #endif
     19 
     20 #include "npf_impl.h"
     21 #include "npf_test.h"
     22 
     23 static const char *ip_list[] = {
     24 	"192.168.1.1",
     25 	"10.0.0.1",
     26 	"192.168.2.1",
     27 	"10.1.0.1",
     28 	"192.168.100.253",
     29 	"10.0.5.1",
     30 	"192.168.128.127",
     31 	"10.0.0.2",
     32 };
     33 
     34 static const uint8_t ip6_list[][16] = {
     35 	{
     36 		0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     37 		0x02, 0xa0, 0xc0, 0xff, 0xfe, 0x10, 0x12, 0x34
     38 	},
     39 	{
     40 		0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     41 		0x02, 0xa0, 0xc0, 0xff, 0x00, 0x00, 0x00, 0x00,
     42 	},
     43 	{
     44 		0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     45 		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
     46 	},
     47 	{
     48 		0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     49 		0x02, 0xa0, 0xc0, 0xff, 0xfe, 0x10, 0x12, 0x30
     50 	}
     51 };
     52 
     53 #define	CHECK_TRUE(x)	\
     54     if (!(x)) { printf("FAIL: %s line %d\n", __func__, __LINE__); return 0; }
     55 
     56 #define	IPSET_TID		0
     57 #define	IPSET_NAME		"ipset-table"
     58 
     59 #define	LPM_TID			1
     60 #define	LPM_NAME		"lpm-table"
     61 
     62 #define	CDB_TID			2
     63 #define	CDB_NAME		"cdb-table"
     64 
     65 #define	IFADDR_TID		3
     66 #define	IFADDR_NAME		".ifaddr-eth0"
     67 
     68 ///////////////////////////////////////////////////////////////////////////
     69 
     70 static bool
     71 check_ip4(const npf_addr_t *addr, const char *ipstr)
     72 {
     73 	npf_addr_t addr_storage, *test_addr = &addr_storage;
     74 	const int alen = sizeof(struct in_addr);
     75 	test_addr->word32[0] = inet_addr(ipstr);
     76 	return memcmp(addr, test_addr, alen) == 0;
     77 }
     78 
     79 static bool
     80 ip4list_insert_lookup(npf_table_t *t, unsigned i)
     81 {
     82 	npf_addr_t addr_storage, *addr = &addr_storage;
     83 	const int alen = sizeof(struct in_addr);
     84 	int error;
     85 
     86 	addr->word32[0] = inet_addr(ip_list[i]);
     87 	error = npf_table_insert(t, alen, addr, NPF_NO_NETMASK);
     88 	CHECK_TRUE(error == 0);
     89 	error = npf_table_lookup(t, alen, addr);
     90 	CHECK_TRUE(error == 0);
     91 	return true;
     92 }
     93 
     94 static bool
     95 fill_with_ip4(npf_tableset_t *tblset)
     96 {
     97 	npf_addr_t addr_storage, *addr = &addr_storage;
     98 	const int alen = sizeof(struct in_addr);
     99 	const int nm = NPF_NO_NETMASK;
    100 
    101 	for (unsigned i = 0; i < __arraycount(ip_list); i++) {
    102 		npf_table_t *t;
    103 		int error;
    104 
    105 		addr->word32[0] = inet_addr(ip_list[i]);
    106 
    107 		t = npf_tableset_getbyname(tblset, IPSET_NAME);
    108 		error = npf_table_insert(t, alen, addr, nm);
    109 		CHECK_TRUE(error == 0);
    110 		error = npf_table_insert(t, alen, addr, nm);
    111 		CHECK_TRUE(error != 0); // duplicate
    112 
    113 		t = npf_tableset_getbyname(tblset, LPM_NAME);
    114 		error = npf_table_insert(t, alen, addr, nm);
    115 		CHECK_TRUE(error == 0);
    116 		error = npf_table_insert(t, alen, addr, nm);
    117 		CHECK_TRUE(error != 0); // duplicate
    118 	}
    119 	return true;
    120 }
    121 
    122 static bool
    123 verify_ip4(npf_tableset_t *tblset)
    124 {
    125 	npf_addr_t addr_storage, *addr = &addr_storage;
    126 	const size_t alen = sizeof(struct in_addr);
    127 	const int nm = NPF_NO_NETMASK;
    128 	npf_table_t *t;
    129 	int error;
    130 
    131 	/* Attempt to add duplicates - should fail. */
    132 	addr->word32[0] = inet_addr(ip_list[0]);
    133 
    134 	t = npf_tableset_getbyname(tblset, IPSET_NAME);
    135 	error = npf_table_insert(t, alen, addr, nm);
    136 	CHECK_TRUE(error != 0);
    137 
    138 	t = npf_tableset_getbyname(tblset, LPM_NAME);
    139 	error = npf_table_insert(t, alen, addr, nm);
    140 	CHECK_TRUE(error != 0);
    141 
    142 	/* Match (validate) each IP entry. */
    143 	for (unsigned i = 0; i < __arraycount(ip_list); i++) {
    144 		addr->word32[0] = inet_addr(ip_list[i]);
    145 
    146 		t = npf_tableset_getbyname(tblset, IPSET_NAME);
    147 		error = npf_table_lookup(t, alen, addr);
    148 		CHECK_TRUE(error == 0);
    149 
    150 		t = npf_tableset_getbyname(tblset, LPM_NAME);
    151 		error = npf_table_lookup(t, alen, addr);
    152 		CHECK_TRUE(error == 0);
    153 	}
    154 	return true;
    155 }
    156 
    157 static bool
    158 clear_ip4(npf_tableset_t *tblset)
    159 {
    160 	npf_addr_t addr_storage, *addr = &addr_storage;
    161 	const int alen = sizeof(struct in_addr);
    162 	const int nm = NPF_NO_NETMASK;
    163 
    164 	for (unsigned i = 0; i < __arraycount(ip_list); i++) {
    165 		npf_table_t *t;
    166 		int error;
    167 
    168 		addr->word32[0] = inet_addr(ip_list[i]);
    169 
    170 		t = npf_tableset_getbyname(tblset, IPSET_NAME);
    171 		error = npf_table_remove(t, alen, addr, nm);
    172 		CHECK_TRUE(error == 0);
    173 
    174 		error = npf_table_remove(t, alen, addr, nm);
    175 		CHECK_TRUE(error != 0);
    176 
    177 		t = npf_tableset_getbyname(tblset, LPM_NAME);
    178 		error = npf_table_remove(t, alen, addr, nm);
    179 		CHECK_TRUE(error == 0);
    180 
    181 		error = npf_table_remove(t, alen, addr, nm);
    182 		CHECK_TRUE(error != 0);
    183 	}
    184 	return true;
    185 }
    186 
    187 ///////////////////////////////////////////////////////////////////////////
    188 
    189 static bool
    190 test_basic(npf_tableset_t *tblset)
    191 {
    192 	npf_addr_t addr_storage, *addr = &addr_storage;
    193 	const int alen = sizeof(struct in_addr);
    194 	npf_table_t *t;
    195 	int error;
    196 
    197 	/* Basic IP set. */
    198 	t = npf_table_create(IPSET_NAME, IPSET_TID, NPF_TABLE_IPSET, NULL, 0);
    199 	CHECK_TRUE(t != NULL);
    200 	error = npf_tableset_insert(tblset, t);
    201 	CHECK_TRUE(error == 0);
    202 
    203 	/* Check for double-insert. */
    204 	error = npf_tableset_insert(tblset, t);
    205 	CHECK_TRUE(error != 0);
    206 
    207 	/* Longest-prefix match (LPM). */
    208 	t = npf_table_create(LPM_NAME, LPM_TID, NPF_TABLE_LPM, NULL, 0);
    209 	CHECK_TRUE(t != NULL);
    210 	error = npf_tableset_insert(tblset, t);
    211 	CHECK_TRUE(error == 0);
    212 
    213 	/* Table for interface addresses. */
    214 	t = npf_table_create(IFADDR_NAME, IFADDR_TID, NPF_TABLE_IFADDR, NULL, 0);
    215 	CHECK_TRUE(t != NULL);
    216 	error = npf_tableset_insert(tblset, t);
    217 	CHECK_TRUE(error == 0);
    218 
    219 	/*
    220 	 * Attempt to match some non-existing entries - should fail.
    221 	 */
    222 	addr->word32[0] = inet_addr(ip_list[0]);
    223 
    224 	t = npf_tableset_getbyname(tblset, IPSET_NAME);
    225 	error = npf_table_lookup(t, alen, addr);
    226 	CHECK_TRUE(error != 0);
    227 
    228 	t = npf_tableset_getbyname(tblset, LPM_NAME);
    229 	error = npf_table_lookup(t, alen, addr);
    230 	CHECK_TRUE(error != 0);
    231 
    232 	return true;
    233 }
    234 
    235 static bool
    236 test_nocopy(npf_tableset_t *tblset)
    237 {
    238 	const int alen = sizeof(struct in_addr);
    239 	const char *tables[] = { IPSET_NAME, LPM_NAME, IFADDR_NAME };
    240 	npf_addr_t *addr, lookup_addr;
    241 
    242 	for (unsigned i = 0; i < __arraycount(tables); i++) {
    243 		npf_table_t *t;
    244 		int error;
    245 
    246 		addr = kmem_zalloc(sizeof(npf_addr_t), KM_SLEEP);
    247 		assert(addr != NULL);
    248 		addr->word32[0] = inet_addr("172.16.90.10");
    249 
    250 		t = npf_tableset_getbyname(tblset, tables[i]);
    251 		(void)npf_table_flush(t);
    252 
    253 		error = npf_table_insert(t, alen, addr, NPF_NO_NETMASK);
    254 		CHECK_TRUE(error == 0);
    255 
    256 		memcpy(&lookup_addr, addr, alen);
    257 		memset(addr, 0xa5, alen); // explicit memset
    258 
    259 		error = npf_table_lookup(t, alen, &lookup_addr);
    260 		CHECK_TRUE(error == 0);
    261 
    262 		CHECK_TRUE(*(volatile unsigned char *)addr == 0xa5);
    263 		kmem_free(addr, sizeof(npf_addr_t));
    264 	}
    265 	return true;
    266 }
    267 
    268 static bool
    269 test_ip6(npf_tableset_t *tblset)
    270 {
    271 	npf_addr_t addr_storage, *addr = &addr_storage;
    272 	const size_t alen = sizeof(struct in6_addr);
    273 	const int nm = NPF_NO_NETMASK;
    274 	npf_table_t *t;
    275 	int error;
    276 
    277 	/* IPv6 addresses. */
    278 	memcpy(addr, ip6_list[0], sizeof(ip6_list[0]));
    279 
    280 	t = npf_tableset_getbyname(tblset, IPSET_NAME);
    281 	error = npf_table_insert(t, alen, addr, nm);
    282 	CHECK_TRUE(error == 0);
    283 	error = npf_table_lookup(t, alen, addr);
    284 	CHECK_TRUE(error == 0);
    285 	error = npf_table_remove(t, alen, addr, nm);
    286 	CHECK_TRUE(error == 0);
    287 
    288 	t = npf_tableset_getbyname(tblset, LPM_NAME);
    289 	error = npf_table_insert(t, alen, addr, nm);
    290 	CHECK_TRUE(error == 0);
    291 	error = npf_table_lookup(t, alen, addr);
    292 	CHECK_TRUE(error == 0);
    293 	error = npf_table_remove(t, alen, addr, nm);
    294 	CHECK_TRUE(error == 0);
    295 
    296 	return true;
    297 }
    298 
    299 static bool
    300 test_lpm_masks4(npf_tableset_t *tblset)
    301 {
    302 	npf_table_t *t = npf_tableset_getbyname(tblset, LPM_NAME);
    303 	npf_addr_t addr_storage, *addr = &addr_storage;
    304 	const size_t alen = sizeof(struct in_addr);
    305 	int error;
    306 
    307 	addr->word32[0] = inet_addr("172.16.90.0");
    308 	error = npf_table_insert(t, alen, addr, 25);
    309 	CHECK_TRUE(error == 0);
    310 
    311 	addr->word32[0] = inet_addr("172.16.90.126");
    312 	error = npf_table_lookup(t, alen, addr);
    313 	CHECK_TRUE(error == 0);
    314 
    315 	addr->word32[0] = inet_addr("172.16.90.128");
    316 	error = npf_table_lookup(t, alen, addr);
    317 	CHECK_TRUE(error != 0);
    318 
    319 	return true;
    320 }
    321 
    322 static bool
    323 test_lpm_masks6(npf_tableset_t *tblset)
    324 {
    325 	npf_table_t *t = npf_tableset_getbyname(tblset, LPM_NAME);
    326 	npf_addr_t addr_storage, *addr = &addr_storage;
    327 	const size_t alen = sizeof(struct in6_addr);
    328 	int error;
    329 
    330 	/*
    331 	 * 96
    332 	 */
    333 	memcpy(addr, ip6_list[1], sizeof(ip6_list[1]));
    334 	error = npf_table_insert(t, alen, addr, 96);
    335 	CHECK_TRUE(error == 0);
    336 
    337 	memcpy(addr, ip6_list[0], sizeof(ip6_list[0]));
    338 	error = npf_table_lookup(t, alen, addr);
    339 	CHECK_TRUE(error == 0);
    340 
    341 	memcpy(addr, ip6_list[1], sizeof(ip6_list[1]));
    342 	error = npf_table_remove(t, alen, addr, 96);
    343 	CHECK_TRUE(error == 0);
    344 
    345 	/*
    346 	 * 32
    347 	 */
    348 	memcpy(addr, ip6_list[2], sizeof(ip6_list[2]));
    349 	error = npf_table_insert(t, alen, addr, 32);
    350 	CHECK_TRUE(error == 0);
    351 
    352 	memcpy(addr, ip6_list[0], sizeof(ip6_list[0]));
    353 	error = npf_table_lookup(t, alen, addr);
    354 	CHECK_TRUE(error == 0);
    355 
    356 	memcpy(addr, ip6_list[2], sizeof(ip6_list[2]));
    357 	error = npf_table_remove(t, alen, addr, 32);
    358 	CHECK_TRUE(error == 0);
    359 
    360 	/*
    361 	 * 126
    362 	 */
    363 	memcpy(addr, ip6_list[3], sizeof(ip6_list[3]));
    364 	error = npf_table_insert(t, alen, addr, 126);
    365 	CHECK_TRUE(error == 0);
    366 
    367 	memcpy(addr, ip6_list[0], sizeof(ip6_list[0]));
    368 	error = npf_table_lookup(t, alen, addr);
    369 	CHECK_TRUE(error != 0);
    370 
    371 	memcpy(addr, ip6_list[3], sizeof(ip6_list[3]));
    372 	error = npf_table_remove(t, alen, addr, 126);
    373 	CHECK_TRUE(error == 0);
    374 
    375 	return true;
    376 }
    377 
    378 static bool
    379 test_const_table(npf_tableset_t *tblset, void *blob, size_t size)
    380 {
    381 	npf_addr_t addr_storage, *addr = &addr_storage;
    382 	const int alen = sizeof(struct in_addr);
    383 	npf_table_t *t;
    384 	int error;
    385 
    386 	t = npf_table_create(CDB_NAME, CDB_TID, NPF_TABLE_CONST, blob, size);
    387 	CHECK_TRUE(t != NULL);
    388 
    389 	error = npf_tableset_insert(tblset, t);
    390 	CHECK_TRUE(error == 0);
    391 
    392 	addr->word32[0] = inet_addr(ip_list[0]);
    393 	error = npf_table_lookup(t, alen, addr);
    394 	CHECK_TRUE(error == 0);
    395 
    396 	for (unsigned i = 1; i < __arraycount(ip_list) - 1; i++) {
    397 		addr->word32[0] = inet_addr(ip_list[i]);
    398 		error = npf_table_lookup(t, alen, addr);
    399 		CHECK_TRUE(error != 0);
    400 	}
    401 	return true;
    402 }
    403 
    404 static bool
    405 test_ifaddr_table(npf_tableset_t *tblset)
    406 {
    407 	npf_addr_t addr_storage, *addr = &addr_storage;
    408 	npf_table_t *t = npf_tableset_getbyname(tblset, IFADDR_NAME);
    409 	int error;
    410 	bool ok;
    411 
    412 	/* Two IPv4 addresses. */
    413 	ok = ip4list_insert_lookup(t, 0);
    414 	CHECK_TRUE(ok);
    415 
    416 	ok = ip4list_insert_lookup(t, 1);
    417 	CHECK_TRUE(ok);
    418 
    419 	/* And one IPv6 address. */
    420 	memcpy(addr, ip6_list[0], sizeof(ip6_list[0]));
    421 	error = npf_table_insert(t, sizeof(struct in6_addr), addr, NPF_NO_NETMASK);
    422 	CHECK_TRUE(error == 0);
    423 
    424 	/*
    425 	 * Get IPv4 addresses.
    426 	 */
    427 	addr = npf_table_getsome(t, sizeof(struct in_addr), 0);
    428 	ok = check_ip4(addr, "192.168.1.1");
    429 	CHECK_TRUE(ok);
    430 
    431 	addr = npf_table_getsome(t, sizeof(struct in_addr), 1);
    432 	ok = check_ip4(addr, "10.0.0.1");
    433 	CHECK_TRUE(ok);
    434 
    435 	addr = npf_table_getsome(t, sizeof(struct in_addr), 2);
    436 	ok = check_ip4(addr, "192.168.1.1");
    437 	CHECK_TRUE(ok);
    438 
    439 	return true;
    440 }
    441 
    442 static void
    443 test_ipset_gc(npf_tableset_t *tblset)
    444 {
    445 	npf_table_t *t = npf_tableset_getbyname(tblset, IPSET_NAME);
    446 	npf_t *npf = npf_getkernctx();
    447 
    448 	npf_config_enter(npf);
    449 	npf_table_gc(npf, t);
    450 	npf_table_flush(t);
    451 	npf_config_exit(npf);
    452 }
    453 
    454 bool
    455 npf_table_test(bool verbose, void *blob, size_t size)
    456 {
    457 	npf_tableset_t *tblset;
    458 	bool ok;
    459 
    460 	(void)verbose;
    461 
    462 	tblset = npf_tableset_create(4);
    463 	CHECK_TRUE(tblset != NULL);
    464 
    465 	ok = test_basic(tblset);
    466 	CHECK_TRUE(ok);
    467 
    468 	/*
    469 	 * Fill IPSET and LPM tables with IPv4 addresses.
    470 	 * Keep them in the table during the other tests.
    471 	 */
    472 	ok = fill_with_ip4(tblset);
    473 	CHECK_TRUE(ok);
    474 
    475 	ok = verify_ip4(tblset);
    476 	CHECK_TRUE(ok);
    477 
    478 	ok = test_ip6(tblset);
    479 	CHECK_TRUE(ok);
    480 
    481 	ok = test_lpm_masks4(tblset);
    482 	CHECK_TRUE(ok);
    483 
    484 	ok = test_lpm_masks6(tblset);
    485 	CHECK_TRUE(ok);
    486 
    487 	ok = test_const_table(tblset, blob, size);
    488 	CHECK_TRUE(ok);
    489 
    490 	ok = test_ifaddr_table(tblset);
    491 	CHECK_TRUE(ok);
    492 
    493 	/*
    494 	 * Remove the above IPv4 addresses -- they must have been untouched.
    495 	 */
    496 	ok = clear_ip4(tblset);
    497 	CHECK_TRUE(ok);
    498 
    499 	ok = test_nocopy(tblset);
    500 	CHECK_TRUE(ok);
    501 
    502 	test_ipset_gc(tblset);
    503 
    504 	npf_tableset_destroy(tblset);
    505 	return true;
    506 }
    507