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  */
41 typedef 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  */
60 static 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  */
78 static 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  */
92 static 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  */
126 static 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  */
140 static 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  */
171 static 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  */
190 static 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  */
215 static int ContainNetmaskAndSetUserData(
216  RADIX_NODE_TYPE *node, uint8_t netmask, bool exact_match, void **user_data_result)
217 {
218  BUG_ON(!node);
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 
243 no_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  */
254 static 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  */
272 static 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  */
296 static 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  */
312 static 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  */
335 static 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 == false) {
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  */
565 static 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  */
589 static 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 == false) {
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  */
711 static 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 == false)
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  */
776 static 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 == false) {
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  */
828 static 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  */
842 static 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 
849 static 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  */
862 static 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  */
877 static 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  */
906 static 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 
912 static 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) == false)
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) == false)
950  return false;
951  if (n1->right && n2->right)
952  if (CompareTreesSub(n1->right, n2->right, Callback) == false)
953  return false;
954 
955  return true;
956 }
957 
958 static 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 }
ADDRESS_BYTES
#define ADDRESS_BYTES
Definition: util-radix4-tree.c:37
MaskIPNetblock
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
unlikely
#define unlikely(expr)
Definition: util-optimize.h:35
SCLogDebug
#define SCLogDebug(...)
Definition: util-debug.h:269
next
struct HtpBodyChunk_ * next
Definition: app-layer-htp.h:0
SC_EINVAL
@ SC_EINVAL
Definition: util-error.h:30
RadixUserData
Structure that hold the user data and the netmask associated with it.
Definition: util-radix-tree-common.h:41
RadixUserData::next
struct RadixUserData * next
Definition: util-radix-tree-common.h:45
MIN
#define MIN(x, y)
Definition: suricata-common.h:391
m
SCMutex m
Definition: flow-hash.h:6
RADIX_CONFIG_TYPE
#define RADIX_CONFIG_TYPE
Definition: util-radix4-tree.c:42
SC_ENOMEM
@ SC_ENOMEM
Definition: util-error.h:29
BUG_ON
#define BUG_ON(x)
Definition: suricata-common.h:300
NETMASK_MAX
#define NETMASK_MAX
Definition: util-radix4-tree.c:38
RADIX_BITTEST
#define RADIX_BITTEST(x, y)
Definition: util-radix-tree-common.h:36
RADIX_TREE_TYPE
#define RADIX_TREE_TYPE
Definition: util-radix4-tree.c:40
RadixUserData::user
void * user
Definition: util-radix-tree-common.h:43
util-validate.h
RADIX_TREE_COMPARE_CALLBACK
#define RADIX_TREE_COMPARE_CALLBACK
Definition: util-radix4-tree.c:43
SC_EEXIST
@ SC_EEXIST
Definition: util-error.h:32
RadixUserData
struct RadixUserData RadixUserData
Structure that hold the user data and the netmask associated with it.
SCLogError
#define SCLogError(...)
Macro used to log ERROR messages.
Definition: util-debug.h:261
SCFree
#define SCFree(p)
Definition: util-mem.h:61
sc_errno
thread_local SCError sc_errno
Definition: util-error.c:31
RADIX_NODE_TYPE
#define RADIX_NODE_TYPE
Definition: util-radix4-tree.c:41
RadixUserData::netmask
uint8_t netmask
Definition: util-radix-tree-common.h:47
SCCalloc
#define SCCalloc(nm, sz)
Definition: util-mem.h:53
SCMemcmp
#define SCMemcmp(a, b, c)
Definition: util-memcmp.h:290
DEBUG_VALIDATE_BUG_ON
#define DEBUG_VALIDATE_BUG_ON(exp)
Definition: util-validate.h:102