diff --git a/src/Makefile.am b/src/Makefile.am index 768f53ee0e..644cc8274b 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -102,6 +102,7 @@ util-debug-filters.c util-debug-filters.h \ util-error.c util-error.h \ util-enum.c util-enum.h \ util-radix-tree.c util-radix-tree.h \ +util-host-os-info.c util-host-os-info.h \ tm-modules.c tm-modules.h \ tm-queues.c tm-queues.h \ tm-queuehandlers.c tm-queuehandlers.h \ diff --git a/src/eidps.c b/src/eidps.c index 03a606e0a5..84fb935d5c 100644 --- a/src/eidps.c +++ b/src/eidps.c @@ -64,6 +64,7 @@ #include "app-layer-dcerpc.h" #include "util-radix-tree.h" +#include "util-host-os-info.h" #include "util-cidr.h" #include "util-unittest.h" #include "util-time.h" @@ -74,7 +75,6 @@ #include "defrag.h" #include "runmodes.h" -#include "util-debug.h" #include "util-debug.h" #include "util-error.h" @@ -468,6 +468,7 @@ int main(int argc, char **argv) SCRadixRegisterTests(); DefragRegisterTests(); SigGroupHeadRegisterTests(); + SCHInfoRegisterTests(); if (list_unittests) { UtListTests(regex_arg); } diff --git a/src/util-enum.c b/src/util-enum.c index 74007667f9..f327bc1fad 100644 --- a/src/util-enum.c +++ b/src/util-enum.c @@ -8,7 +8,9 @@ #include "util-enum.h" /** - * \brief Maps a string name to an enum value from the supplied table + * \brief Maps a string name to an enum value from the supplied table. Please + * specify the last element of any map table with a {NULL, -1}. If + * missing, you will be welcomed with a segfault :) * * \param enum_name Character string that has to be mapped to an enum value * from the table diff --git a/src/util-error.h b/src/util-error.h index d2e89d464c..a7f8ee3034 100644 --- a/src/util-error.h +++ b/src/util-error.h @@ -18,6 +18,10 @@ typedef enum { SC_SPRINTF_ERROR, SC_INVALID_ARGUMENT, SC_SPINLOCK_ERROR, + SC_INVALID_ENUM_MAP, + SC_INVALID_IP_NETBLOCK, + SC_INVALID_IPV4_ADDR, + SC_INVALID_IPV6_ADDR, } SCError; const char *SCErrorToString(SCError); diff --git a/src/util-host-os-info.c b/src/util-host-os-info.c new file mode 100644 index 0000000000..1a19bd5b7c --- /dev/null +++ b/src/util-host-os-info.c @@ -0,0 +1,801 @@ +/** Copyright (c) 2009 Open Information Security Foundation. + * \author Anoop Saldanha + */ + +#include "eidps-common.h" +#include "util-host-os-info.h" +#include "util-error.h" +#include "util-debug.h" +#include "util-radix-tree.h" +#include "stream-tcp-private.h" +#include "stream-tcp-reassemble.h" + +#include "util-enum.h" +#include "util-unittest.h" + +/** Enum map for the various OS flavours */ +SCEnumCharMap sc_hinfo_os_policy_map[ ] = { + { "none", OS_POLICY_NONE }, + { "bsd", OS_POLICY_BSD }, + { "old_linux", OS_POLICY_OLD_LINUX }, + { "linux", OS_POLICY_LINUX }, + { "solaris", OS_POLICY_SOLARIS }, + { "hpux10", OS_POLICY_HPUX10 }, + { "hpux11", OS_POLICY_HPUX11 }, + { "irix", OS_POLICY_IRIX }, + { "macos", OS_POLICY_MACOS }, + { "windows", OS_POLICY_WINDOWS }, + { "vista", OS_POLICY_VISTA }, + { "windows2k3", OS_POLICY_WINDOWS2K3 }, + { NULL, -1 }, +}; + +/** Radix tree that holds the host OS information */ +static SCRadixTree *sc_hinfo_tree = NULL; + +/** + * \brief Validates an IPV4 address and returns the network endian arranged + * version of the IPV4 address + * + * \param addr Pointer to a character string containing an IPV4 address. A + * valid IPV4 address is a character string containing a dotted + * format of "ddd.ddd.ddd.ddd" + * + * \retval Pointer to an in_addr instance containing the network endian format + * of the IPV4 address + * \retval NULL if the IPV4 address is invalid + */ +static struct in_addr *SCHInfoValidateIPV4Address(const char *addr_str) +{ + struct in_addr *addr = NULL; + + if ( (addr = malloc(sizeof(struct in_addr))) == NULL) { + SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); + exit(EXIT_FAILURE); + } + + if (inet_pton(AF_INET, addr_str, addr) <= 0) { + free(addr); + return NULL; + } + + return addr; +} + +/** + * \brief Validates an IPV6 address and returns the network endian arranged + * version of the IPV6 addresss + * + * \param addr Pointer to a character string containing an IPV6 address + * + * \retval Pointer to a in6_addr instance containing the network endian format + * of the IPV6 address + * \retval NULL if the IPV6 address is invalid + */ +static struct in6_addr *SCHInfoValidateIPV6Address(const char *addr_str) +{ + struct in6_addr *addr = NULL; + + if ( (addr = malloc(sizeof(struct in6_addr))) == NULL) { + SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); + exit(EXIT_FAILURE); + } + + if (inet_pton(AF_INET6, addr_str, addr) <= 0) { + free(addr); + return NULL; + } + + return addr; +} + +/** + * \brief Allocates the host_os flavour wrapped in user_data variable to be sent + * along with the key to the radix tree + * + * \param host_os Pointer to a character string containing the host_os flavour + * + * \retval user_data On success, pointer to the user_data that has to be sent + * along with the key, to be added to the Radix tree; NULL on + * failure + */ +static void *SCHInfoAllocUserDataOSPolicy(const char *host_os) +{ + int *user_data = NULL; + + if ( (user_data = malloc(sizeof(int))) == NULL) { + SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); + exit(EXIT_FAILURE); + } + + /* 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(SC_INVALID_ENUM_MAP, "Invalid enum map inside " + "SCHInfoAddHostOSInfo()"); + free(user_data); + return NULL; + } + + return (void *)user_data; +} + +/** + * \brief Used to free the user data that is allocated by host_os_info API + * + * \param Pointer to the data that has to be freed + */ +static void SCHInfoFreeUserDataOSPolicy(void *data) +{ + if (data != NULL) + free(data); + + return; +} + +/** + * \brief Culls the non-netmask portion of the ip address. + * + * This function can also be used for any general purpose use, to mask + * the first netmask bits of the stream data sent as argument + * + * \param stream Pointer to the data to be masked + * \param netmask The mask length(netmask) + * \param bitlen The bitlen of the stream + */ +static void SCHInfoMaskIPNetblock(uint8_t *stream, int netmask, int bitlen) +{ + int bytes = 0; + int mask = 0; + int i = 0; + + bytes = bitlen / 8; + for (i = 0; i < bytes; i++) { + mask = -1; + if ( ((i + 1) * 8) > netmask) { + if ( ((i + 1) * 8 - netmask) < 8) + mask = -1 << ((i + 1) * 8 - netmask); + else + mask = 0; + } + stream[i] &= mask; + } + + return; +} + +/** + * \brief Used to add the host-os-info data obtained from the conf + * + * \param host_os The host_os name/flavour from the conf file + * \param host_os_ip_range Pointer to a char string holding the ip/ip_netblock + * for the host_os specified in the first argument + * \param is_ipv4 Indicates if the ip address to be considered for the + * default configuration is IPV4; if not it is IPV6. + * Specified using SC_HINFO_IS_IPV6 or SC_HINFO_IS_IPV4 + * + * \retval 0 On successfully adding the host os info to the Radix tree + * \retval -1 On failure + */ +int SCHInfoAddHostOSInfo(char *host_os, char *host_os_ip_range, int is_ipv4) +{ + char *ip_str = NULL; + struct in_addr *ipv4_addr = NULL; + struct in6_addr *ipv6_addr = NULL; + char *netmask_str = NULL; + int netmask_value = 0; + int *user_data = NULL; + + if (host_os == NULL || host_os_ip_range == NULL) { + SCLogError(SC_INVALID_ARGUMENT, "Invalid arguments"); + return -1; + } + + /* create the radix tree that would hold all the host os info */ + if (sc_hinfo_tree == NULL) + sc_hinfo_tree = SCRadixCreateRadixTree(SCHInfoFreeUserDataOSPolicy); + + /* the host os flavour that has to be sent as user data */ + if ( (user_data = SCHInfoAllocUserDataOSPolicy(host_os)) == NULL) { + SCLogError(SC_INVALID_ENUM_MAP, "Invalid enum map inside"); + return -1; + } + + /* if we have a default configuration set the appropriate values for the + * netblocks */ + if ( (strcasecmp(host_os_ip_range, "default")) == 0) { + if (is_ipv4) + host_os_ip_range = "0.0.0.0/0"; + else + host_os_ip_range = "::/0"; + } + + if ( (ip_str = strdup(host_os_ip_range)) == NULL) { + SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); + exit(EXIT_FAILURE); + } + + /* check if we have received a netblock */ + if ( (netmask_str = index(ip_str, '/')) != NULL) { + netmask_str[0] = '\0'; + netmask_str++; + } + + if (index(ip_str, ':') == NULL) { + /* if we are here, we have an IPV4 address */ + if ( (ipv4_addr = SCHInfoValidateIPV4Address(ip_str)) == NULL) { + SCLogError(SC_INVALID_IPV4_ADDR, "Invalid IPV4 address"); + return -1; + } + + if (netmask_str == NULL) { + SCRadixAddKeyIPV4((uint8_t *)ipv4_addr, sc_hinfo_tree, + (void *)user_data); + } else { + netmask_value = atoi(netmask_str); + if (netmask_value < 0 || netmask_value > 32) { + SCLogError(SC_INVALID_IP_NETBLOCK, "Invalid IPV4 Netblock"); + free(ipv4_addr); + return -1; + } + + SCHInfoMaskIPNetblock((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 = SCHInfoValidateIPV6Address(ip_str)) == NULL) { + SCLogError(SC_INVALID_IPV6_ADDR, "Invalid IPV6 address inside"); + return -1; + } + + if (netmask_str == NULL) { + SCRadixAddKeyIPV6((uint8_t *)ipv6_addr, sc_hinfo_tree, + (void *)user_data); + } else { + netmask_value = atoi(netmask_str); + if (netmask_value < 0 || netmask_value > 128) { + SCLogError(SC_INVALID_IP_NETBLOCK, "Invalid IPV6 Netblock"); + free(ipv6_addr); + return -1; + } + + SCHInfoMaskIPNetblock((uint8_t *)ipv6_addr, netmask_value, 128); + SCRadixAddKeyIPV6Netblock((uint8_t *)ipv6_addr, sc_hinfo_tree, + (void *)user_data, netmask_value); + } + } + + return *user_data; +} + +/** + * \brief Retrieves the host os flavour, given the ip address + * + * \param Pointer to a string containing an IP address + * + * \retval The host os flavour + */ +int SCHInfoGetHostOSFlavour(char *ip_addr_str) +{ + SCRadixNode *node = NULL; + struct in_addr *ipv4_addr = NULL; + struct in6_addr *ipv6_addr = NULL; + + if (index(ip_addr_str, ':') != NULL) { + if ( (ipv6_addr = SCHInfoValidateIPV6Address(ip_addr_str)) == NULL) { + SCLogError(SC_INVALID_IPV4_ADDR, "Invalid IPV4 address"); + return -1; + } + + if ( (node = SCRadixFindKeyIPV6((uint8_t *)ipv6_addr, sc_hinfo_tree)) == NULL) + return -1; + else + return *((int *)node->prefix->user); + } else { + if ( (ipv4_addr = SCHInfoValidateIPV4Address(ip_addr_str)) == NULL) { + SCLogError(SC_INVALID_IPV4_ADDR, "Invalid IPV4 address"); + return -1; + } + + if ( (node = SCRadixFindKeyIPV4((uint8_t *)ipv4_addr, sc_hinfo_tree)) == NULL) + return -1; + else + return *((int *)node->prefix->user); + } +} + +void SCHInfoCleanResources(void) +{ + if (sc_hinfo_tree != NULL) { + SCRadixReleaseRadixTree(sc_hinfo_tree); + sc_hinfo_tree = NULL; + } + + return; +} + +/*------------------------------------Unit_Tests------------------------------*/ + +#ifdef UNITTESTS + +int SCHInfoTestInvalidOSFlavour01(void) +{ + int result = 1; + + result &= (SCHInfoAddHostOSInfo("bamboo", "192.168.1.1", SC_HINFO_IS_IPV4) == + -1); + result &= (SCHInfoAddHostOSInfo("linux", "192.168.1.1", SC_HINFO_IS_IPV4) == + SCMapEnumNameToValue("linux", sc_hinfo_os_policy_map)); + result &= (SCHInfoAddHostOSInfo("windows", "192.168.1.1", SC_HINFO_IS_IPV4) == + SCMapEnumNameToValue("windows", sc_hinfo_os_policy_map)); + result &= (SCHInfoAddHostOSInfo("solaris", "192.168.1.1", SC_HINFO_IS_IPV4) == + SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)); + result &= (SCHInfoAddHostOSInfo("hpux10", "192.168.1.1", SC_HINFO_IS_IPV4) == + SCMapEnumNameToValue("hpux10", sc_hinfo_os_policy_map)); + result &= (SCHInfoAddHostOSInfo("hpux11", "192.168.1.1", SC_HINFO_IS_IPV4) == + SCMapEnumNameToValue("hpux11", sc_hinfo_os_policy_map)); + result &= (SCHInfoAddHostOSInfo("irix", "192.168.1.1", SC_HINFO_IS_IPV4) == + SCMapEnumNameToValue("irix", sc_hinfo_os_policy_map)); + result &= (SCHInfoAddHostOSInfo("bsd", "192.168.1.1", SC_HINFO_IS_IPV4) == + SCMapEnumNameToValue("bsd", sc_hinfo_os_policy_map)); + result &= (SCHInfoAddHostOSInfo("old_linux", "192.168.1.1", SC_HINFO_IS_IPV4) == + SCMapEnumNameToValue("old_linux", sc_hinfo_os_policy_map)); + result &= (SCHInfoAddHostOSInfo("macos", "192.168.1.1", SC_HINFO_IS_IPV4) == + SCMapEnumNameToValue("macos", sc_hinfo_os_policy_map)); + result &= (SCHInfoAddHostOSInfo("vista", "192.168.1.1", SC_HINFO_IS_IPV4) == + SCMapEnumNameToValue("vista", sc_hinfo_os_policy_map)); + result &= (SCHInfoAddHostOSInfo("windows2k3", "192.168.1.1", SC_HINFO_IS_IPV4) == + SCMapEnumNameToValue("windows2k3", sc_hinfo_os_policy_map)); + + SCHInfoCleanResources(); + + return result; +} + +int SCHInfoTestInvalidIPV4Address02(void) +{ + int result = 1; + + result &= (SCHInfoAddHostOSInfo("linux", "192.168.1.566", SC_HINFO_IS_IPV4) == + -1); + result &= (SCHInfoAddHostOSInfo("linux", "192.168.1", SC_HINFO_IS_IPV4) == + -1); + result &= (SCHInfoAddHostOSInfo("linux", "192.", SC_HINFO_IS_IPV4) == -1); + result &= (SCHInfoAddHostOSInfo("linux", "192.168", SC_HINFO_IS_IPV4) == + -1); + result &= (SCHInfoAddHostOSInfo("linux", "", SC_HINFO_IS_IPV4) == -1); + result &= (SCHInfoAddHostOSInfo("linux", "192.168.1.1/33", SC_HINFO_IS_IPV4) == + -1); + + SCHInfoCleanResources(); + + return result; +} + +int SCHInfoTestInvalidIPV6Address03(void) +{ + int result = 1; + + result &= (SCHInfoAddHostOSInfo("linux", "2362:7322", SC_HINFO_IS_IPV6) == + -1); + result &= (SCHInfoAddHostOSInfo("linux", "19YW:", SC_HINFO_IS_IPV6) == -1); + result &= (SCHInfoAddHostOSInfo("linux", "1235", SC_HINFO_IS_IPV6) == -1); + result &= (SCHInfoAddHostOSInfo("linux", "1922:236115:", SC_HINFO_IS_IPV6) == + -1); + result &= (SCHInfoAddHostOSInfo("linux", "", SC_HINFO_IS_IPV6) == -1); + result &= (SCHInfoAddHostOSInfo("linux", + "1921.6311:6241:6422:7352:ABBB:DDDD:EEEE/129", + SC_HINFO_IS_IPV6) == -1); + + SCHInfoCleanResources(); + + return result; +} + +int SCHInfoTestValidIPV4Address04(void) +{ + int result = 1; + + result &= (SCHInfoAddHostOSInfo("linux", "192.168.1.1", SC_HINFO_IS_IPV4) != + -1); + result &= (SCHInfoAddHostOSInfo("windows", "192.192.1.2", SC_HINFO_IS_IPV4) != + -1); + result &= (SCHInfoAddHostOSInfo("solaris", "192.168.1.100", SC_HINFO_IS_IPV4) != + -1); + result &= (SCHInfoAddHostOSInfo("hpux10", "192.168.2.4", SC_HINFO_IS_IPV4) != + -1); + result &= (SCHInfoAddHostOSInfo("linux", "192.192.1.5", SC_HINFO_IS_IPV4) != + -1); + result &= (SCHInfoAddHostOSInfo("vista", "192.168.10.20", SC_HINFO_IS_IPV4) != + -1); + result &= (SCHInfoAddHostOSInfo("solaris", "111.163.151.62", SC_HINFO_IS_IPV4) != + -1); + result &= (SCHInfoAddHostOSInfo("solaris", "11.1.120.210", SC_HINFO_IS_IPV4) != + -1); + result &= (SCHInfoAddHostOSInfo("linux", "19.18.110.210", SC_HINFO_IS_IPV4) != + -1); + result &= (SCHInfoAddHostOSInfo("windows", "19.18.120.110", SC_HINFO_IS_IPV4) != + -1); + result &= (SCHInfoAddHostOSInfo("hpux11", "191.168.11.128", SC_HINFO_IS_IPV4) != + -1); + result &= (SCHInfoAddHostOSInfo("vista", "191.168.11.192", SC_HINFO_IS_IPV4) != + -1); + + result &= (SCHInfoGetHostOSFlavour("192.168.1.1") == + SCMapEnumNameToValue("linux", sc_hinfo_os_policy_map)); + result &= (SCHInfoGetHostOSFlavour("192.168.1.2") == -1); + result &= (SCHInfoGetHostOSFlavour("192.168.1.100") == + SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)); + result &= (SCHInfoGetHostOSFlavour("192.192.2.4") == -1); + result &= (SCHInfoGetHostOSFlavour("192.168.2.4") == + SCMapEnumNameToValue("hpux10", sc_hinfo_os_policy_map)); + result &= (SCHInfoGetHostOSFlavour("192.192.1.5") == + SCMapEnumNameToValue("linux", sc_hinfo_os_policy_map)); + result &= (SCHInfoGetHostOSFlavour("192.168.10.20") == + SCMapEnumNameToValue("vista", sc_hinfo_os_policy_map)); + result &= (SCHInfoGetHostOSFlavour("111.163.151.62") == + SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)); + result &= (SCHInfoGetHostOSFlavour("11.1.120.210") == + SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)); + result &= (SCHInfoGetHostOSFlavour("19.18.110.210") == + SCMapEnumNameToValue("linux", sc_hinfo_os_policy_map)); + result &= (SCHInfoGetHostOSFlavour("19.18.120.110") == + SCMapEnumNameToValue("windows", sc_hinfo_os_policy_map)); + result &= (SCHInfoGetHostOSFlavour("191.168.11.128") == + SCMapEnumNameToValue("hpux11", sc_hinfo_os_policy_map)); + result &= (SCHInfoGetHostOSFlavour("191.168.11.192") == + SCMapEnumNameToValue("vista", sc_hinfo_os_policy_map)); + result &= (SCHInfoGetHostOSFlavour("191.168.11.224") == -1); + + SCHInfoCleanResources(); + + return result; +} + +int SCHInfoTestValidIPV4Address05(void) +{ + int result = 1; + + result &= (SCHInfoAddHostOSInfo("linux", "192.168.1.1", SC_HINFO_IS_IPV4) != + -1); + result &= (SCHInfoAddHostOSInfo("windows", "192.192.1.2", SC_HINFO_IS_IPV4) != + -1); + result &= (SCHInfoAddHostOSInfo("solaris", "192.168.1.100", SC_HINFO_IS_IPV4) != + -1); + result &= (SCHInfoAddHostOSInfo("hpux10", "192.168.2.4", SC_HINFO_IS_IPV4) != + -1); + result &= (SCHInfoAddHostOSInfo("linux", "192.192.1.5", SC_HINFO_IS_IPV4) != + -1); + result &= (SCHInfoAddHostOSInfo("vista", "192.168.10.20", SC_HINFO_IS_IPV4) != + -1); + result &= (SCHInfoAddHostOSInfo("solaris", "111.163.151.62", SC_HINFO_IS_IPV4) != + -1); + result &= (SCHInfoAddHostOSInfo("hpux11", "111.162.208.124/20", SC_HINFO_IS_IPV4) != + -1); + result &= (SCHInfoAddHostOSInfo("windows", "111.162.240.1", SC_HINFO_IS_IPV4) != + -1); + result &= (SCHInfoAddHostOSInfo("solaris", "111.162.214.100", SC_HINFO_IS_IPV4) != + -1); + result &= (SCHInfoAddHostOSInfo("vista", "111.162.208.100", SC_HINFO_IS_IPV4) != + -1); + result &= (SCHInfoAddHostOSInfo("linux", "111.162.194.112", SC_HINFO_IS_IPV4) != + -1); + + result &= (SCHInfoGetHostOSFlavour("192.168.1.1") == + SCMapEnumNameToValue("linux", sc_hinfo_os_policy_map)); + result &= (SCHInfoGetHostOSFlavour("192.168.1.2") == -1); + result &= (SCHInfoGetHostOSFlavour("192.168.1.100") == + SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)); + result &= (SCHInfoGetHostOSFlavour("192.192.2.4") == -1); + result &= (SCHInfoGetHostOSFlavour("192.168.2.4") == + SCMapEnumNameToValue("hpux10", sc_hinfo_os_policy_map)); + result &= (SCHInfoGetHostOSFlavour("192.192.1.5") == + SCMapEnumNameToValue("linux", sc_hinfo_os_policy_map)); + result &= (SCHInfoGetHostOSFlavour("192.168.10.20") == + SCMapEnumNameToValue("vista", sc_hinfo_os_policy_map)); + result &= (SCHInfoGetHostOSFlavour("111.163.151.62") == + SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)); + result &= (SCHInfoGetHostOSFlavour("111.162.208.0") == + SCMapEnumNameToValue("hpux11", sc_hinfo_os_policy_map)); + result &= (SCHInfoGetHostOSFlavour("111.162.210.1") == + SCMapEnumNameToValue("hpux11", sc_hinfo_os_policy_map)); + result &= (SCHInfoGetHostOSFlavour("111.162.214.1") == + SCMapEnumNameToValue("hpux11", sc_hinfo_os_policy_map)); + result &= (SCHInfoGetHostOSFlavour("111.162.0.0") == -1); + result &= (SCHInfoGetHostOSFlavour("111.162.240.112") == -1); + result &= (SCHInfoGetHostOSFlavour("111.162.240.1") == + SCMapEnumNameToValue("windows", sc_hinfo_os_policy_map)); + result &= (SCHInfoGetHostOSFlavour("111.162.214.100") == + SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)); + result &= (SCHInfoGetHostOSFlavour("111.162.208.100") == + SCMapEnumNameToValue("vista", sc_hinfo_os_policy_map)); + result &= (SCHInfoGetHostOSFlavour("111.162.194.112") == + SCMapEnumNameToValue("linux", sc_hinfo_os_policy_map)); + result &= (SCHInfoGetHostOSFlavour("111.162.208.200") == + SCMapEnumNameToValue("hpux11", sc_hinfo_os_policy_map)); + result &= (SCHInfoGetHostOSFlavour("111.162.208.200") == + SCMapEnumNameToValue("hpux11", sc_hinfo_os_policy_map)); + result &= (SCHInfoGetHostOSFlavour("111.162.200.201") == -1); + + SCHInfoCleanResources(); + + return result; +} + +int SCHInfoTestValidIPV6Address06(void) +{ + int result = 1; + + result &= (SCHInfoAddHostOSInfo("linux", + "2351:2512:6211:6246:235A:6242:2352:62AD", + SC_HINFO_IS_IPV6) != -1); + result &= (SCHInfoAddHostOSInfo("windows", + "6961:6121:2132:6241:423A:2135:2461:621D", + SC_HINFO_IS_IPV6) != -1); + result &= (SCHInfoAddHostOSInfo("solaris", + "DD13:613D:F312:62DD:6213:421A:6212:2652", + SC_HINFO_IS_IPV6) != -1); + result &= (SCHInfoAddHostOSInfo("hpux10", + "9891:2131:2151:6426:1342:674D:622F:2342", + SC_HINFO_IS_IPV6) != -1); + result &= (SCHInfoAddHostOSInfo("linux", + "3525:2351:4223:6211:2311:2667:6242:2154", + SC_HINFO_IS_IPV6) != -1); + result &= (SCHInfoAddHostOSInfo("vista", + "1511:6211:6726:7777:1212:2333:6222:7722", + SC_HINFO_IS_IPV6) != -1); + result &= (SCHInfoAddHostOSInfo("solaris", + "2666:6222:7222:2335:6223:7722:3425:2362", + SC_HINFO_IS_IPV6) != -1); + result &= (SCHInfoAddHostOSInfo("solaris", + "8762:2352:6241:7245:EE23:21AD:2312:622C", + SC_HINFO_IS_IPV6) != -1); + result &= (SCHInfoAddHostOSInfo("linux", + "6422:EE1A:2621:34AD:2462:432D:642E:E13A", + SC_HINFO_IS_IPV6) != -1); + result &= (SCHInfoAddHostOSInfo("windows", + "3521:7622:6241:6242:7277:1234:2352:6234", + SC_HINFO_IS_IPV6) != -1); + result &= (SCHInfoAddHostOSInfo("hpux11", + "2141:6232:6252:2223:7734:2345:6245:6222", + SC_HINFO_IS_IPV6) != -1); + result &= (SCHInfoAddHostOSInfo("vista", + "5222:6432:6432:2322:6662:3423:4322:3245", + SC_HINFO_IS_IPV6) != -1); + + result &= (SCHInfoGetHostOSFlavour("2351:2512:6211:6246:235A:6242:2352:62AD") == + SCMapEnumNameToValue("linux", sc_hinfo_os_policy_map)); + result &= (SCHInfoGetHostOSFlavour("2351:2512:6211:6246:235A:6242:2352:6FFFE") == + -1); + result &= (SCHInfoGetHostOSFlavour("DD13:613D:F312:62DD:6213:421A:6212:2652") == + SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)); + result &= (SCHInfoGetHostOSFlavour("DD13:613D:F312:62DD:6213:421A:6212:2222") == + -1); + result &= (SCHInfoGetHostOSFlavour("9891:2131:2151:6426:1342:674D:622F:2342") == + SCMapEnumNameToValue("hpux10", sc_hinfo_os_policy_map)); + result &= (SCHInfoGetHostOSFlavour("3525:2351:4223:6211:2311:2667:6242:2154") == + SCMapEnumNameToValue("linux", sc_hinfo_os_policy_map)); + result &= (SCHInfoGetHostOSFlavour("1511:6211:6726:7777:1212:2333:6222:7722") == + SCMapEnumNameToValue("vista", sc_hinfo_os_policy_map)); + result &= (SCHInfoGetHostOSFlavour("2666:6222:7222:2335:6223:7722:3425:2362") == + SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)); + result &= (SCHInfoGetHostOSFlavour("8762:2352:6241:7245:EE23:21AD:2312:622C") == + SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)); + result &= (SCHInfoGetHostOSFlavour("6422:EE1A:2621:34AD:2462:432D:642E:E13A") == + SCMapEnumNameToValue("linux", sc_hinfo_os_policy_map)); + result &= (SCHInfoGetHostOSFlavour("3521:7622:6241:6242:7277:1234:2352:6234") == + SCMapEnumNameToValue("windows", sc_hinfo_os_policy_map)); + result &= (SCHInfoGetHostOSFlavour("2141:6232:6252:2223:7734:2345:6245:6222") == + SCMapEnumNameToValue("hpux11", sc_hinfo_os_policy_map)); + result &= (SCHInfoGetHostOSFlavour("5222:6432:6432:2322:6662:3423:4322:3245") == + SCMapEnumNameToValue("vista", sc_hinfo_os_policy_map)); + result &= (SCHInfoGetHostOSFlavour("5222:6432:6432:2322:6662:3423:4322:DDDD") == + -1); + + SCHInfoCleanResources(); + + return result; +} + +int SCHInfoTestValidIPV6Address07(void) +{ + int result = 1; + + result &= (SCHInfoAddHostOSInfo("linux", + "2351:2512:6211:6246:235A:6242:2352:62AD", + SC_HINFO_IS_IPV6) != -1); + result &= (SCHInfoAddHostOSInfo("windows", + "6961:6121:2132:6241:423A:2135:2461:621D", + SC_HINFO_IS_IPV6) != -1); + result &= (SCHInfoAddHostOSInfo("solaris", + "DD13:613D:F312:62DD:6213:421A:6212:2652", + SC_HINFO_IS_IPV6) != -1); + result &= (SCHInfoAddHostOSInfo("hpux10", + "9891:2131:2151:6426:1342:674D:622F:2342", + SC_HINFO_IS_IPV6) != -1); + result &= (SCHInfoAddHostOSInfo("linux", + "3525:2351:4223:6211:2311:2667:6242:2154", + SC_HINFO_IS_IPV6) != -1); + result &= (SCHInfoAddHostOSInfo("vista", + "1511:6211:6726:7777:1212:2333:6222:7722", + SC_HINFO_IS_IPV6) != -1); + result &= (SCHInfoAddHostOSInfo("solaris", + "2666:6222:7222:2335:6223:7722:3425:2362", + SC_HINFO_IS_IPV6) != -1); + result &= (SCHInfoAddHostOSInfo("solaris", + "8762:2352:6241:7245:EE23:21AD:2312:622C/68", + SC_HINFO_IS_IPV6) != -1); + result &= (SCHInfoAddHostOSInfo("linux", + "8762:2352:6241:7245:EE23:21AD:2412:622C", + SC_HINFO_IS_IPV6) != -1); + result &= (SCHInfoAddHostOSInfo("windows", + "8762:2352:6241:7245:EE23:21AD:FFFF:622C", + SC_HINFO_IS_IPV6) != -1); + result &= (SCHInfoAddHostOSInfo("hpux11", + "8762:2352:6241:7245:EE23:21AD:2312:62FF", + SC_HINFO_IS_IPV6) != -1); + result &= (SCHInfoAddHostOSInfo("vista", + "8762:2352:6241:7245:EE23:21AD:2121:1212", + SC_HINFO_IS_IPV6) != -1); + + result &= (SCHInfoGetHostOSFlavour("2351:2512:6211:6246:235A:6242:2352:62AD") == + SCMapEnumNameToValue("linux", sc_hinfo_os_policy_map)); + result &= (SCHInfoGetHostOSFlavour("2351:2512:6211:6246:235A:6242:2352:6FFFE") == + -1); + result &= (SCHInfoGetHostOSFlavour("DD13:613D:F312:62DD:6213:421A:6212:2652") == + SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)); + result &= (SCHInfoGetHostOSFlavour("DD13:613D:F312:62DD:6213:421A:6212:2222") == + -1); + result &= (SCHInfoGetHostOSFlavour("9891:2131:2151:6426:1342:674D:622F:2342") == + SCMapEnumNameToValue("hpux10", sc_hinfo_os_policy_map)); + result &= (SCHInfoGetHostOSFlavour("3525:2351:4223:6211:2311:2667:6242:2154") == + SCMapEnumNameToValue("linux", sc_hinfo_os_policy_map)); + result &= (SCHInfoGetHostOSFlavour("1511:6211:6726:7777:1212:2333:6222:7722") == + SCMapEnumNameToValue("vista", sc_hinfo_os_policy_map)); + result &= (SCHInfoGetHostOSFlavour("2666:6222:7222:2335:6223:7722:3425:2362") == + SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)); + result &= (SCHInfoGetHostOSFlavour("8762:2352:6241:7245:EE23:21AD:2312:622C") == + SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)); + result &= (SCHInfoGetHostOSFlavour("8762:2352:6241:7245:EE23:21AD:2412:622C") == + SCMapEnumNameToValue("linux", sc_hinfo_os_policy_map)); + result &= (SCHInfoGetHostOSFlavour("8762:2352:6241:7245:EE23:21AD:FFFF:622C") == + SCMapEnumNameToValue("windows", sc_hinfo_os_policy_map)); + result &= (SCHInfoGetHostOSFlavour("8762:2352:6241:7245:EE23:21AD:2312:62FF") == + SCMapEnumNameToValue("hpux11", sc_hinfo_os_policy_map)); + result &= (SCHInfoGetHostOSFlavour("8762:2352:6241:7245:EE23:21AD:2121:1212") == + SCMapEnumNameToValue("vista", sc_hinfo_os_policy_map)); + result &= (SCHInfoGetHostOSFlavour("5222:6432:6432:2322:6662:3423:4322:DDDD") == + -1); + result &= (SCHInfoGetHostOSFlavour("8762:2352:6241:7245:EE23:21AD:2121:1DDD") == + SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)); + result &= (SCHInfoGetHostOSFlavour("8762:2352:6241:7245:EE23:FFFF:2121:1DDD") == + SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)); + result &= (SCHInfoGetHostOSFlavour("8762:2352:6241:7245:EE23:21AD:2312:622C") == + SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)); + result &= (SCHInfoGetHostOSFlavour("8762:2352:6241:7245:EE00:0000:0000:0000") == + SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)); + result &= (SCHInfoGetHostOSFlavour("8762:2352:6241:7245:E000:0000:0000:0000") == + SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)); + + SCHInfoCleanResources(); + + return result; +} + +int SCHInfoTestValidIPV6Address08(void) +{ + int result = 1; + + result &= (SCHInfoAddHostOSInfo("linux", + "2351:2512:6211:6246:235A:6242:2352:62AD", + SC_HINFO_IS_IPV6) != -1); + result &= (SCHInfoAddHostOSInfo("windows", + "6961:6121:2132:6241:423A:2135:2461:621D", + SC_HINFO_IS_IPV6) != -1); + result &= (SCHInfoAddHostOSInfo("solaris", + "DD13:613D:F312:62DD:6213:421A:6212:2652", + SC_HINFO_IS_IPV6) != -1); + result &= (SCHInfoAddHostOSInfo("hpux10", + "9891:2131:2151:6426:1342:674D:622F:2342", + SC_HINFO_IS_IPV6) != -1); + result &= (SCHInfoAddHostOSInfo("linux", + "3525:2351:4223:6211:2311:2667:6242:2154", + SC_HINFO_IS_IPV6) != -1); + result &= (SCHInfoAddHostOSInfo("vista", + "1511:6211:6726:7777:1212:2333:6222:7722", + SC_HINFO_IS_IPV6) != -1); + result &= (SCHInfoAddHostOSInfo("solaris", + "2666:6222:7222:2335:6223:7722:3425:2362", + SC_HINFO_IS_IPV6) != -1); + result &= (SCHInfoAddHostOSInfo("solaris", + "8762:2352:6241:7245:EE23:21AD:2312:622C/68", + SC_HINFO_IS_IPV6) != -1); + result &= (SCHInfoAddHostOSInfo("linux", + "8762:2352:6241:7245:EE23:21AD:2412:622C", + SC_HINFO_IS_IPV6) != -1); + result &= (SCHInfoAddHostOSInfo("windows", + "8762:2352:6241:7245:EE23:21AD:FFFF:622C", + SC_HINFO_IS_IPV6) != -1); + result &= (SCHInfoAddHostOSInfo("hpux11", + "8762:2352:6241:7245:EE23:21AD:2312:62FF", + SC_HINFO_IS_IPV6) != -1); + result &= (SCHInfoAddHostOSInfo("vista", + "8762:2352:6241:7245:EE23:21AD:2121:1212", + SC_HINFO_IS_IPV6) != -1); + result &= (SCHInfoAddHostOSInfo("irix", "default", SC_HINFO_IS_IPV6) != -1); + + result &= (SCHInfoGetHostOSFlavour("2351:2512:6211:6246:235A:6242:2352:62AD") == + SCMapEnumNameToValue("linux", sc_hinfo_os_policy_map)); + result &= (SCHInfoGetHostOSFlavour("2351:2512:6211:6246:235A:6242:2352:6FFF") == + SCMapEnumNameToValue("irix", sc_hinfo_os_policy_map)); + result &= (SCHInfoGetHostOSFlavour("DD13:613D:F312:62DD:6213:421A:6212:2652") == + SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)); + result &= (SCHInfoGetHostOSFlavour("DD13:613D:F312:62DD:6213:421A:6212:2222") == + SCMapEnumNameToValue("irix", sc_hinfo_os_policy_map)); + result &= (SCHInfoGetHostOSFlavour("9891:2131:2151:6426:1342:674D:622F:2342") == + SCMapEnumNameToValue("hpux10", sc_hinfo_os_policy_map)); + result &= (SCHInfoGetHostOSFlavour("3525:2351:4223:6211:2311:2667:6242:2154") == + SCMapEnumNameToValue("linux", sc_hinfo_os_policy_map)); + result &= (SCHInfoGetHostOSFlavour("1511:6211:6726:7777:1212:2333:6222:7722") == + SCMapEnumNameToValue("vista", sc_hinfo_os_policy_map)); + result &= (SCHInfoGetHostOSFlavour("2666:6222:7222:2335:6223:7722:3425:2362") == + SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)); + result &= (SCHInfoGetHostOSFlavour("8762:2352:6241:7245:EE23:21AD:2312:622C") == + SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)); + result &= (SCHInfoGetHostOSFlavour("8762:2352:6241:7245:EE23:21AD:2412:622C") == + SCMapEnumNameToValue("linux", sc_hinfo_os_policy_map)); + result &= (SCHInfoGetHostOSFlavour("8762:2352:6241:7245:EE23:21AD:FFFF:622C") == + SCMapEnumNameToValue("windows", sc_hinfo_os_policy_map)); + result &= (SCHInfoGetHostOSFlavour("8762:2352:6241:7245:EE23:21AD:2312:62FF") == + SCMapEnumNameToValue("hpux11", sc_hinfo_os_policy_map)); + result &= (SCHInfoGetHostOSFlavour("8762:2352:6241:7245:EE23:21AD:2121:1212") == + SCMapEnumNameToValue("vista", sc_hinfo_os_policy_map)); + result &= (SCHInfoGetHostOSFlavour("5222:6432:6432:2322:6662:3423:4322:DDDD") == + SCMapEnumNameToValue("irix", sc_hinfo_os_policy_map)); + result &= (SCHInfoGetHostOSFlavour("8762:2352:6241:7245:EE23:21AD:2121:1DDD") == + SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)); + result &= (SCHInfoGetHostOSFlavour("8762:2352:6241:7245:EE23:FFFF:2121:1DDD") == + SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)); + result &= (SCHInfoGetHostOSFlavour("8762:2352:6241:7245:EE23:21AD:2312:622C") == + SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)); + result &= (SCHInfoGetHostOSFlavour("8762:2352:6241:7245:EE00:0000:0000:0000") == + SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)); + result &= (SCHInfoGetHostOSFlavour("8762:2352:6241:7245:E000:0000:0000:0000") == + SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)); + result &= (SCHInfoGetHostOSFlavour("AD23:2DDA:6D1D:A223:E235:0232:1241:1666") == + SCMapEnumNameToValue("irix", sc_hinfo_os_policy_map)); + + + SCHInfoCleanResources(); + + return result; +} + +#endif /* UNITTESTS */ + +void SCHInfoRegisterTests(void) +{ + +#ifdef UNITTESTS + + UtRegisterTest("SCHInfoTesInvalidOSFlavour01", + SCHInfoTestInvalidOSFlavour01, 1); + UtRegisterTest("SCHInfoTestInvalidIPV4Address02", + SCHInfoTestInvalidIPV4Address02, 1); + UtRegisterTest("SCHInfoTestInvalidIPV6Address03", + SCHInfoTestInvalidIPV6Address03, 1); + UtRegisterTest("SCHInfoTestValidIPV4Address04", + SCHInfoTestValidIPV4Address04, 1); + UtRegisterTest("SCHInfoTestValidIPV4Address05", + SCHInfoTestValidIPV4Address05, 1); + UtRegisterTest("SCHInfoTestValidIPV6Address06", + SCHInfoTestValidIPV6Address06, 1); + UtRegisterTest("SCHInfoTestValidIPV6Address07", + SCHInfoTestValidIPV6Address07, 1); + UtRegisterTest("SCHInfoTestValidIPV6Address08", + SCHInfoTestValidIPV6Address08, 1); + +#endif /* UNITTESTS */ + +} diff --git a/src/util-host-os-info.h b/src/util-host-os-info.h new file mode 100644 index 0000000000..66021ae72f --- /dev/null +++ b/src/util-host-os-info.h @@ -0,0 +1,16 @@ +/** Copyright (c) 2009 Open Information Security Foundation. + * \author Anoop Saldanha + */ + +#ifndef __UTIL_HOST_OS_INFO_H__ +#define __UTIL_HOST_OS_INFO_H__ + +#define SC_HINFO_IS_IPV6 0 +#define SC_HINFO_IS_IPV4 1 + +int SCHInfoAddHostOSInfo(char *, char *, int); +int SCHInfoGetHostOSFlavour(char *); +void SCHInfoCleanResources(void); +void SCHInfoRegisterTests(void); + +#endif /* __UTIL_HOST_OS_INFO_H__ */ diff --git a/src/util-radix-tree.c b/src/util-radix-tree.c index 4f4dd0dc51..30d8b74977 100644 --- a/src/util-radix-tree.c +++ b/src/util-radix-tree.c @@ -29,12 +29,14 @@ * \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) + uint16_t key_bitlen, void *user, + int netmask) { SCRadixPrefix *prefix = NULL; if ((key_bitlen % 8 != 0) || key_bitlen == 0) { - SCLogError(SC_INVALID_ARGUMENT, "Invalid argument bitlen - %d", key_bitlen); + SCLogError(SC_INVALID_ARGUMENT, "Invalid argument bitlen - %d", + key_bitlen); return NULL; } @@ -58,6 +60,7 @@ static SCRadixPrefix *SCRadixCreatePrefix(uint8_t *key_stream, memcpy(prefix->stream, key_stream, key_bitlen / 8); prefix->bitlen = key_bitlen; prefix->user = user; + prefix->netmask = netmask; return prefix; } @@ -180,11 +183,13 @@ void SCRadixReleaseRadixTree(SCRadixTree *tree) * \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 if we are adding an IP netblock; -1 if we are + * not adding an IP netblock * * \retval node Pointer to the newly created node */ static SCRadixNode *SCRadixAddKey(uint8_t *key_stream, uint16_t key_bitlen, - SCRadixTree *tree, void *user) + SCRadixTree *tree, void *user, int netmask) { SCRadixNode *node = NULL; SCRadixNode *new_node = NULL; @@ -204,8 +209,10 @@ static SCRadixNode *SCRadixAddKey(uint8_t *key_stream, uint16_t key_bitlen, int j = 0; int temp = 0; - if ( (prefix = SCRadixCreatePrefix(key_stream, key_bitlen, user)) == NULL) + if ( (prefix = SCRadixCreatePrefix(key_stream, key_bitlen, user, + netmask)) == NULL) { return NULL; + } if (tree == NULL) { SCLogError(SC_INVALID_ARGUMENT, "Argument \"tree\" NULL"); @@ -304,7 +311,8 @@ static SCRadixNode *SCRadixAddKey(uint8_t *key_stream, uint16_t key_bitlen, if (node->prefix) return node; - node->prefix = SCRadixCreatePrefix(prefix->stream, prefix->bitlen, NULL); + node->prefix = SCRadixCreatePrefix(prefix->stream, prefix->bitlen, NULL, + -1); return node; } @@ -338,6 +346,20 @@ static SCRadixNode *SCRadixAddKey(uint8_t *key_stream, uint16_t key_bitlen, inter_node->bit = differ_bit; inter_node->parent = node->parent; + if (node->netmasks != NULL) { + if ((node->netmasks[0] - 1) < differ_bit) { + inter_node->netmask_cnt++; + if ( (inter_node->netmasks = malloc(sizeof(int))) == NULL) { + SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); + exit(EXIT_FAILURE); + } + inter_node->netmasks[0] = node->netmasks[0]; + free(node->netmasks); + node->netmasks = NULL; + node->netmask_cnt--; + } + } + if (SC_RADIX_BITTEST(stream[differ_bit >> 3], (0x80 >> (differ_bit % 8))) ) { inter_node->left = node; @@ -358,6 +380,39 @@ static SCRadixNode *SCRadixAddKey(uint8_t *key_stream, uint16_t key_bitlen, node->parent = inter_node; } + if (netmask != -1) { + node = new_node; + parent = new_node->parent; + while (parent != NULL && netmask < (parent->bit + 1)) { + node = parent; + parent = parent->parent; + } + + node->netmask_cnt++; + if ( (node->netmasks = realloc(node->netmasks, (node->netmask_cnt * + sizeof(int)))) == NULL) { + SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); + exit(EXIT_FAILURE); + } + + if (node->netmask_cnt == 1) { + node->netmasks[0] = netmask; + return new_node; + } + + node->netmasks[node->netmask_cnt - 1] = netmask; + + for (i = node->netmask_cnt - 2; i >= 0; i--) { + if (netmask < node->netmasks[i]) { + node->netmasks[i + 1] = netmask; + break; + } + + node->netmasks[i + 1] = node->netmasks[i]; + node->netmasks[i] = netmask; + } + } + return new_node; } @@ -376,7 +431,7 @@ static SCRadixNode *SCRadixAddKey(uint8_t *key_stream, uint16_t key_bitlen, SCRadixNode *SCRadixAddKeyGeneric(uint8_t *key_stream, uint16_t key_bitlen, SCRadixTree *tree, void *user) { - SCRadixNode *node = SCRadixAddKey(key_stream, key_bitlen, tree, user); + SCRadixNode *node = SCRadixAddKey(key_stream, key_bitlen, tree, user, -1); return node; } @@ -395,7 +450,7 @@ SCRadixNode *SCRadixAddKeyGeneric(uint8_t *key_stream, uint16_t key_bitlen, SCRadixNode *SCRadixAddKeyIPV4(uint8_t *key_stream, SCRadixTree *tree, void *user) { - SCRadixNode *node = SCRadixAddKey(key_stream, 32, tree, user); + SCRadixNode *node = SCRadixAddKey(key_stream, 32, tree, user, -1); return node; } @@ -414,7 +469,47 @@ SCRadixNode *SCRadixAddKeyIPV4(uint8_t *key_stream, SCRadixTree *tree, SCRadixNode *SCRadixAddKeyIPV6(uint8_t *key_stream, SCRadixTree *tree, void *user) { - SCRadixNode *node = SCRadixAddKey(key_stream, 128, tree, user); + SCRadixNode *node = SCRadixAddKey(key_stream, 128, tree, user, -1); + + return node; +} + +/** + * \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 if we are adding a netblock + * + * \retval node Pointer to the newly created node + */ +SCRadixNode *SCRadixAddKeyIPV4Netblock(uint8_t *key_stream, SCRadixTree *tree, + void *user, int netmask) +{ + 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 if we are adding a netblock + * + * \retval node Pointer to the newly created node + */ +SCRadixNode *SCRadixAddKeyIPV6Netblock(uint8_t *key_stream, SCRadixTree *tree, + void *user, int netmask) +{ + SCRadixNode *node = SCRadixAddKey(key_stream, 128, tree, user, netmask); return node; } @@ -443,7 +538,7 @@ static void SCRadixRemoveKey(uint8_t *key_stream, uint16_t key_bitlen, if (node == NULL) return; - if ( (prefix = SCRadixCreatePrefix(key_stream, key_bitlen, NULL)) == NULL) + if ( (prefix = SCRadixCreatePrefix(key_stream, key_bitlen, NULL, -1)) == NULL) return; while (node->bit < prefix->bitlen) { @@ -556,25 +651,94 @@ void SCRadixRemoveKeyIPV6(uint8_t *key_stream, SCRadixTree *tree) return SCRadixRemoveKey(key_stream, 128, tree); } + /** - * \brief Checks if a key is present in the tree + * \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(SCRadixPrefix *prefix, + SCRadixNode *node) +{ + SCRadixNode *netmask_node = NULL; + int 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 < node->netmask_cnt; j++) { + bytes = prefix->bitlen / 8; + for (i = 0; i < bytes; i++) { + mask = -1; + if ( ((i + 1) * 8) > node->netmasks[j]) { + if ( ((i + 1) * 8 - node->netmasks[j]) < 8) + mask = -1 << ((i + 1) * 8 - node->netmasks[j]); + else + mask = 0; + } + prefix->stream[i] &= mask; + } + + 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) + return NULL; + } + + if (node->bit != prefix->bitlen || node->prefix == NULL) + return NULL; + + if (memcmp(node->prefix->stream, prefix->stream, bytes) == 0) { + mask = -1 << (8 - prefix->bitlen % 8); + + if (prefix->bitlen % 8 == 0 || + (node->prefix->stream[bytes] & mask) == (prefix->stream[bytes] & mask)) + return node; + } + } + + return SCRadixFindKeyIPNetblock(prefix, netmask_node->parent); +} + +/** + * \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 is_ip_key The key to be searched is an ip address */ static SCRadixNode *SCRadixFindKey(uint8_t *key_stream, uint16_t key_bitlen, - SCRadixTree *tree) + SCRadixTree *tree, int is_ip_key) { SCRadixNode *node = tree->head; SCRadixPrefix *prefix = NULL; int mask = 0; - int i = 0; + int bytes = 0; if (tree->head == NULL) return NULL; - if ( (prefix = SCRadixCreatePrefix(key_stream, key_bitlen, NULL)) == NULL) + if ( (prefix = SCRadixCreatePrefix(key_stream, key_bitlen, NULL, -1)) == NULL) return NULL; while (node->bit < prefix->bitlen) { @@ -592,16 +756,20 @@ static SCRadixNode *SCRadixFindKey(uint8_t *key_stream, uint16_t key_bitlen, if (node->bit != prefix->bitlen || node->prefix == NULL) return NULL; - i = prefix->bitlen / 8; - if (memcmp(node->prefix->stream, prefix->stream, i) == 0) { + bytes = prefix->bitlen / 8; + if (memcmp(node->prefix->stream, prefix->stream, bytes) == 0) { mask = -1 << (8 - prefix->bitlen % 8); if (prefix->bitlen % 8 == 0 || - (node->prefix->stream[i] & mask) == (prefix->stream[i] & mask)) + (node->prefix->stream[bytes] & mask) == (prefix->stream[bytes] & mask)) return node; } - return NULL; + /* if you are not an ip key, get out of here */ + if (is_ip_key == 0) + return NULL; + + return SCRadixFindKeyIPNetblock(prefix, node); } /** @@ -614,7 +782,7 @@ static SCRadixNode *SCRadixFindKey(uint8_t *key_stream, uint16_t key_bitlen, SCRadixNode *SCRadixFindKeyGeneric(uint8_t *key_stream, uint16_t key_bitlen, SCRadixTree *tree) { - return SCRadixFindKey(key_stream, key_bitlen, tree); + return SCRadixFindKey(key_stream, key_bitlen, tree, 0); } /** @@ -626,7 +794,7 @@ SCRadixNode *SCRadixFindKeyGeneric(uint8_t *key_stream, uint16_t key_bitlen, */ SCRadixNode *SCRadixFindKeyIPV4(uint8_t *key_stream, SCRadixTree *tree) { - return SCRadixFindKey(key_stream, 32, tree); + return SCRadixFindKey(key_stream, 32, tree, 1); } /** @@ -638,7 +806,7 @@ SCRadixNode *SCRadixFindKeyIPV4(uint8_t *key_stream, SCRadixTree *tree) */ SCRadixNode *SCRadixFindKeyIPV6(uint8_t *key_stream, SCRadixTree *tree) { - return SCRadixFindKey(key_stream, 128, tree); + return SCRadixFindKey(key_stream, 128, tree, 1); } /** @@ -655,9 +823,17 @@ static void SCRadixPrintNodeInfo(SCRadixNode *node, int level) return; for (i = 0; i < level; i++) - printf(" "); + printf(" "); + + printf("%d [", node->bit); + + if (node->netmasks == NULL) + printf("%d, ", -1); - printf("%d (", node->bit); + for (i = 0; i < node->netmask_cnt; i++) + printf("%d, ", node->netmasks[i]); + + printf("] ("); if (node->prefix != NULL) { for (i = 0; i * 8 < node->prefix->bitlen; i++) { if (i != 0) @@ -1429,6 +1605,661 @@ int SCRadixTestIPV6Removal08(void) return result; } +int SCRadixTestIPV4NetblockInsertion09(void) +{ + SCRadixTree *tree = NULL; + struct sockaddr_in servaddr; + int result = 1; + + tree = SCRadixCreateRadixTree(NULL); + + /* add the keys */ + bzero(&servaddr, 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); + + bzero(&servaddr, 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); + + bzero(&servaddr, 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); + + bzero(&servaddr, 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); + + bzero(&servaddr, 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); + + bzero(&servaddr, 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); + + bzero(&servaddr, 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); + + bzero(&servaddr, 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); + + bzero(&servaddr, 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); + + bzero(&servaddr, 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 existance of a key */ + bzero(&servaddr, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.168.1.6", &servaddr.sin_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV4((uint8_t *)&servaddr.sin_addr, tree) != NULL); + + bzero(&servaddr, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.170.1.6", &servaddr.sin_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV4((uint8_t *)&servaddr.sin_addr, tree) == NULL); + + bzero(&servaddr, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.171.128.145", &servaddr.sin_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV4((uint8_t *)&servaddr.sin_addr, tree) != NULL); + + bzero(&servaddr, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.171.64.6", &servaddr.sin_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV4((uint8_t *)&servaddr.sin_addr, tree) == NULL); + + bzero(&servaddr, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.171.191.6", &servaddr.sin_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV4((uint8_t *)&servaddr.sin_addr, tree) == NULL); + + bzero(&servaddr, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.171.224.6", &servaddr.sin_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV4((uint8_t *)&servaddr.sin_addr, tree) != NULL); + + bzero(&servaddr, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.174.224.6", &servaddr.sin_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV4((uint8_t *)&servaddr.sin_addr, tree) == NULL); + + bzero(&servaddr, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.175.224.6", &servaddr.sin_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV4((uint8_t *)&servaddr.sin_addr, tree) != NULL); + + SCRadixReleaseRadixTree(tree); + + return result; +} + +int SCRadixTestIPV4NetblockInsertion10(void) +{ + SCRadixTree *tree = NULL; + SCRadixNode *node[2]; + struct sockaddr_in servaddr; + int result = 1; + + tree = SCRadixCreateRadixTree(NULL); + + /* add the keys */ + bzero(&servaddr, 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); + + bzero(&servaddr, 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); + + bzero(&servaddr, 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); + + bzero(&servaddr, 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); + + bzero(&servaddr, 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); + + bzero(&servaddr, 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); + + bzero(&servaddr, 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); + + bzero(&servaddr, 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); + + bzero(&servaddr, 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); + + bzero(&servaddr, 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); + + /* test for the existance of a key */ + bzero(&servaddr, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.171.128.53", &servaddr.sin_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV4((uint8_t *)&servaddr.sin_addr, tree) == node[0]); + + bzero(&servaddr, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.171.128.45", &servaddr.sin_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV4((uint8_t *)&servaddr.sin_addr, tree) == node[1]); + + bzero(&servaddr, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.171.128.78", &servaddr.sin_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV4((uint8_t *)&servaddr.sin_addr, tree) == node[0]); + + bzero(&servaddr, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.171.127.78", &servaddr.sin_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV4((uint8_t *)&servaddr.sin_addr, tree) == NULL); + + SCRadixReleaseRadixTree(tree); + + return result; +} + +int SCRadixTestIPV4NetblockInsertion11(void) +{ + SCRadixTree *tree = NULL; + SCRadixNode *node = NULL; + struct sockaddr_in servaddr; + int result = 1; + + tree = SCRadixCreateRadixTree(NULL); + + /* add the keys */ + bzero(&servaddr, 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); + + bzero(&servaddr, 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); + + bzero(&servaddr, 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); + + bzero(&servaddr, 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); + + bzero(&servaddr, 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); + + bzero(&servaddr, 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); + + bzero(&servaddr, 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); + + bzero(&servaddr, 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); + + bzero(&servaddr, 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); + + bzero(&servaddr, 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 existance of a key */ + bzero(&servaddr, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.171.128.53", &servaddr.sin_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV4((uint8_t *)&servaddr.sin_addr, tree) != NULL); + + bzero(&servaddr, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.171.128.45", &servaddr.sin_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV4((uint8_t *)&servaddr.sin_addr, tree) != NULL); + + bzero(&servaddr, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.171.128.78", &servaddr.sin_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV4((uint8_t *)&servaddr.sin_addr, tree) != NULL); + + bzero(&servaddr, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.171.127.78", &servaddr.sin_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV4((uint8_t *)&servaddr.sin_addr, tree) == node); + + bzero(&servaddr, sizeof(servaddr)); + if (inet_pton(AF_INET, "1.1.1.1", &servaddr.sin_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV4((uint8_t *)&servaddr.sin_addr, tree) == node); + + bzero(&servaddr, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.255.254.25", &servaddr.sin_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV4((uint8_t *)&servaddr.sin_addr, tree) == node); + + bzero(&servaddr, sizeof(servaddr)); + if (inet_pton(AF_INET, "169.255.254.25", &servaddr.sin_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV4((uint8_t *)&servaddr.sin_addr, tree) == node); + + bzero(&servaddr, sizeof(servaddr)); + if (inet_pton(AF_INET, "0.0.0.0", &servaddr.sin_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV4((uint8_t *)&servaddr.sin_addr, tree) == node); + + bzero(&servaddr, sizeof(servaddr)); + if (inet_pton(AF_INET, "253.224.1.5", &servaddr.sin_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV4((uint8_t *)&servaddr.sin_addr, tree) != NULL && + SCRadixFindKeyIPV4((uint8_t *)&servaddr.sin_addr, tree) != node); + + bzero(&servaddr, sizeof(servaddr)); + if (inet_pton(AF_INET, "245.63.62.121", &servaddr.sin_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV4((uint8_t *)&servaddr.sin_addr, tree) != NULL && + SCRadixFindKeyIPV4((uint8_t *)&servaddr.sin_addr, tree) == node); + + bzero(&servaddr, sizeof(servaddr)); + if (inet_pton(AF_INET, "253.224.1.6", &servaddr.sin_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV4((uint8_t *)&servaddr.sin_addr, tree) != NULL && + SCRadixFindKeyIPV4((uint8_t *)&servaddr.sin_addr, tree) == node); + + SCRadixReleaseRadixTree(tree); + + return result; +} + +int SCRadixTestIPV4NetblockInsertion12(void) +{ + SCRadixTree *tree = NULL; + SCRadixNode *node[2]; + struct sockaddr_in servaddr; + int result = 1; + + tree = SCRadixCreateRadixTree(NULL); + + /* add the keys */ + bzero(&servaddr, 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); + + bzero(&servaddr, 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); + + bzero(&servaddr, 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); + + bzero(&servaddr, 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); + + bzero(&servaddr, 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); + + bzero(&servaddr, 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); + + bzero(&servaddr, 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); + + bzero(&servaddr, 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); + + bzero(&servaddr, 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); + + bzero(&servaddr, 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 existance of a key */ + bzero(&servaddr, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.171.128.53", &servaddr.sin_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV4((uint8_t *)&servaddr.sin_addr, tree) == node[0]); + + bzero(&servaddr, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.171.128.45", &servaddr.sin_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV4((uint8_t *)&servaddr.sin_addr, tree) == node[1]); + + bzero(&servaddr, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.171.128.78", &servaddr.sin_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV4((uint8_t *)&servaddr.sin_addr, tree) == node[0]); + + bzero(&servaddr, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.171.127.78", &servaddr.sin_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV4((uint8_t *)&servaddr.sin_addr, tree) == NULL); + + bzero(&servaddr, sizeof(servaddr)); + if (inet_pton(AF_INET, "225.175.21.228", &servaddr.sin_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV4((uint8_t *)&servaddr.sin_addr, tree) != NULL); + + bzero(&servaddr, sizeof(servaddr)); + if (inet_pton(AF_INET, "225.175.21.224", &servaddr.sin_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV4((uint8_t *)&servaddr.sin_addr, tree) == NULL); + + bzero(&servaddr, sizeof(servaddr)); + if (inet_pton(AF_INET, "225.175.21.229", &servaddr.sin_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV4((uint8_t *)&servaddr.sin_addr, tree) == NULL); + + bzero(&servaddr, sizeof(servaddr)); + if (inet_pton(AF_INET, "225.175.21.230", &servaddr.sin_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV4((uint8_t *)&servaddr.sin_addr, tree) == NULL); + + SCRadixReleaseRadixTree(tree); + + return result; +} + +int SCRadixTestIPV6NetblockInsertion13(void) +{ + SCRadixTree *tree = NULL; + struct sockaddr_in6 servaddr; + int result = 1; + + tree = SCRadixCreateRadixTree(NULL); + + /* add the keys */ + bzero(&servaddr, 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); + + bzero(&servaddr, 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); + + bzero(&servaddr, 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); + + bzero(&servaddr, 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); + + bzero(&servaddr, 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); + + bzero(&servaddr, 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); + + bzero(&servaddr, 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 */ + bzero(&servaddr, sizeof(servaddr)); + if (inet_pton(AF_INET6, "2003:0BF1:5346:BDEA:7422:8713:9124:2315", + &servaddr.sin6_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree) != NULL); + + bzero(&servaddr, sizeof(servaddr)); + if (inet_pton(AF_INET6, "BD15:9791:5346:6223:AADB:8713:9882:2432", + &servaddr.sin6_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree) != NULL); + + bzero(&servaddr, sizeof(servaddr)); + if (inet_pton(AF_INET6, "1111:A21B:6221:BDEA:BBBA::DBAA:9861", + &servaddr.sin6_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree) != NULL); + + bzero(&servaddr, sizeof(servaddr)); + if (inet_pton(AF_INET6, "4444:0BF7:5346:BDEA:7422:8713:9124:2315", + &servaddr.sin6_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree) != NULL); + + bzero(&servaddr, sizeof(servaddr)); + if (inet_pton(AF_INET6, "DBCA:ABC2:ABCD:DBCA:1245:2342:1111:2212", + &servaddr.sin6_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree) == NULL); + + bzero(&servaddr, sizeof(servaddr)); + if (inet_pton(AF_INET6, "2003:0BF5:5346:1251:7422:1112:9124:2315", + &servaddr.sin6_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree) == NULL); + + bzero(&servaddr, sizeof(servaddr)); + if (inet_pton(AF_INET6, "5555:0BF1:ABCD:ADEA:7922:ABCD:9124:2375", + &servaddr.sin6_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree) != NULL); + + bzero(&servaddr, sizeof(servaddr)); + if (inet_pton(AF_INET6, "DBCA:ABCD:ABCD:DBCA:1245:2342:1111:2212", + &servaddr.sin6_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree) != NULL); + + bzero(&servaddr, sizeof(servaddr)); + if (inet_pton(AF_INET6, "DBCA:ABCD:ABCD:DBAA:1245:2342:1146:6241", + &servaddr.sin6_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree) != NULL); + + bzero(&servaddr, sizeof(servaddr)); + if (inet_pton(AF_INET6, "DBCA:ABCD:ABCD:DBAA:1245:2342:1356:1241", + &servaddr.sin6_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree) != NULL); + + bzero(&servaddr, sizeof(servaddr)); + if (inet_pton(AF_INET6, "DBCA:ABCD:ABCD:DAAA:1245:2342:1146:6241", + &servaddr.sin6_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree) == NULL); + + + SCRadixReleaseRadixTree(tree); + + return result; +} + +int SCRadixTestIPV6NetblockInsertion14(void) +{ + SCRadixTree *tree = NULL; + SCRadixNode *node = NULL; + struct sockaddr_in6 servaddr; + int result = 1; + + tree = SCRadixCreateRadixTree(NULL); + + /* add the keys */ + bzero(&servaddr, 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); + + bzero(&servaddr, 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); + + bzero(&servaddr, 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); + + bzero(&servaddr, 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); + + bzero(&servaddr, 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); + + bzero(&servaddr, 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); + + bzero(&servaddr, 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); + + bzero(&servaddr, 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 */ + bzero(&servaddr, sizeof(servaddr)); + if (inet_pton(AF_INET6, "2004:0BF1:5346:BDEA:7422:8713:9124:2315", + &servaddr.sin6_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree) == node); + + bzero(&servaddr, sizeof(servaddr)); + if (inet_pton(AF_INET6, "2004:0BF1:5346:B116:2362:8713:9124:2315", + &servaddr.sin6_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree) == node); + + bzero(&servaddr, sizeof(servaddr)); + if (inet_pton(AF_INET6, "2004:0B23:3252:BDEA:7422:8713:9124:2341", + &servaddr.sin6_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree) == node); + + bzero(&servaddr, sizeof(servaddr)); + if (inet_pton(AF_INET6, "DBCA:ABCD:ABCD:DBAA:1245:2342:1145:6241", + &servaddr.sin6_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree) != NULL && + SCRadixFindKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree) != node); + + SCRadixReleaseRadixTree(tree); + + return result; +} + #endif void SCRadixRegisterTests(void) @@ -1446,6 +2277,18 @@ void SCRadixRegisterTests(void) SCRadixTestCharacterRemoval06, 1); UtRegisterTest("SCRadixTestIPV6Insertion07", SCRadixTestIPV6Insertion07, 1); UtRegisterTest("SCRadixTestIPV6Removal08", SCRadixTestIPV6Removal08, 1); + UtRegisterTest("SCRadixTestIPV4NetblockInsertion09", + SCRadixTestIPV4NetblockInsertion09, 1); + UtRegisterTest("SCRadixTestIPV4NetblockInsertion10", + SCRadixTestIPV4NetblockInsertion10, 1); + UtRegisterTest("SCRadixTestIPV4NetblockInsertion11", + SCRadixTestIPV4NetblockInsertion11, 1); + UtRegisterTest("SCRadixTestIPV4NetblockInsertion12", + SCRadixTestIPV4NetblockInsertion12, 1); + UtRegisterTest("SCRadixTestIPV6NetblockInsertion13", + SCRadixTestIPV6NetblockInsertion13, 1); + UtRegisterTest("SCRadixTestIPV6NetblockInsertion14", + SCRadixTestIPV6NetblockInsertion14, 1); #endif diff --git a/src/util-radix-tree.h b/src/util-radix-tree.h index 43af1e05c4..675803a6e7 100644 --- a/src/util-radix-tree.h +++ b/src/util-radix-tree.h @@ -17,6 +17,10 @@ typedef struct SCRadixPrefix_ { /* the key that has been stored in the tree */ uint8_t *stream; + /* if this is a prefix that holds a netblock, this field holds the + * netmask, -1 otherwise */ + int netmask; + /* any user data that has to be associated with this key */ void *user; } SCRadixPrefix; @@ -29,6 +33,11 @@ typedef struct SCRadixNode_ { * to determine the path to be taken during a lookup*/ uint16_t bit; + /* holds a list of netmaks that come under this node in the tree */ + int *netmasks; + /* total no of netmasks that are registered under this node */ + int netmask_cnt; + /* holds the prefix that the path to this node holds */ SCRadixPrefix *prefix; @@ -58,6 +67,8 @@ void SCRadixReleaseRadixTree(SCRadixTree *); SCRadixNode *SCRadixAddKeyGeneric(uint8_t *, uint16_t, SCRadixTree *, void *); SCRadixNode *SCRadixAddKeyIPV4(uint8_t *, SCRadixTree *, void *); SCRadixNode *SCRadixAddKeyIPV6(uint8_t *, SCRadixTree *, void *); +SCRadixNode *SCRadixAddKeyIPV4Netblock(uint8_t *, SCRadixTree *, void *, int); +SCRadixNode *SCRadixAddKeyIPV6Netblock(uint8_t *, SCRadixTree *, void *, int); void SCRadixRemoveKeyGeneric(uint8_t *, uint16_t, SCRadixTree *); void SCRadixRemoveKeyIPV4(uint8_t *, SCRadixTree *);