radix: improve address range handling

Handle non-exact address ranges from string. This can come directly
from user input, so here it is accepted but the address is converted
to the address range start. A warning will be issued.

Debug validation checks are added to catch this.

This issue could lead to bad input from iprep (with cidr), defrag config
and htp server personalities to produce a bad radix tree.

Bug: #5084.
Bug: #5085.
Bug: #5086.
pull/7018/head
Victor Julien 4 years ago
parent 51d4e0dced
commit 7fd6fe732b

@ -31,6 +31,8 @@
#include "util-unittest.h"
#include "util-memcmp.h"
#include "util-byte.h"
#include "util-cidr.h"
#include "util-print.h"
/**
* \brief Allocates and returns a new instance of SCRadixUserData.
@ -881,6 +883,49 @@ SCRadixNode *SCRadixAddKeyIPV6(uint8_t *key_stream, SCRadixTree *tree,
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
*
@ -896,6 +941,9 @@ SCRadixNode *SCRadixAddKeyIPV6(uint8_t *key_stream, SCRadixTree *tree,
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;
@ -916,6 +964,9 @@ SCRadixNode *SCRadixAddKeyIPV4Netblock(uint8_t *key_stream, SCRadixTree *tree,
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;
@ -966,7 +1017,19 @@ SCRadixNode *SCRadixAddKeyIPV4String(const char *str, SCRadixTree *tree, void *u
return NULL;
}
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(SC_ERR_INVALID_IP_NETBLOCK, "adding '%s' as '%s/%u'", str, nstr, netmask);
ip = masked;
}
#if defined(DEBUG_VALIDATION) || defined(UNITTESTS)
SCRadixValidateIPv4Key((uint8_t *)&ip, netmask);
#endif
}
return SCRadixAddKey((uint8_t *)&ip, 32, tree, user, netmask);
}
@ -1014,6 +1077,20 @@ SCRadixNode *SCRadixAddKeyIPV6String(const char *str, SCRadixTree *tree, void *u
return NULL;
}
if (netmask != 128) {
struct in6_addr mask6;
CIDRGetIPv6(netmask, &mask6);
for (int i = 0; i < 16; i++) {
addr.s6_addr[i] &= mask6.s6_addr[i];
}
char nstr[64];
PrintInet(AF_INET6, (void *)&addr.s6_addr, nstr, sizeof(nstr));
SCLogWarning(SC_ERR_INVALID_IP_NETBLOCK, "adding '%s' as '%s/%u'", str, nstr, netmask);
#if defined(DEBUG_VALIDATION) || defined(UNITTESTS)
SCRadixValidateIPv6Key((uint8_t *)&addr.s6_addr, netmask);
#endif
}
return SCRadixAddKey(addr.s6_addr, 128, tree, user, netmask);
}
@ -1271,6 +1348,9 @@ void SCRadixRemoveKeyGeneric(uint8_t *key_stream, uint16_t key_bitlen,
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);
return;
}
@ -1302,6 +1382,9 @@ void SCRadixRemoveKeyIPV4(uint8_t *key_stream, SCRadixTree *tree)
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);
return;
}
@ -1502,6 +1585,9 @@ SCRadixNode *SCRadixFindKeyIPV4BestMatch(uint8_t *key_stream, SCRadixTree *tree,
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, 1, user_data_result);
return node;
}
@ -1516,6 +1602,9 @@ SCRadixNode *SCRadixFindKeyIPV4Netblock(uint8_t *key_stream, SCRadixTree *tree,
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, 1, user_data_result);
return node;
}

Loading…
Cancel
Save