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.
pull/1608/head
Victor Julien 11 years ago
parent 979bd35277
commit 1235c578b2

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

@ -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__ */

@ -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 */
}

Loading…
Cancel
Save