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