From cb332b4cda3acebdc567e855b8bc87525f2a9a6d Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sun, 25 Nov 2018 16:40:49 +0100 Subject: [PATCH] detect/http_method: move all tests into tests/ --- src/Makefile.am | 1 - src/detect-engine-file.c | 1 - src/detect-engine-hmd.h | 38 - src/detect-engine-mpm.c | 1 - src/detect-engine-register.c | 1 - src/detect-http-method.c | 728 +-------------- src/runmode-unittests.c | 2 - .../detect-http-method.c} | 838 +++++++++++++++--- 8 files changed, 726 insertions(+), 884 deletions(-) delete mode 100644 src/detect-engine-hmd.h rename src/{detect-engine-hmd.c => tests/detect-http-method.c} (69%) diff --git a/src/Makefile.am b/src/Makefile.am index 2316f3057c..d741e01e96 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -134,7 +134,6 @@ detect-engine-filedata.c detect-engine-filedata.h \ detect-engine-hcbd.c detect-engine-hcbd.h \ detect-engine-hcd.c detect-engine-hcd.h \ detect-engine-hhhd.c detect-engine-hhhd.h \ -detect-engine-hmd.c detect-engine-hmd.h \ detect-engine-hrhd.c detect-engine-hrhd.h \ detect-engine-hrhhd.c detect-engine-hrhhd.h \ detect-engine-hsbd.c detect-engine-hsbd.h \ diff --git a/src/detect-engine-file.c b/src/detect-engine-file.c index e973e1b29d..633dac6d59 100644 --- a/src/detect-engine-file.c +++ b/src/detect-engine-file.c @@ -34,7 +34,6 @@ #include "detect-engine-hcbd.h" #include "detect-engine-hrhd.h" -#include "detect-engine-hmd.h" #include "detect-engine-hcd.h" #include "detect-engine-dcepayload.h" #include "detect-engine-file.h" diff --git a/src/detect-engine-hmd.h b/src/detect-engine-hmd.h deleted file mode 100644 index f5f09f211f..0000000000 --- a/src/detect-engine-hmd.h +++ /dev/null @@ -1,38 +0,0 @@ -/* Copyright (C) 2007-2010 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. - */ - -/** \file - * - * \author Anoop Saldanha - */ - -#ifndef __DETECT_ENGINE_HMD_H__ -#define __DETECT_ENGINE_HMD_H__ - -#include "app-layer-htp.h" - -int DetectEngineInspectHttpMethod(ThreadVars *tv, - DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - const Signature *s, const SigMatchData *smd, - Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id); - -int PrefilterTxMethodRegister(DetectEngineCtx *de_ctx, - SigGroupHead *sgh, MpmCtx *mpm_ctx); - -void DetectEngineHttpMethodRegisterTests(void); - -#endif /* __DETECT_ENGINE_HMD_H__ */ diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index 673465ef0f..4902f55726 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -50,7 +50,6 @@ #include "detect-content.h" #include "detect-engine-payload.h" -#include "detect-engine-hmd.h" #include "detect-engine-hrhd.h" #include "detect-engine-hcd.h" #include "detect-engine-hhhd.h" diff --git a/src/detect-engine-register.c b/src/detect-engine-register.c index 5aca32150e..1d3e8fced7 100644 --- a/src/detect-engine-register.c +++ b/src/detect-engine-register.c @@ -157,7 +157,6 @@ #include "detect-engine-hcbd.h" #include "detect-engine-hsbd.h" #include "detect-engine-hrhd.h" -#include "detect-engine-hmd.h" #include "detect-engine-hcd.h" #include "detect-engine-hsmd.h" #include "detect-engine-hscd.h" diff --git a/src/detect-http-method.c b/src/detect-http-method.c index 8ba7c4d34b..48a96aac01 100644 --- a/src/detect-http-method.c +++ b/src/detect-http-method.c @@ -57,12 +57,13 @@ #include "app-layer-htp.h" #include "detect-http-method.h" -#include "detect-engine-hmd.h" #include "stream-tcp.h" static int g_http_method_buffer_id = 0; static int DetectHttpMethodSetup(DetectEngineCtx *, Signature *, const char *); +#ifdef UNITTESTS void DetectHttpMethodRegisterTests(void); +#endif void DetectHttpMethodFree(void *); static _Bool DetectHttpMethodValidateCallback(const Signature *s, const char **sigerror); static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, @@ -79,7 +80,9 @@ void DetectHttpMethodRegister(void) sigmatch_table[DETECT_AL_HTTP_METHOD].url = DOC_URL DOC_VERSION "/rules/http-keywords.html#http-method"; sigmatch_table[DETECT_AL_HTTP_METHOD].Match = NULL; sigmatch_table[DETECT_AL_HTTP_METHOD].Setup = DetectHttpMethodSetup; +#ifdef UNITTESTS sigmatch_table[DETECT_AL_HTTP_METHOD].RegisterTests = DetectHttpMethodRegisterTests; +#endif sigmatch_table[DETECT_AL_HTTP_METHOD].flags |= SIGMATCH_NOOPT; DetectAppLayerInspectEngineRegister2("http_method", ALPROTO_HTTP, @@ -175,726 +178,9 @@ static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, return buffer; } -#ifdef UNITTESTS /* UNITTESTS */ - -#include "detect-isdataat.h" -#include "stream-tcp-reassemble.h" - -/** \test Check a signature with content */ -static int DetectHttpMethodTest01(void) -{ - DetectEngineCtx *de_ctx = NULL; - int result = 0; - - if ( (de_ctx = DetectEngineCtxInit()) == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, - "alert tcp any any -> any any " - "(msg:\"Testing http_method\"; " - "content:\"GET\"; " - "http_method; sid:1;)"); - - if (de_ctx->sig_list != NULL) { - result = 1; - } else { - printf("sig parse failed: "); - } - - end: - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - return result; -} - -/** \test Check a signature without content (fail) */ -static int DetectHttpMethodTest02(void) -{ - DetectEngineCtx *de_ctx = NULL; - int result = 0; - - if ( (de_ctx = DetectEngineCtxInit()) == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, - "alert tcp any any -> any any " - "(msg:\"Testing http_method\"; " - "http_method; sid:1;)"); - - if (de_ctx->sig_list == NULL) { - result = 1; - } - - end: - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - return result; -} - -/** \test Check a signature with parameter (fail) */ -static int DetectHttpMethodTest03(void) -{ - DetectEngineCtx *de_ctx = NULL; - int result = 0; - - if ( (de_ctx = DetectEngineCtxInit()) == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, - "alert tcp any any -> any any " - "(msg:\"Testing http_method\"; " - "content:\"foobar\"; " - "http_method:\"GET\"; sid:1;)"); - - if (de_ctx->sig_list == NULL) { - result = 1; - } - - end: - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - return result; -} - -/** \test Check a signature with fast_pattern (should work) */ -static int DetectHttpMethodTest04(void) -{ - DetectEngineCtx *de_ctx = NULL; - int result = 0; - - if ( (de_ctx = DetectEngineCtxInit()) == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, - "alert tcp any any -> any any " - "(msg:\"Testing http_method\"; " - "content:\"GET\"; " - "fast_pattern; " - "http_method; sid:1;)"); - - if (de_ctx->sig_list != NULL) { - result = 1; - } - - end: - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - return result; -} - -/** \test Check a signature with rawbytes (fail) */ -static int DetectHttpMethodTest05(void) -{ - DetectEngineCtx *de_ctx = NULL; - int result = 0; - - if ( (de_ctx = DetectEngineCtxInit()) == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, - "alert tcp any any -> any any " - "(msg:\"Testing http_method\"; " - "content:\"GET\"; " - "rawbytes; " - "http_method; sid:1;)"); - - if (de_ctx->sig_list == NULL) { - result = 1; - } - - end: - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - return result; -} - -/** \test setting the nocase flag */ -static int DetectHttpMethodTest12(void) -{ - DetectEngineCtx *de_ctx = NULL; - int result = 0; - - if ( (de_ctx = DetectEngineCtxInit()) == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - if (DetectEngineAppendSig(de_ctx, "alert http any any -> any any " - "(content:\"one\"; http_method; nocase; sid:1;)") == NULL) { - printf("DetectEngineAppend == NULL: "); - goto end; - } - if (DetectEngineAppendSig(de_ctx, "alert http any any -> any any " - "(content:\"one\"; nocase; http_method; sid:2;)") == NULL) { - printf("DetectEngineAppend == NULL: "); - goto end; - } - - if (de_ctx->sig_list->sm_lists[g_http_method_buffer_id] == NULL) { - printf("de_ctx->sig_list->sm_lists[g_http_method_buffer_id] == NULL: "); - goto end; - } - - DetectContentData *hmd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_method_buffer_id]->ctx; - DetectContentData *hmd2 = (DetectContentData *)de_ctx->sig_list->next->sm_lists_tail[g_http_method_buffer_id]->ctx; - - if (!(hmd1->flags & DETECT_CONTENT_NOCASE)) { - printf("nocase flag not set on sig 1: "); - goto end; - } - - if (!(hmd2->flags & DETECT_CONTENT_NOCASE)) { - printf("nocase flag not set on sig 2: "); - goto end; - } - result = 1; - - end: - DetectEngineCtxFree(de_ctx); - return result; -} - -/** \test Check a signature with method + within and pcre with /M (should work) */ -static int DetectHttpMethodTest13(void) -{ - DetectEngineCtx *de_ctx = NULL; - int result = 0; - - if ( (de_ctx = DetectEngineCtxInit()) == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, - "alert tcp any any -> any any " - "(msg:\"Testing http_method\"; " - "pcre:\"/HE/M\"; " - "content:\"AD\"; " - "within:2; http_method; sid:1;)"); - - if (de_ctx->sig_list != NULL) { - result = 1; - } - - end: - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - return result; -} - -/** \test Check a signature with method + within and pcre without /M (should fail) */ -static int DetectHttpMethodTest14(void) -{ - DetectEngineCtx *de_ctx = NULL; - int result = 0; - - if ( (de_ctx = DetectEngineCtxInit()) == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, - "alert tcp any any -> any any " - "(msg:\"Testing http_method\"; " - "pcre:\"/HE/\"; " - "content:\"AD\"; " - "http_method; within:2; sid:1;)"); - - if (de_ctx->sig_list != NULL) { - result = 1; - } - - end: - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - return result; -} - -/** \test Check a signature with method + within and pcre with /M (should work) */ -static int DetectHttpMethodTest15(void) -{ - DetectEngineCtx *de_ctx = NULL; - int result = 0; - - if ( (de_ctx = DetectEngineCtxInit()) == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, - "alert tcp any any -> any any " - "(msg:\"Testing http_method\"; " - "pcre:\"/HE/M\"; " - "content:\"AD\"; " - "http_method; within:2; sid:1;)"); - - if (de_ctx->sig_list != NULL) { - result = 1; - } - - end: - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - return result; -} -/** \test Check a signature with an known request method */ -static int DetectHttpMethodSigTest01(void) -{ - int result = 0; - Flow f; - uint8_t httpbuf1[] = "GET / HTTP/1.0\r\n" - "Host: foo.bar.tld\r\n" - "\r\n"; - uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ - TcpSession ssn; - Packet *p = NULL; - Signature *s = NULL; - ThreadVars th_v; - DetectEngineThreadCtx *det_ctx; - HtpState *http_state = NULL; - 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_HTTP; - - StreamTcpInitConfig(TRUE); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } - - de_ctx->flags |= DE_QUIET; - - s = de_ctx->sig_list = SigInit(de_ctx, - "alert tcp any any -> any any " - "(msg:\"Testing http_method\"; " - "content:\"GET\"; " - "http_method; sid:1;)"); - if (s == NULL) { - goto end; - } - - s = s->next = SigInit(de_ctx, - "alert tcp any any -> any any " - "(msg:\"Testing http_method\"; " - "content:\"POST\"; " - "http_method; sid:2;)"); - if (s == NULL) { - goto end; - } - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOSERVER, httpbuf1, httplen1); - if (r != 0) { - SCLogDebug("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - http_state = f.alstate; - if (http_state == NULL) { - SCLogDebug("no http state: "); - goto end; - } - - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - - if (!(PacketAlertCheck(p, 1))) { - goto end; - } - if (PacketAlertCheck(p, 2)) { - 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 Check a signature with an unknown request method */ -static int DetectHttpMethodSigTest02(void) -{ - int result = 0; - Flow f; - uint8_t httpbuf1[] = "FOO / HTTP/1.0\r\n" - "Host: foo.bar.tld\r\n" - "\r\n"; - uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ - TcpSession ssn; - Packet *p = NULL; - Signature *s = NULL; - ThreadVars th_v; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - 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_HTTP; - - StreamTcpInitConfig(TRUE); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } - - de_ctx->flags |= DE_QUIET; - - s = de_ctx->sig_list = SigInit(de_ctx, - "alert tcp any any -> any any " - "(msg:\"Testing http_method\"; " - "content:\"FOO\"; " - "http_method; sid:1;)"); - if (s == NULL) { - goto end; - } - - s = s->next = SigInit(de_ctx, - "alert tcp any any -> any any " - "(msg:\"Testing http_method\"; " - "content:\"BAR\"; " - "http_method; sid:2;)"); - if (s == NULL) { - goto end; - } - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOSERVER, httpbuf1, httplen1); - if (r != 0) { - SCLogDebug("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - http_state = f.alstate; - if (http_state == NULL) { - SCLogDebug("no http state: "); - goto end; - } - - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - - if (!(PacketAlertCheck(p, 1))) { - goto end; - } - if (PacketAlertCheck(p, 2)) { - 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); - UTHFreePackets(&p, 1); - return result; -} - -/** \test Check a signature against an unparsable request */ -static int DetectHttpMethodSigTest03(void) -{ - int result = 0; - Flow f; - uint8_t httpbuf1[] = " "; - uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ - TcpSession ssn; - Packet *p = NULL; - Signature *s = NULL; - ThreadVars th_v; - DetectEngineThreadCtx *det_ctx; - HtpState *http_state = NULL; - 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_HTTP; - - StreamTcpInitConfig(TRUE); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } - - de_ctx->flags |= DE_QUIET; - - s = de_ctx->sig_list = SigInit(de_ctx, - "alert tcp any any -> any any " - "(msg:\"Testing http_method\"; " - "content:\"GET\"; " - "http_method; sid:1;)"); - if (s == NULL) { - SCLogDebug("Bad signature"); - goto end; - } - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOSERVER, httpbuf1, httplen1); - if (r != 0) { - SCLogDebug("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - http_state = f.alstate; - if (http_state == NULL) { - SCLogDebug("no http state: "); - goto end; - } - - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - - if (PacketAlertCheck(p, 1)) { - 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 Check a signature with an request method and negation of the same */ -static int DetectHttpMethodSigTest04(void) -{ - int result = 0; - Flow f; - uint8_t httpbuf1[] = "GET / HTTP/1.0\r\n" - "Host: foo.bar.tld\r\n" - "\r\n"; - uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ - TcpSession ssn; - Packet *p = NULL; - Signature *s = NULL; - ThreadVars th_v; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - 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_HTTP; - - StreamTcpInitConfig(TRUE); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } - - de_ctx->flags |= DE_QUIET; - - s = de_ctx->sig_list = SigInit(de_ctx, - "alert tcp any any -> any any (msg:\"Testing http_method\"; " - "content:\"GET\"; http_method; sid:1;)"); - if (s == NULL) { - goto end; - } - - s = s->next = SigInit(de_ctx, - "alert tcp any any -> any any (msg:\"Testing http_method\"; " - "content:!\"GET\"; http_method; sid:2;)"); - if (s == NULL) { - goto end; - } - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - FLOWLOCK_WRLOCK(&f); - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOSERVER, httpbuf1, httplen1); - if (r != 0) { - SCLogDebug("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - http_state = f.alstate; - if (http_state == NULL) { - SCLogDebug("no http state: "); - goto end; - } - - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - - if (!(PacketAlertCheck(p, 1))) { - printf("sid 1 didn't match but should have: "); - goto end; - } - if (PacketAlertCheck(p, 2)) { - printf("sid 2 matched but shouldn't have: "); - 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); - UTHFreePackets(&p, 1); - return result; -} - -static int DetectHttpMethodIsdataatParseTest(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_method; " - "isdataat:!4,relative; sid:1;)"); - FAIL_IF_NULL(s); - - SigMatch *sm = s->init_data->smlists_tail[g_http_method_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; -} - -#endif /* UNITTESTS */ - -/** - * \brief this function registers unit tests for DetectHttpMethod - */ -void DetectHttpMethodRegisterTests(void) -{ -#ifdef UNITTESTS /* UNITTESTS */ - SCLogDebug("Registering tests for DetectHttpMethod..."); - UtRegisterTest("DetectHttpMethodTest01", DetectHttpMethodTest01); - UtRegisterTest("DetectHttpMethodTest02", DetectHttpMethodTest02); - UtRegisterTest("DetectHttpMethodTest03", DetectHttpMethodTest03); - UtRegisterTest("DetectHttpMethodTest04", DetectHttpMethodTest04); - UtRegisterTest("DetectHttpMethodTest05", DetectHttpMethodTest05); - UtRegisterTest("DetectHttpMethodTest12 -- nocase flag", - DetectHttpMethodTest12); - UtRegisterTest("DetectHttpMethodTest13", DetectHttpMethodTest13); - UtRegisterTest("DetectHttpMethodTest14", DetectHttpMethodTest14); - UtRegisterTest("DetectHttpMethodTest15", DetectHttpMethodTest15); - UtRegisterTest("DetectHttpMethodSigTest01", DetectHttpMethodSigTest01); - UtRegisterTest("DetectHttpMethodSigTest02", DetectHttpMethodSigTest02); - UtRegisterTest("DetectHttpMethodSigTest03", DetectHttpMethodSigTest03); - UtRegisterTest("DetectHttpMethodSigTest04", DetectHttpMethodSigTest04); - - UtRegisterTest("DetectHttpMethodIsdataatParseTest", - DetectHttpMethodIsdataatParseTest); -#endif /* UNITTESTS */ -} +#ifdef UNITTESTS +#include "tests/detect-http-method.c" +#endif /** * @} diff --git a/src/runmode-unittests.c b/src/runmode-unittests.c index 926d8f9d89..dcc31c6f56 100644 --- a/src/runmode-unittests.c +++ b/src/runmode-unittests.c @@ -39,7 +39,6 @@ #include "detect-engine-hcbd.h" #include "detect-engine-hsbd.h" #include "detect-engine-hrhd.h" -#include "detect-engine-hmd.h" #include "detect-engine-hcd.h" #include "detect-engine-hsmd.h" #include "detect-engine-hscd.h" @@ -200,7 +199,6 @@ static void RegisterUnittests(void) DetectEngineHttpClientBodyRegisterTests(); DetectEngineHttpServerBodyRegisterTests(); DetectEngineHttpRawHeaderRegisterTests(); - DetectEngineHttpMethodRegisterTests(); DetectEngineHttpCookieRegisterTests(); DetectEngineHttpStatMsgRegisterTests(); DetectEngineHttpStatCodeRegisterTests(); diff --git a/src/detect-engine-hmd.c b/src/tests/detect-http-method.c similarity index 69% rename from src/detect-engine-hmd.c rename to src/tests/detect-http-method.c index f8a3df7ea4..e0a815b2a2 100644 --- a/src/detect-engine-hmd.c +++ b/src/tests/detect-http-method.c @@ -30,119 +30,18 @@ * */ -#include "suricata-common.h" -#include "suricata.h" -#include "decode.h" - -#include "detect.h" -#include "detect-engine.h" -#include "detect-engine-hmd.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 "flow-util.h" -#include "util-debug.h" -#include "util-print.h" -#include "flow.h" - -#include "stream-tcp.h" - -#include "app-layer-parser.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 "util-validate.h" - -/** \brief HTTP Method Mpm prefilter callback - * - * \param det_ctx detection engine thread ctx - * \param p packet to inspect - * \param f flow to inspect - * \param txv tx to inspect - * \param pectx inspection context - * - * \retval ret number of matches - */ -static void PrefilterTxMethod(DetectEngineThreadCtx *det_ctx, - const void *pectx, - Packet *p, Flow *f, void *txv, - const uint64_t idx, const uint8_t flags) -{ - SCEnter(); - - const MpmCtx *mpm_ctx = (MpmCtx *)pectx; - htp_tx_t *tx = (htp_tx_t *)txv; - - if (tx->request_method == NULL) - return; - - const uint32_t buffer_len = bstr_len(tx->request_method); - const uint8_t *buffer = bstr_ptr(tx->request_method); - - if (buffer_len >= mpm_ctx->minlen) { - (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, - &det_ctx->mtcu, &det_ctx->pmq, buffer, buffer_len); - } -} - -int PrefilterTxMethodRegister(DetectEngineCtx *de_ctx, - SigGroupHead *sgh, MpmCtx *mpm_ctx) -{ - return PrefilterAppendTxEngine(de_ctx, sgh, PrefilterTxMethod, - ALPROTO_HTTP, HTP_REQUEST_LINE, - mpm_ctx, NULL, "http_method"); -} - -/** - * \brief Do the http_method content inspection for a signature. - * - * \param de_ctx Detection engine context. - * \param det_ctx Detection engine thread context. - * \param s Signature to inspect. - * \param f Flow. - * \param flags App layer flags. - * \param state App layer state. - * - * \retval 0 No match. - * \retval 1 Match. - */ -int DetectEngineInspectHttpMethod(ThreadVars *tv, - DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - const Signature *s, const SigMatchData *smd, - Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) -{ - htp_tx_t *tx = (htp_tx_t *)txv; - if (tx->request_method == NULL) { - if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags) > HTP_REQUEST_LINE) - return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; - else - return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; - } - - det_ctx->buffer_offset = 0; - det_ctx->discontinue_matching = 0; - det_ctx->inspection_recursion_counter = 0; - int r = DetectEngineContentInspection(de_ctx, det_ctx, s, smd, - f, - (uint8_t *)bstr_ptr(tx->request_method), - bstr_len(tx->request_method), - 0, DETECT_CI_FLAGS_SINGLE, - DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE, NULL); - if (r == 1) - return DETECT_ENGINE_INSPECT_SIG_MATCH; - else - return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; -} - -/***********************************Unittests**********************************/ - -#ifdef UNITTESTS +#include "../suricata-common.h" +#include "../suricata.h" +#include "../flow-util.h" +#include "../flow.h" +#include "../app-layer-parser.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 "../detect-isdataat.h" /** * \test Test that the http_method content matches against a http request @@ -1750,12 +1649,715 @@ end: return result; } -#endif /* UNITTESTS */ +/** \test Check a signature with content */ +static int DetectHttpMethodTest01(void) +{ + DetectEngineCtx *de_ctx = NULL; + int result = 0; + + if ( (de_ctx = DetectEngineCtxInit()) == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + de_ctx->sig_list = SigInit(de_ctx, + "alert tcp any any -> any any " + "(msg:\"Testing http_method\"; " + "content:\"GET\"; " + "http_method; sid:1;)"); + + if (de_ctx->sig_list != NULL) { + result = 1; + } else { + printf("sig parse failed: "); + } + + end: + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + return result; +} + +/** \test Check a signature without content (fail) */ +static int DetectHttpMethodTest02(void) +{ + DetectEngineCtx *de_ctx = NULL; + int result = 0; + + if ( (de_ctx = DetectEngineCtxInit()) == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + de_ctx->sig_list = SigInit(de_ctx, + "alert tcp any any -> any any " + "(msg:\"Testing http_method\"; " + "http_method; sid:1;)"); + + if (de_ctx->sig_list == NULL) { + result = 1; + } + + end: + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + return result; +} + +/** \test Check a signature with parameter (fail) */ +static int DetectHttpMethodTest03(void) +{ + DetectEngineCtx *de_ctx = NULL; + int result = 0; + + if ( (de_ctx = DetectEngineCtxInit()) == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + de_ctx->sig_list = SigInit(de_ctx, + "alert tcp any any -> any any " + "(msg:\"Testing http_method\"; " + "content:\"foobar\"; " + "http_method:\"GET\"; sid:1;)"); + + if (de_ctx->sig_list == NULL) { + result = 1; + } + + end: + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + return result; +} + +/** \test Check a signature with fast_pattern (should work) */ +static int DetectHttpMethodTest04(void) +{ + DetectEngineCtx *de_ctx = NULL; + int result = 0; + + if ( (de_ctx = DetectEngineCtxInit()) == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + de_ctx->sig_list = SigInit(de_ctx, + "alert tcp any any -> any any " + "(msg:\"Testing http_method\"; " + "content:\"GET\"; " + "fast_pattern; " + "http_method; sid:1;)"); + + if (de_ctx->sig_list != NULL) { + result = 1; + } + + end: + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + return result; +} + +/** \test Check a signature with rawbytes (fail) */ +static int DetectHttpMethodTest05(void) +{ + DetectEngineCtx *de_ctx = NULL; + int result = 0; + + if ( (de_ctx = DetectEngineCtxInit()) == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + de_ctx->sig_list = SigInit(de_ctx, + "alert tcp any any -> any any " + "(msg:\"Testing http_method\"; " + "content:\"GET\"; " + "rawbytes; " + "http_method; sid:1;)"); + + if (de_ctx->sig_list == NULL) { + result = 1; + } + + end: + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + return result; +} + +/** \test setting the nocase flag */ +static int DetectHttpMethodTest12(void) +{ + DetectEngineCtx *de_ctx = NULL; + int result = 0; + + if ( (de_ctx = DetectEngineCtxInit()) == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + if (DetectEngineAppendSig(de_ctx, "alert http any any -> any any " + "(content:\"one\"; http_method; nocase; sid:1;)") == NULL) { + printf("DetectEngineAppend == NULL: "); + goto end; + } + if (DetectEngineAppendSig(de_ctx, "alert http any any -> any any " + "(content:\"one\"; nocase; http_method; sid:2;)") == NULL) { + printf("DetectEngineAppend == NULL: "); + goto end; + } + + if (de_ctx->sig_list->sm_lists[g_http_method_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_method_buffer_id] == NULL: "); + goto end; + } + + DetectContentData *hmd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_method_buffer_id]->ctx; + DetectContentData *hmd2 = (DetectContentData *)de_ctx->sig_list->next->sm_lists_tail[g_http_method_buffer_id]->ctx; + + if (!(hmd1->flags & DETECT_CONTENT_NOCASE)) { + printf("nocase flag not set on sig 1: "); + goto end; + } + + if (!(hmd2->flags & DETECT_CONTENT_NOCASE)) { + printf("nocase flag not set on sig 2: "); + goto end; + } + result = 1; + + end: + DetectEngineCtxFree(de_ctx); + return result; +} + +/** \test Check a signature with method + within and pcre with /M (should work) */ +static int DetectHttpMethodTest13(void) +{ + DetectEngineCtx *de_ctx = NULL; + int result = 0; + + if ( (de_ctx = DetectEngineCtxInit()) == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + de_ctx->sig_list = SigInit(de_ctx, + "alert tcp any any -> any any " + "(msg:\"Testing http_method\"; " + "pcre:\"/HE/M\"; " + "content:\"AD\"; " + "within:2; http_method; sid:1;)"); + + if (de_ctx->sig_list != NULL) { + result = 1; + } + + end: + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + return result; +} + +/** \test Check a signature with method + within and pcre without /M (should fail) */ +static int DetectHttpMethodTest14(void) +{ + DetectEngineCtx *de_ctx = NULL; + int result = 0; + + if ( (de_ctx = DetectEngineCtxInit()) == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + de_ctx->sig_list = SigInit(de_ctx, + "alert tcp any any -> any any " + "(msg:\"Testing http_method\"; " + "pcre:\"/HE/\"; " + "content:\"AD\"; " + "http_method; within:2; sid:1;)"); + + if (de_ctx->sig_list != NULL) { + result = 1; + } + + end: + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + return result; +} + +/** \test Check a signature with method + within and pcre with /M (should work) */ +static int DetectHttpMethodTest15(void) +{ + DetectEngineCtx *de_ctx = NULL; + int result = 0; + + if ( (de_ctx = DetectEngineCtxInit()) == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + de_ctx->sig_list = SigInit(de_ctx, + "alert tcp any any -> any any " + "(msg:\"Testing http_method\"; " + "pcre:\"/HE/M\"; " + "content:\"AD\"; " + "http_method; within:2; sid:1;)"); + + if (de_ctx->sig_list != NULL) { + result = 1; + } + + end: + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + return result; +} +/** \test Check a signature with an known request method */ +static int DetectHttpMethodSigTest01(void) +{ + int result = 0; + Flow f; + uint8_t httpbuf1[] = "GET / HTTP/1.0\r\n" + "Host: foo.bar.tld\r\n" + "\r\n"; + uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ + TcpSession ssn; + Packet *p = NULL; + Signature *s = NULL; + ThreadVars th_v; + DetectEngineThreadCtx *det_ctx; + HtpState *http_state = NULL; + 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_HTTP; + + StreamTcpInitConfig(TRUE); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) { + goto end; + } + + de_ctx->flags |= DE_QUIET; + + s = de_ctx->sig_list = SigInit(de_ctx, + "alert tcp any any -> any any " + "(msg:\"Testing http_method\"; " + "content:\"GET\"; " + "http_method; sid:1;)"); + if (s == NULL) { + goto end; + } + + s = s->next = SigInit(de_ctx, + "alert tcp any any -> any any " + "(msg:\"Testing http_method\"; " + "content:\"POST\"; " + "http_method; sid:2;)"); + if (s == NULL) { + goto end; + } + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); + if (r != 0) { + SCLogDebug("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + http_state = f.alstate; + if (http_state == NULL) { + SCLogDebug("no http state: "); + goto end; + } + + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + + if (!(PacketAlertCheck(p, 1))) { + goto end; + } + if (PacketAlertCheck(p, 2)) { + 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 Check a signature with an unknown request method */ +static int DetectHttpMethodSigTest02(void) +{ + int result = 0; + Flow f; + uint8_t httpbuf1[] = "FOO / HTTP/1.0\r\n" + "Host: foo.bar.tld\r\n" + "\r\n"; + uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ + TcpSession ssn; + Packet *p = NULL; + Signature *s = NULL; + ThreadVars th_v; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + 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_HTTP; + + StreamTcpInitConfig(TRUE); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) { + goto end; + } + + de_ctx->flags |= DE_QUIET; + + s = de_ctx->sig_list = SigInit(de_ctx, + "alert tcp any any -> any any " + "(msg:\"Testing http_method\"; " + "content:\"FOO\"; " + "http_method; sid:1;)"); + if (s == NULL) { + goto end; + } + + s = s->next = SigInit(de_ctx, + "alert tcp any any -> any any " + "(msg:\"Testing http_method\"; " + "content:\"BAR\"; " + "http_method; sid:2;)"); + if (s == NULL) { + goto end; + } + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); + if (r != 0) { + SCLogDebug("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + http_state = f.alstate; + if (http_state == NULL) { + SCLogDebug("no http state: "); + goto end; + } + + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + + if (!(PacketAlertCheck(p, 1))) { + goto end; + } + if (PacketAlertCheck(p, 2)) { + 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); + UTHFreePackets(&p, 1); + return result; +} + +/** \test Check a signature against an unparsable request */ +static int DetectHttpMethodSigTest03(void) +{ + int result = 0; + Flow f; + uint8_t httpbuf1[] = " "; + uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ + TcpSession ssn; + Packet *p = NULL; + Signature *s = NULL; + ThreadVars th_v; + DetectEngineThreadCtx *det_ctx; + HtpState *http_state = NULL; + 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_HTTP; + + StreamTcpInitConfig(TRUE); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) { + goto end; + } + + de_ctx->flags |= DE_QUIET; -void DetectEngineHttpMethodRegisterTests(void) + s = de_ctx->sig_list = SigInit(de_ctx, + "alert tcp any any -> any any " + "(msg:\"Testing http_method\"; " + "content:\"GET\"; " + "http_method; sid:1;)"); + if (s == NULL) { + SCLogDebug("Bad signature"); + goto end; + } + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); + if (r != 0) { + SCLogDebug("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + http_state = f.alstate; + if (http_state == NULL) { + SCLogDebug("no http state: "); + goto end; + } + + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + + if (PacketAlertCheck(p, 1)) { + 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 Check a signature with an request method and negation of the same */ +static int DetectHttpMethodSigTest04(void) { + int result = 0; + Flow f; + uint8_t httpbuf1[] = "GET / HTTP/1.0\r\n" + "Host: foo.bar.tld\r\n" + "\r\n"; + uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ + TcpSession ssn; + Packet *p = NULL; + Signature *s = NULL; + ThreadVars th_v; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + 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_HTTP; + + StreamTcpInitConfig(TRUE); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) { + goto end; + } + + de_ctx->flags |= DE_QUIET; -#ifdef UNITTESTS + s = de_ctx->sig_list = SigInit(de_ctx, + "alert tcp any any -> any any (msg:\"Testing http_method\"; " + "content:\"GET\"; http_method; sid:1;)"); + if (s == NULL) { + goto end; + } + + s = s->next = SigInit(de_ctx, + "alert tcp any any -> any any (msg:\"Testing http_method\"; " + "content:!\"GET\"; http_method; sid:2;)"); + if (s == NULL) { + goto end; + } + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); + if (r != 0) { + SCLogDebug("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + http_state = f.alstate; + if (http_state == NULL) { + SCLogDebug("no http state: "); + goto end; + } + + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + + if (!(PacketAlertCheck(p, 1))) { + printf("sid 1 didn't match but should have: "); + goto end; + } + if (PacketAlertCheck(p, 2)) { + printf("sid 2 matched but shouldn't have: "); + 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); + UTHFreePackets(&p, 1); + return result; +} + +static int DetectHttpMethodIsdataatParseTest(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_method; " + "isdataat:!4,relative; sid:1;)"); + FAIL_IF_NULL(s); + + SigMatch *sm = s->init_data->smlists_tail[g_http_method_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; +} + +/** + * \brief this function registers unit tests for DetectHttpMethod + */ +void DetectHttpMethodRegisterTests(void) +{ + UtRegisterTest("DetectHttpMethodTest01", DetectHttpMethodTest01); + UtRegisterTest("DetectHttpMethodTest02", DetectHttpMethodTest02); + UtRegisterTest("DetectHttpMethodTest03", DetectHttpMethodTest03); + UtRegisterTest("DetectHttpMethodTest04", DetectHttpMethodTest04); + UtRegisterTest("DetectHttpMethodTest05", DetectHttpMethodTest05); + UtRegisterTest("DetectHttpMethodTest12 -- nocase flag", + DetectHttpMethodTest12); + UtRegisterTest("DetectHttpMethodTest13", DetectHttpMethodTest13); + UtRegisterTest("DetectHttpMethodTest14", DetectHttpMethodTest14); + UtRegisterTest("DetectHttpMethodTest15", DetectHttpMethodTest15); + UtRegisterTest("DetectHttpMethodSigTest01", DetectHttpMethodSigTest01); + UtRegisterTest("DetectHttpMethodSigTest02", DetectHttpMethodSigTest02); + UtRegisterTest("DetectHttpMethodSigTest03", DetectHttpMethodSigTest03); + UtRegisterTest("DetectHttpMethodSigTest04", DetectHttpMethodSigTest04); + + UtRegisterTest("DetectHttpMethodIsdataatParseTest", + DetectHttpMethodIsdataatParseTest); UtRegisterTest("DetectEngineHttpMethodTest01", DetectEngineHttpMethodTest01); UtRegisterTest("DetectEngineHttpMethodTest02", @@ -1790,10 +2392,8 @@ void DetectEngineHttpMethodRegisterTests(void) DetectEngineHttpMethodTest16); UtRegisterTest("DetectEngineHttpMethodTest17", DetectEngineHttpMethodTest17); -#endif /* UNITTESTS */ - - return; } + /** * @} */