From: Victor Julien Date: Tue, 21 Jul 2015 15:27:26 +0000 (+0200) Subject: xff: support ports and more ipv6 notations X-Git-Tag: suricata-3.0RC1~187 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=1235c578b25e2e4ca0eb442dfbe962a7a2f22551;p=thirdparty%2Fsuricata.git xff: support ports and more ipv6 notations 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. --- diff --git a/src/app-layer-htp-xff.c b/src/app-layer-htp-xff.c index 5be84bbdb7..96c6de487f 100644 --- a/src/app-layer-htp-xff.c +++ b/src/app-layer-htp-xff.c @@ -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 @@ -39,6 +40,70 @@ /** 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 +} diff --git a/src/app-layer-htp-xff.h b/src/app-layer-htp-xff.h index ad4eb8acda..1a3b67e16b 100644 --- a/src/app-layer-htp-xff.h +++ b/src/app-layer-htp-xff.h @@ -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__ */ diff --git a/src/app-layer-htp.c b/src/app-layer-htp.c index 1a9c41a5c0..452a607e9c 100644 --- a/src/app-layer-htp.c +++ b/src/app-layer-htp.c @@ -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 */ }