]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
xff: support ports and more ipv6 notations
authorVictor Julien <victor@inliniac.net>
Tue, 21 Jul 2015 15:27:26 +0000 (17:27 +0200)
committerVictor Julien <victor@inliniac.net>
Thu, 23 Jul 2015 17:58:59 +0000 (19:58 +0200)
It's not uncommon to see an header like:
X-Forwarded-For: 1.2.3.4:56789

This patch recognizes this case and ignores the port. It also supports
this for IPv6 if the address has the following notation:
X-Forwarded-For: [12::34]:1234

This patch also adds unittests.

src/app-layer-htp-xff.c
src/app-layer-htp-xff.h
src/app-layer-htp.c

index 5be84bbdb75f306c448c8b49d4e7604a7120fa9e..96c6de487f751e47976c4be6ab4e5fc0bc330ea9 100644 (file)
@@ -31,6 +31,7 @@
 
 #include "util-misc.h"
 #include "util-memrchr.h"
+#include "util-unittest.h"
 
 /** XFF header value minimal length */
 #define XFF_CHAIN_MINLEN 7
 /** Default XFF header name */
 #define XFF_DEFAULT "X-Forwarded-For"
 
+/** \internal
+ *  \brief parse XFF string
+ *  \param input input string, might be modified
+ *  \param output output buffer
+ *  \param output_size size of output buffer
+ *  \retval bool 1 ok, 0 fail
+ */
+static int ParseXFFString(char *input, char *output, int output_size)
+{
+    size_t len = strlen(input);
+    if (len == 0)
+        return 0;
+
+    if (input[0] == '[') {
+        char *end = strchr(input, ']');
+        if (end == NULL) // malformed, not closed
+            return 0;
+
+        if (end != input+(len - 1)) {
+            SCLogDebug("data after closing bracket");
+            // if we ever want to parse the port, we can do it here
+        }
+
+        /* done, lets wrap up */
+        input++;        // skip past [
+        *end = '\0';    // overwrite ], ignore anything after
+
+    } else {
+        /* lets see if the xff string ends in a port */
+        int c = 0;
+        int d = 0;
+        char *p = input;
+        while (*p != '\0') {
+            if (*p == ':')
+                c++;
+            if (*p == '.')
+                d++;
+            p++;
+        }
+        /* 3 dots: ipv4, one ':' port */
+        if (d == 3 && c == 1) {
+            SCLogDebug("XFF w port %s", input);
+            char *x = strchr(input, ':');
+            if (x) {
+                *x = '\0';
+                SCLogDebug("XFF w/o port %s", input);
+                // if we ever want to parse the port, we can do it here
+            }
+        }
+    }
+
+    SCLogDebug("XFF %s", input);
+
+    /** Sanity check on extracted IP for IPv4 and IPv6 */
+    uint32_t ip[4];
+    if (inet_pton(AF_INET,  input, ip) == 1 ||
+        inet_pton(AF_INET6, input, ip) == 1)
+    {
+        strlcpy(output, input, output_size);
+        return 1; // OK
+    }
+    return 0;
+}
+
 /**
  * \brief Function to return XFF IP if any in the selected transaction. The
  * caller needs to lock the flow.
@@ -99,13 +164,7 @@ int HttpXFFGetIPFromTx(const Packet *p, uint64_t tx_id, HttpXFFCfg *xff_cfg,
             }
             p_xff = xff_chain;
         }
-        /** Sanity check on extracted IP for IPv4 and IPv6 */
-        uint32_t ip[4];
-        if ( inet_pton(AF_INET, (char *)p_xff, ip ) == 1 ||
-                inet_pton(AF_INET6, (char *)p_xff, ip ) == 1 ) {
-            strlcpy(dstbuf, (char *)p_xff, dstbuflen);
-            return 1; // OK
-        }
+        return ParseXFFString((char *)p_xff, dstbuf, dstbuflen);
     }
     return 0;
 }
@@ -194,3 +253,112 @@ void HttpXFFGetCfg(ConfNode *conf, HttpXFFCfg *result)
         result->flags = XFF_DISABLED;
     }
 }
