suricata
util-radix4-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 tree for IPv4
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-unittest.h"
32#include "util-memcmp.h"
33#include "util-print.h"
34#include "util-byte.h"
35#include "util-radix4-tree.h"
36
37#define ADDRESS_BYTES (uint8_t)4
38#define NETMASK_MAX (uint8_t)32
39
40#define RADIX_TREE_TYPE SCRadix4Tree
41#define RADIX_NODE_TYPE SCRadix4Node
42#define RADIX_CONFIG_TYPE SCRadix4Config
43#define RADIX_TREE_COMPARE_CALLBACK SCRadix4TreeCompareFunc
44
45static void PrintUserdata(SCRadix4Node *node, int level, void (*PrintData)(void *));
46
47static inline void AddNetmaskToMasks(SCRadix4Node *node, int netmask)
48{
49 SCLogDebug("masks %" PRIX64 ", adding %d/%" PRIX64, (uint64_t)node->masks, netmask,
50 (uint64_t)BIT_U64(netmask));
51 node->masks |= BIT_U64(netmask);
52 SCLogDebug("masks %" PRIX64, (uint64_t)node->masks);
53}
54
55static inline void RemoveNetmaskFromMasks(SCRadix4Node *node, int netmask)
56{
57 SCLogDebug("masks %" PRIX64 ", removing %d/%" PRIX64, (uint64_t)node->masks, netmask,
58 (uint64_t)BIT_U64(netmask));
59 node->masks &= ~BIT_U64(netmask);
60 SCLogDebug("masks %" PRIX64, (uint64_t)node->masks);
61}
62
63static inline void AddNetmasksFromNode(SCRadix4Node *dst, SCRadix4Node *src)
64{
65 dst->masks |= src->masks;
66}
67
68static inline bool NetmasksEmpty(const SCRadix4Node *node)
69{
70 return (node->masks == 0);
71}
72
73static inline bool NetmaskEqualsMask(const SCRadix4Node *node, int netmask)
74{
75 return (node->masks == BIT_U64(netmask));
76}
77
78static inline bool NetmaskIssetInMasks(const SCRadix4Node *node, int netmask)
79{
80 return ((node->masks & BIT_U64(netmask)) != 0);
81}
82
83static inline void ProcessInternode(SCRadix4Node *node, SCRadix4Node *inter_node)
84{
85 const int differ_bit = inter_node->bit;
86 uint64_t rem = 0;
87 for (int x = 0; x <= NETMASK_MAX; x++) {
88 int m = NETMASK_MAX - x;
89 if (m == differ_bit)
90 break;
91 else {
92 rem |= (node->masks & BIT_U64(m));
93 }
94 }
95
96 inter_node->masks |= node->masks;
97 inter_node->masks &= ~rem;
98 node->masks = rem;
99}
100
101/**
102 * \brief Prints the node information from a Radix4 tree
103 *
104 * \param node Pointer to the Radix4 node whose information has to be printed
105 * \param level Used for indentation purposes
106 */
107static void PrintNodeInfo(SCRadix4Node *node, int level, void (*PrintData)(void *))
108{
109 if (node == NULL)
110 return;
111
112 for (int i = 0; i < level; i++)
113 printf(" ");
114
115 printf("%d [", node->bit);
116
117 if (node->masks == 0) {
118 printf(" - ");
119 } else {
120 for (int i = 0, x = 0; i <= 32; i++) {
121 if (node->masks & BIT_U64(i)) {
122 printf("%s%d", (x && x < 32) ? ", " : "", i);
123 x++;
124 }
125 }
126 }
127 printf("] (");
128
129 if (node->has_prefix) {
130 char addr[16] = "";
131 PrintInet(AF_INET, &node->prefix_stream, addr, sizeof(addr));
132 printf("%s - user_data %p)\n", addr, node->user_data);
133 PrintUserdata(node, level + 1, PrintData);
134 } else {
135 printf("no prefix)\n");
136 }
137 return;
138}
139
141
143 const SCRadix4Tree *tree, const uint8_t *key, void **user_data)
144{
145 return FindExactMatch(tree, key, user_data);
146}
147
149 const SCRadix4Tree *tree, const uint8_t *key, const uint8_t netmask, void **user_data)
150{
151 return FindNetblock(tree, key, netmask, user_data);
152}
153
155 const SCRadix4Tree *tree, const uint8_t *key, void **user_data)
156{
157 return FindBestMatch(tree, key, user_data);
158}
159
161 const SCRadix4Tree *tree, const uint8_t *key, void **user_data, uint8_t *out_netmask)
162{
163 return FindBestMatch2(tree, key, user_data, out_netmask);
164}
165
171
173{
174 TreeRelease(tree, config);
175}
176
177/**
178 * \brief Adds a new IPV4 address to the Radix4 tree
179 *
180 * \param key_stream Data that has to be added to the Radix4 tree. In this case
181 * a pointer to an IPV4 address
182 * \param tree Pointer to the Radix4 tree
183 * \param user Pointer to the user data that has to be associated with the
184 * key
185 *
186 * \retval node Pointer to the newly created node
187 */
189 SCRadix4Tree *tree, const SCRadix4Config *config, const uint8_t *key_stream, void *user)
190{
191 return AddKey(tree, config, key_stream, 32, user, false);
192}
193
194/**
195 * \brief Adds a new IPV4 netblock to the Radix4 tree
196 *
197 * \param key_stream Data that has to be added to the Radix4 tree. In this case
198 * a pointer to an IPV4 netblock
199 * \param tree Pointer to the Radix4 tree
200 * \param user Pointer to the user data that has to be associated with the
201 * key
202 * \param netmask The netmask (cidr) if we are adding a netblock
203 *
204 * \retval node Pointer to the newly created node
205 */
207 const uint8_t *key_stream, uint8_t netmask, void *user)
208{
209 return AddKey(tree, config, key_stream, netmask, user, false);
210}
211
212/**
213 * \brief Adds a new IPV4/netblock to the Radix4 tree from a string
214 *
215 * \param str IPV4 string with optional /cidr netmask
216 * \param tree Pointer to the Radix4 tree
217 * \param user Pointer to the user data that has to be associated with
218 * the key
219 *
220 * \retval bool true if node was added, false otherwise
221 *
222 * If the function returns false, `sc_errno` is set:
223 * - SC_EEXIST: Node already exists
224 * - SC_EINVAL: Parameter value error
225 * - SC_ENOMEM: Memory allocation failed
226 */
228 SCRadix4Tree *tree, const SCRadix4Config *config, const char *str, void *user)
229{
230 uint32_t ip;
231 uint8_t netmask = 32;
232 char ip_str[32]; /* Max length for full ipv4/mask string with NUL */
233 char *mask_str = NULL;
234 struct in_addr addr;
235
236 /* Make a copy of the string so it can be modified */
237 strlcpy(ip_str, str, sizeof(ip_str) - 2);
238 *(ip_str + (sizeof(ip_str) - 1)) = '\0';
239
240 /* Does it have a mask? */
241 if (NULL != (mask_str = strchr(ip_str, '/'))) {
242 *(mask_str++) = '\0';
243
244 /* Dotted type netmask not supported */
245 if (strchr(mask_str, '.') != NULL) {
247 return false;
248 }
249
250 uint8_t cidr;
251 if (StringParseU8RangeCheck(&cidr, 10, 0, (const char *)mask_str, 0, 32) < 0) {
253 return false;
254 }
255 netmask = (uint8_t)cidr;
256 }
257
258 /* Validate the IP */
259 if (inet_pton(AF_INET, ip_str, &addr) <= 0) {
261 return false;
262 }
263 ip = addr.s_addr;
264
265 if (AddKey(tree, config, (uint8_t *)&ip, netmask, user, true) == NULL) {
267 return false;
268 }
269 return true;
270}
271
272/**
273 * \brief Removes an IPV4 address key(not a netblock) from the Radix4 tree.
274 * Instead of using this function, we can also used
275 * SCRadix4RemoveKeyIPV4Netblock(), by supplying a netmask value of 32.
276 *
277 * \param key_stream Data that has to be removed from the Radix4 tree. In this
278 * case an IPV4 address
279 * \param tree Pointer to the Radix4 tree from which the key has to be
280 * removed
281 */
283 SCRadix4Tree *tree, const SCRadix4Config *config, const uint8_t *key_stream)
284{
285 RemoveKey(tree, config, key_stream, 32);
286}
287
288/**
289 * \brief Removes an IPV4 address netblock key from the Radix4 tree.
290 *
291 * \param key_stream Data that has to be removed from the Radix4 tree. In this
292 * case an IPV4 address
293 * \param tree Pointer to the Radix4 tree from which the key has to be
294 * removed
295 */
297 const uint8_t *key_stream, uint8_t netmask)
298{
299 SCLogNotice("removing with netmask %u", netmask);
300 RemoveKey(tree, config, key_stream, netmask);
301}
302
304{
305 PrintTree(tree, config);
306}
307
308static void PrintUserdata(SCRadix4Node *node, int level, void (*PrintData)(void *))
309{
310 if (PrintData != NULL) {
311 RadixUserData *ud = node->user_data;
312 while (ud != NULL) {
313 for (int i = 0; i < level; i++)
314 printf(" ");
315 printf("[%d], ", ud->netmask);
316 PrintData(ud->user);
317 ud = ud->next;
318 }
319 } else {
320 RadixUserData *ud = node->user_data;
321 while (ud != NULL) {
322 for (int i = 0; i < level; i++)
323 printf(" ");
324 printf(" [%d], ", ud->netmask);
325 ud = ud->next;
326 }
327 }
328}
329
330static int SCRadix4ForEachNodeSub(
331 const SCRadix4Node *node, SCRadix4ForEachNodeFunc Callback, void *data)
332{
333 BUG_ON(!node);
334
335 /* invoke callback for each stored user data */
336 for (RadixUserData *ud = node->user_data; ud != NULL; ud = ud->next) {
337 if (Callback(node, ud->user, ud->netmask, data) < 0)
338 return -1;
339 }
340
341 if (node->left) {
342 if (SCRadix4ForEachNodeSub(node->left, Callback, data) < 0)
343 return -1;
344 }
345 if (node->right) {
346 if (SCRadix4ForEachNodeSub(node->right, Callback, data) < 0)
347 return -1;
348 }
349 return 0;
350}
351
352int SCRadix4ForEachNode(const SCRadix4Tree *tree, SCRadix4ForEachNodeFunc Callback, void *data)
353{
354 if (tree->head == NULL)
355 return 0;
356 return SCRadix4ForEachNodeSub(tree->head, Callback, data);
357}
358
360 const SCRadix4Tree *t1, const SCRadix4Tree *t2, SCRadix4TreeCompareFunc Callback)
361{
362 return CompareTrees(t1, t2, Callback);
363}
364
365/*------------------------------------Unit_Tests------------------------------*/
366
367#ifdef UNITTESTS
368
369static const SCRadix4Config ut_ip_radix4_config = { NULL, NULL };
370
371#define GET_IPV4(str) \
372 SCLogDebug("setting up %s", (str)); \
373 memset(&(sa), 0, sizeof((sa))); \
374 FAIL_IF(inet_pton(AF_INET, (str), &(sa).sin_addr) <= 0);
375
376#define ADD_IPV4(str) \
377 GET_IPV4((str)); \
378 SCRadix4AddKeyIPV4(&tree, &ut_ip_radix4_config, (uint8_t *)&(sa).sin_addr, NULL);
379
380#define REM_IPV4(str) \
381 GET_IPV4((str)); \
382 SCRadix4RemoveKeyIPV4(&tree, &ut_ip_radix4_config, (uint8_t *)&(sa).sin_addr);
383
384#define ADD_IPV4_MASK(str, cidr) \
385 GET_IPV4((str)); \
386 SCRadix4AddKeyIPV4Netblock( \
387 &tree, &ut_ip_radix4_config, (uint8_t *)&(sa).sin_addr, (cidr), NULL);
388
389#define REM_IPV4_MASK(str, cidr) \
390 GET_IPV4((str)); \
391 SCRadix4RemoveKeyIPV4Netblock(&tree, &ut_ip_radix4_config, (uint8_t *)&(sa).sin_addr, (cidr));
392
393static int SCRadix4TestIPV4Insertion03(void)
394{
395 struct sockaddr_in sa;
397
398 ADD_IPV4("192.168.1.1");
399 ADD_IPV4("192.168.1.2");
400 ADD_IPV4("192.167.1.3");
401 ADD_IPV4("192.167.1.4");
402 ADD_IPV4("192.167.1.4");
403
404 /* test for the existance of a key */
405 GET_IPV4("192.168.1.6");
406 FAIL_IF_NOT(SCRadix4TreeFindExactMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) == NULL);
407
408 /* test for the existance of a key */
409 GET_IPV4("192.167.1.4");
410 FAIL_IF_NOT(SCRadix4TreeFindExactMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) != NULL);
411
412 /* continue adding keys */
413 ADD_IPV4("220.168.1.2");
414 ADD_IPV4("192.168.1.5");
415 ADD_IPV4("192.168.1.18");
416
417 /* test the existence of keys */
418 GET_IPV4("192.168.1.3");
419 FAIL_IF_NOT(SCRadix4TreeFindExactMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) == NULL);
420 GET_IPV4("127.234.2.62");
421 FAIL_IF_NOT(SCRadix4TreeFindExactMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) == NULL);
422
423 GET_IPV4("192.168.1.1");
424 FAIL_IF_NOT(SCRadix4TreeFindExactMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) != NULL);
425 GET_IPV4("192.168.1.5");
426 FAIL_IF_NOT(SCRadix4TreeFindExactMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) != NULL);
427 GET_IPV4("192.168.1.2");
428 FAIL_IF_NOT(SCRadix4TreeFindExactMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) != NULL);
429
430 GET_IPV4("192.167.1.3");
431 FAIL_IF_NOT(SCRadix4TreeFindExactMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) != NULL);
432 GET_IPV4("192.167.1.4");
433 FAIL_IF_NOT(SCRadix4TreeFindExactMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) != NULL);
434 GET_IPV4("220.168.1.2");
435 FAIL_IF_NOT(SCRadix4TreeFindExactMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) != NULL);
436 GET_IPV4("192.168.1.18");
437 FAIL_IF_NOT(SCRadix4TreeFindExactMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) != NULL);
438
439 SCRadix4TreeRelease(&tree, &ut_ip_radix4_config);
440
441 PASS;
442}
443
444static int SCRadix4TestIPV4Removal04(void)
445{
446 struct sockaddr_in sa;
447
449
450 /* add the keys */
451 ADD_IPV4("192.168.1.1");
452 ADD_IPV4("192.168.1.2");
453 ADD_IPV4("192.167.1.3");
454 ADD_IPV4("192.167.1.4");
455 ADD_IPV4("220.168.1.2");
456 ADD_IPV4("192.168.1.5");
457 ADD_IPV4("192.168.1.18");
458
459 /* remove the keys from the tree */
460 REM_IPV4("192.168.1.1");
461 REM_IPV4("192.167.1.3");
462 REM_IPV4("192.167.1.4");
463 REM_IPV4("192.168.1.18");
464
465 GET_IPV4("192.167.1.1");
466 FAIL_IF_NOT(SCRadix4TreeFindExactMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) == NULL);
467 GET_IPV4("192.168.1.2");
468 FAIL_IF_NOT(SCRadix4TreeFindExactMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) != NULL);
469
470 REM_IPV4("192.167.1.3");
471 REM_IPV4("220.168.1.2");
472
473 GET_IPV4("192.168.1.5");
474 FAIL_IF_NOT(SCRadix4TreeFindExactMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) != NULL);
475 GET_IPV4("192.168.1.2");
476 FAIL_IF_NOT(SCRadix4TreeFindExactMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) != NULL);
477
478 REM_IPV4("192.168.1.2");
479 REM_IPV4("192.168.1.5");
480
481 FAIL_IF_NOT_NULL(tree.head);
482
483 SCRadix4TreeRelease(&tree, &ut_ip_radix4_config);
484 PASS;
485}
486
487static int SCRadix4TestIPV4NetblockInsertion09(void)
488{
489 struct sockaddr_in sa;
491
492 /* add the keys */
493 ADD_IPV4("192.168.1.1");
494 ADD_IPV4("192.168.1.2");
495 ADD_IPV4("192.167.1.3");
496 ADD_IPV4("192.167.1.4");
497 ADD_IPV4("220.168.1.2");
498 ADD_IPV4("192.168.1.5");
499 ADD_IPV4("192.168.1.18");
500
501 ADD_IPV4_MASK("192.168.0.0", 16);
502 ADD_IPV4_MASK("192.171.128.0", 24);
503 ADD_IPV4_MASK("192.171.192.0", 18);
504 ADD_IPV4_MASK("192.175.0.0", 16);
505
506 /* test for the existance of a key */
507 GET_IPV4("192.168.1.6");
508 FAIL_IF_NOT(SCRadix4TreeFindExactMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) == NULL);
509 GET_IPV4("192.170.1.6");
510 FAIL_IF_NOT(SCRadix4TreeFindExactMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) == NULL);
511 GET_IPV4("192.171.128.145");
512 FAIL_IF_NOT(SCRadix4TreeFindBestMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) != NULL);
513 GET_IPV4("192.171.64.6");
514 FAIL_IF_NOT(SCRadix4TreeFindExactMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) == NULL);
515 GET_IPV4("192.171.191.6");
516 FAIL_IF_NOT(SCRadix4TreeFindExactMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) == NULL);
517 GET_IPV4("192.171.224.6");
518 FAIL_IF_NOT(SCRadix4TreeFindBestMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) != NULL);
519 GET_IPV4("192.171.224.6");
520 FAIL_IF_NOT(SCRadix4TreeFindExactMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) == NULL);
521 GET_IPV4("192.175.224.6");
522 FAIL_IF_NOT(SCRadix4TreeFindBestMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) != NULL);
523
524 SCRadix4TreeRelease(&tree, &ut_ip_radix4_config);
525 PASS;
526}
527
528static int SCRadix4TestIPV4NetblockInsertion10(void)
529{
530 SCRadix4Node *node[2];
531 struct sockaddr_in sa;
533
534 /* add the keys */
535 ADD_IPV4_MASK("253.192.0.0", 16);
536 ADD_IPV4_MASK("253.192.235.0", 24);
537 ADD_IPV4_MASK("192.167.0.0", 16);
538 ADD_IPV4("192.167.1.4");
539 ADD_IPV4_MASK("220.168.0.0", 16);
540 ADD_IPV4("253.224.1.5");
541 ADD_IPV4_MASK("192.168.0.0", 16);
542
543 GET_IPV4("192.171.128.0");
545 &tree, &ut_ip_radix4_config, (uint8_t *)&sa.sin_addr, 24, NULL);
546
547 GET_IPV4("192.171.128.45");
548 node[1] = SCRadix4AddKeyIPV4(&tree, &ut_ip_radix4_config, (uint8_t *)&sa.sin_addr, NULL);
549
550 ADD_IPV4_MASK("192.171.0.0", 18);
551 ADD_IPV4_MASK("192.175.0.0", 16);
552
553 /* test for the existance of a key */
554 GET_IPV4("192.171.128.53");
555 FAIL_IF_NOT(SCRadix4TreeFindBestMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) == node[0]);
556
557 GET_IPV4("192.171.128.45");
558 FAIL_IF_NOT(SCRadix4TreeFindExactMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) == node[1]);
559
560 GET_IPV4("192.171.128.45");
561 FAIL_IF_NOT(SCRadix4TreeFindBestMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) == node[1]);
562
563 GET_IPV4("192.171.128.78");
564 FAIL_IF_NOT(SCRadix4TreeFindBestMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) == node[0]);
565
566 REM_IPV4_MASK("192.171.128.0", 24);
567
568 GET_IPV4("192.171.128.78");
569 FAIL_IF_NOT(SCRadix4TreeFindBestMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) == NULL);
570 GET_IPV4("192.171.127.78");
571 FAIL_IF_NOT(SCRadix4TreeFindBestMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) == NULL);
572
573 SCRadix4TreeRelease(&tree, &ut_ip_radix4_config);
574
575 PASS;
576}
577
578static int SCRadix4TestIPV4NetblockInsertion11(void)
579{
580 struct sockaddr_in sa;
582
583 /* add the keys */
584 ADD_IPV4_MASK("253.192.0.0", 16);
585 ADD_IPV4_MASK("253.192.235.0", 24);
586 ADD_IPV4_MASK("192.167.0.0", 16);
587 ADD_IPV4("192.167.1.4");
588 ADD_IPV4_MASK("220.168.0.0", 16);
589 ADD_IPV4("253.224.1.5");
590 ADD_IPV4_MASK("192.168.0.0", 16);
591 ADD_IPV4_MASK("192.171.128.0", 24);
592 ADD_IPV4("192.171.128.45");
593 ADD_IPV4_MASK("192.171.0.0", 18);
594 ADD_IPV4_MASK("192.175.0.0", 16);
595
596 GET_IPV4("0.0.0.0");
598 &tree, &ut_ip_radix4_config, (uint8_t *)&sa.sin_addr, 0, NULL);
599 FAIL_IF_NULL(node);
600
601 /* test for the existance of a key */
602 GET_IPV4("192.171.128.53");
603 FAIL_IF_NOT(SCRadix4TreeFindBestMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) != NULL);
604
605 GET_IPV4("192.171.128.45");
606 FAIL_IF_NOT(SCRadix4TreeFindBestMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) != NULL);
607
608 GET_IPV4("192.171.128.78");
609 FAIL_IF_NOT(SCRadix4TreeFindBestMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) != NULL);
610
611 GET_IPV4("192.171.127.78");
612 FAIL_IF_NOT(SCRadix4TreeFindBestMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) == node);
613
614 GET_IPV4("1.1.1.1");
615 FAIL_IF_NOT(SCRadix4TreeFindBestMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) == node);
616
617 GET_IPV4("192.255.254.25");
618 FAIL_IF_NOT(SCRadix4TreeFindBestMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) == node);
619
620 GET_IPV4("169.255.254.25");
621 FAIL_IF_NOT(SCRadix4TreeFindBestMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) == node);
622
623 GET_IPV4("0.0.0.0");
624 FAIL_IF_NOT(SCRadix4TreeFindBestMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) == node);
625
626 GET_IPV4("253.224.1.5");
627 FAIL_IF_NOT(SCRadix4TreeFindExactMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) != NULL);
628 FAIL_IF_NOT(SCRadix4TreeFindExactMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) != node);
629
630 GET_IPV4("245.63.62.121");
631 FAIL_IF_NOT(SCRadix4TreeFindBestMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) != NULL);
632 FAIL_IF_NOT(SCRadix4TreeFindBestMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) == node);
633
634 GET_IPV4("253.224.1.6");
635 FAIL_IF_NOT(SCRadix4TreeFindBestMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) != NULL);
636 FAIL_IF_NOT(SCRadix4TreeFindBestMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) == node);
637
638 /* remove node 0.0.0.0 */
639 REM_IPV4_MASK("0.0.0.0", 0);
640
641 GET_IPV4("253.224.1.6");
642 FAIL_IF_NOT(SCRadix4TreeFindBestMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) == NULL);
643 GET_IPV4("192.171.127.78");
644 FAIL_IF_NOT(SCRadix4TreeFindBestMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) == NULL);
645 GET_IPV4("1.1.1.1");
646 FAIL_IF_NOT(SCRadix4TreeFindBestMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) == NULL);
647
648 GET_IPV4("192.255.254.25");
649 FAIL_IF_NOT(SCRadix4TreeFindBestMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) == NULL);
650 GET_IPV4("169.255.254.25");
651 FAIL_IF_NOT(SCRadix4TreeFindBestMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) == NULL);
652
653 GET_IPV4("0.0.0.0");
654 FAIL_IF_NOT(SCRadix4TreeFindBestMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) == NULL);
655
656 SCRadix4TreeRelease(&tree, &ut_ip_radix4_config);
657 PASS;
658}
659
660static int SCRadix4TestIPV4NetblockInsertion12(void)
661{
662 struct sockaddr_in sa;
664 SCRadix4Node *node[2];
665
666 /* add the keys */
667 ADD_IPV4_MASK("253.192.0.0", 16);
668 ADD_IPV4_MASK("253.192.235.0", 24);
669 ADD_IPV4_MASK("192.167.0.0", 16);
670 ADD_IPV4("192.167.1.4");
671 ADD_IPV4_MASK("220.168.0.0", 16);
672 ADD_IPV4("253.224.1.5");
673 ADD_IPV4_MASK("192.168.0.0", 16);
674
675 GET_IPV4("192.171.128.0");
677 &tree, &ut_ip_radix4_config, (uint8_t *)&sa.sin_addr, 24, NULL);
678 FAIL_IF_NULL(node[0]);
679
680 GET_IPV4("192.171.128.45");
681 node[1] = SCRadix4AddKeyIPV4(&tree, &ut_ip_radix4_config, (uint8_t *)&sa.sin_addr, NULL);
682 FAIL_IF_NULL(node[1]);
683
684 ADD_IPV4_MASK("192.171.0.0", 18);
685 ADD_IPV4_MASK("225.175.21.228", 32);
686
687 /* test for the existance of a key */
688 GET_IPV4("192.171.128.53");
689 FAIL_IF_NOT(SCRadix4TreeFindBestMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) == node[0]);
690 FAIL_IF_NOT(SCRadix4TreeFindExactMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) == NULL);
691
692 GET_IPV4("192.171.128.45");
693 FAIL_IF_NOT(SCRadix4TreeFindExactMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) == node[1]);
694 FAIL_IF_NOT(SCRadix4TreeFindBestMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) == node[1]);
695
696 GET_IPV4("192.171.128.78");
697 FAIL_IF_NOT(SCRadix4TreeFindBestMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) == node[0]);
698 FAIL_IF_NOT(SCRadix4TreeFindExactMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) == NULL);
699
700 GET_IPV4("225.175.21.228");
701 FAIL_IF_NOT(SCRadix4TreeFindExactMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) != NULL);
702
703 GET_IPV4("225.175.21.224");
704 FAIL_IF_NOT(SCRadix4TreeFindExactMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) == NULL);
705
706 GET_IPV4("225.175.21.229");
707 FAIL_IF_NOT(SCRadix4TreeFindExactMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) == NULL);
708
709 GET_IPV4("225.175.21.230");
710 FAIL_IF_NOT(SCRadix4TreeFindExactMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) == NULL);
711
712 SCRadix4TreeRelease(&tree, &ut_ip_radix4_config);
713
714 PASS;
715}
716
717/**
718 * \test Check that the best match search works for all the
719 * possible netblocks of a fixed address
720 */
721static int SCRadix4TestIPV4NetBlocksAndBestSearch16(void)
722{
723 struct sockaddr_in sa;
725
726 GET_IPV4("192.168.1.1");
727
728 for (uint32_t i = 0; i <= 32; i++) {
729 uint32_t *user = SCMalloc(sizeof(uint32_t));
730 FAIL_IF_NULL(user);
731 *user = i;
732 SCRadix4AddKeyIPV4Netblock(&tree, &ut_ip_radix4_config, (uint8_t *)&sa.sin_addr, i, user);
733 void *user_data = NULL;
734 SCRadix4Node *node = SCRadix4TreeFindBestMatch(&tree, (uint8_t *)&sa.sin_addr, &user_data);
735 FAIL_IF_NULL(node);
736 FAIL_IF_NULL(user_data);
737 FAIL_IF(*((uint32_t *)user_data) != i);
738 }
739
740 SCRadix4TreeRelease(&tree, &ut_ip_radix4_config);
741 PASS;
742}
743
744/**
745 * \test Check special combinations of netblocks and addresses
746 * on best search checking the returned userdata
747 */
748static int SCRadix4TestIPV4NetBlocksAndBestSearch19(void)
749{
750 struct sockaddr_in sa;
751 void *user_data = NULL;
753
754 GET_IPV4("0.0.0.0");
755 uint32_t *user = SCMalloc(sizeof(uint32_t));
756 FAIL_IF_NULL(user);
757 *user = 100;
758 SCRadix4AddKeyIPV4Netblock(&tree, &ut_ip_radix4_config, (uint8_t *)&sa.sin_addr, 0, user);
759
760 GET_IPV4("192.168.1.15");
761 SCRadix4Node *node = SCRadix4TreeFindBestMatch(&tree, (uint8_t *)&sa.sin_addr, &user_data);
762 FAIL_IF_NULL(node);
763 FAIL_IF_NULL(user_data);
764 FAIL_IF(*((uint32_t *)user_data) != 100);
765 user_data = NULL;
766
767 GET_IPV4("177.0.0.0");
768 user = SCMalloc(sizeof(uint32_t));
769 FAIL_IF_NULL(user);
770 *user = 200;
771 SCRadix4AddKeyIPV4Netblock(&tree, &ut_ip_radix4_config, (uint8_t *)&sa.sin_addr, 8, user);
772
773 GET_IPV4("177.168.1.15");
774 node = SCRadix4TreeFindBestMatch(&tree, (uint8_t *)&sa.sin_addr, &user_data);
775 FAIL_IF_NULL(node);
776 FAIL_IF_NULL(user_data);
777 FAIL_IF(*((uint32_t *)user_data) != 200);
778 user_data = NULL;
779
780 GET_IPV4("178.168.1.15");
781 node = SCRadix4TreeFindBestMatch(&tree, (uint8_t *)&sa.sin_addr, &user_data);
782 FAIL_IF_NULL(node);
783 FAIL_IF_NULL(user_data);
784 FAIL_IF(*((uint32_t *)user_data) != 100);
785 user_data = NULL;
786
787 GET_IPV4("177.168.0.0");
788 user = SCMalloc(sizeof(uint32_t));
789 FAIL_IF_NULL(user);
790 *user = 300;
791 SCRadix4AddKeyIPV4Netblock(&tree, &ut_ip_radix4_config, (uint8_t *)&sa.sin_addr, 12, user);
792
793 GET_IPV4("177.168.1.15");
794 node = SCRadix4TreeFindBestMatch(&tree, (uint8_t *)&sa.sin_addr, &user_data);
795 FAIL_IF_NULL(node);
796 FAIL_IF_NULL(user_data);
797 FAIL_IF(*((uint32_t *)user_data) != 300);
798 user_data = NULL;
799
800 GET_IPV4("177.167.1.15");
801 node = SCRadix4TreeFindBestMatch(&tree, (uint8_t *)&sa.sin_addr, &user_data);
802 FAIL_IF_NULL(node);
803 FAIL_IF_NULL(user_data);
804 FAIL_IF(*((uint32_t *)user_data) != 300);
805 user_data = NULL;
806
807 GET_IPV4("177.178.1.15");
808 node = SCRadix4TreeFindBestMatch(&tree, (uint8_t *)&sa.sin_addr, &user_data);
809 FAIL_IF_NULL(node);
810 FAIL_IF_NULL(user_data);
811 FAIL_IF(*((uint32_t *)user_data) != 200);
812 user_data = NULL;
813
814 GET_IPV4("197.178.1.15");
815 node = SCRadix4TreeFindBestMatch(&tree, (uint8_t *)&sa.sin_addr, &user_data);
816 FAIL_IF_NULL(node);
817 FAIL_IF_NULL(user_data);
818 FAIL_IF(*((uint32_t *)user_data) != 100);
819 user_data = NULL;
820
821 SCRadix4TreeRelease(&tree, &ut_ip_radix4_config);
822 PASS;
823}
824
825/**
826 * \test SCRadix4TestIPV4NetblockInsertion15 insert a node searching on it.
827 * Should always return true but the purposse of the test is to monitor
828 * the memory usage to detect memleaks (there was one on searching)
829 */
830static int SCRadix4TestIPV4NetblockInsertion25(void)
831{
832 struct sockaddr_in sa;
834 ADD_IPV4_MASK("192.168.0.0", 16);
835 GET_IPV4("192.168.128.53");
836 FAIL_IF_NOT(SCRadix4TreeFindBestMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) != NULL);
837 SCRadix4TreeRelease(&tree, &ut_ip_radix4_config);
838 PASS;
839}
840
841/**
842 * \test SCRadix4TestIPV4NetblockInsertion26 insert a node searching on it.
843 * Should always return true but the purposse of the test is to monitor
844 * the memory usage to detect memleaks (there was one on searching)
845 */
846static int SCRadix4TestIPV4NetblockInsertion26(void)
847{
848 SCRadix4Node *tmp = NULL;
849 struct sockaddr_in sa;
850 char *str = SCStrdup("Hello1");
853 GET_IPV4("0.0.0.0");
854 SCRadix4AddKeyIPV4Netblock(&tree, &ut_ip_radix4_config, (uint8_t *)&sa.sin_addr, 0, str);
855 str = SCStrdup("Hello2");
857 GET_IPV4("176.0.0.1");
858 SCRadix4AddKeyIPV4Netblock(&tree, &ut_ip_radix4_config, (uint8_t *)&sa.sin_addr, 5, str);
859 str = SCStrdup("Hello3");
861 GET_IPV4("0.0.0.0");
862 SCRadix4AddKeyIPV4Netblock(&tree, &ut_ip_radix4_config, (uint8_t *)&sa.sin_addr, 7, str);
863 /* test for the existance of a key */
864 void *retptr = NULL;
865 tmp = SCRadix4TreeFindBestMatch(&tree, (uint8_t *)&sa.sin_addr, &retptr);
866 FAIL_IF_NULL(tmp);
867 FAIL_IF_NULL(retptr);
868 FAIL_IF_NOT(strcmp((char *)retptr, "Hello3") == 0);
869 SCRadix4TreeRelease(&tree, &ut_ip_radix4_config);
870 PASS;
871}
872
873static int SCRadix4TestIPV4InsertRemove01(void)
874{
875 struct sockaddr_in sa;
876
878 ADD_IPV4_MASK("1.0.0.0", 8);
879 ADD_IPV4_MASK("1.1.1.0", 24);
880 ADD_IPV4("1.1.1.1");
881 FAIL_IF(tree.head == NULL);
882 FAIL_IF_NOT(tree.head->bit == 15);
883 FAIL_IF_NULL(tree.head->left);
884 FAIL_IF_NOT(tree.head->left->masks == 0);
885 FAIL_IF_NOT(tree.head->left->bit == 32);
886 FAIL_IF_NULL(tree.head->right);
887 FAIL_IF_NOT(tree.head->right->masks == BIT_U64(24));
888 FAIL_IF_NOT(tree.head->right->bit == 31);
889 SCRadix4PrintTree(&tree, &ut_ip_radix4_config);
890 SCRadix4TreeRelease(&tree, &ut_ip_radix4_config);
891
892 /* tree after adds/removals */
893 tree = SCRadix4TreeInitialize();
894 ADD_IPV4_MASK("1.0.0.0", 8);
895 ADD_IPV4_MASK("1.0.0.0", 10);
896 ADD_IPV4_MASK("1.0.0.0", 12);
897 ADD_IPV4_MASK("1.1.0.0", 16);
898 ADD_IPV4_MASK("1.1.0.0", 18);
899 ADD_IPV4_MASK("1.1.0.0", 20);
900 ADD_IPV4_MASK("1.1.1.0", 24);
901 ADD_IPV4("1.1.1.1");
902 REM_IPV4_MASK("1.1.0.0", 20);
903 REM_IPV4_MASK("1.1.0.0", 18);
904 REM_IPV4_MASK("1.1.0.0", 16);
905 REM_IPV4_MASK("1.0.0.0", 12);
906 REM_IPV4_MASK("1.0.0.0", 10);
907 FAIL_IF(tree.head == NULL);
908 FAIL_IF_NOT(tree.head->bit == 15);
909 FAIL_IF_NULL(tree.head->left);
910 FAIL_IF_NOT(tree.head->left->masks == 0);
911 FAIL_IF_NOT(tree.head->left->bit == 32);
912 FAIL_IF_NULL(tree.head->right);
913 FAIL_IF_NOT(tree.head->right->masks == BIT_U64(24));
914 FAIL_IF_NOT(tree.head->right->bit == 31);
915 SCRadix4PrintTree(&tree, &ut_ip_radix4_config);
916 SCRadix4TreeRelease(&tree, &ut_ip_radix4_config);
917
918 PASS;
919}
920#endif
921
923{
924#ifdef UNITTESTS
925 UtRegisterTest("SCRadix4TestIPV4Insertion03", SCRadix4TestIPV4Insertion03);
926 UtRegisterTest("SCRadix4TestIPV4Removal04", SCRadix4TestIPV4Removal04);
927 UtRegisterTest("SCRadix4TestIPV4NetblockInsertion09", SCRadix4TestIPV4NetblockInsertion09);
928 UtRegisterTest("SCRadix4TestIPV4NetblockInsertion10", SCRadix4TestIPV4NetblockInsertion10);
929 UtRegisterTest("SCRadix4TestIPV4NetblockInsertion11", SCRadix4TestIPV4NetblockInsertion11);
930 UtRegisterTest("SCRadix4TestIPV4NetblockInsertion12", SCRadix4TestIPV4NetblockInsertion12);
932 "SCRadix4TestIPV4NetBlocksAndBestSearch16", SCRadix4TestIPV4NetBlocksAndBestSearch16);
934 "SCRadix4TestIPV4NetBlocksAndBestSearch19", SCRadix4TestIPV4NetBlocksAndBestSearch19);
935 UtRegisterTest("SCRadix4TestIPV4NetblockInsertion25", SCRadix4TestIPV4NetblockInsertion25);
936 UtRegisterTest("SCRadix4TestIPV4NetblockInsertion26", SCRadix4TestIPV4NetblockInsertion26);
937 UtRegisterTest("SCRadix4TestIPV4InsertRemove01", SCRadix4TestIPV4InsertRemove01);
938#endif
939 return;
940}
uint16_t dst
uint16_t src
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 SCRadix4Node_ * right
uint8_t prefix_stream[4]
struct SCRadix4Node_ * left
struct RadixUserData * user_data
Structure for the radix tree.
SCRadix4Node * head
#define BUG_ON(x)
#define BIT_U64(n)
#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
#define SCLogDebug(...)
Definition util-debug.h:275
#define SCLogNotice(...)
Macro used to log NOTICE messages.
Definition util-debug.h:243
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
#define ADD_IPV4_MASK(str, cidr)
SCRadix4Node * SCRadix4TreeFindBestMatch2(const SCRadix4Tree *tree, const uint8_t *key, void **user_data, uint8_t *out_netmask)
#define GET_IPV4(str)
#define ADD_IPV4(str)
SCRadix4Node * SCRadix4TreeFindBestMatch(const SCRadix4Tree *tree, const uint8_t *key, void **user_data)
void SCRadix4RemoveKeyIPV4Netblock(SCRadix4Tree *tree, const SCRadix4Config *config, const uint8_t *key_stream, uint8_t netmask)
Removes an IPV4 address netblock key from the Radix4 tree.
#define REM_IPV4_MASK(str, cidr)
SCRadix4Tree SCRadix4TreeInitialize(void)
SCRadix4Node * SCRadix4TreeFindNetblock(const SCRadix4Tree *tree, const uint8_t *key, const uint8_t netmask, void **user_data)
bool SCRadix4AddKeyIPV4String(SCRadix4Tree *tree, const SCRadix4Config *config, const char *str, void *user)
Adds a new IPV4/netblock to the Radix4 tree from a string.
SCRadix4Node * SCRadix4AddKeyIPV4(SCRadix4Tree *tree, const SCRadix4Config *config, const uint8_t *key_stream, void *user)
Adds a new IPV4 address to the Radix4 tree.
void SCRadix4PrintTree(SCRadix4Tree *tree, const SCRadix4Config *config)
int SCRadix4ForEachNode(const SCRadix4Tree *tree, SCRadix4ForEachNodeFunc Callback, void *data)
void SCRadix4TreeRelease(SCRadix4Tree *tree, const SCRadix4Config *config)
#define REM_IPV4(str)
void SCRadix4RegisterTests(void)
void SCRadix4RemoveKeyIPV4(SCRadix4Tree *tree, const SCRadix4Config *config, const uint8_t *key_stream)
Removes an IPV4 address key(not a netblock) from the Radix4 tree. Instead of using this function,...
SCRadix4Node * SCRadix4TreeFindExactMatch(const SCRadix4Tree *tree, const uint8_t *key, void **user_data)
#define NETMASK_MAX
bool SCRadix4CompareTrees(const SCRadix4Tree *t1, const SCRadix4Tree *t2, SCRadix4TreeCompareFunc Callback)
SCRadix4Node * SCRadix4AddKeyIPV4Netblock(SCRadix4Tree *tree, const SCRadix4Config *config, const uint8_t *key_stream, uint8_t netmask, void *user)
Adds a new IPV4 netblock to the Radix4 tree.
bool(* SCRadix4TreeCompareFunc)(const void *ud1, const void *ud2)
compare content of 2 user data entries
int(* SCRadix4ForEachNodeFunc)(const SCRadix4Node *node, void *user_data, const uint8_t netmask, void *data)
#define SC_RADIX4_TREE_INITIALIZER
#define DEBUG_VALIDATE_BUG_ON(exp)