38#define ADDRESS_BYTES (uint8_t)16
39#define NETMASK_MAX (uint8_t)128
41#define RADIX_TREE_TYPE SCRadix6Tree
42#define RADIX_NODE_TYPE SCRadix6Node
43#define RADIX_TREE_COMPARE_CALLBACK SCRadix6TreeCompareFunc
44#define RADIX_CONFIG_TYPE SCRadix6Config
46static void PrintUserdata(
SCRadix6Node *node,
void (*PrintData)(
void *));
48static inline void AddNetmaskToMasks(
SCRadix6Node *node,
int netmask)
50 uint8_t *masks = node->
masks;
51 masks[netmask / 8] |= 1 << (netmask % 8);
54static inline void RemoveNetmaskFromMasks(
SCRadix6Node *node,
int netmask)
56 uint8_t *masks = node->
masks;
57 masks[netmask / 8] &= ~(1 << (netmask % 8));
62 for (
size_t i = 0; i <
sizeof(
src->masks); i++) {
63 dst->masks[i] |=
src->masks[i];
67static inline bool NetmasksEmpty(
const SCRadix6Node *node)
69 for (
size_t i = 0; i <
sizeof(node->
masks); i++) {
70 if (node->
masks[i] != 0) {
77static inline bool NetmaskEqualsMask(
const SCRadix6Node *node,
int netmask)
79 size_t b = netmask / 8;
81 for (
size_t i = 0; i <
sizeof(node->
masks); i++) {
82 if (i != b && node->
masks[i] != 0)
84 else if (node->
masks[i] != (1 << (netmask % 8)))
90static inline bool NetmaskIssetInMasks(
const SCRadix6Node *node,
int netmask)
92 return ((node->
masks[netmask / 8] & 1 << (netmask % 8)) != 0);
97 const int differ_bit = inter_node->
bit;
98 uint8_t rem[
sizeof(node->
masks)];
99 memset(rem, 0,
sizeof(rem));
106 if (NetmaskIssetInMasks(node,
m))
107 rem[
m / 8] |= 1 << (
m % 8);
111 AddNetmasksFromNode(inter_node, node);
113 for (
size_t i = 0; i <
sizeof(inter_node->
masks); i++) {
114 inter_node->
masks[i] &= ~rem[i];
117 memcpy(node->
masks, rem,
sizeof(node->
masks));
126static void PrintNodeInfo(
SCRadix6Node *node,
int level,
void (*PrintData)(
void *))
130 for (
int i = 0; i < level; i++)
133 printf(
"%d [", node->
bit);
135 if (NetmasksEmpty(node)) {
139 if (NetmaskIssetInMasks(node, i)) {
140 printf(
"%s%d", x ?
", " :
"", i);
150 printf(
"%s)\t%p", addr, node);
151 PrintUserdata(node, PrintData);
154 printf(
"no prefix) %p\n", node);
162 const SCRadix6Tree *tree,
const uint8_t *key,
void **user_data)
164 return FindExactMatch(tree, key, user_data);
168 const SCRadix6Tree *tree,
const uint8_t *key,
const uint8_t netmask,
void **user_data)
170 return FindNetblock(tree, key, netmask, user_data);
174 const SCRadix6Tree *tree,
const uint8_t *key,
void **user_data)
176 return FindBestMatch(tree, key, user_data);
180 const SCRadix6Tree *tree,
const uint8_t *key,
void **user_data, uint8_t *out_netmask)
182 return FindBestMatch2(tree, key, user_data, out_netmask);
199 return AddKey(tree, config, key_stream, 128, user,
false);
215 const uint8_t *key_stream, uint8_t netmask,
void *user)
217 return AddKey(tree, config, key_stream, netmask, user,
false);
220#if defined(DEBUG_VALIDATION) || defined(UNITTESTS)
221static void SCRadix6ValidateIPv6Key(uint8_t *key,
const uint8_t netmask)
227 memset(&mask, 0,
sizeof(mask));
228 struct in6_addr mask6;
230 memcpy(&mask, &mask6.s6_addr,
sizeof(mask));
233 masked[0] =
address[0] & mask[0];
234 masked[1] =
address[1] & mask[1];
235 masked[2] =
address[2] & mask[2];
236 masked[3] =
address[3] & mask[3];
238 if (memcmp(masked,
address,
sizeof(masked)) != 0) {
239 char ostr[64], nstr[64];
241 PrintInet(AF_INET6, (
void *)&masked, nstr,
sizeof(nstr));
242 SCLogNotice(
"input %s/%u != expected %s/%u", ostr, netmask, nstr, netmask);
265 uint8_t netmask = 128;
266 char ip_str[80] =
"";
267 char *mask_str = NULL;
268 struct in6_addr addr;
274 if (NULL != (mask_str = strchr(ip_str,
'/'))) {
275 *(mask_str++) =
'\0';
278 if (strchr(mask_str,
'.') != NULL) {
288 netmask = (uint8_t)cidr;
292 if (inet_pton(AF_INET6, ip_str, &addr) <= 0) {
297 if (netmask != 128) {
298 struct in6_addr maddr;
299 struct in6_addr mask6, check;
301 memcpy(&check, &addr,
sizeof(check));
303 for (
int i = 0; i < 16; i++) {
304 maddr.s6_addr[i] = addr.s6_addr[i] & mask6.s6_addr[i];
305 diff |= (maddr.s6_addr[i] != check.s6_addr[i]);
309 PrintInet(AF_INET6, (
void *)&maddr.s6_addr, nstr,
sizeof(nstr));
311 memcpy(addr.s6_addr, maddr.s6_addr, 16);
312#if defined(DEBUG_VALIDATION) || defined(UNITTESTS)
313 SCRadix6ValidateIPv6Key((uint8_t *)&addr.s6_addr, netmask);
318 if (AddKey(tree, config, (uint8_t *)&addr.s6_addr, netmask, user,
true) == NULL) {
338 RemoveKey(tree, config, key_stream, 128);
350 const uint8_t *key_stream, uint8_t netmask)
352 RemoveKey(tree, config, key_stream, netmask);
357 PrintTree(tree, config);
368 TreeRelease(tree, config);
371static void PrintUserdata(
SCRadix6Node *node,
void (*PrintData)(
void *))
373 if (PrintData != NULL) {
383 printf(
" [%d], ", ud->
netmask);
389static int SCRadix6ForEachNodeSub(
396 if (Callback(node, ud->
user, ud->
netmask, data) < 0)
401 if (SCRadix6ForEachNodeSub(node->
left, Callback, data) < 0)
405 if (SCRadix6ForEachNodeSub(node->
right, Callback, data) < 0)
413 if (tree->
head == NULL)
415 return SCRadix6ForEachNodeSub(tree->
head, Callback, data);
421 return CompareTrees(t1, t2, Callback);
430#define GET_IPV6(str) \
431 SCLogDebug("setting up %s", (str)); \
432 memset(&(sa), 0, sizeof((sa))); \
433 FAIL_IF(inet_pton(AF_INET6, (str), &(sa).sin6_addr) <= 0);
435#define ADD_IPV6(str) \
437 SCRadix6AddKeyIPV6(&tree, &ut_ip_radix6_config, (uint8_t *)&(sa).sin6_addr, NULL);
439#define REM_IPV6(str) \
441 SCRadix6RemoveKeyIPV6(&tree, &ut_ip_radix6_config, (uint8_t *)&(sa).sin6_addr);
443#define ADD_IPV6_MASK(str, cidr) \
445 SCRadix6AddKeyIPV6Netblock( \
446 &tree, &ut_ip_radix6_config, (uint8_t *)&(sa).sin6_addr, (cidr), NULL);
448#define REM_IPV6_MASK(str, cidr) \
450 SCRadix6RemoveKeyIPV6Netblock(&tree, &ut_ip_radix6_config, (uint8_t *)&(sa).sin6_addr, (cidr));
452static int SCRadix6TestIPV6Insertion03(
void)
454 struct sockaddr_in6 sa;
503static int SCRadix6TestIPV6Removal04(
void)
505 struct sockaddr_in6 sa;
546static int SCRadix6TestIPV6NetblockInsertion09(
void)
548 struct sockaddr_in6 sa;
588static int SCRadix6TestIPV6NetblockInsertion10(
void)
591 struct sockaddr_in6 sa;
605 &tree, &ut_ip_radix6_config, (uint8_t *)&sa.sin6_addr, 112, NULL);
608 node[1] =
SCRadix6AddKeyIPV6(&tree, &ut_ip_radix6_config, (uint8_t *)&sa.sin6_addr, NULL);
640static int SCRadix6TestIPV6NetblockInsertion11(
void)
642 struct sockaddr_in6 sa;
660 &tree, &ut_ip_radix6_config, (uint8_t *)&sa.sin6_addr, 0, NULL);
723static int SCRadix6TestIPV6NetblockInsertion12(
void)
725 struct sockaddr_in6 sa;
740 &tree, &ut_ip_radix6_config, (uint8_t *)&sa.sin6_addr, 96, NULL);
744 node[1] =
SCRadix6AddKeyIPV6(&tree, &ut_ip_radix6_config, (uint8_t *)&sa.sin6_addr, NULL);
783static int SCRadix6TestIPV6NetBlocksAndBestSearch16(
void)
785 struct sockaddr_in6 sa;
789 for (uint32_t i = 0; i <= 128; i++) {
790 uint32_t *user =
SCMalloc(
sizeof(uint32_t));
794 void *user_data = NULL;
798 FAIL_IF(*((uint32_t *)user_data) != i);
809static int SCRadix6TestIPV6NetBlocksAndBestSearch19(
void)
811 struct sockaddr_in6 sa;
812 void *user_data = NULL;
816 uint32_t *user =
SCMalloc(
sizeof(uint32_t));
825 FAIL_IF(*((uint32_t *)user_data) != 100);
838 FAIL_IF(*((uint32_t *)user_data) != 200);
845 FAIL_IF(*((uint32_t *)user_data) != 100);
858 FAIL_IF(*((uint32_t *)user_data) != 300);
865 FAIL_IF(*((uint32_t *)user_data) != 300);
872 FAIL_IF(*((uint32_t *)user_data) != 200);
879 FAIL_IF(*((uint32_t *)user_data) != 100);
891static int SCRadix6TestIPV6NetblockInsertion25(
void)
893 struct sockaddr_in6 sa;
907static int SCRadix6TestIPV6NetblockInsertion26(
void)
910 struct sockaddr_in6 sa;
938 FAIL_IF_NOT(strcmp((
char *)retptr,
"Hello3") == 0);
949 UtRegisterTest(
"SCRadix6TestIPV6Insertion03", SCRadix6TestIPV6Insertion03);
950 UtRegisterTest(
"SCRadix6TestIPV6Removal04", SCRadix6TestIPV6Removal04);
951 UtRegisterTest(
"SCRadix6TestIPV6NetblockInsertion09", SCRadix6TestIPV6NetblockInsertion09);
952 UtRegisterTest(
"SCRadix6TestIPV6NetblockInsertion10", SCRadix6TestIPV6NetblockInsertion10);
953 UtRegisterTest(
"SCRadix6TestIPV6NetblockInsertion11", SCRadix6TestIPV6NetblockInsertion11);
954 UtRegisterTest(
"SCRadix6TestIPV6NetblockInsertion12", SCRadix6TestIPV6NetblockInsertion12);
956 "SCRadix6TestIPV6NetBlocksAndBestSearch16", SCRadix6TestIPV6NetBlocksAndBestSearch16);
958 "SCRadix6TestIPV6NetBlocksAndBestSearch19", SCRadix6TestIPV6NetBlocksAndBestSearch19);
959 UtRegisterTest(
"SCRadix6TestIPV6NetblockInsertion25", SCRadix6TestIPV6NetblockInsertion25);
960 UtRegisterTest(
"SCRadix6TestIPV6NetblockInsertion26", SCRadix6TestIPV6NetblockInsertion26);
#define FAIL_IF_NULL(expr)
Fail a test if expression evaluates to NULL.
void UtRegisterTest(const char *name, int(*TestFn)(void))
Register unit test.
#define FAIL_IF_NOT(expr)
Fail a test if expression evaluates to false.
#define PASS
Pass the test.
#define FAIL_IF(expr)
Fail a test if expression evaluates to true.
#define FAIL_IF_NOT_NULL(expr)
Fail a test if expression evaluates to non-NULL.
Structure that hold the user data and the netmask associated with it.
struct RadixUserData * next
Structure for the node in the radix tree.
struct SCRadix6Node_ * left
struct RadixUserData * user_data
uint8_t prefix_stream[16]
struct SCRadix6Node_ * right
Structure for the radix tree.
size_t strlcpy(char *dst, const char *src, size_t siz)
int StringParseU8RangeCheck(uint8_t *res, int base, size_t len, const char *str, uint8_t min, uint8_t max)
void CIDRGetIPv6(int cidr, struct in6_addr *in6)
Creates a cidr ipv6 netblock, based on the cidr netblock value.
#define SCLogNotice(...)
Macro used to log NOTICE messages.
#define SCLogWarning(...)
Macro used to log WARNING messages.
thread_local SCError sc_errno
const char * PrintInet(int af, const void *src, char *dst, socklen_t size)
SCRadix6Node * SCRadix6TreeFindBestMatch(const SCRadix6Tree *tree, const uint8_t *key, void **user_data)
int SCRadix6ForEachNode(const SCRadix6Tree *tree, SCRadix6ForEachNodeFunc Callback, void *data)
SCRadix6Node * SCRadix6TreeFindNetblock(const SCRadix6Tree *tree, const uint8_t *key, const uint8_t netmask, void **user_data)
SCRadix6Node * SCRadix6AddKeyIPV6Netblock(SCRadix6Tree *tree, const SCRadix6Config *config, const uint8_t *key_stream, uint8_t netmask, void *user)
Adds a new IPV6 netblock to the Radix6 tree.
SCRadix6Node * SCRadix6TreeFindBestMatch2(const SCRadix6Tree *tree, const uint8_t *key, void **user_data, uint8_t *out_netmask)
SCRadix6Tree SCRadix6TreeInitialize(void)
void SCRadix6PrintTree(SCRadix6Tree *tree, const SCRadix6Config *config)
void SCRadix6RegisterTests(void)
void SCRadix6RemoveKeyIPV6Netblock(SCRadix6Tree *tree, const SCRadix6Config *config, const uint8_t *key_stream, uint8_t netmask)
Removes an IPV6 address netblock key from the tree.
void SCRadix6TreeRelease(SCRadix6Tree *tree, const SCRadix6Config *config)
#define ADD_IPV6_MASK(str, cidr)
bool SCRadix6AddKeyIPV6String(SCRadix6Tree *tree, const SCRadix6Config *config, const char *str, void *user)
Adds a new IPV6/netblock to the Radix6 tree from a string.
SCRadix6Node * SCRadix6TreeFindExactMatch(const SCRadix6Tree *tree, const uint8_t *key, void **user_data)
#define REM_IPV6_MASK(str, cidr)
bool SCRadix6CompareTrees(const SCRadix6Tree *t1, const SCRadix6Tree *t2, SCRadix6TreeCompareFunc Callback)
void SCRadix6RemoveKeyIPV6(SCRadix6Tree *tree, const SCRadix6Config *config, const uint8_t *key_stream)
Removes an IPV6 address key(not a netblock) from the Radix6 tree. Instead of using this function,...
SCRadix6Node * SCRadix6AddKeyIPV6(SCRadix6Tree *tree, const SCRadix6Config *config, const uint8_t *key_stream, void *user)
Adds a new IPV6 address to the Radix6 tree.
int(* SCRadix6ForEachNodeFunc)(const SCRadix6Node *node, void *user_data, const uint8_t netmask, void *data)
#define SC_RADIX6_TREE_INITIALIZER
bool(* SCRadix6TreeCompareFunc)(const void *ud1, const void *ud2)
compare content of 2 user data entries
#define DEBUG_VALIDATE_BUG_ON(exp)