]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
radix: Detect duplicate netblocks 9306/head
authorJeff Lucovsky <jlucovsky@oisf.net>
Mon, 24 Apr 2023 13:56:01 +0000 (09:56 -0400)
committerVictor Julien <victor@inliniac.net>
Sun, 30 Jul 2023 12:22:52 +0000 (14:22 +0200)
This commit prevents duplicate IPV4/IPV6 netblocks from being added to the
radix tree.

Contributed by Giuseppe Longo <giuseppe@glongo.it>

Issue: 5748

src/app-layer-htp.c
src/defrag-config.c
src/reputation.c
src/util-radix-tree.c
src/util-radix-tree.h

index 312ca78ba29f8806b34be88b133e2991b248a1a1..b576ba3b7b975231f7e1e8f78c3aa1eabb16ce60 100644 (file)
@@ -2606,7 +2606,7 @@ 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);
@@ -2614,7 +2614,7 @@ static void HTPConfigParseParameters(HTPCfgRec *cfg_prec, ConfNode *s,
                 } 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);
index 9e565c66b0a837adcf014b053e200ee13d976f32..7e2ae0cde96a0b0a502df364c7f9efceb1053b87 100644 (file)
@@ -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);
+            }
         }
     }
 }
index 23080620c1c1c2de0e9ebd6ccf02b78e06f5d976..b9f2186d0100a89fb1b57531efd1d4a1470d39dc 100644 (file)
@@ -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 {
@@ -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);
         }
     }
 }
index d5601ba0546e53f2d13086d7d0f879388126995e..97c85602d8a0a163309517b788a9cc7cf60b5503 100644 (file)
@@ -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;
@@ -506,6 +507,7 @@ static SCRadixNode *SCRadixAddKey(
 
     if (tree == NULL) {
         SCLogError("Argument \"tree\" NULL");
+        sc_errno = SC_EINVAL;
         return NULL;
     }
 
@@ -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
@@ -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;
@@ -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
@@ -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;
@@ -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();
@@ -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;
                 }
 
@@ -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
  *
@@ -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;
@@ -980,12 +1013,14 @@ 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;
@@ -993,7 +1028,8 @@ SCRadixNode *SCRadixAddKeyIPV4String(const char *str, SCRadixTree *tree, void *u
 
     /* 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) {
@@ -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;
 }
 
 /**
@@ -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 */
@@ -1040,12 +1087,14 @@ 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;
@@ -1053,7 +1102,8 @@ SCRadixNode *SCRadixAddKeyIPV6String(const char *str, SCRadixTree *tree, void *u
 
     /* Validate the IP */
     if (inet_pton(AF_INET6, ip_str, &addr) <= 0) {
-        return NULL;
+        sc_errno = SC_EINVAL;
+        return false;
     }
 
     if (netmask != 128) {
@@ -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)
index c8fdef689ab184f261319c1603a8b18a0b6bd6ba..c43e14eb01265d56c9309d705bc7de708920b6e9 100644 (file)
@@ -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);