suricata
util-radix6-tree.c
Go to the documentation of this file.
1/* Copyright (C) 2007-2022 Open Information Security Foundation
2 *
3 * You can copy, redistribute or modify this Program under the terms of
4 * the GNU General Public License version 2 as published by the Free
5 * Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * version 2 along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15 * 02110-1301, USA.
16 */
17
18/**
19 * \file
20 *
21 * \author Victor Julien <victor@inliniac.net>
22 * \author Anoop Saldanha <anoopsaldanha@gmail.com>
23 *
24 * Implementation of radix trees
25 */
26
27#include "suricata-common.h"
28#include "util-debug.h"
29#include "util-error.h"
30#include "util-ip.h"
31#include "util-cidr.h"
32#include "util-unittest.h"
33#include "util-memcmp.h"
34#include "util-print.h"
35#include "util-byte.h"
36#include "util-radix6-tree.h"
37
38#define ADDRESS_BYTES (uint8_t)16
39#define NETMASK_MAX (uint8_t)128
40
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
45
46static void PrintUserdata(SCRadix6Node *node, void (*PrintData)(void *));
47
48static inline void AddNetmaskToMasks(SCRadix6Node *node, int netmask)
49{
50 uint8_t *masks = node->masks;
51 masks[netmask / 8] |= 1 << (netmask % 8);
52}
53
54static inline void RemoveNetmaskFromMasks(SCRadix6Node *node, int netmask)
55{
56 uint8_t *masks = node->masks;
57 masks[netmask / 8] &= ~(1 << (netmask % 8));
58}
59
60static inline void AddNetmasksFromNode(SCRadix6Node *dst, SCRadix6Node *src)
61{
62 for (size_t i = 0; i < sizeof(src->masks); i++) {
63 dst->masks[i] |= src->masks[i];
64 }
65}
66
67static inline bool NetmasksEmpty(const SCRadix6Node *node)
68{
69 for (size_t i = 0; i < sizeof(node->masks); i++) {
70 if (node->masks[i] != 0) {
71 return false;
72 }
73 }
74 return true;
75}
76
77static inline bool NetmaskEqualsMask(const SCRadix6Node *node, int netmask)
78{
79 size_t b = netmask / 8;
80
81 for (size_t i = 0; i < sizeof(node->masks); i++) {
82 if (i != b && node->masks[i] != 0)
83 return false;
84 else if (node->masks[i] != (1 << (netmask % 8)))
85 return false;
86 }
87 return true;
88}
89
90static inline bool NetmaskIssetInMasks(const SCRadix6Node *node, int netmask)
91{
92 return ((node->masks[netmask / 8] & 1 << (netmask % 8)) != 0);
93}
94
95static inline void ProcessInternode(SCRadix6Node *node, SCRadix6Node *inter_node)
96{
97 const int differ_bit = inter_node->bit;
98 uint8_t rem[sizeof(node->masks)];
99 memset(rem, 0, sizeof(rem));
100
101 for (int x = 0; x <= NETMASK_MAX; x++) {
102 int m = NETMASK_MAX - x;
103 if (m == differ_bit)
104 break;
105 else {
106 if (NetmaskIssetInMasks(node, m))
107 rem[m / 8] |= 1 << (m % 8);
108 }
109 }
110
111 AddNetmasksFromNode(inter_node, node);
112
113 for (size_t i = 0; i < sizeof(inter_node->masks); i++) {
114 inter_node->masks[i] &= ~rem[i];
115 }
116
117 memcpy(node->masks, rem, sizeof(node->masks));
118}
119
120/**
121 * \brief Prints the node information from a Radix6 tree
122 *
123 * \param node Pointer to the Radix6 node whose information has to be printed
124 * \param level Used for indentation purposes
125 */
126static void PrintNodeInfo(SCRadix6Node *node, int level, void (*PrintData)(void *))
127{
128 if (node == NULL)
129 return;
130 for (int i = 0; i < level; i++)
131 printf(" ");
132
133 printf("%d [", node->bit);
134
135 if (NetmasksEmpty(node)) {
136 printf(" - ");
137 } else {
138 for (int i = 0, x = 0; i <= NETMASK_MAX; i++) {
139 if (NetmaskIssetInMasks(node, i)) {
140 printf("%s%d", x ? ", " : "", i);
141 x++;
142 }
143 }
144 }
145 printf("] (");
146
147 if (node->has_prefix) {
148 char addr[46] = "";
149 PrintInet(AF_INET6, &node->prefix_stream, addr, sizeof(addr));
150 printf("%s)\t%p", addr, node);
151 PrintUserdata(node, PrintData);
152 printf("\n");
153 } else {
154 printf("no prefix) %p\n", node);
155 }
156 return;
157}
158
160
162 const SCRadix6Tree *tree, const uint8_t *key, void **user_data)
163{
164 return FindExactMatch(tree, key, user_data);
165}
166
168 const SCRadix6Tree *tree, const uint8_t *key, const uint8_t netmask, void **user_data)
169{
170 return FindNetblock(tree, key, netmask, user_data);
171}
172
174 const SCRadix6Tree *tree, const uint8_t *key, void **user_data)
175{
176 return FindBestMatch(tree, key, user_data);
177}
178
180 const SCRadix6Tree *tree, const uint8_t *key, void **user_data, uint8_t *out_netmask)
181{
182 return FindBestMatch2(tree, key, user_data, out_netmask);
183}
184
185/**
186 * \brief Adds a new IPV6 address to the Radix6 tree
187 *
188 * \param key_stream Data that has to be added to the Radix6 tree. In this case
189 * a pointer to an IPV6 address
190 * \param tree Pointer to the Radix6 tree
191 * \param user Pointer to the user data that has to be associated with the
192 * key
193 *
194 * \retval node Pointer to the newly created node
195 */
197 SCRadix6Tree *tree, const SCRadix6Config *config, const uint8_t *key_stream, void *user)
198{
199 return AddKey(tree, config, key_stream, 128, user, false);
200}
201
202/**
203 * \brief Adds a new IPV6 netblock to the Radix6 tree
204 *
205 * \param key_stream Data that has to be added to the Radix6 tree. In this case
206 * a pointer to an IPV6 netblock
207 * \param tree Pointer to the Radix6 tree
208 * \param user Pointer to the user data that has to be associated with the
209 * key
210 * \param netmask The netmask (cidr) if we are adding a netblock
211 *
212 * \retval node Pointer to the newly created node
213 */
215 const uint8_t *key_stream, uint8_t netmask, void *user)
216{
217 return AddKey(tree, config, key_stream, netmask, user, false);
218}
219
220#if defined(DEBUG_VALIDATION) || defined(UNITTESTS)
221static void SCRadix6ValidateIPv6Key(uint8_t *key, const uint8_t netmask)
222{
223 uint32_t address[4];
224 memcpy(&address, key, sizeof(address));
225
226 uint32_t mask[4];
227 memset(&mask, 0, sizeof(mask));
228 struct in6_addr mask6;
229 CIDRGetIPv6(netmask, &mask6);
230 memcpy(&mask, &mask6.s6_addr, sizeof(mask));
231
232 uint32_t masked[4];
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];
237
238 if (memcmp(masked, address, sizeof(masked)) != 0) {
239 char ostr[64], nstr[64];
240 PrintInet(AF_INET6, (void *)&address, ostr, sizeof(ostr));
241 PrintInet(AF_INET6, (void *)&masked, nstr, sizeof(nstr));
242 SCLogNotice("input %s/%u != expected %s/%u", ostr, netmask, nstr, netmask);
244 }
245}
246#endif
247/**
248 * \brief Adds a new IPV6/netblock to the Radix6 tree from a string
249 *
250 * \param str IPV6 string with optional /cidr netmask
251 * \param tree Pointer to the Radix6 tree
252 * \param user Pointer to the user data that has to be associated with
253 * the key
254 *
255 * \retval bool true if node was added, false otherwise
256 *
257 * If the function returns false, `sc_errno` is set:
258 * - SC_EEXIST: Node already exists
259 * - SC_EINVAL: Parameter value error
260 * - SC_ENOMEM: Memory allocation failed
261 */
263 SCRadix6Tree *tree, const SCRadix6Config *config, const char *str, void *user)
264{
265 uint8_t netmask = 128;
266 char ip_str[80] = ""; /* Max length for full ipv6/cidr string with NUL */
267 char *mask_str = NULL;
268 struct in6_addr addr;
269
270 /* Make a copy of the string so it can be modified */
271 strlcpy(ip_str, str, sizeof(ip_str));
272
273 /* Does it have a mask? */
274 if (NULL != (mask_str = strchr(ip_str, '/'))) {
275 *(mask_str++) = '\0';
276
277 /* Dotted type netmask not valid for ipv6 */
278 if (strchr(mask_str, '.') != NULL) {
280 return false;
281 }
282
283 uint8_t cidr;
284 if (StringParseU8RangeCheck(&cidr, 10, 0, (const char *)mask_str, 0, 128) < 0) {
286 return false;
287 }
288 netmask = (uint8_t)cidr;
289 }
290
291 /* Validate the IP */
292 if (inet_pton(AF_INET6, ip_str, &addr) <= 0) {
294 return false;
295 }
296
297 if (netmask != 128) {
298 struct in6_addr maddr;
299 struct in6_addr mask6, check;
300 CIDRGetIPv6(netmask, &mask6);
301 memcpy(&check, &addr, sizeof(check));
302 bool diff = false;
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]);
306 }
307 if (diff) {
308 char nstr[64];
309 PrintInet(AF_INET6, (void *)&maddr.s6_addr, nstr, sizeof(nstr));
310 SCLogWarning("adding '%s' as '%s/%u'", str, nstr, netmask);
311 memcpy(addr.s6_addr, maddr.s6_addr, 16);
312#if defined(DEBUG_VALIDATION) || defined(UNITTESTS)
313 SCRadix6ValidateIPv6Key((uint8_t *)&addr.s6_addr, netmask);
314#endif
315 }
316 }
317
318 if (AddKey(tree, config, (uint8_t *)&addr.s6_addr, netmask, user, true) == NULL) {
320 return false;
321 }
322 return true;
323}
324
325/**
326 * \brief Removes an IPV6 address key(not a netblock) from the Radix6 tree.
327 * Instead of using this function, we can also used
328 * SCRadix6RemoveKeyIPV6Netblock(), by supplying a netmask value of 32.
329 *
330 * \param key_stream Data that has to be removed from the Radix6 tree. In this
331 * case an IPV6 address
332 * \param tree Pointer to the Radix6 tree from which the key has to be
333 * removed
334 */
336 SCRadix6Tree *tree, const SCRadix6Config *config, const uint8_t *key_stream)
337{
338 RemoveKey(tree, config, key_stream, 128);
339}
340
341/**
342 * \brief Removes an IPV6 address netblock key from the tree.
343 *
344 * \param key_stream Data that has to be removed from the tree. In this
345 * case an IPV6 address with netmask.
346 * \param tree Pointer to the tree from which the key has to be
347 * removed
348 */
350 const uint8_t *key_stream, uint8_t netmask)
351{
352 RemoveKey(tree, config, key_stream, netmask);
353}
354
356{
357 PrintTree(tree, config);
358}
359
365
367{
368 TreeRelease(tree, config);
369}
370
371static void PrintUserdata(SCRadix6Node *node, void (*PrintData)(void *))
372{
373 if (PrintData != NULL) {
374 RadixUserData *ud = node->user_data;
375 while (ud != NULL) {
376 printf("[%d], ", ud->netmask);
377 PrintData(ud->user);
378 ud = ud->next;
379 }
380 } else {
381 RadixUserData *ud = node->user_data;
382 while (ud != NULL) {
383 printf(" [%d], ", ud->netmask);
384 ud = ud->next;
385 }
386 }
387}
388
389static int SCRadix6ForEachNodeSub(
390 const SCRadix6Node *node, SCRadix6ForEachNodeFunc Callback, void *data)
391{
392 BUG_ON(!node);
393
394 /* invoke callback for each stored user data */
395 for (RadixUserData *ud = node->user_data; ud != NULL; ud = ud->next) {
396 if (Callback(node, ud->user, ud->netmask, data) < 0)
397 return -1;
398 }
399
400 if (node->left) {
401 if (SCRadix6ForEachNodeSub(node->left, Callback, data) < 0)
402 return -1;
403 }
404 if (node->right) {
405 if (SCRadix6ForEachNodeSub(node->right, Callback, data) < 0)
406 return -1;
407 }
408 return 0;
409}
410
411int SCRadix6ForEachNode(const SCRadix6Tree *tree, SCRadix6ForEachNodeFunc Callback, void *data)
412{
413 if (tree->head == NULL)
414 return 0;
415 return SCRadix6ForEachNodeSub(tree->head, Callback, data);
416}
417
419 const SCRadix6Tree *t1, const SCRadix6Tree *t2, SCRadix6TreeCompareFunc Callback)
420{
421 return CompareTrees(t1, t2, Callback);
422}
423
424/*------------------------------------Unit_Tests------------------------------*/
425
426#ifdef UNITTESTS
427
428static const SCRadix6Config ut_ip_radix6_config = { NULL, NULL };
429
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);
434
435#define ADD_IPV6(str) \
436 GET_IPV6((str)); \
437 SCRadix6AddKeyIPV6(&tree, &ut_ip_radix6_config, (uint8_t *)&(sa).sin6_addr, NULL);
438
439#define REM_IPV6(str) \
440 GET_IPV6((str)); \
441 SCRadix6RemoveKeyIPV6(&tree, &ut_ip_radix6_config, (uint8_t *)&(sa).sin6_addr);
442
443#define ADD_IPV6_MASK(str, cidr) \
444 GET_IPV6((str)); \
445 SCRadix6AddKeyIPV6Netblock( \
446 &tree, &ut_ip_radix6_config, (uint8_t *)&(sa).sin6_addr, (cidr), NULL);
447
448#define REM_IPV6_MASK(str, cidr) \
449 GET_IPV6((str)); \
450 SCRadix6RemoveKeyIPV6Netblock(&tree, &ut_ip_radix6_config, (uint8_t *)&(sa).sin6_addr, (cidr));
451
452static int SCRadix6TestIPV6Insertion03(void)
453{
454 struct sockaddr_in6 sa;
456
457 ADD_IPV6("2000:1::1");
458 ADD_IPV6("2000:1::2");
459 ADD_IPV6("2000:0::3");
460 ADD_IPV6("2000:0::4");
461 ADD_IPV6("2000:0::4");
462
463 /* test for the existance of a key */
464 GET_IPV6("2000:1::6");
465 FAIL_IF_NOT(SCRadix6TreeFindExactMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) == NULL);
466
467 /* test for the existance of a key */
468 GET_IPV6("2000:0::4");
469 FAIL_IF_NOT(SCRadix6TreeFindExactMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) != NULL);
470
471 /* continue adding keys */
472 ADD_IPV6("2000:0::2");
473 ADD_IPV6("2000:1::5");
474 ADD_IPV6("2000:1::18");
475
476 /* test the existence of keys */
477 GET_IPV6("2000:1::3");
478 FAIL_IF_NOT(SCRadix6TreeFindExactMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) == NULL);
479 GET_IPV6("2001:1:2:3::62");
480 FAIL_IF_NOT(SCRadix6TreeFindExactMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) == NULL);
481
482 GET_IPV6("2000:1::1");
483 FAIL_IF_NOT(SCRadix6TreeFindExactMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) != NULL);
484 GET_IPV6("2000:1::5");
485 FAIL_IF_NOT(SCRadix6TreeFindExactMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) != NULL);
486 GET_IPV6("2000:1::2");
487 FAIL_IF_NOT(SCRadix6TreeFindExactMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) != NULL);
488
489 GET_IPV6("2000:0::3");
490 FAIL_IF_NOT(SCRadix6TreeFindExactMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) != NULL);
491 GET_IPV6("2000:0::4");
492 FAIL_IF_NOT(SCRadix6TreeFindExactMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) != NULL);
493 GET_IPV6("2000:0::2");
494 FAIL_IF_NOT(SCRadix6TreeFindExactMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) != NULL);
495 GET_IPV6("2000:1::18");
496 FAIL_IF_NOT(SCRadix6TreeFindExactMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) != NULL);
497
498 SCRadix6TreeRelease(&tree, &ut_ip_radix6_config);
499
500 PASS;
501}
502
503static int SCRadix6TestIPV6Removal04(void)
504{
505 struct sockaddr_in6 sa;
507
508 /* add the keys */
509 ADD_IPV6("2000:1::1");
510 ADD_IPV6("2000:1::2");
511 ADD_IPV6("2000:0::3");
512 ADD_IPV6("2000:0::4");
513 ADD_IPV6("1000:1::2");
514 ADD_IPV6("2000:1::5");
515 ADD_IPV6("2000:1::18");
516
517 /* remove the keys from the tree */
518 REM_IPV6("2000:1::1");
519 REM_IPV6("2000:0::3");
520 REM_IPV6("2000:0::4");
521 REM_IPV6("2000:1::18");
522
523 GET_IPV6("2000:0::1");
524 FAIL_IF_NOT(SCRadix6TreeFindExactMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) == NULL);
525 GET_IPV6("2000:1::2");
526 FAIL_IF_NOT(SCRadix6TreeFindExactMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) != NULL);
527
528 REM_IPV6("2000:0::3");
529 REM_IPV6("1000:1::2");
530
531 GET_IPV6("2000:1::5");
532 FAIL_IF_NOT(SCRadix6TreeFindExactMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) != NULL);
533 GET_IPV6("2000:1::2");
534 FAIL_IF_NOT(SCRadix6TreeFindExactMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) != NULL);
535
536 REM_IPV6("2000:1::2");
537 REM_IPV6("2000:1::5");
538
539 FAIL_IF_NOT_NULL(tree.head);
540
541 SCRadix6TreeRelease(&tree, &ut_ip_radix6_config);
542
543 PASS;
544}
545
546static int SCRadix6TestIPV6NetblockInsertion09(void)
547{
548 struct sockaddr_in6 sa;
550
551 /* add the keys */
552 ADD_IPV6("2000::1:1");
553 ADD_IPV6("2000::1:2");
554 ADD_IPV6("2000::0:3");
555 ADD_IPV6("2000::0:4");
556 ADD_IPV6("1000::1:2");
557 ADD_IPV6("2000::1:5");
558 ADD_IPV6("2000::1:18");
559
560 ADD_IPV6_MASK("2000::", 16);
561 ADD_IPV6_MASK("2000::192:171:128:0", 128 - 8);
562 ADD_IPV6_MASK("2000::192:171:192:0", 128 - 14);
563 ADD_IPV6_MASK("2000::192:175:0:0", 128 - 16);
564
565 /* test for the existance of a key */
566 GET_IPV6("2000:1::6");
567 FAIL_IF_NOT(SCRadix6TreeFindExactMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) == NULL);
568 GET_IPV6("2000::192:170:1:6");
569 FAIL_IF_NOT(SCRadix6TreeFindExactMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) == NULL);
570 GET_IPV6("2000::192:171:128:145");
571 FAIL_IF_NOT(SCRadix6TreeFindBestMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) != NULL);
572 GET_IPV6("2000::192:171:64:6");
573 FAIL_IF_NOT(SCRadix6TreeFindExactMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) == NULL);
574 GET_IPV6("2000::192:171:191:6");
575 FAIL_IF_NOT(SCRadix6TreeFindExactMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) == NULL);
576 GET_IPV6("2000::192:171:224:6");
577 FAIL_IF_NOT(SCRadix6TreeFindBestMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) != NULL);
578 GET_IPV6("2000::192:171:224:6");
579 FAIL_IF_NOT(SCRadix6TreeFindExactMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) == NULL);
580 GET_IPV6("2000::192:175:224:6");
581 FAIL_IF_NOT(SCRadix6TreeFindBestMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) != NULL);
582
583 SCRadix6TreeRelease(&tree, &ut_ip_radix6_config);
584
585 PASS;
586}
587
588static int SCRadix6TestIPV6NetblockInsertion10(void)
589{
590 SCRadix6Node *node[2];
591 struct sockaddr_in6 sa;
593
594 /* add the keys */
595 ADD_IPV6_MASK("2000::253:192:0:0", 112);
596 ADD_IPV6_MASK("2000::253:192:235:0", 112);
597 ADD_IPV6_MASK("2000::192:167:0:0", 112);
598 ADD_IPV6("2000:0::4");
599 ADD_IPV6_MASK("2000::220:168:0:0", 112);
600 ADD_IPV6("2000::253:224:1:5");
601 ADD_IPV6_MASK("2000::192:168:0:0", 112);
602
603 GET_IPV6("2000::192:171:128:0");
605 &tree, &ut_ip_radix6_config, (uint8_t *)&sa.sin6_addr, 112, NULL);
606
607 GET_IPV6("2000::192:171:128:45");
608 node[1] = SCRadix6AddKeyIPV6(&tree, &ut_ip_radix6_config, (uint8_t *)&sa.sin6_addr, NULL);
609
610 ADD_IPV6_MASK("2000::192:171:0:0", 110);
611 ADD_IPV6_MASK("2000::192:175:0:0", 112);
612
613 /* test for the existance of a key */
614 GET_IPV6("2000::192:171:128:53");
615 FAIL_IF_NOT(SCRadix6TreeFindBestMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) == node[0]);
616
617 GET_IPV6("2000::192:171:128:45");
618 FAIL_IF_NOT(SCRadix6TreeFindExactMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) == node[1]);
619
620 GET_IPV6("2000::192:171:128:45");
621 FAIL_IF_NOT(SCRadix6TreeFindBestMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) == node[1]);
622
623 GET_IPV6("2000::192:171:128:78");
624 FAIL_IF_NOT(SCRadix6TreeFindBestMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) == node[0]);
625
626 REM_IPV6_MASK("2000::192:171:128:0", 112);
627
628 GET_IPV6("2000::192:171:128:78");
629 SCRadix6Node *n = SCRadix6TreeFindBestMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL);
630 SCLogNotice("n %p", n);
631 FAIL_IF_NOT(SCRadix6TreeFindBestMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) == NULL);
632 GET_IPV6("2000::192:171:127:78");
633 FAIL_IF_NOT(SCRadix6TreeFindBestMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) == NULL);
634
635 SCRadix6TreeRelease(&tree, &ut_ip_radix6_config);
636
637 PASS;
638}
639
640static int SCRadix6TestIPV6NetblockInsertion11(void)
641{
642 struct sockaddr_in6 sa;
644
645 /* add the keys */
646 ADD_IPV6_MASK("2000::253:192:0:0", 96);
647 ADD_IPV6_MASK("2000::253:192:235:0", 112);
648 ADD_IPV6_MASK("2000::192:167:0:0", 96);
649 ADD_IPV6("2000:0::4");
650 ADD_IPV6_MASK("2000::220:168:0:0", 96);
651 ADD_IPV6("2000::253:224:1:5");
652 ADD_IPV6_MASK("2000::192:168:0:0", 96);
653 ADD_IPV6_MASK("2000::192:171:128:0", 112);
654 ADD_IPV6("2000::192:171:128:45");
655 ADD_IPV6_MASK("2000::192:171:0:0", 112);
656 ADD_IPV6_MASK("2000::192:175:0:0", 96);
657
658 GET_IPV6("::");
660 &tree, &ut_ip_radix6_config, (uint8_t *)&sa.sin6_addr, 0, NULL);
661 FAIL_IF_NULL(node);
662
663 /* test for the existance of a key */
664 GET_IPV6("2000::192:171:128:53");
665 FAIL_IF_NOT(SCRadix6TreeFindBestMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) != NULL);
666
667 GET_IPV6("2000::192:171:128:45");
668 FAIL_IF_NOT(SCRadix6TreeFindBestMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) != NULL);
669
670 GET_IPV6("2000::192:171:128:78");
671 FAIL_IF_NOT(SCRadix6TreeFindBestMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) != NULL);
672
673 GET_IPV6("2000::192:171:127:78");
674 FAIL_IF_NOT(SCRadix6TreeFindBestMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) == node);
675
676 GET_IPV6("2000::1:1:1:1");
677 FAIL_IF_NOT(SCRadix6TreeFindBestMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) == node);
678
679 GET_IPV6("2000::192:255:254:25");
680 FAIL_IF_NOT(SCRadix6TreeFindBestMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) == node);
681
682 GET_IPV6("2000::169:255:254:25");
683 FAIL_IF_NOT(SCRadix6TreeFindBestMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) == node);
684
685 GET_IPV6("::");
686 FAIL_IF_NOT(SCRadix6TreeFindBestMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) == node);
687
688 GET_IPV6("2000::253:224:1:5");
689 FAIL_IF_NOT(SCRadix6TreeFindExactMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) != NULL);
690 FAIL_IF_NOT(SCRadix6TreeFindExactMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) != node);
691
692 GET_IPV6("2000::245:63:62:121");
693 FAIL_IF_NOT(SCRadix6TreeFindBestMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) != NULL);
694 FAIL_IF_NOT(SCRadix6TreeFindBestMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) == node);
695
696 GET_IPV6("2000::253:224:1:6");
697 FAIL_IF_NOT(SCRadix6TreeFindBestMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) != NULL);
698 FAIL_IF_NOT(SCRadix6TreeFindBestMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) == node);
699
700 /* remove node 0.0.0.0 */
701 REM_IPV6_MASK("::", 0);
702
703 GET_IPV6("2000::253:224:1:6");
704 FAIL_IF_NOT(SCRadix6TreeFindBestMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) == NULL);
705 GET_IPV6("2000::192:171:127:78");
706 FAIL_IF_NOT(SCRadix6TreeFindBestMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) == NULL);
707 GET_IPV6("2000::1:1:1:1");
708 FAIL_IF_NOT(SCRadix6TreeFindBestMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) == NULL);
709
710 GET_IPV6("2000::192:255:254:25");
711 FAIL_IF_NOT(SCRadix6TreeFindBestMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) == NULL);
712 GET_IPV6("2000::169:255:254:25");
713 FAIL_IF_NOT(SCRadix6TreeFindBestMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) == NULL);
714
715 GET_IPV6("::");
716 FAIL_IF_NOT(SCRadix6TreeFindBestMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) == NULL);
717
718 SCRadix6TreeRelease(&tree, &ut_ip_radix6_config);
719
720 PASS;
721}
722
723static int SCRadix6TestIPV6NetblockInsertion12(void)
724{
725 struct sockaddr_in6 sa;
726 SCRadix6Node *node[2];
728
729 /* add the keys */
730 ADD_IPV6_MASK("2000::253:192:0:0", 96);
731 ADD_IPV6_MASK("2000::253:192:235:0", 112);
732 ADD_IPV6_MASK("2000::192:167:0:0", 96);
733 ADD_IPV6("2000:0::4");
734 ADD_IPV6_MASK("2000::220:168:0:0", 96);
735 ADD_IPV6("2000::253:224:1:5");
736 ADD_IPV6_MASK("2000::192:168:0:0", 96);
737
738 GET_IPV6("2000::192:171:128:0");
740 &tree, &ut_ip_radix6_config, (uint8_t *)&sa.sin6_addr, 96, NULL);
741 FAIL_IF_NULL(node[0]);
742
743 GET_IPV6("2000::192:171:128:45");
744 node[1] = SCRadix6AddKeyIPV6(&tree, &ut_ip_radix6_config, (uint8_t *)&sa.sin6_addr, NULL);
745 FAIL_IF_NULL(node[1]);
746
747 ADD_IPV6_MASK("2000::192:171:0:0", 96);
748 ADD_IPV6_MASK("2000::225:175:21:228", 128);
749
750 /* test for the existance of a key */
751 GET_IPV6("2000::192:171:128:53");
752 FAIL_IF_NOT(SCRadix6TreeFindBestMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) == node[0]);
753 FAIL_IF_NOT(SCRadix6TreeFindExactMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) == NULL);
754
755 GET_IPV6("2000::192:171:128:45");
756 FAIL_IF_NOT(SCRadix6TreeFindExactMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) == node[1]);
757 FAIL_IF_NOT(SCRadix6TreeFindBestMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) == node[1]);
758
759 GET_IPV6("2000::192:171:128:78");
760 FAIL_IF_NOT(SCRadix6TreeFindBestMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) == node[0]);
761 FAIL_IF_NOT(SCRadix6TreeFindExactMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) == NULL);
762
763 GET_IPV6("2000::225:175:21:228");
764 FAIL_IF_NOT(SCRadix6TreeFindExactMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) != NULL);
765
766 GET_IPV6("2000::225:175:21:224");
767 FAIL_IF_NOT(SCRadix6TreeFindExactMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) == NULL);
768
769 GET_IPV6("2000::225:175:21:229");
770 FAIL_IF_NOT(SCRadix6TreeFindExactMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) == NULL);
771
772 GET_IPV6("2000::225:175:21:230");
773 FAIL_IF_NOT(SCRadix6TreeFindExactMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) == NULL);
774
775 SCRadix6TreeRelease(&tree, &ut_ip_radix6_config);
776 PASS;
777}
778
779/**
780 * \test Check that the best match search works for all the
781 * possible netblocks of a fixed address
782 */
783static int SCRadix6TestIPV6NetBlocksAndBestSearch16(void)
784{
785 struct sockaddr_in6 sa;
787
788 GET_IPV6("2000:1::1");
789 for (uint32_t i = 0; i <= 128; i++) {
790 uint32_t *user = SCMalloc(sizeof(uint32_t));
791 FAIL_IF_NULL(user);
792 *user = i;
793 SCRadix6AddKeyIPV6Netblock(&tree, &ut_ip_radix6_config, (uint8_t *)&sa.sin6_addr, i, user);
794 void *user_data = NULL;
795 SCRadix6Node *node = SCRadix6TreeFindBestMatch(&tree, (uint8_t *)&sa.sin6_addr, &user_data);
796 FAIL_IF_NULL(node);
797 FAIL_IF_NULL(user_data);
798 FAIL_IF(*((uint32_t *)user_data) != i);
799 }
800
801 SCRadix6TreeRelease(&tree, &ut_ip_radix6_config);
802 PASS;
803}
804
805/**
806 * \test Check special combinations of netblocks and addresses
807 * on best search checking the returned userdata
808 */
809static int SCRadix6TestIPV6NetBlocksAndBestSearch19(void)
810{
811 struct sockaddr_in6 sa;
812 void *user_data = NULL;
814
815 GET_IPV6("::");
816 uint32_t *user = SCMalloc(sizeof(uint32_t));
817 FAIL_IF_NULL(user);
818 *user = 100;
819 SCRadix6AddKeyIPV6Netblock(&tree, &ut_ip_radix6_config, (uint8_t *)&sa.sin6_addr, 0, user);
820
821 GET_IPV6("2000:1::15");
822 SCRadix6Node *node = SCRadix6TreeFindBestMatch(&tree, (uint8_t *)&sa.sin6_addr, &user_data);
823 FAIL_IF_NULL(node);
824 FAIL_IF_NULL(user_data);
825 FAIL_IF(*((uint32_t *)user_data) != 100);
826 user_data = NULL;
827
828 GET_IPV6("2000:177::0:0:0");
829 user = SCMalloc(sizeof(uint32_t));
830 FAIL_IF_NULL(user);
831 *user = 200;
832 SCRadix6AddKeyIPV6Netblock(&tree, &ut_ip_radix6_config, (uint8_t *)&sa.sin6_addr, 64, user);
833
834 GET_IPV6("2000:177::168:1:15");
835 node = SCRadix6TreeFindBestMatch(&tree, (uint8_t *)&sa.sin6_addr, &user_data);
836 FAIL_IF_NULL(node);
837 FAIL_IF_NULL(user_data);
838 FAIL_IF(*((uint32_t *)user_data) != 200);
839 user_data = NULL;
840
841 GET_IPV6("2000:178::168:1:15");
842 node = SCRadix6TreeFindBestMatch(&tree, (uint8_t *)&sa.sin6_addr, &user_data);
843 FAIL_IF_NULL(node);
844 FAIL_IF_NULL(user_data);
845 FAIL_IF(*((uint32_t *)user_data) != 100);
846 user_data = NULL;
847
848 GET_IPV6("2000:177::168:0:0");
849 user = SCMalloc(sizeof(uint32_t));
850 FAIL_IF_NULL(user);
851 *user = 300;
852 SCRadix6AddKeyIPV6Netblock(&tree, &ut_ip_radix6_config, (uint8_t *)&sa.sin6_addr, 92, user);
853
854 GET_IPV6("2000:177::168:1:15");
855 node = SCRadix6TreeFindBestMatch(&tree, (uint8_t *)&sa.sin6_addr, &user_data);
856 FAIL_IF_NULL(node);
857 FAIL_IF_NULL(user_data);
858 FAIL_IF(*((uint32_t *)user_data) != 300);
859 user_data = NULL;
860
861 GET_IPV6("2000:177::167:1:15");
862 node = SCRadix6TreeFindBestMatch(&tree, (uint8_t *)&sa.sin6_addr, &user_data);
863 FAIL_IF_NULL(node);
864 FAIL_IF_NULL(user_data);
865 FAIL_IF(*((uint32_t *)user_data) != 300);
866 user_data = NULL;
867
868 GET_IPV6("2000:177::178:1:15");
869 node = SCRadix6TreeFindBestMatch(&tree, (uint8_t *)&sa.sin6_addr, &user_data);
870 FAIL_IF_NULL(node);
871 FAIL_IF_NULL(user_data);
872 FAIL_IF(*((uint32_t *)user_data) != 200);
873 user_data = NULL;
874
875 GET_IPV6("2000:197::178:1:15");
876 node = SCRadix6TreeFindBestMatch(&tree, (uint8_t *)&sa.sin6_addr, &user_data);
877 FAIL_IF_NULL(node);
878 FAIL_IF_NULL(user_data);
879 FAIL_IF(*((uint32_t *)user_data) != 100);
880 user_data = NULL;
881
882 SCRadix6TreeRelease(&tree, &ut_ip_radix6_config);
883 PASS;
884}
885
886/**
887 * \test SCRadix6TestIPV6NetblockInsertion15 insert a node searching on it.
888 * Should always return true but the purposse of the test is to monitor
889 * the memory usage to detect memleaks (there was one on searching)
890 */
891static int SCRadix6TestIPV6NetblockInsertion25(void)
892{
893 struct sockaddr_in6 sa;
895 ADD_IPV6_MASK("2000::192:168:0:0", 16);
896 GET_IPV6("2000::192:168:128:53");
897 FAIL_IF_NOT(SCRadix6TreeFindBestMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) != NULL);
898 SCRadix6TreeRelease(&tree, &ut_ip_radix6_config);
899 PASS;
900}
901
902/**
903 * \test SCRadix6TestIPV6NetblockInsertion26 insert a node searching on it.
904 * Should always return true but the purposse of the test is to monitor
905 * the memory usage to detect memleaks (there was one on searching)
906 */
907static int SCRadix6TestIPV6NetblockInsertion26(void)
908{
909 SCRadix6Node *tmp = NULL;
910 struct sockaddr_in6 sa;
911 const SCRadix6Config ut_ip_radix6_config_26 = { free, NULL };
912
913 char *str = SCStrdup("Hello1");
915
917
918 GET_IPV6("::");
919 SCRadix6AddKeyIPV6Netblock(&tree, &ut_ip_radix6_config_26, (uint8_t *)&sa.sin6_addr, 0, str);
920
921 str = SCStrdup("Hello2");
923
924 GET_IPV6("2000::176:0:0:1");
925 SCRadix6AddKeyIPV6Netblock(&tree, &ut_ip_radix6_config_26, (uint8_t *)&sa.sin6_addr, 5, str);
926
927 str = SCStrdup("Hello3");
929
930 GET_IPV6("::");
931 SCRadix6AddKeyIPV6Netblock(&tree, &ut_ip_radix6_config_26, (uint8_t *)&sa.sin6_addr, 7, str);
932
933 /* test for the existance of a key */
934 void *retptr = NULL;
935 tmp = SCRadix6TreeFindBestMatch(&tree, (uint8_t *)&sa.sin6_addr, &retptr);
936 FAIL_IF_NULL(tmp);
937 FAIL_IF_NULL(retptr);
938 FAIL_IF_NOT(strcmp((char *)retptr, "Hello3") == 0);
939
940 SCRadix6TreeRelease(&tree, &ut_ip_radix6_config_26);
941
942 PASS;
943}
944#endif
945
947{
948#ifdef UNITTESTS
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);
961#endif
962 return;
963}
uint16_t dst
uint16_t src
uint8_t address
Definition decode-ppp.h:0
SCMutex m
Definition flow-hash.h:6
#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]
uint8_t masks[17]
struct SCRadix6Node_ * right
Structure for the radix tree.
SCRadix6Node * head
#define BUG_ON(x)
#define str(s)
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)
Definition util-byte.c:462
void CIDRGetIPv6(int cidr, struct in6_addr *in6)
Creates a cidr ipv6 netblock, based on the cidr netblock value.
Definition util-cidr.c:82
#define SCLogNotice(...)
Macro used to log NOTICE messages.
Definition util-debug.h:243
#define SCLogWarning(...)
Macro used to log WARNING messages.
Definition util-debug.h:255
thread_local SCError sc_errno
Definition util-error.c:31
@ SC_EINVAL
Definition util-error.h:30
@ SC_OK
Definition util-error.h:27
#define SCMalloc(sz)
Definition util-mem.h:47
#define SCStrdup(s)
Definition util-mem.h:56
const char * PrintInet(int af, const void *src, char *dst, socklen_t size)
Definition util-print.c:231
SCRadix6Node * SCRadix6TreeFindBestMatch(const SCRadix6Tree *tree, const uint8_t *key, void **user_data)
#define GET_IPV6(str)
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)
#define REM_IPV6(str)
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)
#define ADD_IPV6(str)
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,...
#define NETMASK_MAX
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)