suricata
util-radix-tree-common.h
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 "util-validate.h"
28
29#ifndef ADDRESS_BYTES
30#error "define ADDRESS_BYTES"
31#endif
32#ifndef NETMASK_MAX
33#error "define NETMASK_MAX"
34#endif
35
36#define RADIX_BITTEST(x, y) ((x) & (y))
37
38/**
39 * \brief Structure that hold the user data and the netmask associated with it.
40 */
41typedef struct RadixUserData {
42 /* holds a pointer to the user data associated with the particular netmask */
43 void *user;
44 /* pointer to the next user data in the list */
46 /* holds the netmask value that corresponds to this user data pointer */
47 uint8_t netmask;
49
50/**
51 * \brief Allocates and returns a new instance of RadixUserData.
52 *
53 * \param netmask The netmask entry (cidr) that has to be made in the new
54 * RadixUserData instance
55 * \param user The user data that has to be set for the above
56 * netmask in the newly created RadixUserData instance.
57 *
58 * \retval user_data Pointer to a new instance of RadixUserData.
59 */
60static RadixUserData *AllocUserData(uint8_t netmask, void *user)
61{
62 RadixUserData *user_data = SCCalloc(1, sizeof(RadixUserData));
63 if (unlikely(user_data == NULL)) {
65 return NULL;
66 }
67 user_data->netmask = netmask;
68 user_data->user = user;
69 return user_data;
70}
71
72/**
73 * \brief Deallocates an instance of RadixUserData.
74 *
75 * \param user_data Pointer to the instance of RadixUserData that has to be
76 * freed.
77 */
78static void FreeUserData(RadixUserData *user_data)
79{
80 SCFree(user_data);
81}
82
83/**
84 * \brief Appends a user_data instance(RadixUserData) to a
85 * user_data(RadixUserData) list. We add the new entry in descending
86 * order with respect to the netmask contained in the RadixUserData.
87 *
88 * \param new Pointer to the RadixUserData to be added to the list.
89 * \param list Pointer to the RadixUserData list head, to which "new" has to
90 * be appended.
91 */
92static void AppendToUserDataList(RadixUserData *add, RadixUserData **list)
93{
94 RadixUserData *temp = NULL;
95
96 BUG_ON(add == NULL || list == NULL);
97
98 /* add to the list in descending order. The reason we do this is for
99 * optimizing key retrieval for a ip key under a netblock */
100 RadixUserData *prev = temp = *list;
101 while (temp != NULL) {
102 if (add->netmask > temp->netmask)
103 break;
104 prev = temp;
105 temp = temp->next;
106 }
107
108 if (temp == *list) {
109 add->next = *list;
110 *list = add;
111 } else {
112 add->next = prev->next;
113 prev->next = add;
114 }
115}
116
117/**
118 * \brief Adds a netmask and its user_data for a particular prefix stream.
119 *
120 * \param prefix The prefix stream to which the netmask and its corresponding
121 * user data has to be added.
122 * \param netmask The netmask value (cidr) that has to be added to the prefix.
123 * \param user The pointer to the user data corresponding to the above
124 * netmask.
125 */
126static void AddNetmaskUserDataToNode(RADIX_NODE_TYPE *node, uint8_t netmask, void *user)
127{
128 BUG_ON(!node);
129 AppendToUserDataList(AllocUserData(netmask, user), &node->user_data);
130}
131
132/**
133 * \brief Removes a particular user_data corresponding to a particular netmask
134 * entry, from a prefix.
135 *
136 * \param prefix Pointer to the prefix from which the user_data/netmask entry
137 * has to be removed.
138 * \param netmask The netmask value (cidr) whose user_data has to be deleted.
139 */
140static void RemoveNetmaskUserDataFromNode(RADIX_NODE_TYPE *node, uint8_t netmask)
141{
142 BUG_ON(!node);
143
144 RadixUserData *temp = NULL, *prev = NULL;
145 prev = temp = node->user_data;
146 while (temp != NULL) {
147 if (temp->netmask == netmask) {
148 if (temp == node->user_data)
149 node->user_data = temp->next;
150 else
151 prev->next = temp->next;
152
153 FreeUserData(temp);
154 break;
155 }
156 prev = temp;
157 temp = temp->next;
158 }
159}
160
161/**
162 * \brief Indicates if prefix contains an entry for an ip with a specific netmask.
163 *
164 * \param prefix Pointer to the ip prefix that is being checked.
165 * \param netmask The netmask value (cidr) that has to be checked for
166 * presence in the prefix.
167 *
168 * \retval 1 On match.
169 * \retval 0 On no match.
170 */
171static int ContainNetmask(RADIX_NODE_TYPE *node, uint8_t netmask)
172{
173 BUG_ON(!node);
174 RadixUserData *user_data = node->user_data;
175 while (user_data != NULL) {
176 if (user_data->netmask == netmask)
177 return 1;
178 user_data = user_data->next;
179 }
180 return 0;
181}
182
183/**
184 * \brief Returns the total netmask count for this prefix.
185 *
186 * \param prefix Pointer to the prefix
187 *
188 * \retval count The total netmask count for this prefix.
189 */
190static int NetmaskCount(RADIX_NODE_TYPE *node)
191{
192 BUG_ON(!node);
193 uint32_t count = 0;
194 RadixUserData *user_data = node->user_data;
195 while (user_data != NULL) {
196 count++;
197 user_data = user_data->next;
198 }
199 return count;
200}
201
202/**
203 * \brief Indicates if prefix contains an entry for an ip with a specific netmask
204 * and if it does, it sets `user_data_result` to the netmask user_data entry.
205 *
206 * \param prefix Pointer to the ip prefix that is being checked.
207 * \param netmask The netmask value for which we will have to return the user_data
208 * \param exact_match Bool flag which indicates if we should check if the prefix
209 * holds proper netblock or not.
210 * \param[out] user_data_result user data pointer
211 *
212 * \retval 1 On match.
213 * \retval 0 On no match.
214 */
215static int ContainNetmaskAndSetUserData(
216 RADIX_NODE_TYPE *node, uint8_t netmask, bool exact_match, void **user_data_result)
217{
219
220 RadixUserData *user_data = node->user_data;
221 /* Check if we have a match for an exact ip. An exact ip as in not a proper
222 * netblock, i.e. an ip with a netmask of 32. */
223 if (exact_match) {
224 if (user_data->netmask == netmask) {
225 if (user_data_result)
226 *user_data_result = user_data->user;
227 return 1;
228 } else {
229 goto no_match;
230 }
231 }
232
233 /* Check for the user_data entry for this netmask_value */
234 while (user_data != NULL) {
235 if (user_data->netmask == netmask) {
236 if (user_data_result)
237 *user_data_result = user_data->user;
238 return 1;
239 }
240 user_data = user_data->next;
241 }
242
243no_match:
244 if (user_data_result != NULL)
245 *user_data_result = NULL;
246 return 0;
247}
248
249/**
250 * \brief Creates a new node for the Radix tree
251 *
252 * \retval node The newly created node for the radix tree
253 */
254static inline RADIX_NODE_TYPE *RadixCreateNode(void)
255{
256 RADIX_NODE_TYPE *node = NULL;
257
258 if ((node = SCCalloc(1, sizeof(RADIX_NODE_TYPE))) == NULL) {
260 return NULL;
261 }
262 node->bit = NETMASK_MAX;
263 return node;
264}
265
266/**
267 * \brief Frees a Radix tree node
268 *
269 * \param node Pointer to a Radix tree node
270 * \param tree Pointer to the Radix tree to which this node belongs
271 */
272static void ReleaseNode(
273 RADIX_NODE_TYPE *node, RADIX_TREE_TYPE *tree, const RADIX_CONFIG_TYPE *config)
274{
275 DEBUG_VALIDATE_BUG_ON(config == NULL);
276 if (node != NULL) {
277 RadixUserData *ud = node->user_data;
278 while (ud != NULL) {
279 RadixUserData *next = ud->next;
280 if (config->Free != NULL && ud->user) {
281 config->Free(ud->user);
282 }
283 FreeUserData(ud);
284 ud = next;
285 }
286 SCFree(node);
287 }
288}
289
290/**
291 * \brief Internal helper function used by TreeRelease to free a subtree
292 *
293 * \param node Pointer to the root of the subtree that has to be freed
294 * \param tree Pointer to the Radix tree to which this subtree belongs
295 */
296static void ReleaseSubtree(
297 RADIX_NODE_TYPE *node, RADIX_TREE_TYPE *tree, const RADIX_CONFIG_TYPE *config)
298{
299 DEBUG_VALIDATE_BUG_ON(config == NULL);
300 if (node != NULL) {
301 ReleaseSubtree(node->left, tree, config);
302 ReleaseSubtree(node->right, tree, config);
303 ReleaseNode(node, tree, config);
304 }
305}
306
307/**
308 * \brief frees a Radix tree and all its nodes
309 *
310 * \param tree Pointer to the Radix tree that has to be freed
311 */
312static void TreeRelease(RADIX_TREE_TYPE *tree, const RADIX_CONFIG_TYPE *config)
313{
314 DEBUG_VALIDATE_BUG_ON(config == NULL);
315 if (tree == NULL)
316 return;
317
318 ReleaseSubtree(tree->head, tree, config);
319 tree->head = NULL;
320 return;
321}
322
323/**
324 * \brief Adds a key to the Radix tree. Used internally by the API.
325 *
326 * \param tree Pointer to the Radix tree
327 * \param key_stream Data that has to added to the Radix tree
328 * \param netmask The netmask (cidr)
329 * \param user Pointer to the user data that has to be associated with
330 * this key
331 * \param exclusive True if the node should be added iff it doesn't exist.
332 *
333 * \retval node Pointer to the newly created node
334 */
335static RADIX_NODE_TYPE *AddKey(RADIX_TREE_TYPE *tree, const RADIX_CONFIG_TYPE *config,
336 const uint8_t *key_stream, uint8_t netmask, void *user, const bool exclusive)
337{
338 DEBUG_VALIDATE_BUG_ON(config == NULL);
339 RADIX_NODE_TYPE *node = NULL;
340 RADIX_NODE_TYPE *parent = NULL;
341 RADIX_NODE_TYPE *bottom_node = NULL;
342
343 uint8_t tmp_stream[ADDRESS_BYTES];
344 memcpy(tmp_stream, key_stream, sizeof(tmp_stream));
345
346 if (tree == NULL) {
347 SCLogError("Argument \"tree\" NULL");
349 return NULL;
350 }
351
352 /* chop the ip address against a netmask */
353 MaskIPNetblock(tmp_stream, netmask, NETMASK_MAX);
354
355 /* the very first element in the radix tree */
356 if (tree->head == NULL) {
357 node = RadixCreateNode();
358 if (node == NULL)
359 return NULL;
360 memcpy(node->prefix_stream, tmp_stream, sizeof(tmp_stream));
361 node->has_prefix = true;
362 node->user_data = AllocUserData(netmask, user);
363 if (node->user_data == NULL) {
364 ReleaseNode(node, tree, config);
365 return NULL;
366 }
367 tree->head = node;
368 if (netmask == NETMASK_MAX)
369 return node;
370
371 AddNetmaskToMasks(node, netmask);
372 return node;
373 }
374 node = tree->head;
375
376 /* we walk down the tree only when we satisfy 2 conditions. The first one
377 * being the incoming prefix is shorter than the differ bit of the current
378 * node. In case we fail in this aspect, we walk down to the tree, till we
379 * arrive at a node that ends in a prefix */
380 while (node->bit < NETMASK_MAX || !node->has_prefix) {
381 /* if the bitlen isn't long enough to handle the bit test, we just walk
382 * down along one of the paths, since either paths should end up with a
383 * node that has a common prefix whose differ bit is greater than the
384 * bitlen of the incoming prefix */
385 if (NETMASK_MAX <= node->bit) {
386 if (node->right == NULL)
387 break;
388 node = node->right;
389 } else {
390 if (RADIX_BITTEST(tmp_stream[node->bit >> 3], (0x80 >> (node->bit % 8)))) {
391 if (node->right == NULL)
392 break;
393 node = node->right;
394 } else {
395 if (node->left == NULL)
396 break;
397 node = node->left;
398 }
399 }
400 }
401
402 /* we need to keep a reference to the bottom-most node, that actually holds
403 * the prefix */
404 bottom_node = node;
405
406 /* get the first bit position where the ips differ */
407 uint8_t check_bit = MIN(node->bit, NETMASK_MAX);
408 uint8_t differ_bit = 0;
409 uint8_t j = 0;
410 for (uint8_t i = 0; (i * 8) < check_bit; i++) {
411 int temp = 0;
412 if ((temp = (tmp_stream[i] ^ bottom_node->prefix_stream[i])) == 0) {
413 differ_bit = (i + 1) * 8;
414 continue;
415 }
416
417 /* find out the position where the first bit differs. This method is
418 * faster, but at the cost of being larger. But with larger caches
419 * these days we don't have to worry about cache misses */
420 temp = temp * 2;
421 if (temp >= 256)
422 j = 0;
423 else if (temp >= 128)
424 j = 1;
425 else if (temp >= 64)
426 j = 2;
427 else if (temp >= 32)
428 j = 3;
429 else if (temp >= 16)
430 j = 4;
431 else if (temp >= 8)
432 j = 5;
433 else if (temp >= 4)
434 j = 6;
435 else if (temp >= 2)
436 j = 7;
437
438 differ_bit = i * 8 + j;
439 break;
440 }
441 if (check_bit < differ_bit)
442 differ_bit = check_bit;
443
444 /* walk up the tree till we find the position, to fit our new node in */
445 parent = node->parent;
446 while (parent && differ_bit <= parent->bit) {
447 node = parent;
448 parent = node->parent;
449 }
450 BUG_ON(differ_bit == NETMASK_MAX && node->bit != NETMASK_MAX);
451
452 /* We already have the node in the tree with the same differing bit position */
453 if (differ_bit == NETMASK_MAX && node->bit == NETMASK_MAX) {
454 if (node->has_prefix) {
455 /* Check if we already have this netmask entry covered by this prefix */
456 if (ContainNetmask(node, netmask)) {
457 /* Basically we already have this stream prefix, as well as the
458 * netblock entry for this. A perfect duplicate. */
459 if (exclusive) {
460 SCLogDebug("not inserting since it already exists");
462 return NULL;
463 }
464 SCLogDebug("Duplicate entry for this ip address/netblock");
465 } else {
466 /* Basically we already have this stream prefix, but we don't
467 * have an entry for this particular netmask value for this
468 * prefix. For example, we have an entry for 192.168.0.0 and
469 * 192.168.0.0/16 and now we are trying to enter 192.168.0.0/20 */
470 AddNetmaskUserDataToNode(node, netmask, user);
471
472 /* if we are adding a netmask of 32 it indicates we are adding
473 * an exact host ip into the radix tree, in which case we don't
474 * need to add the netmask value into the tree */
475 if (netmask == NETMASK_MAX)
476 return node;
477
478 /* looks like we have a netmask which is != 32, in which
479 * case we walk up the tree to insert this netmask value in the
480 * correct node */
481 parent = node->parent;
482 while (parent != NULL && netmask < (parent->bit + 1)) {
483 node = parent;
484 parent = parent->parent;
485 }
486
487 AddNetmaskToMasks(node, netmask);
488 if (NetmaskEqualsMask(node, netmask)) {
489 return node;
490 }
491 }
492 }
493 return node;
494 }
495
496 /* create the leaf node for the new key */
497 RADIX_NODE_TYPE *new_node = RadixCreateNode();
498 if (new_node == NULL)
499 return NULL;
500 memcpy(new_node->prefix_stream, tmp_stream, sizeof(tmp_stream));
501 new_node->has_prefix = true;
502 new_node->user_data = AllocUserData(netmask, user);
503 if (new_node->user_data == NULL) {
504 ReleaseNode(new_node, tree, config);
505 return NULL;
506 }
507
508 /* stick our new_node into the tree. Create a node that holds the
509 * differing bit position and break the branch. Also handle the
510 * tranfer of netmasks between node and inter_node(explained in more
511 * detail below) */
512 RADIX_NODE_TYPE *inter_node = RadixCreateNode();
513 if (inter_node == NULL) {
514 ReleaseNode(new_node, tree, config);
515 return NULL;
516 }
517 inter_node->has_prefix = false;
518 inter_node->bit = differ_bit;
519 inter_node->parent = node->parent;
520 SCLogDebug("inter_node: differ_bit %u", differ_bit);
521
522 /* update netmasks for node and set them for inter_node */
523 ProcessInternode(node, inter_node);
524
525 if (RADIX_BITTEST(tmp_stream[differ_bit >> 3], (0x80 >> (differ_bit % 8)))) {
526 inter_node->left = node;
527 inter_node->right = new_node;
528 } else {
529 inter_node->left = new_node;
530 inter_node->right = node;
531 }
532 new_node->parent = inter_node;
533
534 if (node->parent == NULL)
535 tree->head = inter_node;
536 else if (node->parent->right == node)
537 node->parent->right = inter_node;
538 else
539 node->parent->left = inter_node;
540
541 node->parent = inter_node;
542
543 /* insert the netmask into the tree */
544 if (netmask != NETMASK_MAX) {
545 node = new_node;
546 parent = new_node->parent;
547 while (parent != NULL && netmask < (parent->bit + 1)) {
548 node = parent;
549 parent = parent->parent;
550 }
551 AddNetmaskToMasks(node, netmask);
552 }
553 return new_node;
554}
555
556/**
557 * \brief Removes a netblock entry from an ip node. The function first
558 * deletes the netblock/user_data entry for the prefix and then
559 * removes the netmask entry that has been made in the tree, by
560 * walking up the tree and deleting the entry from the specific node.
561 *
562 * \param node The node from which the netblock entry has to be removed.
563 * \param netmask The netmask entry (cidr) that has to be removed.
564 */
565static void RemoveNetblockEntry(RADIX_NODE_TYPE *node, uint8_t netmask)
566{
567 BUG_ON(!node);
568
569 RemoveNetmaskUserDataFromNode(node, netmask);
570
571 if (netmask == NETMASK_MAX) {
572 SCLogDebug("%d == %d", netmask, NETMASK_MAX);
573 return;
574 }
575
576 RemoveNetmaskFromMasks(node, netmask);
577 if (node->parent != NULL)
578 RemoveNetmaskFromMasks(node->parent, netmask);
579 return;
580}
581
582/**
583 * \brief Removes a key from the Radix tree
584 *
585 * \param key_stream Data that has to be removed from the Radix tree
586 * \param tree Pointer to the Radix tree from which the key has to be
587 * removed
588 */
589static void RemoveKey(RADIX_TREE_TYPE *tree, const RADIX_CONFIG_TYPE *config,
590 const uint8_t *key_stream, const uint8_t netmask)
591{
592 RADIX_NODE_TYPE *node = tree->head;
593 RADIX_NODE_TYPE *parent = NULL;
594 RADIX_NODE_TYPE *temp_dest = NULL;
595
596 if (node == NULL) {
597 SCLogDebug("tree is empty");
598 return;
599 }
600
601 uint8_t tmp_stream[ADDRESS_BYTES];
602 memcpy(tmp_stream, key_stream, sizeof(tmp_stream));
603
604 while (node->bit < NETMASK_MAX) {
605 if (RADIX_BITTEST(tmp_stream[node->bit >> 3], (0x80 >> (node->bit % 8)))) {
606 node = node->right;
607 } else {
608 node = node->left;
609 }
610
611 if (node == NULL) {
612 SCLogDebug("no matching node found");
613 return;
614 }
615 }
616
617 if (node->bit != NETMASK_MAX || !node->has_prefix) {
618 SCLogDebug("node %p bit %d != %d, or not has_prefix %s", node, node->bit, NETMASK_MAX,
619 node->has_prefix ? "true" : "false");
620 return;
621 }
622
623 if (SCMemcmp(node->prefix_stream, tmp_stream, sizeof(tmp_stream)) == 0) {
624 if (!ContainNetmask(node, netmask)) {
625 SCLogDebug("key exists in the tree, but this (%d) "
626 "netblock entry doesn't exist",
627 netmask);
628 return;
629 }
630 } else {
631 SCLogDebug("You are trying to remove a key that doesn't exist in the "
632 "Radix Tree");
633 return;
634 }
635
636 /* The ip node does exist, and the netblock entry does exist in this node, if
637 * we have reached this point. If we have more than one netblock entry, it
638 * indicates we have multiple entries for this key. So we delete that
639 * particular netblock entry, and make our way out of this function */
640 if (NetmaskCount(node) > 1) { // || !NoneNegated(node)) {
641 RemoveNetblockEntry(node, netmask);
642 SCLogDebug("NetmaskCount");
643 return;
644 }
645 SCLogDebug("not netmask cnt");
646
647 /* we are deleting the root of the tree. This would be the only node left
648 * in the tree */
649 if (tree->head == node) {
650 ReleaseNode(node, tree, config);
651 tree->head = NULL;
652 SCLogDebug("tree->head == node");
653 return;
654 }
655
656 parent = node->parent;
657 /* parent->parent is not the root of the tree */
658 if (parent->parent != NULL) {
659 if (parent->parent->left == parent) {
660 if (node->parent->left == node) {
661 temp_dest = parent->right;
662 parent->parent->left = parent->right;
663 parent->right->parent = parent->parent;
664 } else {
665 temp_dest = parent->left;
666 parent->parent->left = parent->left;
667 parent->left->parent = parent->parent;
668 }
669 } else {
670 if (node->parent->left == node) {
671 temp_dest = parent->right;
672 parent->parent->right = parent->right;
673 parent->right->parent = parent->parent;
674 } else {
675 temp_dest = parent->left;
676 parent->parent->right = parent->left;
677 parent->left->parent = parent->parent;
678 }
679 }
680 /* parent is the root of the tree */
681 } else {
682 if (parent->left == node) {
683 temp_dest = tree->head->right;
684 tree->head->right->parent = NULL;
685 tree->head = tree->head->right;
686 } else {
687 temp_dest = tree->head->left;
688 tree->head->left->parent = NULL;
689 tree->head = tree->head->left;
690 }
691 }
692 /* We need to shift the netmask entries from the node that would be
693 * deleted to its immediate descendant */
694 AddNetmasksFromNode(temp_dest, parent);
695 RemoveNetmaskFromMasks(temp_dest, netmask);
696 /* release the nodes */
697 ReleaseNode(parent, tree, config);
698 ReleaseNode(node, tree, config);
699
700 SCLogDebug("end (netmask %d)", netmask);
701 return;
702}
703
704/**
705 * \brief Checks if an IP prefix falls under a netblock, in the path to the root
706 * of the tree, from the node. Used internally by FindKey()
707 *
708 * \param prefix Pointer to the prefix that contains the ip address
709 * \param node Pointer to the node from where we have to climb the tree
710 */
711static inline RADIX_NODE_TYPE *FindKeyIPNetblock(const uint8_t *key_stream, RADIX_NODE_TYPE *node,
712 void **user_data_result, uint8_t *out_netmask)
713{
714 while (node != NULL && NetmasksEmpty(node))
715 node = node->parent;
716 if (node == NULL)
717 return NULL;
718
719 uint8_t tmp_stream[ADDRESS_BYTES];
720 memcpy(tmp_stream, key_stream, sizeof(tmp_stream));
721
722 /* hold the node found containing a netmask. We will need it when we call
723 * this function recursively */
724 RADIX_NODE_TYPE *netmask_node = node;
725
726 for (uint8_t j = 0; j <= NETMASK_MAX; j++) {
727 uint8_t m = NETMASK_MAX - j;
728
729 if (!(NetmaskIssetInMasks(netmask_node, m)))
730 continue;
731
732 for (uint8_t i = 0; i < ADDRESS_BYTES; i++) {
733 uint32_t mask = UINT_MAX;
734 if (((i + 1) * 8) > m) {
735 if (((i + 1) * 8 - m) < 8)
736 mask = UINT_MAX << ((i + 1) * 8 - m);
737 else
738 mask = 0;
739 }
740 tmp_stream[i] &= mask;
741 }
742
743 while (node->bit < NETMASK_MAX) {
744 if (RADIX_BITTEST(tmp_stream[node->bit >> 3], (0x80 >> (node->bit % 8)))) {
745 node = node->right;
746 } else {
747 node = node->left;
748 }
749
750 if (node == NULL)
751 return NULL;
752 }
753
754 if (node->bit != NETMASK_MAX || !node->has_prefix)
755 return NULL;
756
757 if (SCMemcmp(node->prefix_stream, tmp_stream, sizeof(tmp_stream)) == 0) {
758 if (ContainNetmaskAndSetUserData(node, m, false, user_data_result)) {
759 *out_netmask = m;
760 return node;
761 }
762 }
763 }
764
765 return FindKeyIPNetblock(tmp_stream, netmask_node->parent, user_data_result, out_netmask);
766}
767
768/**
769 * \brief Checks if an IP address key is present in the tree. The function
770 * apart from handling any normal data, also handles ipv4/ipv6 netblocks
771 *
772 * \param key_stream Data that has to be found in the Radix tree
773 * \param tree Pointer to the Radix tree
774 * \param exact_match The key to be searched is an ip address
775 */
776static RADIX_NODE_TYPE *FindKey(const RADIX_TREE_TYPE *tree, const uint8_t *key_stream,
777 const uint8_t netmask, bool exact_match, void **user_data_result, uint8_t *out_netmask)
778{
779 if (tree == NULL || tree->head == NULL)
780 return NULL;
781
782 RADIX_NODE_TYPE *node = tree->head;
783 uint8_t tmp_stream[ADDRESS_BYTES];
784 memcpy(tmp_stream, key_stream, sizeof(tmp_stream));
785
786 while (node->bit < NETMASK_MAX) {
787 if (RADIX_BITTEST(tmp_stream[node->bit >> 3], (0x80 >> (node->bit % 8)))) {
788 node = node->right;
789 } else {
790 node = node->left;
791 }
792
793 if (node == NULL) {
794 return NULL;
795 }
796 }
797
798 if (node->bit != NETMASK_MAX || !node->has_prefix) {
799 return NULL;
800 }
801
802 if (SCMemcmp(node->prefix_stream, tmp_stream, sizeof(tmp_stream)) == 0) {
803 SCLogDebug("stream match");
804 if (ContainNetmaskAndSetUserData(node, netmask, true, user_data_result)) {
805 SCLogDebug("contains netmask etc");
806 *out_netmask = netmask;
807 return node;
808 }
809 }
810
811 /* if you are not an ip key, get out of here */
812 if (exact_match) {
813 SCLogDebug("no node found and need exact match, so failed");
814 return NULL;
815 }
816
817 RADIX_NODE_TYPE *ret = FindKeyIPNetblock(tmp_stream, node, user_data_result, out_netmask);
818 return ret;
819}
820
821/**
822 * \brief Checks if an IPV4 address is present in the tree
823 *
824 * \param key_stream Data that has to be found in the Radix tree. In this case
825 * an IPV4 address
826 * \param tree Pointer to the Radix tree instance
827 */
828static RADIX_NODE_TYPE *FindExactMatch(
829 const RADIX_TREE_TYPE *tree, const uint8_t *key_stream, void **user_data_result)
830{
831 uint8_t unused = 0;
832 return FindKey(tree, key_stream, NETMASK_MAX, true, user_data_result, &unused);
833}
834
835/**
836 * \brief Checks if an IPV4 address is present in the tree under a netblock
837 *
838 * \param key_stream Data that has to be found in the Radix tree. In this case
839 * an IPV4 address
840 * \param tree Pointer to the Radix tree instance
841 */
842static RADIX_NODE_TYPE *FindBestMatch(
843 const RADIX_TREE_TYPE *tree, const uint8_t *key_stream, void **user_data_result)
844{
845 uint8_t unused = 0;
846 return FindKey(tree, key_stream, NETMASK_MAX, false, user_data_result, &unused);
847}
848
849static RADIX_NODE_TYPE *FindBestMatch2(const RADIX_TREE_TYPE *tree, const uint8_t *key_stream,
850 void **user_data_result, uint8_t *out_netmask)
851{
852 return FindKey(tree, key_stream, NETMASK_MAX, false, user_data_result, out_netmask);
853}
854
855/**
856 * \brief Checks if an IPV4 Netblock address is present in the tree
857 *
858 * \param key_stream Data that has to be found in the Radix tree. In this case
859 * an IPV4 netblock address
860 * \param tree Pointer to the Radix tree instance
861 */
862static RADIX_NODE_TYPE *FindNetblock(const RADIX_TREE_TYPE *tree, const uint8_t *key_stream,
863 const uint8_t netmask, void **user_data_result)
864{
865 uint8_t unused = 0;
866 RADIX_NODE_TYPE *node = FindKey(tree, key_stream, netmask, true, user_data_result, &unused);
867 return node;
868}
869
870/**
871 * \brief Helper function used by PrintTree. Prints the subtree with
872 * node as the root of the subtree
873 *
874 * \param node Pointer to the node that is the root of the subtree to be printed
875 * \param level Used for indentation purposes
876 */
877static void PrintSubtree(RADIX_NODE_TYPE *node, int level, void (*PrintData)(void *))
878{
879 if (node != NULL) {
880 PrintNodeInfo(node, level, PrintData);
881 PrintSubtree(node->left, level + 1, PrintData);
882 PrintSubtree(node->right, level + 1, PrintData);
883 }
884
885 return;
886}
887
888/**
889 * \brief Prints the Radix Tree. While printing the radix tree we use the
890 * following format
891 *
892 * Parent_0
893 * Left_Child_1
894 * Left_Child_2
895 * Right_Child_2
896 * Right_Child_1
897 * Left_Child_2
898 * Right_Child_2 and so on
899 *
900 * Each node printed out holds details on the next bit that differs
901 * amongst its children, and if the node holds a prefix, the perfix is
902 * printed as well.
903 *
904 * \param tree Pointer to the Radix tree that has to be printed
905 */
906static void PrintTree(RADIX_TREE_TYPE *tree, const RADIX_CONFIG_TYPE *config)
907{
908 printf("Printing the Radix Tree: \n");
909 PrintSubtree(tree->head, 0, config->PrintData);
910}
911
912static bool CompareTreesSub(
914{
915 // compare nodes
916 bool n1_has_left = n1->left != NULL;
917 bool n2_has_left = n2->left != NULL;
918 if (n1_has_left != n2_has_left)
919 return false;
920
921 bool n1_has_right = n1->right != NULL;
922 bool n2_has_right = n2->right != NULL;
923 if (n1_has_right != n2_has_right)
924 return false;
925
926 if (SCMemcmp(n1->prefix_stream, n2->prefix_stream, ADDRESS_BYTES) != 0)
927 return false;
928
929 RadixUserData *u1 = n1->user_data;
930 RadixUserData *u2 = n2->user_data;
931 while (1) {
932 if (u1 == NULL && u2 == NULL)
933 break;
934 if ((u1 != NULL && u2 == NULL) || (u1 == NULL && u2 != NULL))
935 return false;
936 if (u1->netmask != u2->netmask)
937 return false;
938
939 if (Callback != NULL) {
940 if (!Callback(u1->user, u2->user))
941 return false;
942 }
943
944 u1 = u1->next;
945 u2 = u2->next;
946 }
947
948 if (n1->left && n2->left)
949 if (!CompareTreesSub(n1->left, n2->left, Callback))
950 return false;
951 if (n1->right && n2->right)
952 if (!CompareTreesSub(n1->right, n2->right, Callback))
953 return false;
954
955 return true;
956}
957
958static bool CompareTrees(
959 const RADIX_TREE_TYPE *t1, const RADIX_TREE_TYPE *t2, RADIX_TREE_COMPARE_CALLBACK Callback)
960{
961 if (t1->head == NULL && t2->head == NULL)
962 return true;
963 if ((t1->head == NULL && t2->head != NULL) || (t1->head != NULL && t2->head == NULL))
964 return false;
965 return CompareTreesSub(t1->head, t2->head, Callback);
966}
struct HtpBodyChunk_ * next
SCMutex m
Definition flow-hash.h:6
Structure that hold the user data and the netmask associated with it.
struct RadixUserData * next
#define BUG_ON(x)
#define MIN(x, y)
#define SCLogDebug(...)
Definition util-debug.h:275
#define SCLogError(...)
Macro used to log ERROR messages.
Definition util-debug.h:267
thread_local SCError sc_errno
Definition util-error.c:31
@ SC_EINVAL
Definition util-error.h:30
@ SC_ENOMEM
Definition util-error.h:29
@ SC_EEXIST
Definition util-error.h:32
void MaskIPNetblock(uint8_t *stream, int netmask, int key_bitlen)
Culls the non-netmask portion of the IP address. For example an IP address 192.168....
Definition util-ip.c:187
#define SCFree(p)
Definition util-mem.h:61
#define SCCalloc(nm, sz)
Definition util-mem.h:53
#define SCMemcmp(a, b, c)
#define unlikely(expr)
#define RADIX_BITTEST(x, y)
#define RADIX_TREE_TYPE
#define RADIX_NODE_TYPE
#define RADIX_TREE_COMPARE_CALLBACK
#define RADIX_CONFIG_TYPE
#define ADDRESS_BYTES
#define NETMASK_MAX
#define DEBUG_VALIDATE_BUG_ON(exp)