From 2f342da048051bca5752bc1fa6ee876ff8fd5802 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 26 Nov 2018 13:13:59 +0100 Subject: [PATCH] detect/http_stat_code: move tests into tests/ --- src/Makefile.am | 1 - src/detect-engine-hscd.h | 28 - src/detect-engine-mpm.c | 1 - src/detect-engine-register.c | 1 - src/detect-http-stat-code.c | 584 +---------------- src/runmode-unittests.c | 2 - .../detect-http-stat-code.c} | 615 ++++++++++++++++-- 7 files changed, 582 insertions(+), 650 deletions(-) delete mode 100644 src/detect-engine-hscd.h rename src/{detect-engine-hscd.c => tests/detect-http-stat-code.c} (76%) diff --git a/src/Makefile.am b/src/Makefile.am index 05edb783aa..b4a62f0d03 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -135,7 +135,6 @@ detect-engine-hcbd.c detect-engine-hcbd.h \ detect-engine-hcd.c detect-engine-hcd.h \ detect-engine-hrhd.c detect-engine-hrhd.h \ detect-engine-hsbd.c detect-engine-hsbd.h \ -detect-engine-hscd.c detect-engine-hscd.h \ detect-engine-iponly.c detect-engine-iponly.h \ detect-engine-loader.c detect-engine-loader.h \ detect-engine-mpm.c detect-engine-mpm.h \ diff --git a/src/detect-engine-hscd.h b/src/detect-engine-hscd.h deleted file mode 100644 index 90fb9d71df..0000000000 --- a/src/detect-engine-hscd.h +++ /dev/null @@ -1,28 +0,0 @@ -/* Copyright (C) 2007-2016 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_HSCD_H__ -#define __DETECT_ENGINE_HSCD_H__ - -void DetectEngineHttpStatCodeRegisterTests(void); - -#endif /* __DETECT_ENGINE_HSCD_H__ */ diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index fea3ae9ed1..b838fdaafa 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -52,7 +52,6 @@ #include "detect-engine-payload.h" #include "detect-engine-hrhd.h" #include "detect-engine-hcd.h" -#include "detect-engine-hscd.h" #include "detect-engine-hcbd.h" #include "detect-engine-hsbd.h" #include "detect-engine-dns.h" diff --git a/src/detect-engine-register.c b/src/detect-engine-register.c index 57d52b85fe..15081b7dd0 100644 --- a/src/detect-engine-register.c +++ b/src/detect-engine-register.c @@ -157,7 +157,6 @@ #include "detect-engine-hsbd.h" #include "detect-engine-hrhd.h" #include "detect-engine-hcd.h" -#include "detect-engine-hscd.h" #include "detect-byte-extract.h" #include "detect-file-data.h" #include "detect-pkt-data.h" diff --git a/src/detect-http-stat-code.c b/src/detect-http-stat-code.c index a2ef823eb1..02ad637b4c 100644 --- a/src/detect-http-stat-code.c +++ b/src/detect-http-stat-code.c @@ -60,14 +60,14 @@ #include "app-layer-htp.h" #include "detect-http-stat-code.h" -#include "detect-engine-hscd.h" #include "stream-tcp-private.h" #include "stream-tcp.h" static int DetectHttpStatCodeSetup(DetectEngineCtx *, Signature *, const char *); +#ifdef UNITTESTS static void DetectHttpStatCodeRegisterTests(void); +#endif static int g_http_stat_code_buffer_id = 0; - static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, const int list_id); @@ -81,8 +81,9 @@ void DetectHttpStatCodeRegister (void) sigmatch_table[DETECT_AL_HTTP_STAT_CODE].desc = "content modifier to match only on HTTP stat-code-buffer"; sigmatch_table[DETECT_AL_HTTP_STAT_CODE].url = DOC_URL DOC_VERSION "/rules/http-keywords.html#http-stat-code"; sigmatch_table[DETECT_AL_HTTP_STAT_CODE].Setup = DetectHttpStatCodeSetup; +#ifdef UNITTESTS sigmatch_table[DETECT_AL_HTTP_STAT_CODE].RegisterTests = DetectHttpStatCodeRegisterTests; - +#endif sigmatch_table[DETECT_AL_HTTP_STAT_CODE].flags |= SIGMATCH_NOOPT; DetectAppLayerInspectEngineRegister2("http_stat_code", ALPROTO_HTTP, @@ -142,583 +143,8 @@ static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, } #ifdef UNITTESTS - -/** - * \test Checks if a http_stat_code is registered in a Signature, if content is not - * specified in the signature or rawbyes is specified or fast_pattern is - * provided in the signature. - */ -static int DetectHttpStatCodeTest01(void) -{ - DetectEngineCtx *de_ctx = NULL; - int result = 0; - - if ((de_ctx = DetectEngineCtxInit()) == NULL) { - printf("DetectEngineCtxInit failed: "); - goto end; - } - - de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Testing http_stat_code\"; http_stat_code; sid:1;)"); - if (de_ctx->sig_list != NULL) { - printf("sid 1 parse failed to error out: "); - goto end; - } - - de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Testing http_stat_code\"; content:\"|FF F1|\";" - " rawbytes; http_stat_code; sid:2;)"); - if (de_ctx->sig_list != NULL) { - printf("sid 2 parse failed to error out: "); - goto end; - } - - de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Testing http_stat_code\"; content:\"100\";" - "fast_pattern; http_stat_code; sid:3;)"); - if (de_ctx->sig_list == NULL) { - printf("sid 3 parse failed: "); - goto end; - } - if (!(((DetectContentData *)de_ctx->sig_list->sm_lists[g_http_stat_code_buffer_id]->ctx)->flags & - DETECT_CONTENT_FAST_PATTERN)) - { - goto end; - } - - result = 1; -end: - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - return result; -} - -/** - * \test Checks if a http_stat_code is registered in a Signature and also checks - * the nocase - */ -static int DetectHttpStatCodeTest02(void) -{ - SigMatch *sm = NULL; - 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_stat_code\"; content:\"one\"; " - "http_stat_code; content:\"200\"; http_stat_code; " - "content:\"two hundred\"; nocase; http_stat_code; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) { - printf("sig parse failed: "); - goto end; - } - - result = 0; - sm = de_ctx->sig_list->sm_lists[g_http_stat_code_buffer_id]; - if (sm == NULL) { - printf("no sigmatch(es): "); - goto end; - } - - SigMatch *prev = NULL; - while (sm != NULL) { - if (sm->type == DETECT_CONTENT) { - result = 1; - } else { - printf("expected DETECT_CONTENT for http_stat_code, got %d: ", sm->type); - goto end; - } - prev = sm; - sm = sm->next; - } - - if (! (((DetectContentData *)prev->ctx)->flags & - DETECT_CONTENT_NOCASE)) - { - result = 0; - } -end: - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - return result; -} - -/** \test Check the signature working to alert when http_stat_code is matched . */ -static int DetectHttpStatCodeSigTest01(void) -{ - int result = 0; - Flow f; - uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n\r\n"; - uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ - uint8_t httpbuf2[] = "HTTP/1.0 200 OK\r\n\r\n"; - uint32_t httplen2 = sizeof(httpbuf2) - 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_TOCLIENT; - 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) { - printf("DetectEngineCtxInit failed: "); - goto end; - } - - de_ctx->flags |= DE_QUIET; - - s = de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any (msg:" - "\"HTTP status code\"; content:\"200\"; http_stat_code; sid:1;)"); - if (s == NULL) { - printf("sig parse failed: "); - 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) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - FLOWLOCK_UNLOCK(&f); - goto end; - } - - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOCLIENT, httpbuf2, httplen2); - if (r != 0) { - printf("toclient chunk 1 returned %" PRId32 ", expected 0: ", r); - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - 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 (det_ctx != NULL) { - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - } - if (de_ctx != NULL) { - DetectEngineCtxFree(de_ctx); - } - - StreamTcpFreeConfig(TRUE); - - UTHFreePackets(&p, 1); - return result; -} - -/** \test Check the signature working to alert when http_stat_code is not matched . */ -static int DetectHttpStatCodeSigTest02(void) -{ - int result = 0; - Flow f; - uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n\r\n"; - uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ - uint8_t httpbuf2[] = "HTTP/1.0 200 OK\r\n\r\n"; - uint32_t httplen2 = sizeof(httpbuf2) - 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_TOCLIENT; - 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 http any any -> any any (msg:" - "\"HTTP status code\"; content:\"no\"; " - "http_stat_code; sid:1;)"); - if (s == NULL) { - goto end; - } - - s->next = SigInit(de_ctx,"alert http any any -> any any (msg:\"HTTP " - "Status code\"; content:\"100\";" - "http_stat_code; sid:2;)"); - if (s->next == 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) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - FLOWLOCK_UNLOCK(&f); - goto end; - } - - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOCLIENT, httpbuf2, httplen2); - if (r != 0) { - printf("toclient chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - 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 matched but shouldn't: "); - goto end; - } - if ((PacketAlertCheck(p, 2))) { - printf("sid 2 match 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); - - UTHFreePackets(&p, 1); - return result; -} - -/** \test Check the signature working to alert when http_stat_code is matched for - * for nocase or not */ -static int DetectHttpStatCodeSigTest03(void) -{ - int result = 0; - Flow f; - uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n\r\n"; - uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ - uint8_t httpbuf2[] = "HTTP/1.0 FAIL OK\r\n\r\n"; - uint32_t httplen2 = sizeof(httpbuf2) - 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_TOCLIENT; - 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 http any any -> any any (msg:" - "\"HTTP status code\"; content:\"FAIL\"; " - "http_stat_code; sid:1;)"); - if (s == NULL) { - goto end; - } - - s->next = SigInit(de_ctx,"alert http any any -> any any (msg:\"HTTP " - "Status code nocase\"; content:\"fail\"; nocase; " - "http_stat_code; sid:2;)"); - if (s->next == 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) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - FLOWLOCK_UNLOCK(&f); - goto end; - } - - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOCLIENT, httpbuf2, httplen2); - if (r != 0) { - printf("toclient chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - 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; - } - if (!(PacketAlertCheck(p, 2))) { - printf("sid 2 didn't match but should 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); - - UTHFreePackets(&p, 1); - return result; -} - -/** \test Check the signature working to alert when http_stat_code is matched for - * for negatoin or not */ -static int DetectHttpStatCodeSigTest04(void) -{ - int result = 0; - Flow f; - uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n\r\n"; - uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ - uint8_t httpbuf2[] = "HTTP/1.0 200 OK\r\n\r\n"; - uint32_t httplen2 = sizeof(httpbuf2) - 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_TOCLIENT; - 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 http any any -> any any (msg:" - "\"HTTP status code\"; content:\"200\"; " - "http_stat_code; sid:1;)"); - if (s == NULL) { - goto end; - } - - s->next = SigInit(de_ctx,"alert http any any -> any any (msg:\"HTTP " - "Status code negation\"; content:!\"100\"; nocase; " - "http_stat_code; sid:2;)"); - if (s->next == 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) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - FLOWLOCK_UNLOCK(&f); - goto end; - } - - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, - STREAM_TOCLIENT, httpbuf2, httplen2); - if (r != 0) { - printf("toclient chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - FLOWLOCK_UNLOCK(&f); - goto end; - } - FLOWLOCK_UNLOCK(&f); - - 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; - } - if (!(PacketAlertCheck(p, 2))) { - printf("sid 2 didn't match but should 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); - - UTHFreePackets(&p, 1); - return result; -} - -#endif /* UNITTESTS */ - -/** - * \brief Register the UNITTESTS for the http_stat_code keyword - */ -void DetectHttpStatCodeRegisterTests (void) -{ -#ifdef UNITTESTS /* UNITTESTS */ - - UtRegisterTest("DetectHttpStatCodeTest01", DetectHttpStatCodeTest01); - UtRegisterTest("DetectHttpStatCodeTest02", DetectHttpStatCodeTest02); - UtRegisterTest("DetectHttpStatCodeSigTest01", DetectHttpStatCodeSigTest01); - UtRegisterTest("DetectHttpStatCodeSigTest02", DetectHttpStatCodeSigTest02); - UtRegisterTest("DetectHttpStatCodeSigTest03", DetectHttpStatCodeSigTest03); - UtRegisterTest("DetectHttpStatCodeSigTest04", DetectHttpStatCodeSigTest04); - +#include "tests/detect-http-stat-code.c" #endif /* UNITTESTS */ -} /** * @} diff --git a/src/runmode-unittests.c b/src/runmode-unittests.c index 81f5e85a74..dc4cba74c9 100644 --- a/src/runmode-unittests.c +++ b/src/runmode-unittests.c @@ -40,7 +40,6 @@ #include "detect-engine-hsbd.h" #include "detect-engine-hrhd.h" #include "detect-engine-hcd.h" -#include "detect-engine-hscd.h" #include "detect-engine-state.h" #include "detect-engine-tag.h" #include "detect-engine-modbus.h" @@ -197,7 +196,6 @@ static void RegisterUnittests(void) DetectEngineHttpServerBodyRegisterTests(); DetectEngineHttpRawHeaderRegisterTests(); DetectEngineHttpCookieRegisterTests(); - DetectEngineHttpStatCodeRegisterTests(); DetectEngineInspectModbusRegisterTests(); DetectEngineRegisterTests(); DetectEngineSMTPFiledataRegisterTests(); diff --git a/src/detect-engine-hscd.c b/src/tests/detect-http-stat-code.c similarity index 76% rename from src/detect-engine-hscd.c rename to src/tests/detect-http-stat-code.c index 1507e84e8b..5987b0e3e3 100644 --- a/src/detect-engine-hscd.c +++ b/src/tests/detect-http-stat-code.c @@ -28,41 +28,19 @@ * \author Victor Julien */ -#include "suricata-common.h" -#include "suricata.h" -#include "decode.h" - -#include "detect.h" -#include "detect-engine.h" -#include "detect-engine-mpm.h" -#include "detect-engine-hscd.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" - -/***********************************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" static int DetectEngineHttpStatCodeTest01(void) - { +{ TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; @@ -1957,12 +1935,569 @@ end: return result; } -#endif /* UNITTESTS */ +/** + * \test Checks if a http_stat_code is registered in a Signature, if content is not + * specified in the signature or rawbyes is specified or fast_pattern is + * provided in the signature. + */ +static int DetectHttpStatCodeTest01(void) +{ + DetectEngineCtx *de_ctx = NULL; + int result = 0; + + if ((de_ctx = DetectEngineCtxInit()) == NULL) { + printf("DetectEngineCtxInit failed: "); + goto end; + } + + de_ctx->flags |= DE_QUIET; + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " + "(msg:\"Testing http_stat_code\"; http_stat_code; sid:1;)"); + if (de_ctx->sig_list != NULL) { + printf("sid 1 parse failed to error out: "); + goto end; + } + + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " + "(msg:\"Testing http_stat_code\"; content:\"|FF F1|\";" + " rawbytes; http_stat_code; sid:2;)"); + if (de_ctx->sig_list != NULL) { + printf("sid 2 parse failed to error out: "); + goto end; + } + + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " + "(msg:\"Testing http_stat_code\"; content:\"100\";" + "fast_pattern; http_stat_code; sid:3;)"); + if (de_ctx->sig_list == NULL) { + printf("sid 3 parse failed: "); + goto end; + } + if (!(((DetectContentData *)de_ctx->sig_list->sm_lists[g_http_stat_code_buffer_id]->ctx)->flags & + DETECT_CONTENT_FAST_PATTERN)) + { + goto end; + } + + result = 1; +end: + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + return result; +} -void DetectEngineHttpStatCodeRegisterTests(void) +/** + * \test Checks if a http_stat_code is registered in a Signature and also checks + * the nocase + */ +static int DetectHttpStatCodeTest02(void) { + SigMatch *sm = NULL; + 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_stat_code\"; content:\"one\"; " + "http_stat_code; content:\"200\"; http_stat_code; " + "content:\"two hundred\"; nocase; http_stat_code; " + "sid:1;)"); + if (de_ctx->sig_list == NULL) { + printf("sig parse failed: "); + goto end; + } -#ifdef UNITTESTS + result = 0; + sm = de_ctx->sig_list->sm_lists[g_http_stat_code_buffer_id]; + if (sm == NULL) { + printf("no sigmatch(es): "); + goto end; + } + + SigMatch *prev = NULL; + while (sm != NULL) { + if (sm->type == DETECT_CONTENT) { + result = 1; + } else { + printf("expected DETECT_CONTENT for http_stat_code, got %d: ", sm->type); + goto end; + } + prev = sm; + sm = sm->next; + } + + if (! (((DetectContentData *)prev->ctx)->flags & + DETECT_CONTENT_NOCASE)) + { + result = 0; + } +end: + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + return result; +} + +/** \test Check the signature working to alert when http_stat_code is matched . */ +static int DetectHttpStatCodeSigTest01(void) +{ + int result = 0; + Flow f; + uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n\r\n"; + uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ + uint8_t httpbuf2[] = "HTTP/1.0 200 OK\r\n\r\n"; + uint32_t httplen2 = sizeof(httpbuf2) - 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_TOCLIENT; + 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) { + printf("DetectEngineCtxInit failed: "); + goto end; + } + + de_ctx->flags |= DE_QUIET; + + s = de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any (msg:" + "\"HTTP status code\"; content:\"200\"; http_stat_code; sid:1;)"); + if (s == NULL) { + printf("sig parse failed: "); + 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) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + FLOWLOCK_UNLOCK(&f); + goto end; + } + + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, httpbuf2, httplen2); + if (r != 0) { + printf("toclient chunk 1 returned %" PRId32 ", expected 0: ", r); + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: "); + 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 (det_ctx != NULL) { + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + } + if (de_ctx != NULL) { + DetectEngineCtxFree(de_ctx); + } + + StreamTcpFreeConfig(TRUE); + + UTHFreePackets(&p, 1); + return result; +} + +/** \test Check the signature working to alert when http_stat_code is not matched . */ +static int DetectHttpStatCodeSigTest02(void) +{ + int result = 0; + Flow f; + uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n\r\n"; + uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ + uint8_t httpbuf2[] = "HTTP/1.0 200 OK\r\n\r\n"; + uint32_t httplen2 = sizeof(httpbuf2) - 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_TOCLIENT; + 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 http any any -> any any (msg:" + "\"HTTP status code\"; content:\"no\"; " + "http_stat_code; sid:1;)"); + if (s == NULL) { + goto end; + } + + s->next = SigInit(de_ctx,"alert http any any -> any any (msg:\"HTTP " + "Status code\"; content:\"100\";" + "http_stat_code; sid:2;)"); + if (s->next == 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) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + FLOWLOCK_UNLOCK(&f); + goto end; + } + + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, httpbuf2, httplen2); + if (r != 0) { + printf("toclient chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + 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 matched but shouldn't: "); + goto end; + } + if ((PacketAlertCheck(p, 2))) { + printf("sid 2 match 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); + + UTHFreePackets(&p, 1); + return result; +} + +/** \test Check the signature working to alert when http_stat_code is matched for + * for nocase or not */ +static int DetectHttpStatCodeSigTest03(void) +{ + int result = 0; + Flow f; + uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n\r\n"; + uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ + uint8_t httpbuf2[] = "HTTP/1.0 FAIL OK\r\n\r\n"; + uint32_t httplen2 = sizeof(httpbuf2) - 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_TOCLIENT; + 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 http any any -> any any (msg:" + "\"HTTP status code\"; content:\"FAIL\"; " + "http_stat_code; sid:1;)"); + if (s == NULL) { + goto end; + } + + s->next = SigInit(de_ctx,"alert http any any -> any any (msg:\"HTTP " + "Status code nocase\"; content:\"fail\"; nocase; " + "http_stat_code; sid:2;)"); + if (s->next == 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) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + FLOWLOCK_UNLOCK(&f); + goto end; + } + + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, httpbuf2, httplen2); + if (r != 0) { + printf("toclient chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + 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; + } + if (!(PacketAlertCheck(p, 2))) { + printf("sid 2 didn't match but should 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); + + UTHFreePackets(&p, 1); + return result; +} + +/** \test Check the signature working to alert when http_stat_code is matched for + * for negatoin or not */ +static int DetectHttpStatCodeSigTest04(void) +{ + int result = 0; + Flow f; + uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n\r\n"; + uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ + uint8_t httpbuf2[] = "HTTP/1.0 200 OK\r\n\r\n"; + uint32_t httplen2 = sizeof(httpbuf2) - 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_TOCLIENT; + 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 http any any -> any any (msg:" + "\"HTTP status code\"; content:\"200\"; " + "http_stat_code; sid:1;)"); + if (s == NULL) { + goto end; + } + + s->next = SigInit(de_ctx,"alert http any any -> any any (msg:\"HTTP " + "Status code negation\"; content:!\"100\"; nocase; " + "http_stat_code; sid:2;)"); + if (s->next == 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) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + FLOWLOCK_UNLOCK(&f); + goto end; + } + + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, httpbuf2, httplen2); + if (r != 0) { + printf("toclient chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + 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; + } + if (!(PacketAlertCheck(p, 2))) { + printf("sid 2 didn't match but should 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); + + UTHFreePackets(&p, 1); + return result; +} + +/** + * \brief Register the UNITTESTS for the http_stat_code keyword + */ +void DetectHttpStatCodeRegisterTests (void) +{ UtRegisterTest("DetectEngineHttpStatCodeTest01", DetectEngineHttpStatCodeTest01); UtRegisterTest("DetectEngineHttpStatCodeTest02", @@ -1993,9 +2528,13 @@ void DetectEngineHttpStatCodeRegisterTests(void) DetectEngineHttpStatCodeTest14); UtRegisterTest("DetectEngineHttpStatCodeTest15", DetectEngineHttpStatCodeTest15); -#endif /* UNITTESTS */ - return; + UtRegisterTest("DetectHttpStatCodeTest01", DetectHttpStatCodeTest01); + UtRegisterTest("DetectHttpStatCodeTest02", DetectHttpStatCodeTest02); + UtRegisterTest("DetectHttpStatCodeSigTest01", DetectHttpStatCodeSigTest01); + UtRegisterTest("DetectHttpStatCodeSigTest02", DetectHttpStatCodeSigTest02); + UtRegisterTest("DetectHttpStatCodeSigTest03", DetectHttpStatCodeSigTest03); + UtRegisterTest("DetectHttpStatCodeSigTest04", DetectHttpStatCodeSigTest04); } /**