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