Skip to content

Commit

Permalink
radix: Detect duplicate netblocks
Browse files Browse the repository at this point in the history
This commit prevents duplicate IPV4/IPV6 netblocks from being added to the
radix tree.

Contributed by Giuseppe Longo <[email protected]>

Issue: 5748
  • Loading branch information
jlucovsky committed Jul 24, 2023
1 parent 291e6ee commit 9e80d74
Show file tree
Hide file tree
Showing 5 changed files with 92 additions and 27 deletions.
4 changes: 2 additions & 2 deletions src/app-layer-htp.c
Original file line number Diff line number Diff line change
Expand Up @@ -2606,15 +2606,15 @@ static void HTPConfigParseParameters(HTPCfgRec *cfg_prec, ConfNode *s,
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) == NULL) {
if (!SCRadixAddKeyIPV6String(pval->val, tree, 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) == NULL) {
if (!SCRadixAddKeyIPV4String(pval->val, tree, cfg_prec)) {
SCLogWarning("LIBHTP failed "
"to add ipv4 server %s, ignoring",
pval->val);
Expand Down
14 changes: 10 additions & 4 deletions src/defrag-config.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,19 @@ 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) == NULL) {
SCLogWarning("failed to add ipv6 host %s", host_ip_range);
if (!SCRadixAddKeyIPV6String(host_ip_range, defrag_tree, (void *)user_data)) {
SCFree(user_data);
if (sc_errno != SC_EEXIST) {
SCLogWarning("failed to add ipv6 host %s", host_ip_range);
}
}
} else {
SCLogDebug("adding ipv4 host %s", host_ip_range);
if (SCRadixAddKeyIPV4String(host_ip_range, defrag_tree, (void *)user_data) == NULL) {
SCLogWarning("failed to add ipv4 host %s", host_ip_range);
if (!SCRadixAddKeyIPV4String(host_ip_range, defrag_tree, (void *)user_data)) {
SCFree(user_data);
if (sc_errno != SC_EEXIST) {
SCLogWarning("failed to add ipv4 host %s", host_ip_range);
}
}
}
}
Expand Down
10 changes: 6 additions & 4 deletions src/reputation.c
Original file line number Diff line number Diff line change
Expand Up @@ -99,9 +99,10 @@ static void SRepCIDRAddNetblock(SRepCIDRTree *cidr_ctx, char *ip, int cat, uint8
}

SCLogDebug("adding ipv6 host %s", ip);
if (SCRadixAddKeyIPV6String(ip, cidr_ctx->srepIPV6_tree[cat], (void *)user_data) == NULL) {
if (!SCRadixAddKeyIPV6String(ip, cidr_ctx->srepIPV6_tree[cat], (void *)user_data)) {
SCFree(user_data);
SCLogWarning("failed to add ipv6 host %s", ip);
if (sc_errno != SC_EEXIST)
SCLogWarning("failed to add ipv6 host %s", ip);
}

} else {
Expand All @@ -115,9 +116,10 @@ static void SRepCIDRAddNetblock(SRepCIDRTree *cidr_ctx, char *ip, int cat, uint8
}

SCLogDebug("adding ipv4 host %s", ip);
if (SCRadixAddKeyIPV4String(ip, cidr_ctx->srepIPV4_tree[cat], (void *)user_data) == NULL) {
if (!SCRadixAddKeyIPV4String(ip, cidr_ctx->srepIPV4_tree[cat], (void *)user_data)) {
SCFree(user_data);
SCLogWarning("failed to add ipv4 host %s", ip);
if (sc_errno != SC_EEXIST)
SCLogWarning("failed to add ipv4 host %s", ip);
}
}
}
Expand Down
87 changes: 72 additions & 15 deletions src/util-radix-tree.c
Original file line number Diff line number Diff line change
Expand Up @@ -482,11 +482,12 @@ void SCRadixReleaseRadixTree(SCRadixTree *tree)
* 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 *SCRadixAddKey(
uint8_t *key_stream, uint8_t key_bitlen, SCRadixTree *tree, void *user, uint8_t netmask)
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;
Expand All @@ -506,6 +507,7 @@ static SCRadixNode *SCRadixAddKey(

if (tree == NULL) {
SCLogError("Argument \"tree\" NULL");
sc_errno = SC_EINVAL;
return NULL;
}

Expand All @@ -518,18 +520,23 @@ static SCRadixNode *SCRadixAddKey(
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))
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
Expand All @@ -545,6 +552,7 @@ static SCRadixNode *SCRadixAddKey(
SCFree(node->netmasks);
node->netmasks = NULL;
SCLogError("Fatal error encountered in SCRadixAddKey. Mem not allocated");
sc_errno = SC_ENOMEM;
return NULL;
}
node->netmasks = ptmp;
Expand Down Expand Up @@ -640,6 +648,11 @@ static SCRadixNode *SCRadixAddKey(
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
Expand Down Expand Up @@ -672,6 +685,7 @@ static SCRadixNode *SCRadixAddKey(
SCFree(node->netmasks);
node->netmasks = NULL;
SCLogError("Fatal error encountered in SCRadixAddKey. Mem not allocated...");
sc_errno = SC_ENOMEM;
return NULL;
}
node->netmasks = ptmp;
Expand Down Expand Up @@ -705,6 +719,7 @@ static SCRadixNode *SCRadixAddKey(
if ( (prefix = SCRadixCreatePrefix(key_stream, key_bitlen, user,
netmask)) == NULL) {
SCLogError("Error creating prefix");
sc_errno = SC_EINVAL;
return NULL;
}
new_node = SCRadixCreateNode();
Expand Down Expand Up @@ -754,6 +769,7 @@ static SCRadixNode *SCRadixAddKey(
SCLogError("Fatal error encountered in SCRadixAddKey. Mem not allocated...");
SCRadixReleaseNode(inter_node, tree);
SCRadixReleaseNode(new_node, tree);
sc_errno = SC_ENOMEM;
return NULL;
}

Expand Down Expand Up @@ -824,6 +840,18 @@ static SCRadixNode *SCRadixAddKey(
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
*
Expand Down Expand Up @@ -959,9 +987,14 @@ SCRadixNode *SCRadixAddKeyIPV6Netblock(uint8_t *key_stream, SCRadixTree *tree,
* \param user Pointer to the user data that has to be associated with
* the key
*
* \retval node Pointer to the newly created node
* \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
*/
SCRadixNode *SCRadixAddKeyIPV4String(const char *str, SCRadixTree *tree, void *user)
bool SCRadixAddKeyIPV4String(const char *str, SCRadixTree *tree, void *user)
{
uint32_t ip;
uint8_t netmask = 32;
Expand All @@ -980,20 +1013,23 @@ SCRadixNode *SCRadixAddKeyIPV4String(const char *str, SCRadixTree *tree, void *u

/* Dotted type netmask not supported (yet) */
if (strchr(mask_str, '.') != NULL) {
return 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) {
return NULL;
sc_errno = SC_EINVAL;
return false;
}

netmask = (uint8_t)cidr;
}

/* Validate the IP */
if (inet_pton(AF_INET, ip_str, &addr) <= 0) {
return NULL;
sc_errno = SC_EINVAL;
return false;
}
ip = addr.s_addr;
if (netmask != 32) {
Expand All @@ -1009,7 +1045,14 @@ SCRadixNode *SCRadixAddKeyIPV4String(const char *str, SCRadixTree *tree, void *u
SCRadixValidateIPv4Key((uint8_t *)&ip, netmask);
#endif
}
return SCRadixAddKey((uint8_t *)&ip, 32, tree, user, netmask);

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;
}

/**
Expand All @@ -1020,9 +1063,13 @@ SCRadixNode *SCRadixAddKeyIPV4String(const char *str, SCRadixTree *tree, void *u
* \param user Pointer to the user data that has to be associated with
* the key
*
* \retval node Pointer to the newly created node
* \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
*/
SCRadixNode *SCRadixAddKeyIPV6String(const char *str, SCRadixTree *tree, void *user)
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 */
Expand All @@ -1040,20 +1087,23 @@ SCRadixNode *SCRadixAddKeyIPV6String(const char *str, SCRadixTree *tree, void *u

/* Dotted type netmask not supported (yet) */
if (strchr(mask_str, '.') != NULL) {
return 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) {
return NULL;
sc_errno = SC_EINVAL;
return false;
}

netmask = (uint8_t)cidr;
}

/* Validate the IP */
if (inet_pton(AF_INET6, ip_str, &addr) <= 0) {
return NULL;
sc_errno = SC_EINVAL;
return false;
}

if (netmask != 128) {
Expand All @@ -1075,7 +1125,14 @@ SCRadixNode *SCRadixAddKeyIPV6String(const char *str, SCRadixTree *tree, void *u
#endif
}

return SCRadixAddKey(addr.s6_addr, 128, tree, user, netmask);
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)
Expand Down
4 changes: 2 additions & 2 deletions src/util-radix-tree.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,8 +102,8 @@ SCRadixNode *SCRadixAddKeyIPV4Netblock(uint8_t *, SCRadixTree *, void *,
uint8_t);
SCRadixNode *SCRadixAddKeyIPV6Netblock(uint8_t *, SCRadixTree *, void *,
uint8_t);
SCRadixNode *SCRadixAddKeyIPV4String(const char *, SCRadixTree *, void *);
SCRadixNode *SCRadixAddKeyIPV6String(const char *, SCRadixTree *, void *);
bool SCRadixAddKeyIPV4String(const char *, SCRadixTree *, void *);
bool SCRadixAddKeyIPV6String(const char *, SCRadixTree *, void *);

void SCRadixRemoveKeyGeneric(uint8_t *, uint16_t, SCRadixTree *);
void SCRadixRemoveKeyIPV4Netblock(uint8_t *, SCRadixTree *, uint8_t);
Expand Down

0 comments on commit 9e80d74

Please sign in to comment.