diff --git a/src/Makefile.am b/src/Makefile.am index a05341e09e..832edfbf78 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -84,6 +84,7 @@ detect-engine-hrhd.c detect-engine-hrhd.h \ detect-engine-hmd.c detect-engine-hmd.h \ 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-state.c detect-engine-state.h \ detect-engine-file.c detect-engine-file.h \ detect-parse.c detect-parse.h \ diff --git a/src/detect-content.h b/src/detect-content.h index 90f1057547..59f2d4a792 100644 --- a/src/detect-content.h +++ b/src/detect-content.h @@ -52,15 +52,16 @@ #define DETECT_CONTENT_HMD_MPM 0x00040000 #define DETECT_CONTENT_HCD_MPM 0x00080000 #define DETECT_CONTENT_HRUD_MPM 0x00100000 +#define DETECT_CONTENT_HSMD_MPM 0x00200000 /* BE - byte extract */ -#define DETECT_CONTENT_OFFSET_BE 0x00200000 -#define DETECT_CONTENT_DEPTH_BE 0x00400000 -#define DETECT_CONTENT_DISTANCE_BE 0x00800000 -#define DETECT_CONTENT_WITHIN_BE 0x01000000 +#define DETECT_CONTENT_OFFSET_BE 0x00400000 +#define DETECT_CONTENT_DEPTH_BE 0x00800000 +#define DETECT_CONTENT_DISTANCE_BE 0x01000000 +#define DETECT_CONTENT_WITHIN_BE 0x02000000 /* replace data */ -#define DETECT_CONTENT_REPLACE 0x02000000 +#define DETECT_CONTENT_REPLACE 0x04000000 #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 8a5e425294..f742761c98 100644 --- a/src/detect-depth.c +++ b/src/detect-depth.c @@ -86,7 +86,7 @@ static int DetectDepthSetup (DetectEngineCtx *de_ctx, Signature *s, char *depths break; default: - pm = SigMatchGetLastSMFromLists(s, 18, + pm = SigMatchGetLastSMFromLists(s, 20, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], DETECT_URICONTENT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], DETECT_AL_HTTP_RAW_URI, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], @@ -95,13 +95,14 @@ static int DetectDepthSetup (DetectEngineCtx *de_ctx, Signature *s, char *depths DETECT_AL_HTTP_HEADER, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], DETECT_AL_HTTP_RAW_HEADER, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], DETECT_AL_HTTP_METHOD, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_AL_HTTP_COOKIE, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]); + DETECT_AL_HTTP_COOKIE, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], + DETECT_AL_HTTP_STAT_MSG, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]); 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 or " - "http_raw_uri option"); + "http_method option, http_cookie, http_raw_uri or " + "http_stat_msg option"); if (dubbed) SCFree(str); return -1; @@ -503,6 +504,47 @@ static int DetectDepthSetup (DetectEngineCtx *de_ctx, Signature *s, char *depths break; + case DETECT_AL_HTTP_STAT_MSG: + cd = (DetectContentData *)pm->ctx; + if (cd->flags & DETECT_CONTENT_NEGATED) { + if (cd->flags & DETECT_CONTENT_FAST_PATTERN) { + SCLogError(SC_ERR_INVALID_SIGNATURE, "You can't have a relative " + "negated keyword set along with a fast_pattern"); + goto error; + } + } else { + if (cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) { + SCLogError(SC_ERR_INVALID_SIGNATURE, "You can't have a relative " + "keyword set along with a fast_pattern:only;"); + goto error; + } + } + + if (str[0] != '-' && isalpha(str[0])) { + SigMatch *bed_sm = + DetectByteExtractRetrieveSMVar(str, s, + SigMatchListSMBelongsTo(s, pm)); + if (bed_sm == NULL) { + SCLogError(SC_ERR_INVALID_SIGNATURE, "Unknown byte_extract var " + "seen in depth - %s\n", str); + goto error; + } + cd->depth = ((DetectByteExtractData *)bed_sm->ctx)->local_id; + cd->flags |= DETECT_CONTENT_DEPTH_BE; + } else { + cd->depth = (uint32_t)atoi(str); + if (cd->depth < cd->content_len) { + cd->depth = cd->content_len; + SCLogDebug("depth increased to %"PRIu32" to match pattern len ", + cd->depth); + } + /* Now update the real limit, as depth is relative to the offset */ + cd->depth += cd->offset; + cd->flags |= DETECT_CONTENT_DEPTH; + } + + break; + default: SCLogError(SC_ERR_DEPTH_MISSING_CONTENT, "depth needs a preceeding " "content (or uricontent) option"); diff --git a/src/detect-distance.c b/src/detect-distance.c index 7947376f0b..c2ee1d33b4 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, 18, + pm = SigMatchGetLastSMFromLists(s, 20, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], DETECT_URICONTENT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], DETECT_AL_HTTP_RAW_URI, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], @@ -169,12 +169,13 @@ static int DetectDistanceSetup (DetectEngineCtx *de_ctx, Signature *s, DETECT_AL_HTTP_HEADER, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], DETECT_AL_HTTP_RAW_HEADER, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], DETECT_AL_HTTP_METHOD, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_AL_HTTP_COOKIE, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]); + DETECT_AL_HTTP_COOKIE, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], + DETECT_AL_HTTP_STAT_MSG, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]); 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 or http_raw_uri option"); + "http_cookie, http_raw_uri or http_stat_msg option"); if (dubbed) SCFree(str); return -1; @@ -832,6 +833,73 @@ static int DetectDistanceSetup (DetectEngineCtx *de_ctx, Signature *s, break; + case DETECT_AL_HTTP_STAT_MSG: + cd = (DetectContentData *)pm->ctx; + if (cd->flags & DETECT_CONTENT_NEGATED) { + if (cd->flags & DETECT_CONTENT_FAST_PATTERN) { + SCLogError(SC_ERR_INVALID_SIGNATURE, "You can't have a relative " + "negated keyword set along with a fast_pattern"); + goto error; + } + } else { + if (cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) { + SCLogError(SC_ERR_INVALID_SIGNATURE, "You can't have a relative " + "keyword set along with a fast_pattern:only;"); + goto error; + } + } + + if (str[0] != '-' && isalpha(str[0])) { + SigMatch *bed_sm = + DetectByteExtractRetrieveSMVar(str, s, + SigMatchListSMBelongsTo(s, pm)); + if (bed_sm == NULL) { + SCLogError(SC_ERR_INVALID_SIGNATURE, "Unknown byte_extract var " + "seen in distance - %s\n", str); + goto error; + } + cd->distance = ((DetectByteExtractData *)bed_sm->ctx)->local_id; + cd->flags |= DETECT_CONTENT_DISTANCE_BE; + } else { + cd->distance = strtol(str, NULL, 10); + if (cd->flags & DETECT_CONTENT_WITHIN) { + if ((cd->distance + cd->content_len) > cd->within) { + cd->within = cd->distance + cd->content_len; + } + } + } + + cd->flags |= DETECT_CONTENT_DISTANCE; + + /* reassigning pm */ + pm = SigMatchGetLastSMFromLists(s, 4, + DETECT_AL_HTTP_STAT_MSG, pm->prev, + DETECT_PCRE, pm->prev); + if (pm == NULL) { + SCLogError(SC_ERR_DISTANCE_MISSING_CONTENT, "distance for " + "http_stat_msg needs preceeding http_stat_msg " + "content"); + goto error; + } + + if (pm->type == DETECT_PCRE) { + DetectPcreData *tmp_pd = (DetectPcreData *)pm->ctx; + tmp_pd->flags |= DETECT_PCRE_RELATIVE_NEXT; + } else { + /* reassigning cd */ + cd = (DetectContentData *)pm->ctx; + if (cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) { + SCLogError(SC_ERR_INVALID_SIGNATURE, "Previous keyword " + "has a fast_pattern:only; set. You can't " + "have relative keywords around a fast_pattern " + "only content"); + goto error; + } + cd->flags |= DETECT_CONTENT_RELATIVE_NEXT; + } + + break; + default: SCLogError(SC_ERR_DISTANCE_MISSING_CONTENT, "distance needs two " "preceeding content or uricontent options"); diff --git a/src/detect-engine-hscd.c b/src/detect-engine-hscd.c new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/detect-engine-hscd.h b/src/detect-engine-hscd.h new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/detect-engine-hsmd.c b/src/detect-engine-hsmd.c new file mode 100644 index 0000000000..2b156bf1a9 --- /dev/null +++ b/src/detect-engine-hsmd.c @@ -0,0 +1,2278 @@ +/* Copyright (C) 2007-2010 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \ingroup httplayer + * + * @{ + */ + +/** + * \file + * + * \author Anoop Saldanha + */ + +#include "suricata-common.h" +#include "suricata.h" +#include "decode.h" + +#include "detect.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-hsmd.h" +#include "detect-parse.h" +#include "detect-engine-state.h" +#include "detect-pcre.h" +#include "detect-isdataat.h" +#include "detect-bytetest.h" +#include "detect-bytejump.h" + +#include "flow-util.h" +#include "util-spm.h" +#include "util-debug.h" +#include "util-print.h" +#include "flow.h" +#include "detect-flow.h" +#include "flow-var.h" +#include "threads.h" +#include "flow-alert-sid.h" + +#include "stream-tcp.h" +#include "stream.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" + +/** + * \brief Run the actual payload match function for http stat msg. + * + * For accounting the last match in relative matching the + * det_ctx->payload_offset var is used. + * + * \param de_ctx Detection engine context. + * \param det_ctx Detection engine thread context. + * \param s Signature to inspect. + * \param sm SigMatch to inspect. + * \param payload Ptr to the http stat msg to inspect. + * \param payload_len Length of the http stat msg. + * + * \retval 0 no match. + * \retval 1 match. + */ +static int DoInspectHttpStatMsg(DetectEngineCtx *de_ctx, + DetectEngineThreadCtx *det_ctx, + Signature *s, SigMatch *sm, + uint8_t *payload, uint32_t payload_len) +{ + SCEnter(); + + det_ctx->inspection_recursion_counter++; + + if (det_ctx->inspection_recursion_counter == de_ctx->inspection_recursion_limit) { + det_ctx->discontinue_matching = 1; + SCReturnInt(0); + } + + if (sm == NULL) { + SCReturnInt(0); + } + + if (sm->type == DETECT_AL_HTTP_STAT_MSG) { + if (payload_len == 0) { + SCReturnInt(0); + } + + DetectContentData *cd = (DetectContentData *)sm->ctx; + + /* disabled to avoid the FP from inspecting multiple transactions */ + //if (cd->flags & DETECT_CONTENT_HRUD_MPM && !(cd->flags & DETECT_CONTENT_NEGATED)) + // goto match; + + /* rule parsers should take care of this */ +#ifdef DEBUG + BUG_ON(cd->depth != 0 && cd->depth <= cd->offset); +#endif + + /* search for our pattern, checking the matches recursively. + * if we match we look for the next SigMatch as well */ + uint8_t *found = NULL; + uint32_t offset = 0; + uint32_t depth = payload_len; + uint32_t prev_offset = 0; /**< used in recursive searching */ + uint32_t prev_payload_offset = det_ctx->payload_offset; + + do { + if (cd->flags & DETECT_CONTENT_DISTANCE || + cd->flags & DETECT_CONTENT_WITHIN) { + SCLogDebug("prev_payload_offset %"PRIu32, prev_payload_offset); + + offset = prev_payload_offset; + depth = payload_len; + + if (cd->flags & DETECT_CONTENT_DISTANCE) { + if (cd->distance < 0 && (uint32_t)(abs(cd->distance)) > offset) + offset = 0; + else + offset += cd->distance; + } + + if (cd->flags & DETECT_CONTENT_WITHIN) { + if ((int32_t)depth > (int32_t)(prev_payload_offset + cd->within + cd->distance)) { + depth = prev_payload_offset + cd->within + cd->distance; + } + } + + if (cd->depth != 0) { + if ((cd->depth + prev_payload_offset) < depth) { + depth = prev_payload_offset + cd->depth; + } + } + + if (cd->offset > offset) { + offset = cd->offset; + } + } else { /* implied no relative matches */ + /* set depth */ + if (cd->depth != 0) { + depth = cd->depth; + } + + /* set offset */ + offset = cd->offset; + prev_payload_offset = 0; + } + + /* update offset with prev_offset if we're searching for + * matches after the first occurence. */ + if (prev_offset != 0) + offset = prev_offset; + + if (depth > payload_len) + depth = payload_len; + + /* if offset is bigger than depth we can never match on a pattern. + * We can however, "match" on a negated pattern. */ + if (offset > depth || depth == 0) { + if (cd->flags & DETECT_CONTENT_NEGATED) { + goto match; + } else { + SCReturnInt(0); + } + } + + uint8_t *spayload = payload + offset; + uint32_t spayload_len = depth - offset; + uint32_t match_offset = 0; +#ifdef DEBUG + BUG_ON(spayload_len > payload_len); +#endif + + /* do the actual search with boyer moore precooked ctx */ + if (cd->flags & DETECT_CONTENT_NOCASE) { + found = BoyerMooreNocase(cd->content, cd->content_len, + spayload, spayload_len, + cd->bm_ctx->bmGs, cd->bm_ctx->bmBc); + } else { + found = BoyerMoore(cd->content, cd->content_len, + spayload, spayload_len, + cd->bm_ctx->bmGs, cd->bm_ctx->bmBc); + } + + /* next we evaluate the result in combination with the + * negation flag. */ + if (found == NULL && !(cd->flags & DETECT_CONTENT_NEGATED)) { + SCReturnInt(0); + } else if (found == NULL && cd->flags & DETECT_CONTENT_NEGATED) { + goto match; + } else if (found != NULL && cd->flags & DETECT_CONTENT_NEGATED) { + det_ctx->discontinue_matching = 1; + SCReturnInt(0); + } else { + match_offset = (uint32_t)((found - payload) + cd->content_len); + det_ctx->payload_offset = match_offset; + + if (!(cd->flags & DETECT_CONTENT_RELATIVE_NEXT)) { + SCLogDebug("no relative match coming up, so this is a match"); + goto match; + } + + /* bail out if we have no next match. Technically this is an + * error, as the current cd has the DETECT_CONTENT_RELATIVE_NEXT + * flag set. */ + if (sm->next == NULL) { + SCReturnInt(0); + } + + /* see if the next payload keywords match. If not, we will + * search for another occurence of this http header content and + * see if the others match then until we run out of matches */ + int r = DoInspectHttpStatMsg(de_ctx, det_ctx, s, sm->next, + payload, payload_len); + if (r == 1) { + SCReturnInt(1); + } + + if (det_ctx->discontinue_matching) + SCReturnInt(0); + + /* set the previous match offset to the start of this match + 1 */ + prev_offset = (match_offset - (cd->content_len - 1)); + SCLogDebug("trying to see if there is another match after " + "prev_offset %"PRIu32, prev_offset); + } + + } while(1); + + } else if (sm->type == DETECT_PCRE) { + SCLogDebug("inspecting pcre"); + DetectPcreData *pe = (DetectPcreData *)sm->ctx; + uint32_t prev_payload_offset = det_ctx->payload_offset; + uint32_t prev_offset = 0; + int r = 0; + + det_ctx->pcre_match_start_offset = 0; + do { + r = DetectPcrePayloadMatch(det_ctx, s, sm, NULL, NULL, + payload, payload_len); + + if (r == 0) { + det_ctx->discontinue_matching = 1; + SCReturnInt(0); + } + + if (!(pe->flags & DETECT_PCRE_RELATIVE_NEXT)) { + SCLogDebug("no relative match coming up, so this is a match"); + goto match; + } + + /* save it, in case we need to do a pcre match once again */ + prev_offset = det_ctx->pcre_match_start_offset; + + /* see if the next payload keywords match. If not, we will + * search for another occurence of this pcre and see + * if the others match, until we run out of matches */ + int r = DoInspectHttpStatMsg(de_ctx, det_ctx, s, sm->next, + payload, payload_len); + if (r == 1) { + SCReturnInt(1); + } + + if (det_ctx->discontinue_matching) + SCReturnInt(0); + + det_ctx->payload_offset = prev_payload_offset; + det_ctx->pcre_match_start_offset = prev_offset; + } while (1); + + } else if (sm->type == DETECT_ISDATAAT) { + SCLogDebug("inspecting isdataat"); + + DetectIsdataatData *id = (DetectIsdataatData *)sm->ctx; + if (id->flags & ISDATAAT_RELATIVE) { + if (det_ctx->payload_offset + id->dataat > payload_len) { + SCLogDebug("det_ctx->payload_offset + id->dataat %"PRIu32" > %"PRIu32, det_ctx->payload_offset + id->dataat, payload_len); + if (id->flags & ISDATAAT_NEGATED) + goto match; + SCReturnInt(0); + } else { + SCLogDebug("relative isdataat match"); + if (id->flags & ISDATAAT_NEGATED) + SCReturnInt(0); + goto match; + } + } else { + if (id->dataat < payload_len) { + SCLogDebug("absolute isdataat match"); + if (id->flags & ISDATAAT_NEGATED) + SCReturnInt(0); + goto match; + } else { + SCLogDebug("absolute isdataat mismatch, id->isdataat %"PRIu32", payload_len %"PRIu32"", id->dataat,payload_len); + if (id->flags & ISDATAAT_NEGATED) + goto match; + SCReturnInt(0); + } + } + } else { + /* we should never get here, but bail out just in case */ + SCLogDebug("sm->type %u", sm->type); +#ifdef DEBUG + BUG_ON(1); +#endif + } + + SCReturnInt(0); + +match: + /* this sigmatch matched, inspect the next one. If it was the last, + * the payload portion of the signature matched. */ + if (sm->next != NULL) { + int r = DoInspectHttpStatMsg(de_ctx, det_ctx, s, sm->next, payload, + payload_len); + SCReturnInt(r); + } else { + SCReturnInt(1); + } +} + +/** + * \brief Run the mpm against http stat msg. + * + * \retval cnt Number of matches reported by the mpm algo. + */ +int DetectEngineRunHttpStatMsgMpm(DetectEngineThreadCtx *det_ctx, Flow *f, + HtpState *htp_state) +{ + SCEnter(); + + uint32_t cnt = 0; + + if (htp_state == NULL) { + SCLogDebug("no HTTP state"); + SCReturnInt(0); + } + + /* locking the flow, we will inspect the htp state */ + SCMutexLock(&f->m); + + if (htp_state->connp == NULL || htp_state->connp->conn == NULL) { + SCLogDebug("HTP state has no conn(p)"); + goto end; + } + + int idx = AppLayerTransactionGetInspectId(f); + if (idx == -1) { + goto end; + } + htp_tx_t *tx = NULL; + + 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 || tx->response_message == NULL) + continue; + + cnt += HttpStatMsgPatternSearch(det_ctx, + (uint8_t *)bstr_ptr(tx->response_message), + bstr_len(tx->response_message)); + } + +end: + SCMutexUnlock(&f->m); + SCReturnInt(cnt); +} + +/** + * \brief Do the http_stat_msg 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 DetectEngineInspectHttpStatMsg(DetectEngineCtx *de_ctx, + DetectEngineThreadCtx *det_ctx, + Signature *s, Flow *f, uint8_t flags, + void *alstate) +{ + SCEnter(); + + int r = 0; + + HtpState *htp_state = (HtpState *)alstate; + if (htp_state == NULL) { + SCLogDebug("no HTTP state"); + SCReturnInt(0); + } + + /* locking the flow, we will inspect the htp state */ + SCMutexLock(&f->m); + + if (htp_state->connp == NULL || htp_state->connp->conn == NULL) { + SCLogDebug("HTP state has no conn(p)"); + goto end; + } + +#ifdef DEBUG + SigMatch *sm = s->sm_lists[DETECT_SM_LIST_HSMDMATCH]; + DetectContentData *co = (DetectContentData *)sm->ctx; + SCLogDebug("co->id %"PRIu32, co->id); +#endif + + int idx = AppLayerTransactionGetInspectId(f); + if (idx == -1) { + goto end; + } + + htp_tx_t *tx = NULL; + + 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 || tx->response_message == NULL) + continue; + + det_ctx->discontinue_matching = 0; + det_ctx->payload_offset = 0; + det_ctx->inspection_recursion_counter = 0; + + r = DoInspectHttpStatMsg(de_ctx, det_ctx, s, + s->sm_lists[DETECT_SM_LIST_HSMDMATCH], + (uint8_t *)bstr_ptr(tx->response_message), + bstr_len(tx->response_message)); + if (r == 1) { + goto end; + } + } + +end: + SCMutexUnlock(&f->m); + SCReturnInt(r); +} + +/***********************************Unittests**********************************/ + +#ifdef UNITTESTS + +static int DetectEngineHttpStatMsgTest01(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 http_buf1[] = + "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; + uint32_t http_len1 = sizeof(http_buf1) - 1; + uint8_t http_buf2[] = + "HTTP/1.0 200 message\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 7\r\n" + "\r\n" + "message"; + uint32_t http_len2 = sizeof(http_buf2) - 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_TOCLIENT; + 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 stat msg test\"; " + "content:\"message\"; http_stat_msg; " + "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_buf1, http_len1); + 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 matched but shouldn't have\n"); + goto end; + } + + r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + 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; +} + +static int DetectEngineHttpStatMsgTest02(void) +{ + TcpSession ssn; + Packet *p1 = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http_buf1[] = + "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; + uint32_t http_len1 = sizeof(http_buf1) - 1; + uint8_t http_buf2[] = + "HTTP/1.0 200 xxxxABC\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 7\r\n" + "\r\n" + "xxxxABC"; + uint32_t http_len2 = sizeof(http_buf2) - 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); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.flags |= FLOW_IPV4; + + p1->flow = &f; + p1->flowflags |= FLOW_PKT_TOCLIENT; + p1->flowflags |= FLOW_PKT_ESTABLISHED; + p1->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 stat msg test\"; " + "content:\"ABC\"; http_stat_msg; offset:4; " + "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_buf1, http_len1); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + goto end; + } + + r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + 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; + } + + 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); + return result; +} + +static int DetectEngineHttpStatMsgTest03(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; + int result = 0; + uint8_t http_buf1[] = + "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; + uint32_t http_len1 = sizeof(http_buf1) - 1; + uint8_t http_buf2[] = + "HTTP/1.0 200 1234567"; + uint32_t http_len2 = sizeof(http_buf2) - 1; + uint8_t http_buf3[] = + "8901234ABC\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 17\r\n" + "\r\n" + "12345678901234ABC"; + uint32_t http_len3 = sizeof(http_buf3) - 1; + + 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_TOCLIENT; + 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 stat msg test\"; " + "content:\"ABC\"; http_stat_msg; offset:14; " + "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_buf1, http_len1); + 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 matched but shouldn't have\n"); + goto end; + } + + r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); + result = 0; + goto end; + } + + r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf3, http_len3); + 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; +} + +static int DetectEngineHttpStatMsgTest04(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 http_buf1[] = + "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; + uint32_t http_len1 = sizeof(http_buf1) - 1; + uint8_t http_buf2[] = + "HTTP/1.0 200 abcdef\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 6\r\n" + "\r\n" + "abcdef"; + uint32_t http_len2 = sizeof(http_buf2) - 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_TOCLIENT; + 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 stat msg test\"; " + "content:!\"abc\"; http_stat_msg; offset:3; " + "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_buf1, http_len1); + 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 matched but shouldn't have: "); + goto end; + } + + r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + 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; +} + +static int DetectEngineHttpStatMsgTest05(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 http_buf1[] = + "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; + uint32_t http_len1 = sizeof(http_buf1) - 1; + uint8_t http_buf2[] = + "HTTP/1.0 200 abcdef\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 6\r\n" + "\r\n" + "abcdef"; + uint32_t http_len2 = sizeof(http_buf2) - 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_TOCLIENT; + 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 stat msg test\"; " + "content:\"abc\"; http_stat_msg; depth:3; " + "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_buf1, http_len1); + 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 matched but shouldn't have: "); + goto end; + } + + r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + 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; +} + +static int DetectEngineHttpStatMsgTest06(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 http_buf1[] = + "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; + uint32_t http_len1 = sizeof(http_buf1) - 1; + uint8_t http_buf2[] = + "HTTP/1.0 200 abcdef\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 6\r\n" + "\r\n" + "abcdef"; + uint32_t http_len2 = sizeof(http_buf2) - 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_TOCLIENT; + 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 stat msg test\"; " + "content:!\"def\"; http_stat_msg; depth:3; " + "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_buf1, http_len1); + 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 matched but shouldn't have: "); + goto end; + } + + r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + 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; +} + +static int DetectEngineHttpStatMsgTest07(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 http_buf1[] = + "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; + uint32_t http_len1 = sizeof(http_buf1) - 1; + uint8_t http_buf2[] = + "HTTP/1.0 200 abcdef\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 6\r\n" + "\r\n" + "abcdef"; + uint32_t http_len2 = sizeof(http_buf2) - 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_TOCLIENT; + 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 stat msg test\"; " + "content:!\"def\"; http_stat_msg; offset:3; " + "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_buf1, http_len1); + 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 matched but shouldn't have: "); + goto end; + } + + r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + 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 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(&p1, 1); + UTHFreePackets(&p2, 1); + return result; +} + +static int DetectEngineHttpStatMsgTest08(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 http_buf1[] = + "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; + uint32_t http_len1 = sizeof(http_buf1) - 1; + uint8_t http_buf2[] = + "HTTP/1.0 200 abcdef\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 6\r\n" + "\r\n" + "abcdef"; + uint32_t http_len2 = sizeof(http_buf2) - 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_TOCLIENT; + 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 stat msg test\"; " + "content:!\"abc\"; http_stat_msg; depth:3; " + "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_buf1, http_len1); + 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 matched but shouldn't have: "); + goto end; + } + + r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + 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 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(&p1, 1); + UTHFreePackets(&p2, 1); + return result; +} + +static int DetectEngineHttpStatMsgTest09(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 http_buf1[] = + "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; + uint32_t http_len1 = sizeof(http_buf1) - 1; + uint8_t http_buf2[] = + "HTTP/1.0 200 abcdef\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 6\r\n" + "\r\n" + "abcdef"; + uint32_t http_len2 = sizeof(http_buf2) - 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_TOCLIENT; + 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 stat msg test\"; " + "content:\"abc\"; http_stat_msg; depth:3; " + "content:\"def\"; http_stat_msg; within:3; " + "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_buf1, http_len1); + 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 matched but shouldn't have: "); + goto end; + } + + r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + 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; +} + +static int DetectEngineHttpStatMsgTest10(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 http_buf1[] = + "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; + uint32_t http_len1 = sizeof(http_buf1) - 1; + uint8_t http_buf2[] = + "HTTP/1.0 200 abcdef\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 6\r\n" + "\r\n" + "abcdef"; + uint32_t http_len2 = sizeof(http_buf2) - 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_TOCLIENT; + 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 stat msg test\"; " + "content:\"abc\"; http_stat_msg; depth:3; " + "content:!\"xyz\"; http_stat_msg; within:3; " + "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_buf1, http_len1); + 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 matched but shouldn't have: "); + goto end; + } + + r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + 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; +} + +static int DetectEngineHttpStatMsgTest11(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 http_buf1[] = + "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; + uint32_t http_len1 = sizeof(http_buf1) - 1; + uint8_t http_buf2[] = + "HTTP/1.0 200 abcdef\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 6\r\n" + "\r\n" + "abcdef"; + uint32_t http_len2 = sizeof(http_buf2) - 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_TOCLIENT; + 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 stat msg test\"; " + "content:\"abc\"; http_stat_msg; depth:3; " + "content:\"xyz\"; http_stat_msg; within:3; " + "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_buf1, http_len1); + 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 matched but shouldn't have: "); + goto end; + } + + r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + 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 did match but should not 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; +} + +static int DetectEngineHttpStatMsgTest12(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 http_buf1[] = + "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; + uint32_t http_len1 = sizeof(http_buf1) - 1; + uint8_t http_buf2[] = + "HTTP/1.0 200 abcdef\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 6\r\n" + "\r\n" + "abcdef"; + uint32_t http_len2 = sizeof(http_buf2) - 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_TOCLIENT; + 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 stat msg test\"; " + "content:\"ab\"; http_stat_msg; depth:2; " + "content:\"ef\"; http_stat_msg; distance:2; " + "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_buf1, http_len1); + 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 matched but shouldn't have: "); + goto end; + } + + r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + 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 did not 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; +} + +static int DetectEngineHttpStatMsgTest13(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 http_buf1[] = + "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; + uint32_t http_len1 = sizeof(http_buf1) - 1; + uint8_t http_buf2[] = + "HTTP/1.0 200 abcdef\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 6\r\n" + "\r\n" + "abcdef"; + uint32_t http_len2 = sizeof(http_buf2) - 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_TOCLIENT; + 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 stat msg test\"; " + "content:\"ab\"; http_stat_msg; depth:3; " + "content:!\"yz\"; http_stat_msg; distance:2; " + "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_buf1, http_len1); + 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 matched but shouldn't have: "); + goto end; + } + + r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + 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 did not 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; +} + +static int DetectEngineHttpStatMsgTest14(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 http_buf1[] = + "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; + uint32_t http_len1 = sizeof(http_buf1) - 1; + uint8_t http_buf2[] = + "HTTP/1.0 200 abcdef\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 6\r\n" + "\r\n" + "abcdef"; + uint32_t http_len2 = sizeof(http_buf2) - 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_TOCLIENT; + 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 stat msg test\"; " + "pcre:/ab/Y; " + "content:\"ef\"; http_stat_msg; distance:2; " + "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_buf1, http_len1); + 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 matched but shouldn't have: "); + goto end; + } + + r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + 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 did not 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; +} + +static int DetectEngineHttpStatMsgTest15(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 http_buf1[] = + "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; + uint32_t http_len1 = sizeof(http_buf1) - 1; + uint8_t http_buf2[] = + "HTTP/1.0 200 abcdef\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 6\r\n" + "\r\n" + "abcdef"; + uint32_t http_len2 = sizeof(http_buf2) - 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_TOCLIENT; + 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 stat msg test\"; " + "pcre:/abc/Y; " + "content:!\"xyz\"; http_stat_msg; distance:0; within:3; " + "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_buf1, http_len1); + 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 matched but shouldn't have: "); + goto end; + } + + r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + 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 did not 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; +} + +#endif /* UNITTESTS */ + +void DetectEngineHttpStatMsgRegisterTests(void) +{ + +#ifdef UNITTESTS + UtRegisterTest("DetectEngineHttpStatMsgTest01", + DetectEngineHttpStatMsgTest01, 1); + UtRegisterTest("DetectEngineHttpStatMsgTest02", + DetectEngineHttpStatMsgTest02, 1); + UtRegisterTest("DetectEngineHttpStatMsgTest03", + DetectEngineHttpStatMsgTest03, 1); + UtRegisterTest("DetectEngineHttpStatMsgTest04", + DetectEngineHttpStatMsgTest04, 1); + UtRegisterTest("DetectEngineHttpStatMsgTest05", + DetectEngineHttpStatMsgTest05, 1); + UtRegisterTest("DetectEngineHttpStatMsgTest06", + DetectEngineHttpStatMsgTest06, 1); + UtRegisterTest("DetectEngineHttpStatMsgTest07", + DetectEngineHttpStatMsgTest07, 1); + UtRegisterTest("DetectEngineHttpStatMsgTest08", + DetectEngineHttpStatMsgTest08, 1); + UtRegisterTest("DetectEngineHttpStatMsgTest09", + DetectEngineHttpStatMsgTest09, 1); + UtRegisterTest("DetectEngineHttpStatMsgTest10", + DetectEngineHttpStatMsgTest10, 1); + UtRegisterTest("DetectEngineHttpStatMsgTest11", + DetectEngineHttpStatMsgTest11, 1); + UtRegisterTest("DetectEngineHttpStatMsgTest12", + DetectEngineHttpStatMsgTest12, 1); + UtRegisterTest("DetectEngineHttpStatMsgTest13", + DetectEngineHttpStatMsgTest13, 1); + UtRegisterTest("DetectEngineHttpStatMsgTest14", + DetectEngineHttpStatMsgTest14, 1); + UtRegisterTest("DetectEngineHttpStatMsgTest15", + DetectEngineHttpStatMsgTest15, 1); +#endif /* UNITTESTS */ + + return; +} + +/** + * @} + */ diff --git a/src/detect-engine-hsmd.h b/src/detect-engine-hsmd.h new file mode 100644 index 0000000000..90ac871753 --- /dev/null +++ b/src/detect-engine-hsmd.h @@ -0,0 +1,34 @@ +/* Copyright (C) 2007-2010 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** \file + * + * \author Anoop Saldanha + */ + +#ifndef __DETECT_ENGINE_HSMD_H__ +#define __DETECT_ENGINE_HSMD_H__ + +#include "app-layer-htp.h" + +int DetectEngineRunHttpStatMsgMpm(DetectEngineThreadCtx *, + Flow *f, HtpState *); +int DetectEngineInspectHttpStatMsg(DetectEngineCtx *, DetectEngineThreadCtx *, + Signature *, Flow *, uint8_t, void *); +void DetectEngineHttpStatMsgRegisterTests(void); + +#endif /* __DETECT_ENGINE_HSMD_H__ */ diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index 04c2441247..1dfdccdac9 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -524,6 +524,31 @@ uint32_t HttpRawUriPatternSearch(DetectEngineThreadCtx *det_ctx, SCReturnUInt(ret); } +/** + * \brief Http stat msg match -- searches for one pattern per signature. + * + * \param det_ctx Detection engine thread ctx. + * \param uri Stat msg to inspect. + * \param uri_len Stat msg length. + * + * \retval ret Number of matches. + */ +uint32_t HttpStatMsgPatternSearch(DetectEngineThreadCtx *det_ctx, + uint8_t *stat_msg, uint32_t stat_msg_len) +{ + SCEnter(); + + if (det_ctx->sgh->mpm_hsmd_ctx == NULL) + SCReturnUInt(0); + + uint32_t ret; + ret = mpm_table[det_ctx->sgh->mpm_hsmd_ctx->mpm_type]. + Search(det_ctx->sgh->mpm_hsmd_ctx, &det_ctx->mtcu, + &det_ctx->pmq, stat_msg, stat_msg_len); + + SCReturnUInt(ret); +} + /** \brief Pattern match -- searches for only one pattern per signature. * * \param det_ctx detection engine thread ctx @@ -1180,6 +1205,7 @@ static void PopulateMpmAddPatternToMpm(DetectEngineCtx *de_ctx, case DETECT_AL_HTTP_RAW_HEADER: case DETECT_AL_HTTP_METHOD: case DETECT_AL_HTTP_COOKIE: + case DETECT_AL_HTTP_STAT_MSG: { MpmCtx *mpm_ctx_ts = NULL; MpmCtx *mpm_ctx_tc = NULL; @@ -1242,6 +1268,10 @@ static void PopulateMpmAddPatternToMpm(DetectEngineCtx *de_ctx, mpm_ctx_tc = sgh->mpm_hrud_ctx_tc; sgh_flags = SIG_GROUP_HEAD_MPM_HRUD; cd_flags = DETECT_CONTENT_HRUD_MPM; + } else if (mpm_sm->type == DETECT_AL_HTTP_STAT_MSG) { + mpm_ctx = sgh->mpm_hsmd_ctx; + sgh_flags = SIG_GROUP_HEAD_MPM_HSMD; + cd_flags = DETECT_CONTENT_HSMD_MPM; } cd = (DetectContentData *)mpm_sm->ctx; @@ -1534,6 +1564,8 @@ int PatternMatchPrepareGroup(DetectEngineCtx *de_ctx, SigGroupHead *sh) uint32_t has_co_hcd = 0; /* used to indicate if sgh has atleast one sig with http_raw_uri */ uint32_t has_co_hrud = 0; + /* used to indicate if sgh has atleast one sig with http_stat_msg */ + uint32_t has_co_hsmd = 0; //uint32_t cnt = 0; uint32_t sig = 0; @@ -1583,6 +1615,10 @@ int PatternMatchPrepareGroup(DetectEngineCtx *de_ctx, SigGroupHead *sh) if (s->sm_lists[DETECT_SM_LIST_HRUDMATCH] != NULL) { has_co_hrud = 1; } + + if (s->sm_lists[DETECT_SM_LIST_HSMDMATCH] != NULL) { + has_co_hsmd = 1; + } } if (has_co_packet > 0) { @@ -1615,6 +1651,9 @@ int PatternMatchPrepareGroup(DetectEngineCtx *de_ctx, SigGroupHead *sh) if (has_co_hrud > 0) { sh->flags |= SIG_GROUP_HAVEHRUDCONTENT; } + if (has_co_hsmd > 0) { + sh->flags |= SIG_GROUP_HAVEHSMDCONTENT; + } /* intialize contexes */ if (sh->flags & SIG_GROUP_HAVECONTENT) { @@ -1872,6 +1911,24 @@ int PatternMatchPrepareGroup(DetectEngineCtx *de_ctx, SigGroupHead *sh) #endif } + if (sh->flags & SIG_GROUP_HAVEHSMDCONTENT) { + if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE) { + sh->mpm_hsmd_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx->sgh_mpm_context_hsmd); + } else { + sh->mpm_hsmd_ctx = MpmFactoryGetMpmCtxForProfile(MPM_CTX_FACTORY_UNIQUE_CONTEXT); + } + if (sh->mpm_hsmd_ctx == NULL) { + SCLogDebug("sh->mpm_hsmd_ctx == NULL. This should never happen"); + exit(EXIT_FAILURE); + } + +#ifndef __SC_CUDA_SUPPORT__ + MpmInitCtx(sh->mpm_hsmd_ctx, de_ctx->mpm_matcher, -1); +#else + MpmInitCtx(sh->mpm_hsmd_ctx, 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 || @@ -1881,6 +1938,7 @@ int PatternMatchPrepareGroup(DetectEngineCtx *de_ctx, SigGroupHead *sh) sh->flags & SIG_GROUP_HAVEHRHDCONTENT || sh->flags & SIG_GROUP_HAVEHMDCONTENT || sh->flags & SIG_GROUP_HAVEHCDCONTENT || + sh->flags & SIG_GROUP_HAVEHSMDCONTENT || sh->flags & SIG_GROUP_HAVEHRUDCONTENT) { PatternMatchPreparePopulateMpm(de_ctx, sh); @@ -2183,6 +2241,18 @@ int PatternMatchPrepareGroup(DetectEngineCtx *de_ctx, SigGroupHead *sh) } } } + if (sh->mpm_hsmd_ctx != NULL) { + if (sh->mpm_hsmd_ctx->pattern_cnt == 0) { + MpmFactoryReClaimMpmCtx(sh->mpm_hsmd_ctx); + sh->mpm_hsmd_ctx = NULL; + } else { + if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL && + sh->flags & SIG_GROUP_HAVEHSMDCONTENT) { + if (mpm_table[sh->mpm_hsmd_ctx->mpm_type].Prepare != NULL) + mpm_table[sh->mpm_hsmd_ctx->mpm_type].Prepare(sh->mpm_hsmd_ctx); + } + } + } //} /* if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) */ } else { MpmFactoryReClaimMpmCtx(sh->mpm_proto_other_ctx); @@ -2208,6 +2278,8 @@ int PatternMatchPrepareGroup(DetectEngineCtx *de_ctx, SigGroupHead *sh) sh->mpm_hcd_ctx_ts = NULL; MpmFactoryReClaimMpmCtx(sh->mpm_hrud_ctx_ts); sh->mpm_hrud_ctx_ts = NULL; + MpmFactoryReClaimMpmCtx(sh->mpm_hsmd_ctx_ts); + sh->mpm_hsmd_ctx_ts = NULL; MpmFactoryReClaimMpmCtx(sh->mpm_proto_tcp_ctx_tc); sh->mpm_proto_tcp_ctx_tc = NULL; @@ -2229,6 +2301,8 @@ int PatternMatchPrepareGroup(DetectEngineCtx *de_ctx, SigGroupHead *sh) sh->mpm_hcd_ctx_tc = NULL; MpmFactoryReClaimMpmCtx(sh->mpm_hrud_ctx_tc); sh->mpm_hrud_ctx_tc = NULL; + MpmFactoryReClaimMpmCtx(sh->mpm_hsmd_ctx_tc); + sh->mpm_hsmd_ctx_tc = NULL; } return 0; diff --git a/src/detect-engine-mpm.h b/src/detect-engine-mpm.h index d0c3a7dad3..1519943788 100644 --- a/src/detect-engine-mpm.h +++ b/src/detect-engine-mpm.h @@ -45,6 +45,7 @@ uint32_t HttpRawHeaderPatternSearch(DetectEngineThreadCtx *, uint8_t *, uint32_t uint32_t HttpMethodPatternSearch(DetectEngineThreadCtx *, uint8_t *, uint32_t, uint8_t); uint32_t HttpCookiePatternSearch(DetectEngineThreadCtx *, uint8_t *, uint32_t, uint8_t); uint32_t HttpRawUriPatternSearch(DetectEngineThreadCtx *, uint8_t *, uint32_t, uint8_t); +uint32_t HttpStatMsgPatternSearch(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 2c1cdaaae3..96ba0acb91 100644 --- a/src/detect-engine-state.c +++ b/src/detect-engine-state.c @@ -64,6 +64,7 @@ #include "detect-engine-hmd.h" #include "detect-engine-hcd.h" #include "detect-engine-hrud.h" +#include "detect-engine-hsmd.h" #include "detect-engine-dcepayload.h" #include "detect-engine-file.h" @@ -493,6 +494,10 @@ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, SCLogDebug("skipping file inspection as we're not yet done with the other inspection"); } } + /* not inspecting in toserver direction */ + if (s->sm_lists[DETECT_SM_LIST_HSMDMATCH] != NULL) { + inspect_flags |= DE_STATE_FLAG_HSMD_INSPECT; + } } 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 @@ -562,6 +567,14 @@ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, SCLogDebug("skipping file inspection as we're not yet done with the other inspection"); } } + if (s->sm_lists[DETECT_SM_LIST_HSMDMATCH] != NULL) { + inspect_flags |= DE_STATE_FLAG_HSMD_INSPECT; + if (DetectEngineInspectHttpStatMsg(de_ctx, det_ctx, s, f, + flags, alstate) == 1) { + match_flags |= DE_STATE_FLAG_HSMD_MATCH; + } + SCLogDebug("inspecting http stat msg"); + } } } else if (alproto == ALPROTO_DCERPC || alproto == ALPROTO_SMB || alproto == ALPROTO_SMB2) { if (s->sm_lists[DETECT_SM_LIST_DMATCH] != NULL) { @@ -885,6 +898,12 @@ int DeStateDetectContinueDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, Dete } } } + /* not inspecting in toserver direction */ + if (s->sm_lists[DETECT_SM_LIST_HSMDMATCH] != NULL) { + if (!(item->flags & DE_STATE_FLAG_HSMD_MATCH)) { + inspect_flags |= DE_STATE_FLAG_HSMD_INSPECT; + } + } } 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 @@ -973,6 +992,18 @@ int DeStateDetectContinueDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, Dete } } } + if (s->sm_lists[DETECT_SM_LIST_HSMDMATCH] != NULL) { + if (!(item->flags & DE_STATE_FLAG_HSMD_MATCH)) { + SCLogDebug("inspecting http stat msg data"); + inspect_flags |= DE_STATE_FLAG_HSMD_INSPECT; + + if (DetectEngineInspectHttpStatMsg(de_ctx, det_ctx, s, f, + flags, alstate) == 1) { + SCLogDebug("http stat msg matched"); + match_flags |= DE_STATE_FLAG_HSMD_MATCH; + } + } + } } 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 789336b02f..7620bddd6c 100644 --- a/src/detect-engine-state.h +++ b/src/detect-engine-state.h @@ -65,6 +65,7 @@ #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_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 */ @@ -77,6 +78,7 @@ #define DE_STATE_FLAG_HRUD_INSPECT DE_STATE_FLAG_HRUD_MATCH /**< hrud payload inspection part inspected */ #define DE_STATE_FLAG_FILE_TC_INSPECT DE_STATE_FLAG_FILE_TC_MATCH #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 */ /* state flags */ #define DE_STATE_FILE_STORE_DISABLED 0x0001 diff --git a/src/detect-fast-pattern.c b/src/detect-fast-pattern.c index 7d7286fbde..40791910a7 100644 --- a/src/detect-fast-pattern.c +++ b/src/detect-fast-pattern.c @@ -146,6 +146,9 @@ void SupportFastPatternForSigMatchTypes(void) SupportFastPatternForSigMatchType(DETECT_AL_HTTP_RAW_URI); SupportFastPatternForSigMatchList(DETECT_SM_LIST_HRUDMATCH); + SupportFastPatternForSigMatchType(DETECT_AL_HTTP_STAT_MSG); + SupportFastPatternForSigMatchList(DETECT_SM_LIST_HSMDMATCH); + return; } @@ -218,17 +221,18 @@ static int DetectFastPatternSetup(DetectEngineCtx *de_ctx, Signature *s, char *a s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH] == NULL && s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH] == NULL && 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_HRUDMATCH] == NULL && + s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH] == 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 or " - "http_raw_uri option"); + "http_raw_header, http_method, http_cookie, " + "http_raw_uri or http_stat_msg option"); return -1; } - SigMatch *pm = SigMatchGetLastSMFromLists(s, 18, + SigMatch *pm = SigMatchGetLastSMFromLists(s, 20, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], DETECT_URICONTENT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], DETECT_AL_HTTP_CLIENT_BODY, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], @@ -237,6 +241,7 @@ static int DetectFastPatternSetup(DetectEngineCtx *de_ctx, Signature *s, char *a DETECT_AL_HTTP_RAW_HEADER, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], DETECT_AL_HTTP_METHOD, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], DETECT_AL_HTTP_COOKIE, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], + DETECT_AL_HTTP_STAT_MSG, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], DETECT_AL_HTTP_RAW_URI, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]); if (pm == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "fast_pattern found inside " @@ -11052,6 +11057,1188 @@ int DetectFastPatternTest383(void) return result; } + + + + + + + + + + + + + + + + + + + +int DetectFastPatternTest384(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_stat_msg; " + "content:!\"oneonetwo\"; fast_pattern:3,4; http_stat_msg; " + "content:\"three\"; http_stat_msg; sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]->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 DetectFastPatternTest385(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_stat_msg; " + "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_HSMDMATCH]; + 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 DetectFastPatternTest386(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_stat_msg; " + "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_HSMDMATCH]; + 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 DetectFastPatternTest387(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_stat_msg; sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + result = 0; + sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSMDMATCH]; + DetectContentData *ud = sm->ctx; + if (sm != NULL) { + 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 DetectFastPatternTest388(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_stat_msg; sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + result = 0; + sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSMDMATCH]; + DetectContentData *ud = sm->ctx; + if (sm != NULL) { + 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 DetectFastPatternTest389(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_stat_msg; " + "content:\"two\"; fast_pattern:only; http_stat_msg; distance:10; sid:1;)"); + if (de_ctx->sig_list != NULL) + goto end; + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest390(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_stat_msg; " + "content:\"two\"; distance:10; fast_pattern:only; http_stat_msg; sid:1;)"); + if (de_ctx->sig_list != NULL) + goto end; + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest391(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_stat_msg; " + "content:\"two\"; fast_pattern:only; http_stat_msg; within:10; sid:1;)"); + if (de_ctx->sig_list != NULL) + goto end; + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest392(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_stat_msg; " + "content:\"two\"; within:10; fast_pattern:only; http_stat_msg; sid:1;)"); + if (de_ctx->sig_list != NULL) + goto end; + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest393(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_stat_msg; " + "content:\"two\"; fast_pattern:only; http_stat_msg; offset:10; sid:1;)"); + if (de_ctx->sig_list != NULL) + goto end; + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest394(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_stat_msg; " + "content:\"two\"; offset:10; fast_pattern:only; http_stat_msg; sid:1;)"); + if (de_ctx->sig_list != NULL) + goto end; + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest395(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_stat_msg; " + "content:\"two\"; fast_pattern:only; http_stat_msg; depth:10; sid:1;)"); + if (de_ctx->sig_list != NULL) + goto end; + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest396(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_stat_msg; " + "content:\"two\"; depth:10; fast_pattern:only; http_stat_msg; sid:1;)"); + if (de_ctx->sig_list != NULL) + goto end; + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest397(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_stat_msg; " + "content:!\"two\"; fast_pattern:only; http_stat_msg; sid:1;)"); + if (de_ctx->sig_list != NULL) + goto end; + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest398(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_stat_msg; " + "content:\"two\"; http_stat_msg; distance:30; " + "content:\"two\"; fast_pattern:only; http_stat_msg; sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]->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 DetectFastPatternTest399(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_stat_msg; " + "content:\"two\"; http_stat_msg; within:30; " + "content:\"two\"; fast_pattern:only; http_stat_msg; sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]->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 DetectFastPatternTest400(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_stat_msg; " + "content:\"two\"; http_stat_msg; offset:30; " + "content:\"two\"; fast_pattern:only; http_stat_msg; sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]->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 DetectFastPatternTest401(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_stat_msg; " + "content:\"two\"; http_stat_msg; depth:30; " + "content:\"two\"; fast_pattern:only; http_stat_msg; sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]->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 DetectFastPatternTest402(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_stat_msg; " + "content:\"two\"; http_stat_msg; sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]->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 DetectFastPatternTest403(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_stat_msg; " + "content:!\"one\"; fast_pattern; http_stat_msg; distance:20; sid:1;)"); + if (de_ctx->sig_list != NULL) + goto end; + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest404(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_stat_msg; " + "content:!\"one\"; fast_pattern; http_stat_msg; within:20; sid:1;)"); + if (de_ctx->sig_list != NULL) + goto end; + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest405(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_stat_msg; " + "content:!\"one\"; fast_pattern; http_stat_msg; offset:20; sid:1;)"); + if (de_ctx->sig_list != NULL) + goto end; + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest406(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_stat_msg; " + "content:!\"one\"; fast_pattern; http_stat_msg; depth:20; sid:1;)"); + if (de_ctx->sig_list != NULL) + goto end; + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest407(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_stat_msg; " + "content:\"oneonetwo\"; fast_pattern:3,4; http_stat_msg; " + "content:\"three\"; http_stat_msg; sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]->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 DetectFastPatternTest408(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_stat_msg; " + "content:\"oneonetwo\"; fast_pattern:3,4; http_stat_msg; " + "content:\"three\"; http_stat_msg; distance:30; sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]->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 DetectFastPatternTest409(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_stat_msg; " + "content:\"oneonetwo\"; fast_pattern:3,4; http_stat_msg; " + "content:\"three\"; http_stat_msg; within:30; sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]->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 DetectFastPatternTest410(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_stat_msg; " + "content:\"oneonetwo\"; fast_pattern:3,4; http_stat_msg; " + "content:\"three\"; http_stat_msg; offset:30; sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]->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 DetectFastPatternTest411(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_stat_msg; " + "content:\"oneonetwo\"; fast_pattern:3,4; http_stat_msg; " + "content:\"three\"; http_stat_msg; depth:30; sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]->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 DetectFastPatternTest412(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_stat_msg; " + "content:\"two\"; http_stat_msg; distance:10; " + "content:\"oneonethree\"; fast_pattern:3,4; http_stat_msg; sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]->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 DetectFastPatternTest413(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_stat_msg; " + "content:\"two\"; http_stat_msg; within:10; " + "content:\"oneonethree\"; fast_pattern:3,4; http_stat_msg; sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]->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 DetectFastPatternTest414(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_stat_msg; " + "content:\"two\"; http_stat_msg; offset:10; " + "content:\"oneonethree\"; fast_pattern:3,4; http_stat_msg; sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]->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 DetectFastPatternTest415(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_stat_msg; " + "content:\"two\"; http_stat_msg; depth:10; " + "content:\"oneonethree\"; fast_pattern:3,4; http_stat_msg; sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]->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 DetectFastPatternTest416(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_stat_msg; " + "content:\"two\"; fast_pattern:65977,4; http_stat_msg; " + "content:\"three\"; http_stat_msg; distance:10; sid:1;)"); + if (de_ctx->sig_list != NULL) + goto end; + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest417(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_stat_msg; " + "content:\"oneonetwo\"; fast_pattern:3,65977; http_stat_msg; " + "content:\"three\"; distance:10; http_stat_msg; sid:1;)"); + if (de_ctx->sig_list != NULL) + goto end; + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest418(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_stat_msg; " + "content:\"two\"; fast_pattern:65534,4; http_stat_msg; " + "content:\"three\"; http_stat_msg; distance:10; sid:1;)"); + if (de_ctx->sig_list != NULL) + goto end; + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest419(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_stat_msg; " + "content:!\"oneonetwo\"; fast_pattern:3,4; http_stat_msg; " + "content:\"three\"; http_stat_msg; sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]->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 DetectFastPatternTest420(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_stat_msg; " + "content:!\"oneonetwo\"; fast_pattern:3,4; http_stat_msg; distance:10; " + "content:\"three\"; http_stat_msg; sid:1;)"); + if (de_ctx->sig_list != NULL) + goto end; + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest421(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_stat_msg; " + "content:!\"oneonetwo\"; fast_pattern:3,4; http_stat_msg; within:10; " + "content:\"three\"; http_stat_msg; sid:1;)"); + if (de_ctx->sig_list != NULL) + goto end; + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest422(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_stat_msg; " + "content:!\"oneonetwo\"; fast_pattern:3,4; http_stat_msg; offset:10; " + "content:\"three\"; http_stat_msg; sid:1;)"); + if (de_ctx->sig_list != NULL) + goto end; + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest423(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_stat_msg; " + "content:!\"oneonetwo\"; fast_pattern:3,4; http_stat_msg; depth:10; " + "content:\"three\"; http_stat_msg; sid:1;)"); + if (de_ctx->sig_list != NULL) + goto end; + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest424(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_stat_msg; " + "content:!\"oneonetwo\"; fast_pattern:3,4; http_stat_msg; " + "content:\"three\"; http_stat_msg; sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]->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) @@ -11459,6 +12646,49 @@ void DetectFastPatternRegisterTests(void) UtRegisterTest("DetectFastPatternTest381", DetectFastPatternTest381, 1); UtRegisterTest("DetectFastPatternTest382", DetectFastPatternTest382, 1); UtRegisterTest("DetectFastPatternTest383", DetectFastPatternTest383, 1); + /* http_raw_uri fast_pattern tests ^ */ + /* http_stat_msg fast_pattern tests v */ + UtRegisterTest("DetectFastPatternTest384", DetectFastPatternTest384, 1); + UtRegisterTest("DetectFastPatternTest385", DetectFastPatternTest385, 1); + UtRegisterTest("DetectFastPatternTest386", DetectFastPatternTest386, 1); + UtRegisterTest("DetectFastPatternTest387", DetectFastPatternTest387, 1); + UtRegisterTest("DetectFastPatternTest388", DetectFastPatternTest388, 1); + UtRegisterTest("DetectFastPatternTest389", DetectFastPatternTest389, 1); + UtRegisterTest("DetectFastPatternTest390", DetectFastPatternTest390, 1); + UtRegisterTest("DetectFastPatternTest391", DetectFastPatternTest391, 1); + UtRegisterTest("DetectFastPatternTest392", DetectFastPatternTest392, 1); + UtRegisterTest("DetectFastPatternTest393", DetectFastPatternTest393, 1); + UtRegisterTest("DetectFastPatternTest394", DetectFastPatternTest394, 1); + UtRegisterTest("DetectFastPatternTest395", DetectFastPatternTest395, 1); + UtRegisterTest("DetectFastPatternTest396", DetectFastPatternTest396, 1); + UtRegisterTest("DetectFastPatternTest397", DetectFastPatternTest397, 1); + UtRegisterTest("DetectFastPatternTest398", DetectFastPatternTest398, 1); + UtRegisterTest("DetectFastPatternTest399", DetectFastPatternTest399, 1); + UtRegisterTest("DetectFastPatternTest400", DetectFastPatternTest400, 1); + UtRegisterTest("DetectFastPatternTest401", DetectFastPatternTest401, 1); + UtRegisterTest("DetectFastPatternTest402", DetectFastPatternTest402, 1); + UtRegisterTest("DetectFastPatternTest403", DetectFastPatternTest403, 1); + UtRegisterTest("DetectFastPatternTest404", DetectFastPatternTest404, 1); + UtRegisterTest("DetectFastPatternTest405", DetectFastPatternTest405, 1); + UtRegisterTest("DetectFastPatternTest406", DetectFastPatternTest406, 1); + UtRegisterTest("DetectFastPatternTest407", DetectFastPatternTest407, 1); + UtRegisterTest("DetectFastPatternTest408", DetectFastPatternTest408, 1); + UtRegisterTest("DetectFastPatternTest409", DetectFastPatternTest409, 1); + UtRegisterTest("DetectFastPatternTest410", DetectFastPatternTest410, 1); + UtRegisterTest("DetectFastPatternTest411", DetectFastPatternTest411, 1); + UtRegisterTest("DetectFastPatternTest412", DetectFastPatternTest412, 1); + UtRegisterTest("DetectFastPatternTest413", DetectFastPatternTest413, 1); + UtRegisterTest("DetectFastPatternTest414", DetectFastPatternTest414, 1); + UtRegisterTest("DetectFastPatternTest415", DetectFastPatternTest415, 1); + UtRegisterTest("DetectFastPatternTest416", DetectFastPatternTest415, 1); + UtRegisterTest("DetectFastPatternTest417", DetectFastPatternTest417, 1); + UtRegisterTest("DetectFastPatternTest418", DetectFastPatternTest418, 1); + UtRegisterTest("DetectFastPatternTest419", DetectFastPatternTest419, 1); + UtRegisterTest("DetectFastPatternTest420", DetectFastPatternTest420, 1); + UtRegisterTest("DetectFastPatternTest421", DetectFastPatternTest421, 1); + UtRegisterTest("DetectFastPatternTest422", DetectFastPatternTest422, 1); + UtRegisterTest("DetectFastPatternTest423", DetectFastPatternTest423, 1); + UtRegisterTest("DetectFastPatternTest424", DetectFastPatternTest424, 1); #endif return; diff --git a/src/detect-http-stat-msg.c b/src/detect-http-stat-msg.c index d4d2e08639..761ec344dd 100644 --- a/src/detect-http-stat-msg.c +++ b/src/detect-http-stat-msg.c @@ -26,6 +26,7 @@ * \file * * \author Gurvinder Singh + * \author Anoop Saldanha * * Implements the http_stat_msg keyword */ @@ -39,6 +40,8 @@ #include "detect-parse.h" #include "detect-engine.h" #include "detect-content.h" +#include "detect-pcre.h" +#include "detect-engine-mpm.h" #include "flow.h" #include "flow-var.h" @@ -72,7 +75,7 @@ void DetectHttpStatMsgFree(void *); void DetectHttpStatMsgRegister (void) { sigmatch_table[DETECT_AL_HTTP_STAT_MSG].name = "http_stat_msg"; sigmatch_table[DETECT_AL_HTTP_STAT_MSG].Match = NULL; - sigmatch_table[DETECT_AL_HTTP_STAT_MSG].AppLayerMatch = DetectHttpStatMsgMatch; + sigmatch_table[DETECT_AL_HTTP_STAT_MSG].AppLayerMatch = NULL; sigmatch_table[DETECT_AL_HTTP_STAT_MSG].alproto = ALPROTO_HTTP; sigmatch_table[DETECT_AL_HTTP_STAT_MSG].Setup = DetectHttpStatMsgSetup; sigmatch_table[DETECT_AL_HTTP_STAT_MSG].Free = DetectHttpStatMsgFree; @@ -96,7 +99,7 @@ void DetectHttpStatMsgRegister (void) { * \retval 0 no match * \retval 1 match */ -int DetectHttpStatMsgMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, +int DetectHttpStatMsgMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, void *state, Signature *s, SigMatch *sm) { @@ -204,92 +207,95 @@ void DetectHttpStatMsgFree(void *ptr) * \retval -1 On failure */ -static int DetectHttpStatMsgSetup (DetectEngineCtx *de_ctx, Signature *s, char *str) +static int DetectHttpStatMsgSetup (DetectEngineCtx *de_ctx, Signature *s, char *arg) { - DetectContentData *hd = NULL; + DetectContentData *cd = NULL; SigMatch *sm = NULL; - /** new sig match to replace previous content */ - SigMatch *nm = NULL; - - if (str != NULL && strcmp(str, "") != 0) { - SCLogError(SC_ERR_INVALID_ARGUMENT, "http_stat_msg shouldn't be supplied" - " with an argument"); + if (arg != NULL && strcmp(arg, "") != 0) { + SCLogError(SC_ERR_INVALID_ARGUMENT, "http_client_body supplied with args"); return -1; } - SigMatch *pm = DetectContentGetLastPattern(s->sm_lists_tail[DETECT_SM_LIST_PMATCH]); - if (pm == NULL) { - SCLogWarning(SC_ERR_INVALID_SIGNATURE, "http_stat_msg found inside " - "the rule, without a content context. Please use a " - "content keyword before using http_stat_msg"); + sm = DetectContentGetLastPattern(s->sm_lists_tail[DETECT_SM_LIST_PMATCH]); + /* if still we are unable to find any content previous keywords, it is an + * invalid rule */ + if (sm == NULL) { + SCLogError(SC_ERR_INVALID_SIGNATURE, "\"http_stat_msg\" keyword " + "found inside the rule without a content context. " + "Please use a \"content\" keyword before using the " + "\"http_stat_msg\" keyword"); return -1; } - /* http_stat_msg should not be used with the fast_pattern rule */ - if (((DetectContentData *)pm->ctx)->flags & DETECT_CONTENT_FAST_PATTERN) { - SCLogWarning(SC_WARN_COMPATIBILITY, "http_stat_msg rule can not " - "be used with the fast_pattern rule keyword. " - "Unsetting fast_pattern on this modifier. Signature ==> %s", - s->sig_str); - ((DetectContentData *)pm->ctx)->flags &= ~DETECT_CONTENT_FAST_PATTERN; + cd = (DetectContentData *)sm->ctx; - /* http_stat_msg should not be used with the rawbytes rule */ - } else if (((DetectContentData *)pm->ctx)->flags & DETECT_CONTENT_RAWBYTES) { + /* http_stat_msg should not be used with the rawbytes rule */ + if (cd->flags & DETECT_CONTENT_RAWBYTES) { SCLogError(SC_ERR_INVALID_SIGNATURE, "http_stat_msg rule can not " - "be used with the rawbytes rule keyword"); + "be used with the rawbytes rule keyword"); return -1; } - nm = SigMatchAlloc(); - if (nm == NULL) { - SCLogError(SC_ERR_MEM_ALLOC, "SigMatchAlloc failed"); + if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_HTTP) { + SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains a non http " + "alproto set"); goto error; } - /* Setup the HttpStatMsg data from Content data structure */ - hd = SCMalloc(sizeof(DetectContentData)); - if (hd == NULL) - goto error; - - memset(hd, 0, sizeof(DetectContentData)); - - /* Setup the http_stat_msg keyword data */ - hd->content_len = ((DetectContentData *)pm->ctx)->content_len; - hd->content = ((DetectContentData *)pm->ctx)->content; - hd->flags |= (((DetectContentData *)pm->ctx)->flags & DETECT_CONTENT_NOCASE) ? - DETECT_CONTENT_NOCASE : 0x00; - hd->flags |= (((DetectContentData *)pm->ctx)->flags & DETECT_CONTENT_NEGATED) ? - DETECT_CONTENT_NEGATED : 0x00; - nm->type = DETECT_AL_HTTP_STAT_MSG; - nm->ctx = (void *)hd; - - /* pull the previous content from the pmatch list, append - * the new match to the match list */ - SigMatchReplaceContent(s, pm, nm); - - /* free the old content sigmatch, the content pattern memory - * is taken over by the new sigmatch */ - BoyerMooreCtxDeInit(((DetectContentData *)pm->ctx)->bm_ctx); - SCFree(pm->ctx); - SCFree(pm); - - /* Flagged the signature as to inspect the app layer data */ - s->flags |= SIG_FLAG_APPLAYER; + 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 (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_HTTP) { - SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting" - " keywords."); - goto error; + } /* if (pm != NULL) */ + + /* reassigning pm */ + pm = SigMatchGetLastSMFromLists(s, 4, + DETECT_AL_HTTP_STAT_MSG, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], + DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]); + if (pm == NULL) { + SCLogError(SC_ERR_INVALID_SIGNATURE, "http_stat_msg seen with a " + "distance or within without a previous http_stat_msg " + "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_AL_HTTP_STAT_MSG); + sm->type = DETECT_AL_HTTP_STAT_MSG; + /* transfer the sm from the pmatch list to hcbdmatch list */ + SigMatchTransferSigMatchAcrossLists(sm, + &s->sm_lists[DETECT_SM_LIST_PMATCH], + &s->sm_lists_tail[DETECT_SM_LIST_PMATCH], + &s->sm_lists[DETECT_SM_LIST_HSMDMATCH], + &s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]); + + /* flag the signature to indicate that we scan the app layer data */ + s->flags |= SIG_FLAG_APPLAYER; s->alproto = ALPROTO_HTTP; + return 0; + error: - if (hd != NULL) - DetectHttpStatMsgFree(hd); - if (sm != NULL) - SCFree(sm); + return -1; } @@ -322,10 +328,11 @@ int DetectHttpStatMsgTest01(void) de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing http_stat_msg\"; content:\"one\";" - "fast_pattern; http_stat_msg;sid:1;)"); - if (de_ctx->sig_list == NULL || - ((DetectContentData *)de_ctx->sig_list->sm_lists[DETECT_SM_LIST_AMATCH]->ctx)->flags & - DETECT_CONTENT_FAST_PATTERN) + "fast_pattern; http_stat_msg; sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + if (!(((DetectContentData *)de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSMDMATCH]->ctx)->flags & + DETECT_CONTENT_FAST_PATTERN)) { goto end; } @@ -362,7 +369,7 @@ int DetectHttpStatMsgTest02(void) } result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_AMATCH]; + sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSMDMATCH]; if (sm == NULL) { printf("no sigmatch(es): "); goto end; @@ -417,7 +424,7 @@ static int DetectHttpStatMsgSigTest01(void) { f.flags |= FLOW_IPV4; p->flow = &f; - p->flowflags |= FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_TOCLIENT; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; @@ -440,7 +447,7 @@ static int DetectHttpStatMsgSigTest01(void) { s->next = SigInit(de_ctx,"alert http any any -> any any (msg:\"HTTP " "Status message nocase\"; content:\"ok\"; nocase; " - "http_stat_msg; sid:2;)"); + "http_stat_msg; sid:2;)"); if (s->next == NULL) { goto end; } @@ -523,7 +530,7 @@ static int DetectHttpStatMsgSigTest02(void) { f.flags |= FLOW_IPV4; p->flow = &f; - p->flowflags |= FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_TOCLIENT; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; @@ -619,7 +626,7 @@ static int DetectHttpStatMsgSigTest03(void) { f.flags |= FLOW_IPV4; p->flow = &f; - p->flowflags |= FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_TOCLIENT; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; diff --git a/src/detect-isdataat.c b/src/detect-isdataat.c index 00fab28efc..5a6702e873 100644 --- a/src/detect-isdataat.c +++ b/src/detect-isdataat.c @@ -351,7 +351,7 @@ int DetectIsdataatSetup (DetectEngineCtx *de_ctx, Signature *s, char *isdataatst } return 0; } - pm = SigMatchGetLastSMFromLists(s, 50, + pm = SigMatchGetLastSMFromLists(s, 52, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], /* 1 */ DETECT_URICONTENT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], DETECT_AL_HTTP_CLIENT_BODY, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], @@ -361,6 +361,7 @@ int DetectIsdataatSetup (DetectEngineCtx *de_ctx, Signature *s, char *isdataatst DETECT_AL_HTTP_METHOD, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], DETECT_AL_HTTP_COOKIE, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], DETECT_AL_HTTP_RAW_URI, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], + DETECT_AL_HTTP_STAT_MSG, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], /* 10 */ DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], @@ -382,7 +383,8 @@ int DetectIsdataatSetup (DetectEngineCtx *de_ctx, Signature *s, char *isdataatst "without a previous content uricontent, " "http_client_body, http_header, http_raw_header, " "http_method, http_cookie, http_raw_uri, " - "byte_test, byte_extract, byte_jump keyword"); + "http_stat_msg, byte_test, byte_extract, byte_jump " + "keyword"); goto error; } else { int list_type = -1; @@ -418,6 +420,9 @@ int DetectIsdataatSetup (DetectEngineCtx *de_ctx, Signature *s, char *isdataatst case DETECT_AL_HTTP_RAW_URI: list_type = DETECT_SM_LIST_HRUDMATCH; break; + case DETECT_AL_HTTP_STAT_MSG: + list_type = DETECT_SM_LIST_HSMDMATCH; + break; default: /* would never happen */ break; @@ -461,6 +466,7 @@ int DetectIsdataatSetup (DetectEngineCtx *de_ctx, Signature *s, char *isdataatst case DETECT_AL_HTTP_METHOD: case DETECT_AL_HTTP_COOKIE: case DETECT_AL_HTTP_RAW_URI: + case DETECT_AL_HTTP_STAT_MSG: /* Set the relative next flag on the prev sigmatch */ cd = (DetectContentData *)prev_pm->ctx; if (cd == NULL) { diff --git a/src/detect-nocase.c b/src/detect-nocase.c index 36e02a6f9a..da9ef4f1e6 100644 --- a/src/detect-nocase.c +++ b/src/detect-nocase.c @@ -180,7 +180,7 @@ static int DetectNocaseSetup (DetectEngineCtx *de_ctx, Signature *s, char *nulls } /* Search for the first previous SigMatch that supports nocase */ - SigMatch *pm = SigMatchGetLastSMFromLists(s, 18, + SigMatch *pm = SigMatchGetLastSMFromLists(s, 20, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], DETECT_URICONTENT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], DETECT_AL_HTTP_CLIENT_BODY, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], @@ -189,12 +189,13 @@ static int DetectNocaseSetup (DetectEngineCtx *de_ctx, Signature *s, char *nulls DETECT_AL_HTTP_RAW_HEADER, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], DETECT_AL_HTTP_METHOD, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], DETECT_AL_HTTP_RAW_URI, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], + DETECT_AL_HTTP_STAT_MSG, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], DETECT_AL_HTTP_COOKIE, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]); 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 or " - "http_raw_uri option"); + "http_header, http_method, http_uri, http_cookie, " + "http_raw_uri or http_stat_msg option"); SCReturnInt(-1); } @@ -210,6 +211,7 @@ static int DetectNocaseSetup (DetectEngineCtx *de_ctx, Signature *s, char *nulls case DETECT_AL_HTTP_METHOD: case DETECT_AL_HTTP_COOKIE: case DETECT_AL_HTTP_RAW_URI: + case DETECT_AL_HTTP_STAT_MSG: cd = (DetectContentData *)pm->ctx; if (cd == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENT, "invalid argument"); diff --git a/src/detect-offset.c b/src/detect-offset.c index 6343fa1f70..949f30b406 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, 18, + pm = SigMatchGetLastSMFromLists(s, 20, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], DETECT_URICONTENT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], DETECT_AL_HTTP_CLIENT_BODY, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], @@ -92,12 +92,13 @@ int DetectOffsetSetup (DetectEngineCtx *de_ctx, Signature *s, char *offsetstr) DETECT_AL_HTTP_RAW_HEADER, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], DETECT_AL_HTTP_METHOD, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], DETECT_AL_HTTP_COOKIE, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], + DETECT_AL_HTTP_STAT_MSG, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], DETECT_AL_HTTP_RAW_URI, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]); 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 or http_raw_uri option"); + "http_cookie, http_raw_uri or http_stat_msg option"); if (dubbed) SCFree(str); return -1; @@ -520,6 +521,50 @@ int DetectOffsetSetup (DetectEngineCtx *de_ctx, Signature *s, char *offsetstr) break; + case DETECT_AL_HTTP_STAT_MSG: + cd = (DetectContentData *)pm->ctx; + if (cd->flags & DETECT_CONTENT_NEGATED) { + if (cd->flags & DETECT_CONTENT_FAST_PATTERN) { + SCLogError(SC_ERR_INVALID_SIGNATURE, "You can't have a relative " + "negated keyword set along with a fast_pattern"); + goto error; + } + } else { + if (cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) { + SCLogError(SC_ERR_INVALID_SIGNATURE, "You can't have a relative " + "keyword set along with a fast_pattern:only;"); + goto error; + } + } + + if (str[0] != '-' && isalpha(str[0])) { + SigMatch *bed_sm = + DetectByteExtractRetrieveSMVar(str, s, + SigMatchListSMBelongsTo(s, pm)); + if (bed_sm == NULL) { + SCLogError(SC_ERR_INVALID_SIGNATURE, "Unknown byte_extract var " + "seen in offset - %s\n", str); + goto error; + } + cd->offset = ((DetectByteExtractData *)bed_sm->ctx)->local_id; + cd->flags |= DETECT_CONTENT_OFFSET_BE; + } else { + cd->offset = (uint32_t)atoi(str); + if (cd->depth != 0) { + if (cd->depth < cd->content_len) { + SCLogDebug("depth increased to %"PRIu32" to match pattern len", + cd->content_len); + cd->depth = cd->content_len; + } + /* Updating the depth as is relative to the offset */ + cd->depth += cd->offset; + } + } + + cd->flags |= DETECT_CONTENT_OFFSET; + + break; + default: SCLogError(SC_ERR_OFFSET_MISSING_CONTENT, "offset needs a preceeding" " content or uricontent option"); diff --git a/src/detect-parse.c b/src/detect-parse.c index b69f9c1c5b..62d0a772e5 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -1425,6 +1425,7 @@ static int SigValidate(Signature *s) { DETECT_REPLACE, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], DETECT_REPLACE, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], 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_HCDMATCH]); if (pm != NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "Signature has" @@ -1441,6 +1442,7 @@ static int SigValidate(Signature *s) { s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH] || s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH] || s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH] || + s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH] || s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]) { SCLogError(SC_ERR_INVALID_SIGNATURE, "Signature combines packet " @@ -1567,6 +1569,8 @@ static Signature *SigInitHelper(DetectEngineCtx *de_ctx, char *sigstr, sig->flags |= SIG_FLAG_STATE_MATCH; if (sig->sm_lists[DETECT_SM_LIST_FILEMATCH]) sig->flags |= SIG_FLAG_STATE_MATCH; + if (sig->sm_lists[DETECT_SM_LIST_HSMDMATCH]) + 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 4740c20412..6318043342 100644 --- a/src/detect-pcre.c +++ b/src/detect-pcre.c @@ -902,6 +902,10 @@ DetectPcreData *DetectPcreParse (char *regexstr) /* suricata extension (http response body inspection) */ pd->flags |= DETECT_PCRE_HTTP_SERVER_BODY; break; + case 'Y': + /* snort's option */ + pd->flags |= DETECT_PCRE_HTTP_STAT_MSG; + break; default: SCLogError(SC_ERR_UNKNOWN_REGEX_MOD, "unknown regex modifier '%c'", *op); goto error; @@ -1070,6 +1074,7 @@ static int DetectPcreSetup (DetectEngineCtx *de_ctx, Signature *s, char *regexst (pd->flags & DETECT_PCRE_HEADER) || (pd->flags & DETECT_PCRE_RAW_HEADER) || (pd->flags & DETECT_PCRE_COOKIE) || + (pd->flags & DETECT_PCRE_HTTP_STAT_MSG) || (pd->flags & DETECT_PCRE_HTTP_CLIENT_BODY) || (pd->flags & DETECT_PCRE_HTTP_SERVER_BODY) || (pd->flags & DETECT_PCRE_HTTP_RAW_URI) ) { @@ -1152,6 +1157,16 @@ static int DetectPcreSetup (DetectEngineCtx *de_ctx, Signature *s, char *regexst s->alproto = ALPROTO_HTTP; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_HRUDMATCH); + } else if (pd->flags & DETECT_PCRE_HTTP_STAT_MSG) { + s->flags |= SIG_FLAG_APPLAYER; + if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_HTTP) { + SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting" + " keywords."); + goto error; + } + s->alproto = ALPROTO_HTTP; + + SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_HSMDMATCH); } else { if (s->alproto == ALPROTO_DCERPC && pd->flags & DETECT_PCRE_RELATIVE) { SigMatch *pm = NULL; @@ -1192,7 +1207,7 @@ static int DetectPcreSetup (DetectEngineCtx *de_ctx, Signature *s, char *regexst SCReturnInt(0); } - prev_sm = SigMatchGetLastSMFromLists(s, 24, + prev_sm = SigMatchGetLastSMFromLists(s, 26, DETECT_CONTENT, sm->prev, DETECT_URICONTENT, sm->prev, DETECT_AL_HTTP_CLIENT_BODY, sm->prev, @@ -1204,7 +1219,8 @@ static int DetectPcreSetup (DetectEngineCtx *de_ctx, Signature *s, char *regexst DETECT_AL_HTTP_METHOD, sm->prev, DETECT_PCRE, sm->prev, DETECT_PCRE_HTTPCOOKIE, sm->prev, - DETECT_PCRE_HTTPMETHOD, sm->prev); + DETECT_PCRE_HTTPMETHOD, sm->prev, + DETECT_AL_HTTP_STAT_MSG, sm->prev); if (prev_sm == NULL) { if (s->alproto == ALPROTO_DCERPC) { SCLogDebug("No preceding content or pcre keyword. Possible " @@ -1233,6 +1249,7 @@ static int DetectPcreSetup (DetectEngineCtx *de_ctx, Signature *s, char *regexst case DETECT_AL_HTTP_SERVER_BODY: case DETECT_AL_HTTP_HEADER: case DETECT_AL_HTTP_RAW_HEADER: + case DETECT_AL_HTTP_STAT_MSG: case DETECT_AL_HTTP_RAW_URI: case DETECT_AL_HTTP_COOKIE: case DETECT_AL_HTTP_METHOD: diff --git a/src/detect-pcre.h b/src/detect-pcre.h index eae443756d..2fd4c27614 100644 --- a/src/detect-pcre.h +++ b/src/detect-pcre.h @@ -43,8 +43,9 @@ #define DETECT_PCRE_COOKIE 0x0800 #define DETECT_PCRE_METHOD 0x1000 #define DETECT_PCRE_HTTP_RAW_URI 0x2000 +#define DETECT_PCRE_HTTP_STAT_MSG 0x4000 -#define DETECT_PCRE_NEGATE 0x4000 +#define DETECT_PCRE_NEGATE 0x8000 typedef struct DetectPcreData_ { /* pcre options */ diff --git a/src/detect-within.c b/src/detect-within.c index e3ff378552..31bd1c613c 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, 18, + pm = SigMatchGetLastSMFromLists(s, 20, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], DETECT_URICONTENT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], DETECT_AL_HTTP_CLIENT_BODY, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], @@ -172,12 +172,14 @@ static int DetectWithinSetup (DetectEngineCtx *de_ctx, Signature *s, char *withi DETECT_AL_HTTP_RAW_HEADER, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], DETECT_AL_HTTP_METHOD, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], DETECT_AL_HTTP_COOKIE, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], + DETECT_AL_HTTP_STAT_MSG, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], DETECT_AL_HTTP_RAW_URI, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]); if (pm == NULL) { SCLogError(SC_ERR_WITHIN_MISSING_CONTENT, "within needs" "preceeding content, uricontent, http_client_body, " "http_server_body, http_header, http_raw_header, " - "http_method, http_cookie or http_raw_uri option"); + "http_method, http_cookie, http_raw_uri or " + "http_stat_msg option"); if (dubbed) SCFree(str); return -1; @@ -888,6 +890,74 @@ static int DetectWithinSetup (DetectEngineCtx *de_ctx, Signature *s, char *withi break; + case DETECT_AL_HTTP_STAT_MSG: + cd = (DetectContentData *)pm->ctx; + if (cd->flags & DETECT_CONTENT_NEGATED) { + if (cd->flags & DETECT_CONTENT_FAST_PATTERN) { + SCLogError(SC_ERR_INVALID_SIGNATURE, "You can't have a relative " + "negated keyword set along with a fast_pattern"); + goto error; + } + } else { + if (cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) { + SCLogError(SC_ERR_INVALID_SIGNATURE, "You can't have a relative " + "keyword set along with a fast_pattern:only;"); + goto error; + } + } + + if (str[0] != '-' && isalpha(str[0])) { + SigMatch *bed_sm = + DetectByteExtractRetrieveSMVar(str, s, + SigMatchListSMBelongsTo(s, pm)); + if (bed_sm == NULL) { + SCLogError(SC_ERR_INVALID_SIGNATURE, "Unknown byte_extract var " + "seen in within - %s\n", str); + goto error; + } + cd->within = ((DetectByteExtractData *)bed_sm->ctx)->local_id; + cd->flags |= DETECT_CONTENT_WITHIN_BE; + } else { + cd->within = strtol(str, NULL, 10); + if (cd->within < (int32_t)cd->content_len) { + SCLogError(SC_ERR_WITHIN_INVALID, "within argument \"%"PRIi32"\" is " + "less than the content length \"%"PRIu32"\" which is invalid, since " + "this will never match. Invalidating signature", cd->within, + cd->content_len); + goto error; + } + } + + cd->flags |= DETECT_CONTENT_WITHIN; + + /* reassigning pm */ + pm = SigMatchGetLastSMFromLists(s, 4, + DETECT_AL_HTTP_STAT_MSG, pm->prev, + DETECT_PCRE, pm->prev); + if (pm == NULL) { + SCLogError(SC_ERR_DISTANCE_MISSING_CONTENT, "distance for http_stat_msg " + "needs preceeding http_stat_msg content"); + goto error; + } + + if (pm->type == DETECT_PCRE) { + DetectPcreData *tmp_pd = (DetectPcreData *)pm->ctx; + tmp_pd->flags |= DETECT_PCRE_RELATIVE_NEXT; + } else { + /* reassigning cd */ + cd = (DetectContentData *)pm->ctx; + if (cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) { + SCLogError(SC_ERR_INVALID_SIGNATURE, "Previous keyword " + "has a fast_pattern:only; set. You can't " + "have relative keywords around a fast_pattern " + "only content"); + goto error; + } + cd->flags |= DETECT_CONTENT_RELATIVE_NEXT; + } + + break; + default: SCLogError(SC_ERR_WITHIN_MISSING_CONTENT, "within needs two " "preceeding content or uricontent options"); diff --git a/src/detect.c b/src/detect.c index 9d07becab2..20ec3332ec 100644 --- a/src/detect.c +++ b/src/detect.c @@ -128,6 +128,7 @@ #include "detect-engine-hmd.h" #include "detect-engine-hcd.h" #include "detect-engine-hrud.h" +#include "detect-engine-hsmd.h" #include "detect-byte-extract.h" #include "detect-file-data.h" #include "detect-replace.h" @@ -1208,6 +1209,11 @@ static inline void DetectMpmPrefilter(DetectEngineCtx *de_ctx, DetectEngineRunHttpRawUriMpm(det_ctx, p->flow, alstate, flags); PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_HRUD); } + if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_HSMD) { + PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_HSMD); + DetectEngineRunHttpStatMsgMpm(det_ctx, p->flow, alstate); + PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_HSMD); + } } } else { SCLogDebug("NOT p->flowflags & FLOW_PKT_ESTABLISHED"); @@ -1944,6 +1950,9 @@ int SignatureIsIPOnly(DetectEngineCtx *de_ctx, Signature *s) { if (s->sm_lists[DETECT_SM_LIST_HRUDMATCH] != NULL) return 0; + if (s->sm_lists[DETECT_SM_LIST_HSMDMATCH] != NULL) + return 0; + if (s->sm_lists[DETECT_SM_LIST_AMATCH] != NULL) return 0; @@ -2022,6 +2031,7 @@ static int SignatureIsDEOnly(DetectEngineCtx *de_ctx, Signature *s) { s->sm_lists[DETECT_SM_LIST_HRHDMATCH] != NULL || s->sm_lists[DETECT_SM_LIST_HMDMATCH] != NULL || s->sm_lists[DETECT_SM_LIST_HCDMATCH] != NULL || + s->sm_lists[DETECT_SM_LIST_HSMDMATCH] != NULL || s->sm_lists[DETECT_SM_LIST_HRUDMATCH] != NULL) { SCReturnInt(0); @@ -2163,6 +2173,11 @@ static int SignatureCreateMask(Signature *s) { SCLogDebug("sig requires http app state"); } + if (s->sm_lists[DETECT_SM_LIST_HSMDMATCH] != 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) { @@ -2324,6 +2339,9 @@ static void SigInitStandardMpmFactoryContexts(DetectEngineCtx *de_ctx) de_ctx->sgh_mpm_context_hrud = MpmFactoryRegisterMpmCtxProfile("hrud", MPM_CTX_FACTORY_FLAGS_PREPARE_WITH_SIG_GROUP_BUILD); + de_ctx->sgh_mpm_context_hsmd = + MpmFactoryRegisterMpmCtxProfile("hsmd", + MPM_CTX_FACTORY_FLAGS_PREPARE_WITH_SIG_GROUP_BUILD); de_ctx->sgh_mpm_context_app_proto_detect = MpmFactoryRegisterMpmCtxProfile("app_proto_detect", 0); @@ -4359,6 +4377,18 @@ int SigGroupBuild (DetectEngineCtx *de_ctx) { mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); } //printf("stream- %d\n", mpm_ctx->pattern_cnt); + + mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx->sgh_mpm_context_hsmd, 0); + if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { + mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); + } + //printf("hsmd- %d\n", mpm_ctx->pattern_cnt); + + mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx->sgh_mpm_context_hsmd, 1); + if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { + mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); + } + //printf("hsmd- %d\n", mpm_ctx->pattern_cnt); } // SigAddressPrepareStage5(de_ctx); diff --git a/src/detect.h b/src/detect.h index 3645bfa7b0..49d442f5e2 100644 --- a/src/detect.h +++ b/src/detect.h @@ -100,6 +100,8 @@ enum { DETECT_SM_LIST_HCDMATCH, /* list for http_raw_uri keyword and the ones relative to it */ DETECT_SM_LIST_HRUDMATCH, + /* list for http_stat_msg keyword and the ones relative to it */ + DETECT_SM_LIST_HSMDMATCH, DETECT_SM_LIST_FILEMATCH, @@ -651,6 +653,7 @@ typedef struct DetectEngineCtx_ { int32_t sgh_mpm_context_hmd; int32_t sgh_mpm_context_hcd; int32_t sgh_mpm_context_hrud; + int32_t sgh_mpm_context_hsmd; int32_t sgh_mpm_context_app_proto_detect; /** sgh for signatures that match against invalid packets. In those cases @@ -838,6 +841,8 @@ typedef struct SigTableElmt_ { #define SIG_GROUP_HEAD_HAVEFILEMAGIC 0x00800000 #define SIG_GROUP_HAVEHSBDCONTENT 0x01000000 #define SIG_GROUP_HEAD_MPM_HSBD 0x02000000 +#define SIG_GROUP_HAVEHSMDCONTENT 0x04000000 +#define SIG_GROUP_HEAD_MPM_HSMD 0x08000000 typedef struct SigGroupHeadInitData_ { /* list of content containers @@ -893,6 +898,7 @@ typedef struct SigGroupHead_ { MpmCtx *mpm_hmd_ctx_ts; MpmCtx *mpm_hcd_ctx_ts; MpmCtx *mpm_hrud_ctx_ts; + MpmCtx *mpm_hsmd_ctx_ts; MpmCtx *mpm_proto_tcp_ctx_tc; MpmCtx *mpm_proto_udp_ctx_tc; @@ -905,6 +911,7 @@ typedef struct SigGroupHead_ { MpmCtx *mpm_hmd_ctx_tc; MpmCtx *mpm_hcd_ctx_tc; MpmCtx *mpm_hrud_ctx_tc; + MpmCtx *mpm_hsmd_ctx_tc; uint16_t mpm_uricontent_maxlen; diff --git a/src/suricata.c b/src/suricata.c index ba7acd8341..ba9120e7b6 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -64,6 +64,7 @@ #include "detect-engine-hmd.h" #include "detect-engine-hcd.h" #include "detect-engine-hrud.h" +#include "detect-engine-hsmd.h" #include "detect-engine-state.h" #include "detect-engine-tag.h" #include "detect-fast-pattern.h" @@ -1437,6 +1438,7 @@ int main(int argc, char **argv) DetectEngineHttpMethodRegisterTests(); DetectEngineHttpCookieRegisterTests(); DetectEngineHttpRawUriRegisterTests(); + DetectEngineHttpStatMsgRegisterTests(); DetectEngineRegisterTests(); SCLogRegisterTests(); SMTPParserRegisterTests();