+
+
+#ifdef UNITTESTS
+static int XFFTest01(void) {
+    char input[] = "1.2.3.4:5678";
+    char output[16];
+    int r = ParseXFFString(input, output, sizeof(output));
+    if (r == 1 && strcmp(output, "1.2.3.4") == 0) {
+        return 1;
+    }
+    return 0;
+}
+
+static int XFFTest02(void) {
+    char input[] = "[12::34]:1234"; // thanks chort!
+    char output[16];
+    int r = ParseXFFString(input, output, sizeof(output));
+    if (r == 1 && strcmp(output, "12::34") == 0) {
+        return 1;
+    }
+    return 0;
+}
+
+static int XFFTest03(void) {
+    char input[] = "[2a03:2880:1010:3f02:face:b00c:0:2]:80"; // thanks chort!
+    char output[46];
+    int r = ParseXFFString(input, output, sizeof(output));
+    if (r == 1 && strcmp(output, "2a03:2880:1010:3f02:face:b00c:0:2") == 0) {
+        return 1;
+    }
+    return 0;
+}
+
+static int XFFTest04(void) {
+    char input[] = "[2a03:2880:1010:3f02:face:b00c:0:2]"; // thanks chort!
+    char output[46];
+    int r = ParseXFFString(input, output, sizeof(output));
+    if (r == 1 && strcmp(output, "2a03:2880:1010:3f02:face:b00c:0:2") == 0) {
+        return 1;
+    }
+    return 0;
+}
+
+static int XFFTest05(void) {
+    char input[] = "[::ffff:1.2.3.4]:1234"; // thanks double-p
+    char output[46];
+    int r = ParseXFFString(input, output, sizeof(output));
+    if (r == 1 && strcmp(output, "::ffff:1.2.3.4") == 0) {
+        return 1;
+    }
+    return 0;
+}
+
+static int XFFTest06(void) {
+    char input[] = "12::34";
+    char output[46];
+    int r = ParseXFFString(input, output, sizeof(output));
+    if (r == 1 && strcmp(output, "12::34") == 0) {
+        return 1;
+    }
+    return 0;
+}
+
+static int XFFTest07(void) {
+    char input[] = "1.2.3.4";
+    char output[46];
+    int r = ParseXFFString(input, output, sizeof(output));
+    if (r == 1 && strcmp(output, "1.2.3.4") == 0) {
+        return 1;
+    }
+    return 0;
+}
+
+static int XFFTest08(void) {
+    char input[] = "[1.2.3.4:1234";
+    char output[46];
+    int r = ParseXFFString(input, output, sizeof(output));
+    if (r == 0) {
+        return 1;
+    }
+    return 0;
+}
+
+static int XFFTest09(void) {
+    char input[] = "999.999.999.999:1234";
+    char output[46];
+    int r = ParseXFFString(input, output, sizeof(output));
+    if (r == 0) {
+        return 1;
+    }
+    return 0;
+}
+
+#endif
+
+void HTPXFFParserRegisterTests(void)
+{
+#ifdef UNITTESTS
+    UtRegisterTest("XFFTest01", XFFTest01, 1);
+    UtRegisterTest("XFFTest02", XFFTest02, 1);
+    UtRegisterTest("XFFTest03", XFFTest03, 1);
+    UtRegisterTest("XFFTest04", XFFTest04, 1);
+    UtRegisterTest("XFFTest05", XFFTest05, 1);
+    UtRegisterTest("XFFTest06", XFFTest06, 1);
+    UtRegisterTest("XFFTest07", XFFTest07, 1);
+    UtRegisterTest("XFFTest08", XFFTest08, 1);
+    UtRegisterTest("XFFTest09", XFFTest09, 1);
+#endif
+}
index ad4eb8acda654a00678f45101dd9804b716fbc21..1a3b67e16b9d7e658ce995676d8612673e6b91ef 100644 (file)
@@ -49,4 +49,6 @@ int HttpXFFGetIPFromTx(const Packet *p, uint64_t tx_id, HttpXFFCfg *xff_cfg, cha
 
 int HttpXFFGetIP(const Packet *p, HttpXFFCfg *xff_cfg, char *dstbuf, int dstbuflen);
 
+void HTPXFFParserRegisterTests(void);
+
 #endif /* __APP_LAYER_HTP_XFF_H__ */
index 1a9c41a5c0ab9cf016ab721fd681758eab4ede9c..452a607e9c2b5566336b62eb68eff3e07d08ecf8 100644 (file)
@@ -35,6 +35,7 @@
 
 #include "suricata.h"
 #include "suricata-common.h"
+#include "conf.h"
 #include "debug.h"
 #include "decode.h"
 #include "threads.h"
@@ -58,6 +59,7 @@
 #include "app-layer-htp-body.h"
 #include "app-layer-htp-file.h"
 #include "app-layer-htp-libhtp.h"
+#include "app-layer-htp-xff.h"
 
 #include "util-spm.h"
 #include "util-debug.h"
@@ -73,7 +75,6 @@
 #include "detect-parse.h"
 
 #include "decode-events.h"
-#include "conf.h"
 
 #include "util-memcmp.h"
 
@@ -6221,6 +6222,7 @@ void HTPParserRegisterTests(void)
     UtRegisterTest("HTPParserTest16", HTPParserTest16, 1);
 
     HTPFileParserRegisterTests();
+    HTPXFFParserRegisterTests();
 #endif /* UNITTESTS */
 }