diff --git a/src/Makefile.am b/src/Makefile.am index 832edfbf78..69eb2a4938 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -85,6 +85,7 @@ 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-hscd.c detect-engine-hscd.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 59f2d4a792..cfeef4b308 100644 --- a/src/detect-content.h +++ b/src/detect-content.h @@ -53,15 +53,16 @@ #define DETECT_CONTENT_HCD_MPM 0x00080000 #define DETECT_CONTENT_HRUD_MPM 0x00100000 #define DETECT_CONTENT_HSMD_MPM 0x00200000 +#define DETECT_CONTENT_HSCD_MPM 0x00400000 /* BE - byte extract */ -#define DETECT_CONTENT_OFFSET_BE 0x00400000 -#define DETECT_CONTENT_DEPTH_BE 0x00800000 -#define DETECT_CONTENT_DISTANCE_BE 0x01000000 -#define DETECT_CONTENT_WITHIN_BE 0x02000000 +#define DETECT_CONTENT_OFFSET_BE 0x00800000 +#define DETECT_CONTENT_DEPTH_BE 0x01000000 +#define DETECT_CONTENT_DISTANCE_BE 0x02000000 +#define DETECT_CONTENT_WITHIN_BE 0x04000000 /* replace data */ -#define DETECT_CONTENT_REPLACE 0x04000000 +#define DETECT_CONTENT_REPLACE 0x08000000 #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 f742761c98..36e02f6a23 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, 20, + pm = SigMatchGetLastSMFromLists(s, 22, 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], @@ -96,13 +96,14 @@ static int DetectDepthSetup (DetectEngineCtx *de_ctx, Signature *s, char *depths 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_CODE, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], 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, http_raw_uri or " - "http_stat_msg option"); + "http_method option, http_cookie, http_raw_uri, " + "http_stat_msg or http_stat_code option"); if (dubbed) SCFree(str); return -1; @@ -545,6 +546,47 @@ static int DetectDepthSetup (DetectEngineCtx *de_ctx, Signature *s, char *depths break; + case DETECT_AL_HTTP_STAT_CODE: + 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 c2ee1d33b4..a55dcaa4db 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, 20, + pm = SigMatchGetLastSMFromLists(s, 22, 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], @@ -170,12 +170,14 @@ static int DetectDistanceSetup (DetectEngineCtx *de_ctx, Signature *s, 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_CODE, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], 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, http_raw_uri or http_stat_msg option"); + "http_cookie, http_raw_uri, http_stat_msg or http_stat_code " + "option"); if (dubbed) SCFree(str); return -1; @@ -900,6 +902,73 @@ static int DetectDistanceSetup (DetectEngineCtx *de_ctx, Signature *s, break; + case DETECT_AL_HTTP_STAT_CODE: + 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_CODE, pm->prev, + DETECT_PCRE, pm->prev); + if (pm == NULL) { + SCLogError(SC_ERR_DISTANCE_MISSING_CONTENT, "distance for " + "http_stat_code needs preceeding http_stat_code " + "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-hsbd.c b/src/detect-engine-hsbd.c index 04eb935bae..fa2debd36b 100644 --- a/src/detect-engine-hsbd.c +++ b/src/detect-engine-hsbd.c @@ -2212,7 +2212,7 @@ static int DetectEngineHttpServerBodyTest14(void) de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http server body test\"; " - "pcre:/ab/S; " + "pcre:/ab/Q; " "content:\"ef\"; http_server_body; distance:2; " "sid:1;)"); if (de_ctx->sig_list == NULL) @@ -2331,7 +2331,7 @@ static int DetectEngineHttpServerBodyTest15(void) de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http server body test\"; " - "pcre:/abc/S; " + "pcre:/abc/Q; " "content:!\"xyz\"; http_server_body; distance:0; within:3; " "sid:1;)"); if (de_ctx->sig_list == NULL) diff --git a/src/detect-engine-hscd.c b/src/detect-engine-hscd.c index e69de29bb2..2dd341cf6c 100644 --- a/src/detect-engine-hscd.c +++ b/src/detect-engine-hscd.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-hscd.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 code. + * + * 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 code to inspect. + * \param payload_len Length of the http stat code. + * + * \retval 0 no match. + * \retval 1 match. + */ +static int DoInspectHttpStatCode(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_CODE) { + 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 = DoInspectHttpStatCode(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 = DoInspectHttpStatCode(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 = DoInspectHttpStatCode(de_ctx, det_ctx, s, sm->next, payload, + payload_len); + SCReturnInt(r); + } else { + SCReturnInt(1); + } +} + +/** + * \brief Run the mpm against http stat code. + * + * \retval cnt Number of matches reported by the mpm algo. + */ +int DetectEngineRunHttpStatCodeMpm(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_status == NULL) + continue; + + cnt += HttpStatCodePatternSearch(det_ctx, + (uint8_t *)bstr_ptr(tx->response_status), + bstr_len(tx->response_status)); + } + +end: + SCMutexUnlock(&f->m); + SCReturnInt(cnt); +} + +/** + * \brief Do the http_stat_code 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 DetectEngineInspectHttpStatCode(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_status == NULL) + continue; + + det_ctx->discontinue_matching = 0; + det_ctx->payload_offset = 0; + det_ctx->inspection_recursion_counter = 0; + + r = DoInspectHttpStatCode(de_ctx, det_ctx, s, + s->sm_lists[DETECT_SM_LIST_HSCDMATCH], + (uint8_t *)bstr_ptr(tx->response_status), + bstr_len(tx->response_status)); + if (r == 1) { + goto end; + } + } + +end: + SCMutexUnlock(&f->m); + SCReturnInt(r); +} + +/***********************************Unittests**********************************/ + +#ifdef UNITTESTS + +static int DetectEngineHttpStatCodeTest01(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 code test\"; " + "content:\"200\"; http_stat_code; " + "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 DetectEngineHttpStatCodeTest02(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 2000123 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 code test\"; " + "content:\"123\"; http_stat_code; 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 DetectEngineHttpStatCodeTest03(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 123"; + uint32_t http_len2 = sizeof(http_buf2) - 1; + uint8_t http_buf3[] = + "456789\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 code test\"; " + "content:\"789\"; http_stat_code; offset:5; " + "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 DetectEngineHttpStatCodeTest04(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 200123 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 code test\"; " + "content:!\"200\"; http_stat_code; 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 DetectEngineHttpStatCodeTest05(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 200123 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 code test\"; " + "content:\"200\"; http_stat_code; 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 DetectEngineHttpStatCodeTest06(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 200123 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 code test\"; " + "content:!\"123\"; http_stat_code; 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 DetectEngineHttpStatCodeTest07(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 200123 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 code test\"; " + "content:!\"123\"; http_stat_code; 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 DetectEngineHttpStatCodeTest08(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 200123 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 code test\"; " + "content:!\"200\"; http_stat_code; 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 DetectEngineHttpStatCodeTest09(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 200123 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 code test\"; " + "content:\"200\"; http_stat_code; depth:3; " + "content:\"123\"; http_stat_code; 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 DetectEngineHttpStatCodeTest10(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 200123 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 code test\"; " + "content:\"200\"; http_stat_code; depth:3; " + "content:!\"124\"; http_stat_code; 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 DetectEngineHttpStatCodeTest11(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 200123 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 code test\"; " + "content:\"200\"; http_stat_code; depth:3; " + "content:\"124\"; http_stat_code; 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 DetectEngineHttpStatCodeTest12(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 200123 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 code test\"; " + "content:\"20\"; http_stat_code; depth:2; " + "content:\"23\"; http_stat_code; 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 DetectEngineHttpStatCodeTest13(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 200123 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 code test\"; " + "content:\"20\"; http_stat_code; depth:3; " + "content:!\"25\"; http_stat_code; 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 DetectEngineHttpStatCodeTest14(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 200123 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 code test\"; " + "pcre:/20/S; " + "content:\"23\"; http_stat_code; 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 DetectEngineHttpStatCodeTest15(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 200123 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 code test\"; " + "pcre:/200/S; " + "content:!\"124\"; http_stat_code; 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 DetectEngineHttpStatCodeRegisterTests(void) +{ + +#ifdef UNITTESTS + UtRegisterTest("DetectEngineHttpStatCodeTest01", + DetectEngineHttpStatCodeTest01, 1); + UtRegisterTest("DetectEngineHttpStatCodeTest02", + DetectEngineHttpStatCodeTest02, 1); + UtRegisterTest("DetectEngineHttpStatCodeTest03", + DetectEngineHttpStatCodeTest03, 1); + UtRegisterTest("DetectEngineHttpStatCodeTest04", + DetectEngineHttpStatCodeTest04, 1); + UtRegisterTest("DetectEngineHttpStatCodeTest05", + DetectEngineHttpStatCodeTest05, 1); + UtRegisterTest("DetectEngineHttpStatCodeTest06", + DetectEngineHttpStatCodeTest06, 1); + UtRegisterTest("DetectEngineHttpStatCodeTest07", + DetectEngineHttpStatCodeTest07, 1); + UtRegisterTest("DetectEngineHttpStatCodeTest08", + DetectEngineHttpStatCodeTest08, 1); + UtRegisterTest("DetectEngineHttpStatCodeTest09", + DetectEngineHttpStatCodeTest09, 1); + UtRegisterTest("DetectEngineHttpStatCodeTest10", + DetectEngineHttpStatCodeTest10, 1); + UtRegisterTest("DetectEngineHttpStatCodeTest11", + DetectEngineHttpStatCodeTest11, 1); + UtRegisterTest("DetectEngineHttpStatCodeTest12", + DetectEngineHttpStatCodeTest12, 1); + UtRegisterTest("DetectEngineHttpStatCodeTest13", + DetectEngineHttpStatCodeTest13, 1); + UtRegisterTest("DetectEngineHttpStatCodeTest14", + DetectEngineHttpStatCodeTest14, 1); + UtRegisterTest("DetectEngineHttpStatCodeTest15", + DetectEngineHttpStatCodeTest15, 1); +#endif /* UNITTESTS */ + + return; +} + +/** + * @} + */ diff --git a/src/detect-engine-hscd.h b/src/detect-engine-hscd.h index e69de29bb2..aea47f171a 100644 --- a/src/detect-engine-hscd.h +++ b/src/detect-engine-hscd.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_HSCD_H__ +#define __DETECT_ENGINE_HSCD_H__ + +#include "app-layer-htp.h" + +int DetectEngineRunHttpStatCodeMpm(DetectEngineThreadCtx *, + Flow *f, HtpState *); +int DetectEngineInspectHttpStatCode(DetectEngineCtx *, DetectEngineThreadCtx *, + Signature *, Flow *, uint8_t, void *); +void DetectEngineHttpStatCodeRegisterTests(void); + +#endif /* __DETECT_ENGINE_HSCD_H__ */ diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index 1dfdccdac9..fb274ef06f 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -527,9 +527,9 @@ uint32_t HttpRawUriPatternSearch(DetectEngineThreadCtx *det_ctx, /** * \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. + * \param det_ctx Detection engine thread ctx. + * \param stat_msg Stat msg to inspect. + * \param stat_msg_len Stat msg length. * * \retval ret Number of matches. */ @@ -549,6 +549,31 @@ uint32_t HttpStatMsgPatternSearch(DetectEngineThreadCtx *det_ctx, SCReturnUInt(ret); } +/** + * \brief Http stat code match -- searches for one pattern per signature. + * + * \param det_ctx Detection engine thread ctx. + * \param stat_code Stat code to inspect. + * \param stat_code_len Stat code length. + * + * \retval ret Number of matches. + */ +uint32_t HttpStatCodePatternSearch(DetectEngineThreadCtx *det_ctx, + uint8_t *stat_code, uint32_t stat_code_len) +{ + SCEnter(); + + if (det_ctx->sgh->mpm_hscd_ctx == NULL) + SCReturnUInt(0); + + uint32_t ret; + ret = mpm_table[det_ctx->sgh->mpm_hscd_ctx->mpm_type]. + Search(det_ctx->sgh->mpm_hscd_ctx, &det_ctx->mtcu, + &det_ctx->pmq, stat_code, stat_code_len); + + SCReturnUInt(ret); +} + /** \brief Pattern match -- searches for only one pattern per signature. * * \param det_ctx detection engine thread ctx @@ -1206,6 +1231,7 @@ static void PopulateMpmAddPatternToMpm(DetectEngineCtx *de_ctx, case DETECT_AL_HTTP_METHOD: case DETECT_AL_HTTP_COOKIE: case DETECT_AL_HTTP_STAT_MSG: + case DETECT_AL_HTTP_STAT_CODE: { MpmCtx *mpm_ctx_ts = NULL; MpmCtx *mpm_ctx_tc = NULL; @@ -1272,6 +1298,10 @@ static void PopulateMpmAddPatternToMpm(DetectEngineCtx *de_ctx, mpm_ctx = sgh->mpm_hsmd_ctx; sgh_flags = SIG_GROUP_HEAD_MPM_HSMD; cd_flags = DETECT_CONTENT_HSMD_MPM; + } else if (mpm_sm->type == DETECT_AL_HTTP_STAT_CODE) { + mpm_ctx = sgh->mpm_hscd_ctx; + sgh_flags = SIG_GROUP_HEAD_MPM_HSCD; + cd_flags = DETECT_CONTENT_HSCD_MPM; } cd = (DetectContentData *)mpm_sm->ctx; @@ -1566,6 +1596,8 @@ int PatternMatchPrepareGroup(DetectEngineCtx *de_ctx, SigGroupHead *sh) 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; + /* used to indicate if sgh has atleast one sig with http_stat_code */ + uint32_t has_co_hscd = 0; //uint32_t cnt = 0; uint32_t sig = 0; @@ -1619,6 +1651,10 @@ int PatternMatchPrepareGroup(DetectEngineCtx *de_ctx, SigGroupHead *sh) if (s->sm_lists[DETECT_SM_LIST_HSMDMATCH] != NULL) { has_co_hsmd = 1; } + + if (s->sm_lists[DETECT_SM_LIST_HSCDMATCH] != NULL) { + has_co_hscd = 1; + } } if (has_co_packet > 0) { @@ -1654,6 +1690,9 @@ int PatternMatchPrepareGroup(DetectEngineCtx *de_ctx, SigGroupHead *sh) if (has_co_hsmd > 0) { sh->flags |= SIG_GROUP_HAVEHSMDCONTENT; } + if (has_co_hscd > 0) { + sh->flags |= SIG_GROUP_HAVEHSCDCONTENT; + } /* intialize contexes */ if (sh->flags & SIG_GROUP_HAVECONTENT) { @@ -1929,6 +1968,24 @@ int PatternMatchPrepareGroup(DetectEngineCtx *de_ctx, SigGroupHead *sh) #endif } + if (sh->flags & SIG_GROUP_HAVEHSCDCONTENT) { + if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE) { + sh->mpm_hscd_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx->sgh_mpm_context_hscd); + } else { + sh->mpm_hscd_ctx = MpmFactoryGetMpmCtxForProfile(MPM_CTX_FACTORY_UNIQUE_CONTEXT); + } + if (sh->mpm_hscd_ctx == NULL) { + SCLogDebug("sh->mpm_hscd_ctx == NULL. This should never happen"); + exit(EXIT_FAILURE); + } + +#ifndef __SC_CUDA_SUPPORT__ + MpmInitCtx(sh->mpm_hscd_ctx, de_ctx->mpm_matcher, -1); +#else + MpmInitCtx(sh->mpm_hscd_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 || @@ -1939,6 +1996,7 @@ int PatternMatchPrepareGroup(DetectEngineCtx *de_ctx, SigGroupHead *sh) sh->flags & SIG_GROUP_HAVEHMDCONTENT || sh->flags & SIG_GROUP_HAVEHCDCONTENT || sh->flags & SIG_GROUP_HAVEHSMDCONTENT || + sh->flags & SIG_GROUP_HAVEHSCDCONTENT || sh->flags & SIG_GROUP_HAVEHRUDCONTENT) { PatternMatchPreparePopulateMpm(de_ctx, sh); @@ -2253,6 +2311,18 @@ int PatternMatchPrepareGroup(DetectEngineCtx *de_ctx, SigGroupHead *sh) } } } + if (sh->mpm_hscd_ctx != NULL) { + if (sh->mpm_hscd_ctx->pattern_cnt == 0) { + MpmFactoryReClaimMpmCtx(sh->mpm_hscd_ctx); + sh->mpm_hscd_ctx = NULL; + } else { + if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL && + sh->flags & SIG_GROUP_HAVEHSCDCONTENT) { + if (mpm_table[sh->mpm_hscd_ctx->mpm_type].Prepare != NULL) + mpm_table[sh->mpm_hscd_ctx->mpm_type].Prepare(sh->mpm_hscd_ctx); + } + } + } //} /* if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) */ } else { MpmFactoryReClaimMpmCtx(sh->mpm_proto_other_ctx); @@ -2280,6 +2350,8 @@ int PatternMatchPrepareGroup(DetectEngineCtx *de_ctx, SigGroupHead *sh) sh->mpm_hrud_ctx_ts = NULL; MpmFactoryReClaimMpmCtx(sh->mpm_hsmd_ctx_ts); sh->mpm_hsmd_ctx_ts = NULL; + MpmFactoryReClaimMpmCtx(sh->mpm_hscd_ctx_ts); + sh->mpm_hscd_ctx_ts = NULL; MpmFactoryReClaimMpmCtx(sh->mpm_proto_tcp_ctx_tc); sh->mpm_proto_tcp_ctx_tc = NULL; @@ -2303,6 +2375,8 @@ int PatternMatchPrepareGroup(DetectEngineCtx *de_ctx, SigGroupHead *sh) sh->mpm_hrud_ctx_tc = NULL; MpmFactoryReClaimMpmCtx(sh->mpm_hsmd_ctx_tc); sh->mpm_hsmd_ctx_tc = NULL; + MpmFactoryReClaimMpmCtx(sh->mpm_hscd_ctx_tc); + sh->mpm_hscd_ctx_tc = NULL; } return 0; diff --git a/src/detect-engine-mpm.h b/src/detect-engine-mpm.h index 1519943788..aa00a619f1 100644 --- a/src/detect-engine-mpm.h +++ b/src/detect-engine-mpm.h @@ -46,6 +46,7 @@ uint32_t HttpMethodPatternSearch(DetectEngineThreadCtx *, uint8_t *, uint32_t, u 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); +uint32_t HttpStatCodePatternSearch(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 96ba0acb91..bc0b94d382 100644 --- a/src/detect-engine-state.c +++ b/src/detect-engine-state.c @@ -65,6 +65,7 @@ #include "detect-engine-hcd.h" #include "detect-engine-hrud.h" #include "detect-engine-hsmd.h" +#include "detect-engine-hscd.h" #include "detect-engine-dcepayload.h" #include "detect-engine-file.h" @@ -498,6 +499,10 @@ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, if (s->sm_lists[DETECT_SM_LIST_HSMDMATCH] != NULL) { inspect_flags |= DE_STATE_FLAG_HSMD_INSPECT; } + /* not inspecting in toserver direction */ + if (s->sm_lists[DETECT_SM_LIST_HSCDMATCH] != NULL) { + inspect_flags |= DE_STATE_FLAG_HSCD_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 @@ -575,6 +580,14 @@ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, } SCLogDebug("inspecting http stat msg"); } + if (s->sm_lists[DETECT_SM_LIST_HSCDMATCH] != NULL) { + inspect_flags |= DE_STATE_FLAG_HSCD_INSPECT; + if (DetectEngineInspectHttpStatCode(de_ctx, det_ctx, s, f, + flags, alstate) == 1) { + match_flags |= DE_STATE_FLAG_HSCD_MATCH; + } + SCLogDebug("inspecting http stat code"); + } } } else if (alproto == ALPROTO_DCERPC || alproto == ALPROTO_SMB || alproto == ALPROTO_SMB2) { if (s->sm_lists[DETECT_SM_LIST_DMATCH] != NULL) { @@ -904,6 +917,12 @@ int DeStateDetectContinueDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, Dete inspect_flags |= DE_STATE_FLAG_HSMD_INSPECT; } } + /* not inspecting in toserver direction */ + if (s->sm_lists[DETECT_SM_LIST_HSCDMATCH] != NULL) { + if (!(item->flags & DE_STATE_FLAG_HSCD_MATCH)) { + inspect_flags |= DE_STATE_FLAG_HSCD_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 @@ -1004,6 +1023,18 @@ int DeStateDetectContinueDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, Dete } } } + if (s->sm_lists[DETECT_SM_LIST_HSCDMATCH] != NULL) { + if (!(item->flags & DE_STATE_FLAG_HSCD_MATCH)) { + SCLogDebug("inspecting http stat code data"); + inspect_flags |= DE_STATE_FLAG_HSCD_INSPECT; + + if (DetectEngineInspectHttpStatCode(de_ctx, det_ctx, s, f, + flags, alstate) == 1) { + SCLogDebug("http stat code matched"); + match_flags |= DE_STATE_FLAG_HSCD_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 7620bddd6c..50e2a5a81c 100644 --- a/src/detect-engine-state.h +++ b/src/detect-engine-state.h @@ -66,6 +66,7 @@ #define DE_STATE_FLAG_FULL_MATCH 0x1000 /**< sig already fully matched */ #define DE_STATE_FLAG_SIG_CANT_MATCH 0x2000 /**< signature has no chance of matching */ #define DE_STATE_FLAG_HSMD_MATCH 0x4000 /**< hsmd payload inspection part matched */ +#define DE_STATE_FLAG_HSCD_MATCH 0x8000 /**< hscd payload inspection part matched */ #define DE_STATE_FLAG_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 */ @@ -79,6 +80,7 @@ #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 */ +#define DE_STATE_FLAG_HSCD_INSPECT DE_STATE_FLAG_HSCD_MATCH /**< hscd 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 40791910a7..ae75d7534d 100644 --- a/src/detect-fast-pattern.c +++ b/src/detect-fast-pattern.c @@ -149,6 +149,9 @@ void SupportFastPatternForSigMatchTypes(void) SupportFastPatternForSigMatchType(DETECT_AL_HTTP_STAT_MSG); SupportFastPatternForSigMatchList(DETECT_SM_LIST_HSMDMATCH); + SupportFastPatternForSigMatchType(DETECT_AL_HTTP_STAT_CODE); + SupportFastPatternForSigMatchList(DETECT_SM_LIST_HSCDMATCH); + return; } @@ -222,17 +225,18 @@ static int DetectFastPatternSetup(DetectEngineCtx *de_ctx, Signature *s, char *a 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_HSMDMATCH] == NULL) { + s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH] == NULL && + s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH] == NULL) { SCLogWarning(SC_WARN_COMPATIBILITY, "fast_pattern found inside the " "rule, without a preceding content based keyword. " "Currently we provide fast_pattern support for content, " "uricontent, http_client_body, http_server_body, http_header, " "http_raw_header, http_method, http_cookie, " - "http_raw_uri or http_stat_msg option"); + "http_raw_uri, http_stat_msg or http_stat_code option"); return -1; } - SigMatch *pm = SigMatchGetLastSMFromLists(s, 20, + SigMatch *pm = SigMatchGetLastSMFromLists(s, 22, 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], @@ -242,6 +246,7 @@ static int DetectFastPatternSetup(DetectEngineCtx *de_ctx, Signature *s, char *a 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_STAT_CODE, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], 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 " @@ -12239,6 +12244,1189 @@ int DetectFastPatternTest424(void) return result; } + + + + + + + + + + + + + + + + + + + + +int DetectFastPatternTest425(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_code; " + "content:!\"oneonetwo\"; fast_pattern:3,4; http_stat_code; " + "content:\"three\"; http_stat_code; sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]->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 DetectFastPatternTest426(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_code; " + "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_HSCDMATCH]; + 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 DetectFastPatternTest427(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_code; " + "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_HSCDMATCH]; + 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 DetectFastPatternTest428(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_code; sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + result = 0; + sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSCDMATCH]; + 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 DetectFastPatternTest429(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_code; sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + result = 0; + sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSCDMATCH]; + 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 DetectFastPatternTest430(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_code; " + "content:\"two\"; fast_pattern:only; http_stat_code; distance:10; sid:1;)"); + if (de_ctx->sig_list != NULL) + goto end; + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest431(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_code; " + "content:\"two\"; distance:10; fast_pattern:only; http_stat_code; sid:1;)"); + if (de_ctx->sig_list != NULL) + goto end; + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest432(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_code; " + "content:\"two\"; fast_pattern:only; http_stat_code; within:10; sid:1;)"); + if (de_ctx->sig_list != NULL) + goto end; + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest433(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_code; " + "content:\"two\"; within:10; fast_pattern:only; http_stat_code; sid:1;)"); + if (de_ctx->sig_list != NULL) + goto end; + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest434(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_code; " + "content:\"two\"; fast_pattern:only; http_stat_code; offset:10; sid:1;)"); + if (de_ctx->sig_list != NULL) + goto end; + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest435(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_code; " + "content:\"two\"; offset:10; fast_pattern:only; http_stat_code; sid:1;)"); + if (de_ctx->sig_list != NULL) + goto end; + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest436(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_code; " + "content:\"two\"; fast_pattern:only; http_stat_code; depth:10; sid:1;)"); + if (de_ctx->sig_list != NULL) + goto end; + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest437(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_code; " + "content:\"two\"; depth:10; fast_pattern:only; http_stat_code; sid:1;)"); + if (de_ctx->sig_list != NULL) + goto end; + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest438(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_code; " + "content:!\"two\"; fast_pattern:only; http_stat_code; sid:1;)"); + if (de_ctx->sig_list != NULL) + goto end; + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest439(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_code; " + "content:\"two\"; http_stat_code; distance:30; " + "content:\"two\"; fast_pattern:only; http_stat_code; sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]->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 DetectFastPatternTest440(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_code; " + "content:\"two\"; http_stat_code; within:30; " + "content:\"two\"; fast_pattern:only; http_stat_code; sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]->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 DetectFastPatternTest441(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_code; " + "content:\"two\"; http_stat_code; offset:30; " + "content:\"two\"; fast_pattern:only; http_stat_code; sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]->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 DetectFastPatternTest442(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_code; " + "content:\"two\"; http_stat_code; depth:30; " + "content:\"two\"; fast_pattern:only; http_stat_code; sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]->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 DetectFastPatternTest443(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_code; " + "content:\"two\"; http_stat_code; sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]->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 DetectFastPatternTest444(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_code; " + "content:!\"one\"; fast_pattern; http_stat_code; distance:20; sid:1;)"); + if (de_ctx->sig_list != NULL) + goto end; + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest445(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_code; " + "content:!\"one\"; fast_pattern; http_stat_code; within:20; sid:1;)"); + if (de_ctx->sig_list != NULL) + goto end; + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest446(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_code; " + "content:!\"one\"; fast_pattern; http_stat_code; offset:20; sid:1;)"); + if (de_ctx->sig_list != NULL) + goto end; + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest447(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_code; " + "content:!\"one\"; fast_pattern; http_stat_code; depth:20; sid:1;)"); + if (de_ctx->sig_list != NULL) + goto end; + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest448(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_code; " + "content:\"oneonetwo\"; fast_pattern:3,4; http_stat_code; " + "content:\"three\"; http_stat_code; sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]->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 DetectFastPatternTest449(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_code; " + "content:\"oneonetwo\"; fast_pattern:3,4; http_stat_code; " + "content:\"three\"; http_stat_code; distance:30; sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]->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 DetectFastPatternTest450(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_code; " + "content:\"oneonetwo\"; fast_pattern:3,4; http_stat_code; " + "content:\"three\"; http_stat_code; within:30; sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]->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 DetectFastPatternTest451(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_code; " + "content:\"oneonetwo\"; fast_pattern:3,4; http_stat_code; " + "content:\"three\"; http_stat_code; offset:30; sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]->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 DetectFastPatternTest452(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_code; " + "content:\"oneonetwo\"; fast_pattern:3,4; http_stat_code; " + "content:\"three\"; http_stat_code; depth:30; sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]->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 DetectFastPatternTest453(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_code; " + "content:\"two\"; http_stat_code; distance:10; " + "content:\"oneonethree\"; fast_pattern:3,4; http_stat_code; sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]->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 DetectFastPatternTest454(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_code; " + "content:\"two\"; http_stat_code; within:10; " + "content:\"oneonethree\"; fast_pattern:3,4; http_stat_code; sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]->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 DetectFastPatternTest455(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_code; " + "content:\"two\"; http_stat_code; offset:10; " + "content:\"oneonethree\"; fast_pattern:3,4; http_stat_code; sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]->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 DetectFastPatternTest456(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_code; " + "content:\"two\"; http_stat_code; depth:10; " + "content:\"oneonethree\"; fast_pattern:3,4; http_stat_code; sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]->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 DetectFastPatternTest457(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_code; " + "content:\"two\"; fast_pattern:65977,4; http_stat_code; " + "content:\"three\"; http_stat_code; distance:10; sid:1;)"); + if (de_ctx->sig_list != NULL) + goto end; + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest458(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_code; " + "content:\"oneonetwo\"; fast_pattern:3,65977; http_stat_code; " + "content:\"three\"; distance:10; http_stat_code; sid:1;)"); + if (de_ctx->sig_list != NULL) + goto end; + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest459(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_code; " + "content:\"two\"; fast_pattern:65534,4; http_stat_code; " + "content:\"three\"; http_stat_code; distance:10; sid:1;)"); + if (de_ctx->sig_list != NULL) + goto end; + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest460(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_code; " + "content:!\"oneonetwo\"; fast_pattern:3,4; http_stat_code; " + "content:\"three\"; http_stat_code; sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]->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 DetectFastPatternTest461(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_code; " + "content:!\"oneonetwo\"; fast_pattern:3,4; http_stat_code; distance:10; " + "content:\"three\"; http_stat_code; sid:1;)"); + if (de_ctx->sig_list != NULL) + goto end; + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest462(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_code; " + "content:!\"oneonetwo\"; fast_pattern:3,4; http_stat_code; within:10; " + "content:\"three\"; http_stat_code; sid:1;)"); + if (de_ctx->sig_list != NULL) + goto end; + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest463(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_code; " + "content:!\"oneonetwo\"; fast_pattern:3,4; http_stat_code; offset:10; " + "content:\"three\"; http_stat_code; sid:1;)"); + if (de_ctx->sig_list != NULL) + goto end; + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest464(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_code; " + "content:!\"oneonetwo\"; fast_pattern:3,4; http_stat_code; depth:10; " + "content:\"three\"; http_stat_code; sid:1;)"); + if (de_ctx->sig_list != NULL) + goto end; + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest465(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_code; " + "content:!\"oneonetwo\"; fast_pattern:3,4; http_stat_code; " + "content:\"three\"; http_stat_code; sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]->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) @@ -12689,6 +13877,49 @@ void DetectFastPatternRegisterTests(void) UtRegisterTest("DetectFastPatternTest422", DetectFastPatternTest422, 1); UtRegisterTest("DetectFastPatternTest423", DetectFastPatternTest423, 1); UtRegisterTest("DetectFastPatternTest424", DetectFastPatternTest424, 1); + /* http_stat_msg fast_pattern tests ^ */ + /* http_stat_code fast_pattern tests v */ + UtRegisterTest("DetectFastPatternTest425", DetectFastPatternTest425, 1); + UtRegisterTest("DetectFastPatternTest426", DetectFastPatternTest426, 1); + UtRegisterTest("DetectFastPatternTest427", DetectFastPatternTest427, 1); + UtRegisterTest("DetectFastPatternTest428", DetectFastPatternTest428, 1); + UtRegisterTest("DetectFastPatternTest429", DetectFastPatternTest429, 1); + UtRegisterTest("DetectFastPatternTest430", DetectFastPatternTest430, 1); + UtRegisterTest("DetectFastPatternTest431", DetectFastPatternTest431, 1); + UtRegisterTest("DetectFastPatternTest432", DetectFastPatternTest432, 1); + UtRegisterTest("DetectFastPatternTest433", DetectFastPatternTest433, 1); + UtRegisterTest("DetectFastPatternTest434", DetectFastPatternTest434, 1); + UtRegisterTest("DetectFastPatternTest435", DetectFastPatternTest435, 1); + UtRegisterTest("DetectFastPatternTest436", DetectFastPatternTest436, 1); + UtRegisterTest("DetectFastPatternTest437", DetectFastPatternTest437, 1); + UtRegisterTest("DetectFastPatternTest438", DetectFastPatternTest438, 1); + UtRegisterTest("DetectFastPatternTest439", DetectFastPatternTest439, 1); + UtRegisterTest("DetectFastPatternTest440", DetectFastPatternTest440, 1); + UtRegisterTest("DetectFastPatternTest441", DetectFastPatternTest441, 1); + UtRegisterTest("DetectFastPatternTest442", DetectFastPatternTest442, 1); + UtRegisterTest("DetectFastPatternTest443", DetectFastPatternTest443, 1); + UtRegisterTest("DetectFastPatternTest444", DetectFastPatternTest444, 1); + UtRegisterTest("DetectFastPatternTest445", DetectFastPatternTest445, 1); + UtRegisterTest("DetectFastPatternTest446", DetectFastPatternTest446, 1); + UtRegisterTest("DetectFastPatternTest447", DetectFastPatternTest447, 1); + UtRegisterTest("DetectFastPatternTest448", DetectFastPatternTest448, 1); + UtRegisterTest("DetectFastPatternTest449", DetectFastPatternTest449, 1); + UtRegisterTest("DetectFastPatternTest450", DetectFastPatternTest450, 1); + UtRegisterTest("DetectFastPatternTest451", DetectFastPatternTest451, 1); + UtRegisterTest("DetectFastPatternTest452", DetectFastPatternTest452, 1); + UtRegisterTest("DetectFastPatternTest453", DetectFastPatternTest453, 1); + UtRegisterTest("DetectFastPatternTest454", DetectFastPatternTest454, 1); + UtRegisterTest("DetectFastPatternTest455", DetectFastPatternTest455, 1); + UtRegisterTest("DetectFastPatternTest456", DetectFastPatternTest456, 1); + UtRegisterTest("DetectFastPatternTest457", DetectFastPatternTest457, 1); + UtRegisterTest("DetectFastPatternTest458", DetectFastPatternTest458, 1); + UtRegisterTest("DetectFastPatternTest459", DetectFastPatternTest459, 1); + UtRegisterTest("DetectFastPatternTest460", DetectFastPatternTest460, 1); + UtRegisterTest("DetectFastPatternTest461", DetectFastPatternTest461, 1); + UtRegisterTest("DetectFastPatternTest462", DetectFastPatternTest462, 1); + UtRegisterTest("DetectFastPatternTest463", DetectFastPatternTest463, 1); + UtRegisterTest("DetectFastPatternTest464", DetectFastPatternTest464, 1); + UtRegisterTest("DetectFastPatternTest465", DetectFastPatternTest465, 1); #endif return; diff --git a/src/detect-http-server-body.c b/src/detect-http-server-body.c index 39cfc03fd4..e398b37be3 100644 --- a/src/detect-http-server-body.c +++ b/src/detect-http-server-body.c @@ -2460,7 +2460,7 @@ int DetectHttpServerBodyTest34(void) de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " - "(pcre:/one/S; " + "(pcre:/one/Q; " "content:\"two\"; within:5; http_server_body; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); @@ -2512,7 +2512,7 @@ int DetectHttpServerBodyTest35(void) de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"two\"; http_server_body; " - "pcre:/one/SR; sid:1;)"); + "pcre:/one/QR; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; @@ -2562,7 +2562,7 @@ int DetectHttpServerBodyTest36(void) de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " - "(pcre:/one/S; " + "(pcre:/one/Q; " "content:\"two\"; distance:5; http_server_body; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); diff --git a/src/detect-http-stat-code.c b/src/detect-http-stat-code.c index 7486385f8f..8fb63e3d09 100644 --- a/src/detect-http-stat-code.c +++ b/src/detect-http-stat-code.c @@ -26,6 +26,7 @@ * \file * * \author Gurvinder Singh + * \author Anoop Saldanha * * Implements the http_stat_code 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" @@ -59,10 +62,10 @@ #include "stream-tcp-private.h" #include "stream-tcp.h" -int DetectHttpStatCodeMatch (ThreadVars *, DetectEngineThreadCtx *, - Flow *, uint8_t , void *, Signature *, - SigMatch *); -static int DetectHttpStatCodeSetup (DetectEngineCtx *, Signature *, char *); +int DetectHttpStatCodeMatch(ThreadVars *, DetectEngineThreadCtx *, + Flow *, uint8_t , void *, Signature *, + SigMatch *); +static int DetectHttpStatCodeSetup(DetectEngineCtx *, Signature *, char *); void DetectHttpStatCodeRegisterTests(void); void DetectHttpStatCodeFree(void *); @@ -72,7 +75,7 @@ void DetectHttpStatCodeFree(void *); void DetectHttpStatCodeRegister (void) { sigmatch_table[DETECT_AL_HTTP_STAT_CODE].name = "http_stat_code"; sigmatch_table[DETECT_AL_HTTP_STAT_CODE].Match = NULL; - sigmatch_table[DETECT_AL_HTTP_STAT_CODE].AppLayerMatch = DetectHttpStatCodeMatch; + sigmatch_table[DETECT_AL_HTTP_STAT_CODE].AppLayerMatch = NULL; sigmatch_table[DETECT_AL_HTTP_STAT_CODE].alproto = ALPROTO_HTTP; sigmatch_table[DETECT_AL_HTTP_STAT_CODE].Setup = DetectHttpStatCodeSetup; sigmatch_table[DETECT_AL_HTTP_STAT_CODE].Free = DetectHttpStatCodeFree; @@ -96,9 +99,9 @@ void DetectHttpStatCodeRegister (void) { * \retval 0 no match * \retval 1 match */ -int DetectHttpStatCodeMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *state, Signature *s, - SigMatch *sm) +int DetectHttpStatCodeMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, + Flow *f, uint8_t flags, void *state, Signature *s, + SigMatch *sm) { SCEnter(); @@ -210,96 +213,96 @@ void DetectHttpStatCodeFree(void *ptr) * \retval -1 On failure */ -static int DetectHttpStatCodeSetup (DetectEngineCtx *de_ctx, Signature *s, char *str) +static int DetectHttpStatCodeSetup (DetectEngineCtx *de_ctx, Signature *s, char *arg) { - SCEnter(); - DetectHttpStatCodeData *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_code shouldn't be supplied" - " with an argument"); - SCReturnInt(-1); + if (arg != NULL && strcmp(arg, "") != 0) { + SCLogError(SC_ERR_INVALID_ARGUMENT, "http_stat_code 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_code found inside " - "the rule, without a content context. Please use a " - "content keyword before using http_stat_code"); + 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_code\" keyword " + "found inside the rule without a content context. " + "Please use a \"content\" keyword before using the " + "\"http_stat_code\" keyword"); return -1; } - /* http_stat_code should not be used with the fast_pattern rule */ - if (((DetectContentData *)pm->ctx)->flags & DETECT_CONTENT_FAST_PATTERN) { - SCLogWarning(SC_WARN_COMPATIBILITY, "http_stat_code 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_code 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_code rule can not " - "be used with the rawbytes rule keyword"); - SCReturnInt(-1); + "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 HttpStatCode data from Content data structure */ - hd = SCMalloc(sizeof(DetectHttpStatCodeData)); - if (hd == NULL) - goto error; - - memset(hd, 0, sizeof(DetectHttpStatCodeData)); - - /* Setup the http_stat_code keyword data */ - hd->data_len = ((DetectContentData *)pm->ctx)->content_len; - hd->data = ((DetectContentData *)pm->ctx)->content; - hd->flags |= (((DetectContentData *)pm->ctx)->flags & DETECT_CONTENT_NOCASE) ? - DETECT_AL_HTTP_STAT_CODE_NOCASE : 0x00; - hd->flags |= (((DetectContentData *)pm->ctx)->flags & DETECT_CONTENT_NEGATED) ? - DETECT_AL_HTTP_STAT_CODE_NEGATED : 0; - hd->code = htp_parse_positive_integer_whitespace((unsigned char *)hd->data, - hd->data_len, 10); - nm->type = DETECT_AL_HTTP_STAT_CODE; - 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_CODE, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], + DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]); + if (pm == NULL) { + SCLogError(SC_ERR_INVALID_SIGNATURE, "http_stat_code seen with a " + "distance or within without a previous http_stat_code " + "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_CODE); + sm->type = DETECT_AL_HTTP_STAT_CODE; + + /* 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_HSCDMATCH], + &s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]); + /* flag the signature to indicate that we scan the app layer data */ + s->flags |= SIG_FLAG_APPLAYER; s->alproto = ALPROTO_HTTP; - SCReturnInt(0); + + return 0; + error: - if (hd != NULL) - DetectHttpStatCodeFree(hd); - if(sm !=NULL) - SCFree(sm); - SCReturnInt(-1); + + return -1; } #ifdef UNITTESTS @@ -342,6 +345,11 @@ int DetectHttpStatCodeTest01(void) printf("sid 3 parse failed: "); goto end; } + if (!(((DetectContentData *)de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSCDMATCH]->ctx)->flags & + DETECT_CONTENT_FAST_PATTERN)) + { + goto end; + } result = 1; end: @@ -375,7 +383,7 @@ int DetectHttpStatCodeTest02(void) } result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_AMATCH]; + sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSCDMATCH]; if (sm == NULL) { printf("no sigmatch(es): "); goto end; @@ -393,8 +401,8 @@ int DetectHttpStatCodeTest02(void) sm = sm->next; } - if (! (((DetectHttpStatCodeData *)prev->ctx)->flags & - DETECT_AL_HTTP_STAT_CODE_NOCASE)) + if (! (((DetectContentData *)prev->ctx)->flags & + DETECT_CONTENT_NOCASE)) { result = 0; } @@ -430,7 +438,7 @@ static int DetectHttpStatCodeSigTest01(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; @@ -523,7 +531,7 @@ static int DetectHttpStatCodeSigTest02(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; @@ -630,7 +638,7 @@ static int DetectHttpStatCodeSigTest03(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; @@ -737,7 +745,7 @@ static int DetectHttpStatCodeSigTest04(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-http-stat-msg.c b/src/detect-http-stat-msg.c index 761ec344dd..245f51ad3b 100644 --- a/src/detect-http-stat-msg.c +++ b/src/detect-http-stat-msg.c @@ -213,7 +213,7 @@ static int DetectHttpStatMsgSetup (DetectEngineCtx *de_ctx, Signature *s, char * SigMatch *sm = NULL; if (arg != NULL && strcmp(arg, "") != 0) { - SCLogError(SC_ERR_INVALID_ARGUMENT, "http_client_body supplied with args"); + SCLogError(SC_ERR_INVALID_ARGUMENT, "http_stat_msg supplied with args"); return -1; } diff --git a/src/detect-isdataat.c b/src/detect-isdataat.c index 5a6702e873..b283167246 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, 52, + pm = SigMatchGetLastSMFromLists(s, 54, 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], @@ -362,6 +362,7 @@ int DetectIsdataatSetup (DetectEngineCtx *de_ctx, Signature *s, char *isdataatst 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_AL_HTTP_STAT_CODE, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], 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], @@ -383,8 +384,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, " - "http_stat_msg, byte_test, byte_extract, byte_jump " - "keyword"); + "http_stat_msg, http_stat_code, byte_test, " + "byte_extract, byte_jump keyword"); goto error; } else { int list_type = -1; @@ -423,6 +424,9 @@ int DetectIsdataatSetup (DetectEngineCtx *de_ctx, Signature *s, char *isdataatst case DETECT_AL_HTTP_STAT_MSG: list_type = DETECT_SM_LIST_HSMDMATCH; break; + case DETECT_AL_HTTP_STAT_CODE: + list_type = DETECT_SM_LIST_HSCDMATCH; + break; default: /* would never happen */ break; @@ -467,6 +471,7 @@ int DetectIsdataatSetup (DetectEngineCtx *de_ctx, Signature *s, char *isdataatst case DETECT_AL_HTTP_COOKIE: case DETECT_AL_HTTP_RAW_URI: case DETECT_AL_HTTP_STAT_MSG: + case DETECT_AL_HTTP_STAT_CODE: /* 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 da9ef4f1e6..b7a7141c2c 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, 20, + SigMatch *pm = SigMatchGetLastSMFromLists(s, 22, 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], @@ -190,12 +190,13 @@ static int DetectNocaseSetup (DetectEngineCtx *de_ctx, Signature *s, char *nulls 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_STAT_CODE, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], 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, " - "http_raw_uri or http_stat_msg option"); + "http_raw_uri, http_stat_msg or http_stat_code option"); SCReturnInt(-1); } @@ -212,6 +213,7 @@ static int DetectNocaseSetup (DetectEngineCtx *de_ctx, Signature *s, char *nulls case DETECT_AL_HTTP_COOKIE: case DETECT_AL_HTTP_RAW_URI: case DETECT_AL_HTTP_STAT_MSG: + case DETECT_AL_HTTP_STAT_CODE: 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 949f30b406..a46b72c91b 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, 20, + pm = SigMatchGetLastSMFromLists(s, 22, 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], @@ -93,12 +93,14 @@ int DetectOffsetSetup (DetectEngineCtx *de_ctx, Signature *s, char *offsetstr) 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_STAT_CODE, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], 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, http_raw_uri or http_stat_msg option"); + "http_cookie, http_raw_uri, http_stat_msg or " + "http_stat_code option"); if (dubbed) SCFree(str); return -1; @@ -565,6 +567,50 @@ int DetectOffsetSetup (DetectEngineCtx *de_ctx, Signature *s, char *offsetstr) break; + case DETECT_AL_HTTP_STAT_CODE: + 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 62d0a772e5..ef01598f89 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -1426,6 +1426,7 @@ static int SigValidate(Signature *s) { 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_HSCDMATCH], DETECT_REPLACE, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]); if (pm != NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "Signature has" @@ -1443,6 +1444,7 @@ static int SigValidate(Signature *s) { 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_HSCDMATCH] || s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]) { SCLogError(SC_ERR_INVALID_SIGNATURE, "Signature combines packet " @@ -1571,6 +1573,8 @@ static Signature *SigInitHelper(DetectEngineCtx *de_ctx, char *sigstr, sig->flags |= SIG_FLAG_STATE_MATCH; if (sig->sm_lists[DETECT_SM_LIST_HSMDMATCH]) sig->flags |= SIG_FLAG_STATE_MATCH; + if (sig->sm_lists[DETECT_SM_LIST_HSCDMATCH]) + 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 6318043342..6ddd7ab3bc 100644 --- a/src/detect-pcre.c +++ b/src/detect-pcre.c @@ -898,7 +898,7 @@ DetectPcreData *DetectPcreParse (char *regexstr) /* snort's option (http request body inspection) */ pd->flags |= DETECT_PCRE_HTTP_CLIENT_BODY; break; - case 'S': + case 'Q': /* suricata extension (http response body inspection) */ pd->flags |= DETECT_PCRE_HTTP_SERVER_BODY; break; @@ -906,6 +906,10 @@ DetectPcreData *DetectPcreParse (char *regexstr) /* snort's option */ pd->flags |= DETECT_PCRE_HTTP_STAT_MSG; break; + case 'S': + /* snort's option */ + pd->flags |= DETECT_PCRE_HTTP_STAT_CODE; + break; default: SCLogError(SC_ERR_UNKNOWN_REGEX_MOD, "unknown regex modifier '%c'", *op); goto error; @@ -1075,6 +1079,7 @@ static int DetectPcreSetup (DetectEngineCtx *de_ctx, Signature *s, char *regexst (pd->flags & DETECT_PCRE_RAW_HEADER) || (pd->flags & DETECT_PCRE_COOKIE) || (pd->flags & DETECT_PCRE_HTTP_STAT_MSG) || + (pd->flags & DETECT_PCRE_HTTP_STAT_CODE) || (pd->flags & DETECT_PCRE_HTTP_CLIENT_BODY) || (pd->flags & DETECT_PCRE_HTTP_SERVER_BODY) || (pd->flags & DETECT_PCRE_HTTP_RAW_URI) ) { @@ -1167,6 +1172,16 @@ static int DetectPcreSetup (DetectEngineCtx *de_ctx, Signature *s, char *regexst s->alproto = ALPROTO_HTTP; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_HSMDMATCH); + } else if (pd->flags & DETECT_PCRE_HTTP_STAT_CODE) { + 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_HSCDMATCH); } else { if (s->alproto == ALPROTO_DCERPC && pd->flags & DETECT_PCRE_RELATIVE) { SigMatch *pm = NULL; @@ -1207,7 +1222,7 @@ static int DetectPcreSetup (DetectEngineCtx *de_ctx, Signature *s, char *regexst SCReturnInt(0); } - prev_sm = SigMatchGetLastSMFromLists(s, 26, + prev_sm = SigMatchGetLastSMFromLists(s, 28, DETECT_CONTENT, sm->prev, DETECT_URICONTENT, sm->prev, DETECT_AL_HTTP_CLIENT_BODY, sm->prev, @@ -1220,7 +1235,8 @@ static int DetectPcreSetup (DetectEngineCtx *de_ctx, Signature *s, char *regexst DETECT_PCRE, sm->prev, DETECT_PCRE_HTTPCOOKIE, sm->prev, DETECT_PCRE_HTTPMETHOD, sm->prev, - DETECT_AL_HTTP_STAT_MSG, sm->prev); + DETECT_AL_HTTP_STAT_MSG, sm->prev, + DETECT_AL_HTTP_STAT_CODE, sm->prev); if (prev_sm == NULL) { if (s->alproto == ALPROTO_DCERPC) { SCLogDebug("No preceding content or pcre keyword. Possible " @@ -1250,6 +1266,7 @@ static int DetectPcreSetup (DetectEngineCtx *de_ctx, Signature *s, char *regexst case DETECT_AL_HTTP_HEADER: case DETECT_AL_HTTP_RAW_HEADER: case DETECT_AL_HTTP_STAT_MSG: + case DETECT_AL_HTTP_STAT_CODE: 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 2fd4c27614..7e878c2ad8 100644 --- a/src/detect-pcre.h +++ b/src/detect-pcre.h @@ -24,35 +24,36 @@ #ifndef __DETECT_PCRE_H__ #define __DETECT_PCRE_H__ -#define DETECT_PCRE_RELATIVE 0x0001 -#define DETECT_PCRE_RAWBYTES 0x0002 -#define DETECT_PCRE_URI 0x0004 +#define DETECT_PCRE_RELATIVE 0x00001 +#define DETECT_PCRE_RAWBYTES 0x00002 +#define DETECT_PCRE_URI 0x00004 -#define DETECT_PCRE_CAPTURE_PKT 0x0008 -#define DETECT_PCRE_CAPTURE_FLOW 0x0010 -#define DETECT_PCRE_MATCH_LIMIT 0x0020 +#define DETECT_PCRE_CAPTURE_PKT 0x00008 +#define DETECT_PCRE_CAPTURE_FLOW 0x00010 +#define DETECT_PCRE_MATCH_LIMIT 0x00020 -#define DETECT_PCRE_HTTP_CLIENT_BODY 0x0040 -#define DETECT_PCRE_HTTP_SERVER_BODY 0x0080 +#define DETECT_PCRE_HTTP_CLIENT_BODY 0x00040 +#define DETECT_PCRE_HTTP_SERVER_BODY 0x00080 -#define DETECT_PCRE_RELATIVE_NEXT 0x0100 +#define DETECT_PCRE_RELATIVE_NEXT 0x00100 /* new modifiers 2.8.5.3 support */ -#define DETECT_PCRE_HEADER 0x0200 -#define DETECT_PCRE_RAW_HEADER 0x0400 -#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_HEADER 0x00200 +#define DETECT_PCRE_RAW_HEADER 0x00400 +#define DETECT_PCRE_COOKIE 0x00800 +#define DETECT_PCRE_METHOD 0x01000 +#define DETECT_PCRE_HTTP_RAW_URI 0x02000 +#define DETECT_PCRE_HTTP_STAT_MSG 0x04000 +#define DETECT_PCRE_HTTP_STAT_CODE 0x08000 -#define DETECT_PCRE_NEGATE 0x8000 +#define DETECT_PCRE_NEGATE 0x10000 typedef struct DetectPcreData_ { /* pcre options */ pcre *re; pcre_extra *sd; int opts; - uint16_t flags; + uint32_t flags; uint16_t capidx; char *capname; } DetectPcreData; diff --git a/src/detect-within.c b/src/detect-within.c index 31bd1c613c..adde569fe7 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, 20, + pm = SigMatchGetLastSMFromLists(s, 22, 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], @@ -173,13 +173,14 @@ static int DetectWithinSetup (DetectEngineCtx *de_ctx, Signature *s, char *withi 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_STAT_CODE, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], 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, http_raw_uri or " - "http_stat_msg option"); + "http_method, http_cookie, http_raw_uri, " + "http_stat_msg or http_stat_code option"); if (dubbed) SCFree(str); return -1; @@ -958,6 +959,74 @@ static int DetectWithinSetup (DetectEngineCtx *de_ctx, Signature *s, char *withi break; + case DETECT_AL_HTTP_STAT_CODE: + 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_CODE, pm->prev, + DETECT_PCRE, pm->prev); + if (pm == NULL) { + SCLogError(SC_ERR_DISTANCE_MISSING_CONTENT, "distance for http_stat_code " + "needs preceeding http_stat_code 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 20ec3332ec..6594f13906 100644 --- a/src/detect.c +++ b/src/detect.c @@ -129,6 +129,7 @@ #include "detect-engine-hcd.h" #include "detect-engine-hrud.h" #include "detect-engine-hsmd.h" +#include "detect-engine-hscd.h" #include "detect-byte-extract.h" #include "detect-file-data.h" #include "detect-replace.h" @@ -1214,6 +1215,11 @@ static inline void DetectMpmPrefilter(DetectEngineCtx *de_ctx, DetectEngineRunHttpStatMsgMpm(det_ctx, p->flow, alstate); PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_HSMD); } + if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_HSCD) { + PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_HSCD); + DetectEngineRunHttpStatCodeMpm(det_ctx, p->flow, alstate); + PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_HSCD); + } } } else { SCLogDebug("NOT p->flowflags & FLOW_PKT_ESTABLISHED"); @@ -1953,6 +1959,9 @@ int SignatureIsIPOnly(DetectEngineCtx *de_ctx, Signature *s) { if (s->sm_lists[DETECT_SM_LIST_HSMDMATCH] != NULL) return 0; + if (s->sm_lists[DETECT_SM_LIST_HSCDMATCH] != NULL) + return 0; + if (s->sm_lists[DETECT_SM_LIST_AMATCH] != NULL) return 0; @@ -2032,6 +2041,7 @@ static int SignatureIsDEOnly(DetectEngineCtx *de_ctx, Signature *s) { 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_HSCDMATCH] != NULL || s->sm_lists[DETECT_SM_LIST_HRUDMATCH] != NULL) { SCReturnInt(0); @@ -2178,6 +2188,11 @@ static int SignatureCreateMask(Signature *s) { SCLogDebug("sig requires http app state"); } + if (s->sm_lists[DETECT_SM_LIST_HSCDMATCH] != 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) { @@ -2342,6 +2357,9 @@ static void SigInitStandardMpmFactoryContexts(DetectEngineCtx *de_ctx) de_ctx->sgh_mpm_context_hsmd = MpmFactoryRegisterMpmCtxProfile("hsmd", MPM_CTX_FACTORY_FLAGS_PREPARE_WITH_SIG_GROUP_BUILD); + de_ctx->sgh_mpm_context_hscd = + MpmFactoryRegisterMpmCtxProfile("hscd", + MPM_CTX_FACTORY_FLAGS_PREPARE_WITH_SIG_GROUP_BUILD); de_ctx->sgh_mpm_context_app_proto_detect = MpmFactoryRegisterMpmCtxProfile("app_proto_detect", 0); @@ -4389,6 +4407,18 @@ int SigGroupBuild (DetectEngineCtx *de_ctx) { 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_hscd, 0); + if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { + mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); + } + //printf("hscd- %d\n", mpm_ctx->pattern_cnt); + + mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx->sgh_mpm_context_hscd, 1); + if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { + mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); + } + //printf("hscd- %d\n", mpm_ctx->pattern_cnt); } // SigAddressPrepareStage5(de_ctx); diff --git a/src/detect.h b/src/detect.h index 49d442f5e2..7e8590694b 100644 --- a/src/detect.h +++ b/src/detect.h @@ -102,6 +102,8 @@ enum { DETECT_SM_LIST_HRUDMATCH, /* list for http_stat_msg keyword and the ones relative to it */ DETECT_SM_LIST_HSMDMATCH, + /* list for http_stat_code keyword and the ones relative to it */ + DETECT_SM_LIST_HSCDMATCH, DETECT_SM_LIST_FILEMATCH, @@ -654,6 +656,7 @@ typedef struct DetectEngineCtx_ { int32_t sgh_mpm_context_hcd; int32_t sgh_mpm_context_hrud; int32_t sgh_mpm_context_hsmd; + int32_t sgh_mpm_context_hscd; int32_t sgh_mpm_context_app_proto_detect; /** sgh for signatures that match against invalid packets. In those cases @@ -843,6 +846,8 @@ typedef struct SigTableElmt_ { #define SIG_GROUP_HEAD_MPM_HSBD 0x02000000 #define SIG_GROUP_HAVEHSMDCONTENT 0x04000000 #define SIG_GROUP_HEAD_MPM_HSMD 0x08000000 +#define SIG_GROUP_HAVEHSCDCONTENT 0x10000000 +#define SIG_GROUP_HEAD_MPM_HSCD 0x20000000 typedef struct SigGroupHeadInitData_ { /* list of content containers @@ -899,6 +904,7 @@ typedef struct SigGroupHead_ { MpmCtx *mpm_hcd_ctx_ts; MpmCtx *mpm_hrud_ctx_ts; MpmCtx *mpm_hsmd_ctx_ts; + MpmCtx *mpm_hscd_ctx_ts; MpmCtx *mpm_proto_tcp_ctx_tc; MpmCtx *mpm_proto_udp_ctx_tc; @@ -912,6 +918,7 @@ typedef struct SigGroupHead_ { MpmCtx *mpm_hcd_ctx_tc; MpmCtx *mpm_hrud_ctx_tc; MpmCtx *mpm_hsmd_ctx_tc; + MpmCtx *mpm_hscd_ctx_tc; uint16_t mpm_uricontent_maxlen; diff --git a/src/suricata-common.h b/src/suricata-common.h index 6ee7b5fe0a..f8e5885324 100644 --- a/src/suricata-common.h +++ b/src/suricata-common.h @@ -184,6 +184,8 @@ typedef enum PacketProfileDetectId_ { PROF_DETECT_MPM_HMD, PROF_DETECT_MPM_HCD, PROF_DETECT_MPM_HRUD, + PROF_DETECT_MPM_HSMD, + PROF_DETECT_MPM_HSCD, PROF_DETECT_IPONLY, PROF_DETECT_RULES, PROF_DETECT_STATEFUL, diff --git a/src/suricata.c b/src/suricata.c index ba9120e7b6..5fe8aa109e 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -65,6 +65,7 @@ #include "detect-engine-hcd.h" #include "detect-engine-hrud.h" #include "detect-engine-hsmd.h" +#include "detect-engine-hscd.h" #include "detect-engine-state.h" #include "detect-engine-tag.h" #include "detect-fast-pattern.h" @@ -1439,6 +1440,7 @@ int main(int argc, char **argv) DetectEngineHttpCookieRegisterTests(); DetectEngineHttpRawUriRegisterTests(); DetectEngineHttpStatMsgRegisterTests(); + DetectEngineHttpStatCodeRegisterTests(); DetectEngineRegisterTests(); SCLogRegisterTests(); SMTPParserRegisterTests();