From 988c92f71c7b83454aa3effb1f6160a2cbba109a Mon Sep 17 00:00:00 2001 From: Anoop Saldanha Date: Tue, 12 Jun 2012 19:51:12 +0530 Subject: [PATCH] http user agent keyword + mpm + inspection + fast pattern support added --- src/Makefile.am | 2 + src/detect-content.h | 11 +- src/detect-depth.c | 7 +- src/detect-distance.c | 9 +- src/detect-engine-content-inspection.h | 1 + src/detect-engine-hua.c | 1789 ++++++++++++++++++ src/detect-engine-hua.h | 33 + src/detect-engine-mpm.c | 104 +- src/detect-engine-mpm.h | 1 + src/detect-engine-state.c | 41 +- src/detect-engine-state.h | 36 +- src/detect-fast-pattern.c | 1239 ++++++++++++- src/detect-http-ua.c | 2354 ++++++++++++++++++++++++ src/detect-http-ua.h | 29 + src/detect-isdataat.c | 22 +- src/detect-nocase.c | 12 +- src/detect-offset.c | 9 +- src/detect-parse.c | 8 +- src/detect-pcre.c | 21 +- src/detect-pcre.h | 4 +- src/detect-within.c | 8 +- src/detect.c | 34 +- src/detect.h | 8 + src/suricata-common.h | 1 + src/suricata.c | 2 + 25 files changed, 5716 insertions(+), 69 deletions(-) create mode 100644 src/detect-engine-hua.c create mode 100644 src/detect-engine-hua.h create mode 100644 src/detect-http-ua.c create mode 100644 src/detect-http-ua.h diff --git a/src/Makefile.am b/src/Makefile.am index 7cc62503ee..10476cf7cd 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -92,6 +92,7 @@ detect-engine-hcd.c detect-engine-hcd.h \ detect-engine-hrud.c detect-engine-hrud.h \ detect-engine-hsmd.c detect-engine-hsmd.h \ detect-engine-hscd.c detect-engine-hscd.h \ +detect-engine-hua.c detect-engine-hua.h \ detect-engine-state.c detect-engine-state.h \ detect-engine-file.c detect-engine-file.h \ detect-engine-analyzer.c detect-engine-analyzer.h \ @@ -149,6 +150,7 @@ detect-http-raw-header.c detect-http-raw-header.h \ detect-http-uri.c detect-http-uri.h \ detect-http-raw-uri.c detect-http-raw-uri.h \ detect-file-data.c detect-file-data.h \ +detect-http-ua.c detect-http-ua.h \ detect-tls.c detect-tls.h \ detect-tls-version.c detect-tls-version.h \ detect-ssh-proto-version.c detect-ssh-proto-version.h \ diff --git a/src/detect-content.h b/src/detect-content.h index aa1734c390..83500f08a6 100644 --- a/src/detect-content.h +++ b/src/detect-content.h @@ -54,15 +54,16 @@ #define DETECT_CONTENT_HRUD_MPM 0x00100000 #define DETECT_CONTENT_HSMD_MPM 0x00200000 #define DETECT_CONTENT_HSCD_MPM 0x00400000 +#define DETECT_CONTENT_HUAD_MPM 0x00800000 /* BE - byte extract */ -#define DETECT_CONTENT_OFFSET_BE 0x00800000 -#define DETECT_CONTENT_DEPTH_BE 0x01000000 -#define DETECT_CONTENT_DISTANCE_BE 0x02000000 -#define DETECT_CONTENT_WITHIN_BE 0x04000000 +#define DETECT_CONTENT_OFFSET_BE 0x01000000 +#define DETECT_CONTENT_DEPTH_BE 0x02000000 +#define DETECT_CONTENT_DISTANCE_BE 0x04000000 +#define DETECT_CONTENT_WITHIN_BE 0x08000000 /* replace data */ -#define DETECT_CONTENT_REPLACE 0x08000000 +#define DETECT_CONTENT_REPLACE 0x10000000 #define DETECT_CONTENT_IS_SINGLE(c) (!((c)->flags & DETECT_CONTENT_DISTANCE || \ (c)->flags & DETECT_CONTENT_WITHIN || \ diff --git a/src/detect-depth.c b/src/detect-depth.c index ddd4aea401..7ab89966b7 100644 --- a/src/detect-depth.c +++ b/src/detect-depth.c @@ -85,7 +85,7 @@ static int DetectDepthSetup (DetectEngineCtx *de_ctx, Signature *s, char *depths break; default: - pm = SigMatchGetLastSMFromLists(s, 22, + pm = SigMatchGetLastSMFromLists(s, 24, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], @@ -96,13 +96,14 @@ static int DetectDepthSetup (DetectEngineCtx *de_ctx, Signature *s, char *depths DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]); + DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], + DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]); if (pm == NULL) { SCLogError(SC_ERR_DEPTH_MISSING_CONTENT, "depth needs " "preceeding content, uricontent option, http_client_body, " "http_server_body, http_header option, http_raw_header option, " "http_method option, http_cookie, http_raw_uri, " - "http_stat_msg or http_stat_code option"); + "http_stat_msg, http_stat_code or http_user_agent option"); if (dubbed) SCFree(str); return -1; diff --git a/src/detect-distance.c b/src/detect-distance.c index 87f3e78f2c..fbcd969c43 100644 --- a/src/detect-distance.c +++ b/src/detect-distance.c @@ -160,7 +160,7 @@ static int DetectDistanceSetup (DetectEngineCtx *de_ctx, Signature *s, } } } else { - pm = SigMatchGetLastSMFromLists(s, 22, + pm = SigMatchGetLastSMFromLists(s, 24, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], @@ -171,13 +171,14 @@ static int DetectDistanceSetup (DetectEngineCtx *de_ctx, Signature *s, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]); + DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], + DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]); if (pm == NULL) { SCLogError(SC_ERR_WITHIN_MISSING_CONTENT, "within needs " "preceeding content, uricontent option, http_client_body, " "http_server_body, http_header, http_raw_header, http_method, " - "http_cookie, http_raw_uri, http_stat_msg or http_stat_code " - "option"); + "http_cookie, http_raw_uri, http_stat_msg, http_stat_code " + "or http_user_agent option"); if (dubbed) SCFree(str); return -1; diff --git a/src/detect-engine-content-inspection.h b/src/detect-engine-content-inspection.h index 21c94743c6..d8402ca827 100644 --- a/src/detect-engine-content-inspection.h +++ b/src/detect-engine-content-inspection.h @@ -38,6 +38,7 @@ enum { DETECT_ENGINE_CONTENT_INSPECTION_MODE_HMD, DETECT_ENGINE_CONTENT_INSPECTION_MODE_HSCD, DETECT_ENGINE_CONTENT_INSPECTION_MODE_HSMD, + DETECT_ENGINE_CONTENT_INSPECTION_MODE_HUAD, }; int DetectEngineContentInspection(DetectEngineCtx *, diff --git a/src/detect-engine-hua.c b/src/detect-engine-hua.c new file mode 100644 index 0000000000..a7f5937163 --- /dev/null +++ b/src/detect-engine-hua.c @@ -0,0 +1,1789 @@ +/* Copyright (C) 2007-2012 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 + * + * \brief Handle HTTP user agent match + * + */ + +#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 "flow-util.h" +#include "util-debug.h" +#include "util-print.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-engine-hua.h" + +int DetectEngineRunHttpUAMpm(DetectEngineThreadCtx *det_ctx, Flow *f, + HtpState *htp_state, uint8_t flags) +{ + htp_tx_t *tx = NULL; + uint32_t cnt = 0; + int idx; + + /* we need to lock because the buffers are not actually true buffers + * but are ones that point to a buffer given by libhtp */ + FLOWLOCK_RDLOCK(f); + + if (htp_state == NULL) { + SCLogDebug("no HTTP state"); + goto end; + } + + if (htp_state->connp == NULL || htp_state->connp->conn == NULL) { + SCLogDebug("HTP state has no conn(p)"); + goto end; + } + + idx = AppLayerTransactionGetInspectId(f); + if (idx == -1) { + goto end; + } + + int size = (int)list_size(htp_state->connp->conn->transactions); + for (; idx < size; idx++) { + + tx = list_get(htp_state->connp->conn->transactions, idx); + if (tx == NULL) + continue; + + htp_header_t *h = (htp_header_t *)table_getc(tx->request_headers, + "User-Agent"); + if (h == NULL) { + SCLogDebug("HTTP user agent header not present in this request"); + continue; + } + + cnt += HttpUAPatternSearch(det_ctx, + (uint8_t *)bstr_ptr(h->value), + bstr_len(h->value), flags); + } + + end: + FLOWLOCK_UNLOCK(f); + return cnt; +} + +/** + * \brief Do the http_user_agent 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 DetectEngineInspectHttpUA(DetectEngineCtx *de_ctx, + DetectEngineThreadCtx *det_ctx, + Signature *s, Flow *f, uint8_t flags, + void *alstate) +{ + SCEnter(); + + int r = 0; + HtpState *htp_state = NULL; + htp_tx_t *tx = NULL; + int idx; + + FLOWLOCK_RDLOCK(f); + + htp_state = (HtpState *)alstate; + if (htp_state == NULL) { + SCLogDebug("no HTTP state"); + goto end; + } + + if (htp_state->connp == NULL || htp_state->connp->conn == NULL) { + SCLogDebug("HTP state has no conn(p)"); + goto end; + } + + idx = AppLayerTransactionGetInspectId(f); + if (idx == -1) { + goto end; + } + + int size = (int)list_size(htp_state->connp->conn->transactions); + for (; idx < size; idx++) { + tx = list_get(htp_state->connp->conn->transactions, idx); + if (tx == NULL) + continue; + + htp_header_t *h = (htp_header_t *)table_getc(tx->request_headers, + "User-Agent"); + if (h == NULL) { + SCLogDebug("HTTP user agent header not present in this request"); + continue; + } + + det_ctx->buffer_offset = 0; + det_ctx->discontinue_matching = 0; + det_ctx->inspection_recursion_counter = 0; + + r = DetectEngineContentInspection(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_HUADMATCH], + f, + (uint8_t *)bstr_ptr(h->value), + bstr_len(h->value), + DETECT_ENGINE_CONTENT_INSPECTION_MODE_HUAD, NULL); + if (r == 1) { + break; + } + } + +end: + FLOWLOCK_UNLOCK(f); + SCReturnInt(r); +} + +/***********************************Unittests**********************************/ + +#ifdef UNITTESTS + +/** + * \test Test that the http_user_agent content matches against a http request + * which holds the content. + */ +static int DetectEngineHttpUATest01(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" + "User-Agent: CONNECT\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint32_t http_len = sizeof(http_buf) - 1; + int result = 0; + + 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.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); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " + "(msg:\"http user agent test\"; " + "content:\"CONNECT\"; http_user_agent; " + "sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, 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 (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); + return result; +} + +/** + * \test Test that the http_user_agent content matches against a http request + * which holds the content. + */ +static int DetectEngineHttpUATest02(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[] = + "CONNECT /index.html HTTP/1.0\r\n" + "User-Agent: CONNECT\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint32_t http_len = sizeof(http_buf) - 1; + int result = 0; + + 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.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); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " + "(msg:\"http user agent test\"; " + "content:\"CO\"; depth:4; http_user_agent; " + "sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, 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 (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); + return result; +} + +/** + * \test Test that the http_user_agent content matches against a http request + * which holds the content. + */ +static int DetectEngineHttpUATest03(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[] = + "CONNECT /index.html HTTP/1.0\r\n" + "User-Agent: CONNECT\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint32_t http_len = sizeof(http_buf) - 1; + int result = 0; + + 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.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); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " + "(msg:\"http_user_agent test\"; " + "content:!\"ECT\"; depth:4; http_user_agent; " + "sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, 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 (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); + return result; +} + +/** + * \test Test that the http_user_agent content matches against a http request + * which holds the content. + */ +static int DetectEngineHttpUATest04(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[] = + "CONNECT /index.html HTTP/1.0\r\n" + "User-Agent: CONNECT\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint32_t http_len = sizeof(http_buf) - 1; + int result = 0; + + 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.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); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " + "(msg:\"http user agent test\"; " + "content:\"ECT\"; depth:4; http_user_agent; " + "sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, 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 matched but shouldn't have: "); + goto end; + } + + result = 1; + +end: + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); + return result; +} + +/** + * \test Test that the http_user_agent content matches against a http request + * which holds the content. + */ +static int DetectEngineHttpUATest05(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[] = + "CONNECT /index.html HTTP/1.0\r\n" + "User-Agent: CONNECT\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint32_t http_len = sizeof(http_buf) - 1; + int result = 0; + + 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.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); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " + "(msg:\"http user agent test\"; " + "content:!\"CON\"; depth:4; http_user_agent; " + "sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, 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 matched but shouldn't have: "); + goto end; + } + + result = 1; + +end: + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); + return result; +} + +/** + * \test Test that the http_user_agent content matches against a http request + * which holds the content. + */ +static int DetectEngineHttpUATest06(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[] = + "CONNECT /index.html HTTP/1.0\r\n" + "User-Agent: CONNECT\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint32_t http_len = sizeof(http_buf) - 1; + int result = 0; + + 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.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); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " + "(msg:\"http user agent test\"; " + "content:\"ECT\"; offset:3; http_user_agent; " + "sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, 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 (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); + return result; +} + +/** + * \test Test that the http_user_agent content matches against a http request + * which holds the content. + */ +static int DetectEngineHttpUATest07(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[] = + "CONNECT /index.html HTTP/1.0\r\n" + "User-Agent: CONNECT\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint32_t http_len = sizeof(http_buf) - 1; + int result = 0; + + 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.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); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " + "(msg:\"http user agent test\"; " + "content:!\"CO\"; offset:3; http_user_agent; " + "sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, 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 (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); + return result; +} + +/** + * \test Test that the http_user_agent content matches against a http request + * which holds the content. + */ +static int DetectEngineHttpUATest08(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[] = + "CONNECT /index.html HTTP/1.0\r\n" + "User-Agent: CONNECT\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint32_t http_len = sizeof(http_buf) - 1; + int result = 0; + + 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.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); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " + "(msg:\"http user agent test\"; " + "content:!\"ECT\"; offset:3; http_user_agent; " + "sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, 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 matched but shouldn't have: "); + goto end; + } + + result = 1; + +end: + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); + return result; +} + +/** + * \test Test that the http_user_agent content matches against a http request + * which holds the content. + */ +static int DetectEngineHttpUATest09(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[] = + "CONNECT /index.html HTTP/1.0\r\n" + "User-Agent: CONNECT\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint32_t http_len = sizeof(http_buf) - 1; + int result = 0; + + 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.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); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " + "(msg:\"http user agent test\"; " + "content:\"CON\"; offset:3; http_user_agent; " + "sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, 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 matched but shouldn't have: "); + goto end; + } + + result = 1; + +end: + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); + return result; +} + +/** + * \test Test that the http_user_agent content matches against a http request + * which holds the content. + */ +static int DetectEngineHttpUATest10(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[] = + "CONNECT /index.html HTTP/1.0\r\n" + "User-Agent: CONNECT\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint32_t http_len = sizeof(http_buf) - 1; + int result = 0; + + 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.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); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " + "(msg:\"http_user_agent test\"; " + "content:\"CO\"; http_user_agent; " + "content:\"EC\"; within:4; http_user_agent; " + "sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, 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 (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); + return result; +} + +/** + * \test Test that the http_user_agent content matches against a http request + * which holds the content. + */ +static int DetectEngineHttpUATest11(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[] = + "CONNECT /index.html HTTP/1.0\r\n" + "User-Agent: CONNECT\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint32_t http_len = sizeof(http_buf) - 1; + int result = 0; + + 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.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); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " + "(msg:\"http user agent test\"; " + "content:\"CO\"; http_user_agent; " + "content:!\"EC\"; within:3; http_user_agent; " + "sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, 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 (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); + return result; +} + +/** + * \test Test that the http_user_agent content matches against a http request + * which holds the content. + */ +static int DetectEngineHttpUATest12(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[] = + "CONNECT /index.html HTTP/1.0\r\n" + "User-Agent: CONNECT\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint32_t http_len = sizeof(http_buf) - 1; + int result = 0; + + 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.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); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " + "(msg:\"http_user_agent test\"; " + "content:\"CO\"; http_user_agent; " + "content:\"EC\"; within:3; http_user_agent; " + "sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, 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 matched but shouldn't have: "); + goto end; + } + + result = 1; + +end: + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); + return result; +} + +/** + * \test Test that the http_user_agent content matches against a http request + * which holds the content. + */ +static int DetectEngineHttpUATest13(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[] = + "CONNECT /index.html HTTP/1.0\r\n" + "User-Agent: CONNECT\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint32_t http_len = sizeof(http_buf) - 1; + int result = 0; + + 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.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); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " + "(msg:\"http user agent test\"; " + "content:\"CO\"; http_user_agent; " + "content:!\"EC\"; within:4; http_user_agent; " + "sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, 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 matched but shouldn't have: "); + goto end; + } + + result = 1; + +end: + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); + return result; +} + +/** + * \test Test that the http_user_agent content matches against a http request + * which holds the content. + */ +static int DetectEngineHttpUATest14(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[] = + "CONNECT /index.html HTTP/1.0\r\n" + "User-Agent: CONNECT\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint32_t http_len = sizeof(http_buf) - 1; + int result = 0; + + 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.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); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " + "(msg:\"http_user_agent test\"; " + "content:\"CO\"; http_user_agent; " + "content:\"EC\"; distance:2; http_user_agent; " + "sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, 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 (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); + return result; +} + +/** + * \test Test that the http_user_agent content matches against a http request + * which holds the content. + */ +static int DetectEngineHttpUATest15(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[] = + "CONNECT /index.html HTTP/1.0\r\n" + "User-Agent: CONNECT\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint32_t http_len = sizeof(http_buf) - 1; + int result = 0; + + 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.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); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " + "(msg:\"http user agent test\"; " + "content:\"CO\"; http_user_agent; " + "content:!\"EC\"; distance:3; http_user_agent; " + "sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, 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 (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); + return result; +} + +/** + * \test Test that the http_user_agent content matches against a http request + * which holds the content. + */ +static int DetectEngineHttpUATest16(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[] = + "CONNECT /index.html HTTP/1.0\r\n" + "User-Agent: CONNECT\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint32_t http_len = sizeof(http_buf) - 1; + int result = 0; + + 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.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); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " + "(msg:\"http user agent test\"; " + "content:\"CO\"; http_user_agent; " + "content:\"EC\"; distance:3; http_user_agent; " + "sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, 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 matched but shouldn't have: "); + goto end; + } + + result = 1; + +end: + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); + return result; +} + +/** + * \test Test that the http_user_agent content matches against a http request + * which holds the content. + */ +static int DetectEngineHttpUATest17(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[] = + "CONNECT /index.html HTTP/1.0\r\n" + "User-Agent: CONNECT\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint32_t http_len = sizeof(http_buf) - 1; + int result = 0; + + 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.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); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " + "(msg:\"http_user_agent test\"; " + "content:\"CO\"; http_user_agent; " + "content:!\"EC\"; distance:2; http_user_agent; " + "sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, 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 matched but shouldn't have: "); + goto end; + } + + result = 1; + +end: + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); + return result; +} + +#endif /* UNITTESTS */ + +void DetectEngineHttpUARegisterTests(void) +{ + +#ifdef UNITTESTS + UtRegisterTest("DetectEngineHttpUATest01", + DetectEngineHttpUATest01, 1); + UtRegisterTest("DetectEngineHttpUATest02", + DetectEngineHttpUATest02, 1); + UtRegisterTest("DetectEngineHttpUATest03", + DetectEngineHttpUATest03, 1); + UtRegisterTest("DetectEngineHttpUATest04", + DetectEngineHttpUATest04, 1); + UtRegisterTest("DetectEngineHttpUATest05", + DetectEngineHttpUATest05, 1); + UtRegisterTest("DetectEngineHttpUATest06", + DetectEngineHttpUATest06, 1); + UtRegisterTest("DetectEngineHttpUATest07", + DetectEngineHttpUATest07, 1); + UtRegisterTest("DetectEngineHttpUATest08", + DetectEngineHttpUATest08, 1); + UtRegisterTest("DetectEngineHttpUATest09", + DetectEngineHttpUATest09, 1); + UtRegisterTest("DetectEngineHttpUATest10", + DetectEngineHttpUATest10, 1); + UtRegisterTest("DetectEngineHttpUATest11", + DetectEngineHttpUATest11, 1); + UtRegisterTest("DetectEngineHttpUATest12", + DetectEngineHttpUATest12, 1); + UtRegisterTest("DetectEngineHttpUATest13", + DetectEngineHttpUATest13, 1); + UtRegisterTest("DetectEngineHttpUATest14", + DetectEngineHttpUATest14, 1); + UtRegisterTest("DetectEngineHttpUATest15", + DetectEngineHttpUATest15, 1); + UtRegisterTest("DetectEngineHttpUATest16", + DetectEngineHttpUATest16, 1); + UtRegisterTest("DetectEngineHttpUATest17", + DetectEngineHttpUATest17, 1); +#endif /* UNITTESTS */ + + return; +} +/** + * @} + */ diff --git a/src/detect-engine-hua.h b/src/detect-engine-hua.h new file mode 100644 index 0000000000..c1048867a0 --- /dev/null +++ b/src/detect-engine-hua.h @@ -0,0 +1,33 @@ +/* Copyright (C) 2007-2012 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_HUA_H__ +#define __DETECT_ENGINE_HUA_H__ + +#include "app-layer-htp.h" + +int DetectEngineInspectHttpUA(DetectEngineCtx *, DetectEngineThreadCtx *, + Signature *, Flow *, uint8_t, void *); +int DetectEngineRunHttpUAMpm(DetectEngineThreadCtx *, Flow *, HtpState *, uint8_t); +void DetectEngineHttpUARegisterTests(void); + +#endif /* __DETECT_ENGINE_HUA_H__ */ diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index 304d23fda9..236f8f3a99 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -598,6 +598,40 @@ uint32_t HttpStatCodePatternSearch(DetectEngineThreadCtx *det_ctx, SCReturnUInt(ret); } +/** + * \brief Http user agent match -- searches for one pattern per signature. + * + * \param det_ctx Detection engine thread ctx. + * \param cookie User-Agent to inspect. + * \param cookie_len User-Agent buffer length. + * + * \retval ret Number of matches. + */ +uint32_t HttpUAPatternSearch(DetectEngineThreadCtx *det_ctx, + uint8_t *ua, uint32_t ua_len, uint8_t flags) +{ + SCEnter(); + + uint32_t ret; + if (flags & STREAM_TOSERVER) { + if (det_ctx->sgh->mpm_huad_ctx_ts == NULL) + SCReturnUInt(0); + + ret = mpm_table[det_ctx->sgh->mpm_huad_ctx_ts->mpm_type]. + Search(det_ctx->sgh->mpm_huad_ctx_ts, &det_ctx->mtcu, + &det_ctx->pmq, ua, ua_len); + } else { + if (det_ctx->sgh->mpm_huad_ctx_tc == NULL) + SCReturnUInt(0); + + ret = mpm_table[det_ctx->sgh->mpm_huad_ctx_tc->mpm_type]. + Search(det_ctx->sgh->mpm_huad_ctx_tc, &det_ctx->mtcu, + &det_ctx->pmq, ua, ua_len); + } + + SCReturnUInt(ret); +} + /** \brief Pattern match -- searches for only one pattern per signature. * * \param det_ctx detection engine thread ctx @@ -1260,6 +1294,7 @@ static void PopulateMpmAddPatternToMpm(DetectEngineCtx *de_ctx, case DETECT_SM_LIST_HCDMATCH: case DETECT_SM_LIST_HSMDMATCH: case DETECT_SM_LIST_HSCDMATCH: + case DETECT_SM_LIST_HUADMATCH: { MpmCtx *mpm_ctx_ts = NULL; MpmCtx *mpm_ctx_tc = NULL; @@ -1336,6 +1371,13 @@ static void PopulateMpmAddPatternToMpm(DetectEngineCtx *de_ctx, mpm_ctx_tc = sgh->mpm_hscd_ctx_tc; sgh_flags = SIG_GROUP_HEAD_MPM_HSCD; cd_flags = DETECT_CONTENT_HSCD_MPM; + } else if (sm_list == DETECT_SM_LIST_HUADMATCH) { + if (s->flags & SIG_FLAG_TOSERVER) + mpm_ctx_ts = sgh->mpm_huad_ctx_ts; + if (s->flags & SIG_FLAG_TOCLIENT) + mpm_ctx_tc = sgh->mpm_huad_ctx_tc; + sgh_flags = SIG_GROUP_HEAD_MPM_HUAD; + cd_flags = DETECT_CONTENT_HUAD_MPM; } cd = (DetectContentData *)mpm_sm->ctx; @@ -1631,6 +1673,8 @@ int PatternMatchPrepareGroup(DetectEngineCtx *de_ctx, SigGroupHead *sh) uint32_t has_co_hsmd = 0; /* used to indicate if sgh has atleast one sig with http_stat_code */ uint32_t has_co_hscd = 0; + /* used to indicate if sgh has atleast one sig with http_user_agent */ + uint32_t has_co_huad = 0; //uint32_t cnt = 0; uint32_t sig = 0; @@ -1686,6 +1730,10 @@ int PatternMatchPrepareGroup(DetectEngineCtx *de_ctx, SigGroupHead *sh) if (s->sm_lists[DETECT_SM_LIST_HSCDMATCH] != NULL) { has_co_hscd = 1; } + + if (s->sm_lists[DETECT_SM_LIST_HUADMATCH] != NULL) { + has_co_huad = 1; + } } if (has_co_packet > 0) { @@ -1724,6 +1772,9 @@ int PatternMatchPrepareGroup(DetectEngineCtx *de_ctx, SigGroupHead *sh) if (has_co_hscd > 0) { sh->flags |= SIG_GROUP_HAVEHSCDCONTENT; } + if (has_co_huad > 0) { + sh->flags |= SIG_GROUP_HAVEHUADCONTENT; + } /* intialize contexes */ if (sh->flags & SIG_GROUP_HAVECONTENT) { @@ -2025,6 +2076,28 @@ int PatternMatchPrepareGroup(DetectEngineCtx *de_ctx, SigGroupHead *sh) #endif } + if (sh->flags & SIG_GROUP_HAVEHUADCONTENT) { + if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE) { + sh->mpm_huad_ctx_ts = MpmFactoryGetMpmCtxForProfile(de_ctx->sgh_mpm_context_huad, 0); + sh->mpm_huad_ctx_tc = MpmFactoryGetMpmCtxForProfile(de_ctx->sgh_mpm_context_huad, 1); + } else { + sh->mpm_huad_ctx_ts = MpmFactoryGetMpmCtxForProfile(MPM_CTX_FACTORY_UNIQUE_CONTEXT, 0); + sh->mpm_huad_ctx_tc = MpmFactoryGetMpmCtxForProfile(MPM_CTX_FACTORY_UNIQUE_CONTEXT, 1); + } + if (sh->mpm_huad_ctx_ts == NULL || sh->mpm_huad_ctx_tc == NULL) { + SCLogDebug("sh->mpm_huad_ctx == NULL. This should never happen"); + exit(EXIT_FAILURE); + } + +#ifndef __SC_CUDA_SUPPORT__ + MpmInitCtx(sh->mpm_huad_ctx_ts, de_ctx->mpm_matcher, -1); + MpmInitCtx(sh->mpm_huad_ctx_tc, de_ctx->mpm_matcher, -1); +#else + MpmInitCtx(sh->mpm_huad_ctx_ts, de_ctx->mpm_matcher, de_ctx->cuda_rc_mod_handle); + MpmInitCtx(sh->mpm_huad_ctx_tc, de_ctx->mpm_matcher, de_ctx->cuda_rc_mod_handle); +#endif + } + if (sh->flags & SIG_GROUP_HAVECONTENT || sh->flags & SIG_GROUP_HAVESTREAMCONTENT || sh->flags & SIG_GROUP_HAVEURICONTENT || @@ -2036,7 +2109,8 @@ int PatternMatchPrepareGroup(DetectEngineCtx *de_ctx, SigGroupHead *sh) sh->flags & SIG_GROUP_HAVEHCDCONTENT || sh->flags & SIG_GROUP_HAVEHSMDCONTENT || sh->flags & SIG_GROUP_HAVEHSCDCONTENT || - sh->flags & SIG_GROUP_HAVEHRUDCONTENT) { + sh->flags & SIG_GROUP_HAVEHRUDCONTENT || + sh->flags & SIG_GROUP_HAVEHUADCONTENT) { PatternMatchPreparePopulateMpm(de_ctx, sh); @@ -2386,6 +2460,30 @@ int PatternMatchPrepareGroup(DetectEngineCtx *de_ctx, SigGroupHead *sh) } } } + if (sh->mpm_huad_ctx_ts != NULL) { + if (sh->mpm_huad_ctx_ts->pattern_cnt == 0) { + MpmFactoryReClaimMpmCtx(sh->mpm_huad_ctx_ts); + sh->mpm_huad_ctx_ts = NULL; + } else { + if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL && + sh->flags & SIG_GROUP_HAVEHUADCONTENT) { + if (mpm_table[sh->mpm_huad_ctx_ts->mpm_type].Prepare != NULL) + mpm_table[sh->mpm_huad_ctx_ts->mpm_type].Prepare(sh->mpm_huad_ctx_ts); + } + } + } + if (sh->mpm_huad_ctx_tc != NULL) { + if (sh->mpm_huad_ctx_tc->pattern_cnt == 0) { + MpmFactoryReClaimMpmCtx(sh->mpm_huad_ctx_tc); + sh->mpm_huad_ctx_tc = NULL; + } else { + if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL && + sh->flags & SIG_GROUP_HAVEHUADCONTENT) { + if (mpm_table[sh->mpm_huad_ctx_tc->mpm_type].Prepare != NULL) + mpm_table[sh->mpm_huad_ctx_tc->mpm_type].Prepare(sh->mpm_huad_ctx_tc); + } + } + } //} /* if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) */ } else { MpmFactoryReClaimMpmCtx(sh->mpm_proto_other_ctx); @@ -2415,6 +2513,8 @@ int PatternMatchPrepareGroup(DetectEngineCtx *de_ctx, SigGroupHead *sh) sh->mpm_hsmd_ctx_ts = NULL; MpmFactoryReClaimMpmCtx(sh->mpm_hscd_ctx_ts); sh->mpm_hscd_ctx_ts = NULL; + MpmFactoryReClaimMpmCtx(sh->mpm_huad_ctx_ts); + sh->mpm_huad_ctx_ts = NULL; MpmFactoryReClaimMpmCtx(sh->mpm_proto_tcp_ctx_tc); sh->mpm_proto_tcp_ctx_tc = NULL; @@ -2440,6 +2540,8 @@ int PatternMatchPrepareGroup(DetectEngineCtx *de_ctx, SigGroupHead *sh) sh->mpm_hsmd_ctx_tc = NULL; MpmFactoryReClaimMpmCtx(sh->mpm_hscd_ctx_tc); sh->mpm_hscd_ctx_tc = NULL; + MpmFactoryReClaimMpmCtx(sh->mpm_huad_ctx_tc); + sh->mpm_huad_ctx_tc = NULL; } return 0; diff --git a/src/detect-engine-mpm.h b/src/detect-engine-mpm.h index aa00a619f1..d89b510a01 100644 --- a/src/detect-engine-mpm.h +++ b/src/detect-engine-mpm.h @@ -47,6 +47,7 @@ uint32_t HttpCookiePatternSearch(DetectEngineThreadCtx *, uint8_t *, uint32_t, u uint32_t HttpRawUriPatternSearch(DetectEngineThreadCtx *, uint8_t *, uint32_t, uint8_t); uint32_t HttpStatMsgPatternSearch(DetectEngineThreadCtx *, uint8_t *, uint32_t, uint8_t); uint32_t HttpStatCodePatternSearch(DetectEngineThreadCtx *, uint8_t *, uint32_t, uint8_t); +uint32_t HttpUAPatternSearch(DetectEngineThreadCtx *, uint8_t *, uint32_t, uint8_t); void PacketPatternCleanup(ThreadVars *, DetectEngineThreadCtx *); void StreamPatternCleanup(ThreadVars *t, DetectEngineThreadCtx *det_ctx, StreamMsg *smsg); diff --git a/src/detect-engine-state.c b/src/detect-engine-state.c index d8be429990..3cdf0d7444 100644 --- a/src/detect-engine-state.c +++ b/src/detect-engine-state.c @@ -66,6 +66,7 @@ #include "detect-engine-hrud.h" #include "detect-engine-hsmd.h" #include "detect-engine-hscd.h" +#include "detect-engine-hua.h" #include "detect-engine-dcepayload.h" #include "detect-engine-file.h" @@ -264,7 +265,7 @@ int DeStateUpdateInspectTransactionId(Flow *f, char direction) { * many args is slow. */ static void DeStateSignatureAppend(DetectEngineState *state, Signature *s, - SigMatch *sm, uint16_t match_flags) { + SigMatch *sm, uint32_t match_flags) { DeStateStore *store = state->tail; if (store == NULL) { @@ -396,8 +397,8 @@ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, SigMatch *sm = s->sm_lists[DETECT_SM_LIST_AMATCH]; int match = 0; int r = 0; - uint16_t inspect_flags = 0; - uint16_t match_flags = 0; + uint32_t inspect_flags = 0; + uint32_t match_flags = 0; uint16_t file_no_match = 0; if (alstate == NULL) { @@ -503,6 +504,14 @@ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, if (s->sm_lists[DETECT_SM_LIST_HSCDMATCH] != NULL) { inspect_flags |= DE_STATE_FLAG_HSCD_INSPECT; } + if (s->sm_lists[DETECT_SM_LIST_HUADMATCH] != NULL) { + inspect_flags |= DE_STATE_FLAG_HUAD_INSPECT; + if (DetectEngineInspectHttpUA(de_ctx, det_ctx, s, f, + flags, alstate) == 1) { + match_flags |= DE_STATE_FLAG_HUAD_MATCH; + } + SCLogDebug("inspecting http cookie"); + } } else if (flags & STREAM_TOCLIENT) { /* For to client set the flags in inspect so it can't match * if the sig requires something only the request has. The rest @@ -588,6 +597,9 @@ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, } SCLogDebug("inspecting http stat code"); } + if (s->sm_lists[DETECT_SM_LIST_HUADMATCH] != NULL) { + inspect_flags |= DE_STATE_FLAG_HUAD_INSPECT; + } } } else if (alproto == ALPROTO_DCERPC || alproto == ALPROTO_SMB || alproto == ALPROTO_SMB2) { if (s->sm_lists[DETECT_SM_LIST_DMATCH] != NULL) { @@ -659,7 +671,7 @@ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, } SCLogDebug("detection done, store results: sm %p, inspect_flags %04X, " - "match_flags %04X", sm, inspect_flags, match_flags); + "match_flags %04X", sm, inspect_flags, match_flags); SCMutexLock(&f->de_state_m); /* match or no match, we store the state anyway @@ -701,8 +713,8 @@ int DeStateDetectContinueDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, Dete SigIntId cnt = 0; SigIntId store_cnt = 0; DeStateStore *store = NULL; - uint16_t inspect_flags = 0; - uint16_t match_flags = 0; + uint32_t inspect_flags = 0; + uint32_t match_flags = 0; int match = 0; uint16_t file_no_match = 0; @@ -927,6 +939,18 @@ int DeStateDetectContinueDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, Dete inspect_flags |= DE_STATE_FLAG_HSCD_INSPECT; } } + if (s->sm_lists[DETECT_SM_LIST_HUADMATCH] != NULL) { + if (!(item->flags & DE_STATE_FLAG_HUAD_MATCH)) { + SCLogDebug("inspecting http user agent data"); + inspect_flags |= DE_STATE_FLAG_HUAD_INSPECT; + + if (DetectEngineInspectHttpUA(de_ctx, det_ctx, s, f, + flags, alstate) == 1) { + SCLogDebug("http user agent matched"); + match_flags |= DE_STATE_FLAG_HUAD_MATCH; + } + } + } } else if (alproto == ALPROTO_HTTP && (flags & STREAM_TOCLIENT)) { /* For to client set the flags in inspect so it can't match * if the sig requires something only the request has. The rest @@ -1039,6 +1063,11 @@ int DeStateDetectContinueDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, Dete } } } + if (s->sm_lists[DETECT_SM_LIST_HUADMATCH] != NULL) { + if (!(item->flags & DE_STATE_FLAG_HUAD_MATCH)) { + inspect_flags |= DE_STATE_FLAG_HUAD_INSPECT; + } + } } else if (alproto == ALPROTO_DCERPC || alproto == ALPROTO_SMB || alproto == ALPROTO_SMB2) { if (s->sm_lists[DETECT_SM_LIST_DMATCH] != NULL) { diff --git a/src/detect-engine-state.h b/src/detect-engine-state.h index 50e2a5a81c..ad717be3ee 100644 --- a/src/detect-engine-state.h +++ b/src/detect-engine-state.h @@ -51,22 +51,23 @@ #define DE_STATE_CHUNK_SIZE 15 /* per stored sig flags */ -#define DE_STATE_FLAG_PAYLOAD_MATCH 0x0001 /**< payload part of the sig matched */ -#define DE_STATE_FLAG_URI_MATCH 0x0002 /**< uri part of the sig matched */ -#define DE_STATE_FLAG_DCE_MATCH 0x0004 /**< dce payload inspection part matched */ -#define DE_STATE_FLAG_HCBD_MATCH 0x0008 /**< hcbd payload inspection part matched */ -#define DE_STATE_FLAG_HSBD_MATCH 0x0010 /**< hcbd payload inspection part matched */ -#define DE_STATE_FLAG_HHD_MATCH 0x0020 /**< hhd payload inspection part matched */ -#define DE_STATE_FLAG_HRHD_MATCH 0x0040 /**< hrhd payload inspection part matched */ -#define DE_STATE_FLAG_HMD_MATCH 0x0080 /**< hmd payload inspection part matched */ -#define DE_STATE_FLAG_HCD_MATCH 0x0100 /**< hcd payload inspection part matched */ -#define DE_STATE_FLAG_HRUD_MATCH 0x0200 /**< hrud payload inspection part matched */ -#define DE_STATE_FLAG_FILE_TC_MATCH 0x0400 -#define DE_STATE_FLAG_FILE_TS_MATCH 0x0800 -#define DE_STATE_FLAG_FULL_MATCH 0x1000 /**< sig already fully matched */ -#define DE_STATE_FLAG_SIG_CANT_MATCH 0x2000 /**< signature has no chance of matching */ -#define DE_STATE_FLAG_HSMD_MATCH 0x4000 /**< hsmd payload inspection part matched */ -#define DE_STATE_FLAG_HSCD_MATCH 0x8000 /**< hscd payload inspection part matched */ +#define DE_STATE_FLAG_PAYLOAD_MATCH 1 /**< payload part of the sig matched */ +#define DE_STATE_FLAG_URI_MATCH 1 << 1 /**< uri part of the sig matched */ +#define DE_STATE_FLAG_DCE_MATCH 1 << 2 /**< dce payload inspection part matched */ +#define DE_STATE_FLAG_HCBD_MATCH 1 << 3 /**< hcbd payload inspection part matched */ +#define DE_STATE_FLAG_HSBD_MATCH 1 << 4 /**< hcbd payload inspection part matched */ +#define DE_STATE_FLAG_HHD_MATCH 1 << 5 /**< hhd payload inspection part matched */ +#define DE_STATE_FLAG_HRHD_MATCH 1 << 6 /**< hrhd payload inspection part matched */ +#define DE_STATE_FLAG_HMD_MATCH 1 << 7 /**< hmd payload inspection part matched */ +#define DE_STATE_FLAG_HCD_MATCH 1 << 8 /**< hcd payload inspection part matched */ +#define DE_STATE_FLAG_HRUD_MATCH 1 << 9 /**< hrud payload inspection part matched */ +#define DE_STATE_FLAG_FILE_TC_MATCH 1 << 10 +#define DE_STATE_FLAG_FILE_TS_MATCH 1 << 11 +#define DE_STATE_FLAG_FULL_MATCH 1 << 12 /**< sig already fully matched */ +#define DE_STATE_FLAG_SIG_CANT_MATCH 1 << 13 /**< signature has no chance of matching */ +#define DE_STATE_FLAG_HSMD_MATCH 1 << 14 /**< hsmd payload inspection part matched */ +#define DE_STATE_FLAG_HSCD_MATCH 1 << 15 /**< hscd payload inspection part matched */ +#define DE_STATE_FLAG_HUAD_MATCH 1 << 16 /**< huad payload inspection part matched */ #define DE_STATE_FLAG_URI_INSPECT DE_STATE_FLAG_URI_MATCH /**< uri part of the sig inspected */ #define DE_STATE_FLAG_DCE_INSPECT DE_STATE_FLAG_DCE_MATCH /**< dce payload inspection part inspected */ @@ -81,6 +82,7 @@ #define DE_STATE_FLAG_FILE_TS_INSPECT DE_STATE_FLAG_FILE_TS_MATCH #define DE_STATE_FLAG_HSMD_INSPECT DE_STATE_FLAG_HSMD_MATCH /**< hsmd payload inspection part inspected */ #define DE_STATE_FLAG_HSCD_INSPECT DE_STATE_FLAG_HSCD_MATCH /**< hscd payload inspection part inspected */ +#define DE_STATE_FLAG_HUAD_INSPECT DE_STATE_FLAG_HUAD_MATCH /**< huad payload inspection part inspected */ /* state flags */ #define DE_STATE_FILE_STORE_DISABLED 0x0001 @@ -100,7 +102,7 @@ typedef enum { typedef struct DeStateStoreItem_ { SigIntId sid; /**< Signature internal id to store the state for (16 or * 32 bit depending on how SigIntId is defined). */ - uint16_t flags; /**< flags */ + uint32_t flags; /**< flags */ SigMatch *nm; /**< next sig match to try, or null if done */ } DeStateStoreItem; diff --git a/src/detect-fast-pattern.c b/src/detect-fast-pattern.c index d97209ee27..398d2e9f9e 100644 --- a/src/detect-fast-pattern.c +++ b/src/detect-fast-pattern.c @@ -152,6 +152,9 @@ void SupportFastPatternForSigMatchTypes(void) SupportFastPatternForSigMatchType(DETECT_CONTENT); SupportFastPatternForSigMatchList(DETECT_SM_LIST_HSCDMATCH); + SupportFastPatternForSigMatchType(DETECT_CONTENT); + SupportFastPatternForSigMatchList(DETECT_SM_LIST_HUADMATCH); + return; } @@ -225,17 +228,19 @@ static int DetectFastPatternSetup(DetectEngineCtx *de_ctx, Signature *s, char *a s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH] == NULL && s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH] == NULL && s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH] == NULL && - s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH] == NULL) { + s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH] == NULL && + s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH] == NULL) { SCLogWarning(SC_WARN_COMPATIBILITY, "fast_pattern found inside the " "rule, without a preceding content based keyword. " "Currently we provide fast_pattern support for content, " "uricontent, http_client_body, http_server_body, http_header, " "http_raw_header, http_method, http_cookie, " - "http_raw_uri, http_stat_msg or http_stat_code option"); + "http_raw_uri, http_stat_msg, http_stat_code or " + "http_user_agent option"); return -1; } - SigMatch *pm = SigMatchGetLastSMFromLists(s, 22, + SigMatch *pm = SigMatchGetLastSMFromLists(s, 24, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], @@ -246,7 +251,8 @@ static int DetectFastPatternSetup(DetectEngineCtx *de_ctx, Signature *s, char *a DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]); + DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], + DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]); if (pm == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "fast_pattern found inside " "the rule, without a content context. Please use a " @@ -15769,6 +15775,1188 @@ int DetectFastPatternTest547(void) return result; } + + + + + + + + + + + + + + + + + +int DetectFastPatternTest548(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 icmp any any -> any any " + "(content:\"one\"; http_user_agent; " + "content:!\"oneonetwo\"; fast_pattern:3,4; http_user_agent; " + "content:\"three\"; http_user_agent; sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; + if (ud->flags & DETECT_CONTENT_FAST_PATTERN && + ud->flags & DETECT_CONTENT_NEGATED && + !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && + ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && + ud->fp_chop_offset == 3 && + ud->fp_chop_len == 4) { + result = 1; + } else { + result = 0; + } + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +/** + * \test Checks if a fast_pattern is registered in a Signature for uricontent. + */ +int DetectFastPatternTest549(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 icmp any any -> any any " + "(content:\"one\"; fast_pattern:only; http_user_agent; " + "msg:\"Testing fast_pattern\"; sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + result = 0; + sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH]; + if (sm != NULL) { + if ( ((DetectContentData *)sm->ctx)->flags & + DETECT_CONTENT_FAST_PATTERN) { + result = 1; + } else { + result = 0; + } + } + + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +/** + * \test Checks if a fast_pattern is registered in a Signature for uricontent. + */ +int DetectFastPatternTest550(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 icmp any any -> any any " + "(content:\"oneoneone\"; fast_pattern:3,4; http_user_agent; " + "msg:\"Testing fast_pattern\"; sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + result = 0; + sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH]; + if (sm != NULL) { + if ( ((DetectContentData *)sm->ctx)->flags & + DETECT_CONTENT_FAST_PATTERN) { + result = 1; + } else { + result = 0; + } + } + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest551(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 icmp any any -> any any " + "(content:\"one\"; fast_pattern:only; http_user_agent; sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH]; + if (sm == NULL) { + goto end; + } + DetectContentData *ud = sm->ctx; + if (ud->flags & DETECT_CONTENT_FAST_PATTERN && + ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && + !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && + ud->fp_chop_offset == 0 && + ud->fp_chop_len == 0) { + result = 1; + } else { + result = 0; + } + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest552(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 icmp any any -> any any " + "(content:\"oneoneone\"; fast_pattern:3,4; http_user_agent; sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH]; + if (sm == NULL) { + goto end; + } + + DetectContentData *ud = sm->ctx; + if (ud->flags & DETECT_CONTENT_FAST_PATTERN && + !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && + ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && + ud->fp_chop_offset == 3 && + ud->fp_chop_len == 4) { + result = 1; + } else { + result = 0; + } + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest553(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 icmp any any -> any any " + "(content:\"one\"; http_user_agent; " + "content:\"two\"; fast_pattern:only; http_user_agent; distance:10; sid:1;)"); + if (de_ctx->sig_list != NULL) + goto end; + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest554(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 icmp any any -> any any " + "(content:\"one\"; http_user_agent; " + "content:\"two\"; distance:10; fast_pattern:only; http_user_agent; sid:1;)"); + if (de_ctx->sig_list != NULL) + goto end; + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest555(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 icmp any any -> any any " + "(content:\"one\"; http_user_agent; " + "content:\"two\"; fast_pattern:only; http_user_agent; within:10; sid:1;)"); + if (de_ctx->sig_list != NULL) + goto end; + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest556(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 icmp any any -> any any " + "(content:\"one\"; http_user_agent; " + "content:\"two\"; within:10; fast_pattern:only; http_user_agent; sid:1;)"); + if (de_ctx->sig_list != NULL) + goto end; + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest557(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 icmp any any -> any any " + "(content:\"one\"; http_user_agent; " + "content:\"two\"; fast_pattern:only; http_user_agent; offset:10; sid:1;)"); + if (de_ctx->sig_list != NULL) + goto end; + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest558(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 icmp any any -> any any " + "(content:\"one\"; http_user_agent; " + "content:\"two\"; offset:10; fast_pattern:only; http_user_agent; sid:1;)"); + if (de_ctx->sig_list != NULL) + goto end; + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest559(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 icmp any any -> any any " + "(content:\"one\"; http_user_agent; " + "content:\"two\"; fast_pattern:only; http_user_agent; depth:10; sid:1;)"); + if (de_ctx->sig_list != NULL) + goto end; + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest560(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 icmp any any -> any any " + "(content:\"one\"; http_user_agent; " + "content:\"two\"; depth:10; fast_pattern:only; http_user_agent; sid:1;)"); + if (de_ctx->sig_list != NULL) + goto end; + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest561(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 icmp any any -> any any " + "(content:\"one\"; http_user_agent; " + "content:!\"two\"; fast_pattern:only; http_user_agent; sid:1;)"); + if (de_ctx->sig_list != NULL) + goto end; + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest562(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 icmp any any -> any any " + "(content:\" one\"; http_user_agent; " + "content:\"two\"; http_user_agent; distance:30; " + "content:\"two\"; fast_pattern:only; http_user_agent; sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; + if (ud->flags & DETECT_CONTENT_FAST_PATTERN && + ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && + !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && + ud->fp_chop_offset == 0 && + ud->fp_chop_len == 0) { + result = 1; + } else { + result = 0; + } + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest563(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 icmp any any -> any any " + "(content:\"one\"; http_user_agent; " + "content:\"two\"; http_user_agent; within:30; " + "content:\"two\"; fast_pattern:only; http_user_agent; sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; + if (ud->flags & DETECT_CONTENT_FAST_PATTERN && + ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && + !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && + ud->fp_chop_offset == 0 && + ud->fp_chop_len == 0) { + result = 1; + } else { + result = 0; + } + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest564(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 icmp any any -> any any " + "(content:\"one\"; http_user_agent; " + "content:\"two\"; http_user_agent; offset:30; " + "content:\"two\"; fast_pattern:only; http_user_agent; sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; + if (ud->flags & DETECT_CONTENT_FAST_PATTERN && + ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && + !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && + ud->fp_chop_offset == 0 && + ud->fp_chop_len == 0) { + result = 1; + } else { + result = 0; + } + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest565(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 icmp any any -> any any " + "(content:\"one\"; http_user_agent; " + "content:\"two\"; http_user_agent; depth:30; " + "content:\"two\"; fast_pattern:only; http_user_agent; sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; + if (ud->flags & DETECT_CONTENT_FAST_PATTERN && + ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && + !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && + ud->fp_chop_offset == 0 && + ud->fp_chop_len == 0) { + result = 1; + } else { + result = 0; + } + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest566(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 icmp any any -> any any " + "(content:!\"one\"; fast_pattern; http_user_agent; " + "content:\"two\"; http_user_agent; sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; + if (ud->flags & DETECT_CONTENT_FAST_PATTERN && + ud->flags & DETECT_CONTENT_NEGATED && + !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && + !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && + ud->fp_chop_offset == 0 && + ud->fp_chop_len == 0) { + result = 1; + } else { + result = 0; + } + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest567(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 icmp any any -> any any " + "(content:\"two\"; http_user_agent; " + "content:!\"one\"; fast_pattern; http_user_agent; distance:20; sid:1;)"); + if (de_ctx->sig_list != NULL) + goto end; + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest568(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 icmp any any -> any any " + "(content:\"two\"; http_user_agent; " + "content:!\"one\"; fast_pattern; http_user_agent; within:20; sid:1;)"); + if (de_ctx->sig_list != NULL) + goto end; + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest569(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 icmp any any -> any any " + "(content:\"two\"; http_user_agent; " + "content:!\"one\"; fast_pattern; http_user_agent; offset:20; sid:1;)"); + if (de_ctx->sig_list != NULL) + goto end; + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest570(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 icmp any any -> any any " + "(content:\"two\"; http_user_agent; " + "content:!\"one\"; fast_pattern; http_user_agent; depth:20; sid:1;)"); + if (de_ctx->sig_list != NULL) + goto end; + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest571(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 icmp any any -> any any " + "(content:\"one\"; http_user_agent; " + "content:\"oneonetwo\"; fast_pattern:3,4; http_user_agent; " + "content:\"three\"; http_user_agent; sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; + if (ud->flags & DETECT_CONTENT_FAST_PATTERN && + !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && + ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && + ud->fp_chop_offset == 3 && + ud->fp_chop_len == 4) { + result = 1; + } else { + result = 0; + } + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest572(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 icmp any any -> any any " + "(content:\"one\"; http_user_agent; " + "content:\"oneonetwo\"; fast_pattern:3,4; http_user_agent; " + "content:\"three\"; http_user_agent; distance:30; sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; + if (ud->flags & DETECT_CONTENT_FAST_PATTERN && + !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && + ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && + ud->fp_chop_offset == 3 && + ud->fp_chop_len == 4) { + result = 1; + } else { + result = 0; + } + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest573(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 icmp any any -> any any " + "(content:\"one\"; http_user_agent; " + "content:\"oneonetwo\"; fast_pattern:3,4; http_user_agent; " + "content:\"three\"; http_user_agent; within:30; sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; + if (ud->flags & DETECT_CONTENT_FAST_PATTERN && + !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && + ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && + ud->fp_chop_offset == 3 && + ud->fp_chop_len == 4) { + result = 1; + } else { + result = 0; + } + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest574(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 icmp any any -> any any " + "(content:\"one\"; http_user_agent; " + "content:\"oneonetwo\"; fast_pattern:3,4; http_user_agent; " + "content:\"three\"; http_user_agent; offset:30; sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; + if (ud->flags & DETECT_CONTENT_FAST_PATTERN && + !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && + ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && + ud->fp_chop_offset == 3 && + ud->fp_chop_len == 4) { + result = 1; + } else { + result = 0; + } + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest575(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 icmp any any -> any any " + "(content:\"one\"; http_user_agent; " + "content:\"oneonetwo\"; fast_pattern:3,4; http_user_agent; " + "content:\"three\"; http_user_agent; depth:30; sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; + if (ud->flags & DETECT_CONTENT_FAST_PATTERN && + !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && + ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && + ud->fp_chop_offset == 3 && + ud->fp_chop_len == 4) { + result = 1; + } else { + result = 0; + } + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest576(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 icmp any any -> any any " + "(content:\"one\"; http_user_agent; " + "content:\"two\"; http_user_agent; distance:10; " + "content:\"oneonethree\"; fast_pattern:3,4; http_user_agent; sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; + if (ud->flags & DETECT_CONTENT_FAST_PATTERN && + !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && + ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && + ud->fp_chop_offset == 3 && + ud->fp_chop_len == 4) { + result = 1; + } else { + result = 0; + } + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest577(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 icmp any any -> any any " + "(content:\"one\"; http_user_agent; " + "content:\"two\"; http_user_agent; within:10; " + "content:\"oneonethree\"; fast_pattern:3,4; http_user_agent; sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; + if (ud->flags & DETECT_CONTENT_FAST_PATTERN && + !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && + ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && + ud->fp_chop_offset == 3 && + ud->fp_chop_len == 4) { + result = 1; + } else { + result = 0; + } + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest578(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 icmp any any -> any any " + "(content:\"one\"; http_user_agent; " + "content:\"two\"; http_user_agent; offset:10; " + "content:\"oneonethree\"; fast_pattern:3,4; http_user_agent; sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; + if (ud->flags & DETECT_CONTENT_FAST_PATTERN && + !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && + ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && + ud->fp_chop_offset == 3 && + ud->fp_chop_len == 4) { + result = 1; + } else { + result = 0; + } + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest579(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 icmp any any -> any any " + "(content:\"one\"; http_user_agent; " + "content:\"two\"; http_user_agent; depth:10; " + "content:\"oneonethree\"; fast_pattern:3,4; http_user_agent; sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; + if (ud->flags & DETECT_CONTENT_FAST_PATTERN && + !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && + ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && + ud->fp_chop_offset == 3 && + ud->fp_chop_len == 4) { + result = 1; + } else { + result = 0; + } + + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest580(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 icmp any any -> any any " + "(content:\"one\"; http_user_agent; " + "content:\"two\"; fast_pattern:65977,4; http_user_agent; " + "content:\"three\"; http_user_agent; distance:10; sid:1;)"); + if (de_ctx->sig_list != NULL) + goto end; + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest581(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 icmp any any -> any any " + "(content:\"one\"; http_user_agent; " + "content:\"oneonetwo\"; fast_pattern:3,65977; http_user_agent; " + "content:\"three\"; distance:10; http_user_agent; sid:1;)"); + if (de_ctx->sig_list != NULL) + goto end; + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest582(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 icmp any any -> any any " + "(content:\"one\"; http_user_agent; " + "content:\"two\"; fast_pattern:65534,4; http_user_agent; " + "content:\"three\"; http_user_agent; distance:10; sid:1;)"); + if (de_ctx->sig_list != NULL) + goto end; + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest583(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 icmp any any -> any any " + "(content:\"one\"; http_user_agent; " + "content:!\"oneonetwo\"; fast_pattern:3,4; http_user_agent; " + "content:\"three\"; http_user_agent; sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; + if (ud->flags & DETECT_CONTENT_FAST_PATTERN && + ud->flags & DETECT_CONTENT_NEGATED && + !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && + ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && + ud->fp_chop_offset == 3 && + ud->fp_chop_len == 4) { + result = 1; + } else { + result = 0; + } + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest584(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 icmp any any -> any any " + "(content:\"one\"; http_user_agent; " + "content:!\"oneonetwo\"; fast_pattern:3,4; http_user_agent; distance:10; " + "content:\"three\"; http_user_agent; sid:1;)"); + if (de_ctx->sig_list != NULL) + goto end; + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest585(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 icmp any any -> any any " + "(content:\"one\"; http_user_agent; " + "content:!\"oneonetwo\"; fast_pattern:3,4; http_user_agent; within:10; " + "content:\"three\"; http_user_agent; sid:1;)"); + if (de_ctx->sig_list != NULL) + goto end; + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest586(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 icmp any any -> any any " + "(content:\"one\"; http_user_agent; " + "content:!\"oneonetwo\"; fast_pattern:3,4; http_user_agent; offset:10; " + "content:\"three\"; http_user_agent; sid:1;)"); + if (de_ctx->sig_list != NULL) + goto end; + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest587(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 icmp any any -> any any " + "(content:\"one\"; http_user_agent; " + "content:!\"oneonetwo\"; fast_pattern:3,4; http_user_agent; depth:10; " + "content:\"three\"; http_user_agent; sid:1;)"); + if (de_ctx->sig_list != NULL) + goto end; + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest588(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 icmp any any -> any any " + "(content:\"one\"; http_user_agent; " + "content:!\"oneonetwo\"; fast_pattern:3,4; http_user_agent; " + "content:\"three\"; http_user_agent; sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; + if (ud->flags & DETECT_CONTENT_FAST_PATTERN && + ud->flags & DETECT_CONTENT_NEGATED && + !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && + ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && + ud->fp_chop_offset == 3 && + ud->fp_chop_len == 4) { + result = 1; + } else { + result = 0; + } + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + + #endif void DetectFastPatternRegisterTests(void) @@ -16348,6 +17536,49 @@ void DetectFastPatternRegisterTests(void) UtRegisterTest("DetectFastPatternTest545", DetectFastPatternTest545, 1); UtRegisterTest("DetectFastPatternTest546", DetectFastPatternTest546, 1); UtRegisterTest("DetectFastPatternTest547", DetectFastPatternTest547, 1); + /* file_data fast_pattern tests ^ */ + /* http_user_agent fast_pattern tests v */ + UtRegisterTest("DetectFastPatternTest548", DetectFastPatternTest548, 1); + UtRegisterTest("DetectFastPatternTest549", DetectFastPatternTest549, 1); + UtRegisterTest("DetectFastPatternTest550", DetectFastPatternTest550, 1); + UtRegisterTest("DetectFastPatternTest551", DetectFastPatternTest551, 1); + UtRegisterTest("DetectFastPatternTest552", DetectFastPatternTest552, 1); + UtRegisterTest("DetectFastPatternTest553", DetectFastPatternTest553, 1); + UtRegisterTest("DetectFastPatternTest554", DetectFastPatternTest554, 1); + UtRegisterTest("DetectFastPatternTest555", DetectFastPatternTest555, 1); + UtRegisterTest("DetectFastPatternTest556", DetectFastPatternTest556, 1); + UtRegisterTest("DetectFastPatternTest557", DetectFastPatternTest557, 1); + UtRegisterTest("DetectFastPatternTest558", DetectFastPatternTest558, 1); + UtRegisterTest("DetectFastPatternTest559", DetectFastPatternTest559, 1); + UtRegisterTest("DetectFastPatternTest560", DetectFastPatternTest560, 1); + UtRegisterTest("DetectFastPatternTest561", DetectFastPatternTest561, 1); + UtRegisterTest("DetectFastPatternTest562", DetectFastPatternTest562, 1); + UtRegisterTest("DetectFastPatternTest563", DetectFastPatternTest563, 1); + UtRegisterTest("DetectFastPatternTest564", DetectFastPatternTest564, 1); + UtRegisterTest("DetectFastPatternTest565", DetectFastPatternTest565, 1); + UtRegisterTest("DetectFastPatternTest566", DetectFastPatternTest566, 1); + UtRegisterTest("DetectFastPatternTest567", DetectFastPatternTest567, 1); + UtRegisterTest("DetectFastPatternTest568", DetectFastPatternTest568, 1); + UtRegisterTest("DetectFastPatternTest569", DetectFastPatternTest569, 1); + UtRegisterTest("DetectFastPatternTest570", DetectFastPatternTest570, 1); + UtRegisterTest("DetectFastPatternTest571", DetectFastPatternTest571, 1); + UtRegisterTest("DetectFastPatternTest572", DetectFastPatternTest572, 1); + UtRegisterTest("DetectFastPatternTest573", DetectFastPatternTest573, 1); + UtRegisterTest("DetectFastPatternTest574", DetectFastPatternTest574, 1); + UtRegisterTest("DetectFastPatternTest575", DetectFastPatternTest575, 1); + UtRegisterTest("DetectFastPatternTest576", DetectFastPatternTest576, 1); + UtRegisterTest("DetectFastPatternTest577", DetectFastPatternTest577, 1); + UtRegisterTest("DetectFastPatternTest578", DetectFastPatternTest578, 1); + UtRegisterTest("DetectFastPatternTest579", DetectFastPatternTest579, 1); + UtRegisterTest("DetectFastPatternTest580", DetectFastPatternTest580, 1); + UtRegisterTest("DetectFastPatternTest581", DetectFastPatternTest581, 1); + UtRegisterTest("DetectFastPatternTest582", DetectFastPatternTest582, 1); + UtRegisterTest("DetectFastPatternTest583", DetectFastPatternTest583, 1); + UtRegisterTest("DetectFastPatternTest584", DetectFastPatternTest584, 1); + UtRegisterTest("DetectFastPatternTest585", DetectFastPatternTest585, 1); + UtRegisterTest("DetectFastPatternTest586", DetectFastPatternTest586, 1); + UtRegisterTest("DetectFastPatternTest587", DetectFastPatternTest587, 1); + UtRegisterTest("DetectFastPatternTest588", DetectFastPatternTest588, 1); #endif return; diff --git a/src/detect-http-ua.c b/src/detect-http-ua.c new file mode 100644 index 0000000000..0d1050e9c0 --- /dev/null +++ b/src/detect-http-ua.c @@ -0,0 +1,2354 @@ +/* Copyright (C) 2007-2012 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 + * + * Implements support for the http_user_agent keyword. + */ + +#include "suricata-common.h" +#include "threads.h" +#include "decode.h" + +#include "detect.h" +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-state.h" +#include "detect-content.h" +#include "detect-pcre.h" + +#include "flow.h" +#include "flow-var.h" +#include "flow-util.h" + +#include "util-debug.h" +#include "util-unittest.h" +#include "util-unittest-helper.h" +#include "util-spm.h" + +#include "app-layer.h" + +#include +#include "app-layer-htp.h" +#include "stream-tcp.h" +#include "detect-http-ua.h" + +int DetectHttpUASetup(DetectEngineCtx *, Signature *, char *); +void DetectHttpUARegisterTests(void); +void DetectHttpUAFree(void *); + +/** + * \brief Registers the keyword handlers for the "http_user_agent" keyword. + */ +void DetectHttpUARegister(void) +{ + sigmatch_table[DETECT_AL_HTTP_USER_AGENT].name = "http_user_agent"; + sigmatch_table[DETECT_AL_HTTP_USER_AGENT].Match = NULL; + sigmatch_table[DETECT_AL_HTTP_USER_AGENT].AppLayerMatch = NULL; + sigmatch_table[DETECT_AL_HTTP_USER_AGENT].Setup = DetectHttpUASetup; + sigmatch_table[DETECT_AL_HTTP_USER_AGENT].Free = DetectHttpUAFree; + sigmatch_table[DETECT_AL_HTTP_USER_AGENT].RegisterTests = DetectHttpUARegisterTests; + sigmatch_table[DETECT_AL_HTTP_USER_AGENT].alproto = ALPROTO_HTTP; + + sigmatch_table[DETECT_AL_HTTP_USER_AGENT].flags |= SIGMATCH_PAYLOAD ; + + return; +} + +/** + * \brief The setup function for the http_user_agent keyword for a signature. + * + * \param de_ctx Pointer to the detection engine context. + * \param s Pointer to the signature for the current Signature being + * parsed from the rules. + * \param m Pointer to the head of the SigMatch for the current rule + * being parsed. + * \param arg Pointer to the string holding the keyword value. + * + * \retval 0 On success + * \retval -1 On failure + */ +int DetectHttpUASetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) +{ + DetectContentData *cd = NULL; + SigMatch *sm = NULL; + + if (arg != NULL && strcmp(arg, "") != 0) { + SCLogError(SC_ERR_INVALID_ARGUMENT, "http_user_agent supplied with args"); + goto error; + } + + sm = SigMatchGetLastSMFromLists(s, 2, + DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH]); + /* if we still can't find any previous content keywords, it's an invalid + * rule */ + if (sm == NULL) { + SCLogError(SC_ERR_INVALID_SIGNATURE, "\"http_user_agent\" keyword " + "found inside the rule without a content context. " + "Please use a \"content\" keyword before using the " + "\"http_user_agent\" keyword"); + goto error; + } + + cd = (DetectContentData *)sm->ctx; + + /* http_user_agent should not be used with the rawbytes rule */ + if (cd->flags & DETECT_CONTENT_RAWBYTES) { + SCLogError(SC_ERR_INVALID_SIGNATURE, "http_user_agent rule can not " + "be used with the rawbytes rule keyword"); + goto error; + } + + if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_HTTP) { + SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains a non http " + "alproto set"); + goto error; + } + + if (s->flags & SIG_FLAG_TOCLIENT) { + SCLogError(SC_ERR_INVALID_SIGNATURE, "http_user_agent can not be used " + "with flow:to_client or flow:from_server. "); + goto error; + } + + if (cd->flags & DETECT_CONTENT_WITHIN || cd->flags & DETECT_CONTENT_DISTANCE) { + SigMatch *pm = SigMatchGetLastSMFromLists(s, 4, + DETECT_CONTENT, sm->prev, + DETECT_PCRE, sm->prev); + /* pm can be NULL now. To accomodate parsing sigs like - + * content:one; http_modifier; content:two; distance:0; http_modifier */ + if (pm != NULL) { + if (pm->type == DETECT_CONTENT) { + DetectContentData *tmp_cd = (DetectContentData *)pm->ctx; + tmp_cd->flags &= ~DETECT_CONTENT_RELATIVE_NEXT; + } else { + DetectPcreData *tmp_pd = (DetectPcreData *)pm->ctx; + tmp_pd->flags &= ~ DETECT_PCRE_RELATIVE_NEXT; + } + + } /* if (pm != NULL) */ + + /* reassigning pm */ + pm = SigMatchGetLastSMFromLists(s, 4, + DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH], + DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]); + if (pm == NULL) { + SCLogError(SC_ERR_INVALID_SIGNATURE, "http_user_agent seen with a " + "distance or within without a previous http_user_agent " + "content. Invalidating signature."); + goto error; + } + if (pm->type == DETECT_PCRE) { + DetectPcreData *tmp_pd = (DetectPcreData *)pm->ctx; + tmp_pd->flags |= DETECT_PCRE_RELATIVE_NEXT; + } else { + DetectContentData *tmp_cd = (DetectContentData *)pm->ctx; + tmp_cd->flags |= DETECT_CONTENT_RELATIVE_NEXT; + } + } + cd->id = DetectPatternGetId(de_ctx->mpm_pattern_id_store, cd, DETECT_SM_LIST_HUADMATCH); + sm->type = DETECT_CONTENT; + + /* transfer the sm from the pmatch list to huadmatch list */ + SigMatchTransferSigMatchAcrossLists(sm, + &s->sm_lists[DETECT_SM_LIST_PMATCH], + &s->sm_lists_tail[DETECT_SM_LIST_PMATCH], + &s->sm_lists[DETECT_SM_LIST_HUADMATCH], + &s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]); + + /* flag the signature to indicate that we scan the app layer data */ + s->flags |= SIG_FLAG_APPLAYER; + s->alproto = ALPROTO_HTTP; + + return 0; + +error: + return -1; +} + +/** + * \brief The function to free the http_user_agent data. + * + * \param ptr Pointer to the http_user_agent. + */ +void DetectHttpUAFree(void *ptr) +{ + DetectContentData *huad = (DetectContentData *)ptr; + if (huad == NULL) + return; + + if (huad->content != NULL) + SCFree(huad->content); + + BoyerMooreCtxDeInit(huad->bm_ctx); + SCFree(huad); + + return; +} + +/************************************Unittests*********************************/ + +#ifdef UNITTESTS + +#include "stream-tcp-reassemble.h" + +/** + * \test Test that a signature containting a http_user_agent is correctly parsed + * and the keyword is registered. + */ +static int DetectHttpUATest01(void) +{ + DetectEngineCtx *de_ctx = NULL; + int result = 0; + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " + "(msg:\"Testing http_user_agent\"; " + "content:\"one\"; http_user_agent; sid:1;)"); + if (de_ctx->sig_list != NULL) { + result = 1; + } else { + goto end; + } + + end: + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + + return result; +} + +/** + * \test Test that a signature containing an valid http_user_agent entry is + * parsed. + */ +static int DetectHttpUATest02(void) +{ + DetectEngineCtx *de_ctx = NULL; + int result = 0; + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " + "(msg:\"Testing http_user_agent\"; " + "content:\"one\"; http_user_agent:; sid:1;)"); + if (de_ctx->sig_list != NULL) + result = 1; + + end: + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + + return result; +} + +/** + * \test Test that an invalid signature containing no content but a + * http_user_agent is invalidated. + */ +static int DetectHttpUATest03(void) +{ + DetectEngineCtx *de_ctx = NULL; + int result = 0; + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " + "(msg:\"Testing http_user_agent\"; " + "http_user_agent; sid:1;)"); + if (de_ctx->sig_list == NULL) + result = 1; + + end: + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + + return result; +} + +/** + * \test Test that an invalid signature containing a rawbytes along with a + * http_user_agent is invalidated. + */ +static int DetectHttpUATest04(void) +{ + DetectEngineCtx *de_ctx = NULL; + int result = 0; + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " + "(msg:\"Testing http_user_agent\"; " + "content:\"one\"; rawbytes; http_user_agent; sid:1;)"); + if (de_ctx->sig_list == NULL) + result = 1; + + end: + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + + return result; +} + +/** + * \test Test that a http_user_agent with nocase is parsed. + */ +static int DetectHttpUATest05(void) +{ + DetectEngineCtx *de_ctx = NULL; + int result = 0; + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " + "(msg:\"Testing http_user_agent\"; " + "content:\"one\"; http_user_agent; nocase; sid:1;)"); + if (de_ctx->sig_list != NULL) + result = 1; + + end: + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + + return result; +} + +/** + *\test Test that the http_user_agent content matches against a http request + * which holds the content. + */ +static int DetectHttpUATest06(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: This is dummy message body\r\n" + "Content-Type: text/html\r\n" + "\r\n"; + uint32_t http_len = sizeof(http_buf) - 1; + int result = 0; + + 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.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); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " + "(msg:\"http user agent test\"; " + "content:\"message\"; http_user_agent; " + "sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, 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 (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); + return result; +} + +/** + *\test Test that the http_user_agent content matches against a http request + * which holds the content. + */ +static int DetectHttpUATest07(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: This is dummy message"; + uint8_t http2_buf[] = + "body1\r\n\r\n"; + uint32_t http1_len = sizeof(http1_buf) - 1; + uint32_t http2_len = sizeof(http2_buf) - 1; + int result = 0; + + 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.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_HTTP; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " + "(msg:\"http user agent test\"; " + "content:\"message\"; http_user_agent; " + "sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, 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 = AppLayerParse(NULL, &f, ALPROTO_HTTP, 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 (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + 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_user_agent content matches against a http request + * which holds the content. + */ +static int DetectHttpUATest08(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: This is dummy mess"; + uint8_t http2_buf[] = + "age body\r\n\r\n"; + uint32_t http1_len = sizeof(http1_buf) - 1; + uint32_t http2_len = sizeof(http2_buf) - 1; + int result = 0; + + + 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.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_HTTP; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " + "(msg:\"http user agent test\"; " + "content:\"message\"; http_user_agent; " + "sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, 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 = AppLayerParse(NULL, &f, ALPROTO_HTTP, 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 (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + 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_user_agent content matches against a http request + * which holds the content, against a cross boundary present pattern. + */ +static int DetectHttpUATest09(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: This is dummy body1"; + uint8_t http2_buf[] = + "This is dummy message body2\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1"; + uint32_t http1_len = sizeof(http1_buf) - 1; + uint32_t http2_len = sizeof(http2_buf) - 1; + int result = 0; + + + 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.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_HTTP; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " + "(msg:\"http user agent test\"; " + "content:\"body1This\"; http_user_agent; " + "sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, 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 = AppLayerParse(NULL, &f, ALPROTO_HTTP, 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 (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + 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_user_agent content matches against a http request + * against a case insensitive pattern. + */ +static int DetectHttpUATest10(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: This is dummy bodY1"; + uint8_t http2_buf[] = + "This is dummy message body2\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy bodY1"; + uint32_t http1_len = sizeof(http1_buf) - 1; + uint32_t http2_len = sizeof(http2_buf) - 1; + int result = 0; + + 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.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_HTTP; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " + "(msg:\"http user agent test\"; " + "content:\"body1this\"; http_user_agent; nocase;" + "sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, 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 = AppLayerParse(NULL, &f, ALPROTO_HTTP, 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 (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + 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_user_agent content matches against a + * http request which doesn't hold the content. + */ +static int DetectHttpUATest11(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: This is dummy message body\r\n" + "Content-Type: text/html\r\n" + "\r\n"; + uint32_t http_len = sizeof(http_buf) - 1; + int result = 0; + + 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.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); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " + "(msg:\"http user agent test\"; " + "content:!\"message\"; http_user_agent; " + "sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, 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 matched but shouldn't have"); + goto end; + } + + result = 1; +end: + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); + return result; +} + +/** + *\test Negative test that the negated http_user_agent content matches against a + * http request which holds hold the content. + */ +static int DetectHttpUATest12(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: This is dummy body\r\n" + "\r\n"; + uint32_t http_len = sizeof(http_buf) - 1; + int result = 0; + + 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.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); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " + "(msg:\"http user agent test\"; " + "content:!\"message\"; http_user_agent; " + "sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, 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 (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); + return result; +} + +/** + * \test Test that the http_user_agent content matches against a http request + * which holds the content. + */ +static int DetectHttpUATest13(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: longbufferabcdefghijklmnopqrstuvwxyz0123456789bufferend\r\n" + "Content-Type: text/html\r\n" + "\r\n"; + uint32_t http_len = sizeof(http_buf) - 1; + int result = 0; + + + 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.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); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " + "(msg:\"http user agent test\"; " + "content:\"abcdefghijklmnopqrstuvwxyz0123456789\"; http_user_agent; " + "sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, 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 (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + 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 DetectHttpUATest14(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[] = "Cookie: dummy1\r\n"; + uint8_t httpbuf3[] = "User-Agent: Body one!!\r\n\r\n"; + 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 */ + uint8_t httpbuf4[] = "GET /?var=val HTTP/1.1\r\n"; + uint8_t httpbuf5[] = "Cookie: dummy2\r\n"; + uint8_t httpbuf6[] = "User-Agent: Body two\r\n\r\n"; + uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */ + uint32_t httplen5 = sizeof(httpbuf5) - 1; /* minus the \0 */ + uint32_t httplen6 = sizeof(httpbuf6) - 1; /* minus the \0 */ + + 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 = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"POST\"; http_method; content:\"dummy1\"; http_cookie; content:\"Body one\"; http_user_agent; 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:\"dummy2\"; http_cookie; content:\"Body two\"; http_user_agent; 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 = AppLayerParse(NULL, &f, ALPROTO_HTTP, 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 = AppLayerParse(NULL, &f, ALPROTO_HTTP, 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 = AppLayerParse(NULL, &f, ALPROTO_HTTP, 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("sig 1 didn't alert: "); + goto end; + } + p->alerts.cnt = 0; + + r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf4, httplen4); + 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) || PacketAlertCheck(p, 2)) { + printf("sig 1 alerted (4): "); + goto end; + } + p->alerts.cnt = 0; + + r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf5, httplen5); + 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 = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf6, httplen6); + 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, 1) || !(PacketAlertCheck(p, 2))) { + printf("signature 2 didn't match or sig 1 matched, but shouldn't 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 (list_size(htp_state->connp->conn->transactions) != 2) { + printf("The http app layer doesn't have 2 transactions, but it should: "); + goto end; + } + + result = 1; +end: + if (det_ctx != NULL) { + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + } + if (de_ctx != NULL) { + SigGroupCleanup(de_ctx); + DetectEngineCtxFree(de_ctx); + } + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePacket(p); + return result; +} + +int DetectHttpUATest16(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 " + "(content:\"one\"; content:\"one\"; http_user_agent; sid:1;)"); + if (de_ctx->sig_list == NULL) { + printf("de_ctx->sig_list == NULL\n"); + goto end; + } + + if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { + printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); + goto end; + } + + if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL) { + printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL\n"); + goto end; + } + + DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; + DetectContentData *huad = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; + if (cd->id == huad->id) + goto end; + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectHttpUATest17(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 " + "(content:\"one\"; http_user_agent; content:\"one\"; sid:1;)"); + if (de_ctx->sig_list == NULL) { + printf("de_ctx->sig_list == NULL\n"); + goto end; + } + + if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { + printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); + goto end; + } + + if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL) { + printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL\n"); + goto end; + } + + DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; + DetectContentData *huad = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; + if (cd->id == huad->id) + goto end; + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectHttpUATest18(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 " + "(content:\"one\"; content:\"one\"; content:\"one\"; http_user_agent; content:\"one\"; sid:1;)"); + if (de_ctx->sig_list == NULL) { + printf("de_ctx->sig_list == NULL\n"); + goto end; + } + + if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { + printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); + goto end; + } + + if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL) { + printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL\n"); + goto end; + } + + DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; + DetectContentData *huad = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; + if (cd->id != 0 || huad->id != 1) + goto end; + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectHttpUATest19(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 " + "(content:\"one\"; http_user_agent; content:\"one\"; content:\"one\"; content:\"one\"; sid:1;)"); + if (de_ctx->sig_list == NULL) { + printf("de_ctx->sig_list == NULL\n"); + goto end; + } + + if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { + printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); + goto end; + } + + if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL) { + printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL\n"); + goto end; + } + + DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; + DetectContentData *huad = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; + if (cd->id != 1 || huad->id != 0) + goto end; + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectHttpUATest20(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 " + "(content:\"one\"; http_user_agent; " + "content:\"one\"; content:\"one\"; http_user_agent; content:\"one\"; sid:1;)"); + if (de_ctx->sig_list == NULL) { + printf("de_ctx->sig_list == NULL\n"); + goto end; + } + + if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { + printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); + goto end; + } + + if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL) { + printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL\n"); + goto end; + } + + DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; + DetectContentData *huad1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; + DetectContentData *huad2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; + if (cd->id != 1 || huad1->id != 0 || huad2->id != 0) + goto end; + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectHttpUATest21(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 " + "(content:\"one\"; http_user_agent; " + "content:\"one\"; content:\"one\"; http_user_agent; content:\"two\"; sid:1;)"); + if (de_ctx->sig_list == NULL) { + printf("de_ctx->sig_list == NULL\n"); + goto end; + } + + if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { + printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); + goto end; + } + + if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL) { + printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL\n"); + goto end; + } + + DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; + DetectContentData *huad1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; + DetectContentData *huad2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; + if (cd->id != 2 || huad1->id != 0 || huad2->id != 0) + goto end; + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + + + + + + + + + + + + + + +int DetectHttpUATest22(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 " + "(content:\"one\"; content:\"two\"; http_user_agent; " + "content:\"three\"; distance:10; http_user_agent; content:\"four\"; sid:1;)"); + if (de_ctx->sig_list == NULL) { + printf("de_ctx->sig_list == NULL\n"); + goto end; + } + + if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { + printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); + goto end; + } + + if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL) { + printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL\n"); + goto end; + } + + DetectContentData *cd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; + DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; + DetectContentData *huad1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; + DetectContentData *huad2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; + if (cd1->flags != 0 || memcmp(cd1->content, "one", cd1->content_len) != 0 || + cd2->flags != 0 || memcmp(cd2->content, "four", cd2->content_len) != 0 || + huad1->flags != DETECT_CONTENT_RELATIVE_NEXT || + memcmp(huad1->content, "two", huad1->content_len) != 0 || + huad2->flags != DETECT_CONTENT_DISTANCE || + memcmp(huad2->content, "three", huad1->content_len) != 0) { + goto end; + } + + if (!DETECT_CONTENT_IS_SINGLE(cd1) || + !DETECT_CONTENT_IS_SINGLE(cd2) || + DETECT_CONTENT_IS_SINGLE(huad1) || + DETECT_CONTENT_IS_SINGLE(huad2)) { + goto end; + } + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectHttpUATest23(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 " + "(content:\"one\"; http_user_agent; pcre:/two/; " + "content:\"three\"; distance:10; http_user_agent; content:\"four\"; sid:1;)"); + if (de_ctx->sig_list == NULL) { + printf("de_ctx->sig_list == NULL\n"); + goto end; + } + + if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { + printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); + goto end; + } + + if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL) { + printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL\n"); + goto end; + } + + DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; + DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; + DetectContentData *huad1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; + DetectContentData *huad2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; + if (pd1->flags != 0 || + cd2->flags != 0 || memcmp(cd2->content, "four", cd2->content_len) != 0 || + huad1->flags != DETECT_CONTENT_RELATIVE_NEXT || + memcmp(huad1->content, "one", huad1->content_len) != 0 || + huad2->flags != DETECT_CONTENT_DISTANCE || + memcmp(huad2->content, "three", huad1->content_len) != 0) { + goto end; + } + + if (!DETECT_CONTENT_IS_SINGLE(cd2) || + DETECT_CONTENT_IS_SINGLE(huad1) || + DETECT_CONTENT_IS_SINGLE(huad2)) { + goto end; + } + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectHttpUATest24(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 " + "(content:\"one\"; http_user_agent; pcre:/two/; " + "content:\"three\"; distance:10; within:15; http_user_agent; content:\"four\"; sid:1;)"); + if (de_ctx->sig_list == NULL) { + printf("de_ctx->sig_list == NULL\n"); + goto end; + } + + if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { + printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); + goto end; + } + + if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL) { + printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL\n"); + goto end; + } + + DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; + DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; + DetectContentData *huad1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; + DetectContentData *huad2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; + if (pd1->flags != 0 || + cd2->flags != 0 || memcmp(cd2->content, "four", cd2->content_len) != 0 || + huad1->flags != DETECT_CONTENT_RELATIVE_NEXT || + memcmp(huad1->content, "one", huad1->content_len) != 0 || + huad2->flags != (DETECT_CONTENT_DISTANCE | DETECT_CONTENT_WITHIN) || + memcmp(huad2->content, "three", huad1->content_len) != 0) { + goto end; + } + + if (!DETECT_CONTENT_IS_SINGLE(cd2) || + DETECT_CONTENT_IS_SINGLE(huad1) || + DETECT_CONTENT_IS_SINGLE(huad2)) { + goto end; + } + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectHttpUATest25(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 " + "(content:\"one\"; http_user_agent; pcre:/two/; " + "content:\"three\"; distance:10; http_user_agent; " + "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->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { + printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); + goto end; + } + + if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL) { + printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL\n"); + goto end; + } + + DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; + DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; + DetectContentData *huad1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; + DetectContentData *huad2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; + if (pd1->flags != DETECT_PCRE_RELATIVE_NEXT || + cd2->flags != DETECT_CONTENT_DISTANCE || + memcmp(cd2->content, "four", cd2->content_len) != 0 || + huad1->flags != DETECT_CONTENT_RELATIVE_NEXT || + memcmp(huad1->content, "one", huad1->content_len) != 0 || + huad2->flags != DETECT_CONTENT_DISTANCE || + memcmp(huad2->content, "three", huad1->content_len) != 0) { + goto end; + } + + if (DETECT_CONTENT_IS_SINGLE(cd2) || + DETECT_CONTENT_IS_SINGLE(huad1) || + DETECT_CONTENT_IS_SINGLE(huad2)) { + goto end; + } + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectHttpUATest26(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 " + "(content:\"one\"; offset:10; http_user_agent; pcre:/two/; " + "content:\"three\"; distance:10; http_user_agent; 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->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { + printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); + goto end; + } + + if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL) { + printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL\n"); + goto end; + } + + DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; + DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; + DetectContentData *huad1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; + DetectContentData *huad2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; + if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT) || + cd2->flags != DETECT_CONTENT_DISTANCE || + memcmp(cd2->content, "four", cd2->content_len) != 0 || + huad1->flags != (DETECT_CONTENT_RELATIVE_NEXT | DETECT_CONTENT_OFFSET) || + memcmp(huad1->content, "one", huad1->content_len) != 0 || + huad2->flags != (DETECT_CONTENT_DISTANCE | DETECT_CONTENT_WITHIN) || + memcmp(huad2->content, "three", huad1->content_len) != 0) { + printf ("failed: http_user_agent incorrect flags"); + goto end; + } + + if (DETECT_CONTENT_IS_SINGLE(cd2) || + DETECT_CONTENT_IS_SINGLE(huad1) || + DETECT_CONTENT_IS_SINGLE(huad2)) { + goto end; + } + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectHttpUATest27(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 " + "(content:\"one\"; offset:10; http_user_agent; pcre:/two/; " + "content:\"three\"; distance:10; http_user_agent; within:10; " + "content:\"four\"; distance:10; sid:1;)"); + if (de_ctx->sig_list == NULL) { + printf("de_ctx->sig_list == NULL\n"); + goto end; + } + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectHttpUATest28(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 " + "(content:\"one\"; http_user_agent; pcre:/two/; " + "content:\"three\"; http_user_agent; 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->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { + printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); + goto end; + } + + if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL) { + printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL\n"); + goto end; + } + + DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; + DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; + DetectContentData *huad1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; + DetectContentData *huad2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; + if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT) || + cd2->flags != DETECT_CONTENT_DISTANCE || + memcmp(cd2->content, "four", cd2->content_len) != 0 || + huad1->flags != 0 || + memcmp(huad1->content, "one", huad1->content_len) != 0 || + huad2->flags != DETECT_CONTENT_DEPTH || + memcmp(huad2->content, "three", huad1->content_len) != 0) { + goto end; + } + + if (DETECT_CONTENT_IS_SINGLE(cd2) || + !DETECT_CONTENT_IS_SINGLE(huad1) || + DETECT_CONTENT_IS_SINGLE(huad2)) { + goto end; + } + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectHttpUATest29(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 " + "(content:\"one\"; http_user_agent; " + "content:\"two\"; distance:0; http_user_agent; sid:1;)"); + if (de_ctx->sig_list == NULL) { + printf("de_ctx->sig_list == NULL\n"); + goto end; + } + + if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL) { + printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL\n"); + goto end; + } + + if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL) { + printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL\n"); + goto end; + } + + DetectContentData *huad1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; + DetectContentData *huad2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; + if (huad1->flags != DETECT_CONTENT_RELATIVE_NEXT || + memcmp(huad1->content, "one", huad1->content_len) != 0 || + huad2->flags != DETECT_CONTENT_DISTANCE || + memcmp(huad2->content, "two", huad1->content_len) != 0) { + goto end; + } + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectHttpUATest30(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 " + "(content:\"one\"; http_user_agent; " + "content:\"two\"; within:5; http_user_agent; sid:1;)"); + if (de_ctx->sig_list == NULL) { + printf("de_ctx->sig_list == NULL\n"); + goto end; + } + + if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL) { + printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL\n"); + goto end; + } + + if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL) { + printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL\n"); + goto end; + } + + DetectContentData *huad1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; + DetectContentData *huad2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; + if (huad1->flags != DETECT_CONTENT_RELATIVE_NEXT || + memcmp(huad1->content, "one", huad1->content_len) != 0 || + huad2->flags != DETECT_CONTENT_WITHIN || + memcmp(huad2->content, "two", huad1->content_len) != 0) { + goto end; + } + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectHttpUATest31(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 " + "(content:\"one\"; within:5; http_user_agent; sid:1;)"); + if (de_ctx->sig_list != NULL) { + printf("de_ctx->sig_list != NULL\n"); + goto end; + } + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectHttpUATest32(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 " + "(content:\"one\"; http_user_agent; within:5; sid:1;)"); + if (de_ctx->sig_list == NULL) { + printf("de_ctx->sig_list != NULL\n"); + goto end; + } + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectHttpUATest33(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 " + "(content:\"one\"; within:5; sid:1;)"); + if (de_ctx->sig_list != NULL) { + printf("de_ctx->sig_list != NULL\n"); + goto end; + } + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectHttpUATest34(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 " + "(pcre:/one/V; " + "content:\"two\"; within:5; http_user_agent; sid:1;)"); + if (de_ctx->sig_list == NULL) { + printf("de_ctx->sig_list == NULL\n"); + goto end; + } + + if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL) { + printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL\n"); + goto end; + } + + if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL) { + printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL\n"); + goto end; + } + + if (de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH] == NULL || + de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->type != DETECT_CONTENT || + de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev == NULL || + de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->type != DETECT_PCRE) { + + goto end; + } + + DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; + DetectContentData *huad2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; + if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT | DETECT_PCRE_HTTP_USER_AGENT) || + huad2->flags != DETECT_CONTENT_WITHIN || + memcmp(huad2->content, "two", huad2->content_len) != 0) { + goto end; + } + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectHttpUATest35(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 " + "(content:\"two\"; http_user_agent; " + "pcre:/one/VR; sid:1;)"); + if (de_ctx->sig_list == NULL) { + printf("de_ctx->sig_list == NULL\n"); + goto end; + } + + if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL) { + printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL\n"); + goto end; + } + + if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL) { + printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL\n"); + goto end; + } + + if (de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH] == NULL || + de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->type != DETECT_PCRE || + de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev == NULL || + de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->type != DETECT_CONTENT) { + + goto end; + } + + DetectContentData *huad1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; + DetectPcreData *pd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; + if (pd2->flags != (DETECT_PCRE_RELATIVE | DETECT_PCRE_HTTP_USER_AGENT) || + huad1->flags != DETECT_CONTENT_RELATIVE_NEXT || + memcmp(huad1->content, "two", huad1->content_len) != 0) { + goto end; + } + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectHttpUATest36(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 " + "(pcre:/one/V; " + "content:\"two\"; distance:5; http_user_agent; sid:1;)"); + if (de_ctx->sig_list == NULL) { + printf("de_ctx->sig_list == NULL\n"); + goto end; + } + + if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL) { + printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL\n"); + goto end; + } + + if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL) { + printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL\n"); + goto end; + } + + if (de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH] == NULL || + de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->type != DETECT_CONTENT || + de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev == NULL || + de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->type != DETECT_PCRE) { + + goto end; + } + + DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; + DetectContentData *huad2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; + if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT | DETECT_PCRE_HTTP_USER_AGENT) || + huad2->flags != DETECT_CONTENT_DISTANCE || + memcmp(huad2->content, "two", huad2->content_len) != 0) { + goto end; + } + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +#endif /* UNITTESTS */ + +void DetectHttpUARegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("DetectHttpUATest01", DetectHttpUATest01, 1); + UtRegisterTest("DetectHttpUATest02", DetectHttpUATest02, 1); + UtRegisterTest("DetectHttpUATest03", DetectHttpUATest03, 1); + UtRegisterTest("DetectHttpUATest04", DetectHttpUATest04, 1); + UtRegisterTest("DetectHttpUATest05", DetectHttpUATest05, 1); + UtRegisterTest("DetectHttpUATest06", DetectHttpUATest06, 1); + UtRegisterTest("DetectHttpUATest07", DetectHttpUATest07, 1); + UtRegisterTest("DetectHttpUATest08", DetectHttpUATest08, 1); + UtRegisterTest("DetectHttpUATest09", DetectHttpUATest09, 1); + UtRegisterTest("DetectHttpUATest10", DetectHttpUATest10, 1); + UtRegisterTest("DetectHttpUATest11", DetectHttpUATest11, 1); + UtRegisterTest("DetectHttpUATest12", DetectHttpUATest12, 1); + UtRegisterTest("DetectHttpUATest13", DetectHttpUATest13, 1); + UtRegisterTest("DetectHttpUATest14", DetectHttpUATest14, 1); + + UtRegisterTest("DetectHttpUATest16", DetectHttpUATest16, 1); + UtRegisterTest("DetectHttpUATest17", DetectHttpUATest17, 1); + UtRegisterTest("DetectHttpUATest18", DetectHttpUATest18, 1); + UtRegisterTest("DetectHttpUATest19", DetectHttpUATest19, 1); + UtRegisterTest("DetectHttpUATest20", DetectHttpUATest20, 1); + UtRegisterTest("DetectHttpUATest21", DetectHttpUATest21, 1); + + UtRegisterTest("DetectHttpUATest22", DetectHttpUATest22, 1); + UtRegisterTest("DetectHttpUATest23", DetectHttpUATest23, 1); + UtRegisterTest("DetectHttpUATest24", DetectHttpUATest24, 1); + UtRegisterTest("DetectHttpUATest25", DetectHttpUATest25, 1); + UtRegisterTest("DetectHttpUATest26", DetectHttpUATest26, 1); + UtRegisterTest("DetectHttpUATest27", DetectHttpUATest27, 1); + UtRegisterTest("DetectHttpUATest28", DetectHttpUATest28, 1); + UtRegisterTest("DetectHttpUATest29", DetectHttpUATest29, 1); + UtRegisterTest("DetectHttpUATest30", DetectHttpUATest30, 1); + UtRegisterTest("DetectHttpUATest31", DetectHttpUATest31, 1); + UtRegisterTest("DetectHttpUATest32", DetectHttpUATest32, 1); + UtRegisterTest("DetectHttpUATest33", DetectHttpUATest33, 1); + UtRegisterTest("DetectHttpUATest34", DetectHttpUATest34, 1); + UtRegisterTest("DetectHttpUATest35", DetectHttpUATest35, 1); + UtRegisterTest("DetectHttpUATest36", DetectHttpUATest36, 1); +#endif /* UNITTESTS */ + + return; +} +/** + * @} + */ diff --git a/src/detect-http-ua.h b/src/detect-http-ua.h new file mode 100644 index 0000000000..2b04245e73 --- /dev/null +++ b/src/detect-http-ua.h @@ -0,0 +1,29 @@ +/* Copyright (C) 2007-2012 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_HTTP_UA_H__ +#define __DETECT_HTTP_UA_H__ + +void DetectHttpUARegister(void); + +#endif /* __DETECT_HTTP_UA_H__ */ diff --git a/src/detect-isdataat.c b/src/detect-isdataat.c index faf5dd109f..ba4773693f 100644 --- a/src/detect-isdataat.c +++ b/src/detect-isdataat.c @@ -351,41 +351,43 @@ int DetectIsdataatSetup (DetectEngineCtx *de_ctx, Signature *s, char *isdataatst } return 0; } - pm = SigMatchGetLastSMFromLists(s, 54, - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], /* 1 */ + pm = SigMatchGetLastSMFromLists(s, 56, + DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], /* 5 */ + DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], /* 10 */ + DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH], + DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], /* 15 */ + DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], + DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH], DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], /* 20 */ + DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_DMATCH], DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_DMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_UMATCH]); /* 25 */ + DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_UMATCH]); if (pm == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "isdataat relative seen " "without a previous content uricontent, " "http_client_body, http_header, http_raw_header, " "http_method, http_cookie, http_raw_uri, " "http_stat_msg, http_stat_code, byte_test, " - "byte_extract, byte_jump keyword"); + "byte_extract, byte_jump or http_user_agent keyword"); goto error; } else { int list_type = SigMatchListSMBelongsTo(s, pm); @@ -457,10 +459,6 @@ int DetectIsdataatSetup (DetectEngineCtx *de_ctx, Signature *s, char *isdataatst return 0; error: - //if (idad != NULL) - // DetectIsdataatFree(idad); - //if (sm != NULL) - // SCFree(sm); return -1; } diff --git a/src/detect-nocase.c b/src/detect-nocase.c index 6cb1e34c55..45c0f5cbfe 100644 --- a/src/detect-nocase.c +++ b/src/detect-nocase.c @@ -74,7 +74,7 @@ static int DetectNocaseSetup (DetectEngineCtx *de_ctx, Signature *s, char *nulls } /* Search for the first previous SigMatch that supports nocase */ - SigMatch *pm = SigMatchGetLastSMFromLists(s, 22, + SigMatch *pm = SigMatchGetLastSMFromLists(s, 24, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], @@ -85,12 +85,14 @@ static int DetectNocaseSetup (DetectEngineCtx *de_ctx, Signature *s, char *nulls DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]); + DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], + DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]); if (pm == NULL) { SCLogError(SC_ERR_NOCASE_MISSING_PATTERN, "\"nocase\" needs a preceeding " - "content, uricontent, http_client_body, http_server_body, " - "http_header, http_method, http_uri, http_cookie, " - "http_raw_uri, http_stat_msg or http_stat_code option"); + "content, uricontent, http_client_body, http_server_body, " + "http_header, http_method, http_uri, http_cookie, " + "http_raw_uri, http_stat_msg, http_stat_code or http_user_agent " + "option"); SCReturnInt(-1); } diff --git a/src/detect-offset.c b/src/detect-offset.c index ba87613b93..dc2b65f335 100644 --- a/src/detect-offset.c +++ b/src/detect-offset.c @@ -83,7 +83,7 @@ int DetectOffsetSetup (DetectEngineCtx *de_ctx, Signature *s, char *offsetstr) break; default: - pm = SigMatchGetLastSMFromLists(s, 22, + pm = SigMatchGetLastSMFromLists(s, 24, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], @@ -94,13 +94,14 @@ int DetectOffsetSetup (DetectEngineCtx *de_ctx, Signature *s, char *offsetstr) DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]); + DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], + DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]); if (pm == NULL) { SCLogError(SC_ERR_OFFSET_MISSING_CONTENT, "offset needs " "preceeding content or uricontent option, http_client_body, " "http_header, http_raw_header, http_method, " - "http_cookie, http_raw_uri, http_stat_msg or " - "http_stat_code option"); + "http_cookie, http_raw_uri, http_stat_msg, " + "http_stat_code or http_user_agent option"); if (dubbed) SCFree(str); return -1; diff --git a/src/detect-parse.c b/src/detect-parse.c index 98a651fa9b..317d0f7a54 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -1098,7 +1098,8 @@ static int SigValidate(Signature *s) { DETECT_REPLACE, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], DETECT_REPLACE, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], DETECT_REPLACE, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_REPLACE, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]); + DETECT_REPLACE, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], + DETECT_REPLACE, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]); if (pm != NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "Signature has" " replace keyword linked with a modified content" @@ -1116,7 +1117,8 @@ static int SigValidate(Signature *s) { s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH] || s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH] || s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH] || - s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]) + s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH] || + s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]) { SCLogError(SC_ERR_INVALID_SIGNATURE, "Signature combines packet " "specific matches (like dsize, flags, ttl) with stream / " @@ -1246,6 +1248,8 @@ static Signature *SigInitHelper(DetectEngineCtx *de_ctx, char *sigstr, sig->flags |= SIG_FLAG_STATE_MATCH; if (sig->sm_lists[DETECT_SM_LIST_HSCDMATCH]) sig->flags |= SIG_FLAG_STATE_MATCH; + if (sig->sm_lists[DETECT_SM_LIST_HUADMATCH]) + sig->flags |= SIG_FLAG_STATE_MATCH; if (!(sig->init_flags & SIG_FLAG_INIT_FLOW)) { sig->flags |= SIG_FLAG_TOSERVER; diff --git a/src/detect-pcre.c b/src/detect-pcre.c index a5391404d8..cc7d671122 100644 --- a/src/detect-pcre.c +++ b/src/detect-pcre.c @@ -850,6 +850,13 @@ DetectPcreData *DetectPcreParse (DetectEngineCtx *de_ctx, char *regexstr) } pd->flags |= DETECT_PCRE_URI; break; + case 'V': + if (pd->flags & DETECT_PCRE_RAWBYTES) { + SCLogError(SC_ERR_INVALID_SIGNATURE, "regex modifier 'V' inconsistent with 'B'"); + goto error; + } + pd->flags |= DETECT_PCRE_HTTP_USER_AGENT; + break; case 'H': /* snort's option */ if (pd->flags & DETECT_PCRE_RAW_HEADER) { SCLogError(SC_ERR_INVALID_SIGNATURE, "regex modifier 'H' inconsistent with 'D'"); @@ -1100,7 +1107,8 @@ static int DetectPcreSetup (DetectEngineCtx *de_ctx, Signature *s, char *regexst (pd->flags & DETECT_PCRE_HTTP_STAT_CODE) || (pd->flags & DETECT_PCRE_HTTP_CLIENT_BODY) || (pd->flags & DETECT_PCRE_HTTP_SERVER_BODY) || - (pd->flags & DETECT_PCRE_HTTP_RAW_URI) ) { + (pd->flags & DETECT_PCRE_HTTP_RAW_URI) || + (pd->flags & DETECT_PCRE_HTTP_USER_AGENT) ) { SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "Invalid option. " "DCERPC rule has pcre keyword with http related modifier."); goto error; @@ -1142,6 +1150,17 @@ static int DetectPcreSetup (DetectEngineCtx *de_ctx, Signature *s, char *regexst s->alproto = ALPROTO_HTTP; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_HCDMATCH); + } else if (pd->flags & DETECT_PCRE_HTTP_USER_AGENT) { + SCLogDebug("User-Agent inspection modifier set on pcre"); + if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_HTTP) { + SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains " + "conflicting keywords."); + goto error; + } + s->flags |= SIG_FLAG_APPLAYER; + s->alproto = ALPROTO_HTTP; + + SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_HUADMATCH); } else if (pd->flags & DETECT_PCRE_METHOD) { //sm->type = DETECT_PCRE_HTTPMETHOD; diff --git a/src/detect-pcre.h b/src/detect-pcre.h index 7e878c2ad8..8a4f03a6e5 100644 --- a/src/detect-pcre.h +++ b/src/detect-pcre.h @@ -45,8 +45,10 @@ #define DETECT_PCRE_HTTP_RAW_URI 0x02000 #define DETECT_PCRE_HTTP_STAT_MSG 0x04000 #define DETECT_PCRE_HTTP_STAT_CODE 0x08000 +#define DETECT_PCRE_HTTP_USER_AGENT 0x10000 -#define DETECT_PCRE_NEGATE 0x10000 + +#define DETECT_PCRE_NEGATE 0x20000 typedef struct DetectPcreData_ { /* pcre options */ diff --git a/src/detect-within.c b/src/detect-within.c index 478fd9dc68..481afe3189 100644 --- a/src/detect-within.c +++ b/src/detect-within.c @@ -163,7 +163,7 @@ static int DetectWithinSetup (DetectEngineCtx *de_ctx, Signature *s, char *withi } } } else { - pm = SigMatchGetLastSMFromLists(s, 22, + pm = SigMatchGetLastSMFromLists(s, 24, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], @@ -174,13 +174,15 @@ static int DetectWithinSetup (DetectEngineCtx *de_ctx, Signature *s, char *withi DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]); + DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], + DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]); if (pm == NULL) { SCLogError(SC_ERR_WITHIN_MISSING_CONTENT, "\"within\" requires " "preceeding content, uricontent, http_client_body, " "http_server_body, http_header, http_raw_header, " "http_method, http_cookie, http_raw_uri, " - "http_stat_msg or http_stat_code option"); + "http_stat_msg, http_stat_code or http_user_agent " + "option"); if (dubbed) SCFree(str); return -1; diff --git a/src/detect.c b/src/detect.c index 00aac168e6..d018f4f931 100644 --- a/src/detect.c +++ b/src/detect.c @@ -50,6 +50,7 @@ #include "detect-http-cookie.h" #include "detect-http-method.h" +#include "detect-http-ua.h" #include "detect-engine-event.h" #include "decode.h" @@ -131,6 +132,7 @@ #include "detect-engine-hrud.h" #include "detect-engine-hsmd.h" #include "detect-engine-hscd.h" +#include "detect-engine-hua.h" #include "detect-byte-extract.h" #include "detect-file-data.h" #include "detect-replace.h" @@ -1250,6 +1252,11 @@ static inline void DetectMpmPrefilter(DetectEngineCtx *de_ctx, DetectEngineRunHttpStatCodeMpm(det_ctx, p->flow, alstate, flags); PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_HSCD); } + if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_HUAD) { + PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_HUAD); + DetectEngineRunHttpUAMpm(det_ctx, p->flow, alstate, flags); + PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_HUAD); + } } } else { SCLogDebug("NOT p->flowflags & FLOW_PKT_ESTABLISHED"); @@ -1978,6 +1985,9 @@ int SignatureIsIPOnly(DetectEngineCtx *de_ctx, Signature *s) { if (s->sm_lists[DETECT_SM_LIST_HSCDMATCH] != NULL) return 0; + if (s->sm_lists[DETECT_SM_LIST_HUADMATCH] != NULL) + return 0; + if (s->sm_lists[DETECT_SM_LIST_AMATCH] != NULL) return 0; @@ -2058,7 +2068,8 @@ static int SignatureIsDEOnly(DetectEngineCtx *de_ctx, Signature *s) { s->sm_lists[DETECT_SM_LIST_HCDMATCH] != NULL || s->sm_lists[DETECT_SM_LIST_HSMDMATCH] != NULL || s->sm_lists[DETECT_SM_LIST_HSCDMATCH] != NULL || - s->sm_lists[DETECT_SM_LIST_HRUDMATCH] != NULL) + s->sm_lists[DETECT_SM_LIST_HRUDMATCH] != NULL || + s->sm_lists[DETECT_SM_LIST_HUADMATCH] != NULL) { SCReturnInt(0); } @@ -2209,6 +2220,11 @@ static int SignatureCreateMask(Signature *s) { SCLogDebug("sig requires http app state"); } + if (s->sm_lists[DETECT_SM_LIST_HUADMATCH] != NULL) { + s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; + SCLogDebug("sig requires http app state"); + } + SigMatch *sm; for (sm = s->sm_lists[DETECT_SM_LIST_AMATCH] ; sm != NULL; sm = sm->next) { switch(sm->type) { @@ -2366,6 +2382,9 @@ static void SigInitStandardMpmFactoryContexts(DetectEngineCtx *de_ctx) de_ctx->sgh_mpm_context_hscd = MpmFactoryRegisterMpmCtxProfile("hscd", MPM_CTX_FACTORY_FLAGS_PREPARE_WITH_SIG_GROUP_BUILD); + de_ctx->sgh_mpm_context_huad = + MpmFactoryRegisterMpmCtxProfile("huad", + MPM_CTX_FACTORY_FLAGS_PREPARE_WITH_SIG_GROUP_BUILD); de_ctx->sgh_mpm_context_app_proto_detect = MpmFactoryRegisterMpmCtxProfile("app_proto_detect", 0); @@ -4425,6 +4444,18 @@ int SigGroupBuild (DetectEngineCtx *de_ctx) { mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); } //printf("hscd- %d\n", mpm_ctx->pattern_cnt); + + mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx->sgh_mpm_context_huad, 0); + if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { + mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); + } + //printf("huad- %d\n", mpm_ctx->pattern_cnt); + + mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx->sgh_mpm_context_huad, 1); + if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { + mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); + } + //printf("huad- %d\n", mpm_ctx->pattern_cnt); } // SigAddressPrepareStage5(de_ctx); @@ -4541,6 +4572,7 @@ void SigTableSetup(void) { DetectFilemagicRegister(); DetectFileMd5Register(); DetectAppLayerEventRegister(); + DetectHttpUARegister(); uint8_t i = 0; for (i = 0; i < DETECT_TBLSIZE; i++) { diff --git a/src/detect.h b/src/detect.h index 5982774c23..61e233caf2 100644 --- a/src/detect.h +++ b/src/detect.h @@ -104,6 +104,8 @@ enum { DETECT_SM_LIST_HSMDMATCH, /* list for http_stat_code keyword and the ones relative to it */ DETECT_SM_LIST_HSCDMATCH, + /* list for http_user_agent keyword and the ones relative to it */ + DETECT_SM_LIST_HUADMATCH, DETECT_SM_LIST_FILEMATCH, @@ -645,6 +647,7 @@ typedef struct DetectEngineCtx_ { int32_t sgh_mpm_context_hrud; int32_t sgh_mpm_context_hsmd; int32_t sgh_mpm_context_hscd; + int32_t sgh_mpm_context_huad; int32_t sgh_mpm_context_app_proto_detect; /** sgh for signatures that match against invalid packets. In those cases @@ -823,6 +826,8 @@ typedef struct SigTableElmt_ { #define SIG_GROUP_HEAD_MPM_HSMD 0x08000000 #define SIG_GROUP_HAVEHSCDCONTENT 0x10000000 #define SIG_GROUP_HEAD_MPM_HSCD 0x20000000 +#define SIG_GROUP_HAVEHUADCONTENT 0x40000000 +#define SIG_GROUP_HEAD_MPM_HUAD 0x80000000 typedef struct SigGroupHeadInitData_ { /* list of content containers @@ -880,6 +885,7 @@ typedef struct SigGroupHead_ { MpmCtx *mpm_hrud_ctx_ts; MpmCtx *mpm_hsmd_ctx_ts; MpmCtx *mpm_hscd_ctx_ts; + MpmCtx *mpm_huad_ctx_ts; MpmCtx *mpm_proto_tcp_ctx_tc; MpmCtx *mpm_proto_udp_ctx_tc; @@ -894,6 +900,7 @@ typedef struct SigGroupHead_ { MpmCtx *mpm_hrud_ctx_tc; MpmCtx *mpm_hsmd_ctx_tc; MpmCtx *mpm_hscd_ctx_tc; + MpmCtx *mpm_huad_ctx_tc; uint16_t mpm_uricontent_maxlen; @@ -998,6 +1005,7 @@ enum { DETECT_AL_HTTP_RAW_URI, DETECT_AL_HTTP_STAT_MSG, DETECT_AL_HTTP_STAT_CODE, + DETECT_AL_HTTP_USER_AGENT, DETECT_AL_SSH_PROTOVERSION, DETECT_AL_SSH_SOFTWAREVERSION, DETECT_AL_SSL_VERSION, diff --git a/src/suricata-common.h b/src/suricata-common.h index 145b0c9bf2..445fa44106 100644 --- a/src/suricata-common.h +++ b/src/suricata-common.h @@ -188,6 +188,7 @@ typedef enum PacketProfileDetectId_ { PROF_DETECT_MPM_HRUD, PROF_DETECT_MPM_HSMD, PROF_DETECT_MPM_HSCD, + PROF_DETECT_MPM_HUAD, PROF_DETECT_IPONLY, PROF_DETECT_RULES, PROF_DETECT_STATEFUL, diff --git a/src/suricata.c b/src/suricata.c index d1c4d93a9b..7f78bd1458 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -74,6 +74,7 @@ #include "detect-engine-hrud.h" #include "detect-engine-hsmd.h" #include "detect-engine-hscd.h" +#include "detect-engine-hua.h" #include "detect-engine-state.h" #include "detect-engine-tag.h" #include "detect-fast-pattern.h" @@ -1523,6 +1524,7 @@ int main(int argc, char **argv) DetectEngineHttpRawUriRegisterTests(); DetectEngineHttpStatMsgRegisterTests(); DetectEngineHttpStatCodeRegisterTests(); + DetectEngineHttpUARegisterTests(); DetectEngineRegisterTests(); SCLogRegisterTests(); SMTPParserRegisterTests();