diff options
Diffstat (limited to 'src/tests/detect-http-client-body.c')
-rw-r--r-- | src/tests/detect-http-client-body.c | 3010 |
1 files changed, 3010 insertions, 0 deletions
diff --git a/src/tests/detect-http-client-body.c b/src/tests/detect-http-client-body.c new file mode 100644 index 0000000..c87d667 --- /dev/null +++ b/src/tests/detect-http-client-body.c @@ -0,0 +1,3010 @@ +/* Copyright (C) 2007-2021 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \ingroup httplayer + * + * @{ + */ + + +/** \file + * + * \author Anoop Saldanha <anoopsaldanha@gmail.com> + * \author Victor Julien <victor@inliniac.net> + * + * \brief Handle HTTP request body match corresponding to http_client_body + * keyword. + * + */ + +#include "../suricata-common.h" +#include "../suricata.h" +#include "../decode.h" + +#include "detect.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-parse.h" +#include "detect-engine-state.h" +#include "detect-engine-content-inspection.h" +#include "detect-engine-prefilter.h" +#include "detect-isdataat.h" +#include "stream-tcp-reassemble.h" +#include "detect-engine-build.h" + +#include "flow-util.h" +#include "util-debug.h" +#include "util-print.h" +#include "flow.h" + +#include "app-layer-parser.h" + +#include "stream-tcp.h" + +#include "util-unittest.h" +#include "util-unittest-helper.h" +#include "app-layer.h" +#include "app-layer-htp.h" +#include "app-layer-protos.h" + +#include "conf.h" +#include "conf-yaml-loader.h" + +#include "util-validate.h" + +#ifdef UNITTESTS + +/** + * \test Test parser accepting valid rules and rejecting invalid rules + */ +static int DetectHttpClientBodyParserTest01(void) +{ + FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_server; content:\"abc\"; http_client_body; sid:1;)", true)); + FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_server; content:\"abc\"; nocase; http_client_body; sid:1;)", true)); + FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_server; content:\"abc\"; endswith; http_client_body; sid:1;)", true)); + FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_server; content:\"abc\"; startswith; http_client_body; sid:1;)", true)); + FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_server; content:\"abc\"; startswith; endswith; http_client_body; sid:1;)", true)); + + FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_server; content:\"abc\"; rawbytes; http_client_body; sid:1;)", false)); + FAIL_IF_NOT(UTHParseSignature("alert tcp any any -> any any (flow:to_server; http_client_body; sid:1;)", false)); + FAIL_IF_NOT(UTHParseSignature("alert tls any any -> any any (flow:to_server; content:\"abc\"; http_client_body; sid:1;)", false)); + PASS; +} + +/** + * \test Test parser accepting valid rules and rejecting invalid rules + */ +static int DetectHttpClientBodyParserTest02(void) +{ + FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_server; http.request_body; content:\"abc\"; sid:1;)", true)); + FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_server; http.request_body; content:\"abc\"; nocase; sid:1;)", true)); + FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_server; http.request_body; content:\"abc\"; endswith; sid:1;)", true)); + FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_server; http.request_body; content:\"abc\"; startswith; sid:1;)", true)); + FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_server; http.request_body; content:\"abc\"; startswith; endswith; sid:1;)", true)); + FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_server; http.request_body; bsize:10; sid:1;)", true)); + + FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_server; http.request_body; content:\"abc\"; rawbytes; sid:1;)", false)); + FAIL_IF_NOT(UTHParseSignature("alert tcp any any -> any any (flow:to_server; http.request_body; sid:1;)", false)); + FAIL_IF_NOT(UTHParseSignature("alert tls any any -> any any (flow:to_server; http.request_body; content:\"abc\"; sid:1;)", false)); + PASS; +} + +struct TestSteps { + const uint8_t *input; + size_t input_size; /**< if 0 strlen will be used */ + int direction; /**< STREAM_TOSERVER, STREAM_TOCLIENT */ + int expect; +}; + +static int RunTest (struct TestSteps *steps, const char *sig, const char *yaml) +{ + TcpSession ssn; + Flow f; + ThreadVars th_v; + DetectEngineThreadCtx *det_ctx = NULL; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + FAIL_IF_NULL(alp_tctx); + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + if (yaml) { + ConfCreateContextBackup(); + ConfInit(); + HtpConfigCreateBackup(); + + ConfYamlLoadString(yaml, strlen(yaml)); + HTPConfigure(); + } + + StreamTcpInitConfig(true); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + de_ctx->flags |= DE_QUIET; + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + f.alproto = ALPROTO_HTTP1; + + SCLogDebug("sig %s", sig); + Signature *s = DetectEngineAppendSig(de_ctx, (char *)sig); + FAIL_IF_NULL(s); + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + FAIL_IF_NULL(det_ctx); + + struct TestSteps *b = steps; + int i = 0; + while (b->input != NULL) { + SCLogDebug("chunk %p %d", b, i); + Packet *p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + FAIL_IF_NULL(p); + p->flow = &f; + p->flowflags = (b->direction == STREAM_TOSERVER) ? FLOW_PKT_TOSERVER : FLOW_PKT_TOCLIENT; + p->flowflags |= FLOW_PKT_ESTABLISHED; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP1, b->direction, + (uint8_t *)b->input, + b->input_size ? b->input_size : strlen((const char *)b->input)); + FAIL_IF_NOT(r == 0); + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + + int match = PacketAlertCheck(p, 1); + FAIL_IF_NOT (b->expect == match); + + UTHFreePackets(&p, 1); + b++; + i++; + } + + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + AppLayerParserThreadCtxFree(alp_tctx); + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(true); + FLOW_DESTROY(&f); + + if (yaml) { + HtpConfigRestoreBackup(); + ConfRestoreContextBackup(); + } + PASS; +} + +static int DetectEngineHttpClientBodyTest01(void) +{ + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"This is dummy message body2", + 0, STREAM_TOSERVER, 1 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (content:\"body1This\"; http_client_body; sid:1;)"; + return RunTest(steps, sig, NULL); +} + +static int DetectEngineHttpClientBodyTest02(void) +{ + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 19\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 1 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (content:\"body1\"; http_client_body; offset:5; sid:1;)"; + return RunTest(steps, sig, NULL); +} + +static int DetectEngineHttpClientBodyTest03(void) +{ + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"This is dummy message body2", + 0, STREAM_TOSERVER, 0 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (content:\"body1\"; http_client_body; offset:16; sid:1;)"; + return RunTest(steps, sig, NULL); +} + +static int DetectEngineHttpClientBodyTest04(void) +{ + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"This is dummy message body2", + 0, STREAM_TOSERVER, 1 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (content:!\"body1\"; http_client_body; offset:16; sid:1;)"; + return RunTest(steps, sig, NULL); +} + +static int DetectEngineHttpClientBodyTest05(void) +{ + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"This is dummy message body2", + 0, STREAM_TOSERVER, 1 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (content:\"body1\"; http_client_body; depth:25; sid:1;)"; + return RunTest(steps, sig, NULL); +} + +static int DetectEngineHttpClientBodyTest06(void) +{ + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"This is dummy message body2", + 0, STREAM_TOSERVER, 0 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (content:!\"body1\"; http_client_body; depth:25; sid:1;)"; + return RunTest(steps, sig, NULL); +} + +static int DetectEngineHttpClientBodyTest07(void) +{ + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"This is dummy message body2", + 0, STREAM_TOSERVER, 1 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (content:!\"body1\"; http_client_body; depth:15; sid:1;)"; + return RunTest(steps, sig, NULL); +} + +static int DetectEngineHttpClientBodyTest08(void) +{ + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"This is dummy message body2", + 0, STREAM_TOSERVER, 1 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (content:\"This is dummy body1This is dummy message body2\"; http_client_body; sid:1;)"; + return RunTest(steps, sig, NULL); +} + +static int DetectEngineHttpClientBodyTest09(void) +{ + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"This is dummy message body2", + 0, STREAM_TOSERVER, 1 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (content:\"body1\"; http_client_body; content:\"This\"; http_client_body; within:5; sid:1;)"; + return RunTest(steps, sig, NULL); +} + +static int DetectEngineHttpClientBodyTest10(void) +{ + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"This is dummy message body2", + 0, STREAM_TOSERVER, 1 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (content:\"body1\"; http_client_body; content:!\"boom\"; http_client_body; within:5; sid:1;)"; + return RunTest(steps, sig, NULL); +} + +static int DetectEngineHttpClientBodyTest11(void) +{ + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"This is dummy message body2", + 0, STREAM_TOSERVER, 0 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (content:\"body1\"; http_client_body; content:\"boom\"; http_client_body; within:5; sid:1;)"; + return RunTest(steps, sig, NULL); +} + +static int DetectEngineHttpClientBodyTest12(void) +{ + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"This is dummy message body2", + 0, STREAM_TOSERVER, 0 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (content:\"body1\"; http_client_body; content:!\"This\"; http_client_body; within:5; sid:1;)"; + return RunTest(steps, sig, NULL); +} + +static int DetectEngineHttpClientBodyTest13(void) +{ + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"This is dummy message body2", + 0, STREAM_TOSERVER, 1 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (content:\"body1\"; http_client_body; content:\"dummy\"; http_client_body; distance:5; sid:1;)"; + return RunTest(steps, sig, NULL); +} + +static int DetectEngineHttpClientBodyTest14(void) +{ + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"This is dummy message body2", + 0, STREAM_TOSERVER, 1 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (content:\"body1\"; http_client_body; content:!\"dummy\"; http_client_body; distance:10; sid:1;)"; + return RunTest(steps, sig, NULL); +} + +static int DetectEngineHttpClientBodyTest15(void) +{ + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"This is dummy message body2", + 0, STREAM_TOSERVER, 0 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (content:\"body1\"; http_client_body; content:\"dummy\"; http_client_body; distance:10; sid:1;)"; + return RunTest(steps, sig, NULL); +} + +static int DetectEngineHttpClientBodyTest16(void) +{ + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"This is dummy message body2", + 0, STREAM_TOSERVER, 0 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (content:\"body1\"; http_client_body; content:!\"dummy\"; http_client_body; distance:5; sid:1;)"; + return RunTest(steps, sig, NULL); +} + +static int DetectEngineHttpClientBodyTest17(void) +{ + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 19\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (content:\"body1\"; http_client_body; content:\"bambu\"; http_client_body; sid:1;)"; + return RunTest(steps, sig, NULL); +} + +static int DetectEngineHttpClientBodyTest18(void) +{ + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 19\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (content:\"body1\"; http_client_body; content:\"bambu\"; http_client_body; fast_pattern; sid:1;)"; + return RunTest(steps, sig, NULL); +} + +static int DetectEngineHttpClientBodyTest19(void) +{ + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 19\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (content:\"bambu\"; http_client_body; content:\"is\"; http_client_body; sid:1;)"; + return RunTest(steps, sig, NULL); +} + +static int DetectEngineHttpClientBodyTest20(void) +{ + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 19\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 1 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (content:\"is\"; http_client_body; fast_pattern; sid:1;)"; + return RunTest(steps, sig, NULL); +} + +static int DetectEngineHttpClientBodyTest21(void) +{ + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"This is dummy message body2", + 0, STREAM_TOSERVER, 1 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (pcre:/body1/P; content:!\"dummy\"; http_client_body; within:7; sid:1;)"; + return RunTest(steps, sig, NULL); +} + +static int DetectEngineHttpClientBodyTest22(void) +{ + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"This is dummy message body2", + 0, STREAM_TOSERVER, 1 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (pcre:/body1/P; content:!\"dummy\"; within:7; http_client_body; sid:1;)"; + return RunTest(steps, sig, NULL); +} + +static int DetectEngineHttpClientBodyTest23(void) +{ + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"This is dummy message body2", + 0, STREAM_TOSERVER, 0 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (pcre:/body1/P; content:!\"dummy\"; distance:3; http_client_body; sid:1;)"; + return RunTest(steps, sig, NULL); +} + +static int DetectEngineHttpClientBodyTest24(void) +{ + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"This is dummy message body2", + 0, STREAM_TOSERVER, 1 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (pcre:/body1/P; content:!\"dummy\"; distance:13; http_client_body; sid:1;)"; + return RunTest(steps, sig, NULL); +} + +static int DetectEngineHttpClientBodyTest25(void) +{ + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"This is dummy message body2", + 0, STREAM_TOSERVER, 1 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (pcre:/body1/P; content:\"dummy\"; within:15; http_client_body; sid:1;)"; + return RunTest(steps, sig, NULL); +} + +static int DetectEngineHttpClientBodyTest26(void) +{ + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"This is dummy message body2", + 0, STREAM_TOSERVER, 0 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (pcre:/body1/P; content:\"dummy\"; within:10; http_client_body; sid:1;)"; + return RunTest(steps, sig, NULL); +} + +static int DetectEngineHttpClientBodyTest27(void) +{ + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"This is dummy message body2", + 0, STREAM_TOSERVER, 1 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (pcre:/body1/P; content:\"dummy\"; distance:8; http_client_body; sid:1;)"; + return RunTest(steps, sig, NULL); +} + +static int DetectEngineHttpClientBodyTest28(void) +{ + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"This is dummy message body2", + 0, STREAM_TOSERVER, 0 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (pcre:/body1/P; content:\"dummy\"; distance:14; http_client_body; sid:1;)"; + return RunTest(steps, sig, NULL); +} + +static int DetectEngineHttpClientBodyTest29(void) +{ + const char *request_buffer = "GET /one HTTP/1.0\r\n" + "Host: localhost\r\n\r\n"; +#define TOTAL_REQUESTS 45 + uint8_t *http_buf = SCMalloc(TOTAL_REQUESTS * strlen(request_buffer)); + if (unlikely(http_buf == NULL)) + return 0; + for (int i = 0; i < TOTAL_REQUESTS; i++) { + memcpy(http_buf + i * strlen(request_buffer), request_buffer, + strlen(request_buffer)); + } + uint32_t http_buf_len = TOTAL_REQUESTS * strlen(request_buffer); +#undef TOTAL_REQUESTS + + struct TestSteps steps[] = { + { (const uint8_t *)http_buf, + (size_t)http_buf_len, STREAM_TOSERVER, 0 }, + + { (const uint8_t *)"HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 5\r\n" + "\r\n" + "dummy", + 0, STREAM_TOCLIENT, 0 }, + + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (content:\"dummyone\"; fast_pattern:0,3; http_server_body; sid:1;)"; + int result = RunTest(steps, sig, NULL); + SCFree(http_buf); + return result; +} + +static int DetectEngineHttpClientBodyTest30(void) +{ + const char yaml[] = "\ +%YAML 1.1\n\ +---\n\ +libhtp:\n\ +\n\ + default-config:\n\ + personality: IDS\n\ + request-body-limit: 0\n\ + response-body-limit: 0\n\ +\n\ + request-body-inspect-window: 0\n\ + response-body-inspect-window: 0\n\ + request-body-minimal-inspect-size: 0\n\ + response-body-minimal-inspect-size: 0\n\ +"; + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"This is dummy message body2", + 0, STREAM_TOSERVER, 0 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (content:\"bags\"; within:4; http_client_body; sid:1;)"; + return RunTest(steps, sig, yaml); +} + +static int DetectEngineHttpClientBodyTest31(void) +{ + const char yaml[] = "\ +%YAML 1.1\n\ +---\n\ +libhtp:\n\ +\n\ + default-config:\n\ + personality: IDS\n\ + request-body-limit: 0\n\ + response-body-limit: 0\n\ +\n\ + request-body-inspect-window: 0\n\ + response-body-inspect-window: 0\n\ + request-body-minimal-inspect-size: 0\n\ + response-body-minimal-inspect-size: 0\n\ +"; + + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"This is dummy message body2", + 0, STREAM_TOSERVER, 0 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (content:\"bags\"; depth:4; http_client_body; sid:1;)"; + return RunTest(steps, sig, yaml); +} + +/** + * \test Test that a signature containing a http_client_body is correctly parsed + * and the keyword is registered. + */ +static int DetectHttpClientBodyTest01(void) +{ + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + de_ctx->flags |= DE_QUIET; + + Signature *s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " + "(msg:\"Testing http_client_body\"; " + "content:\"one\"; http_client_body; sid:1;)"); + FAIL_IF_NULL(s); + + SigMatch *sm = de_ctx->sig_list->init_data->smlists[DETECT_SM_LIST_MATCH]; + FAIL_IF_NOT_NULL(sm); + + DetectEngineCtxFree(de_ctx); + PASS; +} + +/** + * \test Test that a signature containing an valid http_client_body entry is + * parsed. + * \todo error in sig 'http_client_body:;' + */ +static int DetectHttpClientBodyTest02(void) +{ + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + de_ctx->flags |= DE_QUIET; + + Signature *s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " + "(msg:\"Testing http_client_body\"; " + "content:\"one\"; http_client_body:; sid:1;)"); + FAIL_IF_NULL(s); + + DetectEngineCtxFree(de_ctx); + PASS; +} + +/** + * \test Test invalid signatures + */ +static int DetectHttpClientBodyTest03(void) +{ + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + de_ctx->flags |= DE_QUIET; + + const char *sigs[] = { + "alert tcp any any -> any any (http_client_body; sid:1;)", + "alert tcp any any -> any any " + "(msg:\"Testing http_client_body\"; " + "content:\"one\"; rawbytes; http_client_body; sid:2;)", + NULL, + }; + + for (uint32_t i = 0; sigs[i] != NULL; i++) { + Signature *s = DetectEngineAppendSig(de_ctx, sigs[i]); + FAIL_IF_NOT_NULL(s); + } + DetectEngineCtxFree(de_ctx); + PASS; +} + +/** + * \test Test that an invalid signature containing a rawbytes along with a + * http_client_body is invalidated. + */ +static int DetectHttpClientBodyTest05(void) +{ + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + de_ctx->flags |= DE_QUIET; + + const char *sigs[] = { + "alert tcp any any -> any any (content:\"one\"; http_client_body; nocase; sid:1;)", + NULL, + }; + + for (uint32_t i = 0; sigs[i] != NULL; i++) { + Signature *s = DetectEngineAppendSig(de_ctx, sigs[i]); + FAIL_IF_NULL(s); + } + DetectEngineCtxFree(de_ctx); + PASS; +} + +/** + *\test Test that the http_client_body content matches against a http request + * which holds the content. + */ +static int DetectHttpClientBodyTest06(void) +{ + TcpSession ssn; + Packet *p = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http_buf[] = + "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 26\r\n" + "\r\n" + "This is dummy message body"; + uint32_t http_len = sizeof(http_buf) - 1; + int result = 0; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p->flow = &f; + p->flowflags |= FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_ESTABLISHED; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + f.alproto = ALPROTO_HTTP1; + + StreamTcpInitConfig(true); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + Signature *s = DetectEngineAppendSig(de_ctx, "alert http any any -> any any " + "(msg:\"http client body test\"; " + "content:\"message\"; http_client_body; " + "sid:1;)"); + FAIL_IF_NULL(s); + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + int r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, http_buf, http_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + goto end; + } + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: \n"); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + + if (!(PacketAlertCheck(p, 1))) { + printf("sid 1 didn't match but should have\n"); + goto end; + } + + result = 1; +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(true); + FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); + return result; +} + +/** + *\test Test that the http_client_body content matches against a http request + * which holds the content. + */ +static int DetectHttpClientBodyTest07(void) +{ + TcpSession ssn; + Packet *p1 = NULL; + Packet *p2 = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http1_buf[] = + "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 54\r\n" + "\r\n" + "This is dummy message body1"; + uint8_t http2_buf[] = + "This is dummy message body2"; + uint32_t http1_len = sizeof(http1_buf) - 1; + uint32_t http2_len = sizeof(http2_buf) - 1; + int result = 0; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p1->flow = &f; + p1->flowflags |= FLOW_PKT_TOSERVER; + p1->flowflags |= FLOW_PKT_ESTABLISHED; + p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flow = &f; + p2->flowflags |= FLOW_PKT_TOSERVER; + p2->flowflags |= FLOW_PKT_ESTABLISHED; + p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + f.alproto = ALPROTO_HTTP1; + + StreamTcpInitConfig(true); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + Signature *s = DetectEngineAppendSig(de_ctx, "alert http any any -> any any " + "(msg:\"http client body test\"; " + "content:\"message\"; http_client_body; " + "sid:1;)"); + FAIL_IF_NULL(s); + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + int r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, http1_buf, http1_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + goto end; + } + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: "); + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); + + if (PacketAlertCheck(p1, 1)) { + printf("sid 1 matched on p1 but shouldn't have: "); + goto end; + } + + r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, http2_buf, http2_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + if (!(PacketAlertCheck(p2, 1))) { + printf("sid 1 didn't match on p2 but should have: "); + goto end; + } + + result = 1; +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(true); + FLOW_DESTROY(&f); + UTHFreePackets(&p1, 1); + UTHFreePackets(&p2, 1); + return result; +} + +/** + *\test Test that the http_client_body content matches against a http request + * which holds the content. + */ +static int DetectHttpClientBodyTest08(void) +{ + TcpSession ssn; + Packet *p1 = NULL; + Packet *p2 = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http1_buf[] = + "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1"; + uint8_t http2_buf[] = + "This is dummy message body2"; + uint32_t http1_len = sizeof(http1_buf) - 1; + uint32_t http2_len = sizeof(http2_buf) - 1; + int result = 0; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p1->flow = &f; + p1->flowflags |= FLOW_PKT_TOSERVER; + p1->flowflags |= FLOW_PKT_ESTABLISHED; + p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flow = &f; + p2->flowflags |= FLOW_PKT_TOSERVER; + p2->flowflags |= FLOW_PKT_ESTABLISHED; + p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + f.alproto = ALPROTO_HTTP1; + + StreamTcpInitConfig(true); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + Signature *s = DetectEngineAppendSig(de_ctx, "alert http any any -> any any " + "(msg:\"http client body test\"; " + "content:\"message\"; http_client_body; " + "sid:1;)"); + FAIL_IF_NULL(s); + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + int r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, http1_buf, http1_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + goto end; + } + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: "); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); + + if ((PacketAlertCheck(p1, 1))) { + printf("sid 1 didn't match but should have"); + goto end; + } + + r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, http2_buf, http2_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + + if (!(PacketAlertCheck(p2, 1))) { + printf("sid 1 didn't match but should have"); + goto end; + } + + result = 1; +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(true); + FLOW_DESTROY(&f); + UTHFreePackets(&p1, 1); + UTHFreePackets(&p2, 1); + return result; +} + +/** + *\test Test that the http_client_body content matches against a http request + * which holds the content, against a cross boundary present pattern. + */ +static int DetectHttpClientBodyTest09(void) +{ + TcpSession ssn; + Packet *p1 = NULL; + Packet *p2 = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http1_buf[] = + "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1"; + uint8_t http2_buf[] = + "This is dummy message body2"; + uint32_t http1_len = sizeof(http1_buf) - 1; + uint32_t http2_len = sizeof(http2_buf) - 1; + int result = 0; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p1->flow = &f; + p1->flowflags |= FLOW_PKT_TOSERVER; + p1->flowflags |= FLOW_PKT_ESTABLISHED; + p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flow = &f; + p2->flowflags |= FLOW_PKT_TOSERVER; + p2->flowflags |= FLOW_PKT_ESTABLISHED; + p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + f.alproto = ALPROTO_HTTP1; + + StreamTcpInitConfig(true); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + Signature *s = DetectEngineAppendSig(de_ctx, "alert http any any -> any any " + "(msg:\"http client body test\"; " + "content:\"body1This\"; http_client_body; " + "sid:1;)"); + FAIL_IF_NULL(s); + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + int r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, http1_buf, http1_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + goto end; + } + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: "); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); + + if ((PacketAlertCheck(p1, 1))) { + printf("sid 1 didn't match but should have"); + goto end; + } + + r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, http2_buf, http2_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + + if (!(PacketAlertCheck(p2, 1))) { + printf("sid 1 didn't match but should have"); + goto end; + } + + result = 1; +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(true); + FLOW_DESTROY(&f); + UTHFreePackets(&p1, 1); + UTHFreePackets(&p2, 1); + return result; +} + +/** + *\test Test that the http_client_body content matches against a http request + * against a case insensitive pattern. + */ +static int DetectHttpClientBodyTest10(void) +{ + TcpSession ssn; + Packet *p1 = NULL; + Packet *p2 = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http1_buf[] = + "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy bodY1"; + uint8_t http2_buf[] = + "This is dummy message body2"; + uint32_t http1_len = sizeof(http1_buf) - 1; + uint32_t http2_len = sizeof(http2_buf) - 1; + int result = 0; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p1->flow = &f; + p1->flowflags |= FLOW_PKT_TOSERVER; + p1->flowflags |= FLOW_PKT_ESTABLISHED; + p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flow = &f; + p2->flowflags |= FLOW_PKT_TOSERVER; + p2->flowflags |= FLOW_PKT_ESTABLISHED; + p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + f.alproto = ALPROTO_HTTP1; + + StreamTcpInitConfig(true); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + Signature *s = DetectEngineAppendSig(de_ctx, "alert http any any -> any any " + "(msg:\"http client body test\"; " + "content:\"body1This\"; http_client_body; nocase;" + "sid:1;)"); + FAIL_IF_NULL(s); + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + int r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, http1_buf, http1_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + goto end; + } + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: \n"); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); + + if ((PacketAlertCheck(p1, 1))) { + printf("sid 1 didn't match but should have\n"); + goto end; + } + + r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, http2_buf, http2_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + + if (!(PacketAlertCheck(p2, 1))) { + printf("sid 1 didn't match but should have"); + goto end; + } + + result = 1; +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(true); + FLOW_DESTROY(&f); + UTHFreePackets(&p1, 1); + UTHFreePackets(&p2, 1); + return result; +} + +/** + *\test Test that the negated http_client_body content matches against a + * http request which doesn't hold the content. + */ +static int DetectHttpClientBodyTest11(void) +{ + TcpSession ssn; + Packet *p = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http_buf[] = + "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 26\r\n" + "\r\n" + "This is dummy message body"; + uint32_t http_len = sizeof(http_buf) - 1; + int result = 0; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p->flow = &f; + p->flowflags |= FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_ESTABLISHED; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + f.alproto = ALPROTO_HTTP1; + + StreamTcpInitConfig(true); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + Signature *s = DetectEngineAppendSig(de_ctx, "alert http any any -> any any " + "(msg:\"http client body test\"; " + "content:!\"message1\"; http_client_body; " + "sid:1;)"); + FAIL_IF_NULL(s); + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + int r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, http_buf, http_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + goto end; + } + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: "); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + + if (!(PacketAlertCheck(p, 1))) { + printf("sid 1 didn't match but should have"); + goto end; + } + + result = 1; +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(true); + FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); + return result; +} + +/** + *\test Negative test that the negated http_client_body content matches against a + * http request which holds hold the content. + */ +static int DetectHttpClientBodyTest12(void) +{ + TcpSession ssn; + Packet *p = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http_buf[] = + "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 26\r\n" + "\r\n" + "This is dummy message body"; + uint32_t http_len = sizeof(http_buf) - 1; + int result = 0; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p->flow = &f; + p->flowflags |= FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_ESTABLISHED; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + f.alproto = ALPROTO_HTTP1; + + StreamTcpInitConfig(true); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + Signature *s = DetectEngineAppendSig(de_ctx, "alert http any any -> any any " + "(msg:\"http client body test\"; " + "content:!\"message\"; http_client_body; " + "sid:1;)"); + FAIL_IF_NULL(s); + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + int r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, http_buf, http_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + goto end; + } + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: "); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + + if ((PacketAlertCheck(p, 1))) { + printf("sid 1 didn't match but should have"); + goto end; + } + + result = 1; +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(true); + FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); + return result; +} + +/** + *\test Test that the http_client_body content matches against a http request + * which holds the content. + */ +static int DetectHttpClientBodyTest13(void) +{ + TcpSession ssn; + Packet *p = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http_buf[] = + "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 55\r\n" + "\r\n" + "longbufferabcdefghijklmnopqrstuvwxyz0123456789bufferend"; + uint32_t http_len = sizeof(http_buf) - 1; + int result = 0; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p->flow = &f; + p->flowflags |= FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_ESTABLISHED; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + f.alproto = ALPROTO_HTTP1; + + StreamTcpInitConfig(true); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + Signature *s = DetectEngineAppendSig(de_ctx, + "alert http any any -> any any " + "(msg:\"http client body test\"; " + "content:\"abcdefghijklmnopqrstuvwxyz0123456789\"; http_client_body; " + "sid:1;)"); + FAIL_IF_NULL(s); + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + int r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, http_buf, http_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + goto end; + } + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: "); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + + if (!(PacketAlertCheck(p, 1))) { + printf("sid 1 didn't match but should have"); + goto end; + } + + result = 1; +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(true); + FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); + return result; +} + +/** \test multiple http transactions and body chunks of request handling */ +static int DetectHttpClientBodyTest14(void) +{ + int result = 0; + Signature *s = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + ThreadVars th_v; + Flow f; + TcpSession ssn; + Packet *p = NULL; + uint8_t httpbuf1[] = "POST / HTTP/1.1\r\n"; + uint8_t httpbuf2[] = "User-Agent: Mozilla/1.0\r\nContent-Length: 10\r\n"; + uint8_t httpbuf3[] = "Cookie: dummy\r\n\r\n"; + uint8_t httpbuf4[] = "Body one!!"; + uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ + uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ + uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */ + uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */ + uint8_t httpbuf5[] = "GET /?var=val HTTP/1.1\r\n"; + uint8_t httpbuf6[] = "User-Agent: Firefox/1.0\r\n"; + uint8_t httpbuf7[] = "Cookie: dummy2\r\nContent-Length: 10\r\n\r\nBody two!!"; + uint32_t httplen5 = sizeof(httpbuf5) - 1; /* minus the \0 */ + uint32_t httplen6 = sizeof(httpbuf6) - 1; /* minus the \0 */ + uint32_t httplen7 = sizeof(httpbuf7) - 1; /* minus the \0 */ + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p->flow = &f; + p->flowflags |= FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_ESTABLISHED; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + f.alproto = ALPROTO_HTTP1; + + StreamTcpInitConfig(true); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) { + goto end; + } + + de_ctx->flags |= DE_QUIET; + + s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"POST\"; http_method; content:\"Mozilla\"; http_header; content:\"dummy\"; http_cookie; content:\"one\"; http_client_body; sid:1; rev:1;)"); + if (s == NULL) { + printf("sig parse failed: "); + goto end; + } + s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"GET\"; http_method; content:\"Firefox\"; http_header; content:\"dummy2\"; http_cookie; content:\"two\"; http_client_body; sid:2; rev:1;)"); + if (s == NULL) { + printf("sig2 parse failed: "); + goto end; + } + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + int r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf1, httplen1); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + if (PacketAlertCheck(p, 1)) { + printf("sig 1 alerted: "); + goto end; + } + p->alerts.cnt = 0; + + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf2, httplen2); + if (r != 0) { + printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + if (PacketAlertCheck(p, 1)) { + printf("sig 1 alerted (2): "); + goto end; + } + p->alerts.cnt = 0; + + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf3, httplen3); + if (r != 0) { + printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + if (PacketAlertCheck(p, 1)) { + printf("signature matched, but shouldn't have: "); + goto end; + } + p->alerts.cnt = 0; + + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf4, httplen4); + if (r != 0) { + printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + if (!(PacketAlertCheck(p, 1))) { + printf("sig 1 didn't alert: "); + goto end; + } + p->alerts.cnt = 0; + + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf5, httplen5); + if (r != 0) { + printf("toserver chunk 5 returned %" PRId32 ", expected 0: ", r); + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + if (PacketAlertCheck(p, 1)) { + printf("sig 1 alerted (5): "); + goto end; + } + p->alerts.cnt = 0; + + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf6, httplen6); + if (r != 0) { + printf("toserver chunk 6 returned %" PRId32 ", expected 0: ", r); + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + if ((PacketAlertCheck(p, 1)) || (PacketAlertCheck(p, 2))) { + printf("sig 1 alerted (request 2, chunk 6): "); + goto end; + } + p->alerts.cnt = 0; + + SCLogDebug("sending data chunk 7"); + + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf7, httplen7); + if (r != 0) { + printf("toserver chunk 7 returned %" PRId32 ", expected 0: ", r); + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + if (!(PacketAlertCheck(p, 2))) { + printf("signature 2 didn't match, but should have: "); + goto end; + } + p->alerts.cnt = 0; + + HtpState *htp_state = f.alstate; + if (htp_state == NULL) { + printf("no http state: "); + result = 0; + goto end; + } + + if (AppLayerParserGetTxCnt(&f, htp_state) != 2) { + printf("The http app layer doesn't have 2 transactions, but it should: "); + goto end; + } + + result = 1; +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (det_ctx != NULL) { + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + } + if (de_ctx != NULL) { + DetectEngineCtxFree(de_ctx); + } + + StreamTcpFreeConfig(true); + FLOW_DESTROY(&f); + UTHFreePacket(p); + return result; +} + +/** \test multiple http transactions and body chunks of request handling */ +static int DetectHttpClientBodyTest15(void) +{ + int result = 0; + Signature *s = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + ThreadVars th_v; + Flow f; + TcpSession ssn; + Packet *p = NULL; + uint8_t httpbuf1[] = "POST / HTTP/1.1\r\n"; + uint8_t httpbuf2[] = "User-Agent: Mozilla/1.0\r\nContent-Length: 10\r\n"; + uint8_t httpbuf3[] = "Cookie: dummy\r\n\r\n"; + uint8_t httpbuf4[] = "Body one!!"; + uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ + uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ + uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */ + uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */ + uint8_t httpbuf5[] = "GET /?var=val HTTP/1.1\r\n"; + uint8_t httpbuf6[] = "User-Agent: Firefox/1.0\r\n"; + uint8_t httpbuf7[] = "Cookie: dummy2\r\nContent-Length: 10\r\n\r\nBody two!!"; + uint32_t httplen5 = sizeof(httpbuf5) - 1; /* minus the \0 */ + uint32_t httplen6 = sizeof(httpbuf6) - 1; /* minus the \0 */ + uint32_t httplen7 = sizeof(httpbuf7) - 1; /* minus the \0 */ + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p->flow = &f; + p->flowflags |= FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_ESTABLISHED; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + f.alproto = ALPROTO_HTTP1; + + StreamTcpInitConfig(true); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) { + goto end; + } + + de_ctx->flags |= DE_QUIET; + + s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"POST\"; http_method; content:\"Mozilla\"; http_header; content:\"dummy\"; http_cookie; content:\"one\"; http_client_body; sid:1; rev:1;)"); + if (s == NULL) { + printf("sig parse failed: "); + goto end; + } + s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"GET\"; http_method; content:\"Firefox\"; http_header; content:\"dummy2\"; http_cookie; content:\"two\"; http_client_body; sid:2; rev:1;)"); + if (s == NULL) { + printf("sig2 parse failed: "); + goto end; + } + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + int r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf1, httplen1); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + if (PacketAlertCheck(p, 1)) { + printf("sig 1 alerted: "); + goto end; + } + p->alerts.cnt = 0; + + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf2, httplen2); + if (r != 0) { + printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + if (PacketAlertCheck(p, 1)) { + printf("sig 1 alerted (2): "); + goto end; + } + p->alerts.cnt = 0; + + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf3, httplen3); + if (r != 0) { + printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + if (PacketAlertCheck(p, 1)) { + printf("signature matched, but shouldn't have: "); + goto end; + } + p->alerts.cnt = 0; + + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf4, httplen4); + if (r != 0) { + printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + if (!(PacketAlertCheck(p, 1))) { + printf("sig 1 didn't alert: "); + goto end; + } + p->alerts.cnt = 0; + + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf5, httplen5); + if (r != 0) { + printf("toserver chunk 5 returned %" PRId32 ", expected 0: ", r); + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + if (PacketAlertCheck(p, 1)) { + printf("sig 1 alerted (5): "); + goto end; + } + p->alerts.cnt = 0; + + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf6, httplen6); + if (r != 0) { + printf("toserver chunk 6 returned %" PRId32 ", expected 0: ", r); + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + if ((PacketAlertCheck(p, 1)) || (PacketAlertCheck(p, 2))) { + printf("sig 1 alerted (request 2, chunk 6): "); + goto end; + } + p->alerts.cnt = 0; + + SCLogDebug("sending data chunk 7"); + + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf7, httplen7); + if (r != 0) { + printf("toserver chunk 7 returned %" PRId32 ", expected 0: ", r); + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + if (!(PacketAlertCheck(p, 2))) { + printf("signature 2 didn't match, but should have: "); + goto end; + } + p->alerts.cnt = 0; + + HtpState *htp_state = f.alstate; + if (htp_state == NULL) { + printf("no http state: "); + result = 0; + goto end; + } + + /* hardcoded check of the transactions and it's client body chunks */ + if (AppLayerParserGetTxCnt(&f, htp_state) != 2) { + printf("The http app layer doesn't have 2 transactions, but it should: "); + goto end; + } + + htp_tx_t *t1 = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, htp_state, 0); + htp_tx_t *t2 = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, htp_state, 1); + + HtpTxUserData *htud = (HtpTxUserData *) htp_tx_get_user_data(t1); + + HtpBodyChunk *cur = htud->request_body.first; + if (htud->request_body.first == NULL) { + SCLogDebug("No body data in t1 (it should be removed only when the tx is destroyed): "); + goto end; + } + + if (StreamingBufferSegmentCompareRawData(htud->request_body.sb, &cur->sbseg, + (uint8_t *)"Body one!!", 10) != 1) + { + SCLogDebug("Body data in t1 is not correctly set: "); + goto end; + } + + htud = (HtpTxUserData *) htp_tx_get_user_data(t2); + + cur = htud->request_body.first; + if (htud->request_body.first == NULL) { + SCLogDebug("No body data in t1 (it should be removed only when the tx is destroyed): "); + goto end; + } + + if (StreamingBufferSegmentCompareRawData(htud->request_body.sb, &cur->sbseg, + (uint8_t *)"Body two!!", 10) != 1) + { + SCLogDebug("Body data in t1 is not correctly set: "); + goto end; + } + + result = 1; +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (det_ctx != NULL) { + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + } + if (de_ctx != NULL) { + DetectEngineCtxFree(de_ctx); + } + + StreamTcpFreeConfig(true); + FLOW_DESTROY(&f); + UTHFreePacket(p); + return result; +} + +static int DetectHttpClientBodyTest22(void) +{ + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + de_ctx->flags |= DE_QUIET; + Signature *s = DetectEngineAppendSig(de_ctx, + "alert icmp any any -> any any " + "(content:\"one\"; content:\"two\"; http_client_body; " + "content:\"three\"; distance:10; http_client_body; content:\"four\"; sid:1;)"); + FAIL_IF_NULL(s); + FAIL_IF_NULL(s->init_data->smlists[DETECT_SM_LIST_PMATCH]); + FAIL_IF(DetectBufferGetFirstSigMatch(s, g_http_client_body_buffer_id) == NULL); + SigMatch *sm = DetectBufferGetFirstSigMatch(s, g_http_client_body_buffer_id); + FAIL_IF_NULL(sm); + + DetectContentData *cd1 = + (DetectContentData *)s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; + DetectContentData *cd2 = + (DetectContentData *)s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH]->ctx; + DetectContentData *hcbd1 = + (DetectContentData *)DetectBufferGetLastSigMatch(s, g_http_client_body_buffer_id) + ->prev->ctx; + DetectContentData *hcbd2 = + (DetectContentData *)DetectBufferGetLastSigMatch(s, g_http_client_body_buffer_id)->ctx; + FAIL_IF(cd1->flags != 0); + FAIL_IF(memcmp(cd1->content, "one", cd1->content_len) != 0); + FAIL_IF(cd2->flags != 0); + FAIL_IF(memcmp(cd2->content, "four", cd2->content_len) != 0); + FAIL_IF(hcbd1->flags != DETECT_CONTENT_RELATIVE_NEXT); + FAIL_IF(memcmp(hcbd1->content, "two", hcbd1->content_len) != 0); + FAIL_IF(hcbd2->flags != DETECT_CONTENT_DISTANCE); + FAIL_IF(memcmp(hcbd2->content, "three", hcbd1->content_len) != 0); + + FAIL_IF(!DETECT_CONTENT_IS_SINGLE(cd1)); + FAIL_IF(!DETECT_CONTENT_IS_SINGLE(cd2)); + FAIL_IF(DETECT_CONTENT_IS_SINGLE(hcbd1)); + FAIL_IF(DETECT_CONTENT_IS_SINGLE(hcbd2)); + + DetectEngineCtxFree(de_ctx); + PASS; +} + +static int DetectHttpClientBodyTest23(void) +{ + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + de_ctx->flags |= DE_QUIET; + + Signature *s = DetectEngineAppendSig(de_ctx, + "alert icmp any any -> any any " + "(content:\"one\"; http_client_body; pcre:/two/; " + "content:\"three\"; distance:10; http_client_body; content:\"four\"; sid:1;)"); + FAIL_IF_NULL(s); + FAIL_IF_NULL(s->init_data->smlists[DETECT_SM_LIST_PMATCH]); + FAIL_IF_NULL(DetectBufferGetFirstSigMatch(s, g_http_client_body_buffer_id)); + + DetectPcreData *pd1 = + (DetectPcreData *)de_ctx->sig_list->init_data->smlists_tail[DETECT_SM_LIST_PMATCH] + ->prev->ctx; + DetectContentData *cd2 = + (DetectContentData *)de_ctx->sig_list->init_data->smlists_tail[DETECT_SM_LIST_PMATCH] + ->ctx; + DetectContentData *hcbd1 = + (DetectContentData *)DetectBufferGetLastSigMatch(s, g_http_client_body_buffer_id) + ->prev->ctx; + DetectContentData *hcbd2 = + (DetectContentData *)DetectBufferGetLastSigMatch(s, g_http_client_body_buffer_id)->ctx; + FAIL_IF(pd1->flags != 0); + FAIL_IF(cd2->flags != 0); + FAIL_IF(memcmp(cd2->content, "four", cd2->content_len) != 0); + FAIL_IF(hcbd1->flags != DETECT_CONTENT_RELATIVE_NEXT); + FAIL_IF(memcmp(hcbd1->content, "one", hcbd1->content_len) != 0); + FAIL_IF(hcbd2->flags != DETECT_CONTENT_DISTANCE); + FAIL_IF(memcmp(hcbd2->content, "three", hcbd1->content_len) != 0); + FAIL_IF(!DETECT_CONTENT_IS_SINGLE(cd2)); + FAIL_IF(DETECT_CONTENT_IS_SINGLE(hcbd1)); + FAIL_IF(DETECT_CONTENT_IS_SINGLE(hcbd2)); + + DetectEngineCtxFree(de_ctx); + PASS; +} + +static int DetectHttpClientBodyTest24(void) +{ + DetectEngineCtx *de_ctx = NULL; + int result = 0; + + if ( (de_ctx = DetectEngineCtxInit()) == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + Signature *s = DetectEngineAppendSig(de_ctx, "alert icmp any any -> any any " + "(content:\"one\"; http_client_body; pcre:/two/; " + "content:\"three\"; distance:10; within:15; " + "http_client_body; content:\"four\"; sid:1;)"); + if (de_ctx->sig_list == NULL) { + printf("de_ctx->sig_list == NULL\n"); + goto end; + } + + if (de_ctx->sig_list->init_data->smlists[DETECT_SM_LIST_PMATCH] == NULL) { + printf("de_ctx->sig_list->init_data->smlists[DETECT_SM_LIST_PMATCH] == NULL\n"); + goto end; + } + + if (DetectBufferGetFirstSigMatch(s, g_http_client_body_buffer_id) == NULL) { + printf("DetectBufferGetFirstSigMatch(s, g_http_client_body_buffer_id) == NULL\n"); + goto end; + } + + DetectPcreData *pd1 = + (DetectPcreData *)de_ctx->sig_list->init_data->smlists_tail[DETECT_SM_LIST_PMATCH] + ->prev->ctx; + DetectContentData *cd2 = + (DetectContentData *)de_ctx->sig_list->init_data->smlists_tail[DETECT_SM_LIST_PMATCH] + ->ctx; + DetectContentData *hcbd1 = + (DetectContentData *)DetectBufferGetLastSigMatch(s, g_http_client_body_buffer_id) + ->prev->ctx; + DetectContentData *hcbd2 = + (DetectContentData *)DetectBufferGetLastSigMatch(s, g_http_client_body_buffer_id)->ctx; + if (pd1->flags != 0 || + cd2->flags != 0 || memcmp(cd2->content, "four", cd2->content_len) != 0 || + hcbd1->flags != DETECT_CONTENT_RELATIVE_NEXT || + memcmp(hcbd1->content, "one", hcbd1->content_len) != 0 || + hcbd2->flags != (DETECT_CONTENT_DISTANCE | DETECT_CONTENT_WITHIN) || + memcmp(hcbd2->content, "three", hcbd1->content_len) != 0) { + goto end; + } + + if (!DETECT_CONTENT_IS_SINGLE(cd2) || + DETECT_CONTENT_IS_SINGLE(hcbd1) || + DETECT_CONTENT_IS_SINGLE(hcbd2)) { + goto end; + } + + result = 1; + + end: + DetectEngineCtxFree(de_ctx); + return result; +} + +static int DetectHttpClientBodyTest25(void) +{ + DetectEngineCtx *de_ctx = NULL; + int result = 0; + + if ( (de_ctx = DetectEngineCtxInit()) == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + Signature *s = + DetectEngineAppendSig(de_ctx, "alert icmp any any -> any any " + "(content:\"one\"; http_client_body; pcre:/two/; " + "content:\"three\"; distance:10; http_client_body; " + "content:\"four\"; distance:10; sid:1;)"); + if (de_ctx->sig_list == NULL) { + printf("de_ctx->sig_list == NULL\n"); + goto end; + } + + if (de_ctx->sig_list->init_data->smlists[DETECT_SM_LIST_PMATCH] == NULL) { + printf("de_ctx->sig_list->init_data->smlists[DETECT_SM_LIST_PMATCH] == NULL\n"); + goto end; + } + + if (DetectBufferGetFirstSigMatch(s, g_http_client_body_buffer_id) == NULL) { + printf("DetectBufferGetFirstSigMatch(s, g_http_client_body_buffer_id) == NULL\n"); + goto end; + } + + DetectPcreData *pd1 = + (DetectPcreData *)de_ctx->sig_list->init_data->smlists_tail[DETECT_SM_LIST_PMATCH] + ->prev->ctx; + DetectContentData *cd2 = + (DetectContentData *)de_ctx->sig_list->init_data->smlists_tail[DETECT_SM_LIST_PMATCH] + ->ctx; + DetectContentData *hcbd1 = + (DetectContentData *)DetectBufferGetLastSigMatch(s, g_http_client_body_buffer_id) + ->prev->ctx; + DetectContentData *hcbd2 = + (DetectContentData *)DetectBufferGetLastSigMatch(s, g_http_client_body_buffer_id)->ctx; + if (pd1->flags != DETECT_PCRE_RELATIVE_NEXT || + cd2->flags != DETECT_CONTENT_DISTANCE || + memcmp(cd2->content, "four", cd2->content_len) != 0 || + hcbd1->flags != DETECT_CONTENT_RELATIVE_NEXT || + memcmp(hcbd1->content, "one", hcbd1->content_len) != 0 || + hcbd2->flags != DETECT_CONTENT_DISTANCE || + memcmp(hcbd2->content, "three", hcbd1->content_len) != 0) { + goto end; + } + + if (DETECT_CONTENT_IS_SINGLE(cd2) || + DETECT_CONTENT_IS_SINGLE(hcbd1) || + DETECT_CONTENT_IS_SINGLE(hcbd2)) { + goto end; + } + + result = 1; + + end: + DetectEngineCtxFree(de_ctx); + return result; +} + +static int DetectHttpClientBodyTest26(void) +{ + DetectEngineCtx *de_ctx = NULL; + int result = 0; + + if ( (de_ctx = DetectEngineCtxInit()) == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + Signature *s = DetectEngineAppendSig(de_ctx, + "alert icmp any any -> any any " + "(content:\"one\"; offset:10; http_client_body; pcre:/two/; " + "content:\"three\"; distance:10; http_client_body; within:10; " + "content:\"four\"; distance:10; sid:1;)"); + if (de_ctx->sig_list == NULL) { + printf("de_ctx->sig_list == NULL\n"); + goto end; + } + + if (de_ctx->sig_list->init_data->smlists[DETECT_SM_LIST_PMATCH] == NULL) { + printf("de_ctx->sig_list->init_data->smlists[DETECT_SM_LIST_PMATCH] == NULL\n"); + goto end; + } + + if (DetectBufferGetFirstSigMatch(s, g_http_client_body_buffer_id) == NULL) { + printf("DetectBufferGetFirstSigMatch(s, g_http_client_body_buffer_id) == NULL\n"); + goto end; + } + + DetectPcreData *pd1 = + (DetectPcreData *)de_ctx->sig_list->init_data->smlists_tail[DETECT_SM_LIST_PMATCH] + ->prev->ctx; + DetectContentData *cd2 = + (DetectContentData *)de_ctx->sig_list->init_data->smlists_tail[DETECT_SM_LIST_PMATCH] + ->ctx; + DetectContentData *hcbd1 = + (DetectContentData *)DetectBufferGetLastSigMatch(s, g_http_client_body_buffer_id) + ->prev->ctx; + DetectContentData *hcbd2 = + (DetectContentData *)DetectBufferGetLastSigMatch(s, g_http_client_body_buffer_id)->ctx; + if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT) || + cd2->flags != DETECT_CONTENT_DISTANCE || + memcmp(cd2->content, "four", cd2->content_len) != 0 || + hcbd1->flags != (DETECT_CONTENT_RELATIVE_NEXT | DETECT_CONTENT_OFFSET) || + memcmp(hcbd1->content, "one", hcbd1->content_len) != 0 || + hcbd2->flags != (DETECT_CONTENT_DISTANCE | DETECT_CONTENT_WITHIN) || + memcmp(hcbd2->content, "three", hcbd1->content_len) != 0) { + printf ("failed: http_client_body incorrect flags"); + goto end; + } + + if (DETECT_CONTENT_IS_SINGLE(cd2) || + DETECT_CONTENT_IS_SINGLE(hcbd1) || + DETECT_CONTENT_IS_SINGLE(hcbd2)) { + goto end; + } + + result = 1; + + end: + DetectEngineCtxFree(de_ctx); + return result; +} + +static int DetectHttpClientBodyTest27(void) +{ + DetectEngineCtx *de_ctx = NULL; + int result = 0; + + if ( (de_ctx = DetectEngineCtxInit()) == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + Signature *s = DetectEngineAppendSig(de_ctx, + "alert icmp any any -> any any " + "(content:\"one\"; offset:10; http_client_body; pcre:/two/; " + "content:\"three\"; distance:10; http_client_body; within:10; " + "content:\"four\"; distance:10; sid:1;)"); + FAIL_IF_NULL(s); + + result = 1; + + end: + DetectEngineCtxFree(de_ctx); + return result; +} + +static int DetectHttpClientBodyTest28(void) +{ + DetectEngineCtx *de_ctx = NULL; + int result = 0; + + if ( (de_ctx = DetectEngineCtxInit()) == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + Signature *s = DetectEngineAppendSig(de_ctx, "alert icmp any any -> any any " + "(content:\"one\"; http_client_body; pcre:/two/; " + "content:\"three\"; http_client_body; depth:10; " + "content:\"four\"; distance:10; sid:1;)"); + if (de_ctx->sig_list == NULL) { + printf("de_ctx->sig_list == NULL\n"); + goto end; + } + + if (de_ctx->sig_list->init_data->smlists[DETECT_SM_LIST_PMATCH] == NULL) { + printf("de_ctx->sig_list->init_data->smlists[DETECT_SM_LIST_PMATCH] == NULL\n"); + goto end; + } + + if (DetectBufferGetFirstSigMatch(s, g_http_client_body_buffer_id) == NULL) { + printf("DetectBufferGetFirstSigMatch(s, g_http_client_body_buffer_id) == NULL\n"); + goto end; + } + + DetectPcreData *pd1 = + (DetectPcreData *)de_ctx->sig_list->init_data->smlists_tail[DETECT_SM_LIST_PMATCH] + ->prev->ctx; + DetectContentData *cd2 = + (DetectContentData *)de_ctx->sig_list->init_data->smlists_tail[DETECT_SM_LIST_PMATCH] + ->ctx; + DetectContentData *hcbd1 = + (DetectContentData *)DetectBufferGetLastSigMatch(s, g_http_client_body_buffer_id) + ->prev->ctx; + DetectContentData *hcbd2 = + (DetectContentData *)DetectBufferGetLastSigMatch(s, g_http_client_body_buffer_id)->ctx; + if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT) || + cd2->flags != DETECT_CONTENT_DISTANCE || + memcmp(cd2->content, "four", cd2->content_len) != 0 || + hcbd1->flags != 0 || + memcmp(hcbd1->content, "one", hcbd1->content_len) != 0 || + hcbd2->flags != DETECT_CONTENT_DEPTH || + memcmp(hcbd2->content, "three", hcbd1->content_len) != 0) { + goto end; + } + + if (DETECT_CONTENT_IS_SINGLE(cd2) || + !DETECT_CONTENT_IS_SINGLE(hcbd1) || + DETECT_CONTENT_IS_SINGLE(hcbd2)) { + goto end; + } + + result = 1; + + end: + DetectEngineCtxFree(de_ctx); + return result; +} + +static int DetectHttpClientBodyTest29(void) +{ + DetectEngineCtx *de_ctx = NULL; + int result = 0; + + if ( (de_ctx = DetectEngineCtxInit()) == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + Signature *s = + DetectEngineAppendSig(de_ctx, "alert icmp any any -> any any " + "(content:\"one\"; http_client_body; " + "content:\"two\"; distance:0; http_client_body; sid:1;)"); + if (de_ctx->sig_list == NULL) { + printf("de_ctx->sig_list == NULL\n"); + goto end; + } + + if (de_ctx->sig_list->init_data->smlists[DETECT_SM_LIST_PMATCH] != NULL) { + printf("de_ctx->sig_list->init_data->smlists[DETECT_SM_LIST_PMATCH] != NULL\n"); + goto end; + } + + if (DetectBufferGetFirstSigMatch(s, g_http_client_body_buffer_id) == NULL) { + printf("DetectBufferGetFirstSigMatch(s, g_http_client_body_buffer_id) == NULL\n"); + goto end; + } + + DetectContentData *hcbd1 = + (DetectContentData *)DetectBufferGetLastSigMatch(s, g_http_client_body_buffer_id) + ->prev->ctx; + DetectContentData *hcbd2 = + (DetectContentData *)DetectBufferGetLastSigMatch(s, g_http_client_body_buffer_id)->ctx; + if (hcbd1->flags != DETECT_CONTENT_RELATIVE_NEXT || + memcmp(hcbd1->content, "one", hcbd1->content_len) != 0 || + hcbd2->flags != DETECT_CONTENT_DISTANCE || + memcmp(hcbd2->content, "two", hcbd1->content_len) != 0) { + goto end; + } + + result = 1; + + end: + DetectEngineCtxFree(de_ctx); + return result; +} + +static int DetectHttpClientBodyTest30(void) +{ + DetectEngineCtx *de_ctx = NULL; + int result = 0; + + if ( (de_ctx = DetectEngineCtxInit()) == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + Signature *s = + DetectEngineAppendSig(de_ctx, "alert icmp any any -> any any " + "(content:\"one\"; http_client_body; " + "content:\"two\"; within:5; http_client_body; sid:1;)"); + if (de_ctx->sig_list == NULL) { + printf("de_ctx->sig_list == NULL\n"); + goto end; + } + + if (de_ctx->sig_list->init_data->smlists[DETECT_SM_LIST_PMATCH] != NULL) { + printf("de_ctx->sig_list->init_data->smlists[DETECT_SM_LIST_PMATCH] != NULL\n"); + goto end; + } + + if (DetectBufferGetFirstSigMatch(s, g_http_client_body_buffer_id) == NULL) { + printf("DetectBufferGetFirstSigMatch(s, g_http_client_body_buffer_id) == NULL\n"); + goto end; + } + + DetectContentData *hcbd1 = + (DetectContentData *)DetectBufferGetLastSigMatch(s, g_http_client_body_buffer_id) + ->prev->ctx; + DetectContentData *hcbd2 = + (DetectContentData *)DetectBufferGetLastSigMatch(s, g_http_client_body_buffer_id)->ctx; + if (hcbd1->flags != DETECT_CONTENT_RELATIVE_NEXT || + memcmp(hcbd1->content, "one", hcbd1->content_len) != 0 || + hcbd2->flags != DETECT_CONTENT_WITHIN || + memcmp(hcbd2->content, "two", hcbd1->content_len) != 0) { + goto end; + } + + result = 1; + + end: + DetectEngineCtxFree(de_ctx); + return result; +} + +static int DetectHttpClientBodyTest31(void) +{ + DetectEngineCtx *de_ctx = NULL; + int result = 0; + + if ( (de_ctx = DetectEngineCtxInit()) == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + Signature *s = + DetectEngineAppendSig(de_ctx, "alert icmp any any -> any any " + "(content:\"one\"; within:5; http_client_body; sid:1;)"); + FAIL_IF_NULL(s); + + result = 1; + + end: + DetectEngineCtxFree(de_ctx); + return result; +} + +static int DetectHttpClientBodyTest32(void) +{ + DetectEngineCtx *de_ctx = NULL; + int result = 0; + + if ( (de_ctx = DetectEngineCtxInit()) == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + Signature *s = + DetectEngineAppendSig(de_ctx, "alert icmp any any -> any any " + "(content:\"one\"; http_client_body; within:5; sid:1;)"); + FAIL_IF_NULL(s); + + result = 1; + + end: + DetectEngineCtxFree(de_ctx); + return result; +} + +static int DetectHttpClientBodyTest33(void) +{ + DetectEngineCtx *de_ctx = NULL; + int result = 0; + + if ( (de_ctx = DetectEngineCtxInit()) == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + Signature *s = DetectEngineAppendSig(de_ctx, "alert icmp any any -> any any " + "(content:\"one\"; within:5; sid:1;)"); + FAIL_IF_NULL(s); + + result = 1; + + end: + DetectEngineCtxFree(de_ctx); + return result; +} + +static int DetectHttpClientBodyTest34(void) +{ + DetectEngineCtx *de_ctx = NULL; + int result = 0; + + if ( (de_ctx = DetectEngineCtxInit()) == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + Signature *s = + DetectEngineAppendSig(de_ctx, "alert icmp any any -> any any " + "(pcre:/one/P; " + "content:\"two\"; within:5; http_client_body; sid:1;)"); + if (de_ctx->sig_list == NULL) { + printf("de_ctx->sig_list == NULL\n"); + goto end; + } + + if (de_ctx->sig_list->init_data->smlists[DETECT_SM_LIST_PMATCH] != NULL) { + printf("de_ctx->sig_list->init_data->smlists[DETECT_SM_LIST_PMATCH] != NULL\n"); + goto end; + } + + if (DetectBufferGetFirstSigMatch(s, g_http_client_body_buffer_id) == NULL) { + printf("DetectBufferGetFirstSigMatch(s, g_http_client_body_buffer_id) == NULL\n"); + goto end; + } + + if (DetectBufferGetLastSigMatch(s, g_http_client_body_buffer_id) == NULL || + DetectBufferGetLastSigMatch(s, g_http_client_body_buffer_id)->type != DETECT_CONTENT || + DetectBufferGetLastSigMatch(s, g_http_client_body_buffer_id)->prev == NULL || + DetectBufferGetLastSigMatch(s, g_http_client_body_buffer_id)->prev->type != + DETECT_PCRE) { + + goto end; + } + + DetectPcreData *pd1 = + (DetectPcreData *)DetectBufferGetLastSigMatch(s, g_http_client_body_buffer_id) + ->prev->ctx; + DetectContentData *hcbd2 = + (DetectContentData *)DetectBufferGetLastSigMatch(s, g_http_client_body_buffer_id)->ctx; + if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT) || + hcbd2->flags != DETECT_CONTENT_WITHIN || + memcmp(hcbd2->content, "two", hcbd2->content_len) != 0) { + goto end; + } + + result = 1; + + end: + DetectEngineCtxFree(de_ctx); + return result; +} + +static int DetectHttpClientBodyTest35(void) +{ + DetectEngineCtx *de_ctx = NULL; + int result = 0; + + if ( (de_ctx = DetectEngineCtxInit()) == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + Signature *s = DetectEngineAppendSig(de_ctx, "alert icmp any any -> any any " + "(content:\"two\"; http_client_body; " + "pcre:/one/PR; sid:1;)"); + if (de_ctx->sig_list == NULL) { + printf("de_ctx->sig_list == NULL\n"); + goto end; + } + + if (de_ctx->sig_list->init_data->smlists[DETECT_SM_LIST_PMATCH] != NULL) { + printf("de_ctx->sig_list->init_data->smlists[DETECT_SM_LIST_PMATCH] != NULL\n"); + goto end; + } + + if (DetectBufferGetFirstSigMatch(s, g_http_client_body_buffer_id) == NULL) { + printf("DetectBufferGetFirstSigMatch(s, g_http_client_body_buffer_id) == NULL\n"); + goto end; + } + + if (DetectBufferGetLastSigMatch(s, g_http_client_body_buffer_id) == NULL || + DetectBufferGetLastSigMatch(s, g_http_client_body_buffer_id)->type != DETECT_PCRE || + DetectBufferGetLastSigMatch(s, g_http_client_body_buffer_id)->prev == NULL || + DetectBufferGetLastSigMatch(s, g_http_client_body_buffer_id)->prev->type != + DETECT_CONTENT) { + + goto end; + } + + DetectContentData *hcbd1 = + (DetectContentData *)DetectBufferGetLastSigMatch(s, g_http_client_body_buffer_id) + ->prev->ctx; + DetectPcreData *pd2 = + (DetectPcreData *)DetectBufferGetLastSigMatch(s, g_http_client_body_buffer_id)->ctx; + if (pd2->flags != (DETECT_PCRE_RELATIVE) || + hcbd1->flags != DETECT_CONTENT_RELATIVE_NEXT || + memcmp(hcbd1->content, "two", hcbd1->content_len) != 0) { + goto end; + } + + result = 1; + + end: + DetectEngineCtxFree(de_ctx); + return result; +} + +static int DetectHttpClientBodyTest36(void) +{ + DetectEngineCtx *de_ctx = NULL; + int result = 0; + + if ( (de_ctx = DetectEngineCtxInit()) == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + Signature *s = + DetectEngineAppendSig(de_ctx, "alert icmp any any -> any any " + "(pcre:/one/P; " + "content:\"two\"; distance:5; http_client_body; sid:1;)"); + if (de_ctx->sig_list == NULL) { + printf("de_ctx->sig_list == NULL\n"); + goto end; + } + + if (de_ctx->sig_list->init_data->smlists[DETECT_SM_LIST_PMATCH] != NULL) { + printf("de_ctx->sig_list->init_data->smlists[DETECT_SM_LIST_PMATCH] != NULL\n"); + goto end; + } + + if (DetectBufferGetFirstSigMatch(s, g_http_client_body_buffer_id) == NULL) { + printf("DetectBufferGetFirstSigMatch(s, g_http_client_body_buffer_id) == NULL\n"); + goto end; + } + + if (DetectBufferGetLastSigMatch(s, g_http_client_body_buffer_id) == NULL || + DetectBufferGetLastSigMatch(s, g_http_client_body_buffer_id)->type != DETECT_CONTENT || + DetectBufferGetLastSigMatch(s, g_http_client_body_buffer_id)->prev == NULL || + DetectBufferGetLastSigMatch(s, g_http_client_body_buffer_id)->prev->type != + DETECT_PCRE) { + + goto end; + } + + DetectPcreData *pd1 = + (DetectPcreData *)DetectBufferGetLastSigMatch(s, g_http_client_body_buffer_id) + ->prev->ctx; + DetectContentData *hcbd2 = + (DetectContentData *)DetectBufferGetLastSigMatch(s, g_http_client_body_buffer_id)->ctx; + if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT) || + hcbd2->flags != DETECT_CONTENT_DISTANCE || + memcmp(hcbd2->content, "two", hcbd2->content_len) != 0) { + goto end; + } + + result = 1; + + end: + DetectEngineCtxFree(de_ctx); + return result; +} + +static int DetectHttpClientBodyIsdataatParseTest(void) +{ + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + de_ctx->flags |= DE_QUIET; + + Signature *s = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (" + "content:\"one\"; http_client_body; " + "isdataat:!4,relative; sid:1;)"); + FAIL_IF_NULL(s); + + SigMatch *sm = DetectBufferGetLastSigMatch(s, g_http_client_body_buffer_id); + FAIL_IF_NULL(sm); + FAIL_IF_NOT(sm->type == DETECT_ISDATAAT); + + DetectIsdataatData *data = (DetectIsdataatData *)sm->ctx; + FAIL_IF_NOT(data->flags & ISDATAAT_RELATIVE); + FAIL_IF_NOT(data->flags & ISDATAAT_NEGATED); + FAIL_IF(data->flags & ISDATAAT_RAWBYTES); + + DetectEngineCtxFree(de_ctx); + PASS; +} + +void DetectHttpClientBodyRegisterTests(void) +{ + UtRegisterTest("DetectHttpClientBodyParserTest01", DetectHttpClientBodyParserTest01); + UtRegisterTest("DetectHttpClientBodyParserTest02", DetectHttpClientBodyParserTest02); + UtRegisterTest("DetectHttpClientBodyTest01", DetectHttpClientBodyTest01); + UtRegisterTest("DetectHttpClientBodyTest02", DetectHttpClientBodyTest02); + UtRegisterTest("DetectHttpClientBodyTest03", DetectHttpClientBodyTest03); + UtRegisterTest("DetectHttpClientBodyTest05", DetectHttpClientBodyTest05); + UtRegisterTest("DetectHttpClientBodyTest06", DetectHttpClientBodyTest06); + UtRegisterTest("DetectHttpClientBodyTest07", DetectHttpClientBodyTest07); + UtRegisterTest("DetectHttpClientBodyTest08", DetectHttpClientBodyTest08); + UtRegisterTest("DetectHttpClientBodyTest09", DetectHttpClientBodyTest09); + UtRegisterTest("DetectHttpClientBodyTest10", DetectHttpClientBodyTest10); + UtRegisterTest("DetectHttpClientBodyTest11", DetectHttpClientBodyTest11); + UtRegisterTest("DetectHttpClientBodyTest12", DetectHttpClientBodyTest12); + UtRegisterTest("DetectHttpClientBodyTest13", DetectHttpClientBodyTest13); + UtRegisterTest("DetectHttpClientBodyTest14", DetectHttpClientBodyTest14); + UtRegisterTest("DetectHttpClientBodyTest15", DetectHttpClientBodyTest15); + + UtRegisterTest("DetectHttpClientBodyTest22", DetectHttpClientBodyTest22); + UtRegisterTest("DetectHttpClientBodyTest23", DetectHttpClientBodyTest23); + UtRegisterTest("DetectHttpClientBodyTest24", DetectHttpClientBodyTest24); + UtRegisterTest("DetectHttpClientBodyTest25", DetectHttpClientBodyTest25); + UtRegisterTest("DetectHttpClientBodyTest26", DetectHttpClientBodyTest26); + UtRegisterTest("DetectHttpClientBodyTest27", DetectHttpClientBodyTest27); + UtRegisterTest("DetectHttpClientBodyTest28", DetectHttpClientBodyTest28); + UtRegisterTest("DetectHttpClientBodyTest29", DetectHttpClientBodyTest29); + UtRegisterTest("DetectHttpClientBodyTest30", DetectHttpClientBodyTest30); + UtRegisterTest("DetectHttpClientBodyTest31", DetectHttpClientBodyTest31); + UtRegisterTest("DetectHttpClientBodyTest32", DetectHttpClientBodyTest32); + UtRegisterTest("DetectHttpClientBodyTest33", DetectHttpClientBodyTest33); + UtRegisterTest("DetectHttpClientBodyTest34", DetectHttpClientBodyTest34); + UtRegisterTest("DetectHttpClientBodyTest35", DetectHttpClientBodyTest35); + UtRegisterTest("DetectHttpClientBodyTest36", DetectHttpClientBodyTest36); + + UtRegisterTest("DetectHttpClientBodyIsdataatParseTest", + DetectHttpClientBodyIsdataatParseTest); + + UtRegisterTest("DetectEngineHttpClientBodyTest01", + DetectEngineHttpClientBodyTest01); + UtRegisterTest("DetectEngineHttpClientBodyTest02", + DetectEngineHttpClientBodyTest02); + UtRegisterTest("DetectEngineHttpClientBodyTest03", + DetectEngineHttpClientBodyTest03); + UtRegisterTest("DetectEngineHttpClientBodyTest04", + DetectEngineHttpClientBodyTest04); + UtRegisterTest("DetectEngineHttpClientBodyTest05", + DetectEngineHttpClientBodyTest05); + UtRegisterTest("DetectEngineHttpClientBodyTest06", + DetectEngineHttpClientBodyTest06); + UtRegisterTest("DetectEngineHttpClientBodyTest07", + DetectEngineHttpClientBodyTest07); + UtRegisterTest("DetectEngineHttpClientBodyTest08", + DetectEngineHttpClientBodyTest08); + UtRegisterTest("DetectEngineHttpClientBodyTest09", + DetectEngineHttpClientBodyTest09); + UtRegisterTest("DetectEngineHttpClientBodyTest10", + DetectEngineHttpClientBodyTest10); + UtRegisterTest("DetectEngineHttpClientBodyTest11", + DetectEngineHttpClientBodyTest11); + UtRegisterTest("DetectEngineHttpClientBodyTest12", + DetectEngineHttpClientBodyTest12); + UtRegisterTest("DetectEngineHttpClientBodyTest13", + DetectEngineHttpClientBodyTest13); + UtRegisterTest("DetectEngineHttpClientBodyTest14", + DetectEngineHttpClientBodyTest14); + UtRegisterTest("DetectEngineHttpClientBodyTest15", + DetectEngineHttpClientBodyTest15); + UtRegisterTest("DetectEngineHttpClientBodyTest16", + DetectEngineHttpClientBodyTest16); + UtRegisterTest("DetectEngineHttpClientBodyTest17", + DetectEngineHttpClientBodyTest17); + UtRegisterTest("DetectEngineHttpClientBodyTest18", + DetectEngineHttpClientBodyTest18); + UtRegisterTest("DetectEngineHttpClientBodyTest19", + DetectEngineHttpClientBodyTest19); + UtRegisterTest("DetectEngineHttpClientBodyTest20", + DetectEngineHttpClientBodyTest20); + UtRegisterTest("DetectEngineHttpClientBodyTest21", + DetectEngineHttpClientBodyTest21); + UtRegisterTest("DetectEngineHttpClientBodyTest22", + DetectEngineHttpClientBodyTest22); + UtRegisterTest("DetectEngineHttpClientBodyTest23", + DetectEngineHttpClientBodyTest23); + UtRegisterTest("DetectEngineHttpClientBodyTest24", + DetectEngineHttpClientBodyTest24); + UtRegisterTest("DetectEngineHttpClientBodyTest25", + DetectEngineHttpClientBodyTest25); + UtRegisterTest("DetectEngineHttpClientBodyTest26", + DetectEngineHttpClientBodyTest26); + UtRegisterTest("DetectEngineHttpClientBodyTest27", + DetectEngineHttpClientBodyTest27); + UtRegisterTest("DetectEngineHttpClientBodyTest28", + DetectEngineHttpClientBodyTest28); + UtRegisterTest("DetectEngineHttpClientBodyTest29", + DetectEngineHttpClientBodyTest29); + + UtRegisterTest("DetectEngineHttpClientBodyTest30", + DetectEngineHttpClientBodyTest30); + UtRegisterTest("DetectEngineHttpClientBodyTest31", + DetectEngineHttpClientBodyTest31); +} + +#endif + +/** + * @} + */ |