/* $NetBSD: npf_table_test.c,v 1.9 2016/12/26 23:05:05 christos Exp $ */ /* * NPF tableset test. * * Public Domain. */ #ifdef _KERNEL #include #include #endif #ifdef __linux__ #include #else #include #endif #include "npf_impl.h" #include "npf_test.h" static const char *ip_list[] = { "192.168.1.1", "10.0.0.1", "192.168.2.1", "10.1.0.1", "192.168.100.253", "10.0.5.1", "192.168.128.127", "10.0.0.2", }; #if __BYTE_ORDER == __LITTLE_ENDIAN #define U16_TO_LE(x) ((((x) & 0xff) << 8) | (((x) & 0xff00) >> 8)) #else #define U16_TO_LE(x) (x) #endif static const uint16_t ip6_list[][8] = { { U16_TO_LE(0xfe80), 0x0, 0x0, 0x0, U16_TO_LE(0x2a0), U16_TO_LE(0xc0ff), U16_TO_LE(0xfe10), U16_TO_LE(0x1234) }, { U16_TO_LE(0xfe80), 0x0, 0x0, 0x0, U16_TO_LE(0x2a0), U16_TO_LE(0xc0ff), 0x00, 0x0 }, { U16_TO_LE(0xfe80), 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }, { U16_TO_LE(0xfe80), 0x0, 0x0, 0x0, U16_TO_LE(0x2a0), U16_TO_LE(0xc0ff), U16_TO_LE(0xfe10), U16_TO_LE(0x1230) } }; #define check_ok(x) \ ((x) ? true : (printf("fail at line %d\n", __LINE__), false)) #define HASH_TID "hash-table" #define TREE_TID "tree-table" #define CDB_TID "cdb-table" static bool npf_table_test_fill4(npf_tableset_t *tblset, npf_addr_t *addr) { const int alen = sizeof(struct in_addr); const int nm = NPF_NO_NETMASK; bool fail = false; /* Fill both tables with IP addresses. */ for (unsigned i = 0; i < __arraycount(ip_list); i++) { npf_table_t *t; int error; addr->word32[0] = inet_addr(ip_list[i]); t = npf_tableset_getbyname(tblset, HASH_TID); error = npf_table_insert(t, alen, addr, nm); fail |= !check_ok(error == 0); error = npf_table_insert(t, alen, addr, nm); fail |= !check_ok(error != 0); t = npf_tableset_getbyname(tblset, TREE_TID); error = npf_table_insert(t, alen, addr, nm); fail |= !check_ok(error == 0); error = npf_table_insert(t, alen, addr, nm); fail |= !check_ok(error != 0); } return fail; } bool npf_table_test(bool verbose, void *blob, size_t size) { npf_addr_t addr_storage, *addr = &addr_storage; const int nm = NPF_NO_NETMASK; npf_table_t *t, *t1, *t2, *t3; npf_tableset_t *tblset; int error, alen; bool fail = false; void *cdb; u_int i; tblset = npf_tableset_create(3); fail |= !check_ok(tblset != NULL); /* Table ID 1, using hash table with 256 lists. */ t1 = npf_table_create(HASH_TID, 0, NPF_TABLE_HASH, NULL, 256); fail |= !check_ok(t1 != NULL); error = npf_tableset_insert(tblset, t1); fail |= !check_ok(error == 0); /* Check for double-insert. */ error = npf_tableset_insert(tblset, t1); fail |= !check_ok(error != 0); /* Table ID 2, using a prefix tree. */ t2 = npf_table_create(TREE_TID, 1, NPF_TABLE_TREE, NULL, 0); fail |= !(t2 != NULL); error = npf_tableset_insert(tblset, t2); fail |= !check_ok(error == 0); /* Table ID 3, using a CDB. */ cdb = malloc(size, M_TEMP, M_WAITOK); memcpy(cdb, blob, size); t3 = npf_table_create(CDB_TID, 2, NPF_TABLE_CDB, cdb, size); fail |= !(t3 != NULL); error = npf_tableset_insert(tblset, t3); fail |= !check_ok(error == 0); /* Attempt to match non-existing entries - should fail. */ addr->word32[0] = inet_addr(ip_list[0]); alen = sizeof(struct in_addr); t = npf_tableset_getbyname(tblset, HASH_TID); error = npf_table_lookup(t, alen, addr); fail |= !check_ok(error != 0); t = npf_tableset_getbyname(tblset, TREE_TID); error = npf_table_lookup(t, alen, addr); fail |= !check_ok(error != 0); /* Fill both tables with IP addresses. */ fail |= npf_table_test_fill4(tblset, addr); /* Attempt to add duplicates - should fail. */ addr->word32[0] = inet_addr(ip_list[0]); alen = sizeof(struct in_addr); t = npf_tableset_getbyname(tblset, HASH_TID); error = npf_table_insert(t, alen, addr, nm); fail |= !check_ok(error != 0); t = npf_tableset_getbyname(tblset, TREE_TID); error = npf_table_insert(t, alen, addr, nm); fail |= !check_ok(error != 0); /* Match (validate) each IP entry. */ for (i = 0; i < __arraycount(ip_list); i++) { addr->word32[0] = inet_addr(ip_list[i]); t = npf_tableset_getbyname(tblset, HASH_TID); error = npf_table_lookup(t, alen, addr); fail |= !check_ok(error == 0); t = npf_tableset_getbyname(tblset, TREE_TID); error = npf_table_lookup(t, alen, addr); fail |= !check_ok(error == 0); } /* IPv6 addresses. */ memcpy(addr, ip6_list[0], sizeof(ip6_list[0])); alen = sizeof(struct in6_addr); t = npf_tableset_getbyname(tblset, HASH_TID); error = npf_table_insert(t, alen, addr, nm); fail |= !check_ok(error == 0); error = npf_table_lookup(t, alen, addr); fail |= !check_ok(error == 0); error = npf_table_remove(t, alen, addr, nm); fail |= !check_ok(error == 0); t = npf_tableset_getbyname(tblset, TREE_TID); error = npf_table_insert(t, alen, addr, nm); fail |= !check_ok(error == 0); error = npf_table_lookup(t, alen, addr); fail |= !check_ok(error == 0); error = npf_table_remove(t, alen, addr, nm); fail |= !check_ok(error == 0); /* * Masking: 96, 32, 127. */ memcpy(addr, ip6_list[1], sizeof(ip6_list[1])); error = npf_table_insert(t, alen, addr, 96); fail |= !check_ok(error == 0); memcpy(addr, ip6_list[0], sizeof(ip6_list[0])); error = npf_table_lookup(t, alen, addr); fail |= !check_ok(error == 0); memcpy(addr, ip6_list[1], sizeof(ip6_list[1])); error = npf_table_remove(t, alen, addr, 96); fail |= !check_ok(error == 0); memcpy(addr, ip6_list[2], sizeof(ip6_list[2])); error = npf_table_insert(t, alen, addr, 32); fail |= !check_ok(error == 0); memcpy(addr, ip6_list[0], sizeof(ip6_list[0])); error = npf_table_lookup(t, alen, addr); fail |= !check_ok(error == 0); memcpy(addr, ip6_list[2], sizeof(ip6_list[2])); error = npf_table_remove(t, alen, addr, 32); fail |= !check_ok(error == 0); memcpy(addr, ip6_list[3], sizeof(ip6_list[3])); error = npf_table_insert(t, alen, addr, 126); fail |= !check_ok(error == 0); memcpy(addr, ip6_list[0], sizeof(ip6_list[0])); error = npf_table_lookup(t, alen, addr); fail |= !check_ok(error != 0); memcpy(addr, ip6_list[3], sizeof(ip6_list[3])); error = npf_table_remove(t, alen, addr, 126); fail |= !check_ok(error == 0); alen = sizeof(struct in_addr); /* Remove all IPv4 entries. */ for (i = 0; i < __arraycount(ip_list); i++) { addr->word32[0] = inet_addr(ip_list[i]); t = npf_tableset_getbyname(tblset, HASH_TID); error = npf_table_remove(t, alen, addr, nm); fail |= !check_ok(error == 0); t = npf_tableset_getbyname(tblset, TREE_TID); error = npf_table_remove(t, alen, addr, nm); fail |= !check_ok(error == 0); } /* Test CDB. */ addr->word32[0] = inet_addr(ip_list[0]); alen = sizeof(struct in_addr); error = npf_table_lookup(t3, alen, addr); fail |= !check_ok(error == 0); for (i = 1; i < __arraycount(ip_list) - 1; i++) { addr->word32[0] = inet_addr(ip_list[i]); alen = sizeof(struct in_addr); error = npf_table_lookup(t3, alen, addr); fail |= !check_ok(error != 0); } npf_tableset_destroy(tblset); return !fail; }