From e9a2352b997ee01e8ce6b6df6646b88cce9a7754 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 29 Oct 2024 09:35:33 +0100 Subject: [PATCH 01/14] host-os-info: test cleanup --- src/util-host-os-info.c | 80 +++++++++++++---------------------------- 1 file changed, 25 insertions(+), 55 deletions(-) diff --git a/src/util-host-os-info.c b/src/util-host-os-info.c index efbf8024d452..0d455c1c876b 100644 --- a/src/util-host-os-info.c +++ b/src/util-host-os-info.c @@ -376,63 +376,34 @@ static int SCHInfoTestInvalidOSFlavour01(void) { SCHInfoCreateContextBackup(); - int result = 0; + FAIL_IF(SCHInfoAddHostOSInfo("bamboo", "192.168.1.1", SC_HINFO_IS_IPV4) != -1); + FAIL_IF(SCHInfoAddHostOSInfo("linux", "192.168.1.1", SC_HINFO_IS_IPV4) != + SCMapEnumNameToValue("linux", sc_hinfo_os_policy_map)); + FAIL_IF(SCHInfoAddHostOSInfo("windows", "192.168.1.1", SC_HINFO_IS_IPV4) != + SCMapEnumNameToValue("windows", sc_hinfo_os_policy_map)); + FAIL_IF(SCHInfoAddHostOSInfo("solaris", "192.168.1.1", SC_HINFO_IS_IPV4) != + SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)); + FAIL_IF(SCHInfoAddHostOSInfo("hpux10", "192.168.1.1", SC_HINFO_IS_IPV4) != + SCMapEnumNameToValue("hpux10", sc_hinfo_os_policy_map)); + FAIL_IF(SCHInfoAddHostOSInfo("hpux11", "192.168.1.1", SC_HINFO_IS_IPV4) != + SCMapEnumNameToValue("hpux11", sc_hinfo_os_policy_map)); + FAIL_IF(SCHInfoAddHostOSInfo("irix", "192.168.1.1", SC_HINFO_IS_IPV4) != + SCMapEnumNameToValue("irix", sc_hinfo_os_policy_map)); + FAIL_IF(SCHInfoAddHostOSInfo("bsd", "192.168.1.1", SC_HINFO_IS_IPV4) != + SCMapEnumNameToValue("bsd", sc_hinfo_os_policy_map)); + FAIL_IF(SCHInfoAddHostOSInfo("old_linux", "192.168.1.1", SC_HINFO_IS_IPV4) != + SCMapEnumNameToValue("old_linux", sc_hinfo_os_policy_map)); + FAIL_IF(SCHInfoAddHostOSInfo("macos", "192.168.1.1", SC_HINFO_IS_IPV4) != + SCMapEnumNameToValue("macos", sc_hinfo_os_policy_map)); + FAIL_IF(SCHInfoAddHostOSInfo("vista", "192.168.1.1", SC_HINFO_IS_IPV4) != + SCMapEnumNameToValue("vista", sc_hinfo_os_policy_map)); + FAIL_IF(SCHInfoAddHostOSInfo("windows2k3", "192.168.1.1", SC_HINFO_IS_IPV4) != + SCMapEnumNameToValue("windows2k3", sc_hinfo_os_policy_map)); - if (SCHInfoAddHostOSInfo("bamboo", "192.168.1.1", SC_HINFO_IS_IPV4) != -1) { - goto end; - } - if (SCHInfoAddHostOSInfo("linux", "192.168.1.1", SC_HINFO_IS_IPV4) != - SCMapEnumNameToValue("linux", sc_hinfo_os_policy_map)) { - goto end; - } - if (SCHInfoAddHostOSInfo("windows", "192.168.1.1", SC_HINFO_IS_IPV4) != - SCMapEnumNameToValue("windows", sc_hinfo_os_policy_map)) { - goto end; - } - if (SCHInfoAddHostOSInfo("solaris", "192.168.1.1", SC_HINFO_IS_IPV4) != - SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)) { - goto end; - } - if (SCHInfoAddHostOSInfo("hpux10", "192.168.1.1", SC_HINFO_IS_IPV4) != - SCMapEnumNameToValue("hpux10", sc_hinfo_os_policy_map)) { - goto end; - } - if (SCHInfoAddHostOSInfo("hpux11", "192.168.1.1", SC_HINFO_IS_IPV4) != - SCMapEnumNameToValue("hpux11", sc_hinfo_os_policy_map)) { - goto end; - } - if (SCHInfoAddHostOSInfo("irix", "192.168.1.1", SC_HINFO_IS_IPV4) != - SCMapEnumNameToValue("irix", sc_hinfo_os_policy_map)) { - goto end; - } - if (SCHInfoAddHostOSInfo("bsd", "192.168.1.1", SC_HINFO_IS_IPV4) != - SCMapEnumNameToValue("bsd", sc_hinfo_os_policy_map)) { - goto end; - } - if (SCHInfoAddHostOSInfo("old_linux", "192.168.1.1", SC_HINFO_IS_IPV4) != - SCMapEnumNameToValue("old_linux", sc_hinfo_os_policy_map)) { - goto end; - } - if (SCHInfoAddHostOSInfo("macos", "192.168.1.1", SC_HINFO_IS_IPV4) != - SCMapEnumNameToValue("macos", sc_hinfo_os_policy_map)) { - goto end; - } - if (SCHInfoAddHostOSInfo("vista", "192.168.1.1", SC_HINFO_IS_IPV4) != - SCMapEnumNameToValue("vista", sc_hinfo_os_policy_map)) { - goto end; - } - if (SCHInfoAddHostOSInfo("windows2k3", "192.168.1.1", SC_HINFO_IS_IPV4) != - SCMapEnumNameToValue("windows2k3", sc_hinfo_os_policy_map)) { - goto end; - } - - result = 1; - - end: SCHInfoCleanResources(); SCHInfoRestoreContextBackup(); - return result; + PASS; } /** @@ -1604,8 +1575,7 @@ void SCHInfoRegisterTests(void) #ifdef UNITTESTS - UtRegisterTest("SCHInfoTesInvalidOSFlavour01", - SCHInfoTestInvalidOSFlavour01); + UtRegisterTest("SCHInfoTestInvalidOSFlavour01", SCHInfoTestInvalidOSFlavour01); UtRegisterTest("SCHInfoTestInvalidIPV4Address02", SCHInfoTestInvalidIPV4Address02); UtRegisterTest("SCHInfoTestInvalidIPV6Address03", From 8f03a2eb9b0862cbb072cac59dfbfb487e0ba7ef Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 18 May 2022 14:32:35 +0200 Subject: [PATCH 02/14] radix: implement more compact trees Implement a more compact set of trees specifically for IPv4 and IPv6 addresses. This allows for more compact data structures and fewer memory allocations. Based on the existing radix tree implementation. --- src/Makefile.am | 5 + src/runmode-unittests.c | 4 + src/util-radix-tree-common.h | 966 +++++++++++++++++++++++++++++++++++ src/util-radix4-tree.c | 940 ++++++++++++++++++++++++++++++++++ src/util-radix4-tree.h | 119 +++++ src/util-radix6-tree.c | 963 ++++++++++++++++++++++++++++++++++ src/util-radix6-tree.h | 117 +++++ 7 files changed, 3114 insertions(+) create mode 100644 src/util-radix-tree-common.h create mode 100644 src/util-radix4-tree.c create mode 100644 src/util-radix4-tree.h create mode 100644 src/util-radix6-tree.c create mode 100644 src/util-radix6-tree.h diff --git a/src/Makefile.am b/src/Makefile.am index b0f841cfd0c2..665da6e0a59e 100755 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -542,6 +542,9 @@ noinst_HEADERS = \ util-profiling-locks.h \ util-proto-name.h \ util-radix-tree.h \ + util-radix-tree-common.h \ + util-radix4-tree.h \ + util-radix6-tree.h \ util-random.h \ util-reference-config.h \ util-rohash.h \ @@ -1089,6 +1092,8 @@ libsuricata_c_a_SOURCES = \ util-profiling-rules.c \ util-proto-name.c \ util-radix-tree.c \ + util-radix4-tree.c \ + util-radix6-tree.c \ util-random.c \ util-reference-config.c \ util-rohash.c \ diff --git a/src/runmode-unittests.c b/src/runmode-unittests.c index 35780ab101a0..104f7ea78172 100644 --- a/src/runmode-unittests.c +++ b/src/runmode-unittests.c @@ -65,6 +65,8 @@ #include "util-action.h" #include "util-radix-tree.h" +#include "util-radix4-tree.h" +#include "util-radix6-tree.h" #include "util-host-os-info.h" #include "util-cidr.h" #include "util-unittest-helper.h" @@ -172,6 +174,8 @@ static void RegisterUnittests(void) IPPairRegisterUnittests(); SCSigRegisterSignatureOrderingTests(); SCRadixRegisterTests(); + SCRadix4RegisterTests(); + SCRadix6RegisterTests(); DefragRegisterTests(); SigGroupHeadRegisterTests(); SCHInfoRegisterTests(); diff --git a/src/util-radix-tree-common.h b/src/util-radix-tree-common.h new file mode 100644 index 000000000000..8251b42aa544 --- /dev/null +++ b/src/util-radix-tree-common.h @@ -0,0 +1,966 @@ +/* Copyright (C) 2007-2022 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + * \author Anoop Saldanha + * + * Implementation of radix trees + */ + +#include "util-validate.h" + +#ifndef ADDRESS_BYTES +#error "define ADDRESS_BYTES" +#endif +#ifndef NETMASK_MAX +#error "define NETMASK_MAX" +#endif + +#define RADIX_BITTEST(x, y) ((x) & (y)) + +/** + * \brief Structure that hold the user data and the netmask associated with it. + */ +typedef struct RadixUserData { + /* holds a pointer to the user data associated with the particular netmask */ + void *user; + /* pointer to the next user data in the list */ + struct RadixUserData *next; + /* holds the netmask value that corresponds to this user data pointer */ + uint8_t netmask; +} RadixUserData; + +/** + * \brief Allocates and returns a new instance of RadixUserData. + * + * \param netmask The netmask entry (cidr) that has to be made in the new + * RadixUserData instance + * \param user The user data that has to be set for the above + * netmask in the newly created RadixUserData instance. + * + * \retval user_data Pointer to a new instance of RadixUserData. + */ +static RadixUserData *AllocUserData(uint8_t netmask, void *user) +{ + RadixUserData *user_data = SCCalloc(1, sizeof(RadixUserData)); + if (unlikely(user_data == NULL)) { + sc_errno = SC_ENOMEM; + return NULL; + } + user_data->netmask = netmask; + user_data->user = user; + return user_data; +} + +/** + * \brief Deallocates an instance of RadixUserData. + * + * \param user_data Pointer to the instance of RadixUserData that has to be + * freed. + */ +static void FreeUserData(RadixUserData *user_data) +{ + SCFree(user_data); +} + +/** + * \brief Appends a user_data instance(RadixUserData) to a + * user_data(RadixUserData) list. We add the new entry in descending + * order with respect to the netmask contained in the RadixUserData. + * + * \param new Pointer to the RadixUserData to be added to the list. + * \param list Pointer to the RadixUserData list head, to which "new" has to + * be appended. + */ +static void AppendToUserDataList(RadixUserData *add, RadixUserData **list) +{ + RadixUserData *temp = NULL; + + BUG_ON(add == NULL || list == NULL); + + /* add to the list in descending order. The reason we do this is for + * optimizing key retrieval for a ip key under a netblock */ + RadixUserData *prev = temp = *list; + while (temp != NULL) { + if (add->netmask > temp->netmask) + break; + prev = temp; + temp = temp->next; + } + + if (temp == *list) { + add->next = *list; + *list = add; + } else { + add->next = prev->next; + prev->next = add; + } +} + +/** + * \brief Adds a netmask and its user_data for a particular prefix stream. + * + * \param prefix The prefix stream to which the netmask and its corresponding + * user data has to be added. + * \param netmask The netmask value (cidr) that has to be added to the prefix. + * \param user The pointer to the user data corresponding to the above + * netmask. + */ +static void AddNetmaskUserDataToNode(RADIX_NODE_TYPE *node, uint8_t netmask, void *user) +{ + BUG_ON(!node); + AppendToUserDataList(AllocUserData(netmask, user), &node->user_data); +} + +/** + * \brief Removes a particular user_data corresponding to a particular netmask + * entry, from a prefix. + * + * \param prefix Pointer to the prefix from which the user_data/netmask entry + * has to be removed. + * \param netmask The netmask value (cidr) whose user_data has to be deleted. + */ +static void RemoveNetmaskUserDataFromNode(RADIX_NODE_TYPE *node, uint8_t netmask) +{ + BUG_ON(!node); + + RadixUserData *temp = NULL, *prev = NULL; + prev = temp = node->user_data; + while (temp != NULL) { + if (temp->netmask == netmask) { + if (temp == node->user_data) + node->user_data = temp->next; + else + prev->next = temp->next; + + FreeUserData(temp); + break; + } + prev = temp; + temp = temp->next; + } +} + +/** + * \brief Indicates if prefix contains an entry for an ip with a specific netmask. + * + * \param prefix Pointer to the ip prefix that is being checked. + * \param netmask The netmask value (cidr) that has to be checked for + * presence in the prefix. + * + * \retval 1 On match. + * \retval 0 On no match. + */ +static int ContainNetmask(RADIX_NODE_TYPE *node, uint8_t netmask) +{ + BUG_ON(!node); + RadixUserData *user_data = node->user_data; + while (user_data != NULL) { + if (user_data->netmask == netmask) + return 1; + user_data = user_data->next; + } + return 0; +} + +/** + * \brief Returns the total netmask count for this prefix. + * + * \param prefix Pointer to the prefix + * + * \retval count The total netmask count for this prefix. + */ +static int NetmaskCount(RADIX_NODE_TYPE *node) +{ + BUG_ON(!node); + uint32_t count = 0; + RadixUserData *user_data = node->user_data; + while (user_data != NULL) { + count++; + user_data = user_data->next; + } + return count; +} + +/** + * \brief Indicates if prefix contains an entry for an ip with a specific netmask + * and if it does, it sets `user_data_result` to the netmask user_data entry. + * + * \param prefix Pointer to the ip prefix that is being checked. + * \param netmask The netmask value for which we will have to return the user_data + * \param exact_match Bool flag which indicates if we should check if the prefix + * holds proper netblock or not. + * \param[out] user_data_result user data pointer + * + * \retval 1 On match. + * \retval 0 On no match. + */ +static int ContainNetmaskAndSetUserData( + RADIX_NODE_TYPE *node, uint8_t netmask, bool exact_match, void **user_data_result) +{ + BUG_ON(!node); + + RadixUserData *user_data = node->user_data; + /* Check if we have a match for an exact ip. An exact ip as in not a proper + * netblock, i.e. an ip with a netmask of 32. */ + if (exact_match) { + if (user_data->netmask == netmask) { + if (user_data_result) + *user_data_result = user_data->user; + return 1; + } else { + goto no_match; + } + } + + /* Check for the user_data entry for this netmask_value */ + while (user_data != NULL) { + if (user_data->netmask == netmask) { + if (user_data_result) + *user_data_result = user_data->user; + return 1; + } + user_data = user_data->next; + } + +no_match: + if (user_data_result != NULL) + *user_data_result = NULL; + return 0; +} + +/** + * \brief Creates a new node for the Radix tree + * + * \retval node The newly created node for the radix tree + */ +static inline RADIX_NODE_TYPE *RadixCreateNode(void) +{ + RADIX_NODE_TYPE *node = NULL; + + if ((node = SCCalloc(1, sizeof(RADIX_NODE_TYPE))) == NULL) { + sc_errno = SC_ENOMEM; + return NULL; + } + node->bit = NETMASK_MAX; + return node; +} + +/** + * \brief Frees a Radix tree node + * + * \param node Pointer to a Radix tree node + * \param tree Pointer to the Radix tree to which this node belongs + */ +static void ReleaseNode( + RADIX_NODE_TYPE *node, RADIX_TREE_TYPE *tree, const RADIX_CONFIG_TYPE *config) +{ + DEBUG_VALIDATE_BUG_ON(config == NULL); + if (node != NULL) { + RadixUserData *ud = node->user_data; + while (ud != NULL) { + RadixUserData *next = ud->next; + if (config->Free != NULL && ud->user) { + config->Free(ud->user); + } + FreeUserData(ud); + ud = next; + } + SCFree(node); + } +} + +/** + * \brief Internal helper function used by TreeRelease to free a subtree + * + * \param node Pointer to the root of the subtree that has to be freed + * \param tree Pointer to the Radix tree to which this subtree belongs + */ +static void ReleaseSubtree( + RADIX_NODE_TYPE *node, RADIX_TREE_TYPE *tree, const RADIX_CONFIG_TYPE *config) +{ + DEBUG_VALIDATE_BUG_ON(config == NULL); + if (node != NULL) { + ReleaseSubtree(node->left, tree, config); + ReleaseSubtree(node->right, tree, config); + ReleaseNode(node, tree, config); + } +} + +/** + * \brief frees a Radix tree and all its nodes + * + * \param tree Pointer to the Radix tree that has to be freed + */ +static void TreeRelease(RADIX_TREE_TYPE *tree, const RADIX_CONFIG_TYPE *config) +{ + DEBUG_VALIDATE_BUG_ON(config == NULL); + if (tree == NULL) + return; + + ReleaseSubtree(tree->head, tree, config); + tree->head = NULL; + return; +} + +/** + * \brief Adds a key to the Radix tree. Used internally by the API. + * + * \param tree Pointer to the Radix tree + * \param key_stream Data that has to added to the Radix tree + * \param netmask The netmask (cidr) + * \param user Pointer to the user data that has to be associated with + * this key + * \param exclusive True if the node should be added iff it doesn't exist. + * + * \retval node Pointer to the newly created node + */ +static RADIX_NODE_TYPE *AddKey(RADIX_TREE_TYPE *tree, const RADIX_CONFIG_TYPE *config, + const uint8_t *key_stream, uint8_t netmask, void *user, const bool exclusive) +{ + DEBUG_VALIDATE_BUG_ON(config == NULL); + RADIX_NODE_TYPE *node = NULL; + RADIX_NODE_TYPE *parent = NULL; + RADIX_NODE_TYPE *bottom_node = NULL; + + uint8_t tmp_stream[ADDRESS_BYTES]; + memcpy(tmp_stream, key_stream, sizeof(tmp_stream)); + + if (tree == NULL) { + SCLogError("Argument \"tree\" NULL"); + sc_errno = SC_EINVAL; + return NULL; + } + + /* chop the ip address against a netmask */ + MaskIPNetblock(tmp_stream, netmask, NETMASK_MAX); + + /* the very first element in the radix tree */ + if (tree->head == NULL) { + node = RadixCreateNode(); + if (node == NULL) + return NULL; + memcpy(node->prefix_stream, tmp_stream, sizeof(tmp_stream)); + node->has_prefix = true; + node->user_data = AllocUserData(netmask, user); + if (node->user_data == NULL) { + ReleaseNode(node, tree, config); + return NULL; + } + tree->head = node; + if (netmask == NETMASK_MAX) + return node; + + AddNetmaskToMasks(node, netmask); + return node; + } + node = tree->head; + + /* we walk down the tree only when we satisfy 2 conditions. The first one + * being the incoming prefix is shorter than the differ bit of the current + * node. In case we fail in this aspect, we walk down to the tree, till we + * arrive at a node that ends in a prefix */ + while (node->bit < NETMASK_MAX || node->has_prefix == false) { + /* if the bitlen isn't long enough to handle the bit test, we just walk + * down along one of the paths, since either paths should end up with a + * node that has a common prefix whose differ bit is greater than the + * bitlen of the incoming prefix */ + if (NETMASK_MAX <= node->bit) { + if (node->right == NULL) + break; + node = node->right; + } else { + if (RADIX_BITTEST(tmp_stream[node->bit >> 3], (0x80 >> (node->bit % 8)))) { + if (node->right == NULL) + break; + node = node->right; + } else { + if (node->left == NULL) + break; + node = node->left; + } + } + } + + /* we need to keep a reference to the bottom-most node, that actually holds + * the prefix */ + bottom_node = node; + + /* get the first bit position where the ips differ */ + uint8_t check_bit = MIN(node->bit, NETMASK_MAX); + uint8_t differ_bit = 0; + uint8_t j = 0; + for (uint8_t i = 0; (i * 8) < check_bit; i++) { + int temp = 0; + if ((temp = (tmp_stream[i] ^ bottom_node->prefix_stream[i])) == 0) { + differ_bit = (i + 1) * 8; + continue; + } + + /* find out the position where the first bit differs. This method is + * faster, but at the cost of being larger. But with larger caches + * these days we don't have to worry about cache misses */ + temp = temp * 2; + if (temp >= 256) + j = 0; + else if (temp >= 128) + j = 1; + else if (temp >= 64) + j = 2; + else if (temp >= 32) + j = 3; + else if (temp >= 16) + j = 4; + else if (temp >= 8) + j = 5; + else if (temp >= 4) + j = 6; + else if (temp >= 2) + j = 7; + + differ_bit = i * 8 + j; + break; + } + if (check_bit < differ_bit) + differ_bit = check_bit; + + /* walk up the tree till we find the position, to fit our new node in */ + parent = node->parent; + while (parent && differ_bit <= parent->bit) { + node = parent; + parent = node->parent; + } + BUG_ON(differ_bit == NETMASK_MAX && node->bit != NETMASK_MAX); + + /* We already have the node in the tree with the same differing bit position */ + if (differ_bit == NETMASK_MAX && node->bit == NETMASK_MAX) { + if (node->has_prefix) { + /* Check if we already have this netmask entry covered by this prefix */ + if (ContainNetmask(node, netmask)) { + /* Basically we already have this stream prefix, as well as the + * netblock entry for this. A perfect duplicate. */ + if (exclusive) { + SCLogDebug("not inserting since it already exists"); + sc_errno = SC_EEXIST; + return NULL; + } + SCLogDebug("Duplicate entry for this ip address/netblock"); + } else { + /* Basically we already have this stream prefix, but we don't + * have an entry for this particular netmask value for this + * prefix. For example, we have an entry for 192.168.0.0 and + * 192.168.0.0/16 and now we are trying to enter 192.168.0.0/20 */ + AddNetmaskUserDataToNode(node, netmask, user); + + /* if we are adding a netmask of 32 it indicates we are adding + * an exact host ip into the radix tree, in which case we don't + * need to add the netmask value into the tree */ + if (netmask == NETMASK_MAX) + return node; + + /* looks like we have a netmask which is != 32, in which + * case we walk up the tree to insert this netmask value in the + * correct node */ + parent = node->parent; + while (parent != NULL && netmask < (parent->bit + 1)) { + node = parent; + parent = parent->parent; + } + + AddNetmaskToMasks(node, netmask); + if (NetmaskEqualsMask(node, netmask)) { + return node; + } + } + } + return node; + } + + /* create the leaf node for the new key */ + RADIX_NODE_TYPE *new_node = RadixCreateNode(); + if (new_node == NULL) + return NULL; + memcpy(new_node->prefix_stream, tmp_stream, sizeof(tmp_stream)); + new_node->has_prefix = true; + new_node->user_data = AllocUserData(netmask, user); + if (new_node->user_data == NULL) { + ReleaseNode(new_node, tree, config); + return NULL; + } + + /* stick our new_node into the tree. Create a node that holds the + * differing bit position and break the branch. Also handle the + * tranfer of netmasks between node and inter_node(explained in more + * detail below) */ + RADIX_NODE_TYPE *inter_node = RadixCreateNode(); + if (inter_node == NULL) { + ReleaseNode(new_node, tree, config); + return NULL; + } + inter_node->has_prefix = false; + inter_node->bit = differ_bit; + inter_node->parent = node->parent; + SCLogDebug("inter_node: differ_bit %u", differ_bit); + + /* update netmasks for node and set them for inter_node */ + ProcessInternode(node, inter_node); + + if (RADIX_BITTEST(tmp_stream[differ_bit >> 3], (0x80 >> (differ_bit % 8)))) { + inter_node->left = node; + inter_node->right = new_node; + } else { + inter_node->left = new_node; + inter_node->right = node; + } + new_node->parent = inter_node; + + if (node->parent == NULL) + tree->head = inter_node; + else if (node->parent->right == node) + node->parent->right = inter_node; + else + node->parent->left = inter_node; + + node->parent = inter_node; + + /* insert the netmask into the tree */ + if (netmask != NETMASK_MAX) { + node = new_node; + parent = new_node->parent; + while (parent != NULL && netmask < (parent->bit + 1)) { + node = parent; + parent = parent->parent; + } + AddNetmaskToMasks(node, netmask); + } + return new_node; +} + +/** + * \brief Removes a netblock entry from an ip node. The function first + * deletes the netblock/user_data entry for the prefix and then + * removes the netmask entry that has been made in the tree, by + * walking up the tree and deleting the entry from the specific node. + * + * \param node The node from which the netblock entry has to be removed. + * \param netmask The netmask entry (cidr) that has to be removed. + */ +static void RemoveNetblockEntry(RADIX_NODE_TYPE *node, uint8_t netmask) +{ + BUG_ON(!node); + + RemoveNetmaskUserDataFromNode(node, netmask); + + if (netmask == NETMASK_MAX) { + SCLogDebug("%d == %d", netmask, NETMASK_MAX); + return; + } + + RemoveNetmaskFromMasks(node, netmask); + if (node->parent != NULL) + RemoveNetmaskFromMasks(node->parent, netmask); + return; +} + +/** + * \brief Removes a key from the Radix tree + * + * \param key_stream Data that has to be removed from the Radix tree + * \param tree Pointer to the Radix tree from which the key has to be + * removed + */ +static void RemoveKey(RADIX_TREE_TYPE *tree, const RADIX_CONFIG_TYPE *config, + const uint8_t *key_stream, const uint8_t netmask) +{ + RADIX_NODE_TYPE *node = tree->head; + RADIX_NODE_TYPE *parent = NULL; + RADIX_NODE_TYPE *temp_dest = NULL; + + if (node == NULL) { + SCLogDebug("tree is empty"); + return; + } + + uint8_t tmp_stream[ADDRESS_BYTES]; + memcpy(tmp_stream, key_stream, sizeof(tmp_stream)); + + while (node->bit < NETMASK_MAX) { + if (RADIX_BITTEST(tmp_stream[node->bit >> 3], (0x80 >> (node->bit % 8)))) { + node = node->right; + } else { + node = node->left; + } + + if (node == NULL) { + SCLogDebug("no matching node found"); + return; + } + } + + if (node->bit != NETMASK_MAX || node->has_prefix == false) { + SCLogDebug("node %p bit %d != %d, or not has_prefix %s", node, node->bit, NETMASK_MAX, + node->has_prefix ? "true" : "false"); + return; + } + + if (SCMemcmp(node->prefix_stream, tmp_stream, sizeof(tmp_stream)) == 0) { + if (!ContainNetmask(node, netmask)) { + SCLogDebug("key exists in the tree, but this (%d) " + "netblock entry doesn't exist", + netmask); + return; + } + } else { + SCLogDebug("You are trying to remove a key that doesn't exist in the " + "Radix Tree"); + return; + } + + /* The ip node does exist, and the netblock entry does exist in this node, if + * we have reached this point. If we have more than one netblock entry, it + * indicates we have multiple entries for this key. So we delete that + * particular netblock entry, and make our way out of this function */ + if (NetmaskCount(node) > 1) { // || !NoneNegated(node)) { + RemoveNetblockEntry(node, netmask); + SCLogDebug("NetmaskCount"); + return; + } + SCLogDebug("not netmask cnt"); + + /* we are deleting the root of the tree. This would be the only node left + * in the tree */ + if (tree->head == node) { + ReleaseNode(node, tree, config); + tree->head = NULL; + SCLogDebug("tree->head == node"); + return; + } + + parent = node->parent; + /* parent->parent is not the root of the tree */ + if (parent->parent != NULL) { + if (parent->parent->left == parent) { + if (node->parent->left == node) { + temp_dest = parent->right; + parent->parent->left = parent->right; + parent->right->parent = parent->parent; + } else { + temp_dest = parent->left; + parent->parent->left = parent->left; + parent->left->parent = parent->parent; + } + } else { + if (node->parent->left == node) { + temp_dest = parent->right; + parent->parent->right = parent->right; + parent->right->parent = parent->parent; + } else { + temp_dest = parent->left; + parent->parent->right = parent->left; + parent->left->parent = parent->parent; + } + } + /* parent is the root of the tree */ + } else { + if (parent->left == node) { + temp_dest = tree->head->right; + tree->head->right->parent = NULL; + tree->head = tree->head->right; + } else { + temp_dest = tree->head->left; + tree->head->left->parent = NULL; + tree->head = tree->head->left; + } + } + /* We need to shift the netmask entries from the node that would be + * deleted to its immediate descendant */ + AddNetmasksFromNode(temp_dest, parent); + RemoveNetmaskFromMasks(temp_dest, netmask); + /* release the nodes */ + ReleaseNode(parent, tree, config); + ReleaseNode(node, tree, config); + + SCLogDebug("end (netmask %d)", netmask); + return; +} + +/** + * \brief Checks if an IP prefix falls under a netblock, in the path to the root + * of the tree, from the node. Used internally by FindKey() + * + * \param prefix Pointer to the prefix that contains the ip address + * \param node Pointer to the node from where we have to climb the tree + */ +static inline RADIX_NODE_TYPE *FindKeyIPNetblock(const uint8_t *key_stream, RADIX_NODE_TYPE *node, + void **user_data_result, uint8_t *out_netmask) +{ + while (node != NULL && NetmasksEmpty(node)) + node = node->parent; + if (node == NULL) + return NULL; + + uint8_t tmp_stream[ADDRESS_BYTES]; + memcpy(tmp_stream, key_stream, sizeof(tmp_stream)); + + /* hold the node found containing a netmask. We will need it when we call + * this function recursively */ + RADIX_NODE_TYPE *netmask_node = node; + + for (uint8_t j = 0; j <= NETMASK_MAX; j++) { + uint8_t m = NETMASK_MAX - j; + + if (!(NetmaskIssetInMasks(netmask_node, m))) + continue; + + for (uint8_t i = 0; i < ADDRESS_BYTES; i++) { + uint32_t mask = UINT_MAX; + if (((i + 1) * 8) > m) { + if (((i + 1) * 8 - m) < 8) + mask = UINT_MAX << ((i + 1) * 8 - m); + else + mask = 0; + } + tmp_stream[i] &= mask; + } + + while (node->bit < NETMASK_MAX) { + if (RADIX_BITTEST(tmp_stream[node->bit >> 3], (0x80 >> (node->bit % 8)))) { + node = node->right; + } else { + node = node->left; + } + + if (node == NULL) + return NULL; + } + + if (node->bit != NETMASK_MAX || node->has_prefix == false) + return NULL; + + if (SCMemcmp(node->prefix_stream, tmp_stream, sizeof(tmp_stream)) == 0) { + if (ContainNetmaskAndSetUserData(node, m, false, user_data_result)) { + *out_netmask = m; + return node; + } + } + } + + return FindKeyIPNetblock(tmp_stream, netmask_node->parent, user_data_result, out_netmask); +} + +/** + * \brief Checks if an IP address key is present in the tree. The function + * apart from handling any normal data, also handles ipv4/ipv6 netblocks + * + * \param key_stream Data that has to be found in the Radix tree + * \param tree Pointer to the Radix tree + * \param exact_match The key to be searched is an ip address + */ +static RADIX_NODE_TYPE *FindKey(const RADIX_TREE_TYPE *tree, const uint8_t *key_stream, + const uint8_t netmask, bool exact_match, void **user_data_result, uint8_t *out_netmask) +{ + if (tree == NULL || tree->head == NULL) + return NULL; + + RADIX_NODE_TYPE *node = tree->head; + uint8_t tmp_stream[ADDRESS_BYTES]; + memcpy(tmp_stream, key_stream, sizeof(tmp_stream)); + + while (node->bit < NETMASK_MAX) { + if (RADIX_BITTEST(tmp_stream[node->bit >> 3], (0x80 >> (node->bit % 8)))) { + node = node->right; + } else { + node = node->left; + } + + if (node == NULL) { + return NULL; + } + } + + if (node->bit != NETMASK_MAX || node->has_prefix == false) { + return NULL; + } + + if (SCMemcmp(node->prefix_stream, tmp_stream, sizeof(tmp_stream)) == 0) { + SCLogDebug("stream match"); + if (ContainNetmaskAndSetUserData(node, netmask, true, user_data_result)) { + SCLogDebug("contains netmask etc"); + *out_netmask = netmask; + return node; + } + } + + /* if you are not an ip key, get out of here */ + if (exact_match) { + SCLogDebug("no node found and need exact match, so failed"); + return NULL; + } + + RADIX_NODE_TYPE *ret = FindKeyIPNetblock(tmp_stream, node, user_data_result, out_netmask); + return ret; +} + +/** + * \brief Checks if an IPV4 address is present in the tree + * + * \param key_stream Data that has to be found in the Radix tree. In this case + * an IPV4 address + * \param tree Pointer to the Radix tree instance + */ +static RADIX_NODE_TYPE *FindExactMatch( + const RADIX_TREE_TYPE *tree, const uint8_t *key_stream, void **user_data_result) +{ + uint8_t unused = 0; + return FindKey(tree, key_stream, NETMASK_MAX, true, user_data_result, &unused); +} + +/** + * \brief Checks if an IPV4 address is present in the tree under a netblock + * + * \param key_stream Data that has to be found in the Radix tree. In this case + * an IPV4 address + * \param tree Pointer to the Radix tree instance + */ +static RADIX_NODE_TYPE *FindBestMatch( + const RADIX_TREE_TYPE *tree, const uint8_t *key_stream, void **user_data_result) +{ + uint8_t unused = 0; + return FindKey(tree, key_stream, NETMASK_MAX, false, user_data_result, &unused); +} + +static RADIX_NODE_TYPE *FindBestMatch2(const RADIX_TREE_TYPE *tree, const uint8_t *key_stream, + void **user_data_result, uint8_t *out_netmask) +{ + return FindKey(tree, key_stream, NETMASK_MAX, false, user_data_result, out_netmask); +} + +/** + * \brief Checks if an IPV4 Netblock address is present in the tree + * + * \param key_stream Data that has to be found in the Radix tree. In this case + * an IPV4 netblock address + * \param tree Pointer to the Radix tree instance + */ +static RADIX_NODE_TYPE *FindNetblock(const RADIX_TREE_TYPE *tree, const uint8_t *key_stream, + const uint8_t netmask, void **user_data_result) +{ + uint8_t unused = 0; + RADIX_NODE_TYPE *node = FindKey(tree, key_stream, netmask, true, user_data_result, &unused); + return node; +} + +/** + * \brief Helper function used by PrintTree. Prints the subtree with + * node as the root of the subtree + * + * \param node Pointer to the node that is the root of the subtree to be printed + * \param level Used for indentation purposes + */ +static void PrintSubtree(RADIX_NODE_TYPE *node, int level, void (*PrintData)(void *)) +{ + if (node != NULL) { + PrintNodeInfo(node, level, PrintData); + PrintSubtree(node->left, level + 1, PrintData); + PrintSubtree(node->right, level + 1, PrintData); + } + + return; +} + +/** + * \brief Prints the Radix Tree. While printing the radix tree we use the + * following format + * + * Parent_0 + * Left_Child_1 + * Left_Child_2 + * Right_Child_2 + * Right_Child_1 + * Left_Child_2 + * Right_Child_2 and so on + * + * Each node printed out holds details on the next bit that differs + * amongst its children, and if the node holds a prefix, the perfix is + * printed as well. + * + * \param tree Pointer to the Radix tree that has to be printed + */ +static void PrintTree(RADIX_TREE_TYPE *tree, const RADIX_CONFIG_TYPE *config) +{ + printf("Printing the Radix Tree: \n"); + PrintSubtree(tree->head, 0, config->PrintData); +} + +static bool CompareTreesSub( + RADIX_NODE_TYPE *n1, RADIX_NODE_TYPE *n2, RADIX_TREE_COMPARE_CALLBACK Callback) +{ + // compare nodes + bool n1_has_left = n1->left != NULL; + bool n2_has_left = n2->left != NULL; + if (n1_has_left != n2_has_left) + return false; + + bool n1_has_right = n1->right != NULL; + bool n2_has_right = n2->right != NULL; + if (n1_has_right != n2_has_right) + return false; + + if (SCMemcmp(n1->prefix_stream, n2->prefix_stream, ADDRESS_BYTES) != 0) + return false; + + RadixUserData *u1 = n1->user_data; + RadixUserData *u2 = n2->user_data; + while (1) { + if (u1 == NULL && u2 == NULL) + break; + if ((u1 != NULL && u2 == NULL) || (u1 == NULL && u2 != NULL)) + return false; + if (u1->netmask != u2->netmask) + return false; + + if (Callback != NULL) { + if (Callback(u1->user, u2->user) == false) + return false; + } + + u1 = u1->next; + u2 = u2->next; + } + + if (n1->left && n2->left) + if (CompareTreesSub(n1->left, n2->left, Callback) == false) + return false; + if (n1->right && n2->right) + if (CompareTreesSub(n1->right, n2->right, Callback) == false) + return false; + + return true; +} + +static bool CompareTrees( + const RADIX_TREE_TYPE *t1, const RADIX_TREE_TYPE *t2, RADIX_TREE_COMPARE_CALLBACK Callback) +{ + if (t1->head == NULL && t2->head == NULL) + return true; + if ((t1->head == NULL && t2->head != NULL) || (t1->head != NULL && t2->head == NULL)) + return false; + return CompareTreesSub(t1->head, t2->head, Callback); +} diff --git a/src/util-radix4-tree.c b/src/util-radix4-tree.c new file mode 100644 index 000000000000..30031dc183b2 --- /dev/null +++ b/src/util-radix4-tree.c @@ -0,0 +1,940 @@ +/* Copyright (C) 2007-2022 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + * \author Anoop Saldanha + * + * Implementation of radix tree for IPv4 + */ + +#include "suricata-common.h" +#include "util-debug.h" +#include "util-error.h" +#include "util-ip.h" +#include "util-unittest.h" +#include "util-memcmp.h" +#include "util-print.h" +#include "util-byte.h" +#include "util-radix4-tree.h" + +#define ADDRESS_BYTES (uint8_t)4 +#define NETMASK_MAX (uint8_t)32 + +#define RADIX_TREE_TYPE SCRadix4Tree +#define RADIX_NODE_TYPE SCRadix4Node +#define RADIX_CONFIG_TYPE SCRadix4Config +#define RADIX_TREE_COMPARE_CALLBACK SCRadix4TreeCompareFunc + +static void PrintUserdata(SCRadix4Node *node, int level, void (*PrintData)(void *)); + +static inline void AddNetmaskToMasks(SCRadix4Node *node, int netmask) +{ + SCLogDebug("masks %" PRIX64 ", adding %d/%" PRIX64, (uint64_t)node->masks, netmask, + (uint64_t)BIT_U64(netmask)); + node->masks |= BIT_U64(netmask); + SCLogDebug("masks %" PRIX64, (uint64_t)node->masks); +} + +static inline void RemoveNetmaskFromMasks(SCRadix4Node *node, int netmask) +{ + SCLogDebug("masks %" PRIX64 ", removing %d/%" PRIX64, (uint64_t)node->masks, netmask, + (uint64_t)BIT_U64(netmask)); + node->masks &= ~BIT_U64(netmask); + SCLogDebug("masks %" PRIX64, (uint64_t)node->masks); +} + +static inline void AddNetmasksFromNode(SCRadix4Node *dst, SCRadix4Node *src) +{ + dst->masks |= src->masks; +} + +static inline bool NetmasksEmpty(const SCRadix4Node *node) +{ + return (node->masks == 0); +} + +static inline bool NetmaskEqualsMask(const SCRadix4Node *node, int netmask) +{ + return (node->masks == BIT_U64(netmask)); +} + +static inline bool NetmaskIssetInMasks(const SCRadix4Node *node, int netmask) +{ + return ((node->masks & BIT_U64(netmask)) != 0); +} + +static inline void ProcessInternode(SCRadix4Node *node, SCRadix4Node *inter_node) +{ + const int differ_bit = inter_node->bit; + uint64_t rem = 0; + for (int x = 0; x <= NETMASK_MAX; x++) { + int m = NETMASK_MAX - x; + if (m == differ_bit) + break; + else { + rem |= (node->masks & BIT_U64(m)); + } + } + + inter_node->masks |= node->masks; + inter_node->masks &= ~rem; + node->masks = rem; +} + +/** + * \brief Prints the node information from a Radix4 tree + * + * \param node Pointer to the Radix4 node whose information has to be printed + * \param level Used for indentation purposes + */ +static void PrintNodeInfo(SCRadix4Node *node, int level, void (*PrintData)(void *)) +{ + if (node == NULL) + return; + + for (int i = 0; i < level; i++) + printf(" "); + + printf("%d [", node->bit); + + if (node->masks == 0) { + printf(" - "); + } else { + for (int i = 0, x = 0; i <= 32; i++) { + if (node->masks & BIT_U64(i)) { + printf("%s%d", (x && x < 32) ? ", " : "", i); + x++; + } + } + } + printf("] ("); + + if (node->has_prefix) { + char addr[16] = ""; + PrintInet(AF_INET, &node->prefix_stream, addr, sizeof(addr)); + printf("%s - user_data %p)\n", addr, node->user_data); + PrintUserdata(node, level + 1, PrintData); + } else { + printf("no prefix)\n"); + } + return; +} + +#include "util-radix-tree-common.h" + +SCRadix4Node *SCRadix4TreeFindExactMatch( + const SCRadix4Tree *tree, const uint8_t *key, void **user_data) +{ + return FindExactMatch(tree, key, user_data); +} + +SCRadix4Node *SCRadix4TreeFindNetblock( + const SCRadix4Tree *tree, const uint8_t *key, const uint8_t netmask, void **user_data) +{ + return FindNetblock(tree, key, netmask, user_data); +} + +SCRadix4Node *SCRadix4TreeFindBestMatch( + const SCRadix4Tree *tree, const uint8_t *key, void **user_data) +{ + return FindBestMatch(tree, key, user_data); +} + +SCRadix4Node *SCRadix4TreeFindBestMatch2( + const SCRadix4Tree *tree, const uint8_t *key, void **user_data, uint8_t *out_netmask) +{ + return FindBestMatch2(tree, key, user_data, out_netmask); +} + +SCRadix4Tree SCRadix4TreeInitialize(void) +{ + SCRadix4Tree t = SC_RADIX4_TREE_INITIALIZER; + return t; +} + +void SCRadix4TreeRelease(SCRadix4Tree *tree, const SCRadix4Config *config) +{ + TreeRelease(tree, config); +} + +/** + * \brief Adds a new IPV4 address to the Radix4 tree + * + * \param key_stream Data that has to be added to the Radix4 tree. In this case + * a pointer to an IPV4 address + * \param tree Pointer to the Radix4 tree + * \param user Pointer to the user data that has to be associated with the + * key + * + * \retval node Pointer to the newly created node + */ +SCRadix4Node *SCRadix4AddKeyIPV4( + SCRadix4Tree *tree, const SCRadix4Config *config, const uint8_t *key_stream, void *user) +{ + return AddKey(tree, config, key_stream, 32, user, false); +} + +/** + * \brief Adds a new IPV4 netblock to the Radix4 tree + * + * \param key_stream Data that has to be added to the Radix4 tree. In this case + * a pointer to an IPV4 netblock + * \param tree Pointer to the Radix4 tree + * \param user Pointer to the user data that has to be associated with the + * key + * \param netmask The netmask (cidr) if we are adding a netblock + * + * \retval node Pointer to the newly created node + */ +SCRadix4Node *SCRadix4AddKeyIPV4Netblock(SCRadix4Tree *tree, const SCRadix4Config *config, + const uint8_t *key_stream, uint8_t netmask, void *user) +{ + return AddKey(tree, config, key_stream, netmask, user, false); +} + +/** + * \brief Adds a new IPV4/netblock to the Radix4 tree from a string + * + * \param str IPV4 string with optional /cidr netmask + * \param tree Pointer to the Radix4 tree + * \param user Pointer to the user data that has to be associated with + * the key + * + * \retval bool true if node was added, false otherwise + * + * If the function returns false, `sc_errno` is set: + * - SC_EEXIST: Node already exists + * - SC_EINVAL: Parameter value error + * - SC_ENOMEM: Memory allocation failed + */ +bool SCRadix4AddKeyIPV4String( + SCRadix4Tree *tree, const SCRadix4Config *config, const char *str, void *user) +{ + uint32_t ip; + uint8_t netmask = 32; + char ip_str[32]; /* Max length for full ipv4/mask string with NUL */ + char *mask_str = NULL; + struct in_addr addr; + + /* Make a copy of the string so it can be modified */ + strlcpy(ip_str, str, sizeof(ip_str) - 2); + *(ip_str + (sizeof(ip_str) - 1)) = '\0'; + + /* Does it have a mask? */ + if (NULL != (mask_str = strchr(ip_str, '/'))) { + *(mask_str++) = '\0'; + + /* Dotted type netmask not supported */ + if (strchr(mask_str, '.') != NULL) { + sc_errno = SC_EINVAL; + return false; + } + + uint8_t cidr; + if (StringParseU8RangeCheck(&cidr, 10, 0, (const char *)mask_str, 0, 32) < 0) { + sc_errno = SC_EINVAL; + return false; + } + netmask = (uint8_t)cidr; + } + + /* Validate the IP */ + if (inet_pton(AF_INET, ip_str, &addr) <= 0) { + sc_errno = SC_EINVAL; + return false; + } + ip = addr.s_addr; + + if (AddKey(tree, config, (uint8_t *)&ip, netmask, user, true) == NULL) { + DEBUG_VALIDATE_BUG_ON(sc_errno == SC_OK); + return false; + } + return true; +} + +/** + * \brief Removes an IPV4 address key(not a netblock) from the Radix4 tree. + * Instead of using this function, we can also used + * SCRadix4RemoveKeyIPV4Netblock(), by supplying a netmask value of 32. + * + * \param key_stream Data that has to be removed from the Radix4 tree. In this + * case an IPV4 address + * \param tree Pointer to the Radix4 tree from which the key has to be + * removed + */ +void SCRadix4RemoveKeyIPV4( + SCRadix4Tree *tree, const SCRadix4Config *config, const uint8_t *key_stream) +{ + RemoveKey(tree, config, key_stream, 32); +} + +/** + * \brief Removes an IPV4 address netblock key from the Radix4 tree. + * + * \param key_stream Data that has to be removed from the Radix4 tree. In this + * case an IPV4 address + * \param tree Pointer to the Radix4 tree from which the key has to be + * removed + */ +void SCRadix4RemoveKeyIPV4Netblock(SCRadix4Tree *tree, const SCRadix4Config *config, + const uint8_t *key_stream, uint8_t netmask) +{ + SCLogNotice("removing with netmask %u", netmask); + RemoveKey(tree, config, key_stream, netmask); +} + +void SCRadix4PrintTree(SCRadix4Tree *tree, const SCRadix4Config *config) +{ + PrintTree(tree, config); +} + +static void PrintUserdata(SCRadix4Node *node, int level, void (*PrintData)(void *)) +{ + if (PrintData != NULL) { + RadixUserData *ud = node->user_data; + while (ud != NULL) { + for (int i = 0; i < level; i++) + printf(" "); + printf("[%d], ", ud->netmask); + PrintData(ud->user); + ud = ud->next; + } + } else { + RadixUserData *ud = node->user_data; + while (ud != NULL) { + for (int i = 0; i < level; i++) + printf(" "); + printf(" [%d], ", ud->netmask); + ud = ud->next; + } + } +} + +static int SCRadix4ForEachNodeSub( + const SCRadix4Node *node, SCRadix4ForEachNodeFunc Callback, void *data) +{ + BUG_ON(!node); + + /* invoke callback for each stored user data */ + for (RadixUserData *ud = node->user_data; ud != NULL; ud = ud->next) { + if (Callback(node, ud->user, ud->netmask, data) < 0) + return -1; + } + + if (node->left) { + if (SCRadix4ForEachNodeSub(node->left, Callback, data) < 0) + return -1; + } + if (node->right) { + if (SCRadix4ForEachNodeSub(node->right, Callback, data) < 0) + return -1; + } + return 0; +} + +int SCRadix4ForEachNode(const SCRadix4Tree *tree, SCRadix4ForEachNodeFunc Callback, void *data) +{ + if (tree->head == NULL) + return 0; + return SCRadix4ForEachNodeSub(tree->head, Callback, data); +} + +bool SCRadix4CompareTrees( + const SCRadix4Tree *t1, const SCRadix4Tree *t2, SCRadix4TreeCompareFunc Callback) +{ + return CompareTrees(t1, t2, Callback); +} + +/*------------------------------------Unit_Tests------------------------------*/ + +#ifdef UNITTESTS + +static const SCRadix4Config ut_ip_radix4_config = { NULL, NULL }; + +#define GET_IPV4(str) \ + SCLogDebug("setting up %s", (str)); \ + memset(&(sa), 0, sizeof((sa))); \ + FAIL_IF(inet_pton(AF_INET, (str), &(sa).sin_addr) <= 0); + +#define ADD_IPV4(str) \ + GET_IPV4((str)); \ + SCRadix4AddKeyIPV4(&tree, &ut_ip_radix4_config, (uint8_t *)&(sa).sin_addr, NULL); + +#define REM_IPV4(str) \ + GET_IPV4((str)); \ + SCRadix4RemoveKeyIPV4(&tree, &ut_ip_radix4_config, (uint8_t *)&(sa).sin_addr); + +#define ADD_IPV4_MASK(str, cidr) \ + GET_IPV4((str)); \ + SCRadix4AddKeyIPV4Netblock( \ + &tree, &ut_ip_radix4_config, (uint8_t *)&(sa).sin_addr, (cidr), NULL); + +#define REM_IPV4_MASK(str, cidr) \ + GET_IPV4((str)); \ + SCRadix4RemoveKeyIPV4Netblock(&tree, &ut_ip_radix4_config, (uint8_t *)&(sa).sin_addr, (cidr)); + +static int SCRadix4TestIPV4Insertion03(void) +{ + struct sockaddr_in sa; + SCRadix4Tree tree = SCRadix4TreeInitialize(); + + ADD_IPV4("192.168.1.1"); + ADD_IPV4("192.168.1.2"); + ADD_IPV4("192.167.1.3"); + ADD_IPV4("192.167.1.4"); + ADD_IPV4("192.167.1.4"); + + /* test for the existance of a key */ + GET_IPV4("192.168.1.6"); + FAIL_IF_NOT(SCRadix4TreeFindExactMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) == NULL); + + /* test for the existance of a key */ + GET_IPV4("192.167.1.4"); + FAIL_IF_NOT(SCRadix4TreeFindExactMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) != NULL); + + /* continue adding keys */ + ADD_IPV4("220.168.1.2"); + ADD_IPV4("192.168.1.5"); + ADD_IPV4("192.168.1.18"); + + /* test the existence of keys */ + GET_IPV4("192.168.1.3"); + FAIL_IF_NOT(SCRadix4TreeFindExactMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) == NULL); + GET_IPV4("127.234.2.62"); + FAIL_IF_NOT(SCRadix4TreeFindExactMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) == NULL); + + GET_IPV4("192.168.1.1"); + FAIL_IF_NOT(SCRadix4TreeFindExactMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) != NULL); + GET_IPV4("192.168.1.5"); + FAIL_IF_NOT(SCRadix4TreeFindExactMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) != NULL); + GET_IPV4("192.168.1.2"); + FAIL_IF_NOT(SCRadix4TreeFindExactMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) != NULL); + + GET_IPV4("192.167.1.3"); + FAIL_IF_NOT(SCRadix4TreeFindExactMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) != NULL); + GET_IPV4("192.167.1.4"); + FAIL_IF_NOT(SCRadix4TreeFindExactMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) != NULL); + GET_IPV4("220.168.1.2"); + FAIL_IF_NOT(SCRadix4TreeFindExactMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) != NULL); + GET_IPV4("192.168.1.18"); + FAIL_IF_NOT(SCRadix4TreeFindExactMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) != NULL); + + SCRadix4TreeRelease(&tree, &ut_ip_radix4_config); + + PASS; +} + +static int SCRadix4TestIPV4Removal04(void) +{ + struct sockaddr_in sa; + + SCRadix4Tree tree = SCRadix4TreeInitialize(); + + /* add the keys */ + ADD_IPV4("192.168.1.1"); + ADD_IPV4("192.168.1.2"); + ADD_IPV4("192.167.1.3"); + ADD_IPV4("192.167.1.4"); + ADD_IPV4("220.168.1.2"); + ADD_IPV4("192.168.1.5"); + ADD_IPV4("192.168.1.18"); + + /* remove the keys from the tree */ + REM_IPV4("192.168.1.1"); + REM_IPV4("192.167.1.3"); + REM_IPV4("192.167.1.4"); + REM_IPV4("192.168.1.18"); + + GET_IPV4("192.167.1.1"); + FAIL_IF_NOT(SCRadix4TreeFindExactMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) == NULL); + GET_IPV4("192.168.1.2"); + FAIL_IF_NOT(SCRadix4TreeFindExactMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) != NULL); + + REM_IPV4("192.167.1.3"); + REM_IPV4("220.168.1.2"); + + GET_IPV4("192.168.1.5"); + FAIL_IF_NOT(SCRadix4TreeFindExactMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) != NULL); + GET_IPV4("192.168.1.2"); + FAIL_IF_NOT(SCRadix4TreeFindExactMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) != NULL); + + REM_IPV4("192.168.1.2"); + REM_IPV4("192.168.1.5"); + + FAIL_IF_NOT_NULL(tree.head); + + SCRadix4TreeRelease(&tree, &ut_ip_radix4_config); + PASS; +} + +static int SCRadix4TestIPV4NetblockInsertion09(void) +{ + struct sockaddr_in sa; + SCRadix4Tree tree = SCRadix4TreeInitialize(); + + /* add the keys */ + ADD_IPV4("192.168.1.1"); + ADD_IPV4("192.168.1.2"); + ADD_IPV4("192.167.1.3"); + ADD_IPV4("192.167.1.4"); + ADD_IPV4("220.168.1.2"); + ADD_IPV4("192.168.1.5"); + ADD_IPV4("192.168.1.18"); + + ADD_IPV4_MASK("192.168.0.0", 16); + ADD_IPV4_MASK("192.171.128.0", 24); + ADD_IPV4_MASK("192.171.192.0", 18); + ADD_IPV4_MASK("192.175.0.0", 16); + + /* test for the existance of a key */ + GET_IPV4("192.168.1.6"); + FAIL_IF_NOT(SCRadix4TreeFindExactMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) == NULL); + GET_IPV4("192.170.1.6"); + FAIL_IF_NOT(SCRadix4TreeFindExactMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) == NULL); + GET_IPV4("192.171.128.145"); + FAIL_IF_NOT(SCRadix4TreeFindBestMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) != NULL); + GET_IPV4("192.171.64.6"); + FAIL_IF_NOT(SCRadix4TreeFindExactMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) == NULL); + GET_IPV4("192.171.191.6"); + FAIL_IF_NOT(SCRadix4TreeFindExactMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) == NULL); + GET_IPV4("192.171.224.6"); + FAIL_IF_NOT(SCRadix4TreeFindBestMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) != NULL); + GET_IPV4("192.171.224.6"); + FAIL_IF_NOT(SCRadix4TreeFindExactMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) == NULL); + GET_IPV4("192.175.224.6"); + FAIL_IF_NOT(SCRadix4TreeFindBestMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) != NULL); + + SCRadix4TreeRelease(&tree, &ut_ip_radix4_config); + PASS; +} + +static int SCRadix4TestIPV4NetblockInsertion10(void) +{ + SCRadix4Node *node[2]; + struct sockaddr_in sa; + SCRadix4Tree tree = SCRadix4TreeInitialize(); + + /* add the keys */ + ADD_IPV4_MASK("253.192.0.0", 16); + ADD_IPV4_MASK("253.192.235.0", 24); + ADD_IPV4_MASK("192.167.0.0", 16); + ADD_IPV4("192.167.1.4"); + ADD_IPV4_MASK("220.168.0.0", 16); + ADD_IPV4("253.224.1.5"); + ADD_IPV4_MASK("192.168.0.0", 16); + + GET_IPV4("192.171.128.0"); + node[0] = SCRadix4AddKeyIPV4Netblock( + &tree, &ut_ip_radix4_config, (uint8_t *)&sa.sin_addr, 24, NULL); + + GET_IPV4("192.171.128.45"); + node[1] = SCRadix4AddKeyIPV4(&tree, &ut_ip_radix4_config, (uint8_t *)&sa.sin_addr, NULL); + + ADD_IPV4_MASK("192.171.0.0", 18); + ADD_IPV4_MASK("192.175.0.0", 16); + + /* test for the existance of a key */ + GET_IPV4("192.171.128.53"); + FAIL_IF_NOT(SCRadix4TreeFindBestMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) == node[0]); + + GET_IPV4("192.171.128.45"); + FAIL_IF_NOT(SCRadix4TreeFindExactMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) == node[1]); + + GET_IPV4("192.171.128.45"); + FAIL_IF_NOT(SCRadix4TreeFindBestMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) == node[1]); + + GET_IPV4("192.171.128.78"); + FAIL_IF_NOT(SCRadix4TreeFindBestMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) == node[0]); + + REM_IPV4_MASK("192.171.128.0", 24); + + GET_IPV4("192.171.128.78"); + FAIL_IF_NOT(SCRadix4TreeFindBestMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) == NULL); + GET_IPV4("192.171.127.78"); + FAIL_IF_NOT(SCRadix4TreeFindBestMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) == NULL); + + SCRadix4TreeRelease(&tree, &ut_ip_radix4_config); + + PASS; +} + +static int SCRadix4TestIPV4NetblockInsertion11(void) +{ + struct sockaddr_in sa; + SCRadix4Tree tree = SCRadix4TreeInitialize(); + + /* add the keys */ + ADD_IPV4_MASK("253.192.0.0", 16); + ADD_IPV4_MASK("253.192.235.0", 24); + ADD_IPV4_MASK("192.167.0.0", 16); + ADD_IPV4("192.167.1.4"); + ADD_IPV4_MASK("220.168.0.0", 16); + ADD_IPV4("253.224.1.5"); + ADD_IPV4_MASK("192.168.0.0", 16); + ADD_IPV4_MASK("192.171.128.0", 24); + ADD_IPV4("192.171.128.45"); + ADD_IPV4_MASK("192.171.0.0", 18); + ADD_IPV4_MASK("192.175.0.0", 16); + + GET_IPV4("0.0.0.0"); + SCRadix4Node *node = SCRadix4AddKeyIPV4Netblock( + &tree, &ut_ip_radix4_config, (uint8_t *)&sa.sin_addr, 0, NULL); + FAIL_IF_NULL(node); + + /* test for the existance of a key */ + GET_IPV4("192.171.128.53"); + FAIL_IF_NOT(SCRadix4TreeFindBestMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) != NULL); + + GET_IPV4("192.171.128.45"); + FAIL_IF_NOT(SCRadix4TreeFindBestMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) != NULL); + + GET_IPV4("192.171.128.78"); + FAIL_IF_NOT(SCRadix4TreeFindBestMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) != NULL); + + GET_IPV4("192.171.127.78"); + FAIL_IF_NOT(SCRadix4TreeFindBestMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) == node); + + GET_IPV4("1.1.1.1"); + FAIL_IF_NOT(SCRadix4TreeFindBestMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) == node); + + GET_IPV4("192.255.254.25"); + FAIL_IF_NOT(SCRadix4TreeFindBestMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) == node); + + GET_IPV4("169.255.254.25"); + FAIL_IF_NOT(SCRadix4TreeFindBestMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) == node); + + GET_IPV4("0.0.0.0"); + FAIL_IF_NOT(SCRadix4TreeFindBestMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) == node); + + GET_IPV4("253.224.1.5"); + FAIL_IF_NOT(SCRadix4TreeFindExactMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) != NULL); + FAIL_IF_NOT(SCRadix4TreeFindExactMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) != node); + + GET_IPV4("245.63.62.121"); + FAIL_IF_NOT(SCRadix4TreeFindBestMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) != NULL); + FAIL_IF_NOT(SCRadix4TreeFindBestMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) == node); + + GET_IPV4("253.224.1.6"); + FAIL_IF_NOT(SCRadix4TreeFindBestMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) != NULL); + FAIL_IF_NOT(SCRadix4TreeFindBestMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) == node); + + /* remove node 0.0.0.0 */ + REM_IPV4_MASK("0.0.0.0", 0); + + GET_IPV4("253.224.1.6"); + FAIL_IF_NOT(SCRadix4TreeFindBestMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) == NULL); + GET_IPV4("192.171.127.78"); + FAIL_IF_NOT(SCRadix4TreeFindBestMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) == NULL); + GET_IPV4("1.1.1.1"); + FAIL_IF_NOT(SCRadix4TreeFindBestMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) == NULL); + + GET_IPV4("192.255.254.25"); + FAIL_IF_NOT(SCRadix4TreeFindBestMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) == NULL); + GET_IPV4("169.255.254.25"); + FAIL_IF_NOT(SCRadix4TreeFindBestMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) == NULL); + + GET_IPV4("0.0.0.0"); + FAIL_IF_NOT(SCRadix4TreeFindBestMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) == NULL); + + SCRadix4TreeRelease(&tree, &ut_ip_radix4_config); + PASS; +} + +static int SCRadix4TestIPV4NetblockInsertion12(void) +{ + struct sockaddr_in sa; + SCRadix4Tree tree = SCRadix4TreeInitialize(); + SCRadix4Node *node[2]; + + /* add the keys */ + ADD_IPV4_MASK("253.192.0.0", 16); + ADD_IPV4_MASK("253.192.235.0", 24); + ADD_IPV4_MASK("192.167.0.0", 16); + ADD_IPV4("192.167.1.4"); + ADD_IPV4_MASK("220.168.0.0", 16); + ADD_IPV4("253.224.1.5"); + ADD_IPV4_MASK("192.168.0.0", 16); + + GET_IPV4("192.171.128.0"); + node[0] = SCRadix4AddKeyIPV4Netblock( + &tree, &ut_ip_radix4_config, (uint8_t *)&sa.sin_addr, 24, NULL); + FAIL_IF_NULL(node[0]); + + GET_IPV4("192.171.128.45"); + node[1] = SCRadix4AddKeyIPV4(&tree, &ut_ip_radix4_config, (uint8_t *)&sa.sin_addr, NULL); + FAIL_IF_NULL(node[1]); + + ADD_IPV4_MASK("192.171.0.0", 18); + ADD_IPV4_MASK("225.175.21.228", 32); + + /* test for the existance of a key */ + GET_IPV4("192.171.128.53"); + FAIL_IF_NOT(SCRadix4TreeFindBestMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) == node[0]); + FAIL_IF_NOT(SCRadix4TreeFindExactMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) == NULL); + + GET_IPV4("192.171.128.45"); + FAIL_IF_NOT(SCRadix4TreeFindExactMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) == node[1]); + FAIL_IF_NOT(SCRadix4TreeFindBestMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) == node[1]); + + GET_IPV4("192.171.128.78"); + FAIL_IF_NOT(SCRadix4TreeFindBestMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) == node[0]); + FAIL_IF_NOT(SCRadix4TreeFindExactMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) == NULL); + + GET_IPV4("225.175.21.228"); + FAIL_IF_NOT(SCRadix4TreeFindExactMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) != NULL); + + GET_IPV4("225.175.21.224"); + FAIL_IF_NOT(SCRadix4TreeFindExactMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) == NULL); + + GET_IPV4("225.175.21.229"); + FAIL_IF_NOT(SCRadix4TreeFindExactMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) == NULL); + + GET_IPV4("225.175.21.230"); + FAIL_IF_NOT(SCRadix4TreeFindExactMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) == NULL); + + SCRadix4TreeRelease(&tree, &ut_ip_radix4_config); + + PASS; +} + +/** + * \test Check that the best match search works for all the + * possible netblocks of a fixed address + */ +static int SCRadix4TestIPV4NetBlocksAndBestSearch16(void) +{ + struct sockaddr_in sa; + SCRadix4Tree tree = SCRadix4TreeInitialize(); + + GET_IPV4("192.168.1.1"); + + for (uint32_t i = 0; i <= 32; i++) { + uint32_t *user = SCMalloc(sizeof(uint32_t)); + FAIL_IF_NULL(user); + *user = i; + SCRadix4AddKeyIPV4Netblock(&tree, &ut_ip_radix4_config, (uint8_t *)&sa.sin_addr, i, user); + void *user_data = NULL; + SCRadix4Node *node = SCRadix4TreeFindBestMatch(&tree, (uint8_t *)&sa.sin_addr, &user_data); + FAIL_IF_NULL(node); + FAIL_IF_NULL(user_data); + FAIL_IF(*((uint32_t *)user_data) != i); + } + + SCRadix4TreeRelease(&tree, &ut_ip_radix4_config); + PASS; +} + +/** + * \test Check special combinations of netblocks and addresses + * on best search checking the returned userdata + */ +static int SCRadix4TestIPV4NetBlocksAndBestSearch19(void) +{ + struct sockaddr_in sa; + void *user_data = NULL; + SCRadix4Tree tree = SCRadix4TreeInitialize(); + + GET_IPV4("0.0.0.0"); + uint32_t *user = SCMalloc(sizeof(uint32_t)); + FAIL_IF_NULL(user); + *user = 100; + SCRadix4AddKeyIPV4Netblock(&tree, &ut_ip_radix4_config, (uint8_t *)&sa.sin_addr, 0, user); + + GET_IPV4("192.168.1.15"); + SCRadix4Node *node = SCRadix4TreeFindBestMatch(&tree, (uint8_t *)&sa.sin_addr, &user_data); + FAIL_IF_NULL(node); + FAIL_IF_NULL(user_data); + FAIL_IF(*((uint32_t *)user_data) != 100); + user_data = NULL; + + GET_IPV4("177.0.0.0"); + user = SCMalloc(sizeof(uint32_t)); + FAIL_IF_NULL(user); + *user = 200; + SCRadix4AddKeyIPV4Netblock(&tree, &ut_ip_radix4_config, (uint8_t *)&sa.sin_addr, 8, user); + + GET_IPV4("177.168.1.15"); + node = SCRadix4TreeFindBestMatch(&tree, (uint8_t *)&sa.sin_addr, &user_data); + FAIL_IF_NULL(node); + FAIL_IF_NULL(user_data); + FAIL_IF(*((uint32_t *)user_data) != 200); + user_data = NULL; + + GET_IPV4("178.168.1.15"); + node = SCRadix4TreeFindBestMatch(&tree, (uint8_t *)&sa.sin_addr, &user_data); + FAIL_IF_NULL(node); + FAIL_IF_NULL(user_data); + FAIL_IF(*((uint32_t *)user_data) != 100); + user_data = NULL; + + GET_IPV4("177.168.0.0"); + user = SCMalloc(sizeof(uint32_t)); + FAIL_IF_NULL(user); + *user = 300; + SCRadix4AddKeyIPV4Netblock(&tree, &ut_ip_radix4_config, (uint8_t *)&sa.sin_addr, 12, user); + + GET_IPV4("177.168.1.15"); + node = SCRadix4TreeFindBestMatch(&tree, (uint8_t *)&sa.sin_addr, &user_data); + FAIL_IF_NULL(node); + FAIL_IF_NULL(user_data); + FAIL_IF(*((uint32_t *)user_data) != 300); + user_data = NULL; + + GET_IPV4("177.167.1.15"); + node = SCRadix4TreeFindBestMatch(&tree, (uint8_t *)&sa.sin_addr, &user_data); + FAIL_IF_NULL(node); + FAIL_IF_NULL(user_data); + FAIL_IF(*((uint32_t *)user_data) != 300); + user_data = NULL; + + GET_IPV4("177.178.1.15"); + node = SCRadix4TreeFindBestMatch(&tree, (uint8_t *)&sa.sin_addr, &user_data); + FAIL_IF_NULL(node); + FAIL_IF_NULL(user_data); + FAIL_IF(*((uint32_t *)user_data) != 200); + user_data = NULL; + + GET_IPV4("197.178.1.15"); + node = SCRadix4TreeFindBestMatch(&tree, (uint8_t *)&sa.sin_addr, &user_data); + FAIL_IF_NULL(node); + FAIL_IF_NULL(user_data); + FAIL_IF(*((uint32_t *)user_data) != 100); + user_data = NULL; + + SCRadix4TreeRelease(&tree, &ut_ip_radix4_config); + PASS; +} + +/** + * \test SCRadix4TestIPV4NetblockInsertion15 insert a node searching on it. + * Should always return true but the purposse of the test is to monitor + * the memory usage to detect memleaks (there was one on searching) + */ +static int SCRadix4TestIPV4NetblockInsertion25(void) +{ + struct sockaddr_in sa; + SCRadix4Tree tree = SCRadix4TreeInitialize(); + ADD_IPV4_MASK("192.168.0.0", 16); + GET_IPV4("192.168.128.53"); + FAIL_IF_NOT(SCRadix4TreeFindBestMatch(&tree, (uint8_t *)&sa.sin_addr, NULL) != NULL); + SCRadix4TreeRelease(&tree, &ut_ip_radix4_config); + PASS; +} + +/** + * \test SCRadix4TestIPV4NetblockInsertion26 insert a node searching on it. + * Should always return true but the purposse of the test is to monitor + * the memory usage to detect memleaks (there was one on searching) + */ +static int SCRadix4TestIPV4NetblockInsertion26(void) +{ + SCRadix4Node *tmp = NULL; + struct sockaddr_in sa; + char *str = SCStrdup("Hello1"); + FAIL_IF_NULL(str); + SCRadix4Tree tree = SCRadix4TreeInitialize(); + GET_IPV4("0.0.0.0"); + SCRadix4AddKeyIPV4Netblock(&tree, &ut_ip_radix4_config, (uint8_t *)&sa.sin_addr, 0, str); + str = SCStrdup("Hello2"); + FAIL_IF_NULL(str); + GET_IPV4("176.0.0.1"); + SCRadix4AddKeyIPV4Netblock(&tree, &ut_ip_radix4_config, (uint8_t *)&sa.sin_addr, 5, str); + str = SCStrdup("Hello3"); + FAIL_IF_NULL(str); + GET_IPV4("0.0.0.0"); + SCRadix4AddKeyIPV4Netblock(&tree, &ut_ip_radix4_config, (uint8_t *)&sa.sin_addr, 7, str); + /* test for the existance of a key */ + void *retptr = NULL; + tmp = SCRadix4TreeFindBestMatch(&tree, (uint8_t *)&sa.sin_addr, &retptr); + FAIL_IF_NULL(tmp); + FAIL_IF_NULL(retptr); + FAIL_IF_NOT(strcmp((char *)retptr, "Hello3") == 0); + SCRadix4TreeRelease(&tree, &ut_ip_radix4_config); + PASS; +} + +static int SCRadix4TestIPV4InsertRemove01(void) +{ + struct sockaddr_in sa; + + SCRadix4Tree tree = SCRadix4TreeInitialize(); + ADD_IPV4_MASK("1.0.0.0", 8); + ADD_IPV4_MASK("1.1.1.0", 24); + ADD_IPV4("1.1.1.1"); + FAIL_IF(tree.head == NULL); + FAIL_IF_NOT(tree.head->bit == 15); + FAIL_IF_NULL(tree.head->left); + FAIL_IF_NOT(tree.head->left->masks == 0); + FAIL_IF_NOT(tree.head->left->bit == 32); + FAIL_IF_NULL(tree.head->right); + FAIL_IF_NOT(tree.head->right->masks == BIT_U64(24)); + FAIL_IF_NOT(tree.head->right->bit == 31); + SCRadix4PrintTree(&tree, &ut_ip_radix4_config); + SCRadix4TreeRelease(&tree, &ut_ip_radix4_config); + + /* tree after adds/removals */ + tree = SCRadix4TreeInitialize(); + ADD_IPV4_MASK("1.0.0.0", 8); + ADD_IPV4_MASK("1.0.0.0", 10); + ADD_IPV4_MASK("1.0.0.0", 12); + ADD_IPV4_MASK("1.1.0.0", 16); + ADD_IPV4_MASK("1.1.0.0", 18); + ADD_IPV4_MASK("1.1.0.0", 20); + ADD_IPV4_MASK("1.1.1.0", 24); + ADD_IPV4("1.1.1.1"); + REM_IPV4_MASK("1.1.0.0", 20); + REM_IPV4_MASK("1.1.0.0", 18); + REM_IPV4_MASK("1.1.0.0", 16); + REM_IPV4_MASK("1.0.0.0", 12); + REM_IPV4_MASK("1.0.0.0", 10); + FAIL_IF(tree.head == NULL); + FAIL_IF_NOT(tree.head->bit == 15); + FAIL_IF_NULL(tree.head->left); + FAIL_IF_NOT(tree.head->left->masks == 0); + FAIL_IF_NOT(tree.head->left->bit == 32); + FAIL_IF_NULL(tree.head->right); + FAIL_IF_NOT(tree.head->right->masks == BIT_U64(24)); + FAIL_IF_NOT(tree.head->right->bit == 31); + SCRadix4PrintTree(&tree, &ut_ip_radix4_config); + SCRadix4TreeRelease(&tree, &ut_ip_radix4_config); + + PASS; +} +#endif + +void SCRadix4RegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("SCRadix4TestIPV4Insertion03", SCRadix4TestIPV4Insertion03); + UtRegisterTest("SCRadix4TestIPV4Removal04", SCRadix4TestIPV4Removal04); + UtRegisterTest("SCRadix4TestIPV4NetblockInsertion09", SCRadix4TestIPV4NetblockInsertion09); + UtRegisterTest("SCRadix4TestIPV4NetblockInsertion10", SCRadix4TestIPV4NetblockInsertion10); + UtRegisterTest("SCRadix4TestIPV4NetblockInsertion11", SCRadix4TestIPV4NetblockInsertion11); + UtRegisterTest("SCRadix4TestIPV4NetblockInsertion12", SCRadix4TestIPV4NetblockInsertion12); + UtRegisterTest( + "SCRadix4TestIPV4NetBlocksAndBestSearch16", SCRadix4TestIPV4NetBlocksAndBestSearch16); + UtRegisterTest( + "SCRadix4TestIPV4NetBlocksAndBestSearch19", SCRadix4TestIPV4NetBlocksAndBestSearch19); + UtRegisterTest("SCRadix4TestIPV4NetblockInsertion25", SCRadix4TestIPV4NetblockInsertion25); + UtRegisterTest("SCRadix4TestIPV4NetblockInsertion26", SCRadix4TestIPV4NetblockInsertion26); + UtRegisterTest("SCRadix4TestIPV4InsertRemove01", SCRadix4TestIPV4InsertRemove01); +#endif + return; +} diff --git a/src/util-radix4-tree.h b/src/util-radix4-tree.h new file mode 100644 index 000000000000..966657557aca --- /dev/null +++ b/src/util-radix4-tree.h @@ -0,0 +1,119 @@ +/* Copyright (C) 2007-2022 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + * Based on util-radix-tree.[ch] by: + * \author Anoop Saldanha + */ + +#ifndef SURICATA_UTIL_RADIX4_TREE_H +#define SURICATA_UTIL_RADIX4_TREE_H + +#include "suricata-common.h" + +struct RadixUserData; + +/** + * \brief Structure for the node in the radix tree + */ +typedef struct SCRadix4Node_ { + /** holds bitmap of netmasks that come under this node in the tree */ + uint64_t masks : 33; + uint64_t pad1 : 31; + + /** the bit position where the bits differ in the nodes children. Used + * to determine the path to be taken during a lookup */ + uint8_t bit; + + /** bool to see if prefix_stream is filled */ + bool has_prefix; + + /** the key that has been stored in the tree */ + uint8_t prefix_stream[4]; + + /** User data that is associated with this key. We need a user data field + * for each netblock value possible since one ip can be associated + * with any of the 32 netblocks. */ + struct RadixUserData *user_data; + + /** the left and the right children of a node */ + struct SCRadix4Node_ *left, *right; + + /** the parent node for this tree */ + struct SCRadix4Node_ *parent; +} SCRadix4Node; + +/** + * \brief Structure for the radix tree + */ +typedef struct SCRadix4Tree_ { + /** the root node in the radix tree */ + SCRadix4Node *head; +} SCRadix4Tree; + +typedef struct SCRadix4Config_ { + void (*Free)(void *); + /** function pointer that is supplied by the user to free the user data + * held by the user field of SCRadix4Node */ + void (*PrintData)(void *); // debug only? +} SCRadix4Config; + +#define SC_RADIX4_TREE_INITIALIZER \ + { \ + .head = NULL \ + } + +SCRadix4Tree SCRadix4TreeInitialize(void); +void SCRadix4TreeRelease(SCRadix4Tree *, const SCRadix4Config *); + +SCRadix4Node *SCRadix4AddKeyIPV4(SCRadix4Tree *, const SCRadix4Config *, const uint8_t *, void *); +SCRadix4Node *SCRadix4AddKeyIPV4Netblock( + SCRadix4Tree *, const SCRadix4Config *, const uint8_t *, uint8_t, void *); +bool SCRadix4AddKeyIPV4String(SCRadix4Tree *, const SCRadix4Config *, const char *, void *); + +void SCRadix4RemoveKeyIPV4Netblock( + SCRadix4Tree *, const SCRadix4Config *, const uint8_t *, uint8_t); +void SCRadix4RemoveKeyIPV4(SCRadix4Tree *, const SCRadix4Config *, const uint8_t *); + +SCRadix4Node *SCRadix4TreeFindExactMatch(const SCRadix4Tree *, const uint8_t *, void **); +SCRadix4Node *SCRadix4TreeFindNetblock( + const SCRadix4Tree *, const uint8_t *, const uint8_t, void **); +SCRadix4Node *SCRadix4TreeFindBestMatch(const SCRadix4Tree *, const uint8_t *, void **); +SCRadix4Node *SCRadix4TreeFindBestMatch2(const SCRadix4Tree *, const uint8_t *, void **, uint8_t *); + +void SCRadix4PrintTree(SCRadix4Tree *, const SCRadix4Config *config); +void SCRadix4PrintNodeInfo(SCRadix4Node *, int, void (*PrintData)(void *)); + +void SCRadix4RegisterTests(void); + +typedef int (*SCRadix4ForEachNodeFunc)( + const SCRadix4Node *node, void *user_data, const uint8_t netmask, void *data); + +int SCRadix4ForEachNode(const SCRadix4Tree *tree, SCRadix4ForEachNodeFunc Callback, void *data); + +/** \brief compare content of 2 user data entries + * \retval true equal + * \retval false not equal + */ +typedef bool (*SCRadix4TreeCompareFunc)(const void *ud1, const void *ud2); +bool SCRadix4CompareTrees( + const SCRadix4Tree *t1, const SCRadix4Tree *t2, SCRadix4TreeCompareFunc Callback); + +#endif /* SURICATA_UTIL_RADIX4_TREE_H */ diff --git a/src/util-radix6-tree.c b/src/util-radix6-tree.c new file mode 100644 index 000000000000..725ffbae1409 --- /dev/null +++ b/src/util-radix6-tree.c @@ -0,0 +1,963 @@ +/* Copyright (C) 2007-2022 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + * \author Anoop Saldanha + * + * Implementation of radix trees + */ + +#include "suricata-common.h" +#include "util-debug.h" +#include "util-error.h" +#include "util-ip.h" +#include "util-cidr.h" +#include "util-unittest.h" +#include "util-memcmp.h" +#include "util-print.h" +#include "util-byte.h" +#include "util-radix6-tree.h" + +#define ADDRESS_BYTES (uint8_t)16 +#define NETMASK_MAX (uint8_t)128 + +#define RADIX_TREE_TYPE SCRadix6Tree +#define RADIX_NODE_TYPE SCRadix6Node +#define RADIX_TREE_COMPARE_CALLBACK SCRadix6TreeCompareFunc +#define RADIX_CONFIG_TYPE SCRadix6Config + +static void PrintUserdata(SCRadix6Node *node, void (*PrintData)(void *)); + +static inline void AddNetmaskToMasks(SCRadix6Node *node, int netmask) +{ + uint8_t *masks = node->masks; + masks[netmask / 8] |= 1 << (netmask % 8); +} + +static inline void RemoveNetmaskFromMasks(SCRadix6Node *node, int netmask) +{ + uint8_t *masks = node->masks; + masks[netmask / 8] &= ~(1 << (netmask % 8)); +} + +static inline void AddNetmasksFromNode(SCRadix6Node *dst, SCRadix6Node *src) +{ + for (size_t i = 0; i < sizeof(src->masks); i++) { + dst->masks[i] |= src->masks[i]; + } +} + +static inline bool NetmasksEmpty(const SCRadix6Node *node) +{ + for (size_t i = 0; i < sizeof(node->masks); i++) { + if (node->masks[i] != 0) { + return false; + } + } + return true; +} + +static inline bool NetmaskEqualsMask(const SCRadix6Node *node, int netmask) +{ + size_t b = netmask / 8; + + for (size_t i = 0; i < sizeof(node->masks); i++) { + if (i != b && node->masks[i] != 0) + return false; + else if (node->masks[i] != (1 << (netmask % 8))) + return false; + } + return true; +} + +static inline bool NetmaskIssetInMasks(const SCRadix6Node *node, int netmask) +{ + return ((node->masks[netmask / 8] & 1 << (netmask % 8)) != 0); +} + +static inline void ProcessInternode(SCRadix6Node *node, SCRadix6Node *inter_node) +{ + const int differ_bit = inter_node->bit; + uint8_t rem[sizeof(node->masks)]; + memset(rem, 0, sizeof(rem)); + + for (int x = 0; x <= NETMASK_MAX; x++) { + int m = NETMASK_MAX - x; + if (m == differ_bit) + break; + else { + if (NetmaskIssetInMasks(node, m)) + rem[m / 8] |= 1 << (m % 8); + } + } + + AddNetmasksFromNode(inter_node, node); + + for (size_t i = 0; i < sizeof(inter_node->masks); i++) { + inter_node->masks[i] &= ~rem[i]; + } + + memcpy(node->masks, rem, sizeof(node->masks)); +} + +/** + * \brief Prints the node information from a Radix6 tree + * + * \param node Pointer to the Radix6 node whose information has to be printed + * \param level Used for indentation purposes + */ +static void PrintNodeInfo(SCRadix6Node *node, int level, void (*PrintData)(void *)) +{ + if (node == NULL) + return; + for (int i = 0; i < level; i++) + printf(" "); + + printf("%d [", node->bit); + + if (NetmasksEmpty(node)) { + printf(" - "); + } else { + for (int i = 0, x = 0; i <= NETMASK_MAX; i++) { + if (NetmaskIssetInMasks(node, i)) { + printf("%s%d", x ? ", " : "", i); + x++; + } + } + } + printf("] ("); + + if (node->has_prefix) { + char addr[46] = ""; + PrintInet(AF_INET6, &node->prefix_stream, addr, sizeof(addr)); + printf("%s)\t%p", addr, node); + PrintUserdata(node, PrintData); + printf("\n"); + } else { + printf("no prefix) %p\n", node); + } + return; +} + +#include "util-radix-tree-common.h" + +SCRadix6Node *SCRadix6TreeFindExactMatch( + const SCRadix6Tree *tree, const uint8_t *key, void **user_data) +{ + return FindExactMatch(tree, key, user_data); +} + +SCRadix6Node *SCRadix6TreeFindNetblock( + const SCRadix6Tree *tree, const uint8_t *key, const uint8_t netmask, void **user_data) +{ + return FindNetblock(tree, key, netmask, user_data); +} + +SCRadix6Node *SCRadix6TreeFindBestMatch( + const SCRadix6Tree *tree, const uint8_t *key, void **user_data) +{ + return FindBestMatch(tree, key, user_data); +} + +SCRadix6Node *SCRadix6TreeFindBestMatch2( + const SCRadix6Tree *tree, const uint8_t *key, void **user_data, uint8_t *out_netmask) +{ + return FindBestMatch2(tree, key, user_data, out_netmask); +} + +/** + * \brief Adds a new IPV6 address to the Radix6 tree + * + * \param key_stream Data that has to be added to the Radix6 tree. In this case + * a pointer to an IPV6 address + * \param tree Pointer to the Radix6 tree + * \param user Pointer to the user data that has to be associated with the + * key + * + * \retval node Pointer to the newly created node + */ +SCRadix6Node *SCRadix6AddKeyIPV6( + SCRadix6Tree *tree, const SCRadix6Config *config, const uint8_t *key_stream, void *user) +{ + return AddKey(tree, config, key_stream, 128, user, false); +} + +/** + * \brief Adds a new IPV6 netblock to the Radix6 tree + * + * \param key_stream Data that has to be added to the Radix6 tree. In this case + * a pointer to an IPV6 netblock + * \param tree Pointer to the Radix6 tree + * \param user Pointer to the user data that has to be associated with the + * key + * \param netmask The netmask (cidr) if we are adding a netblock + * + * \retval node Pointer to the newly created node + */ +SCRadix6Node *SCRadix6AddKeyIPV6Netblock(SCRadix6Tree *tree, const SCRadix6Config *config, + const uint8_t *key_stream, uint8_t netmask, void *user) +{ + return AddKey(tree, config, key_stream, netmask, user, false); +} + +#if defined(DEBUG_VALIDATION) || defined(UNITTESTS) +static void SCRadix6ValidateIPv6Key(uint8_t *key, const uint8_t netmask) +{ + uint32_t address[4]; + memcpy(&address, key, sizeof(address)); + + uint32_t mask[4]; + memset(&mask, 0, sizeof(mask)); + struct in6_addr mask6; + CIDRGetIPv6(netmask, &mask6); + memcpy(&mask, &mask6.s6_addr, sizeof(mask)); + + uint32_t masked[4]; + masked[0] = address[0] & mask[0]; + masked[1] = address[1] & mask[1]; + masked[2] = address[2] & mask[2]; + masked[3] = address[3] & mask[3]; + + if (memcmp(masked, address, sizeof(masked)) != 0) { + char ostr[64], nstr[64]; + PrintInet(AF_INET6, (void *)&address, ostr, sizeof(ostr)); + PrintInet(AF_INET6, (void *)&masked, nstr, sizeof(nstr)); + SCLogNotice("input %s/%u != expected %s/%u", ostr, netmask, nstr, netmask); + abort(); + } +} +#endif +/** + * \brief Adds a new IPV6/netblock to the Radix6 tree from a string + * + * \param str IPV6 string with optional /cidr netmask + * \param tree Pointer to the Radix6 tree + * \param user Pointer to the user data that has to be associated with + * the key + * + * \retval bool true if node was added, false otherwise + * + * If the function returns false, `sc_errno` is set: + * - SC_EEXIST: Node already exists + * - SC_EINVAL: Parameter value error + * - SC_ENOMEM: Memory allocation failed + */ +bool SCRadix6AddKeyIPV6String( + SCRadix6Tree *tree, const SCRadix6Config *config, const char *str, void *user) +{ + uint8_t netmask = 128; + char ip_str[80] = ""; /* Max length for full ipv6/cidr string with NUL */ + char *mask_str = NULL; + struct in6_addr addr; + + /* Make a copy of the string so it can be modified */ + strlcpy(ip_str, str, sizeof(ip_str)); + + /* Does it have a mask? */ + if (NULL != (mask_str = strchr(ip_str, '/'))) { + *(mask_str++) = '\0'; + + /* Dotted type netmask not valid for ipv6 */ + if (strchr(mask_str, '.') != NULL) { + sc_errno = SC_EINVAL; + return false; + } + + uint8_t cidr; + if (StringParseU8RangeCheck(&cidr, 10, 0, (const char *)mask_str, 0, 128) < 0) { + sc_errno = SC_EINVAL; + return false; + } + netmask = (uint8_t)cidr; + } + + /* Validate the IP */ + if (inet_pton(AF_INET6, ip_str, &addr) <= 0) { + sc_errno = SC_EINVAL; + return false; + } + + if (netmask != 128) { + struct in6_addr maddr; + struct in6_addr mask6, check; + CIDRGetIPv6(netmask, &mask6); + memcpy(&check, &addr, sizeof(check)); + bool diff = false; + for (int i = 0; i < 16; i++) { + maddr.s6_addr[i] = addr.s6_addr[i] & mask6.s6_addr[i]; + diff |= (maddr.s6_addr[i] != check.s6_addr[i]); + } + if (diff) { + char nstr[64]; + PrintInet(AF_INET6, (void *)&maddr.s6_addr, nstr, sizeof(nstr)); + SCLogWarning("adding '%s' as '%s/%u'", str, nstr, netmask); + memcpy(addr.s6_addr, maddr.s6_addr, 16); +#if defined(DEBUG_VALIDATION) || defined(UNITTESTS) + SCRadix6ValidateIPv6Key((uint8_t *)&addr.s6_addr, netmask); +#endif + } + } + + if (AddKey(tree, config, (uint8_t *)&addr.s6_addr, netmask, user, true) == NULL) { + DEBUG_VALIDATE_BUG_ON(sc_errno == SC_OK); + return false; + } + return true; +} + +/** + * \brief Removes an IPV6 address key(not a netblock) from the Radix6 tree. + * Instead of using this function, we can also used + * SCRadix6RemoveKeyIPV6Netblock(), by supplying a netmask value of 32. + * + * \param key_stream Data that has to be removed from the Radix6 tree. In this + * case an IPV6 address + * \param tree Pointer to the Radix6 tree from which the key has to be + * removed + */ +void SCRadix6RemoveKeyIPV6( + SCRadix6Tree *tree, const SCRadix6Config *config, const uint8_t *key_stream) +{ + RemoveKey(tree, config, key_stream, 128); +} + +/** + * \brief Removes an IPV6 address netblock key from the tree. + * + * \param key_stream Data that has to be removed from the tree. In this + * case an IPV6 address with netmask. + * \param tree Pointer to the tree from which the key has to be + * removed + */ +void SCRadix6RemoveKeyIPV6Netblock(SCRadix6Tree *tree, const SCRadix6Config *config, + const uint8_t *key_stream, uint8_t netmask) +{ + RemoveKey(tree, config, key_stream, netmask); +} + +void SCRadix6PrintTree(SCRadix6Tree *tree, const SCRadix6Config *config) +{ + PrintTree(tree, config); +} + +SCRadix6Tree SCRadix6TreeInitialize(void) +{ + SCRadix6Tree t = SC_RADIX6_TREE_INITIALIZER; + return t; +} + +void SCRadix6TreeRelease(SCRadix6Tree *tree, const SCRadix6Config *config) +{ + TreeRelease(tree, config); +} + +static void PrintUserdata(SCRadix6Node *node, void (*PrintData)(void *)) +{ + if (PrintData != NULL) { + RadixUserData *ud = node->user_data; + while (ud != NULL) { + printf("[%d], ", ud->netmask); + PrintData(ud->user); + ud = ud->next; + } + } else { + RadixUserData *ud = node->user_data; + while (ud != NULL) { + printf(" [%d], ", ud->netmask); + ud = ud->next; + } + } +} + +static int SCRadix6ForEachNodeSub( + const SCRadix6Node *node, SCRadix6ForEachNodeFunc Callback, void *data) +{ + BUG_ON(!node); + + /* invoke callback for each stored user data */ + for (RadixUserData *ud = node->user_data; ud != NULL; ud = ud->next) { + if (Callback(node, ud->user, ud->netmask, data) < 0) + return -1; + } + + if (node->left) { + if (SCRadix6ForEachNodeSub(node->left, Callback, data) < 0) + return -1; + } + if (node->right) { + if (SCRadix6ForEachNodeSub(node->right, Callback, data) < 0) + return -1; + } + return 0; +} + +int SCRadix6ForEachNode(const SCRadix6Tree *tree, SCRadix6ForEachNodeFunc Callback, void *data) +{ + if (tree->head == NULL) + return 0; + return SCRadix6ForEachNodeSub(tree->head, Callback, data); +} + +bool SCRadix6CompareTrees( + const SCRadix6Tree *t1, const SCRadix6Tree *t2, SCRadix6TreeCompareFunc Callback) +{ + return CompareTrees(t1, t2, Callback); +} + +/*------------------------------------Unit_Tests------------------------------*/ + +#ifdef UNITTESTS + +static const SCRadix6Config ut_ip_radix6_config = { NULL, NULL }; + +#define GET_IPV6(str) \ + SCLogDebug("setting up %s", (str)); \ + memset(&(sa), 0, sizeof((sa))); \ + FAIL_IF(inet_pton(AF_INET6, (str), &(sa).sin6_addr) <= 0); + +#define ADD_IPV6(str) \ + GET_IPV6((str)); \ + SCRadix6AddKeyIPV6(&tree, &ut_ip_radix6_config, (uint8_t *)&(sa).sin6_addr, NULL); + +#define REM_IPV6(str) \ + GET_IPV6((str)); \ + SCRadix6RemoveKeyIPV6(&tree, &ut_ip_radix6_config, (uint8_t *)&(sa).sin6_addr); + +#define ADD_IPV6_MASK(str, cidr) \ + GET_IPV6((str)); \ + SCRadix6AddKeyIPV6Netblock( \ + &tree, &ut_ip_radix6_config, (uint8_t *)&(sa).sin6_addr, (cidr), NULL); + +#define REM_IPV6_MASK(str, cidr) \ + GET_IPV6((str)); \ + SCRadix6RemoveKeyIPV6Netblock(&tree, &ut_ip_radix6_config, (uint8_t *)&(sa).sin6_addr, (cidr)); + +static int SCRadix6TestIPV6Insertion03(void) +{ + struct sockaddr_in6 sa; + SCRadix6Tree tree = SCRadix6TreeInitialize(); + + ADD_IPV6("2000:1::1"); + ADD_IPV6("2000:1::2"); + ADD_IPV6("2000:0::3"); + ADD_IPV6("2000:0::4"); + ADD_IPV6("2000:0::4"); + + /* test for the existance of a key */ + GET_IPV6("2000:1::6"); + FAIL_IF_NOT(SCRadix6TreeFindExactMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) == NULL); + + /* test for the existance of a key */ + GET_IPV6("2000:0::4"); + FAIL_IF_NOT(SCRadix6TreeFindExactMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) != NULL); + + /* continue adding keys */ + ADD_IPV6("2000:0::2"); + ADD_IPV6("2000:1::5"); + ADD_IPV6("2000:1::18"); + + /* test the existence of keys */ + GET_IPV6("2000:1::3"); + FAIL_IF_NOT(SCRadix6TreeFindExactMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) == NULL); + GET_IPV6("2001:1:2:3::62"); + FAIL_IF_NOT(SCRadix6TreeFindExactMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) == NULL); + + GET_IPV6("2000:1::1"); + FAIL_IF_NOT(SCRadix6TreeFindExactMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) != NULL); + GET_IPV6("2000:1::5"); + FAIL_IF_NOT(SCRadix6TreeFindExactMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) != NULL); + GET_IPV6("2000:1::2"); + FAIL_IF_NOT(SCRadix6TreeFindExactMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) != NULL); + + GET_IPV6("2000:0::3"); + FAIL_IF_NOT(SCRadix6TreeFindExactMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) != NULL); + GET_IPV6("2000:0::4"); + FAIL_IF_NOT(SCRadix6TreeFindExactMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) != NULL); + GET_IPV6("2000:0::2"); + FAIL_IF_NOT(SCRadix6TreeFindExactMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) != NULL); + GET_IPV6("2000:1::18"); + FAIL_IF_NOT(SCRadix6TreeFindExactMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) != NULL); + + SCRadix6TreeRelease(&tree, &ut_ip_radix6_config); + + PASS; +} + +static int SCRadix6TestIPV6Removal04(void) +{ + struct sockaddr_in6 sa; + SCRadix6Tree tree = SCRadix6TreeInitialize(); + + /* add the keys */ + ADD_IPV6("2000:1::1"); + ADD_IPV6("2000:1::2"); + ADD_IPV6("2000:0::3"); + ADD_IPV6("2000:0::4"); + ADD_IPV6("1000:1::2"); + ADD_IPV6("2000:1::5"); + ADD_IPV6("2000:1::18"); + + /* remove the keys from the tree */ + REM_IPV6("2000:1::1"); + REM_IPV6("2000:0::3"); + REM_IPV6("2000:0::4"); + REM_IPV6("2000:1::18"); + + GET_IPV6("2000:0::1"); + FAIL_IF_NOT(SCRadix6TreeFindExactMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) == NULL); + GET_IPV6("2000:1::2"); + FAIL_IF_NOT(SCRadix6TreeFindExactMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) != NULL); + + REM_IPV6("2000:0::3"); + REM_IPV6("1000:1::2"); + + GET_IPV6("2000:1::5"); + FAIL_IF_NOT(SCRadix6TreeFindExactMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) != NULL); + GET_IPV6("2000:1::2"); + FAIL_IF_NOT(SCRadix6TreeFindExactMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) != NULL); + + REM_IPV6("2000:1::2"); + REM_IPV6("2000:1::5"); + + FAIL_IF_NOT_NULL(tree.head); + + SCRadix6TreeRelease(&tree, &ut_ip_radix6_config); + + PASS; +} + +static int SCRadix6TestIPV6NetblockInsertion09(void) +{ + struct sockaddr_in6 sa; + SCRadix6Tree tree = SCRadix6TreeInitialize(); + + /* add the keys */ + ADD_IPV6("2000::1:1"); + ADD_IPV6("2000::1:2"); + ADD_IPV6("2000::0:3"); + ADD_IPV6("2000::0:4"); + ADD_IPV6("1000::1:2"); + ADD_IPV6("2000::1:5"); + ADD_IPV6("2000::1:18"); + + ADD_IPV6_MASK("2000::", 16); + ADD_IPV6_MASK("2000::192:171:128:0", 128 - 8); + ADD_IPV6_MASK("2000::192:171:192:0", 128 - 14); + ADD_IPV6_MASK("2000::192:175:0:0", 128 - 16); + + /* test for the existance of a key */ + GET_IPV6("2000:1::6"); + FAIL_IF_NOT(SCRadix6TreeFindExactMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) == NULL); + GET_IPV6("2000::192:170:1:6"); + FAIL_IF_NOT(SCRadix6TreeFindExactMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) == NULL); + GET_IPV6("2000::192:171:128:145"); + FAIL_IF_NOT(SCRadix6TreeFindBestMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) != NULL); + GET_IPV6("2000::192:171:64:6"); + FAIL_IF_NOT(SCRadix6TreeFindExactMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) == NULL); + GET_IPV6("2000::192:171:191:6"); + FAIL_IF_NOT(SCRadix6TreeFindExactMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) == NULL); + GET_IPV6("2000::192:171:224:6"); + FAIL_IF_NOT(SCRadix6TreeFindBestMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) != NULL); + GET_IPV6("2000::192:171:224:6"); + FAIL_IF_NOT(SCRadix6TreeFindExactMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) == NULL); + GET_IPV6("2000::192:175:224:6"); + FAIL_IF_NOT(SCRadix6TreeFindBestMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) != NULL); + + SCRadix6TreeRelease(&tree, &ut_ip_radix6_config); + + PASS; +} + +static int SCRadix6TestIPV6NetblockInsertion10(void) +{ + SCRadix6Node *node[2]; + struct sockaddr_in6 sa; + SCRadix6Tree tree = SCRadix6TreeInitialize(); + + /* add the keys */ + ADD_IPV6_MASK("2000::253:192:0:0", 112); + ADD_IPV6_MASK("2000::253:192:235:0", 112); + ADD_IPV6_MASK("2000::192:167:0:0", 112); + ADD_IPV6("2000:0::4"); + ADD_IPV6_MASK("2000::220:168:0:0", 112); + ADD_IPV6("2000::253:224:1:5"); + ADD_IPV6_MASK("2000::192:168:0:0", 112); + + GET_IPV6("2000::192:171:128:0"); + node[0] = SCRadix6AddKeyIPV6Netblock( + &tree, &ut_ip_radix6_config, (uint8_t *)&sa.sin6_addr, 112, NULL); + + GET_IPV6("2000::192:171:128:45"); + node[1] = SCRadix6AddKeyIPV6(&tree, &ut_ip_radix6_config, (uint8_t *)&sa.sin6_addr, NULL); + + ADD_IPV6_MASK("2000::192:171:0:0", 110); + ADD_IPV6_MASK("2000::192:175:0:0", 112); + + /* test for the existance of a key */ + GET_IPV6("2000::192:171:128:53"); + FAIL_IF_NOT(SCRadix6TreeFindBestMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) == node[0]); + + GET_IPV6("2000::192:171:128:45"); + FAIL_IF_NOT(SCRadix6TreeFindExactMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) == node[1]); + + GET_IPV6("2000::192:171:128:45"); + FAIL_IF_NOT(SCRadix6TreeFindBestMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) == node[1]); + + GET_IPV6("2000::192:171:128:78"); + FAIL_IF_NOT(SCRadix6TreeFindBestMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) == node[0]); + + REM_IPV6_MASK("2000::192:171:128:0", 112); + + GET_IPV6("2000::192:171:128:78"); + SCRadix6Node *n = SCRadix6TreeFindBestMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL); + SCLogNotice("n %p", n); + FAIL_IF_NOT(SCRadix6TreeFindBestMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) == NULL); + GET_IPV6("2000::192:171:127:78"); + FAIL_IF_NOT(SCRadix6TreeFindBestMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) == NULL); + + SCRadix6TreeRelease(&tree, &ut_ip_radix6_config); + + PASS; +} + +static int SCRadix6TestIPV6NetblockInsertion11(void) +{ + struct sockaddr_in6 sa; + SCRadix6Tree tree = SCRadix6TreeInitialize(); + + /* add the keys */ + ADD_IPV6_MASK("2000::253:192:0:0", 96); + ADD_IPV6_MASK("2000::253:192:235:0", 112); + ADD_IPV6_MASK("2000::192:167:0:0", 96); + ADD_IPV6("2000:0::4"); + ADD_IPV6_MASK("2000::220:168:0:0", 96); + ADD_IPV6("2000::253:224:1:5"); + ADD_IPV6_MASK("2000::192:168:0:0", 96); + ADD_IPV6_MASK("2000::192:171:128:0", 112); + ADD_IPV6("2000::192:171:128:45"); + ADD_IPV6_MASK("2000::192:171:0:0", 112); + ADD_IPV6_MASK("2000::192:175:0:0", 96); + + GET_IPV6("::"); + SCRadix6Node *node = SCRadix6AddKeyIPV6Netblock( + &tree, &ut_ip_radix6_config, (uint8_t *)&sa.sin6_addr, 0, NULL); + FAIL_IF_NULL(node); + + /* test for the existance of a key */ + GET_IPV6("2000::192:171:128:53"); + FAIL_IF_NOT(SCRadix6TreeFindBestMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) != NULL); + + GET_IPV6("2000::192:171:128:45"); + FAIL_IF_NOT(SCRadix6TreeFindBestMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) != NULL); + + GET_IPV6("2000::192:171:128:78"); + FAIL_IF_NOT(SCRadix6TreeFindBestMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) != NULL); + + GET_IPV6("2000::192:171:127:78"); + FAIL_IF_NOT(SCRadix6TreeFindBestMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) == node); + + GET_IPV6("2000::1:1:1:1"); + FAIL_IF_NOT(SCRadix6TreeFindBestMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) == node); + + GET_IPV6("2000::192:255:254:25"); + FAIL_IF_NOT(SCRadix6TreeFindBestMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) == node); + + GET_IPV6("2000::169:255:254:25"); + FAIL_IF_NOT(SCRadix6TreeFindBestMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) == node); + + GET_IPV6("::"); + FAIL_IF_NOT(SCRadix6TreeFindBestMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) == node); + + GET_IPV6("2000::253:224:1:5"); + FAIL_IF_NOT(SCRadix6TreeFindExactMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) != NULL); + FAIL_IF_NOT(SCRadix6TreeFindExactMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) != node); + + GET_IPV6("2000::245:63:62:121"); + FAIL_IF_NOT(SCRadix6TreeFindBestMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) != NULL); + FAIL_IF_NOT(SCRadix6TreeFindBestMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) == node); + + GET_IPV6("2000::253:224:1:6"); + FAIL_IF_NOT(SCRadix6TreeFindBestMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) != NULL); + FAIL_IF_NOT(SCRadix6TreeFindBestMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) == node); + + /* remove node 0.0.0.0 */ + REM_IPV6_MASK("::", 0); + + GET_IPV6("2000::253:224:1:6"); + FAIL_IF_NOT(SCRadix6TreeFindBestMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) == NULL); + GET_IPV6("2000::192:171:127:78"); + FAIL_IF_NOT(SCRadix6TreeFindBestMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) == NULL); + GET_IPV6("2000::1:1:1:1"); + FAIL_IF_NOT(SCRadix6TreeFindBestMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) == NULL); + + GET_IPV6("2000::192:255:254:25"); + FAIL_IF_NOT(SCRadix6TreeFindBestMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) == NULL); + GET_IPV6("2000::169:255:254:25"); + FAIL_IF_NOT(SCRadix6TreeFindBestMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) == NULL); + + GET_IPV6("::"); + FAIL_IF_NOT(SCRadix6TreeFindBestMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) == NULL); + + SCRadix6TreeRelease(&tree, &ut_ip_radix6_config); + + PASS; +} + +static int SCRadix6TestIPV6NetblockInsertion12(void) +{ + struct sockaddr_in6 sa; + SCRadix6Node *node[2]; + SCRadix6Tree tree = SCRadix6TreeInitialize(); + + /* add the keys */ + ADD_IPV6_MASK("2000::253:192:0:0", 96); + ADD_IPV6_MASK("2000::253:192:235:0", 112); + ADD_IPV6_MASK("2000::192:167:0:0", 96); + ADD_IPV6("2000:0::4"); + ADD_IPV6_MASK("2000::220:168:0:0", 96); + ADD_IPV6("2000::253:224:1:5"); + ADD_IPV6_MASK("2000::192:168:0:0", 96); + + GET_IPV6("2000::192:171:128:0"); + node[0] = SCRadix6AddKeyIPV6Netblock( + &tree, &ut_ip_radix6_config, (uint8_t *)&sa.sin6_addr, 96, NULL); + FAIL_IF_NULL(node[0]); + + GET_IPV6("2000::192:171:128:45"); + node[1] = SCRadix6AddKeyIPV6(&tree, &ut_ip_radix6_config, (uint8_t *)&sa.sin6_addr, NULL); + FAIL_IF_NULL(node[1]); + + ADD_IPV6_MASK("2000::192:171:0:0", 96); + ADD_IPV6_MASK("2000::225:175:21:228", 128); + + /* test for the existance of a key */ + GET_IPV6("2000::192:171:128:53"); + FAIL_IF_NOT(SCRadix6TreeFindBestMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) == node[0]); + FAIL_IF_NOT(SCRadix6TreeFindExactMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) == NULL); + + GET_IPV6("2000::192:171:128:45"); + FAIL_IF_NOT(SCRadix6TreeFindExactMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) == node[1]); + FAIL_IF_NOT(SCRadix6TreeFindBestMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) == node[1]); + + GET_IPV6("2000::192:171:128:78"); + FAIL_IF_NOT(SCRadix6TreeFindBestMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) == node[0]); + FAIL_IF_NOT(SCRadix6TreeFindExactMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) == NULL); + + GET_IPV6("2000::225:175:21:228"); + FAIL_IF_NOT(SCRadix6TreeFindExactMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) != NULL); + + GET_IPV6("2000::225:175:21:224"); + FAIL_IF_NOT(SCRadix6TreeFindExactMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) == NULL); + + GET_IPV6("2000::225:175:21:229"); + FAIL_IF_NOT(SCRadix6TreeFindExactMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) == NULL); + + GET_IPV6("2000::225:175:21:230"); + FAIL_IF_NOT(SCRadix6TreeFindExactMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) == NULL); + + SCRadix6TreeRelease(&tree, &ut_ip_radix6_config); + PASS; +} + +/** + * \test Check that the best match search works for all the + * possible netblocks of a fixed address + */ +static int SCRadix6TestIPV6NetBlocksAndBestSearch16(void) +{ + struct sockaddr_in6 sa; + SCRadix6Tree tree = SCRadix6TreeInitialize(); + + GET_IPV6("2000:1::1"); + for (uint32_t i = 0; i <= 128; i++) { + uint32_t *user = SCMalloc(sizeof(uint32_t)); + FAIL_IF_NULL(user); + *user = i; + SCRadix6AddKeyIPV6Netblock(&tree, &ut_ip_radix6_config, (uint8_t *)&sa.sin6_addr, i, user); + void *user_data = NULL; + SCRadix6Node *node = SCRadix6TreeFindBestMatch(&tree, (uint8_t *)&sa.sin6_addr, &user_data); + FAIL_IF_NULL(node); + FAIL_IF_NULL(user_data); + FAIL_IF(*((uint32_t *)user_data) != i); + } + + SCRadix6TreeRelease(&tree, &ut_ip_radix6_config); + PASS; +} + +/** + * \test Check special combinations of netblocks and addresses + * on best search checking the returned userdata + */ +static int SCRadix6TestIPV6NetBlocksAndBestSearch19(void) +{ + struct sockaddr_in6 sa; + void *user_data = NULL; + SCRadix6Tree tree = SCRadix6TreeInitialize(); + + GET_IPV6("::"); + uint32_t *user = SCMalloc(sizeof(uint32_t)); + FAIL_IF_NULL(user); + *user = 100; + SCRadix6AddKeyIPV6Netblock(&tree, &ut_ip_radix6_config, (uint8_t *)&sa.sin6_addr, 0, user); + + GET_IPV6("2000:1::15"); + SCRadix6Node *node = SCRadix6TreeFindBestMatch(&tree, (uint8_t *)&sa.sin6_addr, &user_data); + FAIL_IF_NULL(node); + FAIL_IF_NULL(user_data); + FAIL_IF(*((uint32_t *)user_data) != 100); + user_data = NULL; + + GET_IPV6("2000:177::0:0:0"); + user = SCMalloc(sizeof(uint32_t)); + FAIL_IF_NULL(user); + *user = 200; + SCRadix6AddKeyIPV6Netblock(&tree, &ut_ip_radix6_config, (uint8_t *)&sa.sin6_addr, 64, user); + + GET_IPV6("2000:177::168:1:15"); + node = SCRadix6TreeFindBestMatch(&tree, (uint8_t *)&sa.sin6_addr, &user_data); + FAIL_IF_NULL(node); + FAIL_IF_NULL(user_data); + FAIL_IF(*((uint32_t *)user_data) != 200); + user_data = NULL; + + GET_IPV6("2000:178::168:1:15"); + node = SCRadix6TreeFindBestMatch(&tree, (uint8_t *)&sa.sin6_addr, &user_data); + FAIL_IF_NULL(node); + FAIL_IF_NULL(user_data); + FAIL_IF(*((uint32_t *)user_data) != 100); + user_data = NULL; + + GET_IPV6("2000:177::168:0:0"); + user = SCMalloc(sizeof(uint32_t)); + FAIL_IF_NULL(user); + *user = 300; + SCRadix6AddKeyIPV6Netblock(&tree, &ut_ip_radix6_config, (uint8_t *)&sa.sin6_addr, 92, user); + + GET_IPV6("2000:177::168:1:15"); + node = SCRadix6TreeFindBestMatch(&tree, (uint8_t *)&sa.sin6_addr, &user_data); + FAIL_IF_NULL(node); + FAIL_IF_NULL(user_data); + FAIL_IF(*((uint32_t *)user_data) != 300); + user_data = NULL; + + GET_IPV6("2000:177::167:1:15"); + node = SCRadix6TreeFindBestMatch(&tree, (uint8_t *)&sa.sin6_addr, &user_data); + FAIL_IF_NULL(node); + FAIL_IF_NULL(user_data); + FAIL_IF(*((uint32_t *)user_data) != 300); + user_data = NULL; + + GET_IPV6("2000:177::178:1:15"); + node = SCRadix6TreeFindBestMatch(&tree, (uint8_t *)&sa.sin6_addr, &user_data); + FAIL_IF_NULL(node); + FAIL_IF_NULL(user_data); + FAIL_IF(*((uint32_t *)user_data) != 200); + user_data = NULL; + + GET_IPV6("2000:197::178:1:15"); + node = SCRadix6TreeFindBestMatch(&tree, (uint8_t *)&sa.sin6_addr, &user_data); + FAIL_IF_NULL(node); + FAIL_IF_NULL(user_data); + FAIL_IF(*((uint32_t *)user_data) != 100); + user_data = NULL; + + SCRadix6TreeRelease(&tree, &ut_ip_radix6_config); + PASS; +} + +/** + * \test SCRadix6TestIPV6NetblockInsertion15 insert a node searching on it. + * Should always return true but the purposse of the test is to monitor + * the memory usage to detect memleaks (there was one on searching) + */ +static int SCRadix6TestIPV6NetblockInsertion25(void) +{ + struct sockaddr_in6 sa; + SCRadix6Tree tree = SCRadix6TreeInitialize(); + ADD_IPV6_MASK("2000::192:168:0:0", 16); + GET_IPV6("2000::192:168:128:53"); + FAIL_IF_NOT(SCRadix6TreeFindBestMatch(&tree, (uint8_t *)&sa.sin6_addr, NULL) != NULL); + SCRadix6TreeRelease(&tree, &ut_ip_radix6_config); + PASS; +} + +/** + * \test SCRadix6TestIPV6NetblockInsertion26 insert a node searching on it. + * Should always return true but the purposse of the test is to monitor + * the memory usage to detect memleaks (there was one on searching) + */ +static int SCRadix6TestIPV6NetblockInsertion26(void) +{ + SCRadix6Node *tmp = NULL; + struct sockaddr_in6 sa; + const SCRadix6Config ut_ip_radix6_config_26 = { free, NULL }; + + char *str = SCStrdup("Hello1"); + FAIL_IF_NULL(str); + + SCRadix6Tree tree = SCRadix6TreeInitialize(); + + GET_IPV6("::"); + SCRadix6AddKeyIPV6Netblock(&tree, &ut_ip_radix6_config_26, (uint8_t *)&sa.sin6_addr, 0, str); + + str = SCStrdup("Hello2"); + FAIL_IF_NULL(str); + + GET_IPV6("2000::176:0:0:1"); + SCRadix6AddKeyIPV6Netblock(&tree, &ut_ip_radix6_config_26, (uint8_t *)&sa.sin6_addr, 5, str); + + str = SCStrdup("Hello3"); + FAIL_IF_NULL(str); + + GET_IPV6("::"); + SCRadix6AddKeyIPV6Netblock(&tree, &ut_ip_radix6_config_26, (uint8_t *)&sa.sin6_addr, 7, str); + + /* test for the existance of a key */ + void *retptr = NULL; + tmp = SCRadix6TreeFindBestMatch(&tree, (uint8_t *)&sa.sin6_addr, &retptr); + FAIL_IF_NULL(tmp); + FAIL_IF_NULL(retptr); + FAIL_IF_NOT(strcmp((char *)retptr, "Hello3") == 0); + + SCRadix6TreeRelease(&tree, &ut_ip_radix6_config_26); + + PASS; +} +#endif + +void SCRadix6RegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("SCRadix6TestIPV6Insertion03", SCRadix6TestIPV6Insertion03); + UtRegisterTest("SCRadix6TestIPV6Removal04", SCRadix6TestIPV6Removal04); + UtRegisterTest("SCRadix6TestIPV6NetblockInsertion09", SCRadix6TestIPV6NetblockInsertion09); + UtRegisterTest("SCRadix6TestIPV6NetblockInsertion10", SCRadix6TestIPV6NetblockInsertion10); + UtRegisterTest("SCRadix6TestIPV6NetblockInsertion11", SCRadix6TestIPV6NetblockInsertion11); + UtRegisterTest("SCRadix6TestIPV6NetblockInsertion12", SCRadix6TestIPV6NetblockInsertion12); + UtRegisterTest( + "SCRadix6TestIPV6NetBlocksAndBestSearch16", SCRadix6TestIPV6NetBlocksAndBestSearch16); + UtRegisterTest( + "SCRadix6TestIPV6NetBlocksAndBestSearch19", SCRadix6TestIPV6NetBlocksAndBestSearch19); + UtRegisterTest("SCRadix6TestIPV6NetblockInsertion25", SCRadix6TestIPV6NetblockInsertion25); + UtRegisterTest("SCRadix6TestIPV6NetblockInsertion26", SCRadix6TestIPV6NetblockInsertion26); +#endif + return; +} diff --git a/src/util-radix6-tree.h b/src/util-radix6-tree.h new file mode 100644 index 000000000000..8df51e2e7b13 --- /dev/null +++ b/src/util-radix6-tree.h @@ -0,0 +1,117 @@ +/* Copyright (C) 2007-2022 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + * Based on util-radix-tree.[ch] by: + * \author Anoop Saldanha + */ + +#ifndef SURICATA_UTIL_RADIX6_TREE_H +#define SURICATA_UTIL_RADIX6_TREE_H + +#include "suricata-common.h" + +struct RadixUserData; + +/** + * \brief Structure for the node in the radix tree + */ +typedef struct SCRadix6Node_ { + /** the key that has been stored in the tree */ + uint8_t prefix_stream[16]; + + /** holds bitmap of netmasks that come under this node in the tree */ + uint8_t masks[17]; + + /** the bit position where the bits differ in the nodes children. Used + * to determine the path to be taken during a lookup */ + uint8_t bit; + /** bool to see if prefix_stream is filled */ + bool has_prefix; + + /** User data that has is associated with this key. We need a user + * data field for each netblock value possible since one ip can be associated + * with any of the 128 netblocks. */ + struct RadixUserData *user_data; + + /** the left and the right children of a node */ + struct SCRadix6Node_ *left, *right; + + /** the parent node for this tree */ + struct SCRadix6Node_ *parent; +} SCRadix6Node; + +/** + * \brief Structure for the radix tree + */ +typedef struct SCRadix6Tree_ { + /** the root node in the radix tree */ + SCRadix6Node *head; +} SCRadix6Tree; + +typedef struct SCRadix6Config_ { + void (*Free)(void *); + /** function pointer that is supplied by the user to free the user data + * held by the user field of SCRadix6Node */ + void (*PrintData)(void *); +} SCRadix6Config; + +#define SC_RADIX6_TREE_INITIALIZER \ + { \ + .head = NULL \ + } + +SCRadix6Tree SCRadix6TreeInitialize(void); +void SCRadix6TreeRelease(SCRadix6Tree *, const SCRadix6Config *); + +SCRadix6Node *SCRadix6AddKeyIPV6(SCRadix6Tree *, const SCRadix6Config *, const uint8_t *, void *); +SCRadix6Node *SCRadix6AddKeyIPV6Netblock( + SCRadix6Tree *, const SCRadix6Config *, const uint8_t *, uint8_t, void *); +bool SCRadix6AddKeyIPV6String(SCRadix6Tree *, const SCRadix6Config *, const char *, void *); + +void SCRadix6RemoveKeyIPV6Netblock( + SCRadix6Tree *, const SCRadix6Config *, const uint8_t *, uint8_t); +void SCRadix6RemoveKeyIPV6(SCRadix6Tree *, const SCRadix6Config *, const uint8_t *); + +SCRadix6Node *SCRadix6TreeFindExactMatch(const SCRadix6Tree *, const uint8_t *, void **); +SCRadix6Node *SCRadix6TreeFindNetblock( + const SCRadix6Tree *, const uint8_t *, const uint8_t, void **); +SCRadix6Node *SCRadix6TreeFindBestMatch(const SCRadix6Tree *, const uint8_t *, void **); +SCRadix6Node *SCRadix6TreeFindBestMatch2(const SCRadix6Tree *, const uint8_t *, void **, uint8_t *); + +void SCRadix6PrintTree(SCRadix6Tree *, const SCRadix6Config *); +void SCRadix6PrintNodeInfo(SCRadix6Node *, int, void (*PrintData)(void *)); + +void SCRadix6RegisterTests(void); + +typedef int (*SCRadix6ForEachNodeFunc)( + const SCRadix6Node *node, void *user_data, const uint8_t netmask, void *data); + +int SCRadix6ForEachNode(const SCRadix6Tree *tree, SCRadix6ForEachNodeFunc Callback, void *data); + +/** \brief compare content of 2 user data entries + * \retval true equal + * \retval false not equal + */ +typedef bool (*SCRadix6TreeCompareFunc)(const void *ud1, const void *ud2); +bool SCRadix6CompareTrees( + const SCRadix6Tree *t1, const SCRadix6Tree *t2, SCRadix6TreeCompareFunc Callback); + +#endif /* SURICATA_UTIL_RADIX4_TREE_H */ From c75b29c74f7566c5ee249eab816c6255f9f81212 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 18 May 2022 21:35:00 +0200 Subject: [PATCH 03/14] reputation: switch cidr handling to radix4/6 Splits the unified tree into a ipv4 specific and ipv6 specific tree. --- src/reputation.c | 59 +++++++++++++++++++----------------------------- src/reputation.h | 9 ++++---- 2 files changed, 28 insertions(+), 40 deletions(-) diff --git a/src/reputation.c b/src/reputation.c index 88ee1b7ce5e3..417b60a52480 100644 --- a/src/reputation.c +++ b/src/reputation.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2019 Open Information Security Foundation +/* Copyright (C) 2007-2022 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free @@ -39,6 +39,8 @@ #include "util-print.h" #include "util-unittest.h" #include "util-validate.h" +#include "util-radix4-tree.h" +#include "util-radix6-tree.h" /** effective reputation version, atomic as the host * time out code will use it to check if a host's @@ -75,6 +77,9 @@ static void SRepCIDRFreeUserData(void *data) SCFree(data); } +static SCRadix4Config iprep_radix4_config = { SRepCIDRFreeUserData, NULL }; +static SCRadix6Config iprep_radix6_config = { SRepCIDRFreeUserData, NULL }; + static void SRepCIDRAddNetblock(SRepCIDRTree *cidr_ctx, char *ip, int cat, uint8_t value) { SReputation *user_data = NULL; @@ -86,34 +91,18 @@ static void SRepCIDRAddNetblock(SRepCIDRTree *cidr_ctx, char *ip, int cat, uint8 user_data->rep[cat] = value; if (strchr(ip, ':') != NULL) { - if (cidr_ctx->srepIPV6_tree[cat] == NULL) { - cidr_ctx->srepIPV6_tree[cat] = SCRadixCreateRadixTree(SRepCIDRFreeUserData, NULL); - if (cidr_ctx->srepIPV6_tree[cat] == NULL) { - SCLogDebug("Error initializing Reputation IPV6 with CIDR module for cat %d", cat); - exit(EXIT_FAILURE); - } - SCLogDebug("Reputation IPV6 with CIDR module for cat %d initialized", cat); - } - SCLogDebug("adding ipv6 host %s", ip); - if (!SCRadixAddKeyIPV6String(ip, cidr_ctx->srepIPV6_tree[cat], (void *)user_data)) { + if (!SCRadix6AddKeyIPV6String( + &cidr_ctx->srep_ipv6_tree[cat], &iprep_radix6_config, ip, (void *)user_data)) { SCFree(user_data); if (sc_errno != SC_EEXIST) SCLogWarning("failed to add ipv6 host %s", ip); } } else { - if (cidr_ctx->srepIPV4_tree[cat] == NULL) { - cidr_ctx->srepIPV4_tree[cat] = SCRadixCreateRadixTree(SRepCIDRFreeUserData, NULL); - if (cidr_ctx->srepIPV4_tree[cat] == NULL) { - SCLogDebug("Error initializing Reputation IPV4 with CIDR module for cat %d", cat); - exit(EXIT_FAILURE); - } - SCLogDebug("Reputation IPV4 with CIDR module for cat %d initialized", cat); - } - SCLogDebug("adding ipv4 host %s", ip); - if (!SCRadixAddKeyIPV4String(ip, cidr_ctx->srepIPV4_tree[cat], (void *)user_data)) { + if (!SCRadix4AddKeyIPV4String( + &cidr_ctx->srep_ipv4_tree[cat], &iprep_radix4_config, ip, (void *)user_data)) { SCFree(user_data); if (sc_errno != SC_EEXIST) SCLogWarning("failed to add ipv4 host %s", ip); @@ -124,7 +113,7 @@ static void SRepCIDRAddNetblock(SRepCIDRTree *cidr_ctx, char *ip, int cat, uint8 static int8_t SRepCIDRGetIPv4IPRep(SRepCIDRTree *cidr_ctx, uint8_t *ipv4_addr, uint8_t cat) { void *user_data = NULL; - (void)SCRadixFindKeyIPV4BestMatch(ipv4_addr, cidr_ctx->srepIPV4_tree[cat], &user_data); + (void)SCRadix4TreeFindBestMatch(&cidr_ctx->srep_ipv4_tree[cat], ipv4_addr, &user_data); if (user_data == NULL) return -1; @@ -135,7 +124,7 @@ static int8_t SRepCIDRGetIPv4IPRep(SRepCIDRTree *cidr_ctx, uint8_t *ipv4_addr, u static int8_t SRepCIDRGetIPv6IPRep(SRepCIDRTree *cidr_ctx, uint8_t *ipv6_addr, uint8_t cat) { void *user_data = NULL; - (void)SCRadixFindKeyIPV6BestMatch(ipv6_addr, cidr_ctx->srepIPV6_tree[cat], &user_data); + (void)SCRadix6TreeFindBestMatch(&cidr_ctx->srep_ipv6_tree[cat], ipv6_addr, &user_data); if (user_data == NULL) return -1; @@ -584,6 +573,12 @@ int SRepInit(DetectEngineCtx *de_ctx) de_ctx->srepCIDR_ctx = (SRepCIDRTree *)SCCalloc(1, sizeof(SRepCIDRTree)); if (de_ctx->srepCIDR_ctx == NULL) exit(EXIT_FAILURE); + + for (int i = 0; i < SREP_MAX_CATS; i++) { + de_ctx->srepCIDR_ctx->srep_ipv4_tree[i] = SCRadix4TreeInitialize(); + de_ctx->srepCIDR_ctx->srep_ipv6_tree[i] = SCRadix6TreeInitialize(); + } + SRepCIDRTree *cidr_ctx = de_ctx->srepCIDR_ctx; if (SRepGetVersion() == 0) { @@ -651,21 +646,13 @@ int SRepInit(DetectEngineCtx *de_ctx) return 0; } -void SRepDestroy(DetectEngineCtx *de_ctx) { +void SRepDestroy(DetectEngineCtx *de_ctx) +{ if (de_ctx->srepCIDR_ctx != NULL) { - int i; - for (i = 0; i < SREP_MAX_CATS; i++) { - if (de_ctx->srepCIDR_ctx->srepIPV4_tree[i] != NULL) { - SCRadixReleaseRadixTree(de_ctx->srepCIDR_ctx->srepIPV4_tree[i]); - de_ctx->srepCIDR_ctx->srepIPV4_tree[i] = NULL; - } - - if (de_ctx->srepCIDR_ctx->srepIPV6_tree[i] != NULL) { - SCRadixReleaseRadixTree(de_ctx->srepCIDR_ctx->srepIPV6_tree[i]); - de_ctx->srepCIDR_ctx->srepIPV6_tree[i] = NULL; - } + for (int i = 0; i < SREP_MAX_CATS; i++) { + SCRadix4TreeRelease(&de_ctx->srepCIDR_ctx->srep_ipv4_tree[i], &iprep_radix4_config); + SCRadix6TreeRelease(&de_ctx->srepCIDR_ctx->srep_ipv6_tree[i], &iprep_radix6_config); } - SCFree(de_ctx->srepCIDR_ctx); de_ctx->srepCIDR_ctx = NULL; } diff --git a/src/reputation.h b/src/reputation.h index d7009776ceda..91285c340e01 100644 --- a/src/reputation.h +++ b/src/reputation.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2019 Open Information Security Foundation +/* Copyright (C) 2007-2022 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free @@ -27,14 +27,15 @@ #define SURICATA_REPUTATION_H #include "host.h" -#include "util-radix-tree.h" +#include "util-radix4-tree.h" +#include "util-radix6-tree.h" #define SREP_MAX_CATS 60 #define SREP_MAX_VAL 127 typedef struct SRepCIDRTree_ { - SCRadixTree *srepIPV4_tree[SREP_MAX_CATS]; - SCRadixTree *srepIPV6_tree[SREP_MAX_CATS]; + SCRadix4Tree srep_ipv4_tree[SREP_MAX_CATS]; + SCRadix6Tree srep_ipv6_tree[SREP_MAX_CATS]; } SRepCIDRTree; typedef struct SReputation_ { From 46fb7bb16233b8e9f160a75013e6ec3664160f72 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 18 May 2022 22:09:56 +0200 Subject: [PATCH 04/14] defrag/config: switch to radix4/6 Splits the unified tree into a ipv4 specific and ipv6 specific tree. --- src/defrag-config.c | 48 ++++++++++++++++++++++----------------------- src/defrag-config.h | 2 +- 2 files changed, 24 insertions(+), 26 deletions(-) diff --git a/src/defrag-config.c b/src/defrag-config.c index 23725dea3963..d22ac44a0b73 100644 --- a/src/defrag-config.c +++ b/src/defrag-config.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2013 Open Information Security Foundation +/* Copyright (C) 2007-2022 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free @@ -25,12 +25,9 @@ #include "suricata-common.h" #include "defrag-config.h" #include "util-misc.h" -#include "util-radix-tree.h" #include "conf.h" - -static SCRadixTree *defrag_tree = NULL; - -static int default_timeout = 0; +#include "util-radix4-tree.h" +#include "util-radix6-tree.h" static void DefragPolicyFreeUserData(void *data) { @@ -38,7 +35,14 @@ static void DefragPolicyFreeUserData(void *data) SCFree(data); } -static void DefragPolicyAddHostInfo(char *host_ip_range, uint64_t timeout) +static SCRadix4Tree defrag4_tree = SC_RADIX4_TREE_INITIALIZER; +static SCRadix6Tree defrag6_tree = SC_RADIX6_TREE_INITIALIZER; +static SCRadix4Config defrag4_config = { DefragPolicyFreeUserData, NULL }; +static SCRadix6Config defrag6_config = { DefragPolicyFreeUserData, NULL }; + +static int default_timeout = 0; + +static void DefragPolicyAddHostInfo(const char *host_ip_range, uint64_t timeout) { uint64_t *user_data = NULL; @@ -50,7 +54,8 @@ static void DefragPolicyAddHostInfo(char *host_ip_range, uint64_t timeout) if (strchr(host_ip_range, ':') != NULL) { SCLogDebug("adding ipv6 host %s", host_ip_range); - if (!SCRadixAddKeyIPV6String(host_ip_range, defrag_tree, (void *)user_data)) { + if (!SCRadix6AddKeyIPV6String( + &defrag6_tree, &defrag6_config, host_ip_range, (void *)user_data)) { SCFree(user_data); if (sc_errno != SC_EEXIST) { SCLogWarning("failed to add ipv6 host %s", host_ip_range); @@ -58,8 +63,8 @@ static void DefragPolicyAddHostInfo(char *host_ip_range, uint64_t timeout) } } else { SCLogDebug("adding ipv4 host %s", host_ip_range); - if (!SCRadixAddKeyIPV4String(host_ip_range, defrag_tree, (void *)user_data)) { - SCFree(user_data); + if (!SCRadix4AddKeyIPV4String( + &defrag4_tree, &defrag4_config, host_ip_range, (void *)user_data)) { if (sc_errno != SC_EEXIST) { SCLogWarning("failed to add ipv4 host %s", host_ip_range); } @@ -67,20 +72,20 @@ static void DefragPolicyAddHostInfo(char *host_ip_range, uint64_t timeout) } } -static int DefragPolicyGetIPv4HostTimeout(uint8_t *ipv4_addr) +static int DefragPolicyGetIPv4HostTimeout(const uint8_t *ipv4_addr) { void *user_data = NULL; - (void)SCRadixFindKeyIPV4BestMatch(ipv4_addr, defrag_tree, &user_data); + (void)SCRadix4TreeFindBestMatch(&defrag4_tree, ipv4_addr, &user_data); if (user_data == NULL) return -1; return *((int *)user_data); } -static int DefragPolicyGetIPv6HostTimeout(uint8_t *ipv6_addr) +static int DefragPolicyGetIPv6HostTimeout(const uint8_t *ipv6_addr) { void *user_data = NULL; - (void)SCRadixFindKeyIPV6BestMatch(ipv6_addr, defrag_tree, &user_data); + (void)SCRadix6TreeFindBestMatch(&defrag6_tree, ipv6_addr, &user_data); if (user_data == NULL) return -1; @@ -92,9 +97,9 @@ int DefragPolicyGetHostTimeout(Packet *p) int timeout = 0; if (PacketIsIPv4(p)) - timeout = DefragPolicyGetIPv4HostTimeout((uint8_t *)GET_IPV4_DST_ADDR_PTR(p)); + timeout = DefragPolicyGetIPv4HostTimeout((const uint8_t *)GET_IPV4_DST_ADDR_PTR(p)); else if (PacketIsIPv6(p)) - timeout = DefragPolicyGetIPv6HostTimeout((uint8_t *)GET_IPV6_DST_ADDR(p)); + timeout = DefragPolicyGetIPv6HostTimeout((const uint8_t *)GET_IPV6_DST_ADDR(p)); if (timeout <= 0) timeout = default_timeout; @@ -134,11 +139,6 @@ void DefragPolicyLoadFromConfig(void) { SCEnter(); - defrag_tree = SCRadixCreateRadixTree(DefragPolicyFreeUserData, NULL); - if (defrag_tree == NULL) { - FatalError("Can't alloc memory for the defrag config tree."); - } - ConfNode *server_config = ConfGetNode("defrag.host-config"); if (server_config == NULL) { SCLogDebug("failed to read host config"); @@ -160,8 +160,6 @@ void DefragPolicyLoadFromConfig(void) void DefragTreeDestroy(void) { - if (defrag_tree != NULL) { - SCRadixReleaseRadixTree(defrag_tree); - } - defrag_tree = NULL; + SCRadix4TreeRelease(&defrag4_tree, &defrag4_config); + SCRadix6TreeRelease(&defrag6_tree, &defrag6_config); } diff --git a/src/defrag-config.h b/src/defrag-config.h index e2b15dbb3167..3696c908bcf7 100644 --- a/src/defrag-config.h +++ b/src/defrag-config.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2013 Open Information Security Foundation +/* Copyright (C) 2007-2022 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free From 82cd053fc8ad647c2eb379cd2b9ea1cc1f4420b2 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 18 May 2022 23:49:56 +0200 Subject: [PATCH 05/14] htp: switch config tree to radix4/6 Splits the unified tree into a ipv4 specific and ipv6 specific tree. --- src/app-layer-htp.c | 74 ++++++++++++++++++++++----------------------- 1 file changed, 36 insertions(+), 38 deletions(-) diff --git a/src/app-layer-htp.c b/src/app-layer-htp.c index 4acc105bab9a..f1d3c56c16af 100644 --- a/src/app-layer-htp.c +++ b/src/app-layer-htp.c @@ -76,7 +76,16 @@ //#define PRINT /** Fast lookup tree (radix) for the various HTP configurations */ -static SCRadixTree *cfgtree; +static struct HTPConfigTree { + SCRadix4Tree ipv4; + SCRadix6Tree ipv6; +} cfgtree = { + .ipv4 = SC_RADIX4_TREE_INITIALIZER, + .ipv6 = SC_RADIX6_TREE_INITIALIZER, +}; +SCRadix4Config htp_radix4_cfg = { NULL, NULL }; +SCRadix6Config htp_radix6_cfg = { NULL, NULL }; + /** List of HTP configurations. */ static HTPCfgRec cfglist; @@ -791,11 +800,12 @@ static int Setup(Flow *f, HtpState *hstate) if (FLOW_IS_IPV4(f)) { SCLogDebug("Looking up HTP config for ipv4 %08x", *GET_IPV4_DST_ADDR_PTR(f)); - (void)SCRadixFindKeyIPV4BestMatch((uint8_t *)GET_IPV4_DST_ADDR_PTR(f), cfgtree, &user_data); + (void)SCRadix4TreeFindBestMatch( + &cfgtree.ipv4, (uint8_t *)GET_IPV4_DST_ADDR_PTR(f), &user_data); } else if (FLOW_IS_IPV6(f)) { SCLogDebug("Looking up HTP config for ipv6"); - (void)SCRadixFindKeyIPV6BestMatch((uint8_t *)GET_IPV6_DST_ADDR(f), cfgtree, &user_data); + (void)SCRadix6TreeFindBestMatch(&cfgtree.ipv6, (uint8_t *)GET_IPV6_DST_ADDR(f), &user_data); } else { SCLogError("unknown address family, bug!"); @@ -1659,8 +1669,6 @@ void HTPFreeConfig(void) } HTPCfgRec *nextrec = cfglist.next; - SCRadixReleaseRadixTree(cfgtree); - cfgtree = NULL; htp_config_destroy(cfglist.cfg); while (nextrec != NULL) { HTPCfgRec *htprec = nextrec; @@ -1669,6 +1677,8 @@ void HTPFreeConfig(void) htp_config_destroy(htprec->cfg); SCFree(htprec); } + SCRadix4TreeRelease(&cfgtree.ipv4, &htp_radix4_cfg); + SCRadix6TreeRelease(&cfgtree.ipv6, &htp_radix6_cfg); SCReturn; } @@ -2162,8 +2172,7 @@ static void HTPConfigSetDefaultsPhase2(const char *name, HTPCfgRec *cfg_prec) htp_config_register_request_line(cfg_prec->cfg, HTPCallbackRequestLine); } -static void HTPConfigParseParameters(HTPCfgRec *cfg_prec, ConfNode *s, - SCRadixTree *tree) +static void HTPConfigParseParameters(HTPCfgRec *cfg_prec, ConfNode *s, struct HTPConfigTree *tree) { if (cfg_prec == NULL || s == NULL || tree == NULL) return; @@ -2171,31 +2180,26 @@ static void HTPConfigParseParameters(HTPCfgRec *cfg_prec, ConfNode *s, ConfNode *p = NULL; /* Default Parameters */ - TAILQ_FOREACH(p, &s->head, next) { - + TAILQ_FOREACH (p, &s->head, next) { if (strcasecmp("address", p->name) == 0) { ConfNode *pval; /* Addresses */ TAILQ_FOREACH(pval, &p->head, next) { - SCLogDebug("LIBHTP server %s: %s=%s", s->name, p->name, - pval->val); - + SCLogDebug("LIBHTP server %s: %s=%s", s->name, p->name, pval->val); /* IPV6 or IPV4? */ if (strchr(pval->val, ':') != NULL) { SCLogDebug("LIBHTP adding ipv6 server %s at %s: %p", s->name, pval->val, cfg_prec->cfg); - if (!SCRadixAddKeyIPV6String(pval->val, tree, cfg_prec)) { - SCLogWarning("LIBHTP failed to " - "add ipv6 server %s, ignoring", - pval->val); + if (!SCRadix6AddKeyIPV6String( + &tree->ipv6, &htp_radix6_cfg, pval->val, cfg_prec)) { + SCLogWarning("LIBHTP failed to add ipv6 server %s, ignoring", pval->val); } } else { SCLogDebug("LIBHTP adding ipv4 server %s at %s: %p", s->name, pval->val, cfg_prec->cfg); - if (!SCRadixAddKeyIPV4String(pval->val, tree, cfg_prec)) { - SCLogWarning("LIBHTP failed " - "to add ipv4 server %s, ignoring", - pval->val); + if (!SCRadix4AddKeyIPV4String( + &tree->ipv4, &htp_radix4_cfg, pval->val, cfg_prec)) { + SCLogWarning("LIBHTP failed to add ipv4 server %s, ignoring", pval->val); } } /* else - if (strchr(pval->val, ':') != NULL) */ } /* TAILQ_FOREACH(pval, &p->head, next) */ @@ -2563,10 +2567,6 @@ void HTPConfigure(void) htp_sbcfg.Realloc = HTPRealloc; htp_sbcfg.Free = HTPFree; - cfgtree = SCRadixCreateRadixTree(NULL, NULL); - if (NULL == cfgtree) - exit(EXIT_FAILURE); - /* Default Config */ cfglist.cfg = htp_config_create(); if (NULL == cfglist.cfg) { @@ -2575,10 +2575,10 @@ void HTPConfigure(void) SCLogDebug("LIBHTP default config: %p", cfglist.cfg); HTPConfigSetDefaultsPhase1(&cfglist); if (ConfGetNode("app-layer.protocols.http.libhtp") == NULL) { - HTPConfigParseParameters(&cfglist, ConfGetNode("libhtp.default-config"), - cfgtree); + HTPConfigParseParameters(&cfglist, ConfGetNode("libhtp.default-config"), &cfgtree); } else { - HTPConfigParseParameters(&cfglist, ConfGetNode("app-layer.protocols.http.libhtp.default-config"), cfgtree); + HTPConfigParseParameters( + &cfglist, ConfGetNode("app-layer.protocols.http.libhtp.default-config"), &cfgtree); } HTPConfigSetDefaultsPhase2("default", &cfglist); @@ -2621,7 +2621,7 @@ void HTPConfigure(void) } HTPConfigSetDefaultsPhase1(htprec); - HTPConfigParseParameters(htprec, s, cfgtree); + HTPConfigParseParameters(htprec, s, &cfgtree); HTPConfigSetDefaultsPhase2(s->name, htprec); } @@ -3957,14 +3957,11 @@ libhtp:\n\ ConfCreateContextBackup(); ConfInit(); HtpConfigCreateBackup(); - ConfYamlLoadString(input, strlen(input)); - HTPConfigure(); - FAIL_IF_NULL(cfglist.cfg); - - FAIL_IF_NULL(cfgtree); + FAIL_IF_NULL(cfgtree.ipv4.head); + FAIL_IF_NULL(cfgtree.ipv6.head); htp_cfg_t *htp = cfglist.cfg; uint8_t buf[128]; @@ -3973,7 +3970,7 @@ libhtp:\n\ addr = "192.168.10.42"; FAIL_IF(inet_pton(AF_INET, addr, buf) != 1); - (void)SCRadixFindKeyIPV4BestMatch(buf, cfgtree, &user_data); + (void)SCRadix4TreeFindBestMatch(&cfgtree.ipv4, buf, &user_data); FAIL_IF_NULL(user_data); HTPCfgRec *htp_cfg_rec = user_data; htp = htp_cfg_rec->cfg; @@ -3983,7 +3980,7 @@ libhtp:\n\ user_data = NULL; addr = "::1"; FAIL_IF(inet_pton(AF_INET6, addr, buf) != 1); - (void)SCRadixFindKeyIPV6BestMatch(buf, cfgtree, &user_data); + (void)SCRadix6TreeFindBestMatch(&cfgtree.ipv6, buf, &user_data); FAIL_IF_NULL(user_data); htp_cfg_rec = user_data; htp = htp_cfg_rec->cfg; @@ -4049,16 +4046,17 @@ libhtp:\n\ f->alproto = ALPROTO_HTTP1; htp_cfg_t *htp = cfglist.cfg; + FAIL_IF_NULL(htp); void *user_data = NULL; - (void)SCRadixFindKeyIPV4BestMatch((uint8_t *)f->dst.addr_data32, cfgtree, &user_data); + (void)SCRadix4TreeFindBestMatch(&cfgtree.ipv4, (uint8_t *)f->dst.addr_data32, &user_data); FAIL_IF_NULL(user_data); + HTPCfgRec *htp_cfg_rec = user_data; htp = htp_cfg_rec->cfg; + FAIL_IF_NULL(user_data); SCLogDebug("LIBHTP using config: %p", htp); - FAIL_IF_NULL(htp); - StreamTcpInitConfig(true); uint32_t u; From 8536dd51b5f7cf67227dc8f059208165c6ab2f9d Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 19 May 2022 08:12:09 +0200 Subject: [PATCH 06/14] host-os-policy: switch to radix4/6 Splits the unified tree into a ipv4 specific and ipv6 specific tree. --- src/util-host-os-info.c | 314 ++++++++++++---------------------------- src/util-host-os-info.h | 3 +- 2 files changed, 91 insertions(+), 226 deletions(-) diff --git a/src/util-host-os-info.c b/src/util-host-os-info.c index 0d455c1c876b..1b5443bc7777 100644 --- a/src/util-host-os-info.c +++ b/src/util-host-os-info.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation +/* Copyright (C) 2007-2022 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free @@ -28,7 +28,8 @@ #include "util-error.h" #include "util-debug.h" #include "util-ip.h" -#include "util-radix-tree.h" +#include "util-radix4-tree.h" +#include "util-radix6-tree.h" #include "util-byte.h" #include "stream-tcp-private.h" #include "stream-tcp-reassemble.h" @@ -58,9 +59,9 @@ SCEnumCharMap sc_hinfo_os_policy_map[ ] = { { NULL, -1 }, }; -/** Radix tree that holds the host OS information */ -static SCRadixTree *sc_hinfo_tree = NULL; - +/** Radix trees that hold the host OS information */ +static SCRadix4Tree sc_hinfo_tree4 = SC_RADIX4_TREE_INITIALIZER; +static SCRadix6Tree sc_hinfo_tree6 = SC_RADIX6_TREE_INITIALIZER; /** * \brief Allocates the host_os flavour wrapped in user_data variable to be sent @@ -75,20 +76,18 @@ static SCRadixTree *sc_hinfo_tree = NULL; */ static void *SCHInfoAllocUserDataOSPolicy(const char *host_os) { - int *user_data = NULL; - - if ( (user_data = SCMalloc(sizeof(int))) == NULL) { - FatalError("Error allocating memory. Exiting"); - } - /* the host os flavour that has to be sent as user data */ - if ( (*user_data = SCMapEnumNameToValue(host_os, sc_hinfo_os_policy_map)) == -1) { - SCLogError("Invalid enum map inside " - "SCHInfoAddHostOSInfo()"); - SCFree(user_data); + int v = SCMapEnumNameToValue(host_os, sc_hinfo_os_policy_map); + if (v == -1) { + SCLogError("Invalid enum map inside SCHInfoAddHostOSInfo()"); return NULL; } + int *user_data = SCMalloc(sizeof(int)); + if (user_data == NULL) { + FatalError("Error allocating memory. Exiting"); + } + *user_data = v; return (void *)user_data; } @@ -103,6 +102,9 @@ static void SCHInfoFreeUserDataOSPolicy(void *data) SCFree(data); } +static const SCRadix4Config ospolicy_radix4_config = { SCHInfoFreeUserDataOSPolicy, NULL }; +static const SCRadix6Config ospolicy_radix6_config = { SCHInfoFreeUserDataOSPolicy, NULL }; + /** * \brief Used to add the host-os-info data obtained from the conf * @@ -121,10 +123,6 @@ int SCHInfoAddHostOSInfo(const char *host_os, const char *host_os_ip_range, int { char *ip_str = NULL; char *ip_str_rem = NULL; - struct in_addr *ipv4_addr = NULL; - struct in6_addr *ipv6_addr = NULL; - char *netmask_str = NULL; - uint8_t netmask_value = 0; int *user_data = NULL; bool recursive = false; @@ -134,10 +132,6 @@ int SCHInfoAddHostOSInfo(const char *host_os, const char *host_os_ip_range, int return -1; } - /* create the radix tree that would hold all the host os info */ - if (sc_hinfo_tree == NULL) - sc_hinfo_tree = SCRadixCreateRadixTree(SCHInfoFreeUserDataOSPolicy, NULL); - /* the host os flavour that has to be sent as user data */ if ( (user_data = SCHInfoAllocUserDataOSPolicy(host_os)) == NULL) { SCLogError("Invalid enum map inside"); @@ -164,64 +158,30 @@ int SCHInfoAddHostOSInfo(const char *host_os, const char *host_os_ip_range, int recursive = true; } - /* check if we have received a netblock */ - if ( (netmask_str = strchr(ip_str, '/')) != NULL) { - netmask_str[0] = '\0'; - netmask_str++; - } - if (strchr(ip_str, ':') == NULL) { - /* if we are here, we have an IPV4 address */ - if ( (ipv4_addr = ValidateIPV4Address(ip_str)) == NULL) { - SCLogError("Invalid IPV4 address"); + if (!SCRadix4AddKeyIPV4String( + &sc_hinfo_tree4, &ospolicy_radix4_config, ip_str, user_data)) { + if (sc_errno == SC_EEXIST) { + SCLogError("duplicate ipv4 address '%s'", ip_str); + } else { + SCLogError("invalid ipv4 address '%s'", ip_str); + } SCHInfoFreeUserDataOSPolicy(user_data); SCFree(ip_str); return -1; } - - if (netmask_str == NULL) { - SCRadixAddKeyIPV4((uint8_t *)ipv4_addr, sc_hinfo_tree, - (void *)user_data); - } else { - if (StringParseU8RangeCheck(&netmask_value, 10, 0, (const char *)netmask_str, 0, 32) < - 0) { - SCLogError("Invalid IPV4 Netblock"); - SCHInfoFreeUserDataOSPolicy(user_data); - SCFree(ipv4_addr); - SCFree(ip_str); - return -1; - } - - MaskIPNetblock((uint8_t *)ipv4_addr, netmask_value, 32); - SCRadixAddKeyIPV4Netblock((uint8_t *)ipv4_addr, sc_hinfo_tree, - (void *)user_data, netmask_value); - } } else { - /* if we are here, we have an IPV6 address */ - if ( (ipv6_addr = ValidateIPV6Address(ip_str)) == NULL) { - SCLogError("Invalid IPV6 address inside"); + if (!SCRadix6AddKeyIPV6String( + &sc_hinfo_tree6, &ospolicy_radix6_config, ip_str, user_data)) { + if (sc_errno == SC_EEXIST) { + SCLogError("duplicate ipv6 address '%s'", ip_str); + } else { + SCLogError("invalid ipv6 address '%s'", ip_str); + } SCHInfoFreeUserDataOSPolicy(user_data); SCFree(ip_str); return -1; } - - if (netmask_str == NULL) { - SCRadixAddKeyIPV6((uint8_t *)ipv6_addr, sc_hinfo_tree, - (void *)user_data); - } else { - if (StringParseU8RangeCheck(&netmask_value, 10, 0, (const char *)netmask_str, 0, 128) < - 0) { - SCLogError("Invalid IPV6 Netblock"); - SCHInfoFreeUserDataOSPolicy(user_data); - SCFree(ipv6_addr); - SCFree(ip_str); - return -1; - } - - MaskIPNetblock((uint8_t *)ipv6_addr, netmask_value, 128); - SCRadixAddKeyIPV6Netblock((uint8_t *)ipv6_addr, sc_hinfo_tree, - (void *)user_data, netmask_value); - } } if (recursive) { @@ -229,13 +189,10 @@ int SCHInfoAddHostOSInfo(const char *host_os, const char *host_os_ip_range, int } SCFree(ip_str); - if (ipv4_addr != NULL) - SCFree(ipv4_addr); - if (ipv6_addr != NULL) - SCFree(ipv6_addr); return *user_data; } +#ifdef UNITTESTS /** * \brief Retrieves the host os flavour, given an ipv4/ipv6 address as a string. * @@ -243,41 +200,38 @@ int SCHInfoAddHostOSInfo(const char *host_os, const char *host_os_ip_range, int * * \retval The OS flavour on success; -1 on failure, or on not finding the key */ -int SCHInfoGetHostOSFlavour(const char *ip_addr_str) +static int SCHInfoGetHostOSFlavour(const char *str) { - struct in_addr *ipv4_addr = NULL; - struct in6_addr *ipv6_addr = NULL; void *user_data = NULL; - if (ip_addr_str == NULL || strchr(ip_addr_str, '/') != NULL) + if (str == NULL || strchr(str, '/') != NULL) return -1; - if (strchr(ip_addr_str, ':') != NULL) { - if ( (ipv6_addr = ValidateIPV6Address(ip_addr_str)) == NULL) { - SCLogError("Invalid IPV4 address"); + if (strchr(str, ':') != NULL) { + struct in6_addr addr; + if (inet_pton(AF_INET6, str, &addr) <= 0) { + SCLogError("Invalid IPV6 address"); return -1; } - - (void)SCRadixFindKeyIPV6BestMatch((uint8_t *)ipv6_addr, sc_hinfo_tree, &user_data); - SCFree(ipv6_addr); + (void)SCRadix6TreeFindBestMatch(&sc_hinfo_tree6, (uint8_t *)&addr.s6_addr, &user_data); if (user_data == NULL) return -1; else return *((int *)user_data); } else { - if ( (ipv4_addr = ValidateIPV4Address(ip_addr_str)) == NULL) { + struct in_addr addr; + if (inet_pton(AF_INET, str, &addr) <= 0) { SCLogError("Invalid IPV4 address"); return -1; } - - (void)SCRadixFindKeyIPV4BestMatch((uint8_t *)ipv4_addr, sc_hinfo_tree, &user_data); - SCFree(ipv4_addr); + (void)SCRadix4TreeFindBestMatch(&sc_hinfo_tree4, (uint8_t *)&addr.s_addr, &user_data); if (user_data == NULL) return -1; else return *((int *)user_data); } } +#endif /** * \brief Retrieves the host os flavour, given an ipv4 address in the raw @@ -287,14 +241,13 @@ int SCHInfoGetHostOSFlavour(const char *ip_addr_str) * * \retval The OS flavour on success; -1 on failure, or on not finding the key */ -int SCHInfoGetIPv4HostOSFlavour(uint8_t *ipv4_addr) +int SCHInfoGetIPv4HostOSFlavour(uint8_t *addr) { void *user_data = NULL; - (void)SCRadixFindKeyIPV4BestMatch(ipv4_addr, sc_hinfo_tree, &user_data); + (void)SCRadix4TreeFindBestMatch(&sc_hinfo_tree4, addr, &user_data); if (user_data == NULL) return -1; - else - return *((int *)user_data); + return *((int *)user_data); } /** @@ -305,22 +258,19 @@ int SCHInfoGetIPv4HostOSFlavour(uint8_t *ipv4_addr) * * \retval The OS flavour on success; -1 on failure, or on not finding the key */ -int SCHInfoGetIPv6HostOSFlavour(uint8_t *ipv6_addr) +int SCHInfoGetIPv6HostOSFlavour(uint8_t *addr) { void *user_data = NULL; - (void)SCRadixFindKeyIPV6BestMatch(ipv6_addr, sc_hinfo_tree, &user_data); + (void)SCRadix6TreeFindBestMatch(&sc_hinfo_tree6, addr, &user_data); if (user_data == NULL) return -1; - else - return *((int *)user_data); + return *((int *)user_data); } void SCHInfoCleanResources(void) { - if (sc_hinfo_tree != NULL) { - SCRadixReleaseRadixTree(sc_hinfo_tree); - sc_hinfo_tree = NULL; - } + SCRadix4TreeRelease(&sc_hinfo_tree4, &ospolicy_radix4_config); + SCRadix6TreeRelease(&sc_hinfo_tree6, &ospolicy_radix6_config); } /** @@ -342,10 +292,9 @@ void SCHInfoLoadFromConfig(void) if (host->val != NULL && strchr(host->val, ':') != NULL) is_ipv4 = 0; if (SCHInfoAddHostOSInfo(policy->name, host->val, is_ipv4) == -1) { - SCLogError("Failed to add host \"%s\" with policy \"%s\" to host " + FatalError("Failed to add host \"%s\" with policy \"%s\" to host " "info database", host->val, policy->name); - exit(EXIT_FAILURE); } } } @@ -354,18 +303,23 @@ void SCHInfoLoadFromConfig(void) /*------------------------------------Unit_Tests------------------------------*/ #ifdef UNITTESTS -static SCRadixTree *sc_hinfo_tree_backup = NULL; +static SCRadix4Tree sc_hinfo_tree_backup4 = SC_RADIX4_TREE_INITIALIZER; +static SCRadix6Tree sc_hinfo_tree_backup6 = SC_RADIX6_TREE_INITIALIZER; static void SCHInfoCreateContextBackup(void) { - sc_hinfo_tree_backup = sc_hinfo_tree; - sc_hinfo_tree = NULL; + sc_hinfo_tree_backup4 = sc_hinfo_tree4; + sc_hinfo_tree4 = SCRadix4TreeInitialize(); + sc_hinfo_tree_backup6 = sc_hinfo_tree6; + sc_hinfo_tree6 = SCRadix6TreeInitialize(); } static void SCHInfoRestoreContextBackup(void) { - sc_hinfo_tree = sc_hinfo_tree_backup; - sc_hinfo_tree_backup = NULL; + sc_hinfo_tree4 = sc_hinfo_tree_backup4; + sc_hinfo_tree_backup4 = SCRadix4TreeInitialize(); + sc_hinfo_tree6 = sc_hinfo_tree_backup6; + sc_hinfo_tree_backup6 = SCRadix6TreeInitialize(); } /** @@ -377,27 +331,27 @@ static int SCHInfoTestInvalidOSFlavour01(void) SCHInfoCreateContextBackup(); FAIL_IF(SCHInfoAddHostOSInfo("bamboo", "192.168.1.1", SC_HINFO_IS_IPV4) != -1); - FAIL_IF(SCHInfoAddHostOSInfo("linux", "192.168.1.1", SC_HINFO_IS_IPV4) != + FAIL_IF(SCHInfoAddHostOSInfo("linux", "192.168.1.2", SC_HINFO_IS_IPV4) != SCMapEnumNameToValue("linux", sc_hinfo_os_policy_map)); - FAIL_IF(SCHInfoAddHostOSInfo("windows", "192.168.1.1", SC_HINFO_IS_IPV4) != + FAIL_IF(SCHInfoAddHostOSInfo("windows", "192.168.1.3", SC_HINFO_IS_IPV4) != SCMapEnumNameToValue("windows", sc_hinfo_os_policy_map)); - FAIL_IF(SCHInfoAddHostOSInfo("solaris", "192.168.1.1", SC_HINFO_IS_IPV4) != + FAIL_IF(SCHInfoAddHostOSInfo("solaris", "192.168.1.4", SC_HINFO_IS_IPV4) != SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)); - FAIL_IF(SCHInfoAddHostOSInfo("hpux10", "192.168.1.1", SC_HINFO_IS_IPV4) != + FAIL_IF(SCHInfoAddHostOSInfo("hpux10", "192.168.1.5", SC_HINFO_IS_IPV4) != SCMapEnumNameToValue("hpux10", sc_hinfo_os_policy_map)); - FAIL_IF(SCHInfoAddHostOSInfo("hpux11", "192.168.1.1", SC_HINFO_IS_IPV4) != + FAIL_IF(SCHInfoAddHostOSInfo("hpux11", "192.168.1.6", SC_HINFO_IS_IPV4) != SCMapEnumNameToValue("hpux11", sc_hinfo_os_policy_map)); - FAIL_IF(SCHInfoAddHostOSInfo("irix", "192.168.1.1", SC_HINFO_IS_IPV4) != + FAIL_IF(SCHInfoAddHostOSInfo("irix", "192.168.1.7", SC_HINFO_IS_IPV4) != SCMapEnumNameToValue("irix", sc_hinfo_os_policy_map)); - FAIL_IF(SCHInfoAddHostOSInfo("bsd", "192.168.1.1", SC_HINFO_IS_IPV4) != + FAIL_IF(SCHInfoAddHostOSInfo("bsd", "192.168.1.8", SC_HINFO_IS_IPV4) != SCMapEnumNameToValue("bsd", sc_hinfo_os_policy_map)); - FAIL_IF(SCHInfoAddHostOSInfo("old_linux", "192.168.1.1", SC_HINFO_IS_IPV4) != + FAIL_IF(SCHInfoAddHostOSInfo("old_linux", "192.168.1.9", SC_HINFO_IS_IPV4) != SCMapEnumNameToValue("old_linux", sc_hinfo_os_policy_map)); - FAIL_IF(SCHInfoAddHostOSInfo("macos", "192.168.1.1", SC_HINFO_IS_IPV4) != + FAIL_IF(SCHInfoAddHostOSInfo("macos", "192.168.1.10", SC_HINFO_IS_IPV4) != SCMapEnumNameToValue("macos", sc_hinfo_os_policy_map)); - FAIL_IF(SCHInfoAddHostOSInfo("vista", "192.168.1.1", SC_HINFO_IS_IPV4) != + FAIL_IF(SCHInfoAddHostOSInfo("vista", "192.168.1.11", SC_HINFO_IS_IPV4) != SCMapEnumNameToValue("vista", sc_hinfo_os_policy_map)); - FAIL_IF(SCHInfoAddHostOSInfo("windows2k3", "192.168.1.1", SC_HINFO_IS_IPV4) != + FAIL_IF(SCHInfoAddHostOSInfo("windows2k3", "192.168.1.12", SC_HINFO_IS_IPV4) != SCMapEnumNameToValue("windows2k3", sc_hinfo_os_policy_map)); SCHInfoCleanResources(); @@ -1218,114 +1172,26 @@ static int SCHInfoTestValidIPV4Address09(void) { SCHInfoCreateContextBackup(); - int result = 0; - - if (SCHInfoAddHostOSInfo("linux", "192.168.1.0", SC_HINFO_IS_IPV4) == -1) { - goto end; - } - if (SCHInfoAddHostOSInfo("windows", "192.192.1.2", SC_HINFO_IS_IPV4) == -1) { - goto end; - } - if (SCHInfoGetHostOSFlavour("192.168.1.0") != - SCMapEnumNameToValue("linux", sc_hinfo_os_policy_map)) { - goto end; - } - if (SCHInfoAddHostOSInfo("solaris", "192.168.1.0/16", SC_HINFO_IS_IPV4) == -1) { - goto end; - } - if (SCHInfoAddHostOSInfo("macos", "192.168.1.0/20", SC_HINFO_IS_IPV4) == -1) { - goto end; - } - if (SCHInfoGetHostOSFlavour("192.168.1.0") != - SCMapEnumNameToValue("linux", sc_hinfo_os_policy_map)) { - goto end; - } - if (SCHInfoAddHostOSInfo("vista", "192.168.50.128/25", SC_HINFO_IS_IPV4) == -1) { - goto end; - } - if (SCHInfoGetHostOSFlavour("192.168.50.128") != - SCMapEnumNameToValue("vista", sc_hinfo_os_policy_map)) { - goto end; - } - if (SCHInfoAddHostOSInfo("irix", "192.168.50.128", SC_HINFO_IS_IPV4) == -1) { - goto end; - } - if (SCHInfoGetHostOSFlavour("192.168.50.128") != - SCMapEnumNameToValue("irix", sc_hinfo_os_policy_map)) { - goto end; - } - - if (SCHInfoGetHostOSFlavour("192.168.1.100") != - SCMapEnumNameToValue("macos", sc_hinfo_os_policy_map)) { - goto end; - } - - struct sockaddr_in servaddr; - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.168.0.0", &servaddr.sin_addr) <= 0) { - goto end; - } - - SCRadixRemoveKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, sc_hinfo_tree, 16); - - if (SCHInfoGetHostOSFlavour("192.168.1.100") != - SCMapEnumNameToValue("macos", sc_hinfo_os_policy_map)) { - goto end; - } - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.168.0.0", &servaddr.sin_addr) <= 0) { - goto end; - } - SCRadixRemoveKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, sc_hinfo_tree, 20); - - if (SCHInfoGetHostOSFlavour("192.168.1.100") != -1) { - goto end; - } - if (SCHInfoAddHostOSInfo("solaris", "192.168.1.0/16", SC_HINFO_IS_IPV4) == -1) { - goto end; - } - if (SCHInfoAddHostOSInfo("macos", "192.168.1.0/20", SC_HINFO_IS_IPV4) == -1) { - goto end; - } - - /* 192.168.1.100 should match "macos" as its more specific than - * "solaris". */ - if (SCHInfoGetHostOSFlavour("192.168.1.100") != - SCMapEnumNameToValue("macos", sc_hinfo_os_policy_map)) { - goto end; - } - - /* Remove the 192.168.1.0/20 -> macos entry. */ - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.168.0.0", &servaddr.sin_addr) <= 0) { - goto end; - } - SCRadixRemoveKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, sc_hinfo_tree, 20); - - if (SCHInfoGetHostOSFlavour("192.168.1.100") != - SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)) { - goto end; - } - - /* Remove the 192.168.1.0/16 -> solaris entry. */ - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.168.0.0", &servaddr.sin_addr) <= 0) { - goto end; - } - SCRadixRemoveKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, sc_hinfo_tree, 16); - - if (SCHInfoGetHostOSFlavour("192.168.1.100") != -1) { - goto end; - } - - result = 1; + FAIL_IF(SCHInfoAddHostOSInfo("linux", "192.168.1.0", SC_HINFO_IS_IPV4) == -1); + FAIL_IF(SCHInfoAddHostOSInfo("windows", "192.192.1.2", SC_HINFO_IS_IPV4) == -1); + FAIL_IF(SCHInfoGetHostOSFlavour("192.168.1.0") != + SCMapEnumNameToValue("linux", sc_hinfo_os_policy_map)); + FAIL_IF(SCHInfoAddHostOSInfo("solaris", "192.168.1.0/16", SC_HINFO_IS_IPV4) == -1); + FAIL_IF(SCHInfoAddHostOSInfo("macos", "192.168.1.0/20", SC_HINFO_IS_IPV4) == -1); + FAIL_IF(SCHInfoGetHostOSFlavour("192.168.1.0") != + SCMapEnumNameToValue("linux", sc_hinfo_os_policy_map)); + FAIL_IF(SCHInfoAddHostOSInfo("vista", "192.168.50.128/25", SC_HINFO_IS_IPV4) == -1); + FAIL_IF(SCHInfoGetHostOSFlavour("192.168.50.128") != + SCMapEnumNameToValue("vista", sc_hinfo_os_policy_map)); + FAIL_IF(SCHInfoAddHostOSInfo("irix", "192.168.50.128", SC_HINFO_IS_IPV4) == -1); + FAIL_IF(SCHInfoGetHostOSFlavour("192.168.50.128") != + SCMapEnumNameToValue("irix", sc_hinfo_os_policy_map)); + FAIL_IF(SCHInfoGetHostOSFlavour("192.168.1.100") != + SCMapEnumNameToValue("macos", sc_hinfo_os_policy_map)); - end: SCHInfoCleanResources(); SCHInfoRestoreContextBackup(); - - return result; + PASS; } /** diff --git a/src/util-host-os-info.h b/src/util-host-os-info.h index d597ed334556..c9b96b206d3e 100644 --- a/src/util-host-os-info.h +++ b/src/util-host-os-info.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation +/* Copyright (C) 2007-2022 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free @@ -28,7 +28,6 @@ #define SC_HINFO_IS_IPV4 1 int SCHInfoAddHostOSInfo(const char *, const char *, int); -int SCHInfoGetHostOSFlavour(const char *); int SCHInfoGetIPv4HostOSFlavour(uint8_t *); int SCHInfoGetIPv6HostOSFlavour(uint8_t *); void SCHInfoCleanResources(void); From 4b6296c848a59e18e1e4ff543a1c17c68dfc677c Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 29 Oct 2024 15:33:30 +0100 Subject: [PATCH 07/14] detect/iponly: reimplement with radix4 for ipv4 Use a more compact ipv4 specific structure. --- src/detect-engine-iponly.c | 103 ++++++++++++++++--------------------- src/detect.h | 3 +- 2 files changed, 45 insertions(+), 61 deletions(-) diff --git a/src/detect-engine-iponly.c b/src/detect-engine-iponly.c index 8a61b5c2d512..170cdbda1424 100644 --- a/src/detect-engine-iponly.c +++ b/src/detect-engine-iponly.c @@ -901,6 +901,8 @@ int IPOnlySigParseAddress(const DetectEngineCtx *de_ctx, return -1; } +static const SCRadix4Config iponly_radix4_config = { SigNumArrayFree, SigNumArrayPrint }; + /** * \brief Setup the IP Only detection engine context * @@ -909,8 +911,8 @@ int IPOnlySigParseAddress(const DetectEngineCtx *de_ctx, */ void IPOnlyInit(DetectEngineCtx *de_ctx, DetectEngineIPOnlyCtx *io_ctx) { - io_ctx->tree_ipv4src = SCRadixCreateRadixTree(SigNumArrayFree, SigNumArrayPrint); - io_ctx->tree_ipv4dst = SCRadixCreateRadixTree(SigNumArrayFree, SigNumArrayPrint); + io_ctx->tree_ipv4src = SCRadix4TreeInitialize(); + io_ctx->tree_ipv4dst = SCRadix4TreeInitialize(); io_ctx->tree_ipv6src = SCRadixCreateRadixTree(SigNumArrayFree, SigNumArrayPrint); io_ctx->tree_ipv6dst = SCRadixCreateRadixTree(SigNumArrayFree, SigNumArrayPrint); @@ -952,13 +954,8 @@ void IPOnlyDeinit(DetectEngineCtx *de_ctx, DetectEngineIPOnlyCtx *io_ctx) if (io_ctx == NULL) return; - if (io_ctx->tree_ipv4src != NULL) - SCRadixReleaseRadixTree(io_ctx->tree_ipv4src); - io_ctx->tree_ipv4src = NULL; - - if (io_ctx->tree_ipv4dst != NULL) - SCRadixReleaseRadixTree(io_ctx->tree_ipv4dst); - io_ctx->tree_ipv4dst = NULL; + SCRadix4TreeRelease(&io_ctx->tree_ipv4src, &iponly_radix4_config); + SCRadix4TreeRelease(&io_ctx->tree_ipv4dst, &iponly_radix4_config); if (io_ctx->tree_ipv6src != NULL) SCRadixReleaseRadixTree(io_ctx->tree_ipv6src); @@ -1012,16 +1009,16 @@ void IPOnlyMatchPacket(ThreadVars *tv, const DetectEngineCtx *de_ctx, SCEnter(); if (p->src.family == AF_INET) { - (void)SCRadixFindKeyIPV4BestMatch((uint8_t *)&GET_IPV4_SRC_ADDR_U32(p), - io_ctx->tree_ipv4src, &user_data_src); + (void)SCRadix4TreeFindBestMatch( + &io_ctx->tree_ipv4src, (uint8_t *)&GET_IPV4_SRC_ADDR_U32(p), &user_data_src); } else if (p->src.family == AF_INET6) { (void)SCRadixFindKeyIPV6BestMatch((uint8_t *)&GET_IPV6_SRC_ADDR(p), io_ctx->tree_ipv6src, &user_data_src); } if (p->dst.family == AF_INET) { - (void)SCRadixFindKeyIPV4BestMatch((uint8_t *)&GET_IPV4_DST_ADDR_U32(p), - io_ctx->tree_ipv4dst, &user_data_dst); + (void)SCRadix4TreeFindBestMatch( + &io_ctx->tree_ipv4dst, (uint8_t *)&GET_IPV4_DST_ADDR_U32(p), &user_data_dst); } else if (p->dst.family == AF_INET6) { (void)SCRadixFindKeyIPV6BestMatch((uint8_t *)&GET_IPV6_DST_ADDR(p), io_ctx->tree_ipv6dst, &user_data_dst); @@ -1144,6 +1141,7 @@ void IPOnlyPrepare(DetectEngineCtx *de_ctx) IPOnlyCIDRListQSort(&(de_ctx->io_ctx).ip_dst); IPOnlyCIDRItem *src, *dst; + SCRadix4Node *node4 = NULL; SCRadixNode *node = NULL; /* Prepare Src radix trees */ @@ -1160,21 +1158,18 @@ void IPOnlyPrepare(DetectEngineCtx *de_ctx) void *user_data = NULL; if (src->netmask == 32) - (void)SCRadixFindKeyIPV4ExactMatch((uint8_t *)&src->ip[0], - (de_ctx->io_ctx).tree_ipv4src, - &user_data); + (void)SCRadix4TreeFindExactMatch( + &de_ctx->io_ctx.tree_ipv4src, (uint8_t *)&src->ip[0], &user_data); else - (void)SCRadixFindKeyIPV4Netblock((uint8_t *)&src->ip[0], - (de_ctx->io_ctx).tree_ipv4src, - src->netmask, &user_data); + (void)SCRadix4TreeFindNetblock(&de_ctx->io_ctx.tree_ipv4src, (uint8_t *)&src->ip[0], + src->netmask, &user_data); if (user_data == NULL) { SCLogDebug("Exact match not found"); /** Not found, look if there's a subnet of this range with * bigger netmask */ - (void)SCRadixFindKeyIPV4BestMatch((uint8_t *)&src->ip[0], - (de_ctx->io_ctx).tree_ipv4src, - &user_data); + (void)SCRadix4TreeFindBestMatch( + &de_ctx->io_ctx.tree_ipv4src, (uint8_t *)&src->ip[0], &user_data); if (user_data == NULL) { SCLogDebug("best match not found"); @@ -1192,14 +1187,12 @@ void IPOnlyPrepare(DetectEngineCtx *de_ctx) sna->array[src->signum / 8] |= tmp; if (src->netmask == 32) - node = SCRadixAddKeyIPV4((uint8_t *)&src->ip[0], - (de_ctx->io_ctx).tree_ipv4src, sna); + node4 = SCRadix4AddKeyIPV4(&de_ctx->io_ctx.tree_ipv4src, + &iponly_radix4_config, (uint8_t *)&src->ip[0], sna); else - node = SCRadixAddKeyIPV4Netblock((uint8_t *)&src->ip[0], - (de_ctx->io_ctx).tree_ipv4src, - sna, src->netmask); - - if (node == NULL) + node4 = SCRadix4AddKeyIPV4Netblock(&de_ctx->io_ctx.tree_ipv4src, + &iponly_radix4_config, (uint8_t *)&src->ip[0], src->netmask, sna); + if (node4 == NULL) SCLogError("Error inserting in the " "src ipv4 radix tree"); } else { @@ -1220,14 +1213,12 @@ void IPOnlyPrepare(DetectEngineCtx *de_ctx) sna->array[src->signum / 8] |= tmp; if (src->netmask == 32) - node = SCRadixAddKeyIPV4((uint8_t *)&src->ip[0], - (de_ctx->io_ctx).tree_ipv4src, sna); + node4 = SCRadix4AddKeyIPV4(&de_ctx->io_ctx.tree_ipv4src, + &iponly_radix4_config, (uint8_t *)&src->ip[0], sna); else - node = SCRadixAddKeyIPV4Netblock((uint8_t *)&src->ip[0], - (de_ctx->io_ctx).tree_ipv4src, sna, - src->netmask); - - if (node == NULL) { + node4 = SCRadix4AddKeyIPV4Netblock(&de_ctx->io_ctx.tree_ipv4src, + &iponly_radix4_config, (uint8_t *)&src->ip[0], src->netmask, sna); + if (node4 == NULL) { char tmpstr[64]; PrintInet(src->family, &src->ip[0], tmpstr, sizeof(tmpstr)); SCLogError("Error inserting in the" @@ -1353,15 +1344,11 @@ void IPOnlyPrepare(DetectEngineCtx *de_ctx) void *user_data = NULL; if (dst->netmask == 32) - (void) SCRadixFindKeyIPV4ExactMatch((uint8_t *) &dst->ip[0], - (de_ctx->io_ctx).tree_ipv4dst, - &user_data); + (void)SCRadix4TreeFindExactMatch( + &de_ctx->io_ctx.tree_ipv4dst, (uint8_t *)&dst->ip[0], &user_data); else - (void) SCRadixFindKeyIPV4Netblock((uint8_t *) &dst->ip[0], - (de_ctx->io_ctx).tree_ipv4dst, - dst->netmask, - &user_data); - + (void)SCRadix4TreeFindNetblock(&de_ctx->io_ctx.tree_ipv4dst, (uint8_t *)&dst->ip[0], + dst->netmask, &user_data); if (user_data == NULL) { SCLogDebug("Exact match not found"); @@ -1369,9 +1356,8 @@ void IPOnlyPrepare(DetectEngineCtx *de_ctx) * Not found, look if there's a subnet of this range * with bigger netmask */ - (void) SCRadixFindKeyIPV4BestMatch((uint8_t *)&dst->ip[0], - (de_ctx->io_ctx).tree_ipv4dst, - &user_data); + (void)SCRadix4TreeFindBestMatch( + &de_ctx->io_ctx.tree_ipv4dst, (uint8_t *)&dst->ip[0], &user_data); if (user_data == NULL) { SCLogDebug("Best match not found"); @@ -1388,14 +1374,12 @@ void IPOnlyPrepare(DetectEngineCtx *de_ctx) sna->array[dst->signum / 8] |= tmp; if (dst->netmask == 32) - node = SCRadixAddKeyIPV4((uint8_t *)&dst->ip[0], - (de_ctx->io_ctx).tree_ipv4dst, sna); + node4 = SCRadix4AddKeyIPV4(&de_ctx->io_ctx.tree_ipv4dst, + &iponly_radix4_config, (uint8_t *)&dst->ip[0], sna); else - node = SCRadixAddKeyIPV4Netblock((uint8_t *)&dst->ip[0], - (de_ctx->io_ctx).tree_ipv4dst, - sna, dst->netmask); - - if (node == NULL) + node4 = SCRadix4AddKeyIPV4Netblock(&de_ctx->io_ctx.tree_ipv4dst, + &iponly_radix4_config, (uint8_t *)&dst->ip[0], dst->netmask, sna); + if (node4 == NULL) SCLogError("Error inserting in the dst " "ipv4 radix tree"); } else { @@ -1415,14 +1399,13 @@ void IPOnlyPrepare(DetectEngineCtx *de_ctx) sna->array[dst->signum / 8] |= tmp; if (dst->netmask == 32) - node = SCRadixAddKeyIPV4((uint8_t *)&dst->ip[0], - (de_ctx->io_ctx).tree_ipv4dst, sna); + node4 = SCRadix4AddKeyIPV4(&de_ctx->io_ctx.tree_ipv4dst, + &iponly_radix4_config, (uint8_t *)&dst->ip[0], sna); else - node = SCRadixAddKeyIPV4Netblock((uint8_t *)&dst->ip[0], - (de_ctx->io_ctx).tree_ipv4dst, - sna, dst->netmask); + node4 = SCRadix4AddKeyIPV4Netblock(&de_ctx->io_ctx.tree_ipv4dst, + &iponly_radix4_config, (uint8_t *)&dst->ip[0], dst->netmask, sna); - if (node == NULL) + if (node4 == NULL) SCLogError("Error inserting in the dst " "ipv4 radix tree"); } diff --git a/src/detect.h b/src/detect.h index fe755b7f0d14..44a4f18bd0a9 100644 --- a/src/detect.h +++ b/src/detect.h @@ -37,6 +37,7 @@ #include "util-spm.h" #include "util-hash.h" #include "util-hashlist.h" +#include "util-radix4-tree.h" #include "util-radix-tree.h" #include "util-file.h" #include "reputation.h" @@ -766,7 +767,7 @@ typedef struct SCFPSupportSMList_ { /** \brief IP only rules matching ctx. */ typedef struct DetectEngineIPOnlyCtx_ { /* Lookup trees */ - SCRadixTree *tree_ipv4src, *tree_ipv4dst; + SCRadix4Tree tree_ipv4src, tree_ipv4dst; SCRadixTree *tree_ipv6src, *tree_ipv6dst; /* Used to build the radix trees */ From 0ea6fe668e892f574658cdc8d534025e162e1825 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 29 Oct 2024 15:58:37 +0100 Subject: [PATCH 08/14] detect/iponly: reimplement with radix4 for ipv6 Use a more compact ipv6 specific structure. --- src/detect-engine-iponly.c | 104 +++++++++++++++---------------------- src/detect.h | 4 +- 2 files changed, 44 insertions(+), 64 deletions(-) diff --git a/src/detect-engine-iponly.c b/src/detect-engine-iponly.c index 170cdbda1424..6143f83e5725 100644 --- a/src/detect-engine-iponly.c +++ b/src/detect-engine-iponly.c @@ -902,6 +902,7 @@ int IPOnlySigParseAddress(const DetectEngineCtx *de_ctx, } static const SCRadix4Config iponly_radix4_config = { SigNumArrayFree, SigNumArrayPrint }; +static const SCRadix6Config iponly_radix6_config = { SigNumArrayFree, SigNumArrayPrint }; /** * \brief Setup the IP Only detection engine context @@ -913,8 +914,8 @@ void IPOnlyInit(DetectEngineCtx *de_ctx, DetectEngineIPOnlyCtx *io_ctx) { io_ctx->tree_ipv4src = SCRadix4TreeInitialize(); io_ctx->tree_ipv4dst = SCRadix4TreeInitialize(); - io_ctx->tree_ipv6src = SCRadixCreateRadixTree(SigNumArrayFree, SigNumArrayPrint); - io_ctx->tree_ipv6dst = SCRadixCreateRadixTree(SigNumArrayFree, SigNumArrayPrint); + io_ctx->tree_ipv6src = SCRadix6TreeInitialize(); + io_ctx->tree_ipv6dst = SCRadix6TreeInitialize(); io_ctx->sig_mapping = SCCalloc(1, de_ctx->sig_array_len * sizeof(uint32_t)); if (io_ctx->sig_mapping == NULL) { @@ -957,13 +958,8 @@ void IPOnlyDeinit(DetectEngineCtx *de_ctx, DetectEngineIPOnlyCtx *io_ctx) SCRadix4TreeRelease(&io_ctx->tree_ipv4src, &iponly_radix4_config); SCRadix4TreeRelease(&io_ctx->tree_ipv4dst, &iponly_radix4_config); - if (io_ctx->tree_ipv6src != NULL) - SCRadixReleaseRadixTree(io_ctx->tree_ipv6src); - io_ctx->tree_ipv6src = NULL; - - if (io_ctx->tree_ipv6dst != NULL) - SCRadixReleaseRadixTree(io_ctx->tree_ipv6dst); - io_ctx->tree_ipv6dst = NULL; + SCRadix6TreeRelease(&io_ctx->tree_ipv6src, &iponly_radix6_config); + SCRadix6TreeRelease(&io_ctx->tree_ipv6dst, &iponly_radix6_config); if (io_ctx->sig_mapping != NULL) SCFree(io_ctx->sig_mapping); @@ -1012,16 +1008,16 @@ void IPOnlyMatchPacket(ThreadVars *tv, const DetectEngineCtx *de_ctx, (void)SCRadix4TreeFindBestMatch( &io_ctx->tree_ipv4src, (uint8_t *)&GET_IPV4_SRC_ADDR_U32(p), &user_data_src); } else if (p->src.family == AF_INET6) { - (void)SCRadixFindKeyIPV6BestMatch((uint8_t *)&GET_IPV6_SRC_ADDR(p), - io_ctx->tree_ipv6src, &user_data_src); + (void)SCRadix6TreeFindBestMatch( + &io_ctx->tree_ipv6src, (uint8_t *)&GET_IPV6_SRC_ADDR(p), &user_data_src); } if (p->dst.family == AF_INET) { (void)SCRadix4TreeFindBestMatch( &io_ctx->tree_ipv4dst, (uint8_t *)&GET_IPV4_DST_ADDR_U32(p), &user_data_dst); } else if (p->dst.family == AF_INET6) { - (void)SCRadixFindKeyIPV6BestMatch((uint8_t *)&GET_IPV6_DST_ADDR(p), - io_ctx->tree_ipv6dst, &user_data_dst); + (void)SCRadix6TreeFindBestMatch( + &io_ctx->tree_ipv6dst, (uint8_t *)&GET_IPV6_DST_ADDR(p), &user_data_dst); } src = user_data_src; @@ -1142,7 +1138,7 @@ void IPOnlyPrepare(DetectEngineCtx *de_ctx) IPOnlyCIDRItem *src, *dst; SCRadix4Node *node4 = NULL; - SCRadixNode *node = NULL; + SCRadix6Node *node6 = NULL; /* Prepare Src radix trees */ for (src = (de_ctx->io_ctx).ip_src; src != NULL; ) { @@ -1249,20 +1245,15 @@ void IPOnlyPrepare(DetectEngineCtx *de_ctx) void *user_data = NULL; if (src->netmask == 128) - (void)SCRadixFindKeyIPV6ExactMatch((uint8_t *)&src->ip[0], - (de_ctx->io_ctx).tree_ipv6src, - &user_data); + (void)SCRadix6TreeFindExactMatch( + &de_ctx->io_ctx.tree_ipv6src, (uint8_t *)&src->ip[0], &user_data); else - (void)SCRadixFindKeyIPV6Netblock((uint8_t *)&src->ip[0], - (de_ctx->io_ctx).tree_ipv6src, - src->netmask, &user_data); - + (void)SCRadix6TreeFindNetblock(&de_ctx->io_ctx.tree_ipv6src, (uint8_t *)&src->ip[0], + src->netmask, &user_data); if (user_data == NULL) { /* Not found, look if there's a subnet of this range with bigger netmask */ - (void)SCRadixFindKeyIPV6BestMatch((uint8_t *)&src->ip[0], - (de_ctx->io_ctx).tree_ipv6src, - &user_data); - + (void)SCRadix6TreeFindBestMatch( + &de_ctx->io_ctx.tree_ipv6src, (uint8_t *)&src->ip[0], &user_data); if (user_data == NULL) { /* Not found, insert a new one */ SigNumArray *sna = SigNumArrayNew(de_ctx, &de_ctx->io_ctx); @@ -1278,13 +1269,12 @@ void IPOnlyPrepare(DetectEngineCtx *de_ctx) sna->array[src->signum / 8] |= tmp; if (src->netmask == 128) - node = SCRadixAddKeyIPV6((uint8_t *)&src->ip[0], - (de_ctx->io_ctx).tree_ipv6src, sna); + node6 = SCRadix6AddKeyIPV6(&de_ctx->io_ctx.tree_ipv6src, + &iponly_radix6_config, (uint8_t *)&src->ip[0], sna); else - node = SCRadixAddKeyIPV6Netblock((uint8_t *)&src->ip[0], - (de_ctx->io_ctx).tree_ipv6src, - sna, src->netmask); - if (node == NULL) + node6 = SCRadix6AddKeyIPV6Netblock(&de_ctx->io_ctx.tree_ipv6src, + &iponly_radix6_config, (uint8_t *)&src->ip[0], src->netmask, sna); + if (node6 == NULL) SCLogError("Error inserting in the src " "ipv6 radix tree"); } else { @@ -1302,13 +1292,12 @@ void IPOnlyPrepare(DetectEngineCtx *de_ctx) sna->array[src->signum / 8] |= tmp; if (src->netmask == 128) - node = SCRadixAddKeyIPV6((uint8_t *)&src->ip[0], - (de_ctx->io_ctx).tree_ipv6src, sna); + node6 = SCRadix6AddKeyIPV6(&de_ctx->io_ctx.tree_ipv6src, + &iponly_radix6_config, (uint8_t *)&src->ip[0], sna); else - node = SCRadixAddKeyIPV6Netblock((uint8_t *)&src->ip[0], - (de_ctx->io_ctx).tree_ipv6src, - sna, src->netmask); - if (node == NULL) + node6 = SCRadix6AddKeyIPV6Netblock(&de_ctx->io_ctx.tree_ipv6src, + &iponly_radix6_config, (uint8_t *)&src->ip[0], src->netmask, sna); + if (node6 == NULL) SCLogError("Error inserting in the src " "ipv6 radix tree"); } @@ -1429,22 +1418,17 @@ void IPOnlyPrepare(DetectEngineCtx *de_ctx) void *user_data = NULL; if (dst->netmask == 128) - (void) SCRadixFindKeyIPV6ExactMatch((uint8_t *)&dst->ip[0], - (de_ctx->io_ctx).tree_ipv6dst, - &user_data); + (void)SCRadix6TreeFindExactMatch( + &de_ctx->io_ctx.tree_ipv6dst, (uint8_t *)&dst->ip[0], &user_data); else - (void) SCRadixFindKeyIPV6Netblock((uint8_t *)&dst->ip[0], - (de_ctx->io_ctx).tree_ipv6dst, - dst->netmask, &user_data); - + (void)SCRadix6TreeFindNetblock(&de_ctx->io_ctx.tree_ipv6dst, (uint8_t *)&dst->ip[0], + dst->netmask, &user_data); if (user_data == NULL) { /** Not found, look if there's a subnet of this range with * bigger netmask */ - (void) SCRadixFindKeyIPV6BestMatch((uint8_t *)&dst->ip[0], - (de_ctx->io_ctx).tree_ipv6dst, - &user_data); - + (void)SCRadix6TreeFindBestMatch( + &de_ctx->io_ctx.tree_ipv6dst, (uint8_t *)&dst->ip[0], &user_data); if (user_data == NULL) { /* Not found, insert a new one */ SigNumArray *sna = SigNumArrayNew(de_ctx, &de_ctx->io_ctx); @@ -1459,14 +1443,12 @@ void IPOnlyPrepare(DetectEngineCtx *de_ctx) sna->array[dst->signum / 8] |= tmp; if (dst->netmask == 128) - node = SCRadixAddKeyIPV6((uint8_t *)&dst->ip[0], - (de_ctx->io_ctx).tree_ipv6dst, sna); + node6 = SCRadix6AddKeyIPV6(&de_ctx->io_ctx.tree_ipv6dst, + &iponly_radix6_config, (uint8_t *)&dst->ip[0], sna); else - node = SCRadixAddKeyIPV6Netblock((uint8_t *)&dst->ip[0], - (de_ctx->io_ctx).tree_ipv6dst, - sna, dst->netmask); - - if (node == NULL) + node6 = SCRadix6AddKeyIPV6Netblock(&de_ctx->io_ctx.tree_ipv6dst, + &iponly_radix6_config, (uint8_t *)&dst->ip[0], dst->netmask, sna); + if (node6 == NULL) SCLogError("Error inserting in the dst " "ipv6 radix tree"); } else { @@ -1484,14 +1466,12 @@ void IPOnlyPrepare(DetectEngineCtx *de_ctx) sna->array[dst->signum / 8] |= tmp; if (dst->netmask == 128) - node = SCRadixAddKeyIPV6((uint8_t *)&dst->ip[0], - (de_ctx->io_ctx).tree_ipv6dst, sna); + node6 = SCRadix6AddKeyIPV6(&de_ctx->io_ctx.tree_ipv6dst, + &iponly_radix6_config, (uint8_t *)&dst->ip[0], sna); else - node = SCRadixAddKeyIPV6Netblock((uint8_t *)&dst->ip[0], - (de_ctx->io_ctx).tree_ipv6dst, - sna, dst->netmask); - - if (node == NULL) + node6 = SCRadix6AddKeyIPV6Netblock(&de_ctx->io_ctx.tree_ipv6dst, + &iponly_radix6_config, (uint8_t *)&dst->ip[0], dst->netmask, sna); + if (node6 == NULL) SCLogError("Error inserting in the dst " "ipv6 radix tree"); } diff --git a/src/detect.h b/src/detect.h index 44a4f18bd0a9..d71764fa7d08 100644 --- a/src/detect.h +++ b/src/detect.h @@ -38,7 +38,7 @@ #include "util-hash.h" #include "util-hashlist.h" #include "util-radix4-tree.h" -#include "util-radix-tree.h" +#include "util-radix6-tree.h" #include "util-file.h" #include "reputation.h" @@ -768,7 +768,7 @@ typedef struct SCFPSupportSMList_ { typedef struct DetectEngineIPOnlyCtx_ { /* Lookup trees */ SCRadix4Tree tree_ipv4src, tree_ipv4dst; - SCRadixTree *tree_ipv6src, *tree_ipv6dst; + SCRadix6Tree tree_ipv6src, tree_ipv6dst; /* Used to build the radix trees */ IPOnlyCIDRItem *ip_src, *ip_dst; From 3eb2f6a584808d9900903c88e64bb47b48cb604a Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 29 Oct 2024 16:04:44 +0100 Subject: [PATCH 09/14] radix: remove old radix tree implementation No longer used. --- src/Makefile.am | 2 - src/runmode-unittests.c | 2 - src/util-radix-tree.c | 3818 --------------------------------------- src/util-radix-tree.h | 126 -- 4 files changed, 3948 deletions(-) delete mode 100644 src/util-radix-tree.c delete mode 100644 src/util-radix-tree.h diff --git a/src/Makefile.am b/src/Makefile.am index 665da6e0a59e..c2cf2dd93ab5 100755 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -541,7 +541,6 @@ noinst_HEADERS = \ util-profiling.h \ util-profiling-locks.h \ util-proto-name.h \ - util-radix-tree.h \ util-radix-tree-common.h \ util-radix4-tree.h \ util-radix6-tree.h \ @@ -1091,7 +1090,6 @@ libsuricata_c_a_SOURCES = \ util-profiling-rulegroups.c \ util-profiling-rules.c \ util-proto-name.c \ - util-radix-tree.c \ util-radix4-tree.c \ util-radix6-tree.c \ util-random.c \ diff --git a/src/runmode-unittests.c b/src/runmode-unittests.c index 104f7ea78172..6e49c24f8d55 100644 --- a/src/runmode-unittests.c +++ b/src/runmode-unittests.c @@ -64,7 +64,6 @@ #include "app-layer-smtp.h" #include "util-action.h" -#include "util-radix-tree.h" #include "util-radix4-tree.h" #include "util-radix6-tree.h" #include "util-host-os-info.h" @@ -173,7 +172,6 @@ static void RegisterUnittests(void) HostRegisterUnittests(); IPPairRegisterUnittests(); SCSigRegisterSignatureOrderingTests(); - SCRadixRegisterTests(); SCRadix4RegisterTests(); SCRadix6RegisterTests(); DefragRegisterTests(); diff --git a/src/util-radix-tree.c b/src/util-radix-tree.c deleted file mode 100644 index 1b378338f758..000000000000 --- a/src/util-radix-tree.c +++ /dev/null @@ -1,3818 +0,0 @@ -/* Copyright (C) 2007-2022 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Anoop Saldanha - * - * Implementation of radix trees - */ - -#include "suricata-common.h" -#include "util-radix-tree.h" -#include "util-debug.h" -#include "util-error.h" -#include "util-ip.h" -#include "util-unittest.h" -#include "util-memcmp.h" -#include "util-byte.h" -#include "util-cidr.h" -#include "util-print.h" -#include "util-validate.h" - -/** - * \brief Allocates and returns a new instance of SCRadixUserData. - * - * \param netmask The netmask entry (cidr) that has to be made in the new - * SCRadixUserData instance - * \param user The user data that has to be set for the above - * netmask in the newly created SCRadixUserData instance. - * - * \retval user_data Pointer to a new instance of SCRadixUserData. - */ -static SCRadixUserData *SCRadixAllocSCRadixUserData(uint8_t netmask, void *user) -{ - SCRadixUserData *user_data = SCCalloc(1, sizeof(SCRadixUserData)); - if (unlikely(user_data == NULL)) { - SCLogError("Error allocating memory"); - return NULL; - } - - user_data->netmask = netmask; - user_data->user = user; - - return user_data; -} - -/** - * \brief Deallocates an instance of SCRadixUserData. - * - * \param user_data Pointer to the instance of SCRadixUserData that has to be - * freed. - */ -static void SCRadixDeAllocSCRadixUserData(SCRadixUserData *user_data) -{ - SCFree(user_data); -} - -/** - * \brief Appends a user_data instance(SCRadixUserData) to a - * user_data(SCRadixUserData) list. We add the new entry in descending - * order with respect to the netmask contained in the SCRadixUserData. - * - * \param new Pointer to the SCRadixUserData to be added to the list. - * \param list Pointer to the SCRadixUserData list head, to which "new" has to - * be appended. - */ -static void SCRadixAppendToSCRadixUserDataList(SCRadixUserData *new, - SCRadixUserData **list) -{ - SCRadixUserData *temp = NULL; - SCRadixUserData *prev = NULL; - - if (new == NULL || list == NULL) { - FatalError("new or list supplied as NULL"); - } - - /* add to the list in descending order. The reason we do this is for - * optimizing key retrieval for a ip key under a netblock */ - prev = temp = *list; - while (temp != NULL) { - if (new->netmask > temp->netmask) - break; - prev = temp; - temp = temp->next; - } - - if (temp == *list) { - new->next = *list; - *list = new; - } else { - new->next = prev->next; - prev->next = new; - } -} - -/** - * \brief Creates a new Prefix for a key. Used internally by the API. - * - * \param key_stream Data that has to be wrapped in a SCRadixPrefix instance to - * be processed for insertion/lookup/removal of a node by the - * radix tree - * \param key_bitlen The bitlen of the above stream. For example if the - * stream holds the ipv4 address(4 bytes), bitlen would be 32 - * \param user Pointer to the user data that has to be associated with - * this key - * - * \retval prefix The newly created prefix instance on success; NULL on failure - */ -static SCRadixPrefix *SCRadixCreatePrefix(uint8_t *key_stream, - uint16_t key_bitlen, void *user, - uint8_t netmask) -{ - SCRadixPrefix *prefix = NULL; - - if (key_bitlen == 0 || (key_bitlen % 8 != 0)) { - SCLogError("Invalid argument bitlen - %d", key_bitlen); - return NULL; - } - - if (key_stream == NULL) { - SCLogError("Argument \"stream\" NULL"); - return NULL; - } - - if ((prefix = SCCalloc(1, sizeof(SCRadixPrefix))) == NULL) - goto error; - - if ((prefix->stream = SCCalloc(1, key_bitlen / 8)) == NULL) - goto error; - - memcpy(prefix->stream, key_stream, key_bitlen / 8); - prefix->bitlen = key_bitlen; - - prefix->user_data = SCRadixAllocSCRadixUserData(netmask, user); - if (prefix->user_data == NULL) { - goto error; - } - - return prefix; - -error: - if (prefix != NULL) { - if (prefix->stream != NULL) { - SCFree(prefix->stream); - } - SCFree(prefix); - } - - return NULL; -} - -/** - * \brief Adds a netmask and its user_data for a particular prefix stream. - * - * \param prefix The prefix stream to which the netmask and its corresponding - * user data has to be added. - * \param netmask The netmask value (cidr) that has to be added to the prefix. - * \param user The pointer to the user data corresponding to the above - * netmask. - */ -static void SCRadixAddNetmaskUserDataToPrefix(SCRadixPrefix *prefix, - uint8_t netmask, - void *user) -{ - if (prefix == NULL || user == NULL) { - FatalError("prefix or user NULL"); - } - - SCRadixAppendToSCRadixUserDataList( - SCRadixAllocSCRadixUserData(netmask, user), &prefix->user_data); -} - -/** - * \brief Removes a particular user_data corresponding to a particular netmask - * entry, from a prefix. - * - * \param prefix Pointer to the prefix from which the user_data/netmask entry - * has to be removed. - * \param netmask The netmask value (cidr) whose user_data has to be deleted. - */ -static void SCRadixRemoveNetmaskUserDataFromPrefix(SCRadixPrefix *prefix, - uint8_t netmask) -{ - SCRadixUserData *temp = NULL, *prev = NULL; - - if (prefix == NULL) { - FatalError("prefix NULL"); - } - - prev = temp = prefix->user_data; - while (temp != NULL) { - if (temp->netmask == netmask) { - if (temp == prefix->user_data) - prefix->user_data = temp->next; - else - prev->next = temp->next; - - SCRadixDeAllocSCRadixUserData(temp); - break; - } - prev = temp; - temp = temp->next; - } -} - -/** - * \brief Indicates if prefix contains an entry for an ip with a specific netmask. - * - * \param prefix Pointer to the ip prefix that is being checked. - * \param netmask The netmask value (cidr) that has to be checked for - * presence in the prefix. - * - * \retval 1 On match. - * \retval 0 On no match. - */ -static int SCRadixPrefixContainNetmask(SCRadixPrefix *prefix, uint8_t netmask) -{ - SCRadixUserData *user_data = NULL; - - if (prefix == NULL) { - SCLogError("prefix is NULL"); - goto no_match; - } - - user_data = prefix->user_data; - while (user_data != NULL) { - if (user_data->netmask == netmask) - return 1; - user_data = user_data->next; - } - - no_match: - return 0; -} - -/** - * \brief Returns the total netmask count for this prefix. - * - * \param prefix Pointer to the prefix - * - * \retval count The total netmask count for this prefix. - */ -static int SCRadixPrefixNetmaskCount(SCRadixPrefix *prefix) -{ - SCRadixUserData *user_data = NULL; - uint32_t count = 0; - - if (prefix == NULL) { - SCLogError("prefix is NULL"); - return 0; - } - - user_data = prefix->user_data; - while (user_data != NULL) { - count++; - user_data = user_data->next; - } - - return count; -} - -/** - * \brief Indicates if prefix contains an entry for an ip with a specific netmask - * and if it does, it sets the user data field - * SCRadixPrefix->user_data_result to the netmask user_data entry. - * - * \param prefix Pointer to the ip prefix that is being checked. - * \param netmask The netmask value for which we will have to return the user_data - * \param exact_match flag which indicates if we should check if the prefix - * holds proper netblock(< 32 for ipv4 and < 128 for ipv6) or not. - * - * \retval 1 On match. - * \retval 0 On no match. - */ -static int SCRadixPrefixContainNetmaskAndSetUserData( - SCRadixPrefix *prefix, uint16_t netmask, bool exact_match, void **user_data_result) -{ - SCRadixUserData *user_data = NULL; - - if (prefix == NULL) { - SCLogError("prefix is NULL"); - goto no_match; - } - - user_data = prefix->user_data; - /* Check if we have a match for an exact ip. An exact ip as in not a proper - * netblock, i.e. an ip with a netmask of 32(ipv4) or 128(ipv6) */ - if (exact_match) { - if (user_data->netmask == netmask) { - if (user_data_result) - *user_data_result = user_data->user; - return 1; - } else { - goto no_match; - } - } - - /* Check for the user_data entry for this netmask_value */ - while (user_data != NULL) { - if (user_data->netmask == netmask) { - if (user_data_result) - *user_data_result = user_data->user; - return 1; - } - user_data = user_data->next; - } - -no_match: - if (user_data_result != NULL) - *user_data_result = NULL; - return 0; -} - -/** - * \brief Frees a SCRadixPrefix instance - * - * \param prefix Pointer to a prefix instance - * \param tree Pointer to the Radix tree to which this prefix belongs - */ -static void SCRadixReleasePrefix(SCRadixPrefix *prefix, SCRadixTree *tree) -{ - SCRadixUserData *user_data_temp1 = NULL; - SCRadixUserData *user_data_temp2 = NULL; - - if (prefix != NULL) { - if (prefix->stream != NULL) - SCFree(prefix->stream); - - user_data_temp1 = prefix->user_data; - if (tree->Free != NULL) { - while (user_data_temp1 != NULL) { - user_data_temp2 = user_data_temp1; - user_data_temp1 = user_data_temp1->next; - tree->Free(user_data_temp2->user); - SCRadixDeAllocSCRadixUserData(user_data_temp2); - } - } else if (user_data_temp1 != NULL) { - SCFree(user_data_temp1); - } - - SCFree(prefix); - } -} - -/** - * \brief Creates a new node for the Radix tree - * - * \retval node The newly created node for the radix tree - */ -static inline SCRadixNode *SCRadixCreateNode(void) -{ - SCRadixNode *node = NULL; - - if ((node = SCCalloc(1, sizeof(SCRadixNode))) == NULL) { - SCLogError("Fatal error encountered in SCRadixCreateNode. Mem not allocated..."); - return NULL; - } - - return node; -} - -/** - * \brief Frees a Radix tree node - * - * \param node Pointer to a Radix tree node - * \param tree Pointer to the Radix tree to which this node belongs - */ -static void SCRadixReleaseNode(SCRadixNode *node, SCRadixTree *tree) -{ - if (node != NULL) { - SCRadixReleasePrefix(node->prefix, tree); - - if (node->netmasks != NULL) - SCFree(node->netmasks); - - SCFree(node); - } -} - -/** - * \brief Creates a new Radix tree - * - * \param Free Function pointer supplied by the user to be used by the Radix - * cleanup API to free the user supplied data - * - * \retval tree The newly created radix tree on success - * - * \initonly (all radix trees should be created at init) - */ -SCRadixTree *SCRadixCreateRadixTree(void (*Free)(void*), void (*PrintData)(void*)) -{ - SCRadixTree *tree = NULL; - - if ((tree = SCCalloc(1, sizeof(SCRadixTree))) == NULL) { - FatalError("Fatal error encountered in SCRadixCreateRadixTree. Exiting..."); - } - - tree->Free = Free; - tree->PrintData = PrintData; - - return tree; -} - -/** - * \brief Internal helper function used by SCRadixReleaseRadixTree to free a - * subtree - * - * \param node Pointer to the root of the subtree that has to be freed - * \param tree Pointer to the Radix tree to which this subtree belongs - */ -static void SCRadixReleaseRadixSubtree(SCRadixNode *node, SCRadixTree *tree) -{ - if (node != NULL) { - SCRadixReleaseRadixSubtree(node->left, tree); - SCRadixReleaseRadixSubtree(node->right, tree); - SCRadixReleaseNode(node, tree); - } -} - -/** - * \brief Frees a Radix tree and all its nodes - * - * \param tree Pointer to the Radix tree that has to be freed - */ -void SCRadixReleaseRadixTree(SCRadixTree *tree) -{ - if (tree == NULL) - return; - - SCRadixReleaseRadixSubtree(tree->head, tree); - tree->head = NULL; - SCFree(tree); -} - -/** - * \brief Adds a key to the Radix tree. Used internally by the API. - * - * \param key_stream Data that has to added to the Radix tree - * \param key_bitlen The bitlen of the above stream. For example if the - * stream is the string "abcd", the bitlen would be 32. If - * the stream is an IPV6 address bitlen would be 128 - * \param tree Pointer to the Radix tree - * \param user Pointer to the user data that has to be associated with - * this key - * \param netmask The netmask (cidr) if we are adding an IP netblock; 255 - * if we are not adding an IP netblock - * \param exclusive True if the node should be added iff it doesn't exist. - * - * \retval node Pointer to the newly created node - */ -static SCRadixNode *SCRadixAddKeyInternal(uint8_t *key_stream, uint8_t key_bitlen, - SCRadixTree *tree, void *user, uint8_t netmask, bool exclusive) -{ - SCRadixNode *node = NULL; - SCRadixNode *new_node = NULL; - SCRadixNode *parent = NULL; - SCRadixNode *inter_node = NULL; - SCRadixNode *bottom_node = NULL; - void *ptmp; - - uint8_t *stream = NULL; - uint8_t bitlen = 0; - - uint16_t check_bit = 0; - uint16_t differ_bit = 0; - - uint16_t i = 0; - uint16_t j = 0; - - if (tree == NULL) { - SCLogError("Argument \"tree\" NULL"); - sc_errno = SC_EINVAL; - return NULL; - } - - /* chop the ip address against a netmask */ - MaskIPNetblock(key_stream, netmask, key_bitlen); - - /* the very first element in the radix tree */ - if (tree->head == NULL) { - SCRadixPrefix *prefix = NULL; - if ( (prefix = SCRadixCreatePrefix(key_stream, key_bitlen, user, - netmask)) == NULL) { - SCLogError("Error creating prefix"); - sc_errno = SC_EINVAL; - return NULL; - } - node = SCRadixCreateNode(); - if (node == NULL) { - SCRadixReleasePrefix(prefix, tree); - sc_errno = SC_ENOMEM; - return NULL; - } - node->prefix = prefix; - node->bit = prefix->bitlen; - tree->head = node; - if (netmask == 255 || (netmask == 32 && key_bitlen == 32) || - (netmask == 128 && key_bitlen == 128)) { - sc_errno = SC_EINVAL; - return node; - } - - /* if we have reached here, we are actually having a proper netblock in - * our hand(i.e. < 32 for ipv4 and < 128 for ipv6). Add the netmask for - * this node. The reason we add netmasks other than 32 and 128, is - * because we need those netmasks in case of searches for ips contained - * in netblocks. If the netmask is 32 or 128, either ways we will be - * having an exact match for that ip value. If it is not, we start - * chopping the incoming search ip key using the netmask values added - * into the tree and then verify for a match */ - node->netmask_cnt++; - if ( (ptmp = SCRealloc(node->netmasks, (node->netmask_cnt * - sizeof(uint8_t)))) == NULL) { - SCFree(node->netmasks); - node->netmasks = NULL; - SCLogError("Fatal error encountered in SCRadixAddKey. Mem not allocated"); - sc_errno = SC_ENOMEM; - return NULL; - } - node->netmasks = ptmp; - node->netmasks[0] = netmask; - return node; - } - - node = tree->head; - stream = key_stream; - bitlen = key_bitlen; - - /* we walk down the tree only when we satisfy 2 conditions. The first one - * being the incoming prefix is shorter than the differ bit of the current - * node. In case we fail in this aspect, we walk down to the tree, till we - * arrive at a node that ends in a prefix */ - while (node->bit < bitlen || node->prefix == NULL) { - /* if the bitlen isn't long enough to handle the bit test, we just walk - * down along one of the paths, since either paths should end up with a - * node that has a common prefix whose differ bit is greater than the - * bitlen of the incoming prefix */ - if (bitlen <= node->bit) { - if (node->right == NULL) - break; - node = node->right; - } else { - if (SC_RADIX_BITTEST(stream[node->bit >> 3], - (0x80 >> (node->bit % 8))) ) { - if (node->right == NULL) - break; - node = node->right; - } else { - if (node->left == NULL) - break; - node = node->left; - } - } - } - - /* we need to keep a reference to the bottom-most node, that actually holds - * the prefix */ - bottom_node = node; - - DEBUG_VALIDATE_BUG_ON(bottom_node == NULL); - DEBUG_VALIDATE_BUG_ON(bottom_node->prefix == NULL); - - /* get the first bit position where the ips differ */ - check_bit = (node->bit < bitlen)? node->bit: bitlen; - for (i = 0; (i * 8) < check_bit; i++) { - int temp; - if ((temp = (stream[i] ^ bottom_node->prefix->stream[i])) == 0) { - differ_bit = (i + 1) * 8; - continue; - } - - /* find out the position where the first bit differs. This method is - * faster, but at the cost of being larger. But with larger caches - * these days we don't have to worry about cache misses */ - temp = temp * 2; - if (temp >= 256) - j = 0; - else if (temp >= 128) - j = 1; - else if (temp >= 64) - j = 2; - else if (temp >= 32) - j = 3; - else if (temp >= 16) - j = 4; - else if (temp >= 8) - j = 5; - else if (temp >= 4) - j = 6; - else if (temp >= 2) - j = 7; - - differ_bit = i * 8 + j; - break; - } - if (check_bit < differ_bit) - differ_bit = check_bit; - - /* walk up the tree till we find the position, to fit our new node in */ - parent = node->parent; - while (parent && differ_bit <= parent->bit) { - node = parent; - parent = node->parent; - } - - /* We already have the node in the tree with the same differing bit pstn */ - if (differ_bit == bitlen && node->bit == bitlen) { - if (node->prefix != NULL) { - /* Check if we already have this netmask entry covered by this prefix */ - if (SCRadixPrefixContainNetmask(node->prefix, netmask)) { - /* Basically we already have this stream prefix, as well as the - * netblock entry for this. A perfect duplicate. */ - if (exclusive) { - SCLogDebug("not inserting since it already exists"); - sc_errno = SC_EEXIST; - return NULL; - } - SCLogDebug("Duplicate entry for this ip address/netblock"); - } else { - /* Basically we already have this stream prefix, but we don't - * have an entry for this particular netmask value for this - * prefix. For example, we have an entry for 192.168.0.0 and - * 192.168.0.0/16 and now we are trying to enter 192.168.0.0/20 */ - SCRadixAddNetmaskUserDataToPrefix(node->prefix, netmask, user); - - /* if we are adding a netmask of 32(for ipv4) or 128(for ipv6) - * it indicates we are adding an exact host ip into the radix - * tree, in which case we don't need to add the netmask value - * into the tree */ - if (netmask == 255 || (netmask == 32 && bitlen == 32) || (netmask == 128 && bitlen == 128)) - return node; - - /* looks like we have a netmask which is != 32 or 128, in which - * case we walk up the tree to insert this netmask value in the - * correct node */ - parent = node->parent; - while (parent != NULL && netmask < (parent->bit + 1)) { - node = parent; - parent = parent->parent; - } - - node->netmask_cnt++; - new_node = node; - - if ( (ptmp = SCRealloc(node->netmasks, (node->netmask_cnt * - sizeof(uint8_t)))) == NULL) { - SCFree(node->netmasks); - node->netmasks = NULL; - SCLogError("Fatal error encountered in SCRadixAddKey. Mem not allocated..."); - sc_errno = SC_ENOMEM; - return NULL; - } - node->netmasks = ptmp; - - if (node->netmask_cnt == 1) { - node->netmasks[0] = netmask; - return new_node; - } - - node->netmasks[node->netmask_cnt - 1] = netmask; - - for (i = node->netmask_cnt - 1; i > 0; i--) { - if (netmask < node->netmasks[i - 1]) { - node->netmasks[i] = netmask; - break; - } - - node->netmasks[i] = node->netmasks[i - 1]; - node->netmasks[i - 1] = netmask; - } - } - } else { - node->prefix = SCRadixCreatePrefix(key_stream, key_bitlen, - user, 255); - } - return node; - } - - /* create the leaf node for the new key */ - SCRadixPrefix *prefix = NULL; - if ( (prefix = SCRadixCreatePrefix(key_stream, key_bitlen, user, - netmask)) == NULL) { - SCLogError("Error creating prefix"); - sc_errno = SC_EINVAL; - return NULL; - } - new_node = SCRadixCreateNode(); - - if (new_node == NULL) { - SCRadixReleasePrefix(prefix, tree); - sc_errno = SC_ENOMEM; - return NULL; - } - - new_node->prefix = prefix; - new_node->bit = prefix->bitlen; - - /* indicates that we have got a key that has length that is already covered - * by a prefix of some other key in the tree. We create a new intermediate - * node with a single child and stick it in. We need the if only in the - * case of variable length keys */ - if (differ_bit == bitlen) { - if (SC_RADIX_BITTEST(bottom_node->prefix->stream[differ_bit >> 3], - (0x80 >> (differ_bit % 8))) ) { - new_node->right = node; - } else { - new_node->left = node; - } - new_node->parent = node->parent; - - if (node->parent == NULL) - tree->head = new_node; - else if (node->parent->right == node) - node->parent->right = new_node; - else - node->parent->left = new_node; - - node->parent = new_node; - /* stick our new_node into the tree. Create a node that holds the - * differing bit position and break the branch. Also handle the - * transfer of netmasks between node and inter_node(explained in more - * detail below) */ - } else { - inter_node = SCRadixCreateNode(); - - if (inter_node == NULL) { - SCRadixReleaseNode(new_node, tree); - sc_errno = SC_ENOMEM; - return NULL; - } - - inter_node->prefix = NULL; - inter_node->bit = differ_bit; - inter_node->parent = node->parent; - - if (node->netmasks != NULL) { - for (i = 0; i < node->netmask_cnt; i++) { - if (node->netmasks[i] < differ_bit + 1) - break; - } - - if (i < node->netmask_cnt) { - if ( (inter_node->netmasks = SCMalloc((node->netmask_cnt - i) * - sizeof(uint8_t))) == NULL) { - SCLogError("Fatal error encountered in SCRadixAddKey. Mem not allocated..."); - SCRadixReleaseNode(inter_node, tree); - SCRadixReleaseNode(new_node, tree); - sc_errno = SC_ENOMEM; - return NULL; - } - - for (j = 0; j < (node->netmask_cnt - i); j++) - inter_node->netmasks[j] = node->netmasks[i + j]; - - inter_node->netmask_cnt = (node->netmask_cnt - i); - node->netmask_cnt = i; - } - } - - if (SC_RADIX_BITTEST(stream[differ_bit >> 3], - (0x80 >> (differ_bit % 8))) ) { - inter_node->left = node; - inter_node->right = new_node; - } else { - inter_node->left = new_node; - inter_node->right = node; - } - new_node->parent = inter_node; - - if (node->parent == NULL) - tree->head = inter_node; - else if (node->parent->right == node) - node->parent->right = inter_node; - else - node->parent->left = inter_node; - - node->parent = inter_node; - } - - /* insert the netmask into the tree */ - if (netmask != 255 && (netmask != 32 || (netmask == 32 && bitlen != 32)) && netmask != 128) { - node = new_node; - parent = new_node->parent; - while (parent != NULL && netmask < (parent->bit + 1)) { - node = parent; - parent = parent->parent; - } - - node->netmask_cnt++; - if ( (ptmp = SCRealloc(node->netmasks, (node->netmask_cnt * - sizeof(uint8_t)))) == NULL) { - SCFree(node->netmasks); - node->netmasks = NULL; - FatalError("Fatal error encountered in SCRadixAddKey. Exiting..."); - } - node->netmasks = ptmp; - - if (node->netmask_cnt == 1) { - node->netmasks[0] = netmask; - return new_node; - } - - node->netmasks[node->netmask_cnt - 1] = netmask; - - for (i = node->netmask_cnt - 1; i > 0; i--) { - if (netmask < node->netmasks[i - 1]) { - node->netmasks[i] = netmask; - break; - } - - node->netmasks[i] = node->netmasks[i - 1]; - node->netmasks[i - 1] = netmask; - } - } - - return new_node; -} - -static SCRadixNode *SCRadixAddKeyExclusive( - uint8_t *key_stream, uint8_t key_bitlen, SCRadixTree *tree, void *user, uint8_t netmask) -{ - return SCRadixAddKeyInternal(key_stream, key_bitlen, tree, user, netmask, true); -} - -static SCRadixNode *SCRadixAddKey( - uint8_t *key_stream, uint8_t key_bitlen, SCRadixTree *tree, void *user, uint8_t netmask) -{ - return SCRadixAddKeyInternal(key_stream, key_bitlen, tree, user, netmask, false); -} - -/** - * \brief Adds a new IPV4 address to the Radix tree - * - * \param key_stream Data that has to be added to the Radix tree. In this case - * a pointer to an IPV4 address - * \param tree Pointer to the Radix tree - * \param user Pointer to the user data that has to be associated with the - * key - * - * \retval node Pointer to the newly created node - */ -SCRadixNode *SCRadixAddKeyIPV4(uint8_t *key_stream, SCRadixTree *tree, - void *user) -{ - SCRadixNode *node = SCRadixAddKey(key_stream, 32, tree, user, 32); - - return node; -} - -/** - * \brief Adds a new IPV6 address to the Radix tree - * - * \param key_stream Data that has to be added to the Radix tree. In this case - * the pointer to an IPV6 address - * \param tree Pointer to the Radix tree - * \param user Pointer to the user data that has to be associated with the - * key - * - * \retval node Pointer to the newly created node - */ -SCRadixNode *SCRadixAddKeyIPV6(uint8_t *key_stream, SCRadixTree *tree, - void *user) -{ - SCRadixNode *node = SCRadixAddKey(key_stream, 128, tree, user, 128); - - return node; -} - -#if defined(DEBUG_VALIDATION) || defined(UNITTESTS) -static void SCRadixValidateIPv4Key(uint8_t *key, const uint8_t netmask) -{ - uint32_t address; - memcpy(&address, key, sizeof(address)); - uint32_t mask = CIDRGet(netmask); - if (address != (address & mask)) { - uint32_t masked = address & mask; - char ostr[16], nstr[16]; - PrintInet(AF_INET, (void *)&address, ostr, sizeof(ostr)); - PrintInet(AF_INET, (void *)&masked, nstr, sizeof(nstr)); - SCLogNotice("input %s/%u != expected %s/%u", ostr, netmask, nstr, netmask); - abort(); - } -} - -static void SCRadixValidateIPv6Key(uint8_t *key, const uint8_t netmask) -{ - uint32_t address[4]; - memcpy(&address, key, sizeof(address)); - - uint32_t mask[4]; - memset(&mask, 0, sizeof(mask)); - struct in6_addr mask6; - CIDRGetIPv6(netmask, &mask6); - memcpy(&mask, &mask6.s6_addr, sizeof(mask)); - - uint32_t masked[4]; - masked[0] = address[0] & mask[0]; - masked[1] = address[1] & mask[1]; - masked[2] = address[2] & mask[2]; - masked[3] = address[3] & mask[3]; - - if (memcmp(masked, address, sizeof(masked)) != 0) { - char ostr[64], nstr[64]; - PrintInet(AF_INET6, (void *)&address, ostr, sizeof(ostr)); - PrintInet(AF_INET6, (void *)&masked, nstr, sizeof(nstr)); - SCLogNotice("input %s/%u != expected %s/%u", ostr, netmask, nstr, netmask); - abort(); - } -} -#endif - -/** - * \brief Adds a new IPV4 netblock to the Radix tree - * - * \param key_stream Data that has to be added to the Radix tree. In this case - * a pointer to an IPV4 netblock - * \param tree Pointer to the Radix tree - * \param user Pointer to the user data that has to be associated with the - * key - * \param netmask The netmask (cidr) if we are adding a netblock - * - * \retval node Pointer to the newly created node - */ -SCRadixNode *SCRadixAddKeyIPV4Netblock(uint8_t *key_stream, SCRadixTree *tree, - void *user, uint8_t netmask) -{ -#if defined(DEBUG_VALIDATION) || defined(UNITTESTS) - SCRadixValidateIPv4Key(key_stream, netmask); -#endif - SCRadixNode *node = SCRadixAddKey(key_stream, 32, tree, user, netmask); - - return node; -} - -/** - * \brief Adds a new IPV6 netblock to the Radix tree - * - * \param key_stream Data that has to be added to the Radix tree. In this case - * a pointer to an IPV6 netblock - * \param tree Pointer to the Radix tree - * \param user Pointer to the user data that has to be associated with the - * key - * \param netmask The netmask (cidr) if we are adding a netblock - * - * \retval node Pointer to the newly created node - */ -SCRadixNode *SCRadixAddKeyIPV6Netblock(uint8_t *key_stream, SCRadixTree *tree, - void *user, uint8_t netmask) -{ -#if defined(DEBUG_VALIDATION) || defined(UNITTESTS) - SCRadixValidateIPv6Key(key_stream, netmask); -#endif - SCRadixNode *node = SCRadixAddKey(key_stream, 128, tree, user, netmask); - - return node; -} - -/** - * \brief Adds a new IPV4/netblock to the Radix tree from a string - * - * \param str IPV4 string with optional /cidr netmask - * \param tree Pointer to the Radix tree - * \param user Pointer to the user data that has to be associated with - * the key - * - * \retval bool true (false) if the node was (wasn't) added. - * - * sc_errno is set: - * - SC_OK: Node added - * - SC_EEXIST: Node already exists - * - SC_EINVAL: Parameter value error - */ -bool SCRadixAddKeyIPV4String(const char *str, SCRadixTree *tree, void *user) -{ - uint32_t ip; - uint8_t netmask = 32; - char ip_str[32]; /* Max length for full ipv4/mask string with NUL */ - char *mask_str = NULL; - struct in_addr addr; - - /* Make a copy of the string so it can be modified */ - strlcpy(ip_str, str, sizeof(ip_str) - 2); - *(ip_str + (sizeof(ip_str) - 1)) = '\0'; - - /* Does it have a mask? */ - if (NULL != (mask_str = strchr(ip_str, '/'))) { - uint8_t cidr; - *(mask_str++) = '\0'; - - /* Dotted type netmask not supported (yet) */ - if (strchr(mask_str, '.') != NULL) { - sc_errno = SC_EINVAL; - return false; - } - - /* Get binary values for cidr mask */ - if (StringParseU8RangeCheck(&cidr, 10, 0, (const char *)mask_str, 0, 32) < 0) { - sc_errno = SC_EINVAL; - return false; - } - - netmask = (uint8_t)cidr; - } - - /* Validate the IP */ - if (inet_pton(AF_INET, ip_str, &addr) <= 0) { - sc_errno = SC_EINVAL; - return false; - } - ip = addr.s_addr; - if (netmask != 32) { - uint32_t mask = CIDRGet(netmask); - uint32_t masked = ip & mask; - if (masked != ip) { - char nstr[16]; - PrintInet(AF_INET, (void *)&masked, nstr, sizeof(nstr)); - SCLogWarning("adding '%s' as '%s/%u'", str, nstr, netmask); - ip = masked; - } -#if defined(DEBUG_VALIDATION) || defined(UNITTESTS) - SCRadixValidateIPv4Key((uint8_t *)&ip, netmask); -#endif - } - - SCLogDebug("trying to add %s, but only if it doesn't exist", ip_str); - /* Add, but only if not there */ - if (SCRadixAddKeyExclusive((uint8_t *)&ip, 32, tree, user, netmask) == NULL) { - return false; - } - - return true; -} - -/** - * \brief Adds a new IPV6/netblock to the Radix tree from a string - * - * \param str IPV6 string with optional /cidr netmask - * \param tree Pointer to the Radix tree - * \param user Pointer to the user data that has to be associated with - * the key - * - * \retval bool true (false) if the node was (wasn't) added. - * sc_errno is set: - * - SC_OK: Node added - * - SC_EEXIST: Node already exists - * - SC_EINVAL: Parameter value error - */ -bool SCRadixAddKeyIPV6String(const char *str, SCRadixTree *tree, void *user) -{ - uint8_t netmask = 128; - char ip_str[80]; /* Max length for full ipv6/mask string with NUL */ - char *mask_str = NULL; - struct in6_addr addr; - - /* Make a copy of the string so it can be modified */ - strlcpy(ip_str, str, sizeof(ip_str) - 2); - *(ip_str + sizeof(ip_str) - 1) = '\0'; - - /* Does it have a mask? */ - if (NULL != (mask_str = strchr(ip_str, '/'))) { - uint8_t cidr; - *(mask_str++) = '\0'; - - /* Dotted type netmask not supported (yet) */ - if (strchr(mask_str, '.') != NULL) { - sc_errno = SC_EINVAL; - return false; - } - - /* Get binary values for cidr mask */ - if (StringParseU8RangeCheck(&cidr, 10, 0, (const char *)mask_str, 0, 128) < 0) { - sc_errno = SC_EINVAL; - return false; - } - - netmask = (uint8_t)cidr; - } - - /* Validate the IP */ - if (inet_pton(AF_INET6, ip_str, &addr) <= 0) { - sc_errno = SC_EINVAL; - return false; - } - - if (netmask != 128) { - struct in6_addr mask6, check; - CIDRGetIPv6(netmask, &mask6); - memcpy(&check, &addr, sizeof(check)); - bool diff = false; - for (int i = 0; i < 16; i++) { - addr.s6_addr[i] &= mask6.s6_addr[i]; - diff |= (addr.s6_addr[i] != check.s6_addr[i]); - } - if (diff) { - char nstr[64]; - PrintInet(AF_INET6, (void *)&addr.s6_addr, nstr, sizeof(nstr)); - SCLogWarning("adding '%s' as '%s/%u'", str, nstr, netmask); - } -#if defined(DEBUG_VALIDATION) || defined(UNITTESTS) - SCRadixValidateIPv6Key((uint8_t *)&addr.s6_addr, netmask); -#endif - } - - SCLogDebug("trying to add %s, but only if it doesn't exist", str); - /* Add, but only if not there */ - if (SCRadixAddKeyExclusive(addr.s6_addr, 128, tree, user, netmask) == NULL) { - return false; - } - - sc_errno = SC_OK; - return true; -} - -static void SCRadixTransferNetmasksBWNodes(SCRadixNode *dest, SCRadixNode *src) -{ - int i = 0, j = 0; - void *ptmp = NULL; - - if (src == NULL || dest == NULL) { - SCLogError("src or dest NULL"); - return; - } - - /* no netmasks in the source node, to transfer to the destination node */ - if (src->netmasks == NULL) - return; - - if ( (ptmp = SCRealloc(dest->netmasks, - (src->netmask_cnt + dest->netmask_cnt) * - sizeof(uint8_t))) == NULL) { - SCFree(dest->netmasks); - dest->netmasks = NULL; - return; - } - dest->netmasks = ptmp; - - for (i = dest->netmask_cnt, j = 0; j < src->netmask_cnt; i++, j++) - dest->netmasks[i] = src->netmasks[j]; -} - -/** - * \brief Removes a netblock entry from an ip node. The function first - * deletes the netblock/user_data entry for the prefix and then - * removes the netmask entry that has been made in the tree, by - * walking up the tree and deleting the entry from the specific node. - * - * \param node The node from which the netblock entry has to be removed. - * \param netmask The netmask entry (cidr) that has to be removed. - */ -static void SCRadixRemoveNetblockEntry(SCRadixNode *node, uint8_t netmask) -{ - void *ptmp; - SCRadixNode *parent = NULL; - int i = 0; - - if (node == NULL) { - SCLogError("Invalid argument. Node is NULL"); - return; - } - - SCRadixRemoveNetmaskUserDataFromPrefix(node->prefix, netmask); - - if (netmask == 32 || netmask == 128) - return; - - parent = node->parent; - while (parent != NULL && netmask < (parent->bit + 1)) { - parent = parent->parent; - } - - for (i = 0; i < node->netmask_cnt; i++) { - if (node->netmasks[i] == netmask) - break; - } - - if (i == node->netmask_cnt) { - SCLogDebug("Something's wrong with the tree. We are unable to find the " - "netmask entry"); - return; - } - - for ( ; i < node->netmask_cnt - 1; i++) - node->netmasks[i] = node->netmasks[i + 1]; - - node->netmask_cnt--; - if (node->netmask_cnt == 0) { - SCFree(node->netmasks); - node->netmasks = NULL; - return; - } - - ptmp = SCRealloc(node->netmasks, node->netmask_cnt * sizeof(uint8_t)); - if (ptmp == NULL) { - SCFree(node->netmasks); - node->netmasks = NULL; - return; - } - node->netmasks = ptmp; -} - -/** - * \brief Removes a key from the Radix tree - * - * \param key_stream Data that has to be removed from the Radix tree - * \param key_bitlen The bitlen of the above stream. For example if the - * stream holds an IPV4 address(4 bytes), bitlen would be 32 - * \param tree Pointer to the Radix tree from which the key has to be - * removed - */ -static void SCRadixRemoveKey(uint8_t *key_stream, uint16_t key_bitlen, - SCRadixTree *tree, uint8_t netmask) -{ - SCRadixNode *node = tree->head; - SCRadixNode *parent = NULL; - SCRadixNode *temp_dest = NULL; - - SCRadixPrefix *prefix = NULL; - - uint32_t mask = 0; - int i = 0; - - if (node == NULL) - return; - - if ( (prefix = SCRadixCreatePrefix(key_stream, key_bitlen, NULL, 255)) == NULL) - return; - - while (node->bit < prefix->bitlen) { - if (SC_RADIX_BITTEST(prefix->stream[node->bit >> 3], - (0x80 >> (node->bit % 8))) ) { - node = node->right; - } else { - node = node->left; - } - - if (node == NULL) { - SCRadixReleasePrefix(prefix, tree); - return; - } - } - - if (node->bit != prefix->bitlen || node->prefix == NULL) { - SCRadixReleasePrefix(prefix, tree); - return; - } - - i = prefix->bitlen / 8; - if (SCMemcmp(node->prefix->stream, prefix->stream, i) == 0) { - mask = UINT_MAX << (8 - prefix->bitlen % 8); - - if (prefix->bitlen % 8 == 0 || - (node->prefix->stream[i] & mask) == (prefix->stream[i] & mask)) { - if (!SCRadixPrefixContainNetmask(node->prefix, netmask)) { - SCLogDebug("The ip key exists in the Radix Tree, but this(%d) " - "netblock entry doesn't exist", netmask); - SCRadixReleasePrefix(prefix, tree); - return; - } - } else { - SCLogDebug("You are trying to remove a key that doesn't exist in " - "the Radix Tree"); - SCRadixReleasePrefix(prefix, tree); - return; - } - } else { - SCLogDebug("You are trying to remove a key that doesn't exist in the " - "Radix Tree"); - SCRadixReleasePrefix(prefix, tree); - return; - } - - /* The ip node does exist, and the netblock entry does exist in this node, if - * we have reached this point. If we have more than one netblock entry, it - * indicates we have multiple entries for this key. So we delete that - * particular netblock entry, and make our way out of this function */ - if (SCRadixPrefixNetmaskCount(node->prefix) > 1) { - SCRadixRemoveNetblockEntry(node, netmask); - SCRadixReleasePrefix(prefix, tree); - return; - } - - /* we are deleting the root of the tree. This would be the only node left - * in the tree */ - if (tree->head == node) { - SCRadixReleaseNode(node, tree); - tree->head = NULL; - SCRadixReleasePrefix(prefix, tree); - return; - } - - parent = node->parent; - /* parent->parent is not the root of the tree */ - if (parent->parent != NULL) { - if (parent->parent->left == parent) { - if (node->parent->left == node) { - temp_dest = parent->right; - parent->parent->left = parent->right; - parent->right->parent = parent->parent; - } else { - temp_dest = parent->left; - parent->parent->left = parent->left; - parent->left->parent = parent->parent; - } - } else { - if (node->parent->left == node) { - temp_dest = parent->right; - parent->parent->right = parent->right; - parent->right->parent = parent->parent; - } else { - temp_dest = parent->left; - parent->parent->right = parent->left; - parent->left->parent = parent->parent; - } - } - /* parent is the root of the tree */ - } else { - if (parent->left == node) { - temp_dest = tree->head->right; - tree->head->right->parent = NULL; - tree->head = tree->head->right; - } else { - temp_dest = tree->head->left; - tree->head->left->parent = NULL; - tree->head = tree->head->left; - } - } - /* We need to shift the netmask entries from the node that would be - * deleted to its immediate descendant */ - SCRadixTransferNetmasksBWNodes(temp_dest, parent); - /* release the nodes */ - SCRadixReleaseNode(parent, tree); - SCRadixReleaseNode(node, tree); - SCRadixReleasePrefix(prefix, tree); -} - -/** - * \brief Removes an IPV4 address netblock key from the Radix tree. - * - * \param key_stream Data that has to be removed from the Radix tree. In this - * case an IPV4 address - * \param tree Pointer to the Radix tree from which the key has to be - * removed - */ -void SCRadixRemoveKeyIPV4Netblock(uint8_t *key_stream, SCRadixTree *tree, - uint8_t netmask) -{ -#if defined(DEBUG_VALIDATION) || defined(UNITTESTS) - SCRadixValidateIPv4Key(key_stream, netmask); -#endif - SCRadixRemoveKey(key_stream, 32, tree, netmask); -} - -/** - * \brief Removes an IPV4 address key(not a netblock) from the Radix tree. - * Instead of using this function, we can also used - * SCRadixRemoveKeyIPV4Netblock(), by supplying a netmask value of 32. - * - * \param key_stream Data that has to be removed from the Radix tree. In this - * case an IPV4 address - * \param tree Pointer to the Radix tree from which the key has to be - * removed - */ -void SCRadixRemoveKeyIPV4(uint8_t *key_stream, SCRadixTree *tree) -{ - SCRadixRemoveKey(key_stream, 32, tree, 32); -} - -/** - * \brief Removes an IPV6 netblock address key from the Radix tree. - * - * \param key_stream Data that has to be removed from the Radix tree. In this - * case an IPV6 address - * \param tree Pointer to the Radix tree from which the key has to be - * removed - */ -void SCRadixRemoveKeyIPV6Netblock(uint8_t *key_stream, SCRadixTree *tree, - uint8_t netmask) -{ -#if defined(DEBUG_VALIDATION) || defined(UNITTESTS) - SCRadixValidateIPv6Key(key_stream, netmask); -#endif - SCRadixRemoveKey(key_stream, 128, tree, netmask); -} - -/** - * \brief Removes an IPV6 address key(not a netblock) from the Radix tree. - * Instead of using this function, we can also used - * SCRadixRemoveKeyIPV6Netblock(), by supplying a netmask value of 128. - * - * \param key_stream Data that has to be removed from the Radix tree. In this - * case an IPV6 address - * \param tree Pointer to the Radix tree from which the key has to be - * removed - */ -void SCRadixRemoveKeyIPV6(uint8_t *key_stream, SCRadixTree *tree) -{ - SCRadixRemoveKey(key_stream, 128, tree, 128); -} - -/** - * \brief Checks if an IP prefix falls under a netblock, in the path to the root - * of the tree, from the node. Used internally by SCRadixFindKey() - * - * \param prefix Pointer to the prefix that contains the ip address - * \param node Pointer to the node from where we have to climb the tree - */ -static inline SCRadixNode *SCRadixFindKeyIPNetblock( - uint8_t *key_stream, uint8_t key_bitlen, SCRadixNode *node, void **user_data_result) -{ - SCRadixNode *netmask_node = NULL; - uint32_t mask = 0; - int bytes = 0; - int i = 0; - int j = 0; - - while (node != NULL && node->netmasks == NULL) - node = node->parent; - - if (node == NULL) - return NULL; - /* hold the node found containing a netmask. We will need it when we call - * this function recursively */ - netmask_node = node; - - for (j = 0; j < netmask_node->netmask_cnt; j++) { - bytes = key_bitlen / 8; - for (i = 0; i < bytes; i++) { - mask = UINT_MAX; - if ( ((i + 1) * 8) > netmask_node->netmasks[j]) { - if ( ((i + 1) * 8 - netmask_node->netmasks[j]) < 8) - mask = UINT_MAX << ((i + 1) * 8 - netmask_node->netmasks[j]); - else - mask = 0; - } - key_stream[i] &= mask; - } - - while (node->bit < key_bitlen) { - if (SC_RADIX_BITTEST(key_stream[node->bit >> 3], - (0x80 >> (node->bit % 8))) ) { - node = node->right; - } else { - node = node->left; - } - - if (node == NULL) - return NULL; - } - - if (node->bit != key_bitlen || node->prefix == NULL) - return NULL; - - if (SCMemcmp(node->prefix->stream, key_stream, bytes) == 0) { - mask = UINT_MAX << (8 - key_bitlen % 8); - - if (key_bitlen % 8 == 0 || - (node->prefix->stream[bytes] & mask) == (key_stream[bytes] & mask)) { - if (SCRadixPrefixContainNetmaskAndSetUserData( - node->prefix, netmask_node->netmasks[j], false, user_data_result)) - return node; - } - } - } - - return SCRadixFindKeyIPNetblock(key_stream, key_bitlen, netmask_node->parent, user_data_result); -} - -/** - * \brief Checks if an IP address key is present in the tree. The function - * apart from handling any normal data, also handles ipv4/ipv6 netblocks - * - * \param key_stream Data that has to be found in the Radix tree - * \param key_bitlen The bitlen of the above stream. - * \param tree Pointer to the Radix tree - * \param exact_match The key to be searched is an ip address - * \param netmask Netmask used during exact match - */ -static SCRadixNode *SCRadixFindKey(uint8_t *key_stream, uint8_t key_bitlen, uint8_t netmask, - SCRadixTree *tree, bool exact_match, void **user_data_result) -{ - if (tree == NULL || tree->head == NULL) - return NULL; - - SCRadixNode *node = tree->head; - uint32_t mask = 0; - int bytes = 0; - uint8_t tmp_stream[255]; - - memset(tmp_stream, 0, 255); - memcpy(tmp_stream, key_stream, key_bitlen / 8); - - while (node->bit < key_bitlen) { - if (SC_RADIX_BITTEST(tmp_stream[node->bit >> 3], - (0x80 >> (node->bit % 8))) ) { - node = node->right; - } else { - node = node->left; - } - - if (node == NULL) { - return NULL; - } - } - - if (node->bit != key_bitlen || node->prefix == NULL) { - return NULL; - } - - bytes = key_bitlen / 8; - if (SCMemcmp(node->prefix->stream, tmp_stream, bytes) == 0) { - mask = UINT_MAX << (8 - key_bitlen % 8); - - if (key_bitlen % 8 == 0 || - (node->prefix->stream[bytes] & mask) == (tmp_stream[bytes] & mask)) { - if (SCRadixPrefixContainNetmaskAndSetUserData( - node->prefix, netmask, true, user_data_result)) { - return node; - } - } - } - - /* if you are not an ip key, get out of here */ - if (exact_match) { - return NULL; - } - - SCRadixNode *ret = SCRadixFindKeyIPNetblock(tmp_stream, key_bitlen, node, user_data_result); - return ret; -} - -/** - * \brief Checks if an IPV4 address is present in the tree - * - * \param key_stream Data that has to be found in the Radix tree. In this case - * an IPV4 address - * \param tree Pointer to the Radix tree instance - */ -SCRadixNode *SCRadixFindKeyIPV4ExactMatch(uint8_t *key_stream, SCRadixTree *tree, void **user_data_result) -{ - return SCRadixFindKey(key_stream, 32, 32, tree, true, user_data_result); -} - -/** - * \brief Checks if an IPV4 address is present in the tree under a netblock - * - * \param key_stream Data that has to be found in the Radix tree. In this case - * an IPV4 address - * \param tree Pointer to the Radix tree instance - */ -SCRadixNode *SCRadixFindKeyIPV4BestMatch(uint8_t *key_stream, SCRadixTree *tree, void **user_data_result) -{ - return SCRadixFindKey(key_stream, 32, 32, tree, false, user_data_result); -} - -/** - * \brief Checks if an IPV4 Netblock address is present in the tree - * - * \param key_stream Data that has to be found in the Radix tree. In this case - * an IPV4 netblock address - * \param tree Pointer to the Radix tree instance - */ -SCRadixNode *SCRadixFindKeyIPV4Netblock(uint8_t *key_stream, SCRadixTree *tree, - uint8_t netmask, void **user_data_result) -{ -#if defined(DEBUG_VALIDATION) || defined(UNITTESTS) - SCRadixValidateIPv4Key(key_stream, netmask); -#endif - SCRadixNode *node = SCRadixFindKey(key_stream, 32, netmask, tree, true, user_data_result); - return node; -} - -/** - * \brief Checks if an IPV6 Netblock address is present in the tree - * - * \param key_stream Data that has to be found in the Radix tree. In this case - * an IPV6 netblock address - * \param tree Pointer to the Radix tree instance - */ -SCRadixNode *SCRadixFindKeyIPV6Netblock(uint8_t *key_stream, SCRadixTree *tree, - uint8_t netmask, void **user_data_result) -{ -#if defined(DEBUG_VALIDATION) || defined(UNITTESTS) - SCRadixValidateIPv6Key(key_stream, netmask); -#endif - SCRadixNode *node = SCRadixFindKey(key_stream, 128, netmask, tree, true, user_data_result); - return node; -} - -/** - * \brief Checks if an IPV6 address is present in the tree - * - * \param key_stream Data that has to be found in the Radix tree. In this case - * an IPV6 address - * \param tree Pointer to the Radix tree instance - */ -SCRadixNode *SCRadixFindKeyIPV6ExactMatch(uint8_t *key_stream, SCRadixTree *tree, void **user_data_result) -{ - return SCRadixFindKey(key_stream, 128, 128, tree, true, user_data_result); -} - -/** - * \brief Checks if an IPV6 address is present in the tree under a netblock - * - * \param key_stream Data that has to be found in the Radix tree. In this case - * an IPV6 address - * \param tree Pointer to the Radix tree instance - */ -SCRadixNode *SCRadixFindKeyIPV6BestMatch(uint8_t *key_stream, SCRadixTree *tree, void **user_data_result) -{ - return SCRadixFindKey(key_stream, 128, 128, tree, false, user_data_result); -} - -/** - * \brief Prints the node information from a Radix tree - * - * \param node Pointer to the Radix node whose information has to be printed - * \param level Used for indentation purposes - */ -void SCRadixPrintNodeInfo(SCRadixNode *node, int level, void (*PrintData)(void*)) -{ - int i = 0; - - if (node == NULL) - return; - - for (i = 0; i < level; i++) - printf(" "); - - printf("%d [", node->bit); - - if (node->netmasks == NULL) { - printf("%d, ", -1); - } else { - for (i = 0; i < node->netmask_cnt; i++) - printf("%s%d", (0 == i ? "" : ", "), node->netmasks[i]); - } - - printf("] ("); - if (node->prefix != NULL) { - for (i = 0; i * 8 < node->prefix->bitlen; i++) - printf("%s%d", (0 == i ? "" : "."), node->prefix->stream[i]); - printf(") user_data %p\n", node->prefix->user_data); - - SCRadixUserData *ud = node->prefix->user_data; - do { - for (int x = 0; x <= level; x++) - printf(" "); - printf("[%d] (%p): ", ud->netmask, ud->user); - if (PrintData != NULL) { - PrintData(ud->user); - } else { - printf("NULL"); - } - printf("\n"); - ud = ud->next; - } while (ud != NULL); - } else { - printf("inter_node)\n"); - } -} - -/** - * \brief Helper function used by SCRadixPrintTree. Prints the subtree with - * node as the root of the subtree - * - * \param node Pointer to the node that is the root of the subtree to be printed - * \param level Used for indentation purposes - */ -static void SCRadixPrintRadixSubtree(SCRadixNode *node, int level, void (*PrintData)(void*)) -{ - if (node != NULL) { - SCRadixPrintNodeInfo(node, level, PrintData); - SCRadixPrintRadixSubtree(node->left, level + 1, PrintData); - SCRadixPrintRadixSubtree(node->right, level + 1, PrintData); - } -} - -/** - * \brief Prints the Radix Tree. While printing the radix tree we use the - * following format - * - * Parent_0 - * Left_Child_1 - * Left_Child_2 - * Right_Child_2 - * Right_Child_1 - * Left_Child_2 - * Right_Child_2 and so on - * - * Each node printed out holds details on the next bit that differs - * amongst its children, and if the node holds a prefix, the perfix is - * printed as well. - * - * \param tree Pointer to the Radix tree that has to be printed - */ -void SCRadixPrintTree(SCRadixTree *tree) -{ - printf("Printing the Radix Tree: \n"); - - SCRadixPrintRadixSubtree(tree->head, 0, tree->PrintData); -} - -/*------------------------------------Unit_Tests------------------------------*/ - -#ifdef UNITTESTS - -static int SCRadixTestIPV4Insertion03(void) -{ - SCRadixTree *tree = NULL; - struct sockaddr_in servaddr; - int result = 1; - - tree = SCRadixCreateRadixTree(free, NULL); - - /* add the keys */ - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.168.1.1", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.168.1.2", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.167.1.3", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.167.1.4", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); - - /* add a key that already exists in the tree */ - SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); - - /* test for the existence of a key */ - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.168.1.6", &servaddr.sin_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) == NULL); - - /* test for the existence of a key */ - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.167.1.4", &servaddr.sin_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) != NULL); - - /* continue adding keys */ - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "220.168.1.2", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.168.1.5", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.168.1.18", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); - - /* test the existence of keys */ - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.168.1.3", &servaddr.sin_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) == NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "127.234.2.62", &servaddr.sin_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) == NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.168.1.1", &servaddr.sin_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) != NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.168.1.5", &servaddr.sin_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) != NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.168.1.2", &servaddr.sin_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) != NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.167.1.3", &servaddr.sin_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) != NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.167.1.4", &servaddr.sin_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) != NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "220.168.1.2", &servaddr.sin_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) != NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.168.1.18", &servaddr.sin_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) != NULL); - - SCRadixReleaseRadixTree(tree); - - return result; -} - -static int SCRadixTestIPV4Removal04(void) -{ - SCRadixTree *tree = NULL; - struct sockaddr_in servaddr; - int result = 1; - - tree = SCRadixCreateRadixTree(free, NULL); - - /* add the keys */ - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.168.1.1", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.168.1.2", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.167.1.3", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.167.1.4", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "220.168.1.2", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.168.1.5", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.168.1.18", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); - - /* remove the keys from the tree */ - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.168.1.1", &servaddr.sin_addr) <= 0) - return 0; - SCRadixRemoveKeyIPV4((uint8_t *)&servaddr.sin_addr, tree); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.167.1.3", &servaddr.sin_addr) <= 0) - return 0; - SCRadixRemoveKeyIPV4((uint8_t *)&servaddr.sin_addr, tree); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.167.1.4", &servaddr.sin_addr) <= 0) - return 0; - SCRadixRemoveKeyIPV4((uint8_t *)&servaddr.sin_addr, tree); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.168.1.18", &servaddr.sin_addr) <= 0) - return 0; - SCRadixRemoveKeyIPV4((uint8_t *)&servaddr.sin_addr, tree); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.167.1.1", &servaddr.sin_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) == NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.168.1.2", &servaddr.sin_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) != NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.167.1.3", &servaddr.sin_addr) <= 0) - return 0; - SCRadixRemoveKeyIPV4((uint8_t *)&servaddr.sin_addr, tree); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "220.168.1.2", &servaddr.sin_addr) <= 0) - return 0; - SCRadixRemoveKeyIPV4((uint8_t *)&servaddr.sin_addr, tree); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.168.1.5", &servaddr.sin_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) != NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.168.1.2", &servaddr.sin_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) != NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.168.1.2", &servaddr.sin_addr) <= 0) - return 0; - SCRadixRemoveKeyIPV4((uint8_t *)&servaddr.sin_addr, tree); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.168.1.5", &servaddr.sin_addr) <= 0) - return 0; - SCRadixRemoveKeyIPV4((uint8_t *)&servaddr.sin_addr, tree); - - result &= (tree->head == NULL); - - SCRadixReleaseRadixTree(tree); - - return result; -} - -static int SCRadixTestIPV6Insertion07(void) -{ - SCRadixTree *tree = NULL; - struct sockaddr_in6 servaddr; - int result = 1; - - tree = SCRadixCreateRadixTree(free, NULL); - - /* add the keys */ - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "2003:0BF1:5346:BDEA:7422:8713:9124:2315", - &servaddr.sin6_addr) <= 0) - return 0; - SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "BD15:9791:5346:6223:AADB:8713:9882:2432", - &servaddr.sin6_addr) <= 0) - return 0; - SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "1111:A21B:6221:BDEA:BBBA::DBAA:9861", - &servaddr.sin6_addr) <= 0) - return 0; - SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "4444:0BF7:5346:BDEA:7422:8713:9124:2315", - &servaddr.sin6_addr) <= 0) - return 0; - SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); - - /* Try to add the prefix that already exists in the tree */ - SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "5555:0BF1:ABCD:ADEA:7922:ABCD:9124:2375", - &servaddr.sin6_addr) <= 0) - return 0; - SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "DBCA:ABCD:ABCD:DBCA:1245:2342:1111:2212", - &servaddr.sin6_addr) <= 0) - return 0; - SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "2003:0BF1:5346:1251:7422:1112:9124:2315", - &servaddr.sin6_addr) <= 0) - return 0; - SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); - - /* test the existence of keys */ - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "2003:0BF1:5346:BDEA:7422:8713:9124:2315", - &servaddr.sin6_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) != NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "BD15:9791:5346:6223:AADB:8713:9882:2432", - &servaddr.sin6_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) != NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "1111:A21B:6221:BDEA:BBBA::DBAA:9861", - &servaddr.sin6_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) != NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "4444:0BF7:5346:BDEA:7422:8713:9124:2315", - &servaddr.sin6_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) != NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "DBCA:ABC2:ABCD:DBCA:1245:2342:1111:2212", - &servaddr.sin6_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) == NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "2003:0BF5:5346:1251:7422:1112:9124:2315", - &servaddr.sin6_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) == NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "5555:0BF1:ABCD:ADEA:7922:ABCD:9124:2375", - &servaddr.sin6_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) != NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "DBCA:ABCD:ABCD:DBCA:1245:2342:1111:2212", - &servaddr.sin6_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) != NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "2003:0BF1:5346:1251:7422:1112:9124:2315", - &servaddr.sin6_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) != NULL); - - SCRadixReleaseRadixTree(tree); - - return result; -} - -static int SCRadixTestIPV6Removal08(void) -{ - SCRadixTree *tree = NULL; - struct sockaddr_in6 servaddr; - int result = 1; - - tree = SCRadixCreateRadixTree(free, NULL); - - /* add the keys */ - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "2003:0BF1:5346:BDEA:7422:8713:9124:2315", - &servaddr.sin6_addr) <= 0) - return 0; - SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "BD15:9791:5346:6223:AADB:8713:9882:2432", - &servaddr.sin6_addr) <= 0) - return 0; - SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "1111:A21B:6221:BDEA:BBBA::DBAA:9861", - &servaddr.sin6_addr) <= 0) - return 0; - SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "4444:0BF7:5346:BDEA:7422:8713:9124:2315", - &servaddr.sin6_addr) <= 0) - return 0; - SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); - - /* Try to add the prefix that already exists in the tree */ - SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "5555:0BF1:ABCD:ADEA:7922:ABCD:9124:2375", - &servaddr.sin6_addr) <= 0) - return 0; - SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "DBCA:ABCD:ABCD:DBCA:1245:2342:1111:2212", - &servaddr.sin6_addr) <= 0) - return 0; - SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "2003:0BF1:5346:1251:7422:1112:9124:2315", - &servaddr.sin6_addr) <= 0) - return 0; - SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); - - /* test the existence of keys */ - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "2003:0BF1:5346:BDEA:7422:8713:9124:2315", - &servaddr.sin6_addr) <= 0) - return 0; - SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "8888:0BF1:5346:BDEA:6422:8713:9124:2315", - &servaddr.sin6_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) == NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "2006:0BF1:5346:BDEA:7422:8713:9124:2315", - &servaddr.sin6_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) == NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "2003:0BF1:5346:BDEA:7422:8713:9124:2315", - &servaddr.sin6_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) != NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "BD15:9791:5346:6223:AADB:8713:9882:2432", - &servaddr.sin6_addr) <= 0) - return 0; - SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); - - /* test for existence */ - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "1111:A21B:6221:BDEA:BBBA::DBAA:9861", - &servaddr.sin6_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) != NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "4444:0BF7:5346:BDEA:7422:8713:9124:2315", - &servaddr.sin6_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) != NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "5555:0BF1:ABCD:ADEA:7922:ABCD:9124:2375", - &servaddr.sin6_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) != NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "DBCA:ABCD:ABCD:DBCA:1245:2342:1111:2212", - &servaddr.sin6_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) != NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "2003:0BF1:5346:1251:7422:1112:9124:2315", - &servaddr.sin6_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) != NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "2003:0BF1:5346:BDEA:7422:8713:DDDD:2315", - &servaddr.sin6_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) == NULL); - - /* remove keys */ - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "2003:0BF1:5346:BDEA:7422:8713:9124:2315", - &servaddr.sin6_addr) <= 0) - return 0; - SCRadixRemoveKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "BD15:9791:5346:6223:AADB:8713:9882:2432", - &servaddr.sin6_addr) <= 0) - return 0; - SCRadixRemoveKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree); - - /* test for existence */ - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "2003:0BF1:5346:BDEA:7422:8713:9124:2315", - &servaddr.sin6_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) == NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "BD15:9791:5346:6223:AADB:8713:9882:2432", - &servaddr.sin6_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) == NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "1111:A21B:6221:BDEA:BBBA::DBAA:9861", - &servaddr.sin6_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) != NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "4444:0BF7:5346:BDEA:7422:8713:9124:2315", - &servaddr.sin6_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) != NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "5555:0BF1:ABCD:ADEA:7922:ABCD:9124:2375", - &servaddr.sin6_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) != NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "DBCA:ABCD:ABCD:DBCA:1245:2342:1111:2212", - &servaddr.sin6_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) != NULL); - - /* remove keys */ - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "1111:A21B:6221:BDEA:BBBA::DBAA:9861", - &servaddr.sin6_addr) <= 0) - return 0; - SCRadixRemoveKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "4444:0BF7:5346:BDEA:7422:8713:9124:2315", - &servaddr.sin6_addr) <= 0) - return 0; - SCRadixRemoveKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "5555:0BF1:ABCD:ADEA:7922:ABCD:9124:2375", - &servaddr.sin6_addr) <= 0) - return 0; - SCRadixRemoveKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "DBCA:ABCD:ABCD:DBCA:1245:2342:1111:2212", - &servaddr.sin6_addr) <= 0) - return 0; - SCRadixRemoveKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree); - - /* test for existence */ - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "2003:0BF1:5346:BDEA:7422:8713:9124:2315", - &servaddr.sin6_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) == NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "BD15:9791:5346:6223:AADB:8713:9882:2432", - &servaddr.sin6_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) == NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "1111:A21B:6221:BDEA:BBBA::DBAA:9861", - &servaddr.sin6_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) == NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "4444:0BF7:5346:BDEA:7422:8713:9124:2315", - &servaddr.sin6_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) == NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "5555:0BF1:ABCD:ADEA:7922:ABCD:9124:2375", - &servaddr.sin6_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) == NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "DBCA:ABCD:ABCD:DBCA:1245:2342:1111:2212", - &servaddr.sin6_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) == NULL); - - SCRadixReleaseRadixTree(tree); - - return result; -} - -/** Bug #5066 - * - * insert: - * - 100.117.241.0/25: 100.117.241.0 - 100.117.241.127 - * - 100.117.241.0/26: 100.117.241.0 - 100.117.241.63 - * - * check: - * - 100.117.241.64/26: 100.117.241.64 - 100.117.241.127 - */ - -static int SCRadixTestIPV4Bug5066(void) -{ - struct sockaddr_in servaddr; - SCRadixNode *node = NULL; - - SCLogDebug("setup tree"); - SCRadixTree *tree = SCRadixCreateRadixTree(free, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - FAIL_IF(inet_pton(AF_INET, "100.117.241.0", &servaddr.sin_addr) <= 0); - SCLogDebug("add 100.117.241.0/25"); - SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, strdup("1"), 25); - SCRadixPrintTree(tree); - SCLogDebug("find 100.117.241.0/25"); - char *r = NULL; - node = SCRadixFindKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, 25, (void **)&r); - FAIL_IF_NULL(node); - SCRadixPrintNodeInfo(node, 0, NULL); - - SCLogDebug("add 100.117.241.0/26"); - FAIL_IF(inet_pton(AF_INET, "100.117.241.0", &servaddr.sin_addr) <= 0); - SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, strdup("2"), 26); - SCRadixPrintTree(tree); - SCLogDebug("find 100.117.241.0/26"); - node = SCRadixFindKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, 26, NULL); - FAIL_IF_NULL(node); - SCRadixPrintNodeInfo(node, 0, NULL); - - SCLogDebug("find 100.117.241.64/26 (should fail)"); - FAIL_IF(inet_pton(AF_INET, "100.117.241.64", &servaddr.sin_addr) <= 0); - node = SCRadixFindKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, 26, NULL); - FAIL_IF_NOT_NULL(node); - SCRadixPrintNodeInfo(node, 0, NULL); - - SCLogDebug("add 100.117.241.64/26"); - SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, strdup("3"), 26); - SCLogDebug("find 100.117.241.64/26 (should succeed)"); - node = SCRadixFindKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, 26, NULL); - FAIL_IF_NULL(node); - SCRadixPrintNodeInfo(node, 0, NULL); - - SCRadixPrintTree(tree); - - SCRadixReleaseRadixTree(tree); - PASS; -} - -static void SCRadixTestIPV4Bug5066v2PrintData(void *d) -{ - const char *s = d; - printf("%s", s); -} - -static int SCRadixTestIPV4Bug5066v2(void) -{ - struct sockaddr_in servaddr; - SCRadixNode *node = NULL; - - SCLogDebug("setup tree"); - SCRadixTree *tree = SCRadixCreateRadixTree(free, SCRadixTestIPV4Bug5066v2PrintData); - - memset(&servaddr, 0, sizeof(servaddr)); - FAIL_IF(inet_pton(AF_INET, "1.2.3.0", &servaddr.sin_addr) <= 0); - SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, strdup("1.2.3.0/24"), 24); - SCRadixPrintTree(tree); - char *r = NULL; - node = SCRadixFindKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, 24, (void **)&r); - SCRadixPrintTree(tree); - FAIL_IF_NULL(node); - SCRadixPrintNodeInfo(node, 0, NULL); - FAIL_IF_NOT(strcmp(r, "1.2.3.0/24") == 0); - - memset(&servaddr, 0, sizeof(servaddr)); - FAIL_IF(inet_pton(AF_INET, "1.2.3.0", &servaddr.sin_addr) <= 0); - SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, strdup("1.2.3.0/25"), 25); - SCRadixPrintTree(tree); - r = NULL; - node = SCRadixFindKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, 25, (void **)&r); - SCRadixPrintTree(tree); - FAIL_IF_NULL(node); - SCRadixPrintNodeInfo(node, 0, NULL); - FAIL_IF_NOT(strcmp(r, "1.2.3.0/25") == 0); - - memset(&servaddr, 0, sizeof(servaddr)); - FAIL_IF(inet_pton(AF_INET, "1.2.3.0", &servaddr.sin_addr) <= 0); - SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, strdup("1.2.3.0/26"), 26); - SCRadixPrintTree(tree); - r = NULL; - node = SCRadixFindKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, 26, (void **)&r); - SCRadixPrintTree(tree); - FAIL_IF_NULL(node); - SCRadixPrintNodeInfo(node, 0, NULL); - FAIL_IF_NOT(strcmp(r, "1.2.3.0/26") == 0); - - memset(&servaddr, 0, sizeof(servaddr)); - FAIL_IF(inet_pton(AF_INET, "1.2.3.64", &servaddr.sin_addr) <= 0); - SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, strdup("1.2.3.64/26"), 26); - SCRadixPrintTree(tree); - r = NULL; - node = SCRadixFindKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, 26, (void **)&r); - SCRadixPrintTree(tree); - FAIL_IF_NULL(node); - SCRadixPrintNodeInfo(node, 0, NULL); - FAIL_IF_NOT(strcmp(r, "1.2.3.64/26") == 0); - - memset(&servaddr, 0, sizeof(servaddr)); - FAIL_IF(inet_pton(AF_INET, "1.2.3.64", &servaddr.sin_addr) <= 0); - SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, strdup("1.2.3.64/27"), 27); - SCRadixPrintTree(tree); - r = NULL; - node = SCRadixFindKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, 27, (void **)&r); - SCRadixPrintTree(tree); - FAIL_IF_NULL(node); - SCRadixPrintNodeInfo(node, 0, NULL); - FAIL_IF_NOT(strcmp(r, "1.2.3.64/27") == 0); - - memset(&servaddr, 0, sizeof(servaddr)); - FAIL_IF(inet_pton(AF_INET, "1.2.3.96", &servaddr.sin_addr) <= 0); - SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, strdup("1.2.3.96/27"), 27); - SCRadixPrintTree(tree); - r = NULL; - node = SCRadixFindKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, 27, (void **)&r); - SCRadixPrintTree(tree); - FAIL_IF_NULL(node); - SCLogNotice("node:"); - SCRadixPrintNodeInfo(node, 0, NULL); - FAIL_IF_NOT(strcmp(r, "1.2.3.96/27") == 0); - - SCRadixReleaseRadixTree(tree); - PASS; -} - -/** Bug #5066 - */ -static int SCRadixTestIPV6Bug5066(void) -{ - struct sockaddr_in6 servaddr; - SCRadixNode *node = NULL; - - SCLogDebug("setup tree"); - SCRadixTree *tree = SCRadixCreateRadixTree(free, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - FAIL_IF(inet_pton(AF_INET6, "2000::1:0", &servaddr.sin6_addr) <= 0); - SCLogDebug("add 2000::1:0/121"); - SCRadixAddKeyIPV6Netblock((uint8_t *)&servaddr.sin6_addr, tree, strdup("1"), 121); - SCRadixPrintTree(tree); - SCLogDebug("find 2000::1:0/121"); - char *r = NULL; - node = SCRadixFindKeyIPV6Netblock((uint8_t *)&servaddr.sin6_addr, tree, 121, (void **)&r); - FAIL_IF_NULL(node); - SCRadixPrintNodeInfo(node, 0, NULL); - - SCLogDebug("add 2000::1:0/122"); - FAIL_IF(inet_pton(AF_INET6, "2000::1:0", &servaddr.sin6_addr) <= 0); - SCRadixAddKeyIPV6Netblock((uint8_t *)&servaddr.sin6_addr, tree, strdup("2"), 122); - SCRadixPrintTree(tree); - SCLogDebug("find 2000::1:0/122"); - node = SCRadixFindKeyIPV6Netblock((uint8_t *)&servaddr.sin6_addr, tree, 122, NULL); - FAIL_IF_NULL(node); - SCRadixPrintNodeInfo(node, 0, NULL); - - SCLogDebug("find 2000::1:40/122 (should fail)"); - FAIL_IF(inet_pton(AF_INET6, "2000::1:40", &servaddr.sin6_addr) <= 0); - node = SCRadixFindKeyIPV6Netblock((uint8_t *)&servaddr.sin6_addr, tree, 122, NULL); - FAIL_IF_NOT_NULL(node); - SCRadixPrintNodeInfo(node, 0, NULL); - - SCLogDebug("add 2000::1:40/122"); - SCRadixAddKeyIPV6Netblock((uint8_t *)&servaddr.sin6_addr, tree, strdup("3"), 122); - SCLogDebug("find 2000::1:40/122 (should succeed)"); - node = SCRadixFindKeyIPV6Netblock((uint8_t *)&servaddr.sin6_addr, tree, 122, NULL); - FAIL_IF_NULL(node); - SCRadixPrintNodeInfo(node, 0, NULL); - - SCRadixPrintTree(tree); - - SCRadixReleaseRadixTree(tree); - PASS; -} - -static int SCRadixTestIPV4NetblockInsertion09(void) -{ - SCRadixTree *tree = NULL; - struct sockaddr_in servaddr; - int result = 1; - - tree = SCRadixCreateRadixTree(free, NULL); - - /* add the keys */ - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.168.1.1", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.168.1.2", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.167.1.3", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.167.1.4", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "220.168.1.2", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.168.1.5", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.168.1.18", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.168.0.0", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 16); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.171.128.0", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 24); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.171.192.0", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 18); - - if (inet_pton(AF_INET, "192.175.0.0", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 16); - - /* test for the existence of a key */ - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.168.1.6", &servaddr.sin_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) != NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.170.1.6", &servaddr.sin_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) == NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.171.128.145", &servaddr.sin_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) != NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.171.64.6", &servaddr.sin_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) == NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.171.191.6", &servaddr.sin_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) == NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.171.224.6", &servaddr.sin_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) != NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.174.224.6", &servaddr.sin_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) == NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.175.224.6", &servaddr.sin_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) != NULL); - - SCRadixReleaseRadixTree(tree); - - return result; -} - -static int SCRadixTestIPV4NetblockInsertion10(void) -{ - SCRadixTree *tree = NULL; - SCRadixNode *node[2]; - struct sockaddr_in servaddr; - - tree = SCRadixCreateRadixTree(free, NULL); - - /* add the keys */ - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "253.192.0.0", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 16); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "253.192.235.0", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 24); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.167.0.0", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 16); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.167.1.4", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "220.168.0.0", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 16); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "253.224.1.5", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.168.0.0", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 16); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.171.128.0", &servaddr.sin_addr) <= 0) - return 0; - node[0] = SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 24); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.171.128.45", &servaddr.sin_addr) <= 0) - return 0; - node[1] = SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.171.0.0", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 18); - - if (inet_pton(AF_INET, "192.175.0.0", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 16); - - SCRadixPrintTree(tree); - - /* test for the existence of a key */ - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.171.128.53", &servaddr.sin_addr) <= 0) - return 0; - SCRadixNode *found = SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, NULL); - FAIL_IF_NOT(found == node[0]); - - SCLogDebug("search \"exact\" match for 192.171.128.45"); - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.171.128.45", &servaddr.sin_addr) <= 0) - return 0; - found = SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree, NULL); - FAIL_IF_NOT(found == node[1]); - - SCLogDebug("search \"best\" match for 192.171.128.45"); - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.171.128.45", &servaddr.sin_addr) <= 0) - return 0; - found = SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, NULL); - FAIL_IF_NOT(found == node[1]); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.171.128.78", &servaddr.sin_addr) <= 0) - return 0; - found = SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, NULL); - FAIL_IF_NOT(found == node[0]); - - /* let us remove a netblock */ - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.171.128.0", &servaddr.sin_addr) <= 0) - return 0; - SCRadixRemoveKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, 24); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.171.128.78", &servaddr.sin_addr) <= 0) - return 0; - found = SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, NULL); - FAIL_IF_NOT_NULL(found); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.171.127.78", &servaddr.sin_addr) <= 0) - return 0; - found = SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, NULL); - FAIL_IF_NOT_NULL(found); - - SCRadixReleaseRadixTree(tree); - PASS; -} - -static int SCRadixTestIPV4NetblockInsertion11(void) -{ - SCRadixTree *tree = NULL; - SCRadixNode *node = NULL; - struct sockaddr_in servaddr; - int result = 1; - - tree = SCRadixCreateRadixTree(free, NULL); - - /* add the keys */ - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "253.192.0.0", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 16); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "253.192.235.0", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 24); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.167.0.0", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 16); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.167.1.4", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "220.168.0.0", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 16); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "253.224.1.5", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.168.0.0", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 16); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.171.128.0", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 24); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.171.128.45", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.171.0.0", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 18); - - if (inet_pton(AF_INET, "192.175.0.0", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 16); - - if (inet_pton(AF_INET, "0.0.0.0", &servaddr.sin_addr) <= 0) - return 0; - node = SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 0); - - /* test for the existence of a key */ - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.171.128.53", &servaddr.sin_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) != NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.171.128.45", &servaddr.sin_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) != NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.171.128.78", &servaddr.sin_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) != NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.171.127.78", &servaddr.sin_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) == node); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "1.1.1.1", &servaddr.sin_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) == node); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.255.254.25", &servaddr.sin_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) == node); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "169.255.254.25", &servaddr.sin_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) == node); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "0.0.0.0", &servaddr.sin_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) == node); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "253.224.1.5", &servaddr.sin_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) != NULL && - SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) != node); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "245.63.62.121", &servaddr.sin_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) != NULL && - SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) == node); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "253.224.1.6", &servaddr.sin_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) != NULL && - SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) == node); - - /* remove node 0.0.0.0 */ - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "0.0.0.0", &servaddr.sin_addr) <= 0) - return 0; - SCRadixRemoveKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, 0); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "253.224.1.6", &servaddr.sin_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) == NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.171.127.78", &servaddr.sin_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) == NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "1.1.1.1", &servaddr.sin_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) == NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.255.254.25", &servaddr.sin_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) == NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "169.255.254.25", &servaddr.sin_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) == NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "0.0.0.0", &servaddr.sin_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) == NULL); - - SCRadixReleaseRadixTree(tree); - - return result; -} - -static int SCRadixTestIPV4NetblockInsertion12(void) -{ - SCRadixTree *tree = NULL; - SCRadixNode *node[2]; - struct sockaddr_in servaddr; - int result = 1; - - tree = SCRadixCreateRadixTree(free, NULL); - - /* add the keys */ - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "253.192.0.0", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 16); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "253.192.235.0", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 24); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.167.0.0", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 16); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.167.1.4", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "220.168.0.0", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 16); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "253.224.1.5", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.168.0.0", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 16); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.171.128.0", &servaddr.sin_addr) <= 0) - return 0; - node[0] = SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 24); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.171.128.45", &servaddr.sin_addr) <= 0) - return 0; - node[1] = SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.171.0.0", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 18); - - if (inet_pton(AF_INET, "225.175.21.228", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 32); - - /* test for the existence of a key */ - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.171.128.53", &servaddr.sin_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) == node[0]); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.171.128.53", &servaddr.sin_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) == NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.171.128.45", &servaddr.sin_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) == node[1]); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.171.128.45", &servaddr.sin_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) == node[1]); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.171.128.45", &servaddr.sin_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) == node[1]); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.171.128.78", &servaddr.sin_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) == node[0]); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.171.127.78", &servaddr.sin_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) == NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "225.175.21.228", &servaddr.sin_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) != NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "225.175.21.224", &servaddr.sin_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) == NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "225.175.21.229", &servaddr.sin_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) == NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "225.175.21.230", &servaddr.sin_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) == NULL); - - SCRadixReleaseRadixTree(tree); - - return result; -} - -static int SCRadixTestIPV6NetblockInsertion13(void) -{ - SCRadixTree *tree = NULL; - struct sockaddr_in6 servaddr; - int result = 1; - - tree = SCRadixCreateRadixTree(free, NULL); - - /* add the keys */ - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "2003:0BF1:5346:BDEA:7422:8713:9124:2315", - &servaddr.sin6_addr) <= 0) - return 0; - SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "BD15:9791:5346:6223:AADB:8713:9882:2432", - &servaddr.sin6_addr) <= 0) - return 0; - SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "1111:A21B:6221:BDEA:BBBA::DBAA:9861", - &servaddr.sin6_addr) <= 0) - return 0; - SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "4444:0BF7:5346:BDEA:7422:8713:9124:2315", - &servaddr.sin6_addr) <= 0) - return 0; - SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "5555:0BF1:ABCD:ADEA:7922:ABCD:9124:2375", - &servaddr.sin6_addr) <= 0) - return 0; - SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "DBCA:ABCD:ABCD:DB00:0000:0000:0000:0000", - &servaddr.sin6_addr) <= 0) - return 0; - SCRadixAddKeyIPV6Netblock((uint8_t *)&servaddr.sin6_addr, tree, NULL, 56); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "DBCA:ABCD:ABCD:DBAA:1245:2342:1145:6241", - &servaddr.sin6_addr) <= 0) - return 0; - SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); - - /* test the existence of keys */ - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "2003:0BF1:5346:BDEA:7422:8713:9124:2315", - &servaddr.sin6_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) != NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "BD15:9791:5346:6223:AADB:8713:9882:2432", - &servaddr.sin6_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) != NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "1111:A21B:6221:BDEA:BBBA::DBAA:9861", - &servaddr.sin6_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) != NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "1111:A21B:6221:BDEA:BBBA::DBAA:9861", - &servaddr.sin6_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV6BestMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) != NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "4444:0BF7:5346:BDEA:7422:8713:9124:2315", - &servaddr.sin6_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) != NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "DBCA:ABC2:ABCD:DBCA:1245:2342:1111:2212", - &servaddr.sin6_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) == NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "2003:0BF5:5346:1251:7422:1112:9124:2315", - &servaddr.sin6_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) == NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "5555:0BF1:ABCD:ADEA:7922:ABCD:9124:2375", - &servaddr.sin6_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) != NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "DBCA:ABCD:ABCD:DBCA:1245:2342:1111:2212", - &servaddr.sin6_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV6BestMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) != NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "DBCA:ABCD:ABCD:DBAA:1245:2342:1146:6241", - &servaddr.sin6_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV6BestMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) != NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "DBCA:ABCD:ABCD:DBAA:1245:2342:1356:1241", - &servaddr.sin6_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV6BestMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) != NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "DBCA:ABCD:ABCD:DAAA:1245:2342:1146:6241", - &servaddr.sin6_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) == NULL); - - - SCRadixReleaseRadixTree(tree); - - return result; -} - -static int SCRadixTestIPV6NetblockInsertion14(void) -{ - SCRadixTree *tree = NULL; - SCRadixNode *node = NULL; - struct sockaddr_in6 servaddr; - int result = 1; - - tree = SCRadixCreateRadixTree(free, NULL); - - /* add the keys */ - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "2003:0BF1:5346:BDEA:7422:8713:9124:2315", - &servaddr.sin6_addr) <= 0) - return 0; - SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "BD15:9791:5346:6223:AADB:8713:9882:2432", - &servaddr.sin6_addr) <= 0) - return 0; - SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "1111:A21B:6221:BDEA:BBBA::DBAA:9861", - &servaddr.sin6_addr) <= 0) - return 0; - SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "4444:0BF7:5346:BDEA:7422:8713:9124:2315", - &servaddr.sin6_addr) <= 0) - return 0; - SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "5555:0BF1:ABCD:ADEA:7922:ABCD:9124:2375", - &servaddr.sin6_addr) <= 0) - return 0; - SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "DBCA:ABCD:ABCD:DB00:0000:0000:0000:0000", - &servaddr.sin6_addr) <= 0) - return 0; - SCRadixAddKeyIPV6Netblock((uint8_t *)&servaddr.sin6_addr, tree, NULL, 56); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "DBCA:ABCD:ABCD:DBAA:1245:2342:1145:6241", - &servaddr.sin6_addr) <= 0) - return 0; - SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "::", &servaddr.sin6_addr) <= 0) - return 0; - node = SCRadixAddKeyIPV6Netblock((uint8_t *)&servaddr.sin6_addr, tree, NULL, - 0); - - /* test the existence of keys */ - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "2004:0BF1:5346:BDEA:7422:8713:9124:2315", - &servaddr.sin6_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) == NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "2004:0BF1:5346:BDEA:7422:8713:9124:2315", - &servaddr.sin6_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV6BestMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) == node); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "2004:0BF1:5346:B116:2362:8713:9124:2315", - &servaddr.sin6_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV6BestMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) == node); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "2004:0B23:3252:BDEA:7422:8713:9124:2341", - &servaddr.sin6_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV6BestMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) == node); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "DBCA:ABCD:ABCD:DBAA:1245:2342:1145:6241", - &servaddr.sin6_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) != NULL && - SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) != node); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "DBCA:ABCD:ABCD:DBAA:1245:2342:1145:6241", - &servaddr.sin6_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV6BestMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) != NULL && - SCRadixFindKeyIPV6BestMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) != node); - - SCRadixReleaseRadixTree(tree); - - return result; -} - -/** - * \test Check that the best match search works for all the - * possible netblocks of a fixed address - */ -static int SCRadixTestIPV4NetBlocksAndBestSearch15(void) -{ - - SCRadixTree *tree = SCRadixCreateRadixTree(free, NULL); - FAIL_IF_NULL(tree); - - struct sockaddr_in servaddr; - memset(&servaddr, 0, sizeof(servaddr)); - FAIL_IF(inet_pton(AF_INET, "192.168.0.1", &servaddr.sin_addr) <= 0); - - for (uint32_t i = 0; i <= 32; i++) { - uint32_t *user = SCMalloc(sizeof(uint32_t)); - FAIL_IF_NULL(user); - *user = i; - - char str[32]; - snprintf(str, sizeof(str), "192.168.0.1/%u", i); - SCRadixAddKeyIPV4String(str, tree, user); - - void *user_data = NULL; - SCRadixNode *node = SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, &user_data); - FAIL_IF_NULL(node); - FAIL_IF_NULL(user_data); - FAIL_IF(*((uint32_t *)user_data) != i); - } - - SCRadixReleaseRadixTree(tree); - PASS; -} - -/** - * \test Check that the best match search works for all the - * possible netblocks of a fixed address - */ -static int SCRadixTestIPV4NetBlocksAndBestSearch16(void) -{ - - SCRadixTree *tree = SCRadixCreateRadixTree(free, NULL); - FAIL_IF_NULL(tree); - - struct sockaddr_in servaddr; - memset(&servaddr, 0, sizeof(servaddr)); - FAIL_IF(inet_pton(AF_INET, "192.168.1.1", &servaddr.sin_addr) <= 0); - - for (uint32_t i = 0; i <= 32; i++) { - uint32_t *user = SCMalloc(sizeof(uint32_t)); - FAIL_IF_NULL(user); - *user = i; - - char str[32]; - snprintf(str, sizeof(str), "192.168.1.1/%u", i); - SCRadixAddKeyIPV4String(str, tree, user); - - void *user_data = NULL; - SCRadixNode *node = SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, &user_data); - FAIL_IF_NULL(node); - FAIL_IF_NULL(user_data); - FAIL_IF(*((uint32_t *)user_data) != i); - } - - SCRadixReleaseRadixTree(tree); - PASS; -} - -/** - * \test Check that the best match search works for all the - * possible netblocks of a fixed address - */ -static int SCRadixTestIPV4NetBlocksAndBestSearch17(void) -{ - SCRadixTree *tree = SCRadixCreateRadixTree(free, NULL); - FAIL_IF_NULL(tree); - - struct sockaddr_in servaddr; - memset(&servaddr, 0, sizeof(servaddr)); - FAIL_IF(inet_pton(AF_INET, "10.0.0.1", &servaddr.sin_addr) <= 0); - - for (uint32_t i = 0; i <= 32; i++) { - uint32_t *user = SCMalloc(sizeof(uint32_t)); - FAIL_IF_NULL(user); - *user = i; - - char str[32]; - snprintf(str, sizeof(str), "10.0.0.1/%u", i); - SCRadixAddKeyIPV4String(str, tree, user); - - void *user_data = NULL; - SCRadixNode *node = SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, &user_data); - FAIL_IF_NULL(node); - FAIL_IF_NULL(user_data); - FAIL_IF(*((uint32_t *)user_data) != i); - } - - SCRadixReleaseRadixTree(tree); - PASS; -} - -/** - * \test Check that the best match search works for all the - * possible netblocks of a fixed address - */ -static int SCRadixTestIPV4NetBlocksAndBestSearch18(void) -{ - SCRadixTree *tree = SCRadixCreateRadixTree(free, NULL); - FAIL_IF_NULL(tree); - - struct sockaddr_in servaddr; - memset(&servaddr, 0, sizeof(servaddr)); - FAIL_IF(inet_pton(AF_INET, "172.26.0.1", &servaddr.sin_addr) <= 0); - - for (uint32_t i = 0; i <= 32; i++) { - uint32_t *user = SCMalloc(sizeof(uint32_t)); - FAIL_IF_NULL(user); - *user = i; - - char str[32]; - snprintf(str, sizeof(str), "172.26.0.1/%u", i); - SCRadixAddKeyIPV4String(str, tree, user); - - void *user_data = NULL; - SCRadixNode *node = SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, &user_data); - FAIL_IF_NULL(node); - FAIL_IF_NULL(user_data); - FAIL_IF(*((uint32_t *)user_data) != i); - } - - SCRadixReleaseRadixTree(tree); - PASS; -} - -/** - * \test Check special combinations of netblocks and addresses - * on best search checking the returned userdata - */ -static int SCRadixTestIPV4NetBlocksAndBestSearch19(void) -{ - SCRadixTree *tree = SCRadixCreateRadixTree(free, NULL); - FAIL_IF_NULL(tree); - - struct sockaddr_in servaddr; - memset(&servaddr, 0, sizeof(servaddr)); - FAIL_IF(inet_pton(AF_INET, "0.0.0.0", &servaddr.sin_addr) <= 0); - - uint32_t *user = SCMalloc(sizeof(uint32_t)); - FAIL_IF_NULL(user); - *user = 100; - - SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, user, 0); - - memset(&servaddr, 0, sizeof(servaddr)); - FAIL_IF(inet_pton(AF_INET, "192.168.1.15", &servaddr.sin_addr) <= 0); - void *user_data = NULL; - SCRadixNode *node = SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, &user_data); - FAIL_IF_NULL(node); - FAIL_IF_NULL(user_data); - FAIL_IF(*((uint32_t *)user_data) != 100); - - user_data = NULL; - memset(&servaddr, 0, sizeof(servaddr)); - FAIL_IF(inet_pton(AF_INET, "177.0.0.0", &servaddr.sin_addr) <= 0); - user = SCMalloc(sizeof(uint32_t)); - FAIL_IF_NULL(user); - *user = 200; - - SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, user, 8); - - memset(&servaddr, 0, sizeof(servaddr)); - FAIL_IF(inet_pton(AF_INET, "177.168.1.15", &servaddr.sin_addr) <= 0); - - node = SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, &user_data); - FAIL_IF_NULL(node); - FAIL_IF_NULL(user_data); - FAIL_IF(*((uint32_t *)user_data) != 200); - - user_data = NULL; - memset(&servaddr, 0, sizeof(servaddr)); - FAIL_IF(inet_pton(AF_INET, "178.168.1.15", &servaddr.sin_addr) <= 0); - - node = SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, &user_data); - FAIL_IF_NULL(node); - FAIL_IF_NULL(user_data); - FAIL_IF(*((uint32_t *)user_data) != 100); - - user_data = NULL; - memset(&servaddr, 0, sizeof(servaddr)); - FAIL_IF(inet_pton(AF_INET, "177.160.0.0", &servaddr.sin_addr) <= 0); - user = SCMalloc(sizeof(uint32_t)); - FAIL_IF_NULL(user); - *user = 300; - - SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, user, 12); - - memset(&servaddr, 0, sizeof(servaddr)); - FAIL_IF(inet_pton(AF_INET, "177.168.1.15", &servaddr.sin_addr) <= 0); - - node = SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, &user_data); - FAIL_IF_NULL(node); - FAIL_IF_NULL(user_data); - FAIL_IF(*((uint32_t *)user_data) != 300); - - user_data = NULL; - memset(&servaddr, 0, sizeof(servaddr)); - FAIL_IF(inet_pton(AF_INET, "177.167.1.15", &servaddr.sin_addr) <= 0); - - node = SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, &user_data); - FAIL_IF_NULL(node); - FAIL_IF_NULL(user_data); - FAIL_IF(*((uint32_t *)user_data) != 300); - - user_data = NULL; - memset(&servaddr, 0, sizeof(servaddr)); - FAIL_IF(inet_pton(AF_INET, "177.178.1.15", &servaddr.sin_addr) <= 0); - - node = SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, &user_data); - FAIL_IF_NULL(node); - FAIL_IF_NULL(user_data); - FAIL_IF(*((uint32_t *)user_data) != 200); - - user_data = NULL; - memset(&servaddr, 0, sizeof(servaddr)); - FAIL_IF(inet_pton(AF_INET, "197.178.1.15", &servaddr.sin_addr) <= 0); - - node = SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, &user_data); - FAIL_IF_NULL(node); - FAIL_IF_NULL(user_data); - FAIL_IF(*((uint32_t *)user_data) != 100); - - SCRadixReleaseRadixTree(tree); - PASS; -} - -/** - * \test Check that the best match search works for all the - * possible netblocks of a fixed address - */ -static int SCRadixTestIPV6NetBlocksAndBestSearch20(void) -{ - SCRadixTree *tree = SCRadixCreateRadixTree(free, NULL); - FAIL_IF_NULL(tree); - - struct sockaddr_in6 servaddr; - memset(&servaddr, 0, sizeof(servaddr)); - FAIL_IF(inet_pton(AF_INET6, "ABAB:CDCD:ABAB:CDCD:1234:4321:1234:4321", &servaddr.sin6_addr) <= - 0); - - for (uint32_t i = 0; i <= 128; i++) { - uint32_t *user = SCMalloc(sizeof(uint32_t)); - FAIL_IF_NULL(user); - *user = i; - - char str[64]; - snprintf(str, sizeof(str), "ABAB:CDCD:ABAB:CDCD:1234:4321:1234:4321/%u", i); - SCRadixAddKeyIPV6String(str, tree, user); - - void *user_data = NULL; - SCRadixNode *node = SCRadixFindKeyIPV6BestMatch((uint8_t *)&servaddr.sin6_addr, tree, &user_data); - FAIL_IF_NULL(node); - FAIL_IF_NULL(user_data); - FAIL_IF(*((uint32_t *)user_data) != i); - } - - SCRadixReleaseRadixTree(tree); - PASS; -} - -/** - * \test Check that the best match search works for all the - * possible netblocks of a fixed address - */ -static int SCRadixTestIPV6NetBlocksAndBestSearch21(void) -{ - SCRadixTree *tree = SCRadixCreateRadixTree(free, NULL); - FAIL_IF_NULL(tree); - - struct sockaddr_in6 servaddr; - memset(&servaddr, 0, sizeof(servaddr)); - FAIL_IF(inet_pton(AF_INET6, "ff00::1", &servaddr.sin6_addr) <= 0); - - for (uint32_t i = 0; i <= 128; i++) { - uint32_t *user = SCMalloc(sizeof(uint32_t)); - FAIL_IF_NULL(user); - *user = i; - - char str[64]; - snprintf(str, sizeof(str), "ff00::1/%u", i); - SCRadixAddKeyIPV6String(str, tree, user); - - void *user_data = NULL; - SCRadixNode *node = SCRadixFindKeyIPV6BestMatch((uint8_t *)&servaddr.sin6_addr, tree, &user_data); - FAIL_IF_NULL(node); - FAIL_IF_NULL(user_data); - FAIL_IF(*((uint32_t *)user_data) != i); - } - - SCRadixReleaseRadixTree(tree); - PASS; -} - -/** - * \test Check that the best match search works for all the - * possible netblocks of a fixed address - */ -static int SCRadixTestIPV6NetBlocksAndBestSearch22(void) -{ - SCRadixTree *tree = SCRadixCreateRadixTree(free, NULL); - FAIL_IF_NULL(tree); - - struct sockaddr_in6 servaddr; - memset(&servaddr, 0, sizeof(servaddr)); - FAIL_IF(inet_pton(AF_INET6, "ff00::192:168:1:1", &servaddr.sin6_addr) <= 0); - - for (uint32_t i = 0; i <= 128; i++) { - uint32_t *user = SCMalloc(sizeof(uint32_t)); - FAIL_IF_NULL(user); - *user = i; - - char str[64]; - snprintf(str, sizeof(str), "ff00::192:168:1:1/%u", i); - SCRadixAddKeyIPV6String(str, tree, user); - - void *user_data = NULL; - SCRadixNode *node = SCRadixFindKeyIPV6BestMatch((uint8_t *)&servaddr.sin6_addr, tree, &user_data); - FAIL_IF_NULL(node); - FAIL_IF_NULL(user_data); - FAIL_IF(*((uint32_t *)user_data) != i); - } - - SCRadixReleaseRadixTree(tree); - PASS; -} - -/** - * \test Check that the best match search works for all the - * possible netblocks of a fixed address - */ -static int SCRadixTestIPV6NetBlocksAndBestSearch23(void) -{ - SCRadixTree *tree = SCRadixCreateRadixTree(free, NULL); - FAIL_IF_NULL(tree); - - struct sockaddr_in6 servaddr; - memset(&servaddr, 0, sizeof(servaddr)); - FAIL_IF(inet_pton(AF_INET6, "FF00:ABCD:BCDA::ABCD", &servaddr.sin6_addr) <= 0); - - for (uint32_t i = 0; i <= 128; i++) { - uint32_t *user = SCMalloc(sizeof(uint32_t)); - FAIL_IF_NULL(user); - *user = i; - - char str[64]; - snprintf(str, sizeof(str), "FF00:ABCD:BCDA::ABCD/%u", i); - SCRadixAddKeyIPV6String(str, tree, user); - - void *user_data = NULL; - SCRadixNode *node = SCRadixFindKeyIPV6BestMatch((uint8_t *)&servaddr.sin6_addr, tree, &user_data); - FAIL_IF_NULL(node); - FAIL_IF_NULL(user_data); - FAIL_IF(*((uint32_t *)user_data) != i); - } - - SCRadixReleaseRadixTree(tree); - PASS; -} - -/** - * \test Check special combinations of netblocks and addresses - * on best search checking the returned userdata - */ -static int SCRadixTestIPV6NetBlocksAndBestSearch24(void) -{ - struct sockaddr_in6 servaddr; - void *user_data = NULL; - - SCRadixTree *tree = SCRadixCreateRadixTree(free, NULL); - FAIL_IF_NULL(tree); - - uint32_t *user = SCMalloc(sizeof(uint32_t)); - FAIL_IF_NULL(user); - *user = 100; - SCRadixAddKeyIPV6String("::/0", tree, user); - - memset(&servaddr, 0, sizeof(servaddr)); - FAIL_IF(inet_pton(AF_INET6, "ABCD::1", &servaddr.sin6_addr) <= 0); - SCRadixNode *node = SCRadixFindKeyIPV6BestMatch((uint8_t *)&servaddr.sin6_addr, tree, &user_data); - FAIL_IF_NULL(node); - FAIL_IF_NULL(user_data); - FAIL_IF(*((uint32_t *)user_data) != 100); - - user_data = NULL; - user = SCMalloc(sizeof(uint32_t)); - FAIL_IF_NULL(user); - *user = 200; - SCRadixAddKeyIPV6String("ABCD::0/8", tree, user); - - memset(&servaddr, 0, sizeof(servaddr)); - FAIL_IF(inet_pton(AF_INET6, "ABCD::1", &servaddr.sin6_addr) <= 0); - node = SCRadixFindKeyIPV6BestMatch((uint8_t *)&servaddr.sin6_addr, tree, &user_data); - FAIL_IF_NULL(node); - FAIL_IF_NULL(user_data); - FAIL_IF(*((uint32_t *)user_data) != 200); - - user_data = NULL; - memset(&servaddr, 0, sizeof(servaddr)); - FAIL_IF(inet_pton(AF_INET6, "DCBA::1", &servaddr.sin6_addr) <= 0); - - node = SCRadixFindKeyIPV6BestMatch((uint8_t *)&servaddr.sin6_addr, tree, &user_data); - FAIL_IF_NULL(node); - FAIL_IF_NULL(user_data); - FAIL_IF(*((uint32_t *)user_data) != 100); - - user_data = NULL; - user = SCMalloc(sizeof(uint32_t)); - FAIL_IF_NULL(user); - *user = 300; - SCRadixAddKeyIPV6String("ABCD:ABCD::0/12", tree, user); - - memset(&servaddr, 0, sizeof(servaddr)); - FAIL_IF(inet_pton(AF_INET6, "ABCD:ABCD::1", &servaddr.sin6_addr) <= 0); - node = SCRadixFindKeyIPV6BestMatch((uint8_t *)&servaddr.sin6_addr, tree, &user_data); - FAIL_IF_NULL(node); - FAIL_IF_NULL(user_data); - FAIL_IF(*((uint32_t *)user_data) != 300); - - user_data = NULL; - memset(&servaddr, 0, sizeof(servaddr)); - FAIL_IF(inet_pton(AF_INET6, "ABCD:AAAA::1", &servaddr.sin6_addr) <= 0); - node = SCRadixFindKeyIPV6BestMatch((uint8_t *)&servaddr.sin6_addr, tree, &user_data); - FAIL_IF_NULL(node); - FAIL_IF_NULL(user_data); - FAIL_IF(*((uint32_t *)user_data) != 300); - - user_data = NULL; - memset(&servaddr, 0, sizeof(servaddr)); - FAIL_IF(inet_pton(AF_INET6, "ABAB::1", &servaddr.sin6_addr) <= 0); - node = SCRadixFindKeyIPV6BestMatch((uint8_t *)&servaddr.sin6_addr, tree, &user_data); - FAIL_IF_NULL(node); - FAIL_IF_NULL(user_data); - FAIL_IF(*((uint32_t *)user_data) != 200); - - user_data = NULL; - memset(&servaddr, 0, sizeof(servaddr)); - FAIL_IF(inet_pton(AF_INET6, "CABD::1", &servaddr.sin6_addr) <= 0); - node = SCRadixFindKeyIPV6BestMatch((uint8_t *)&servaddr.sin6_addr, tree, &user_data); - FAIL_IF_NULL(node); - FAIL_IF_NULL(user_data); - FAIL_IF(*((uint32_t *)user_data) != 100); - - SCRadixReleaseRadixTree(tree); - PASS; -} - -/** - * \test SCRadixTestIPV4NetblockInsertion15 insert a node searching on it. - * Should always return true but the purpose of the test is to monitor - * the memory usage to detect memleaks (there was one on searching) - */ -static int SCRadixTestIPV4NetblockInsertion25(void) -{ - SCRadixTree *tree = NULL; - struct sockaddr_in servaddr; - int result = 1; - - tree = SCRadixCreateRadixTree(free, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.168.0.0", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 16); - - /* test for the existence of a key */ - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.168.128.53", &servaddr.sin_addr) <= 0) - return 0; - - result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) != NULL); - - SCRadixReleaseRadixTree(tree); - - return result; -} - -/** - * \test SCRadixTestIPV4NetblockInsertion26 insert a node searching on it. - * Should always return true but the purpose of the test is to monitor - * the memory usage to detect memleaks (there was one on searching) - */ -static int SCRadixTestIPV4NetblockInsertion26(void) -{ - struct sockaddr_in servaddr; - - SCRadixTree *tree = SCRadixCreateRadixTree(free, NULL); - FAIL_IF_NULL(tree); - - memset(&servaddr, 0, sizeof(servaddr)); - FAIL_IF(inet_pton(AF_INET, "0.0.0.0", &servaddr.sin_addr) <= 0); - - char *str = SCStrdup("Hello1"); - FAIL_IF_NULL(str); - SCRadixNode *node = SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, str, 0); - FAIL_IF_NULL(node); - - str = SCStrdup("Hello1"); - FAIL_IF_NULL(str); - - memset(&servaddr, 0, sizeof(servaddr)); - FAIL_IF(inet_pton(AF_INET, "176.0.0.0", &servaddr.sin_addr) <= 0); - - node = SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, str, 5); - FAIL_IF_NULL(node); - - str = SCStrdup("Hello1"); - FAIL_IF_NULL(str); - - memset(&servaddr, 0, sizeof(servaddr)); - FAIL_IF(inet_pton(AF_INET, "0.0.0.0", &servaddr.sin_addr) <= 0); - - node = SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, str, 7); - FAIL_IF_NULL(node); - - /* test for the existence of a key */ - // result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree) != NULL); - - SCRadixReleaseRadixTree(tree); - - PASS; -} - -#endif - -void SCRadixRegisterTests(void) -{ - -#ifdef UNITTESTS - UtRegisterTest("SCRadixTestIPV4Insertion03", SCRadixTestIPV4Insertion03); - UtRegisterTest("SCRadixTestIPV4Removal04", SCRadixTestIPV4Removal04); - UtRegisterTest("SCRadixTestIPV6Insertion07", SCRadixTestIPV6Insertion07); - UtRegisterTest("SCRadixTestIPV6Removal08", SCRadixTestIPV6Removal08); - UtRegisterTest("SCRadixTestIPV4NetblockInsertion09", - SCRadixTestIPV4NetblockInsertion09); - UtRegisterTest("SCRadixTestIPV4Bug5066", SCRadixTestIPV4Bug5066); - UtRegisterTest("SCRadixTestIPV4Bug5066v2", SCRadixTestIPV4Bug5066v2); - UtRegisterTest("SCRadixTestIPV6Bug5066", SCRadixTestIPV6Bug5066); - UtRegisterTest("SCRadixTestIPV4NetblockInsertion10", - SCRadixTestIPV4NetblockInsertion10); - UtRegisterTest("SCRadixTestIPV4NetblockInsertion11", - SCRadixTestIPV4NetblockInsertion11); - UtRegisterTest("SCRadixTestIPV4NetblockInsertion12", - SCRadixTestIPV4NetblockInsertion12); - UtRegisterTest("SCRadixTestIPV6NetblockInsertion13", - SCRadixTestIPV6NetblockInsertion13); - UtRegisterTest("SCRadixTestIPV6NetblockInsertion14", - SCRadixTestIPV6NetblockInsertion14); - UtRegisterTest("SCRadixTestIPV4NetBlocksAndBestSearch15", - SCRadixTestIPV4NetBlocksAndBestSearch15); - UtRegisterTest("SCRadixTestIPV4NetBlocksAndBestSearch16", - SCRadixTestIPV4NetBlocksAndBestSearch16); - UtRegisterTest("SCRadixTestIPV4NetBlocksAndBestSearch17", - SCRadixTestIPV4NetBlocksAndBestSearch17); - UtRegisterTest("SCRadixTestIPV4NetBlocksAndBestSearch18", - SCRadixTestIPV4NetBlocksAndBestSearch18); - UtRegisterTest("SCRadixTestIPV4NetBlocksAndBestSearch19", - SCRadixTestIPV4NetBlocksAndBestSearch19); - UtRegisterTest("SCRadixTestIPV6NetBlocksAndBestSearch20", - SCRadixTestIPV6NetBlocksAndBestSearch20); - UtRegisterTest("SCRadixTestIPV6NetBlocksAndBestSearch21", - SCRadixTestIPV6NetBlocksAndBestSearch21); - UtRegisterTest("SCRadixTestIPV6NetBlocksAndBestSearch22", - SCRadixTestIPV6NetBlocksAndBestSearch22); - UtRegisterTest("SCRadixTestIPV6NetBlocksAndBestSearch23", - SCRadixTestIPV6NetBlocksAndBestSearch23); - UtRegisterTest("SCRadixTestIPV6NetBlocksAndBestSearch24", - SCRadixTestIPV6NetBlocksAndBestSearch24); - UtRegisterTest("SCRadixTestIPV4NetblockInsertion25", - SCRadixTestIPV4NetblockInsertion25); - UtRegisterTest("SCRadixTestIPV4NetblockInsertion26", - SCRadixTestIPV4NetblockInsertion26); -#endif -} diff --git a/src/util-radix-tree.h b/src/util-radix-tree.h deleted file mode 100644 index 4a6b8d7f6cbd..000000000000 --- a/src/util-radix-tree.h +++ /dev/null @@ -1,126 +0,0 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Anoop Saldanha - */ - -#ifndef SURICATA_UTIL_RADIX_TREE_H -#define SURICATA_UTIL_RADIX_TREE_H - -#define SC_RADIX_BITTEST(x, y) ((x) & (y)) - -/** - * \brief Structure that hold the user data and the netmask associated with it. - */ -typedef struct SCRadixUserData_ { - /* holds a pointer to the user data associated with the particular netmask */ - void *user; - /* pointer to the next user data in the list */ - struct SCRadixUserData_ *next; - /* holds the netmask value that corresponds to this user data pointer */ - uint8_t netmask; -} SCRadixUserData; - -/** - * \brief Structure for the prefix/key in the radix tree - */ -typedef struct SCRadixPrefix_ { - /* length of the stream */ - uint16_t bitlen; - - /* the key that has been stored in the tree */ - uint8_t *stream; - - /* any user data that has to be associated with this key. We need a user - * data field for each netblock value possible since one ip can be associated - * with any of the 32 or 128 netblocks. Also for non-ips, we store the - * netmask as 255 in SCRadixUserData->netmask */ - SCRadixUserData *user_data; -} SCRadixPrefix; - -/** - * \brief Structure for the node in the radix tree - */ -typedef struct SCRadixNode_ { - /* the bit position where the bits differ in the nodes children. Used - * to determine the path to be taken during a lookup*/ - uint16_t bit; - - uint16_t pad0; - - /* total no of netmasks that are registered under this node */ - uint16_t netmask_cnt; - /* holds a list of netmasks that come under this node in the tree */ - uint8_t *netmasks; - - /* holds the prefix that the path to this node holds */ - SCRadixPrefix *prefix; - - /* the left and the right children of a node */ - struct SCRadixNode_ *left, *right; - - /* the parent node for this tree */ - struct SCRadixNode_ *parent; -} SCRadixNode; - -/** - * \brief Structure for the radix tree - */ -typedef struct SCRadixTree_ { - /* the root node in the radix tree */ - SCRadixNode *head; - - /* function pointer that is supplied by the user to free the user data - * held by the user field of SCRadixNode */ - void (*PrintData)(void *); - void (*Free)(void *); -} SCRadixTree; - -SCRadixTree *SCRadixCreateRadixTree(void (*Free)(void*), void (*PrintData)(void*)); -void SCRadixReleaseRadixTree(SCRadixTree *); - -SCRadixNode *SCRadixAddKeyIPV4(uint8_t *, SCRadixTree *, void *); -SCRadixNode *SCRadixAddKeyIPV6(uint8_t *, SCRadixTree *, void *); -SCRadixNode *SCRadixAddKeyIPV4Netblock(uint8_t *, SCRadixTree *, void *, - uint8_t); -SCRadixNode *SCRadixAddKeyIPV6Netblock(uint8_t *, SCRadixTree *, void *, - uint8_t); -bool SCRadixAddKeyIPV4String(const char *, SCRadixTree *, void *); -bool SCRadixAddKeyIPV6String(const char *, SCRadixTree *, void *); - -void SCRadixRemoveKeyIPV4Netblock(uint8_t *, SCRadixTree *, uint8_t); -void SCRadixRemoveKeyIPV4(uint8_t *, SCRadixTree *); -void SCRadixRemoveKeyIPV6Netblock(uint8_t *, SCRadixTree *, uint8_t); -void SCRadixRemoveKeyIPV6(uint8_t *, SCRadixTree *); - -SCRadixNode *SCRadixFindKeyIPV4ExactMatch(uint8_t *, SCRadixTree *, void **); -SCRadixNode *SCRadixFindKeyIPV4Netblock(uint8_t *, SCRadixTree *, uint8_t, void **); -SCRadixNode *SCRadixFindKeyIPV4BestMatch(uint8_t *, SCRadixTree *, void **); - -SCRadixNode *SCRadixFindKeyIPV6ExactMatch(uint8_t *, SCRadixTree *, void **); -SCRadixNode *SCRadixFindKeyIPV6Netblock(uint8_t *, SCRadixTree *, uint8_t, void **); -SCRadixNode *SCRadixFindKeyIPV6BestMatch(uint8_t *, SCRadixTree *, void **); - -void SCRadixPrintTree(SCRadixTree *); -void SCRadixPrintNodeInfo(SCRadixNode *, int, void (*PrintData)(void*)); - -void SCRadixRegisterTests(void); - -#endif /* SURICATA_UTIL_RADIX_TREE_H */ From 4aeb606a9718d10ab581f502513c51254e1f044e Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 30 Oct 2024 08:52:08 +0100 Subject: [PATCH 10/14] detect/ip-only: remove dead code --- src/detect-engine-iponly.c | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/src/detect-engine-iponly.c b/src/detect-engine-iponly.c index 6143f83e5725..2143b333abb0 100644 --- a/src/detect-engine-iponly.c +++ b/src/detect-engine-iponly.c @@ -1220,7 +1220,6 @@ void IPOnlyPrepare(DetectEngineCtx *de_ctx) SCLogError("Error inserting in the" " src ipv4 radix tree ip %s netmask %" PRIu8, tmpstr, src->netmask); - //SCRadixPrintTree((de_ctx->io_ctx).tree_ipv4src); exit(-1); } } @@ -1493,20 +1492,6 @@ void IPOnlyPrepare(DetectEngineCtx *de_ctx) dst = dst->next; SCFree(tmpaux); } - - /* print all the trees: for debugging it might print too much info - SCLogDebug("Radix tree src ipv4:"); - SCRadixPrintTree((de_ctx->io_ctx).tree_ipv4src); - SCLogDebug("Radix tree src ipv6:"); - SCRadixPrintTree((de_ctx->io_ctx).tree_ipv6src); - SCLogDebug("__________________"); - - SCLogDebug("Radix tree dst ipv4:"); - SCRadixPrintTree((de_ctx->io_ctx).tree_ipv4dst); - SCLogDebug("Radix tree dst ipv6:"); - SCRadixPrintTree((de_ctx->io_ctx).tree_ipv6dst); - SCLogDebug("__________________"); - */ } /** From a8c63992fb987640828996ef9759687dd820aba8 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 30 Oct 2024 09:06:19 +0100 Subject: [PATCH 11/14] detect/sigorder: remove data structs from global namespace Rename types enum to reflect it is not using a radix tree anymore. --- src/detect-engine-sigorder.c | 70 ++++++++++++++++++++++++++---------- src/detect-engine-sigorder.h | 39 -------------------- src/detect.h | 3 +- 3 files changed, 52 insertions(+), 60 deletions(-) diff --git a/src/detect-engine-sigorder.c b/src/detect-engine-sigorder.c index 28bfd71569dc..4a4ad1de9cd0 100644 --- a/src/detect-engine-sigorder.c +++ b/src/detect-engine-sigorder.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2013 Open Information Security Foundation +/* Copyright (C) 2007-2024 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free @@ -66,6 +66,44 @@ #define DETECT_XBITS_TYPE_SET_READ 3 #define DETECT_XBITS_TYPE_SET 4 +/** + * \brief Different kinds of helper data that can be used by the signature + * ordering module. Used by the "user" field in SCSigSignatureWrapper + */ +typedef enum { + DETECT_SIGORDER_FLOWBITS, + DETECT_SIGORDER_FLOWVAR, + DETECT_SIGORDER_PKTVAR, + DETECT_SIGORDER_FLOWINT, + DETECT_SIGORDER_HOSTBITS, + DETECT_SIGORDER_IPPAIRBITS, + DETECT_SIGORDER_MAX +} DetectSigorderUserDataType; + +/** + * \brief Signature wrapper used by signature ordering module while ordering + * signatures + */ +typedef struct SCSigSignatureWrapper_ { + /* the wrapped signature */ + Signature *sig; + + /* user data that is to be associated with this sigwrapper */ + int user[DETECT_SIGORDER_MAX]; + + struct SCSigSignatureWrapper_ *next; +} SCSigSignatureWrapper; + +/** + * \brief Structure holding the signature ordering function used by the + * signature ordering module + */ +typedef struct SCSigOrderFunc_ { + /* Pointer to the Signature Ordering function */ + int (*SWCompare)(SCSigSignatureWrapper *sw1, SCSigSignatureWrapper *sw2); + + struct SCSigOrderFunc_ *next; +} SCSigOrderFunc; /** * \brief Registers a keyword-based, signature ordering function @@ -439,7 +477,7 @@ static inline int SCSigGetXbitsType(Signature *sig, enum VarTypes type) */ static inline void SCSigProcessUserDataForFlowbits(SCSigSignatureWrapper *sw) { - sw->user[SC_RADIX_USER_DATA_FLOWBITS] = SCSigGetFlowbitsType(sw->sig); + sw->user[DETECT_SIGORDER_FLOWBITS] = SCSigGetFlowbitsType(sw->sig); } /** @@ -451,12 +489,12 @@ static inline void SCSigProcessUserDataForFlowbits(SCSigSignatureWrapper *sw) */ static inline void SCSigProcessUserDataForFlowvar(SCSigSignatureWrapper *sw) { - sw->user[SC_RADIX_USER_DATA_FLOWVAR] = SCSigGetFlowvarType(sw->sig); + sw->user[DETECT_SIGORDER_FLOWVAR] = SCSigGetFlowvarType(sw->sig); } static inline void SCSigProcessUserDataForFlowint(SCSigSignatureWrapper *sw) { - sw->user[SC_RADIX_USER_DATA_FLOWINT] = SCSigGetFlowintType(sw->sig); + sw->user[DETECT_SIGORDER_FLOWINT] = SCSigGetFlowintType(sw->sig); } /** @@ -468,7 +506,7 @@ static inline void SCSigProcessUserDataForFlowint(SCSigSignatureWrapper *sw) */ static inline void SCSigProcessUserDataForPktvar(SCSigSignatureWrapper *sw) { - sw->user[SC_RADIX_USER_DATA_PKTVAR] = SCSigGetPktvarType(sw->sig); + sw->user[DETECT_SIGORDER_PKTVAR] = SCSigGetPktvarType(sw->sig); } /** @@ -480,7 +518,7 @@ static inline void SCSigProcessUserDataForPktvar(SCSigSignatureWrapper *sw) */ static inline void SCSigProcessUserDataForHostbits(SCSigSignatureWrapper *sw) { - sw->user[SC_RADIX_USER_DATA_HOSTBITS] = SCSigGetXbitsType(sw->sig, VAR_TYPE_HOST_BIT); + sw->user[DETECT_SIGORDER_HOSTBITS] = SCSigGetXbitsType(sw->sig, VAR_TYPE_HOST_BIT); } /** @@ -492,7 +530,7 @@ static inline void SCSigProcessUserDataForHostbits(SCSigSignatureWrapper *sw) */ static inline void SCSigProcessUserDataForIPPairbits(SCSigSignatureWrapper *sw) { - sw->user[SC_RADIX_USER_DATA_IPPAIRBITS] = SCSigGetXbitsType(sw->sig, VAR_TYPE_IPPAIR_BIT); + sw->user[DETECT_SIGORDER_IPPAIRBITS] = SCSigGetXbitsType(sw->sig, VAR_TYPE_IPPAIR_BIT); } /* Return 1 if sw1 comes before sw2 in the final list. */ @@ -609,8 +647,7 @@ static int SCSigOrderByActionCompare(SCSigSignatureWrapper *sw1, static int SCSigOrderByFlowbitsCompare(SCSigSignatureWrapper *sw1, SCSigSignatureWrapper *sw2) { - return sw1->user[SC_RADIX_USER_DATA_FLOWBITS] - - sw2->user[SC_RADIX_USER_DATA_FLOWBITS]; + return sw1->user[DETECT_SIGORDER_FLOWBITS] - sw2->user[DETECT_SIGORDER_FLOWBITS]; } /** @@ -623,8 +660,7 @@ static int SCSigOrderByFlowbitsCompare(SCSigSignatureWrapper *sw1, static int SCSigOrderByFlowvarCompare(SCSigSignatureWrapper *sw1, SCSigSignatureWrapper *sw2) { - return sw1->user[SC_RADIX_USER_DATA_FLOWVAR] - - sw2->user[SC_RADIX_USER_DATA_FLOWVAR]; + return sw1->user[DETECT_SIGORDER_FLOWVAR] - sw2->user[DETECT_SIGORDER_FLOWVAR]; } /** @@ -637,15 +673,13 @@ static int SCSigOrderByFlowvarCompare(SCSigSignatureWrapper *sw1, static int SCSigOrderByPktvarCompare(SCSigSignatureWrapper *sw1, SCSigSignatureWrapper *sw2) { - return sw1->user[SC_RADIX_USER_DATA_PKTVAR] - - sw2->user[SC_RADIX_USER_DATA_PKTVAR]; + return sw1->user[DETECT_SIGORDER_PKTVAR] - sw2->user[DETECT_SIGORDER_PKTVAR]; } static int SCSigOrderByFlowintCompare(SCSigSignatureWrapper *sw1, SCSigSignatureWrapper *sw2) { - return sw1->user[SC_RADIX_USER_DATA_FLOWINT] - - sw2->user[SC_RADIX_USER_DATA_FLOWINT]; + return sw1->user[DETECT_SIGORDER_FLOWINT] - sw2->user[DETECT_SIGORDER_FLOWINT]; } /** @@ -658,8 +692,7 @@ static int SCSigOrderByFlowintCompare(SCSigSignatureWrapper *sw1, static int SCSigOrderByHostbitsCompare(SCSigSignatureWrapper *sw1, SCSigSignatureWrapper *sw2) { - return sw1->user[SC_RADIX_USER_DATA_HOSTBITS] - - sw2->user[SC_RADIX_USER_DATA_HOSTBITS]; + return sw1->user[DETECT_SIGORDER_HOSTBITS] - sw2->user[DETECT_SIGORDER_HOSTBITS]; } /** @@ -672,8 +705,7 @@ static int SCSigOrderByHostbitsCompare(SCSigSignatureWrapper *sw1, static int SCSigOrderByIPPairbitsCompare(SCSigSignatureWrapper *sw1, SCSigSignatureWrapper *sw2) { - return sw1->user[SC_RADIX_USER_DATA_IPPAIRBITS] - - sw2->user[SC_RADIX_USER_DATA_IPPAIRBITS]; + return sw1->user[DETECT_SIGORDER_IPPAIRBITS] - sw2->user[DETECT_SIGORDER_IPPAIRBITS]; } /** diff --git a/src/detect-engine-sigorder.h b/src/detect-engine-sigorder.h index d45a4e443ff9..d859846c629e 100644 --- a/src/detect-engine-sigorder.h +++ b/src/detect-engine-sigorder.h @@ -24,45 +24,6 @@ #ifndef SURICATA_DETECT_ENGINE_SIGORDER_H #define SURICATA_DETECT_ENGINE_SIGORDER_H -/** - * \brief Different kinds of helper data that can be used by the signature - * ordering module. Used by the "user" field in SCSigSignatureWrapper - */ -typedef enum{ - SC_RADIX_USER_DATA_FLOWBITS, - SC_RADIX_USER_DATA_FLOWVAR, - SC_RADIX_USER_DATA_PKTVAR, - SC_RADIX_USER_DATA_FLOWINT, - SC_RADIX_USER_DATA_HOSTBITS, - SC_RADIX_USER_DATA_IPPAIRBITS, - SC_RADIX_USER_DATA_MAX -} SCRadixUserDataType; - -/** - * \brief Signature wrapper used by signature ordering module while ordering - * signatures - */ -typedef struct SCSigSignatureWrapper_ { - /* the wrapped signature */ - Signature *sig; - - /* user data that is to be associated with this sigwrapper */ - int user[SC_RADIX_USER_DATA_MAX]; - - struct SCSigSignatureWrapper_ *next; -} SCSigSignatureWrapper; - -/** - * \brief Structure holding the signature ordering function used by the - * signature ordering module - */ -typedef struct SCSigOrderFunc_ { - /* Pointer to the Signature Ordering function */ - int (*SWCompare)(SCSigSignatureWrapper *sw1, SCSigSignatureWrapper *sw2); - - struct SCSigOrderFunc_ *next; -} SCSigOrderFunc; - void SCSigOrderSignatures(DetectEngineCtx *); void SCSigRegisterSignatureOrderingFuncs(DetectEngineCtx *); void SCSigRegisterSignatureOrderingTests(void); diff --git a/src/detect.h b/src/detect.h index d71764fa7d08..4c22f509a3f3 100644 --- a/src/detect.h +++ b/src/detect.h @@ -53,9 +53,8 @@ // tx_id value to use when there is no transaction #define PACKET_ALERT_NOTX UINT64_MAX -/* forward declarations for the structures from detect-engine-sigorder.h */ +/* forward declaration for sigorder logic in detect-engine-sigorder.[ch] */ struct SCSigOrderFunc_; -struct SCSigSignatureWrapper_; /* Forward declarations for structures from Rust. */ typedef struct SCDetectRequiresStatus SCDetectRequiresStatus; From 13f420c7934ac90ceb2eb7f01757c07304e765fa Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 30 Oct 2024 10:50:52 +0100 Subject: [PATCH 12/14] detect/ip-only: code cleanups Move repeated pattern into helper function. --- src/detect-engine-iponly.c | 157 ++++++++----------------------------- 1 file changed, 31 insertions(+), 126 deletions(-) diff --git a/src/detect-engine-iponly.c b/src/detect-engine-iponly.c index 2143b333abb0..fb333f0eda3d 100644 --- a/src/detect-engine-iponly.c +++ b/src/detect-engine-iponly.c @@ -1116,6 +1116,17 @@ void IPOnlyMatchPacket(ThreadVars *tv, const DetectEngineCtx *de_ctx, SCReturn; } +static void IPOnlyPrepareUpdateBitarray(const IPOnlyCIDRItem *src, SigNumArray *sna) +{ + uint8_t tmp = (uint8_t)(1 << (src->signum % 8)); + if (src->negated > 0) + /* Unset it */ + sna->array[src->signum / 8] &= ~tmp; + else + /* Set it */ + sna->array[src->signum / 8] |= tmp; +} + /** * \brief Build the radix trees from the lists of parsed addresses in CIDR format * the result should be 4 radix trees: src/dst ipv4 and src/dst ipv6 @@ -1133,15 +1144,14 @@ void IPOnlyPrepare(DetectEngineCtx *de_ctx) IPOnlyCIDRListPrint((de_ctx->io_ctx).ip_dst); */ - IPOnlyCIDRListQSort(&(de_ctx->io_ctx).ip_src); - IPOnlyCIDRListQSort(&(de_ctx->io_ctx).ip_dst); + IPOnlyCIDRListQSort(&de_ctx->io_ctx.ip_src); + IPOnlyCIDRListQSort(&de_ctx->io_ctx.ip_dst); - IPOnlyCIDRItem *src, *dst; SCRadix4Node *node4 = NULL; SCRadix6Node *node6 = NULL; /* Prepare Src radix trees */ - for (src = (de_ctx->io_ctx).ip_src; src != NULL; ) { + for (IPOnlyCIDRItem *src = de_ctx->io_ctx.ip_src; src != NULL;) { if (src->family == AF_INET) { /* SCLogDebug("To IPv4"); @@ -1171,16 +1181,7 @@ void IPOnlyPrepare(DetectEngineCtx *de_ctx) /* Not found, insert a new one */ SigNumArray *sna = SigNumArrayNew(de_ctx, &de_ctx->io_ctx); - - /* Update the sig */ - uint8_t tmp = (uint8_t)(1 << (src->signum % 8)); - - if (src->negated > 0) - /* Unset it */ - sna->array[src->signum / 8] &= ~tmp; - else - /* Set it */ - sna->array[src->signum / 8] |= tmp; + IPOnlyPrepareUpdateBitarray(src, sna); if (src->netmask == 32) node4 = SCRadix4AddKeyIPV4(&de_ctx->io_ctx.tree_ipv4src, @@ -1195,18 +1196,8 @@ void IPOnlyPrepare(DetectEngineCtx *de_ctx) SCLogDebug("Best match found"); /* Found, copy the sig num table, add this signum and insert */ - SigNumArray *sna = NULL; - sna = SigNumArrayCopy((SigNumArray *) user_data); - - /* Update the sig */ - uint8_t tmp = (uint8_t)(1 << (src->signum % 8)); - - if (src->negated > 0) - /* Unset it */ - sna->array[src->signum / 8] &= ~tmp; - else - /* Set it */ - sna->array[src->signum / 8] |= tmp; + SigNumArray *sna = SigNumArrayCopy((SigNumArray *)user_data); + IPOnlyPrepareUpdateBitarray(src, sna); if (src->netmask == 32) node4 = SCRadix4AddKeyIPV4(&de_ctx->io_ctx.tree_ipv4src, @@ -1228,16 +1219,7 @@ void IPOnlyPrepare(DetectEngineCtx *de_ctx) /* it's already inserted. Update it */ SigNumArray *sna = (SigNumArray *)user_data; - - /* Update the sig */ - uint8_t tmp = (uint8_t)(1 << (src->signum % 8)); - - if (src->negated > 0) - /* Unset it */ - sna->array[src->signum / 8] &= ~tmp; - else - /* Set it */ - sna->array[src->signum / 8] |= tmp; + IPOnlyPrepareUpdateBitarray(src, sna); } } else if (src->family == AF_INET6) { SCLogDebug("To IPv6"); @@ -1256,16 +1238,7 @@ void IPOnlyPrepare(DetectEngineCtx *de_ctx) if (user_data == NULL) { /* Not found, insert a new one */ SigNumArray *sna = SigNumArrayNew(de_ctx, &de_ctx->io_ctx); - - /* Update the sig */ - uint8_t tmp = (uint8_t)(1 << (src->signum % 8)); - - if (src->negated > 0) - /* Unset it */ - sna->array[src->signum / 8] &= ~tmp; - else - /* Set it */ - sna->array[src->signum / 8] |= tmp; + IPOnlyPrepareUpdateBitarray(src, sna); if (src->netmask == 128) node6 = SCRadix6AddKeyIPV6(&de_ctx->io_ctx.tree_ipv6src, @@ -1278,17 +1251,8 @@ void IPOnlyPrepare(DetectEngineCtx *de_ctx) "ipv6 radix tree"); } else { /* Found, copy the sig num table, add this signum and insert */ - SigNumArray *sna = NULL; - sna = SigNumArrayCopy((SigNumArray *)user_data); - - /* Update the sig */ - uint8_t tmp = (uint8_t)(1 << (src->signum % 8)); - if (src->negated > 0) - /* Unset it */ - sna->array[src->signum / 8] &= ~tmp; - else - /* Set it */ - sna->array[src->signum / 8] |= tmp; + SigNumArray *sna = SigNumArrayCopy((SigNumArray *)user_data); + IPOnlyPrepareUpdateBitarray(src, sna); if (src->netmask == 128) node6 = SCRadix6AddKeyIPV6(&de_ctx->io_ctx.tree_ipv6src, @@ -1303,15 +1267,7 @@ void IPOnlyPrepare(DetectEngineCtx *de_ctx) } else { /* it's already inserted. Update it */ SigNumArray *sna = (SigNumArray *)user_data; - - /* Update the sig */ - uint8_t tmp = (uint8_t)(1 << (src->signum % 8)); - if (src->negated > 0) - /* Unset it */ - sna->array[src->signum / 8] &= ~tmp; - else - /* Set it */ - sna->array[src->signum / 8] |= tmp; + IPOnlyPrepareUpdateBitarray(src, sna); } } IPOnlyCIDRItem *tmpaux = src; @@ -1322,9 +1278,8 @@ void IPOnlyPrepare(DetectEngineCtx *de_ctx) SCLogDebug("dsts:"); /* Prepare Dst radix trees */ - for (dst = (de_ctx->io_ctx).ip_dst; dst != NULL; ) { + for (IPOnlyCIDRItem *dst = de_ctx->io_ctx.ip_dst; dst != NULL;) { if (dst->family == AF_INET) { - SCLogDebug("To IPv4"); SCLogDebug("Item has netmask %"PRIu8" negated: %s; IP: %s; signum:" " %"PRIu32"", dst->netmask, (dst->negated)?"yes":"no", @@ -1351,15 +1306,7 @@ void IPOnlyPrepare(DetectEngineCtx *de_ctx) /** Not found, insert a new one */ SigNumArray *sna = SigNumArrayNew(de_ctx, &de_ctx->io_ctx); - - /** Update the sig */ - uint8_t tmp = (uint8_t)(1 << (dst->signum % 8)); - if (dst->negated > 0) - /** Unset it */ - sna->array[dst->signum / 8] &= ~tmp; - else - /** Set it */ - sna->array[dst->signum / 8] |= tmp; + IPOnlyPrepareUpdateBitarray(dst, sna); if (dst->netmask == 32) node4 = SCRadix4AddKeyIPV4(&de_ctx->io_ctx.tree_ipv4dst, @@ -1374,17 +1321,8 @@ void IPOnlyPrepare(DetectEngineCtx *de_ctx) SCLogDebug("Best match found"); /* Found, copy the sig num table, add this signum and insert */ - SigNumArray *sna = NULL; - sna = SigNumArrayCopy((SigNumArray *) user_data); - - /* Update the sig */ - uint8_t tmp = (uint8_t)(1 << (dst->signum % 8)); - if (dst->negated > 0) - /* Unset it */ - sna->array[dst->signum / 8] &= ~tmp; - else - /* Set it */ - sna->array[dst->signum / 8] |= tmp; + SigNumArray *sna = SigNumArrayCopy((SigNumArray *)user_data); + IPOnlyPrepareUpdateBitarray(dst, sna); if (dst->netmask == 32) node4 = SCRadix4AddKeyIPV4(&de_ctx->io_ctx.tree_ipv4dst, @@ -1402,15 +1340,7 @@ void IPOnlyPrepare(DetectEngineCtx *de_ctx) /* it's already inserted. Update it */ SigNumArray *sna = (SigNumArray *)user_data; - - /* Update the sig */ - uint8_t tmp = (uint8_t)(1 << (dst->signum % 8)); - if (dst->negated > 0) - /* Unset it */ - sna->array[dst->signum / 8] &= ~tmp; - else - /* Set it */ - sna->array[dst->signum / 8] |= tmp; + IPOnlyPrepareUpdateBitarray(dst, sna); } } else if (dst->family == AF_INET6) { SCLogDebug("To IPv6"); @@ -1431,15 +1361,7 @@ void IPOnlyPrepare(DetectEngineCtx *de_ctx) if (user_data == NULL) { /* Not found, insert a new one */ SigNumArray *sna = SigNumArrayNew(de_ctx, &de_ctx->io_ctx); - - /* Update the sig */ - uint8_t tmp = (uint8_t)(1 << (dst->signum % 8)); - if (dst->negated > 0) - /* Unset it */ - sna->array[dst->signum / 8] &= ~tmp; - else - /* Set it */ - sna->array[dst->signum / 8] |= tmp; + IPOnlyPrepareUpdateBitarray(dst, sna); if (dst->netmask == 128) node6 = SCRadix6AddKeyIPV6(&de_ctx->io_ctx.tree_ipv6dst, @@ -1452,17 +1374,8 @@ void IPOnlyPrepare(DetectEngineCtx *de_ctx) "ipv6 radix tree"); } else { /* Found, copy the sig num table, add this signum and insert */ - SigNumArray *sna = NULL; - sna = SigNumArrayCopy((SigNumArray *)user_data); - - /* Update the sig */ - uint8_t tmp = (uint8_t)(1 << (dst->signum % 8)); - if (dst->negated > 0) - /* Unset it */ - sna->array[dst->signum / 8] &= ~tmp; - else - /* Set it */ - sna->array[dst->signum / 8] |= tmp; + SigNumArray *sna = SigNumArrayCopy((SigNumArray *)user_data); + IPOnlyPrepareUpdateBitarray(dst, sna); if (dst->netmask == 128) node6 = SCRadix6AddKeyIPV6(&de_ctx->io_ctx.tree_ipv6dst, @@ -1477,15 +1390,7 @@ void IPOnlyPrepare(DetectEngineCtx *de_ctx) } else { /* it's already inserted. Update it */ SigNumArray *sna = (SigNumArray *)user_data; - - /* Update the sig */ - uint8_t tmp = (uint8_t)(1 << (dst->signum % 8)); - if (dst->negated > 0) - /* Unset it */ - sna->array[dst->signum / 8] &= ~tmp; - else - /* Set it */ - sna->array[dst->signum / 8] |= tmp; + IPOnlyPrepareUpdateBitarray(dst, sna); } } IPOnlyCIDRItem *tmpaux = dst; From 7682816ef92fc7c158ca7c76b0666013fb52031a Mon Sep 17 00:00:00 2001 From: Philippe Antoine Date: Tue, 8 Oct 2024 16:32:18 +0200 Subject: [PATCH 13/14] http1/detect: code simplification - DetectEngineInspectBufferHttpHeader is only used with ALPROTO_HTTP1 - engine->progress should be HTP_REQUEST_HEADERS or HTP_RESPONSE_HEADERS based on the direction --- src/detect-http-header.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/detect-http-header.c b/src/detect-http-header.c index 8839544a5f92..0a1a8ecadeed 100644 --- a/src/detect-http-header.c +++ b/src/detect-http-header.c @@ -176,6 +176,8 @@ static uint8_t DetectEngineInspectBufferHttpHeader(DetectEngineCtx *de_ctx, const int list_id = engine->sm_list; InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); + bool eof = + (AppLayerParserGetStateProgress(f->proto, f->alproto, txv, flags) > engine->progress); if (buffer->inspect == NULL) { SCLogDebug("setting up inspect buffer %d", list_id); @@ -209,14 +211,8 @@ static uint8_t DetectEngineInspectBufferHttpHeader(DetectEngineCtx *de_ctx, return DETECT_ENGINE_INSPECT_SIG_MATCH; } end: - if (flags & STREAM_TOSERVER) { - if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP1, txv, flags) > - HTP_REQUEST_HEADERS) - return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; - } else { - if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP1, txv, flags) > - HTP_RESPONSE_HEADERS) - return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; + if (eof) { + return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; } return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; } From 4ec90bd2276afab1c3c3eea82a1fd1216ee0961c Mon Sep 17 00:00:00 2001 From: Philippe Antoine Date: Thu, 30 Nov 2023 14:47:14 +0100 Subject: [PATCH 14/14] detect: absent keyword to test absence of sticky buffer Ticket: 2224 It takes an argument to match only if the buffer is absent, or it can still match if the buffer is present, but we test the absence of some content. For multi buffers, absent matches if there are 0 buffers. For file keywords, absent matches if there is no file. --- doc/userguide/rules/payload-keywords.rst | 21 ++++ src/detect-engine-analyzer.c | 9 ++ src/detect-engine-content-inspection.c | 28 ++++- src/detect-engine-content-inspection.h | 6 + src/detect-engine-mpm.c | 3 + src/detect-engine-register.h | 1 + src/detect-engine.c | 12 ++ src/detect-file-data.c | 8 ++ src/detect-filemagic.c | 10 +- src/detect-filename.c | 10 +- src/detect-http-client-body.c | 3 + src/detect-http-header.c | 3 + src/detect-isdataat.c | 136 +++++++++++++++++++++++ src/detect-isdataat.h | 7 ++ src/detect-parse.c | 4 + src/detect.h | 2 + 16 files changed, 259 insertions(+), 4 deletions(-) diff --git a/doc/userguide/rules/payload-keywords.rst b/doc/userguide/rules/payload-keywords.rst index 2e92b7046269..780ad111f7dc 100644 --- a/doc/userguide/rules/payload-keywords.rst +++ b/doc/userguide/rules/payload-keywords.rst @@ -274,6 +274,27 @@ You can also use the negation (!) before isdataat. .. image:: payload-keywords/isdataat1.png +absent +------ + +The keyword ``absent`` checks that a sticky buffer does not exist. +It can be used without any argument to match only on absent buffer : + +Example of ``absent`` in a rule: + +.. container:: example-rule + + alert http any any -> any any (msg:"HTTP request without referer"; :example-rule-emphasis:`http.referer; absent;` sid:1; rev:1;) + + +It can take an argument "or_else" to match on absent buffer or on what comes next such as negated content, for instance : + +.. container:: example-rule + + alert http any any -> any any (msg:"HTTP request without referer"; :example-rule-emphasis:`http.referer; absent: or_else;` content: !"abc"; sid:1; rev:1;) + +For files (ie ``file.data``), absent means there are no files in the transaction. + bsize ----- diff --git a/src/detect-engine-analyzer.c b/src/detect-engine-analyzer.c index d852792fd3da..dae6f9f2f270 100644 --- a/src/detect-engine-analyzer.c +++ b/src/detect-engine-analyzer.c @@ -39,6 +39,7 @@ #include "detect-pcre.h" #include "detect-bytejump.h" #include "detect-bytetest.h" +#include "detect-isdataat.h" #include "detect-flow.h" #include "detect-tcp-flags.h" #include "detect-tcp-ack.h" @@ -855,6 +856,14 @@ static void DumpMatches(RuleAnalyzer *ctx, JsonBuilder *js, const SigMatchData * jb_close(js); break; } + case DETECT_ABSENT: { + const DetectAbsentData *dad = (const DetectAbsentData *)smd->ctx; + jb_open_object(js, "absent"); + jb_set_bool(js, "or_else", dad->or_else); + jb_close(js); + break; + } + case DETECT_IPOPTS: { const DetectIpOptsData *cd = (const DetectIpOptsData *)smd->ctx; diff --git a/src/detect-engine-content-inspection.c b/src/detect-engine-content-inspection.c index d4dab42816d5..e43e693b2151 100644 --- a/src/detect-engine-content-inspection.c +++ b/src/detect-engine-content-inspection.c @@ -382,6 +382,13 @@ static int DetectEngineContentInspectionInternal(DetectEngineThreadCtx *det_ctx, prev_offset); } while(1); + } else if (smd->type == DETECT_ABSENT) { + const DetectAbsentData *id = (DetectAbsentData *)smd->ctx; + if (!id->or_else) { + // we match only on absent buffer + goto no_match; + } + goto match; } else if (smd->type == DETECT_ISDATAAT) { SCLogDebug("inspecting isdataat"); @@ -646,8 +653,7 @@ static int DetectEngineContentInspectionInternal(DetectEngineThreadCtx *det_ctx, goto match; } goto no_match_discontinue; - } - else if (smd->type == DETECT_LUA) { + } else if (smd->type == DETECT_LUA) { SCLogDebug("lua starting"); if (DetectLuaMatchBuffer(det_ctx, s, smd, buffer, buffer_len, @@ -758,6 +764,24 @@ bool DetectEngineContentInspectionBuffer(DetectEngineCtx *de_ctx, DetectEngineTh return false; } +bool DetectContentInspectionMatchOnAbsentBuffer(const SigMatchData *smd) +{ + // we will match on NULL buffers there is one absent + bool absent_data = false; + while (1) { + if (smd->type == DETECT_ABSENT) { + absent_data = true; + break; + } + if (smd->is_last) { + break; + } + // smd does not get reused after this loop + smd++; + } + return absent_data; +} + #ifdef UNITTESTS #include "tests/detect-engine-content-inspection.c" #endif diff --git a/src/detect-engine-content-inspection.h b/src/detect-engine-content-inspection.h index 2c253b77ad3d..fe53086badd9 100644 --- a/src/detect-engine-content-inspection.h +++ b/src/detect-engine-content-inspection.h @@ -68,6 +68,12 @@ bool DetectEngineContentInspectionBuffer(DetectEngineCtx *de_ctx, DetectEngineTh const Signature *s, const SigMatchData *smd, Packet *p, Flow *f, const InspectionBuffer *b, const enum DetectContentInspectionType inspection_mode); +/** \brief tells if we should match on absent buffer, because + * there is an absent keyword being used + * \param smd array of content inspection matches + * \retval bool true to match on absent buffer, false otherwise */ +bool DetectContentInspectionMatchOnAbsentBuffer(const SigMatchData *smd); + void DetectEngineContentInspectionRegisterTests(void); #endif /* SURICATA_DETECT_ENGINE_CONTENT_INSPECTION_H */ diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index 5e8687e34686..1c9984ea9541 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -1125,6 +1125,9 @@ void RetrieveFPForSig(const DetectEngineCtx *de_ctx, Signature *s) } for (SigMatch *sm = s->init_data->buffers[x].head; sm != NULL; sm = sm->next) { + // a buffer with absent keyword cannot be used as fast_pattern + if (sm->type == DETECT_ABSENT) + break; if (sm->type != DETECT_CONTENT) continue; diff --git a/src/detect-engine-register.h b/src/detect-engine-register.h index db4cd957af9d..e5f550be7547 100644 --- a/src/detect-engine-register.h +++ b/src/detect-engine-register.h @@ -93,6 +93,7 @@ enum DetectKeywordId { DETECT_LUA, DETECT_ISDATAAT, DETECT_AL_URILEN, + DETECT_ABSENT, /* end of content inspection */ DETECT_METADATA, diff --git a/src/detect-engine.c b/src/detect-engine.c index 77c25a1cf3a9..f4195739e2c1 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -666,6 +666,7 @@ static void AppendAppInspectEngine(DetectEngineCtx *de_ctx, new_engine->sm_list = t->sm_list; new_engine->sm_list_base = t->sm_list_base; new_engine->smd = smd; + new_engine->match_on_null = DetectContentInspectionMatchOnAbsentBuffer(smd); new_engine->progress = t->progress; new_engine->v2 = t->v2; SCLogDebug("sm_list %d new_engine->v2 %p/%p/%p", new_engine->sm_list, new_engine->v2.Callback, @@ -2172,6 +2173,9 @@ uint8_t DetectEngineInspectBufferGeneric(DetectEngineCtx *de_ctx, DetectEngineTh const InspectionBuffer *buffer = engine->v2.GetData(det_ctx, transforms, f, flags, txv, list_id); if (unlikely(buffer == NULL)) { + if (eof && engine->match_on_null) { + return DETECT_ENGINE_INSPECT_SIG_MATCH; + } return eof ? DETECT_ENGINE_INSPECT_SIG_CANT_MATCH : DETECT_ENGINE_INSPECT_SIG_NO_MATCH; } @@ -2233,6 +2237,14 @@ uint8_t DetectEngineInspectMultiBufferGeneric(DetectEngineCtx *de_ctx, } local_id++; } while (1); + if (local_id == 0) { + // That means we did not get even one buffer value from the multi-buffer + const bool eof = (AppLayerParserGetStateProgress(f->proto, f->alproto, txv, flags) > + engine->progress); + if (eof && engine->match_on_null) { + return DETECT_ENGINE_INSPECT_SIG_MATCH; + } + } return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; } diff --git a/src/detect-file-data.c b/src/detect-file-data.c index a721c08c7cf9..d976b51c00b4 100644 --- a/src/detect-file-data.c +++ b/src/detect-file-data.c @@ -403,6 +403,14 @@ uint8_t DetectEngineInspectFiledata(DetectEngineCtx *de_ctx, DetectEngineThreadC if (ffc == NULL) { return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH_FILES; } + if (ffc->head == NULL) { + const bool eof = (AppLayerParserGetStateProgress(f->proto, f->alproto, txv, flags) > + engine->progress); + if (eof && engine->match_on_null) { + return DETECT_ENGINE_INSPECT_SIG_MATCH; + } + return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; + } int local_file_id = 0; File *file = ffc->head; diff --git a/src/detect-filemagic.c b/src/detect-filemagic.c index f23434d8666e..0f8d94a7b5b1 100644 --- a/src/detect-filemagic.c +++ b/src/detect-filemagic.c @@ -307,7 +307,15 @@ static uint8_t DetectEngineInspectFilemagic(DetectEngineCtx *de_ctx, DetectEngin AppLayerGetFileState files = AppLayerParserGetTxFiles(f, txv, flags); FileContainer *ffc = files.fc; - if (ffc == NULL) { + if (ffc == NULL || ffc->head == NULL) { + const bool eof = (AppLayerParserGetStateProgress(f->proto, f->alproto, txv, flags) > + engine->progress); + if (eof && engine->match_on_null) { + return DETECT_ENGINE_INSPECT_SIG_MATCH; + } + if (ffc != NULL) { + return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; + } return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH_FILES; } diff --git a/src/detect-filename.c b/src/detect-filename.c index f75fdbd680fe..ef144cf44086 100644 --- a/src/detect-filename.c +++ b/src/detect-filename.c @@ -244,7 +244,15 @@ static uint8_t DetectEngineInspectFilename(DetectEngineCtx *de_ctx, DetectEngine AppLayerGetFileState files = AppLayerParserGetTxFiles(f, txv, flags); FileContainer *ffc = files.fc; - if (ffc == NULL) { + if (ffc == NULL || ffc->head == NULL) { + const bool eof = (AppLayerParserGetStateProgress(f->proto, f->alproto, txv, flags) > + engine->progress); + if (eof && engine->match_on_null) { + return DETECT_ENGINE_INSPECT_SIG_MATCH; + } + if (ffc != NULL) { + return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; + } return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH_FILES; } diff --git a/src/detect-http-client-body.c b/src/detect-http-client-body.c index 5e5604ea594d..7747b61b858b 100644 --- a/src/detect-http-client-body.c +++ b/src/detect-http-client-body.c @@ -312,6 +312,9 @@ static uint8_t DetectEngineInspectBufferHttpBody(DetectEngineCtx *de_ctx, const InspectionBuffer *buffer = HttpRequestBodyGetDataCallback( det_ctx, engine->v2.transforms, f, flags, txv, engine->sm_list, engine->sm_list_base); if (buffer == NULL || buffer->inspect == NULL) { + if (eof && engine->match_on_null) { + return DETECT_ENGINE_INSPECT_SIG_MATCH; + } return eof ? DETECT_ENGINE_INSPECT_SIG_CANT_MATCH : DETECT_ENGINE_INSPECT_SIG_NO_MATCH; } diff --git a/src/detect-http-header.c b/src/detect-http-header.c index 0a1a8ecadeed..22a487583ae7 100644 --- a/src/detect-http-header.c +++ b/src/detect-http-header.c @@ -191,6 +191,9 @@ static uint8_t DetectEngineInspectBufferHttpHeader(DetectEngineCtx *de_ctx, uint8_t *rawdata = GetBufferForTX(txv, det_ctx, f, flags, &rawdata_len); if (rawdata_len == 0) { SCLogDebug("no data"); + if (engine->match_on_null && eof) { + return DETECT_ENGINE_INSPECT_SIG_MATCH; + } goto end; } /* setup buffer and apply transforms */ diff --git a/src/detect-isdataat.c b/src/detect-isdataat.c index 7b4d629ad3a1..6bc4e961c07a 100644 --- a/src/detect-isdataat.c +++ b/src/detect-isdataat.c @@ -35,6 +35,7 @@ #include "detect-isdataat.h" #include "detect-content.h" +#include "detect-bytetest.h" #include "detect-uricontent.h" #include "detect-engine-build.h" @@ -56,11 +57,99 @@ static DetectParseRegex parse_regex; int DetectIsdataatSetup (DetectEngineCtx *, Signature *, const char *); #ifdef UNITTESTS static void DetectIsdataatRegisterTests(void); +static void DetectAbsentRegisterTests(void); #endif void DetectIsdataatFree(DetectEngineCtx *, void *); static int DetectEndsWithSetup (DetectEngineCtx *de_ctx, Signature *s, const char *nullstr); +static void DetectAbsentFree(DetectEngineCtx *de_ctx, void *ptr) +{ + SCFree(ptr); +} + +static int DetectAbsentSetup(DetectEngineCtx *de_ctx, Signature *s, const char *optstr) +{ + if (s->init_data->list == DETECT_SM_LIST_NOTSET) { + SCLogError("no buffer for absent keyword"); + return -1; + } + + if (DetectBufferGetActiveList(de_ctx, s) == -1) + return -1; + + bool or_else; + if (optstr == NULL) { + or_else = false; + } else if (strcmp(optstr, "or_else") == 0) { + or_else = true; + } else { + SCLogError("unhandled value for absent keyword: %s", optstr); + return -1; + } + if (s->init_data->curbuf == NULL || s->init_data->list != (int)s->init_data->curbuf->id) { + SCLogError("unspected buffer for absent keyword"); + return -1; + } + const DetectBufferType *b = DetectEngineBufferTypeGetById(de_ctx, s->init_data->list); + if (!b || b->frame) { + SCLogError("absent does not work with frames"); + return -1; + } + if (s->init_data->curbuf->tail != NULL) { + SCLogError("absent must come first right after buffer"); + return -1; + } + DetectAbsentData *dad = SCMalloc(sizeof(DetectAbsentData)); + if (unlikely(dad == NULL)) + return -1; + + dad->or_else = or_else; + + if (SigMatchAppendSMToList(de_ctx, s, DETECT_ABSENT, (SigMatchCtx *)dad, s->init_data->list) == + NULL) { + DetectAbsentFree(de_ctx, dad); + return -1; + } + return 0; +} + +bool DetectAbsentValidateContentCallback(Signature *s, const SignatureInitDataBuffer *b) +{ + bool has_other = false; + bool only_absent = false; + bool has_absent = false; + for (const SigMatch *sm = b->head; sm != NULL; sm = sm->next) { + if (sm->type == DETECT_ABSENT) { + has_absent = true; + const DetectAbsentData *dad = (const DetectAbsentData *)sm->ctx; + if (!dad->or_else) { + only_absent = true; + } + } else { + has_other = true; + if (sm->type == DETECT_CONTENT) { + const DetectContentData *cd = (DetectContentData *)sm->ctx; + if (has_absent && (cd->flags & DETECT_CONTENT_FAST_PATTERN)) { + SCLogError("signature can't have absent and fast_pattern on the same buffer"); + return false; + } + } + } + } + + if (only_absent && has_other) { + SCLogError("signature can't have a buffer tested absent and tested with other keywords " + "such as content"); + return false; + } else if (has_absent && !only_absent && !has_other) { + SCLogError( + "signature with absent: or_else expects other keywords to test on such as content"); + return false; + } + return true; +} + /** * \brief Registration function for isdataat: keyword */ @@ -82,6 +171,16 @@ void DetectIsdataatRegister(void) sigmatch_table[DETECT_ENDS_WITH].Setup = DetectEndsWithSetup; sigmatch_table[DETECT_ENDS_WITH].flags = SIGMATCH_NOOPT; + sigmatch_table[DETECT_ABSENT].name = "absent"; + sigmatch_table[DETECT_ABSENT].desc = "test if the buffer is absent"; + sigmatch_table[DETECT_ABSENT].url = "/rules/payload-keywords.html#absent"; + sigmatch_table[DETECT_ABSENT].Setup = DetectAbsentSetup; + sigmatch_table[DETECT_ABSENT].Free = DetectAbsentFree; + sigmatch_table[DETECT_ABSENT].flags = SIGMATCH_OPTIONAL_OPT; +#ifdef UNITTESTS + sigmatch_table[DETECT_ABSENT].RegisterTests = DetectAbsentRegisterTests; +#endif + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex); } @@ -584,4 +683,41 @@ void DetectIsdataatRegisterTests(void) UtRegisterTest("DetectIsdataatTestPacket02", DetectIsdataatTestPacket02); UtRegisterTest("DetectIsdataatTestPacket03", DetectIsdataatTestPacket03); } + +static int DetectAbsentTestParse01(void) +{ + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF(de_ctx == NULL); + de_ctx->flags |= DE_QUIET; + + Signature *s = DetectEngineAppendSig(de_ctx, + "alert http any any -> any any " + "(msg:\"invalid absent only with negated content\"; http.user_agent; " + "absent; content:!\"one\"; sid:2;)"); + FAIL_IF(s != NULL); + s = DetectEngineAppendSig(de_ctx, "alert http any any -> any any " + "(msg:\"invalid absent\"; http.user_agent; " + "content:!\"one\"; absent; sid:2;)"); + FAIL_IF(s != NULL); + s = DetectEngineAppendSig(de_ctx, "alert http any any -> any any " + "(msg:\"invalid absent\"; http.user_agent; " + "content:\"one\"; absent: or_else; sid:2;)"); + FAIL_IF(s != NULL); + s = DetectEngineAppendSig(de_ctx, "alert http any any -> any any " + "(msg:\"absent without sticky buffer\"; " + "content:!\"one\"; absent: or_else; sid:2;)"); + FAIL_IF(s != NULL); + s = DetectEngineAppendSig(de_ctx, + "alert websocket any any -> any any " + "(msg:\"absent with frame\"; " + "frame: websocket.pdu; absent: or_else; content:!\"one\"; sid:2;)"); + FAIL_IF(s != NULL); + DetectEngineCtxFree(de_ctx); + PASS; +} + +void DetectAbsentRegisterTests(void) +{ + UtRegisterTest("DetectAbsentTestParse01", DetectAbsentTestParse01); +} #endif diff --git a/src/detect-isdataat.h b/src/detect-isdataat.h index 01ea2e304f42..c0cff8848385 100644 --- a/src/detect-isdataat.h +++ b/src/detect-isdataat.h @@ -34,7 +34,14 @@ typedef struct DetectIsdataatData_ { uint8_t flags; /* isdataat options*/ } DetectIsdataatData; +typedef struct DetectAbsentData_ { + /** absent or try to match with other keywords (false means only absent) */ + bool or_else; +} DetectAbsentData; + /* prototypes */ void DetectIsdataatRegister (void); +bool DetectAbsentValidateContentCallback(Signature *s, const SignatureInitDataBuffer *); + #endif /* SURICATA_DETECT_ISDATAAT_H */ diff --git a/src/detect-parse.c b/src/detect-parse.c index 984501c1dd8a..3b03dfb92b36 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -35,6 +35,7 @@ #include "detect-content.h" #include "detect-bsize.h" +#include "detect-isdataat.h" #include "detect-pcre.h" #include "detect-uricontent.h" #include "detect-reference.h" @@ -1971,6 +1972,9 @@ static int SigValidate(DetectEngineCtx *de_ctx, Signature *s) if (!DetectBsizeValidateContentCallback(s, b)) { SCReturnInt(0); } + if (!DetectAbsentValidateContentCallback(s, b)) { + SCReturnInt(0); + } } int ts_excl = 0; diff --git a/src/detect.h b/src/detect.h index 4c22f509a3f3..e88b5540ac79 100644 --- a/src/detect.h +++ b/src/detect.h @@ -432,6 +432,8 @@ typedef struct DetectEngineAppInspectionEngine_ { uint8_t id; /**< per sig id used in state keeping */ bool mpm; bool stream; + /** will match on a NULL buffer (so an absent buffer) */ + bool match_on_null; uint16_t sm_list; uint16_t sm_list_base; /**< base buffer being transformed */ int16_t progress;