diff --git a/src/Makefile.am b/src/Makefile.am index 151f667eb6..0ab87fe08a 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -76,6 +76,7 @@ detect-engine-payload.c detect-engine-payload.h \ detect-engine-dcepayload.c detect-engine-dcepayload.h \ detect-engine-uri.c detect-engine-uri.h \ detect-engine-hcbd.c detect-engine-hcbd.h \ +detect-engine-hsbd.c detect-engine-hsbd.h \ detect-engine-hhd.c detect-engine-hhd.h \ detect-engine-hrhd.c detect-engine-hrhd.h \ detect-engine-hmd.c detect-engine-hmd.h \ @@ -148,6 +149,7 @@ detect-dce-stub-data.c detect-dce-stub-data.h \ detect-urilen.c detect-urilen.h \ detect-detection-filter.c detect-detection-filter.h \ detect-http-client-body.c detect-http-client-body.h \ +detect-http-server-body.c detect-http-server-body.h \ detect-http-stat-msg.c detect-http-stat-msg.h \ detect-asn1.c detect-asn1.h \ detect-filename.c detect-filename.h \ diff --git a/src/detect-content.h b/src/detect-content.h index a5f47a7ab0..90f1057547 100644 --- a/src/detect-content.h +++ b/src/detect-content.h @@ -46,20 +46,21 @@ #define DETECT_CONTENT_STREAM_MPM 0x00001000 #define DETECT_CONTENT_URI_MPM 0x00002000 #define DETECT_CONTENT_HCBD_MPM 0x00004000 -#define DETECT_CONTENT_HHD_MPM 0x00008000 -#define DETECT_CONTENT_HRHD_MPM 0x00010000 -#define DETECT_CONTENT_HMD_MPM 0x00020000 -#define DETECT_CONTENT_HCD_MPM 0x00040000 -#define DETECT_CONTENT_HRUD_MPM 0x00080000 +#define DETECT_CONTENT_HSBD_MPM 0x00008000 +#define DETECT_CONTENT_HHD_MPM 0x00010000 +#define DETECT_CONTENT_HRHD_MPM 0x00020000 +#define DETECT_CONTENT_HMD_MPM 0x00040000 +#define DETECT_CONTENT_HCD_MPM 0x00080000 +#define DETECT_CONTENT_HRUD_MPM 0x00100000 /* BE - byte extract */ -#define DETECT_CONTENT_OFFSET_BE 0x00100000 -#define DETECT_CONTENT_DEPTH_BE 0x00200000 -#define DETECT_CONTENT_DISTANCE_BE 0x00400000 -#define DETECT_CONTENT_WITHIN_BE 0x00800000 +#define DETECT_CONTENT_OFFSET_BE 0x00200000 +#define DETECT_CONTENT_DEPTH_BE 0x00400000 +#define DETECT_CONTENT_DISTANCE_BE 0x00800000 +#define DETECT_CONTENT_WITHIN_BE 0x01000000 /* replace data */ -#define DETECT_CONTENT_REPLACE 0x01000000 +#define DETECT_CONTENT_REPLACE 0x02000000 #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 ceecc12aa4..7fc2646630 100644 --- a/src/detect-depth.c +++ b/src/detect-depth.c @@ -73,8 +73,8 @@ static int DetectDepthSetup (DetectEngineCtx *de_ctx, Signature *s, char *depths case ALPROTO_DCERPC: /* add to the latest content keyword from either dmatch or pmatch */ pm = SigMatchGetLastSMFromLists(s, 4, - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_DMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH]); + DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_DMATCH], + DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH]); if (pm == NULL) { SCLogError(SC_ERR_DEPTH_MISSING_CONTENT, "depth needs " "preceeding content option for dcerpc sig"); @@ -86,21 +86,22 @@ static int DetectDepthSetup (DetectEngineCtx *de_ctx, Signature *s, char *depths break; default: - pm = SigMatchGetLastSMFromLists(s, 16, - 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], - DETECT_AL_HTTP_CLIENT_BODY, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_AL_HTTP_HEADER, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_AL_HTTP_RAW_HEADER, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_AL_HTTP_METHOD, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_AL_HTTP_COOKIE, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]); + pm = SigMatchGetLastSMFromLists(s, 18, + 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], + DETECT_AL_HTTP_CLIENT_BODY, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], + DETECT_AL_HTTP_SERVER_BODY, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], + DETECT_AL_HTTP_HEADER, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], + DETECT_AL_HTTP_RAW_HEADER, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], + DETECT_AL_HTTP_METHOD, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], + DETECT_AL_HTTP_COOKIE, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]); if (pm == NULL) { SCLogError(SC_ERR_DEPTH_MISSING_CONTENT, "depth needs " - "preceeding content, uricontent option, http_client_body, " - "http_header option, http_raw_header option, " - "http_method option, http_cookie or " - "http_raw_uri option"); + "preceeding content, uricontent option, http_client_body, " + "http_server_body, http_header option, http_raw_header option, " + "http_method option, http_cookie or " + "http_raw_uri option"); if (dubbed) SCFree(str); return -1; @@ -251,6 +252,48 @@ static int DetectDepthSetup (DetectEngineCtx *de_ctx, Signature *s, char *depths break; + case DETECT_AL_HTTP_SERVER_BODY: + 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; + case DETECT_AL_HTTP_HEADER: cd = (DetectContentData *)pm->ctx; if (cd->flags & DETECT_CONTENT_NEGATED) { diff --git a/src/detect-distance.c b/src/detect-distance.c index c758ad9818..b34969cba3 100644 --- a/src/detect-distance.c +++ b/src/detect-distance.c @@ -86,19 +86,19 @@ static int DetectDistanceSetup (DetectEngineCtx *de_ctx, Signature *s, SigMatch *pm2_ots = NULL; dcem = SigMatchGetLastSMFromLists(s, 6, - DETECT_DCE_IFACE, s->sm_lists_tail[DETECT_SM_LIST_AMATCH], - DETECT_DCE_OPNUM, s->sm_lists_tail[DETECT_SM_LIST_AMATCH], - DETECT_DCE_STUB_DATA, s->sm_lists_tail[DETECT_SM_LIST_AMATCH]); + DETECT_DCE_IFACE, s->sm_lists_tail[DETECT_SM_LIST_AMATCH], + DETECT_DCE_OPNUM, s->sm_lists_tail[DETECT_SM_LIST_AMATCH], + DETECT_DCE_STUB_DATA, s->sm_lists_tail[DETECT_SM_LIST_AMATCH]); pm1_ots = SigMatchGetLastSMFromLists(s, 6, - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_PMATCH]); + DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], + DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], + DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_PMATCH]); if (pm1_ots != NULL && pm1_ots->prev != NULL) { pm2_ots = SigMatchGetLastSMFromLists(s, 6, - DETECT_CONTENT, pm1_ots->prev, - DETECT_PCRE, pm1_ots->prev, - DETECT_BYTEJUMP, pm1_ots->prev); + DETECT_CONTENT, pm1_ots->prev, + DETECT_PCRE, pm1_ots->prev, + DETECT_BYTEJUMP, pm1_ots->prev); } dm = SigMatchGetLastSMFromLists(s, 2, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_DMATCH]); @@ -115,10 +115,10 @@ static int DetectDistanceSetup (DetectEngineCtx *de_ctx, Signature *s, if (pm1->idx > dcem->idx) { /* transfer pm1 to dmatch list and within is against this */ SigMatchTransferSigMatchAcrossLists(pm1, - &s->sm_lists[DETECT_SM_LIST_PMATCH], - &s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - &s->sm_lists[DETECT_SM_LIST_DMATCH], - &s->sm_lists_tail[DETECT_SM_LIST_DMATCH]); + &s->sm_lists[DETECT_SM_LIST_PMATCH], + &s->sm_lists_tail[DETECT_SM_LIST_PMATCH], + &s->sm_lists[DETECT_SM_LIST_DMATCH], + &s->sm_lists_tail[DETECT_SM_LIST_DMATCH]); pm = pm1; } else { /* within is against pm1 and we continue this way */ @@ -130,10 +130,10 @@ static int DetectDistanceSetup (DetectEngineCtx *de_ctx, Signature *s, } else if (pm1->idx > dcem->idx) { /* transfer pm1 to dmatch list and within is against this */ SigMatchTransferSigMatchAcrossLists(pm1, - &s->sm_lists[DETECT_SM_LIST_PMATCH], - &s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - &s->sm_lists[DETECT_SM_LIST_DMATCH], - &s->sm_lists_tail[DETECT_SM_LIST_DMATCH]); + &s->sm_lists[DETECT_SM_LIST_PMATCH], + &s->sm_lists_tail[DETECT_SM_LIST_PMATCH], + &s->sm_lists[DETECT_SM_LIST_DMATCH], + &s->sm_lists_tail[DETECT_SM_LIST_DMATCH]); pm = pm1; } else { /* within is against pm1 and we continue this way */ @@ -149,10 +149,10 @@ static int DetectDistanceSetup (DetectEngineCtx *de_ctx, Signature *s, } else if (pm2_ots == NULL || pm2_ots->idx < dcem->idx) { /* trasnfer pm1 to dmatch list and pm = pm1 */ SigMatchTransferSigMatchAcrossLists(pm1, - &s->sm_lists[DETECT_SM_LIST_PMATCH], - &s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - &s->sm_lists[DETECT_SM_LIST_DMATCH], - &s->sm_lists_tail[DETECT_SM_LIST_DMATCH]); + &s->sm_lists[DETECT_SM_LIST_PMATCH], + &s->sm_lists_tail[DETECT_SM_LIST_PMATCH], + &s->sm_lists[DETECT_SM_LIST_DMATCH], + &s->sm_lists_tail[DETECT_SM_LIST_DMATCH]); pm = pm1; } else { /* within is against pm1, pm = pm1 */ @@ -160,19 +160,20 @@ static int DetectDistanceSetup (DetectEngineCtx *de_ctx, Signature *s, } } } else { - pm = SigMatchGetLastSMFromLists(s, 16, - 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], - DETECT_AL_HTTP_CLIENT_BODY, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_AL_HTTP_HEADER, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_AL_HTTP_RAW_HEADER, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_AL_HTTP_METHOD, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_AL_HTTP_COOKIE, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]); + pm = SigMatchGetLastSMFromLists(s, 18, + 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], + DETECT_AL_HTTP_CLIENT_BODY, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], + DETECT_AL_HTTP_SERVER_BODY, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], + DETECT_AL_HTTP_HEADER, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], + DETECT_AL_HTTP_RAW_HEADER, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], + DETECT_AL_HTTP_METHOD, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], + DETECT_AL_HTTP_COOKIE, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]); if (pm == NULL) { SCLogError(SC_ERR_WITHIN_MISSING_CONTENT, "within needs" "preceeding content, uricontent option, http_client_body, " - "http_header, http_raw_header, http_method, " + "http_server_body, http_header, http_raw_header, http_method, " "http_cookie or http_raw_uri option"); if (dubbed) SCFree(str); @@ -461,6 +462,73 @@ static int DetectDistanceSetup (DetectEngineCtx *de_ctx, Signature *s, break; + case DETECT_AL_HTTP_SERVER_BODY: + cd = (DetectContentData *)pm->ctx; + + 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; + } + } + } + + 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; + } + } + + cd->flags |= DETECT_CONTENT_DISTANCE; + + /* reassigning pm */ + pm = SigMatchGetLastSMFromLists(s, 4, + DETECT_AL_HTTP_SERVER_BODY, pm->prev, + DETECT_PCRE, pm->prev); + if (pm == NULL) { + SCLogError(SC_ERR_DISTANCE_MISSING_CONTENT, "distance for http_server_body " + "needs preceeding http_server_body 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; + case DETECT_AL_HTTP_HEADER: cd = (DetectContentData *)pm->ctx; if (cd->flags & DETECT_CONTENT_NEGATED) { diff --git a/src/detect-engine-hsbd.c b/src/detect-engine-hsbd.c new file mode 100644 index 0000000000..5a9dbf65c1 --- /dev/null +++ b/src/detect-engine-hsbd.c @@ -0,0 +1,2363 @@ +/* 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 + * \author Victor Julien + * + * \brief Handle HTTP response body match corresponding to http_server_body + * keyword. + * + */ + +#include "suricata-common.h" +#include "suricata.h" +#include "decode.h" + +#include "detect.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-parse.h" +#include "detect-engine-state.h" +#include "detect-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 response body. + * + * For accounting the last match in relative matching the + * det_ctx->payload_offset int 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 response body to inspect. + * \param payload_len Length of the response body. + * + * \retval 0 no match. + * \retval 1 match. + */ +static int DoInspectHttpServerBody(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_SERVER_BODY) { + if (payload_len == 0) { + SCReturnInt(0); + } + + DetectContentData *cd = (DetectContentData *)sm->ctx; + SCLogDebug("inspecting content %"PRIu32" payload_len %"PRIu32, cd->id, payload_len); + + //if (cd->flags & DETECT_CONTENT_HSBD_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 server body content + * and see if the others match then until we run out of matches */ + int r = DoInspectHttpServerBody(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 = DoInspectHttpServerBody(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 { + /* 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 = DoInspectHttpServerBody(de_ctx, det_ctx, s, sm->next, payload, + payload_len); + SCReturnInt(r); + } else { + SCReturnInt(1); + } +} + +/** + * \brief Helps buffer response bodies for different transactions and stores them + * away in detection code. + * + * \param de_ctx Detection Engine ctx. + * \param det_ctx Detection engine thread ctx. + * \param f Pointer to the flow. + * \param htp_state http state. + * + * \warning Make sure flow is locked. + */ +static void DetectEngineBufferHttpServerBodies(DetectEngineCtx *de_ctx, + DetectEngineThreadCtx *det_ctx, Flow *f, HtpState *htp_state) +{ + int idx = 0; + htp_tx_t *tx = NULL; + int i = 0; + + if (det_ctx->hsbd_buffers_list_len > 0) { + SCReturn; + } + + if (htp_state == NULL) { + SCLogDebug("no HTTP state"); + goto end; + } + + if (htp_state->connp == NULL || htp_state->connp->conn == NULL) { + SCLogDebug("HTP state has no conn(p)"); + goto end; + } + + /* get the transaction id */ + int tmp_idx = AppLayerTransactionGetInspectId(f); + /* error! get out of here */ + if (tmp_idx == -1) + goto end; + + /* let's get the transaction count. We need this to hold the server body + * buffer for each transaction */ + det_ctx->hsbd_buffers_list_len = list_size(htp_state->connp->conn->transactions) - tmp_idx; + /* no transactions?! cool. get out of here */ + if (det_ctx->hsbd_buffers_list_len == 0) + goto end; + + /* assign space to hold buffers. Each per transaction */ + det_ctx->hsbd_buffers = SCMalloc(det_ctx->hsbd_buffers_list_len * sizeof(uint8_t *)); + if (det_ctx->hsbd_buffers == NULL) { + goto end; + } + memset(det_ctx->hsbd_buffers, 0, det_ctx->hsbd_buffers_list_len * sizeof(uint8_t *)); + + det_ctx->hsbd_buffers_len = SCMalloc(det_ctx->hsbd_buffers_list_len * sizeof(uint32_t)); + if (det_ctx->hsbd_buffers_len == NULL) { + goto end; + } + memset(det_ctx->hsbd_buffers_len, 0, det_ctx->hsbd_buffers_list_len * sizeof(uint32_t)); + + idx = AppLayerTransactionGetInspectId(f); + if (idx == -1) { + goto end; + } + + int size = (int)list_size(htp_state->connp->conn->transactions); + for (; idx < size; idx++, i++) { + + tx = list_get(htp_state->connp->conn->transactions, idx); + if (tx == NULL) + continue; + + HtpTxUserData *htud = (HtpTxUserData *)htp_tx_get_user_data(tx); + if (htud == NULL) + continue; + + HtpBodyChunk *cur = htud->response_body.first; + + if (htud->response_body.nchunks == 0) { + SCLogDebug("No http chunks to inspect for this transacation"); + continue; + } else { + /* no chunks?!! move on to the next transaction */ + if (cur == NULL) { + SCLogDebug("No http chunks to inspect"); + continue; + } + + /* in case of chunked transfer encoding, we don't have the length + * of the response body until we see a chunk with length 0. This + * doesn't let us use the response body callback function to + * figure out the end of response body. Instead we do it here. If + * the length is 0, and we have already seen content, it indicates + * chunked transfer. We also check if the parser has truly seen + * the last chunk by checking the progress state for the + * transaction. If we are done parsing all the chunks, we would + * have it set to something other than TX_PROGRESS_REQ_BODY. + * Either ways we should be moving away from buffering in the end + * and running content validation on this buffer type of architecture + * to a stateful inspection, where we can inspect body chunks as and + * when they come */ + if (htud->response_body.content_len == 0) { + if ((htud->response_body.content_len_so_far > 0) && + tx->progress != TX_PROGRESS_REQ_BODY) { + /* final length of the body */ + htud->flags |= HTP_BODY_COMPLETE; + } + } + + /* inspect the body if the transfer is complete or we have hit + * our body size limit */ + if (!(htud->flags & HTP_BODY_COMPLETE)) { + SCLogDebug("we still haven't seen the entire response body. " + "Let's defer body inspection till we see the " + "entire body."); + continue; + } + + uint8_t *chunks_buffer = NULL; + int32_t chunks_buffer_len = 0; + while (cur != NULL) { + chunks_buffer_len += cur->len; + if ( (chunks_buffer = SCRealloc(chunks_buffer, chunks_buffer_len)) == NULL) { + goto end; + } + + memcpy(chunks_buffer + chunks_buffer_len - cur->len, cur->data, cur->len); + cur = cur->next; + } + /* store the buffers. We will need it for further inspection */ + det_ctx->hsbd_buffers[i] = chunks_buffer; + det_ctx->hsbd_buffers_len[i] = chunks_buffer_len; + + } /* else - if (htud->body.nchunks == 0) */ + } /* for (idx = AppLayerTransactionGetInspectId(f); .. */ + +end: + return; +} + +int DetectEngineRunHttpServerBodyMpm(DetectEngineCtx *de_ctx, + DetectEngineThreadCtx *det_ctx, Flow *f, HtpState *htp_state) +{ + int i; + uint32_t cnt = 0; + + /* bail before locking if we have nothing to do */ + if (det_ctx->hsbd_buffers_list_len == 0) { + SCMutexLock(&f->m); + DetectEngineBufferHttpServerBodies(de_ctx, det_ctx, f, htp_state); + SCMutexUnlock(&f->m); + } + + for (i = 0; i < det_ctx->hsbd_buffers_list_len; i++) { + cnt += HttpServerBodyPatternSearch(det_ctx, + det_ctx->hsbd_buffers[i], + det_ctx->hsbd_buffers_len[i]); + } + + return cnt; +} + + +/** + * \brief Do the http_server_body 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 DetectEngineInspectHttpServerBody(DetectEngineCtx *de_ctx, + DetectEngineThreadCtx *det_ctx, Signature *s, Flow *f, uint8_t flags, + void *alstate) +{ + SCEnter(); + int r = 0; + int i = 0; + + /* bail before locking if we have nothing to do */ + if (det_ctx->hsbd_buffers_list_len == 0) { + SCMutexLock(&f->m); + DetectEngineBufferHttpServerBodies(de_ctx, det_ctx, f, alstate); + SCMutexUnlock(&f->m); + } + + for (i = 0; i < det_ctx->hsbd_buffers_list_len; i++) { + uint8_t *hsbd_buffer = det_ctx->hsbd_buffers[i]; + uint32_t hsbd_buffer_len = det_ctx->hsbd_buffers_len[i]; + + if (hsbd_buffer == NULL) + continue; + + r = DoInspectHttpServerBody(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_HSBDMATCH], + hsbd_buffer, hsbd_buffer_len); + if (r == 1) { + break; + } + } + + SCReturnInt(r); +} + +/** + * \brief Clean the hsbd buffers. + * + * \param det_ctx Pointer to the detection engine thread ctx. + */ +void DetectEngineCleanHSBDBuffers(DetectEngineThreadCtx *det_ctx) +{ + if (det_ctx->hsbd_buffers_list_len != 0) { + int i; + for (i = 0; i < det_ctx->hsbd_buffers_list_len; i++) { + if (det_ctx->hsbd_buffers[i] != NULL) + SCFree(det_ctx->hsbd_buffers[i]); + } + if (det_ctx->hsbd_buffers != NULL) { + SCFree(det_ctx->hsbd_buffers); + det_ctx->hsbd_buffers = NULL; + } + if (det_ctx->hsbd_buffers_len != NULL) { + SCFree(det_ctx->hsbd_buffers_len); + det_ctx->hsbd_buffers_len = NULL; + } + det_ctx->hsbd_buffers_list_len = 0; + } + + return; +} + + +/***********************************Unittests**********************************/ + +#ifdef UNITTESTS + +static int DetectEngineHttpServerBodyTest01(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 ok\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 server body test\"; " + "content:\"message\"; http_server_body; " + "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 DetectEngineHttpServerBodyTest02(void) +{ + TcpSession ssn; + Packet *p1 = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http_buf1[] = + "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; + uint32_t http_len1 = sizeof(http_buf1) - 1; + uint8_t http_buf2[] = + "HTTP/1.0 200 ok\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 server body test\"; " + "content:\"ABC\"; http_server_body; 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 DetectEngineHttpServerBodyTest03(void) +{ + TcpSession ssn; + Packet *p1 = NULL; + Packet *p2 = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + int result = 0; + uint8_t http_buf1[] = + "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; + uint32_t http_len1 = sizeof(http_buf1) - 1; + uint8_t http_buf2[] = + "HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 17\r\n" + "\r\n" + "1234567"; + uint32_t http_len2 = sizeof(http_buf2) - 1; + uint8_t http_buf3[] = + "8901234ABC"; + 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 server body test\"; " + "content:\"ABC\"; http_server_body; offset:14; " + "sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + goto end; + } + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: \n"); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); + + if (PacketAlertCheck(p1, 1)) { + printf("sid 1 matched but shouldn't have\n"); + goto end; + } + + r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); + result = 0; + goto end; + } + + r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf3, http_len3); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + + if (!(PacketAlertCheck(p2, 1))) { + printf("sid 1 didn't match but should have"); + goto end; + } + + result = 1; + +end: + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p1, 1); + UTHFreePackets(&p2, 1); + return result; +} + +static int DetectEngineHttpServerBodyTest04(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 ok\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 server body test\"; " + "content:!\"abc\"; http_server_body; 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 DetectEngineHttpServerBodyTest05(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 ok\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 server body test\"; " + "content:\"abc\"; http_server_body; 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 DetectEngineHttpServerBodyTest06(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 ok\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 server body test\"; " + "content:!\"def\"; http_server_body; 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 DetectEngineHttpServerBodyTest07(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 ok\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 server body test\"; " + "content:!\"def\"; http_server_body; 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 DetectEngineHttpServerBodyTest08(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 ok\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 server body test\"; " + "content:!\"abc\"; http_server_body; 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 DetectEngineHttpServerBodyTest09(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 ok\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 server body test\"; " + "content:\"abc\"; http_server_body; depth:3; " + "content:\"def\"; http_server_body; 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 DetectEngineHttpServerBodyTest10(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 ok\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 server body test\"; " + "content:\"abc\"; http_server_body; depth:3; " + "content:!\"xyz\"; http_server_body; 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 DetectEngineHttpServerBodyTest11(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 ok\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 server body test\"; " + "content:\"abc\"; http_server_body; depth:3; " + "content:\"xyz\"; http_server_body; 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 DetectEngineHttpServerBodyTest12(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 ok\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 server body test\"; " + "content:\"ab\"; http_server_body; depth:2; " + "content:\"ef\"; http_server_body; 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 DetectEngineHttpServerBodyTest13(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 ok\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 server body test\"; " + "content:\"ab\"; http_server_body; depth:3; " + "content:!\"yz\"; http_server_body; 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 DetectEngineHttpServerBodyTest14(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 ok\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 server body test\"; " + "pcre:/ab/S; " + "content:\"ef\"; http_server_body; 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 DetectEngineHttpServerBodyTest15(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 ok\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 server body test\"; " + "pcre:/abc/S; " + "content:!\"xyz\"; http_server_body; 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 DetectEngineHttpServerBodyRegisterTests(void) +{ + +#ifdef UNITTESTS + UtRegisterTest("DetectEngineHttpServerBodyTest01", + DetectEngineHttpServerBodyTest01, 1); + UtRegisterTest("DetectEngineHttpServerBodyTest02", + DetectEngineHttpServerBodyTest02, 1); + UtRegisterTest("DetectEngineHttpServerBodyTest03", + DetectEngineHttpServerBodyTest03, 1); + UtRegisterTest("DetectEngineHttpServerBodyTest04", + DetectEngineHttpServerBodyTest04, 1); + UtRegisterTest("DetectEngineHttpServerBodyTest05", + DetectEngineHttpServerBodyTest05, 1); + UtRegisterTest("DetectEngineHttpServerBodyTest06", + DetectEngineHttpServerBodyTest06, 1); + UtRegisterTest("DetectEngineHttpServerBodyTest07", + DetectEngineHttpServerBodyTest07, 1); + UtRegisterTest("DetectEngineHttpServerBodyTest08", + DetectEngineHttpServerBodyTest08, 1); + UtRegisterTest("DetectEngineHttpServerBodyTest09", + DetectEngineHttpServerBodyTest09, 1); + UtRegisterTest("DetectEngineHttpServerBodyTest10", + DetectEngineHttpServerBodyTest10, 1); + UtRegisterTest("DetectEngineHttpServerBodyTest11", + DetectEngineHttpServerBodyTest11, 1); + UtRegisterTest("DetectEngineHttpServerBodyTest12", + DetectEngineHttpServerBodyTest12, 1); + UtRegisterTest("DetectEngineHttpServerBodyTest13", + DetectEngineHttpServerBodyTest13, 1); + UtRegisterTest("DetectEngineHttpServerBodyTest14", + DetectEngineHttpServerBodyTest14, 1); + UtRegisterTest("DetectEngineHttpServerBodyTest15", + DetectEngineHttpServerBodyTest15, 1); +#endif /* UNITTESTS */ + + return; +} +/** + * @} + */ diff --git a/src/detect-engine-hsbd.h b/src/detect-engine-hsbd.h new file mode 100644 index 0000000000..3efec785bc --- /dev/null +++ b/src/detect-engine-hsbd.h @@ -0,0 +1,39 @@ +/* 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_HSBD_H__ +#define __DETECT_ENGINE_HSBD_H__ + +#define ENGINE_HSBD_BUFFER_LIMIT 20000 + +#include "app-layer-htp.h" + +int DetectEngineRunHttpServerBodyMpm(DetectEngineCtx *, + DetectEngineThreadCtx *, Flow *f, HtpState *); +int DetectEngineInspectHttpServerBody(DetectEngineCtx *, + DetectEngineThreadCtx *, Signature *, Flow *, uint8_t, void *); + +void DetectEngineCleanHSBDBuffers(DetectEngineThreadCtx *); +void DetectEngineHttpServerBodyRegisterTests(void); + +#endif /* __DETECT_ENGINE_HSBD_H__ */ + diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index 0327179b2e..ff30f08d23 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -293,6 +293,31 @@ uint32_t HttpClientBodyPatternSearch(DetectEngineThreadCtx *det_ctx, SCReturnUInt(ret); } +/** \brief Http server body pattern match -- searches for one pattern per + * signature. + * + * \param det_ctx Detection engine thread ctx. + * \param body The request body to inspect. + * \param body_len Body length. + * + * \retval ret Number of matches. + */ +uint32_t HttpServerBodyPatternSearch(DetectEngineThreadCtx *det_ctx, + uint8_t *body, uint32_t body_len) +{ + SCEnter(); + + if (det_ctx->sgh->mpm_hsbd_ctx == NULL) + SCReturnUInt(0); + + uint32_t ret; + ret = mpm_table[det_ctx->sgh->mpm_hsbd_ctx->mpm_type]. + Search(det_ctx->sgh->mpm_hsbd_ctx, &det_ctx->mtcu, + &det_ctx->pmq, body, body_len); + + SCReturnUInt(ret); +} + /** * \brief Http header match -- searches for one pattern per signature. * @@ -712,6 +737,7 @@ static void PopulateMpmAddPatternToMpm(DetectEngineCtx *de_ctx, DetectContentData *cd = NULL; DetectContentData *ud = NULL; DetectContentData *hcbd = NULL; + DetectContentData *hsbd = NULL; DetectContentData *hhd = NULL; DetectContentData *hrhd = NULL; DetectContentData *hmd = NULL; @@ -953,6 +979,61 @@ static void PopulateMpmAddPatternToMpm(DetectEngineCtx *de_ctx, break; } /* case DETECT_AL_HTTP_CLIENT_BODY */ + case DETECT_AL_HTTP_SERVER_BODY: + { + hsbd = (DetectContentData *)mpm_sm->ctx; + if (hsbd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) { + /* add the content to the "hcbd" mpm */ + if (hsbd->flags & DETECT_CONTENT_NOCASE) { + mpm_table[sgh->mpm_hsbd_ctx->mpm_type]. + AddPatternNocase(sgh->mpm_hsbd_ctx, + hsbd->content + hsbd->fp_chop_offset, + hsbd->fp_chop_len, + 0, 0, hsbd->id, s->num, flags); + } else { + mpm_table[sgh->mpm_hsbd_ctx->mpm_type]. + AddPattern(sgh->mpm_hsbd_ctx, + hsbd->content + hsbd->fp_chop_offset, + hsbd->fp_chop_len, + 0, 0, hsbd->id, s->num, flags); + } + } else { + if (hsbd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) { + if (DETECT_CONTENT_IS_SINGLE(hsbd)) { + hsbd->flags |= DETECT_CONTENT_HSBD_MPM; + } + + /* see if we can bypass the match validation for this pattern */ + } else { + if (DETECT_CONTENT_IS_SINGLE(hsbd)) { + hsbd->flags |= DETECT_CONTENT_HSBD_MPM; + } + } /* else - if (hcbd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) */ + + /* add the content to the "hsbd" mpm */ + if (hsbd->flags & DETECT_CONTENT_NOCASE) { + mpm_table[sgh->mpm_hsbd_ctx->mpm_type]. + AddPatternNocase(sgh->mpm_hsbd_ctx, + hsbd->content, hsbd->content_len, + 0, 0, hsbd->id, s->num, flags); + } else { + mpm_table[sgh->mpm_hsbd_ctx->mpm_type]. + AddPattern(sgh->mpm_hsbd_ctx, + hsbd->content, hsbd->content_len, + 0, 0, hsbd->id, s->num, flags); + } + } + /* tell matcher we are inspecting uri */ + s->flags |= SIG_FLAG_MPM_HSBDCONTENT; + s->mpm_http_pattern_id = hsbd->id; + if (hsbd->flags & DETECT_CONTENT_NEGATED) + s->flags |= SIG_FLAG_MPM_HSBDCONTENT_NEG; + + sgh->flags |= SIG_GROUP_HEAD_MPM_HSBD; + + break; + } /* case DETECT_AL_HTTP_CLIENT_BODY */ + case DETECT_AL_HTTP_HEADER: { hhd = (DetectContentData *)mpm_sm->ctx; @@ -1516,6 +1597,8 @@ int PatternMatchPrepareGroup(DetectEngineCtx *de_ctx, SigGroupHead *sh) uint32_t has_co_uri = 0; /**< our sgh has uri inspecting content */ /* used to indicate if sgh has atleast one sig with http_client_body */ uint32_t has_co_hcbd = 0; + /* used to indicate if sgh has atleast one sig with http_server_body */ + uint32_t has_co_hsbd = 0; /* used to indicate if sgh has atleast one sig with http_header */ uint32_t has_co_hhd = 0; /* used to indicate if sgh has atleast one sig with http_raw_header */ @@ -1552,6 +1635,10 @@ int PatternMatchPrepareGroup(DetectEngineCtx *de_ctx, SigGroupHead *sh) has_co_hcbd = 1; } + if (s->sm_lists[DETECT_SM_LIST_HSBDMATCH] != NULL) { + has_co_hsbd = 1; + } + if (s->sm_lists[DETECT_SM_LIST_HHDMATCH] != NULL) { has_co_hhd = 1; } @@ -1585,6 +1672,9 @@ int PatternMatchPrepareGroup(DetectEngineCtx *de_ctx, SigGroupHead *sh) if (has_co_hcbd > 0) { sh->flags |= SIG_GROUP_HAVEHCBDCONTENT; } + if (has_co_hsbd > 0) { + sh->flags |= SIG_GROUP_HAVEHSBDCONTENT; + } if (has_co_hhd > 0) { sh->flags |= SIG_GROUP_HAVEHHDCONTENT; } @@ -1674,6 +1764,24 @@ int PatternMatchPrepareGroup(DetectEngineCtx *de_ctx, SigGroupHead *sh) #endif } + if (sh->flags & SIG_GROUP_HAVEHSBDCONTENT) { + if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE) { + sh->mpm_hsbd_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx->sgh_mpm_context_hsbd); + } else { + sh->mpm_hsbd_ctx = MpmFactoryGetMpmCtxForProfile(MPM_CTX_FACTORY_UNIQUE_CONTEXT); + } + if (sh->mpm_hsbd_ctx == NULL) { + SCLogDebug("sh->mpm_hsbd_ctx == NULL. This should never happen"); + exit(EXIT_FAILURE); + } + +#ifndef __SC_CUDA_SUPPORT__ + MpmInitCtx(sh->mpm_hsbd_ctx, de_ctx->mpm_matcher, -1); +#else + MpmInitCtx(sh->mpm_hsbd_ctx, de_ctx->mpm_matcher, de_ctx->cuda_rc_mod_handle); +#endif + } + if (sh->flags & SIG_GROUP_HAVEHHDCONTENT) { if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE) { sh->mpm_hhd_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx->sgh_mpm_context_hhd); @@ -1768,6 +1876,7 @@ int PatternMatchPrepareGroup(DetectEngineCtx *de_ctx, SigGroupHead *sh) sh->flags & SIG_GROUP_HAVESTREAMCONTENT || sh->flags & SIG_GROUP_HAVEURICONTENT || sh->flags & SIG_GROUP_HAVEHCBDCONTENT || + sh->flags & SIG_GROUP_HAVEHSBDCONTENT || sh->flags & SIG_GROUP_HAVEHHDCONTENT || sh->flags & SIG_GROUP_HAVEHRHDCONTENT || sh->flags & SIG_GROUP_HAVEHMDCONTENT || @@ -1821,6 +1930,17 @@ int PatternMatchPrepareGroup(DetectEngineCtx *de_ctx, SigGroupHead *sh) } } } + if (sh->mpm_hsbd_ctx != NULL) { + if (sh->mpm_hsbd_ctx->pattern_cnt == 0) { + MpmFactoryReClaimMpmCtx(sh->mpm_hsbd_ctx); + sh->mpm_hsbd_ctx = NULL; + } else { + if (sh->flags & SIG_GROUP_HAVEHSBDCONTENT) { + if (mpm_table[sh->mpm_hsbd_ctx->mpm_type].Prepare != NULL) + mpm_table[sh->mpm_hsbd_ctx->mpm_type].Prepare(sh->mpm_hsbd_ctx); + } + } + } if (sh->mpm_hhd_ctx != NULL) { if (sh->mpm_hhd_ctx->pattern_cnt == 0) { MpmFactoryReClaimMpmCtx(sh->mpm_hhd_ctx); diff --git a/src/detect-engine-mpm.h b/src/detect-engine-mpm.h index 0d852c9447..164b6dfa38 100644 --- a/src/detect-engine-mpm.h +++ b/src/detect-engine-mpm.h @@ -39,6 +39,7 @@ uint32_t PacketPatternSearch(DetectEngineThreadCtx *, Packet *); uint32_t UriPatternSearch(DetectEngineThreadCtx *, uint8_t *, uint16_t); uint32_t StreamPatternSearch(DetectEngineThreadCtx *, Packet *, StreamMsg *, uint8_t); uint32_t HttpClientBodyPatternSearch(DetectEngineThreadCtx *, uint8_t *, uint32_t); +uint32_t HttpServerBodyPatternSearch(DetectEngineThreadCtx *, uint8_t *, uint32_t); uint32_t HttpHeaderPatternSearch(DetectEngineThreadCtx *, uint8_t *, uint32_t); uint32_t HttpRawHeaderPatternSearch(DetectEngineThreadCtx *, uint8_t *, uint32_t); uint32_t HttpMethodPatternSearch(DetectEngineThreadCtx *, uint8_t *, uint32_t); diff --git a/src/detect-engine-state.c b/src/detect-engine-state.c index 8910a37638..f6618a472b 100644 --- a/src/detect-engine-state.c +++ b/src/detect-engine-state.c @@ -424,6 +424,10 @@ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, } SCLogDebug("inspecting http client body"); } + /* not inspecting in toserver direction */ + if (s->sm_lists[DETECT_SM_LIST_HSBDMATCH] != NULL) { + inspect_flags |= DE_STATE_FLAG_HSBD_INSPECT; + } if (s->sm_lists[DETECT_SM_LIST_HHDMATCH] != NULL) { inspect_flags |= DE_STATE_FLAG_HHD_INSPECT; if (DetectEngineInspectHttpHeader(de_ctx, det_ctx, s, f, @@ -494,6 +498,14 @@ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, if (s->sm_lists[DETECT_SM_LIST_HCBDMATCH] != NULL) { inspect_flags |= DE_STATE_FLAG_HCBD_INSPECT; } + if (s->sm_lists[DETECT_SM_LIST_HSBDMATCH] != NULL) { + inspect_flags |= DE_STATE_FLAG_HSBD_INSPECT; + if (DetectEngineInspectHttpServerBody(de_ctx, det_ctx, s, f, + flags, alstate) == 1) { + match_flags |= DE_STATE_FLAG_HSBD_MATCH; + } + SCLogDebug("inspecting http server body"); + } if (s->sm_lists[DETECT_SM_LIST_HHDMATCH] != NULL) { inspect_flags |= DE_STATE_FLAG_HHD_INSPECT; if (DetectEngineInspectHttpHeader(de_ctx, det_ctx, s, f, @@ -769,6 +781,12 @@ int DeStateDetectContinueDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, Dete } } } + /* not inspecting in toserver direction */ + if (s->sm_lists[DETECT_SM_LIST_HSBDMATCH] != NULL) { + if (!(item->flags & DE_STATE_FLAG_HSBD_MATCH)) { + inspect_flags |= DE_STATE_FLAG_HSBD_INSPECT; + } + } if (s->sm_lists[DETECT_SM_LIST_HHDMATCH] != NULL) { if (!(item->flags & DE_STATE_FLAG_HHD_MATCH)) { SCLogDebug("inspecting http header data"); @@ -857,10 +875,26 @@ int DeStateDetectContinueDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, Dete * if the sig requires something only the request has. The rest * will be inspected in the opposite direction. */ if (s->sm_lists[DETECT_SM_LIST_UMATCH] != NULL) { - inspect_flags |= DE_STATE_FLAG_URI_INSPECT; + if (!(item->flags & DE_STATE_FLAG_URI_MATCH)) { + inspect_flags |= DE_STATE_FLAG_URI_INSPECT; + } } if (s->sm_lists[DETECT_SM_LIST_HCBDMATCH] != NULL) { - inspect_flags |= DE_STATE_FLAG_HCBD_INSPECT; + if (!(item->flags & DE_STATE_FLAG_HCBD_MATCH)) { + inspect_flags |= DE_STATE_FLAG_HCBD_INSPECT; + } + } + if (s->sm_lists[DETECT_SM_LIST_HSBDMATCH] != NULL) { + if (!(item->flags & DE_STATE_FLAG_HSBD_MATCH)) { + SCLogDebug("inspecting http server body data"); + inspect_flags |= DE_STATE_FLAG_HSBD_INSPECT; + + if (DetectEngineInspectHttpServerBody(de_ctx, det_ctx, s, f, + flags, alstate) == 1) { + SCLogDebug("http server body matched"); + match_flags |= DE_STATE_FLAG_HSBD_MATCH; + } + } } if (s->sm_lists[DETECT_SM_LIST_HHDMATCH] != NULL) { inspect_flags |= DE_STATE_FLAG_HHD_INSPECT; @@ -879,7 +913,9 @@ int DeStateDetectContinueDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, Dete SCLogDebug("inspecting http raw header"); } if (s->sm_lists[DETECT_SM_LIST_HMDMATCH] != NULL) { - inspect_flags |= DE_STATE_FLAG_HMD_INSPECT; + if (!(item->flags & DE_STATE_FLAG_HMD_MATCH)) { + inspect_flags |= DE_STATE_FLAG_HMD_INSPECT; + } } if (s->sm_lists[DETECT_SM_LIST_HCDMATCH] != NULL) { inspect_flags |= DE_STATE_FLAG_HCD_INSPECT; @@ -890,7 +926,9 @@ int DeStateDetectContinueDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, Dete SCLogDebug("inspecting http cookie"); } if (s->sm_lists[DETECT_SM_LIST_HRUDMATCH] != NULL) { - inspect_flags |= DE_STATE_FLAG_HRUD_INSPECT; + if (!(item->flags & DE_STATE_FLAG_HRUD_MATCH)) { + inspect_flags |= DE_STATE_FLAG_HRUD_INSPECT; + } } if (s->sm_lists[DETECT_SM_LIST_FILEMATCH] != NULL) { if (!(item->flags & DE_STATE_FLAG_FILE_TC_MATCH)) { @@ -980,6 +1018,7 @@ int DeStateDetectContinueDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, Dete /* mark the sig as matched */ item->nm = NULL; + SCLogDebug("inspect_flags %04x match_flags %04x", inspect_flags, match_flags); if (inspect_flags == 0 || (inspect_flags == match_flags)) { det_ctx->de_state_sig_array[item->sid] = DE_STATE_MATCH_NEW; SCLogDebug("state set to %s", DeStateMatchResultToString(DE_STATE_MATCH_NEW)); @@ -991,6 +1030,7 @@ int DeStateDetectContinueDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, Dete } } } else { + SCLogDebug("inspect_flags %04x match_flags %04x", inspect_flags, match_flags); if (inspect_flags != 0 && (inspect_flags == match_flags)) { det_ctx->de_state_sig_array[item->sid] = DE_STATE_MATCH_NEW; SCLogDebug("state set to %s", DeStateMatchResultToString(DE_STATE_MATCH_NEW)); diff --git a/src/detect-engine-state.h b/src/detect-engine-state.h index 71dd3c680f..d65a790736 100644 --- a/src/detect-engine-state.h +++ b/src/detect-engine-state.h @@ -55,19 +55,21 @@ #define DE_STATE_FLAG_URI_MATCH 0x0002 /**< uri part of the sig matched */ #define DE_STATE_FLAG_DCE_MATCH 0x0004 /**< dce payload inspection part matched */ #define DE_STATE_FLAG_HCBD_MATCH 0x0008 /**< hcbd payload inspection part matched */ -#define DE_STATE_FLAG_HHD_MATCH 0x0010 /**< hhd payload inspection part matched */ -#define DE_STATE_FLAG_HRHD_MATCH 0x0020 /**< hrhd payload inspection part matched */ -#define DE_STATE_FLAG_HMD_MATCH 0x0040 /**< hmd payload inspection part matched */ -#define DE_STATE_FLAG_HCD_MATCH 0x0080 /**< hcd payload inspection part matched */ -#define DE_STATE_FLAG_HRUD_MATCH 0x0100 /**< hrud payload inspection part matched */ -#define DE_STATE_FLAG_FILE_TC_MATCH 0x0200 -#define DE_STATE_FLAG_FILE_TS_MATCH 0x0400 -#define DE_STATE_FLAG_FULL_MATCH 0x0800 /**< sig already fully matched */ -#define DE_STATE_FLAG_SIG_CANT_MATCH 0x1000 /**< signature has no chance of matching */ +#define DE_STATE_FLAG_HSBD_MATCH 0x0010 /**< hcbd payload inspection part matched */ +#define DE_STATE_FLAG_HHD_MATCH 0x0020 /**< hhd payload inspection part matched */ +#define DE_STATE_FLAG_HRHD_MATCH 0x0040 /**< hrhd payload inspection part matched */ +#define DE_STATE_FLAG_HMD_MATCH 0x0080 /**< hmd payload inspection part matched */ +#define DE_STATE_FLAG_HCD_MATCH 0x0100 /**< hcd payload inspection part matched */ +#define DE_STATE_FLAG_HRUD_MATCH 0x0200 /**< hrud payload inspection part matched */ +#define DE_STATE_FLAG_FILE_TC_MATCH 0x0400 +#define DE_STATE_FLAG_FILE_TS_MATCH 0x0800 +#define DE_STATE_FLAG_FULL_MATCH 0x1000 /**< sig already fully matched */ +#define DE_STATE_FLAG_SIG_CANT_MATCH 0x2000 /**< signature has no chance of matching */ #define DE_STATE_FLAG_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 */ #define DE_STATE_FLAG_HCBD_INSPECT DE_STATE_FLAG_HCBD_MATCH /**< hcbd payload inspection part inspected */ +#define DE_STATE_FLAG_HSBD_INSPECT DE_STATE_FLAG_HSBD_MATCH /**< hsbd payload inspection part inspected */ #define DE_STATE_FLAG_HHD_INSPECT DE_STATE_FLAG_HHD_MATCH /**< hhd payload inspection part inspected */ #define DE_STATE_FLAG_HRHD_INSPECT DE_STATE_FLAG_HRHD_MATCH /**< hrhd payload inspection part inspected */ #define DE_STATE_FLAG_HMD_INSPECT DE_STATE_FLAG_HMD_MATCH /**< hmd payload inspection part inspected */ diff --git a/src/detect-fast-pattern.c b/src/detect-fast-pattern.c index 19c0b5228e..9ee9b2b797 100644 --- a/src/detect-fast-pattern.c +++ b/src/detect-fast-pattern.c @@ -128,6 +128,9 @@ void SupportFastPatternForSigMatchTypes(void) SupportFastPatternForSigMatchType(DETECT_AL_HTTP_CLIENT_BODY); SupportFastPatternForSigMatchList(DETECT_SM_LIST_HCBDMATCH); + SupportFastPatternForSigMatchType(DETECT_AL_HTTP_SERVER_BODY); + SupportFastPatternForSigMatchList(DETECT_SM_LIST_HSBDMATCH); + SupportFastPatternForSigMatchType(DETECT_AL_HTTP_HEADER); SupportFastPatternForSigMatchList(DETECT_SM_LIST_HHDMATCH); @@ -210,6 +213,7 @@ static int DetectFastPatternSetup(DetectEngineCtx *de_ctx, Signature *s, char *a if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] == NULL && s->sm_lists_tail[DETECT_SM_LIST_UMATCH] == NULL && s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH] == NULL && + s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH] == NULL && s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH] == NULL && s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH] == NULL && s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH] == NULL && @@ -218,21 +222,22 @@ static int DetectFastPatternSetup(DetectEngineCtx *de_ctx, Signature *s, char *a 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_header, " + "uricontent, http_client_body, http_server_body, http_header, " "http_raw_header, http_method, http_cookie or " "http_raw_uri option"); return -1; } - SigMatch *pm = SigMatchGetLastSMFromLists(s, 16, - 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], - DETECT_AL_HTTP_HEADER, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_AL_HTTP_RAW_HEADER, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_AL_HTTP_METHOD, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_AL_HTTP_COOKIE, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_AL_HTTP_RAW_URI, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]); + SigMatch *pm = SigMatchGetLastSMFromLists(s, 18, + 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], + DETECT_AL_HTTP_SERVER_BODY, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], + DETECT_AL_HTTP_HEADER, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], + DETECT_AL_HTTP_RAW_HEADER, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], + DETECT_AL_HTTP_METHOD, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], + DETECT_AL_HTTP_COOKIE, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], + DETECT_AL_HTTP_RAW_URI, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]); if (pm == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "fast_pattern found inside " "the rule, without a content context. Please use a " diff --git a/src/detect-http-client-body.c b/src/detect-http-client-body.c index 60bfd83acf..aec2475954 100644 --- a/src/detect-http-client-body.c +++ b/src/detect-http-client-body.c @@ -2447,7 +2447,7 @@ int DetectHttpClientBodyTest34(void) DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; DetectContentData *hcbd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; - if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT | DETECT_PCRE_HTTP_BODY_AL) || + if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT | DETECT_PCRE_HTTP_CLIENT_BODY) || hcbd2->flags != DETECT_CONTENT_WITHIN || memcmp(hcbd2->content, "two", hcbd2->content_len) != 0) { goto end; @@ -2498,7 +2498,7 @@ int DetectHttpClientBodyTest35(void) DetectContentData *hcbd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; DetectPcreData *pd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; - if (pd2->flags != (DETECT_PCRE_RELATIVE | DETECT_PCRE_HTTP_BODY_AL) || + if (pd2->flags != (DETECT_PCRE_RELATIVE | DETECT_PCRE_HTTP_CLIENT_BODY) || hcbd1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(hcbd1->content, "two", hcbd1->content_len) != 0) { goto end; @@ -2549,7 +2549,7 @@ int DetectHttpClientBodyTest36(void) DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; DetectContentData *hcbd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; - if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT | DETECT_PCRE_HTTP_BODY_AL) || + if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT | DETECT_PCRE_HTTP_CLIENT_BODY) || hcbd2->flags != DETECT_CONTENT_DISTANCE || memcmp(hcbd2->content, "two", hcbd2->content_len) != 0) { goto end; diff --git a/src/detect-http-server-body.c b/src/detect-http-server-body.c new file mode 100644 index 0000000000..527c36dff2 --- /dev/null +++ b/src/detect-http-server-body.c @@ -0,0 +1,2708 @@ +/* Copyright (C) 2007-2011 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 + * \author Victor Julien + * + * Implements support for the http_server_body keyword + */ + +#include "suricata-common.h" +#include "threads.h" +#include "decode.h" + +#include "detect.h" +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-state.h" +#include "detect-content.h" +#include "detect-pcre.h" + +#include "flow.h" +#include "flow-var.h" +#include "flow-util.h" + +#include "util-debug.h" +#include "util-unittest.h" +#include "util-unittest-helper.h" +#include "util-spm.h" + +#include "app-layer.h" + +#include +#include "app-layer-htp.h" +#include "detect-http-server-body.h" +#include "stream-tcp.h" + +int DetectHttpServerBodySetup(DetectEngineCtx *, Signature *, char *); +void DetectHttpServerBodyRegisterTests(void); +void DetectHttpServerBodyFree(void *); + +/** + * \brief Registers the keyword handlers for the "http_server_body" keyword. + */ +void DetectHttpServerBodyRegister(void) +{ + sigmatch_table[DETECT_AL_HTTP_SERVER_BODY].name = "http_server_body"; + sigmatch_table[DETECT_AL_HTTP_SERVER_BODY].Match = NULL; + sigmatch_table[DETECT_AL_HTTP_SERVER_BODY].AppLayerMatch = NULL; + sigmatch_table[DETECT_AL_HTTP_SERVER_BODY].Setup = DetectHttpServerBodySetup; + sigmatch_table[DETECT_AL_HTTP_SERVER_BODY].Free = DetectHttpServerBodyFree; + sigmatch_table[DETECT_AL_HTTP_SERVER_BODY].RegisterTests = DetectHttpServerBodyRegisterTests; + sigmatch_table[DETECT_AL_HTTP_SERVER_BODY].alproto = ALPROTO_HTTP; + + sigmatch_table[DETECT_AL_HTTP_SERVER_BODY].flags |= SIGMATCH_PAYLOAD ; +} + +/** + * \brief The setup function for the http_server_body keyword for a signature. + * + * \param de_ctx Pointer to the detection engine context. + * \param s Pointer to signature for the current Signature being parsed + * from the rules. + * \param m Pointer to the head of the SigMatchs for the current rule + * being parsed. + * \param arg Pointer to the string holding the keyword value. + * + * \retval 0 On success + * \retval -1 On failure + */ +int DetectHttpServerBodySetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) +{ + DetectContentData *cd = NULL; + SigMatch *sm = NULL; + + if (arg != NULL && strcmp(arg, "") != 0) { + SCLogError(SC_ERR_INVALID_ARGUMENT, "http_server_body supplied with args"); + return -1; + } + + 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_server_body\" keyword " + "found inside the rule without a content context. " + "Please use a \"content\" keyword before using the " + "\"http_server_body\" keyword"); + return -1; + } + + cd = (DetectContentData *)sm->ctx; + + /* http_server_body should not be used with the rawbytes rule */ + if (cd->flags & DETECT_CONTENT_RAWBYTES) { + SCLogError(SC_ERR_INVALID_SIGNATURE, "http_server_body rule can not " + "be used with the rawbytes rule keyword"); + return -1; + } + + if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_HTTP) { + SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains a non http " + "alproto set"); + goto error; + } + + if (cd->flags & DETECT_CONTENT_WITHIN || cd->flags & DETECT_CONTENT_DISTANCE) { + SigMatch *pm = SigMatchGetLastSMFromLists(s, 4, + DETECT_CONTENT, sm->prev, + DETECT_PCRE, sm->prev); + /* pm can be NULL now. To accomodate parsing sigs like - + * content:one; http_modifier; content:two; distance:0; http_modifier */ + if (pm != NULL) { + if (pm->type == DETECT_CONTENT) { + DetectContentData *tmp_cd = (DetectContentData *)pm->ctx; + tmp_cd->flags &= ~DETECT_CONTENT_RELATIVE_NEXT; + } else { + DetectPcreData *tmp_pd = (DetectPcreData *)pm->ctx; + tmp_pd->flags &= ~ DETECT_PCRE_RELATIVE_NEXT; + } + + } /* if (pm != NULL) */ + + /* reassigning pm */ + pm = SigMatchGetLastSMFromLists(s, 4, + DETECT_AL_HTTP_SERVER_BODY, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], + DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]); + if (pm == NULL) { + SCLogError(SC_ERR_INVALID_SIGNATURE, "http_server_body seen with a " + "distance or within without a previous http_server_body " + "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_SERVER_BODY); + sm->type = DETECT_AL_HTTP_SERVER_BODY; + + /* transfer the sm from the pmatch list to hsbdmatch list */ + SigMatchTransferSigMatchAcrossLists(sm, + &s->sm_lists[DETECT_SM_LIST_PMATCH], + &s->sm_lists_tail[DETECT_SM_LIST_PMATCH], + &s->sm_lists[DETECT_SM_LIST_HSBDMATCH], + &s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]); + + /* flag the signature to indicate that we scan the app layer data */ + s->flags |= SIG_FLAG_APPLAYER; + s->alproto = ALPROTO_HTTP; + + /* enable http request body callback in the http app layer parser */ + AppLayerHtpEnableResponseBodyCallback(); + + return 0; + +error: + //if (cd != NULL) + // DetectHttpServerBodyFree(cd); + //if (sm != NULL) + // SCFree(sm); + + return -1; +} + +/** + * \brief The function to free the http_server_body data. + * + * \param ptr Pointer to the http_server_body. + */ +void DetectHttpServerBodyFree(void *ptr) +{ + SCEnter(); + DetectContentData *hsbd = (DetectContentData *)ptr; + if (hsbd == NULL) + SCReturn; + + if (hsbd->content != NULL) + SCFree(hsbd->content); + + BoyerMooreCtxDeInit(hsbd->bm_ctx); + SCFree(hsbd); + + SCReturn; +} + +/************************************Unittests*********************************/ + +#ifdef UNITTESTS + +#include "stream-tcp-reassemble.h" + +/** + * \test Test that a signature containting a http_server_body is correctly parsed + * and the keyword is registered. + */ +static int DetectHttpServerBodyTest01(void) +{ + DetectEngineCtx *de_ctx = NULL; + int result = 0; + SigMatch *sm = NULL; + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " + "(msg:\"Testing http_server_body\"; " + "content:\"one\"; http_server_body; sid:1;)"); + if (de_ctx->sig_list == NULL) { + goto end; + } + + /* sm should not be in the MATCH list */ + sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_MATCH]; + if (sm != NULL) { + goto end; + } + + sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH]; + if (sm == NULL) { + goto end; + } + + if (sm->type != DETECT_AL_HTTP_SERVER_BODY) { + printf("sm type not DETECT_AL_HTTP_SERVER_BODY: "); + goto end; + } + + if (sm->next != NULL) { + goto end; + } + + result = 1; +end: + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + + return result; +} + +/** + * \test Test that a signature containing an valid http_server_body entry is + * parsed. + */ +static int DetectHttpServerBodyTest02(void) +{ + DetectEngineCtx *de_ctx = NULL; + int result = 0; + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " + "(msg:\"Testing http_server_body\"; " + "content:\"one\"; http_server_body:; sid:1;)"); + if (de_ctx->sig_list != NULL) + result = 1; + + end: + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + + return result; +} + +/** + * \test Test that an invalid signature containing no content but a http_server_body + * is invalidated. + */ +static int DetectHttpServerBodyTest03(void) +{ + DetectEngineCtx *de_ctx = NULL; + int result = 0; + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " + "(msg:\"Testing http_server_body\"; " + "http_server_body; sid:1;)"); + if (de_ctx->sig_list == NULL) + result = 1; + + end: + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + + return result; +} + +/** + * \test Test that an invalid signature containing a rawbytes along with a + * http_server_body is invalidated. + */ +static int DetectHttpServerBodyTest04(void) +{ + DetectEngineCtx *de_ctx = NULL; + int result = 0; + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " + "(msg:\"Testing http_server_body\"; " + "content:\"one\"; rawbytes; http_server_body; sid:1;)"); + if (de_ctx->sig_list == NULL) + result = 1; + + end: + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + + return result; +} + +/** + * \test Test that an invalid signature containing a rawbytes along with a + * http_server_body is invalidated. + */ +static int DetectHttpServerBodyTest05(void) +{ + DetectEngineCtx *de_ctx = NULL; + int result = 0; + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " + "(msg:\"Testing http_server_body\"; " + "content:\"one\"; http_server_body; nocase; sid:1;)"); + if (de_ctx->sig_list != NULL) + result = 1; + + end: + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + + return result; +} + +/** + *\test Test that the http_server_body content matches against a http request + * which holds the content. + */ +static int DetectHttpServerBodyTest06(void) +{ + TcpSession ssn; + Packet *p = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http_buf[] = + "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: 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_len = sizeof(http_buf) - 1; + uint8_t http_buf2[] = + "HTTP/1.0 200 ok\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)); + + p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.flags |= FLOW_IPV4; + + p->flow = &f; + p->flowflags |= FLOW_PKT_TOCLIENT; + p->flowflags |= FLOW_PKT_ESTABLISHED; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + 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 server body test\"; " + "content:\"message\"; http_server_body; " + "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|STREAM_START|STREAM_EOF, http_buf, http_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + goto end; + } + r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_START|STREAM_EOF, 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, p); + + if (!(PacketAlertCheck(p, 1))) { + printf("sid 1 didn't match but should have: "); + goto end; + } + + result = 1; +end: + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); + return result; +} + +/** + *\test Test that the http_server_body content matches against a http request + * which holds the content. + */ +static int DetectHttpServerBodyTest07(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 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 14\r\n" + "\r\n" + "message"; + uint32_t http_len2 = sizeof(http_buf2) - 1; + uint8_t http_buf3[] = + "message"; + uint32_t http_len3 = sizeof(http_buf3) - 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_TOCLIENT; + 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 server body test\"; " + "content:\"message\"; http_server_body; " + "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|STREAM_START|STREAM_EOF, 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|STREAM_START, http_buf2, http_len2); + if (r != 0) { + printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); + result = 0; + goto end; + } + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: "); + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); + + if (!(PacketAlertCheck(p1, 1))) { + printf("sid 1 didn't match on p1 but should have: "); + goto end; + } + + r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_EOF, http_buf3, http_len3); + if (r != 0) { + printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + if (PacketAlertCheck(p2, 1)) { + printf("sid 1 matched on p2 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; +} + +/** + *\test Test that the http_server_body content matches against a http request + * which holds the content. + */ +static int DetectHttpServerBodyTest08(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 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 14\r\n" + "\r\n" + "bigmes"; + uint32_t http_len2 = sizeof(http_buf2) - 1; + uint8_t http_buf3[] = + "sage4u!!"; + uint32_t http_len3 = sizeof(http_buf3) - 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_TOCLIENT; + 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 client body test\"; " + "content:\"message\"; http_server_body; " + "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|STREAM_START, 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: "); + result = 0; + goto end; + } + + r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_START, http_buf2, http_len2); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); + + if ((PacketAlertCheck(p1, 1))) { + printf("sid 1 matched but shouldn't have: "); + goto end; + } + + r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_EOF, http_buf3, http_len3); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + + if (!(PacketAlertCheck(p2, 1))) { + printf("sid 1 didn't match but should have: "); + goto end; + } + + result = 1; +end: + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p1, 1); + UTHFreePackets(&p2, 1); + return result; +} + +/** + *\test Test that the http_server_body content matches against a http request + * which holds the content. + */ +static int DetectHttpServerBodyTest09(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 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 14\r\n" + "\r\n" + "bigmes"; + uint32_t http_len2 = sizeof(http_buf2) - 1; + uint8_t http_buf3[] = + "sag"; + uint32_t http_len3 = sizeof(http_buf3) - 1; + uint8_t http_buf4[] = + "e4u!!"; + uint32_t http_len4 = sizeof(http_buf4) - 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_TOCLIENT; + 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 client body test\"; " + "content:\"message\"; http_server_body; " + "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|STREAM_START, 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: "); + result = 0; + goto end; + } + + r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_START, http_buf2, http_len2); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); + + if ((PacketAlertCheck(p1, 1))) { + printf("sid 1 matched but shouldn't have: "); + goto end; + } + + r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_EOF, http_buf3, http_len3); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + goto end; + } + + r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_EOF, http_buf4, http_len4); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + + if (!(PacketAlertCheck(p2, 1))) { + printf("sid 1 didn't match but should have: "); + goto end; + } + + result = 1; +end: + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p1, 1); + UTHFreePackets(&p2, 1); + return result; +} + +/** + *\test Test that the http_server_body content matches against a http request + * which holds the content. Case insensitve. + */ +static int DetectHttpServerBodyTest10(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 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 14\r\n" + "\r\n" + "bigmes"; + uint32_t http_len2 = sizeof(http_buf2) - 1; + uint8_t http_buf3[] = + "sag"; + uint32_t http_len3 = sizeof(http_buf3) - 1; + uint8_t http_buf4[] = + "e4u!!"; + uint32_t http_len4 = sizeof(http_buf4) - 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_TOCLIENT; + 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 client body test\"; " + "content:\"MeSSaGE\"; http_server_body; nocase; " + "sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, 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: "); + result = 0; + goto end; + } + + r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_START, http_buf2, http_len2); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); + + if ((PacketAlertCheck(p1, 1))) { + printf("sid 1 matched but shouldn't have: "); + goto end; + } + + r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_EOF, http_buf3, http_len3); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + goto end; + } + + r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_EOF, http_buf4, http_len4); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + + if (!(PacketAlertCheck(p2, 1))) { + printf("sid 1 didn't match but should have: "); + goto end; + } + + result = 1; +end: + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p1, 1); + UTHFreePackets(&p2, 1); + return result; +} + +/** + *\test Test that the http_server_body content matches against a http request + * which holds the content. Negated match. + */ +static int DetectHttpServerBodyTest11(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 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 14\r\n" + "\r\n"; + uint32_t http_len2 = sizeof(http_buf2) - 1; + uint8_t http_buf3[] = + "bigmessage4u!!"; + uint32_t http_len3 = sizeof(http_buf3) - 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_TOCLIENT; + 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 client body test\"; " + "content:!\"MaSSaGE\"; http_server_body; nocase; " + "sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, 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: "); + result = 0; + goto end; + } + + r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_START, http_buf2, http_len2); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); + + if (PacketAlertCheck(p1, 1)) { + printf("sid 1 matched but shouldn't have (p1): "); + goto end; + } + + r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_EOF, http_buf3, http_len3); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + + if (!(PacketAlertCheck(p2, 1))) { + printf("sid 1 didn't match but should have (p2): "); + goto end; + } + + result = 1; +end: + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p1, 1); + UTHFreePackets(&p2, 1); + return result; +} + +/** + *\test Test that the http_server_body content matches against a http request + * which holds the content. Negated match. + */ +static int DetectHttpServerBodyTest12(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 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 14\r\n" + "\r\n"; + uint32_t http_len2 = sizeof(http_buf2) - 1; + uint8_t http_buf3[] = + "bigmessage4u!!"; + uint32_t http_len3 = sizeof(http_buf3) - 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_TOCLIENT; + 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 client body test\"; " + "content:!\"MeSSaGE\"; http_server_body; nocase; " + "sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, 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: "); + result = 0; + goto end; + } + + r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_START, http_buf2, http_len2); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); + + if (PacketAlertCheck(p1, 1)) { + printf("sid 1 matched but shouldn't have (p1): "); + goto end; + } + + r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_EOF, http_buf3, http_len3); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + + if (PacketAlertCheck(p2, 1)) { + printf("sid 1 matched but shouldn't have (p2): "); + 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 DetectHttpServerBodyTest13(void) +{ + TcpSession ssn; + Packet *p = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http_buf[] = + "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: 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_len = sizeof(http_buf) - 1; + uint8_t http_buf2[] = + "HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 55\r\n" + "\r\n" + "longbufferabcdefghijklmnopqrstuvwxyz0123456789bufferend"; + 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)); + + p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.flags |= FLOW_IPV4; + + p->flow = &f; + p->flowflags |= FLOW_PKT_TOCLIENT; + p->flowflags |= FLOW_PKT_ESTABLISHED; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + 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 server body test\"; " + "content:\"longbufferabcdefghijklmnopqrstuvwxyz0123456789bufferend\"; http_server_body; " + "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|STREAM_START|STREAM_EOF, http_buf, http_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + goto end; + } + r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_START|STREAM_EOF, 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, p); + + if (!(PacketAlertCheck(p, 1))) { + printf("sid 1 didn't match but should have: "); + goto end; + } + + result = 1; +end: + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); + return result; +} + +/** \test multiple http transactions and body chunks of request handling */ +static int DetectHttpServerBodyTest14(void) { + int result = 0; + Signature *s = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + ThreadVars th_v; + Flow f; + TcpSession ssn; + Packet *p = NULL; + uint8_t httpbuf1[] = "GET /index1.html HTTP/1.1\r\n" + "User-Agent: Mozilla/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Connection: keep-alive\r\n" + "Cookie: dummy1\r\n\r\n"; + uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ + uint8_t httpbuf2[] = "HTTP/1.1 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 3\r\n" + "\r\n" + "one"; + uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ + uint8_t httpbuf3[] = "GET /index2.html HTTP/1.1\r\n" + "User-Agent: Firefox/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Connection: keep-alive\r\n" + "Cookie: dummy2\r\n\r\n"; + uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */ + uint8_t httpbuf4[] = "HTTP/1.1 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 3\r\n" + "\r\n" + "two"; + uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */ + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p->flow = &f; + p->flowflags |= FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_ESTABLISHED; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) { + goto end; + } + + de_ctx->flags |= DE_QUIET; + + s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"GET\"; http_method; content:\"Mozilla\"; http_header; content:\"dummy1\"; http_cookie; content:\"one\"; http_server_body; sid:1; rev:1;)"); + if (s == NULL) { + printf("sig parse failed: "); + goto end; + } + s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"GET\"; http_method; content:\"Firefox\"; http_header; content:\"dummy2\"; http_cookie; content:\"two\"; http_server_body; sid:2; rev:1;)"); + if (s == NULL) { + printf("sig2 parse failed: "); + goto end; + } + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, httpbuf1, httplen1); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + if (PacketAlertCheck(p, 1)) { + printf("sig 1 alerted (tx 1): "); + goto end; + } + p->alerts.cnt = 0; + + p->flowflags &= ~FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_TOCLIENT; + + r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT, httpbuf2, httplen2); + if (r != 0) { + printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + if (!(PacketAlertCheck(p, 1))) { + printf("sig 1 didn't alert (tx 1): "); + goto end; + } + p->alerts.cnt = 0; + + p->flowflags &= ~FLOW_PKT_TOCLIENT; + p->flowflags |= FLOW_PKT_TOSERVER; + + r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf3, httplen3); + if (r != 0) { + printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + if (PacketAlertCheck(p, 1)) { + printf("sig 1 matched, but shouldn't have (tx 2): "); + goto end; + } + if ((PacketAlertCheck(p, 2))) { + printf("sig 2 alerted (tx 2): "); + goto end; + } + p->alerts.cnt = 0; + + p->flowflags &= ~FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_TOCLIENT; + + r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_EOF, httpbuf4, httplen4); + if (r != 0) { + printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + if ((PacketAlertCheck(p, 1))) { + printf("sig 1 alerted (tx 2): "); + goto end; + } + if (!(PacketAlertCheck(p, 2))) { + printf("sig 2 didn't alert (tx 2): "); + goto end; + } + p->alerts.cnt = 0; + + HtpState *htp_state = f.alstate; + if (htp_state == NULL) { + printf("no http state: "); + goto end; + } + + if (list_size(htp_state->connp->conn->transactions) != 2) { + printf("The http app layer doesn't have 2 transactions, but it should: "); + goto end; + } + + result = 1; +end: + if (det_ctx != NULL) { + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + } + if (de_ctx != NULL) { + SigGroupCleanup(de_ctx); + DetectEngineCtxFree(de_ctx); + } + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePacket(p); + return result; +} + +static int DetectHttpServerBodyTest15(void) { + int result = 0; + Signature *s = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + ThreadVars th_v; + Flow f; + TcpSession ssn; + Packet *p = NULL; + uint8_t httpbuf1[] = "GET /index1.html HTTP/1.1\r\n" + "User-Agent: Mozilla/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Connection: keep-alive\r\n" + "Cookie: dummy1\r\n\r\n"; + uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ + uint8_t httpbuf2[] = "HTTP/1.1 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 3\r\n" + "\r\n" + "one"; + uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ + uint8_t httpbuf3[] = "GET /index2.html HTTP/1.1\r\n" + "User-Agent: Firefox/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Connection: keep-alive\r\n" + "Cookie: dummy2\r\n\r\n"; + uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */ + uint8_t httpbuf4[] = "HTTP/1.1 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 3\r\n" + "\r\n" + "two"; + uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */ + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p->flow = &f; + p->flowflags |= FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_ESTABLISHED; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) { + goto end; + } + + de_ctx->flags |= DE_QUIET; + + s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"GET\"; http_method; content:\"index1\"; http_uri; content:\"Mozilla\"; http_header; content:\"dummy1\"; http_cookie; content:\"one\"; http_server_body; sid:1; rev:1;)"); + if (s == NULL) { + printf("sig parse failed: "); + goto end; + } + s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"GET\"; http_method; content:\"index2\"; http_uri; content:\"Firefox\"; http_header; content:\"dummy2\"; http_cookie; content:\"two\"; http_server_body; sid:2; rev:1;)"); + if (s == NULL) { + printf("sig2 parse failed: "); + goto end; + } + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, httpbuf1, httplen1); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + if (PacketAlertCheck(p, 1)) { + printf("sig 1 alerted (tx 1): "); + goto end; + } + p->alerts.cnt = 0; + + p->flowflags &= ~FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_TOCLIENT; + + r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT, httpbuf2, httplen2); + if (r != 0) { + printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + if (!(PacketAlertCheck(p, 1))) { + printf("sig 1 didn't alert (tx 1): "); + goto end; + } + p->alerts.cnt = 0; + + p->flowflags &= ~FLOW_PKT_TOCLIENT; + p->flowflags |= FLOW_PKT_TOSERVER; + + r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf3, httplen3); + if (r != 0) { + printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + if (PacketAlertCheck(p, 1)) { + printf("sig 1 matched, but shouldn't have (tx 2): "); + goto end; + } + if ((PacketAlertCheck(p, 2))) { + printf("sig 2 alerted (tx 2): "); + goto end; + } + p->alerts.cnt = 0; + + p->flowflags &= ~FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_TOCLIENT; + + r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_EOF, httpbuf4, httplen4); + if (r != 0) { + printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + if ((PacketAlertCheck(p, 1))) { + printf("sig 1 alerted (tx 2): "); + goto end; + } + if (!(PacketAlertCheck(p, 2))) { + printf("sig 2 didn't alert (tx 2): "); + goto end; + } + p->alerts.cnt = 0; + + HtpState *htp_state = f.alstate; + if (htp_state == NULL) { + printf("no http state: "); + goto end; + } + + if (list_size(htp_state->connp->conn->transactions) != 2) { + printf("The http app layer doesn't have 2 transactions, but it should: "); + goto end; + } + + result = 1; +end: + if (det_ctx != NULL) { + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + } + if (de_ctx != NULL) { + SigGroupCleanup(de_ctx); + DetectEngineCtxFree(de_ctx); + } + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePacket(p); + return result; +} + +/** \test multiple http transactions and body chunks of request handling */ +int DetectHttpServerBodyTest16(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\"; content:\"one\"; http_server_body; sid:1;)"); + if (de_ctx->sig_list == NULL) { + printf("de_ctx->sig_list == NULL\n"); + goto end; + } + + if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { + printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); + goto end; + } + + if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL) { + printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL\n"); + goto end; + } + + DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; + DetectContentData *hsbd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + if (cd->id == hsbd->id) + goto end; + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectHttpServerBodyTest17(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_server_body; content:\"one\"; sid:1;)"); + if (de_ctx->sig_list == NULL) { + printf("de_ctx->sig_list == NULL\n"); + goto end; + } + + if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { + printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); + goto end; + } + + if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL) { + printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL\n"); + goto end; + } + + DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; + DetectContentData *hsbd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + if (cd->id == hsbd->id) + goto end; + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectHttpServerBodyTest18(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\"; content:\"one\"; content:\"one\"; http_server_body; content:\"one\"; sid:1;)"); + if (de_ctx->sig_list == NULL) { + printf("de_ctx->sig_list == NULL\n"); + goto end; + } + + if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { + printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); + goto end; + } + + if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL) { + printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL\n"); + goto end; + } + + DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; + DetectContentData *hsbd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + if (cd->id != 0 || hsbd->id != 1) + goto end; + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectHttpServerBodyTest19(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_server_body; content:\"one\"; content:\"one\"; content:\"one\"; sid:1;)"); + if (de_ctx->sig_list == NULL) { + printf("de_ctx->sig_list == NULL\n"); + goto end; + } + + if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { + printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); + goto end; + } + + if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL) { + printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL\n"); + goto end; + } + + DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; + DetectContentData *hsbd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + if (cd->id != 1 || hsbd->id != 0) + goto end; + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectHttpServerBodyTest20(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_server_body; " + "content:\"one\"; content:\"one\"; http_server_body; content:\"one\"; sid:1;)"); + if (de_ctx->sig_list == NULL) { + printf("de_ctx->sig_list == NULL\n"); + goto end; + } + + if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { + printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); + goto end; + } + + if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL) { + printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL\n"); + goto end; + } + + DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; + DetectContentData *hsbd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + DetectContentData *hsbd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; + if (cd->id != 1 || hsbd1->id != 0 || hsbd2->id != 0) + goto end; + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectHttpServerBodyTest21(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_server_body; " + "content:\"one\"; content:\"one\"; http_server_body; content:\"two\"; sid:1;)"); + if (de_ctx->sig_list == NULL) { + printf("de_ctx->sig_list == NULL\n"); + goto end; + } + + if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { + printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); + goto end; + } + + if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL) { + printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL\n"); + goto end; + } + + DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; + DetectContentData *hsbd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + DetectContentData *hsbd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; + if (cd->id != 2 || hsbd1->id != 0 || hsbd2->id != 0) + goto end; + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + + + + + + + + + + + + + + +int DetectHttpServerBodyTest22(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\"; content:\"two\"; http_server_body; " + "content:\"three\"; distance:10; http_server_body; content:\"four\"; sid:1;)"); + if (de_ctx->sig_list == NULL) { + printf("de_ctx->sig_list == NULL\n"); + goto end; + } + + if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { + printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); + goto end; + } + + if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL) { + printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL\n"); + goto end; + } + + DetectContentData *cd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; + DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; + DetectContentData *hsbd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; + DetectContentData *hsbd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + if (cd1->flags != 0 || memcmp(cd1->content, "one", cd1->content_len) != 0 || + cd2->flags != 0 || memcmp(cd2->content, "four", cd2->content_len) != 0 || + hsbd1->flags != DETECT_CONTENT_RELATIVE_NEXT || + memcmp(hsbd1->content, "two", hsbd1->content_len) != 0 || + hsbd2->flags != DETECT_CONTENT_DISTANCE || + memcmp(hsbd2->content, "three", hsbd1->content_len) != 0) { + goto end; + } + + if (!DETECT_CONTENT_IS_SINGLE(cd1) || + !DETECT_CONTENT_IS_SINGLE(cd2) || + DETECT_CONTENT_IS_SINGLE(hsbd1) || + DETECT_CONTENT_IS_SINGLE(hsbd2)) { + goto end; + } + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectHttpServerBodyTest23(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_server_body; pcre:/two/; " + "content:\"three\"; distance:10; http_server_body; content:\"four\"; sid:1;)"); + if (de_ctx->sig_list == NULL) { + printf("de_ctx->sig_list == NULL\n"); + goto end; + } + + if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { + printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); + goto end; + } + + if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL) { + printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL\n"); + goto end; + } + + DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; + DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; + DetectContentData *hsbd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; + DetectContentData *hsbd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + if (pd1->flags != 0 || + cd2->flags != 0 || memcmp(cd2->content, "four", cd2->content_len) != 0 || + hsbd1->flags != DETECT_CONTENT_RELATIVE_NEXT || + memcmp(hsbd1->content, "one", hsbd1->content_len) != 0 || + hsbd2->flags != DETECT_CONTENT_DISTANCE || + memcmp(hsbd2->content, "three", hsbd1->content_len) != 0) { + goto end; + } + + if (!DETECT_CONTENT_IS_SINGLE(cd2) || + DETECT_CONTENT_IS_SINGLE(hsbd1) || + DETECT_CONTENT_IS_SINGLE(hsbd2)) { + goto end; + } + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectHttpServerBodyTest24(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_server_body; pcre:/two/; " + "content:\"three\"; distance:10; within:15; http_server_body; content:\"four\"; sid:1;)"); + if (de_ctx->sig_list == NULL) { + printf("de_ctx->sig_list == NULL\n"); + goto end; + } + + if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { + printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); + goto end; + } + + if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL) { + printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL\n"); + goto end; + } + + DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; + DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; + DetectContentData *hsbd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; + DetectContentData *hsbd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + if (pd1->flags != 0 || + cd2->flags != 0 || memcmp(cd2->content, "four", cd2->content_len) != 0 || + hsbd1->flags != DETECT_CONTENT_RELATIVE_NEXT || + memcmp(hsbd1->content, "one", hsbd1->content_len) != 0 || + hsbd2->flags != (DETECT_CONTENT_DISTANCE | DETECT_CONTENT_WITHIN) || + memcmp(hsbd2->content, "three", hsbd1->content_len) != 0) { + goto end; + } + + if (!DETECT_CONTENT_IS_SINGLE(cd2) || + DETECT_CONTENT_IS_SINGLE(hsbd1) || + DETECT_CONTENT_IS_SINGLE(hsbd2)) { + goto end; + } + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectHttpServerBodyTest25(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_server_body; pcre:/two/; " + "content:\"three\"; distance:10; http_server_body; " + "content:\"four\"; distance:10; sid:1;)"); + if (de_ctx->sig_list == NULL) { + printf("de_ctx->sig_list == NULL\n"); + goto end; + } + + if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { + printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); + goto end; + } + + if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL) { + printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL\n"); + goto end; + } + + DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; + DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; + DetectContentData *hsbd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; + DetectContentData *hsbd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + if (pd1->flags != DETECT_PCRE_RELATIVE_NEXT || + cd2->flags != DETECT_CONTENT_DISTANCE || + memcmp(cd2->content, "four", cd2->content_len) != 0 || + hsbd1->flags != DETECT_CONTENT_RELATIVE_NEXT || + memcmp(hsbd1->content, "one", hsbd1->content_len) != 0 || + hsbd2->flags != DETECT_CONTENT_DISTANCE || + memcmp(hsbd2->content, "three", hsbd1->content_len) != 0) { + goto end; + } + + if (DETECT_CONTENT_IS_SINGLE(cd2) || + DETECT_CONTENT_IS_SINGLE(hsbd1) || + DETECT_CONTENT_IS_SINGLE(hsbd2)) { + goto end; + } + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectHttpServerBodyTest26(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\"; offset:10; http_server_body; pcre:/two/; " + "content:\"three\"; distance:10; http_server_body; depth:10; " + "content:\"four\"; distance:10; sid:1;)"); + if (de_ctx->sig_list == NULL) { + printf("de_ctx->sig_list == NULL\n"); + goto end; + } + + if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { + printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); + goto end; + } + + if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL) { + printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL\n"); + goto end; + } + + DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; + DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; + DetectContentData *hsbd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; + DetectContentData *hsbd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT) || + cd2->flags != DETECT_CONTENT_DISTANCE || + memcmp(cd2->content, "four", cd2->content_len) != 0 || + hsbd1->flags != (DETECT_CONTENT_RELATIVE_NEXT | DETECT_CONTENT_OFFSET) || + memcmp(hsbd1->content, "one", hsbd1->content_len) != 0 || + hsbd2->flags != (DETECT_CONTENT_DISTANCE | DETECT_CONTENT_DEPTH) || + memcmp(hsbd2->content, "three", hsbd1->content_len) != 0) { + goto end; + } + + if (DETECT_CONTENT_IS_SINGLE(cd2) || + DETECT_CONTENT_IS_SINGLE(hsbd1) || + DETECT_CONTENT_IS_SINGLE(hsbd2)) { + goto end; + } + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectHttpServerBodyTest27(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\"; offset:10; http_server_body; pcre:/two/; distance:10; " + "content:\"three\"; distance:10; http_server_body; depth:10; " + "content:\"four\"; distance:10; sid:1;)"); + if (de_ctx->sig_list != NULL) { + printf("de_ctx->sig_list != NULL\n"); + goto end; + } + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectHttpServerBodyTest28(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_server_body; pcre:/two/; " + "content:\"three\"; http_server_body; depth:10; " + "content:\"four\"; distance:10; sid:1;)"); + if (de_ctx->sig_list == NULL) { + printf("de_ctx->sig_list == NULL\n"); + goto end; + } + + if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { + printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); + goto end; + } + + if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL) { + printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL\n"); + goto end; + } + + DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; + DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; + DetectContentData *hsbd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; + DetectContentData *hsbd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT) || + cd2->flags != DETECT_CONTENT_DISTANCE || + memcmp(cd2->content, "four", cd2->content_len) != 0 || + hsbd1->flags != 0 || + memcmp(hsbd1->content, "one", hsbd1->content_len) != 0 || + hsbd2->flags != DETECT_CONTENT_DEPTH || + memcmp(hsbd2->content, "three", hsbd1->content_len) != 0) { + goto end; + } + + if (DETECT_CONTENT_IS_SINGLE(cd2) || + !DETECT_CONTENT_IS_SINGLE(hsbd1) || + DETECT_CONTENT_IS_SINGLE(hsbd2)) { + goto end; + } + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectHttpServerBodyTest29(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_server_body; " + "content:\"two\"; distance:0; http_server_body; sid:1;)"); + if (de_ctx->sig_list == NULL) { + printf("de_ctx->sig_list == NULL\n"); + goto end; + } + + if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL) { + printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL\n"); + goto end; + } + + if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL) { + printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL\n"); + goto end; + } + + DetectContentData *hsbd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; + DetectContentData *hsbd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + if (hsbd1->flags != DETECT_CONTENT_RELATIVE_NEXT || + memcmp(hsbd1->content, "one", hsbd1->content_len) != 0 || + hsbd2->flags != DETECT_CONTENT_DISTANCE || + memcmp(hsbd2->content, "two", hsbd1->content_len) != 0) { + goto end; + } + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectHttpServerBodyTest30(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_server_body; " + "content:\"two\"; within:5; http_server_body; sid:1;)"); + if (de_ctx->sig_list == NULL) { + printf("de_ctx->sig_list == NULL\n"); + goto end; + } + + if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL) { + printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL\n"); + goto end; + } + + if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL) { + printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL\n"); + goto end; + } + + DetectContentData *hsbd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; + DetectContentData *hsbd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + if (hsbd1->flags != DETECT_CONTENT_RELATIVE_NEXT || + memcmp(hsbd1->content, "one", hsbd1->content_len) != 0 || + hsbd2->flags != DETECT_CONTENT_WITHIN || + memcmp(hsbd2->content, "two", hsbd1->content_len) != 0) { + goto end; + } + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectHttpServerBodyTest31(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\"; within:5; http_server_body; sid:1;)"); + if (de_ctx->sig_list != NULL) { + printf("de_ctx->sig_list != NULL\n"); + goto end; + } + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectHttpServerBodyTest32(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_server_body; within:5; sid:1;)"); + if (de_ctx->sig_list != NULL) { + printf("de_ctx->sig_list != NULL\n"); + goto end; + } + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectHttpServerBodyTest33(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\"; within:5; sid:1;)"); + if (de_ctx->sig_list != NULL) { + printf("de_ctx->sig_list != NULL\n"); + goto end; + } + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectHttpServerBodyTest34(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 " + "(pcre:/one/S; " + "content:\"two\"; within:5; http_server_body; sid:1;)"); + if (de_ctx->sig_list == NULL) { + printf("de_ctx->sig_list == NULL\n"); + goto end; + } + + if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL) { + printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL\n"); + goto end; + } + + if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL) { + printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL\n"); + goto end; + } + + if (de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH] == NULL || + de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->type != DETECT_AL_HTTP_SERVER_BODY || + de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev == NULL || + de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->type != DETECT_PCRE) { + + goto end; + } + + DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; + DetectContentData *hsbd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT | DETECT_PCRE_HTTP_SERVER_BODY) || + hsbd2->flags != DETECT_CONTENT_WITHIN || + memcmp(hsbd2->content, "two", hsbd2->content_len) != 0) { + goto end; + } + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectHttpServerBodyTest35(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_server_body; " + "pcre:/one/SR; sid:1;)"); + if (de_ctx->sig_list == NULL) { + printf("de_ctx->sig_list == NULL\n"); + goto end; + } + + if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL) { + printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL\n"); + goto end; + } + + if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL) { + printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL\n"); + goto end; + } + + if (de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH] == NULL || + de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->type != DETECT_PCRE || + de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev == NULL || + de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->type != DETECT_AL_HTTP_SERVER_BODY) { + + goto end; + } + + DetectContentData *hsbd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; + DetectPcreData *pd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + if (pd2->flags != (DETECT_PCRE_RELATIVE | DETECT_PCRE_HTTP_SERVER_BODY) || + hsbd1->flags != DETECT_CONTENT_RELATIVE_NEXT || + memcmp(hsbd1->content, "two", hsbd1->content_len) != 0) { + goto end; + } + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectHttpServerBodyTest36(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 " + "(pcre:/one/S; " + "content:\"two\"; distance:5; http_server_body; sid:1;)"); + if (de_ctx->sig_list == NULL) { + printf("de_ctx->sig_list == NULL\n"); + goto end; + } + + if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL) { + printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL\n"); + goto end; + } + + if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL) { + printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL\n"); + goto end; + } + + if (de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH] == NULL || + de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->type != DETECT_AL_HTTP_SERVER_BODY || + de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev == NULL || + de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->type != DETECT_PCRE) { + + goto end; + } + + DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; + DetectContentData *hsbd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT | DETECT_PCRE_HTTP_SERVER_BODY) || + hsbd2->flags != DETECT_CONTENT_DISTANCE || + memcmp(hsbd2->content, "two", hsbd2->content_len) != 0) { + goto end; + } + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +#endif /* UNITTESTS */ + +void DetectHttpServerBodyRegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("DetectHttpServerBodyTest01", DetectHttpServerBodyTest01, 1); + UtRegisterTest("DetectHttpServerBodyTest02", DetectHttpServerBodyTest02, 1); + UtRegisterTest("DetectHttpServerBodyTest03", DetectHttpServerBodyTest03, 1); + UtRegisterTest("DetectHttpServerBodyTest04", DetectHttpServerBodyTest04, 1); + UtRegisterTest("DetectHttpServerBodyTest05", DetectHttpServerBodyTest05, 1); + UtRegisterTest("DetectHttpServerBodyTest06", DetectHttpServerBodyTest06, 1); + UtRegisterTest("DetectHttpServerBodyTest07", DetectHttpServerBodyTest07, 1); + UtRegisterTest("DetectHttpServerBodyTest08", DetectHttpServerBodyTest08, 1); + UtRegisterTest("DetectHttpServerBodyTest09", DetectHttpServerBodyTest09, 1); + UtRegisterTest("DetectHttpServerBodyTest10", DetectHttpServerBodyTest10, 1); + UtRegisterTest("DetectHttpServerBodyTest11", DetectHttpServerBodyTest11, 1); + UtRegisterTest("DetectHttpServerBodyTest12", DetectHttpServerBodyTest12, 1); + UtRegisterTest("DetectHttpServerBodyTest13", DetectHttpServerBodyTest13, 1); + UtRegisterTest("DetectHttpServerBodyTest14", DetectHttpServerBodyTest14, 1); + UtRegisterTest("DetectHttpServerBodyTest15", DetectHttpServerBodyTest15, 1); + UtRegisterTest("DetectHttpServerBodyTest16", DetectHttpServerBodyTest16, 1); + UtRegisterTest("DetectHttpServerBodyTest17", DetectHttpServerBodyTest17, 1); + UtRegisterTest("DetectHttpServerBodyTest18", DetectHttpServerBodyTest18, 1); + UtRegisterTest("DetectHttpServerBodyTest19", DetectHttpServerBodyTest19, 1); + UtRegisterTest("DetectHttpServerBodyTest20", DetectHttpServerBodyTest20, 1); + UtRegisterTest("DetectHttpServerBodyTest21", DetectHttpServerBodyTest21, 1); + UtRegisterTest("DetectHttpServerBodyTest22", DetectHttpServerBodyTest22, 1); + UtRegisterTest("DetectHttpServerBodyTest23", DetectHttpServerBodyTest23, 1); + UtRegisterTest("DetectHttpServerBodyTest24", DetectHttpServerBodyTest24, 1); + UtRegisterTest("DetectHttpServerBodyTest25", DetectHttpServerBodyTest25, 1); + UtRegisterTest("DetectHttpServerBodyTest26", DetectHttpServerBodyTest26, 1); + UtRegisterTest("DetectHttpServerBodyTest27", DetectHttpServerBodyTest27, 1); + UtRegisterTest("DetectHttpServerBodyTest28", DetectHttpServerBodyTest28, 1); + UtRegisterTest("DetectHttpServerBodyTest29", DetectHttpServerBodyTest29, 1); + UtRegisterTest("DetectHttpServerBodyTest30", DetectHttpServerBodyTest30, 1); + UtRegisterTest("DetectHttpServerBodyTest31", DetectHttpServerBodyTest31, 1); + UtRegisterTest("DetectHttpServerBodyTest32", DetectHttpServerBodyTest32, 1); + UtRegisterTest("DetectHttpServerBodyTest33", DetectHttpServerBodyTest33, 1); + UtRegisterTest("DetectHttpServerBodyTest34", DetectHttpServerBodyTest34, 1); + UtRegisterTest("DetectHttpServerBodyTest35", DetectHttpServerBodyTest35, 1); + UtRegisterTest("DetectHttpServerBodyTest36", DetectHttpServerBodyTest36, 1); +#endif /* UNITTESTS */ + + return; +} +/** + * @} + */ diff --git a/src/detect-http-server-body.h b/src/detect-http-server-body.h new file mode 100644 index 0000000000..70472fe48a --- /dev/null +++ b/src/detect-http-server-body.h @@ -0,0 +1,29 @@ +/* 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_HTTP_SERVER_BODY_H__ +#define __DETECT_HTTP_SERVER_BODY_H__ + +void DetectHttpServerBodyRegister(void); + +#endif /* __DETECT_HTTP_SERVER_BODY_H__ */ diff --git a/src/detect-isdataat.c b/src/detect-isdataat.c index 9a21bc3325..159226517e 100644 --- a/src/detect-isdataat.c +++ b/src/detect-isdataat.c @@ -268,13 +268,13 @@ int DetectIsdataatSetup (DetectEngineCtx *de_ctx, Signature *s, char *isdataatst idad->flags & ISDATAAT_RELATIVE) { pm = SigMatchGetLastSMFromLists(s, 6, - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_PMATCH]); + DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], + DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], + DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_PMATCH]); dm = SigMatchGetLastSMFromLists(s, 6, - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_DMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_DMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_DMATCH]); + DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_DMATCH], + DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_DMATCH], + DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_DMATCH]); if (pm == NULL) { SigMatchAppendDcePayload(s, sm); @@ -286,9 +286,9 @@ int DetectIsdataatSetup (DetectEngineCtx *de_ctx, Signature *s, char *isdataatst SigMatchAppendDcePayload(s, sm); } prev_pm = SigMatchGetLastSMFromLists(s, 6, - DETECT_CONTENT, sm->prev, - DETECT_BYTEJUMP, sm->prev, - DETECT_PCRE, sm->prev); + DETECT_CONTENT, sm->prev, + DETECT_BYTEJUMP, sm->prev, + DETECT_PCRE, sm->prev); if (prev_pm == NULL) { SCLogDebug("No preceding content or pcre keyword. Possible " "since this is a dce alproto sig."); @@ -318,30 +318,31 @@ int DetectIsdataatSetup (DetectEngineCtx *de_ctx, Signature *s, char *isdataatst } return 0; } - pm = SigMatchGetLastSMFromLists(s, 40, - 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], - DETECT_AL_HTTP_HEADER, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_AL_HTTP_RAW_HEADER, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], /* 5 */ - DETECT_AL_HTTP_METHOD, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_AL_HTTP_COOKIE, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_AL_HTTP_RAW_URI, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], /* 10 */ - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], /* 15 */ - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_DMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_DMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_UMATCH]); + pm = SigMatchGetLastSMFromLists(s, 48, + 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], + DETECT_AL_HTTP_SERVER_BODY, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], + DETECT_AL_HTTP_HEADER, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], /* 5 */ + 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_RAW_URI, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], + 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], + DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], + DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], + DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], /* 15 */ + DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], + DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], + DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], + DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], + DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_DMATCH], /* 20 */ + DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], + DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], + DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_DMATCH], + DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_UMATCH]); /* 24 */ if (pm == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "isdataat relative seen " "without a previous content uricontent, " @@ -365,6 +366,9 @@ int DetectIsdataatSetup (DetectEngineCtx *de_ctx, Signature *s, char *isdataatst case DETECT_AL_HTTP_CLIENT_BODY: list_type = DETECT_SM_LIST_HCBDMATCH; break; + case DETECT_AL_HTTP_SERVER_BODY: + list_type = DETECT_SM_LIST_HCBDMATCH; + break; case DETECT_AL_HTTP_RAW_HEADER: list_type = DETECT_SM_LIST_HRHDMATCH; break; @@ -417,6 +421,7 @@ int DetectIsdataatSetup (DetectEngineCtx *de_ctx, Signature *s, char *isdataatst case DETECT_CONTENT: case DETECT_URICONTENT: case DETECT_AL_HTTP_CLIENT_BODY: + case DETECT_AL_HTTP_SERVER_BODY: case DETECT_AL_HTTP_HEADER: case DETECT_AL_HTTP_RAW_HEADER: case DETECT_AL_HTTP_METHOD: diff --git a/src/detect-nocase.c b/src/detect-nocase.c index 9b11351138..36e02a6f9a 100644 --- a/src/detect-nocase.c +++ b/src/detect-nocase.c @@ -180,45 +180,36 @@ static int DetectNocaseSetup (DetectEngineCtx *de_ctx, Signature *s, char *nulls } /* Search for the first previous SigMatch that supports nocase */ - //SigMatch *pm = SigMatchGetLastNocasePattern(s); - SigMatch *pm = SigMatchGetLastSMFromLists(s, 16, - 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], - DETECT_AL_HTTP_HEADER, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_AL_HTTP_RAW_HEADER, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_AL_HTTP_METHOD, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_AL_HTTP_RAW_URI, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_AL_HTTP_COOKIE, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]); + SigMatch *pm = SigMatchGetLastSMFromLists(s, 18, + 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], + DETECT_AL_HTTP_SERVER_BODY, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], + DETECT_AL_HTTP_HEADER, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], + DETECT_AL_HTTP_RAW_HEADER, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], + DETECT_AL_HTTP_METHOD, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], + DETECT_AL_HTTP_RAW_URI, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], + 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_header, " - "http_method, http_uri, http_cookie or http_raw_uri option"); + "content, uricontent, http_client_body, http_server_body, " + "http_header, http_method, http_uri, http_cookie or " + "http_raw_uri option"); SCReturnInt(-1); } - DetectContentData *ud = NULL; DetectContentData *cd = NULL; - DetectContentData *dhcb = NULL; - DetectContentData *dhcd = NULL; - DetectContentData *dhhd = NULL; - DetectContentData *dhrhd = NULL; - DetectContentData *dhmd = NULL; - DetectContentData *dhrud = NULL; switch (pm->type) { - case DETECT_URICONTENT: - ud = (DetectContentData *)pm->ctx; - if (ud == NULL) { - SCLogError(SC_ERR_INVALID_ARGUMENT, "invalid argument"); - SCReturnInt(-1); - } - ud->flags |= DETECT_CONTENT_NOCASE; - /* Recreate the context with nocase chars */ - BoyerMooreCtxToNocase(ud->bm_ctx, ud->content, ud->content_len); - break; - case DETECT_CONTENT: + case DETECT_URICONTENT: + case DETECT_AL_HTTP_CLIENT_BODY: + case DETECT_AL_HTTP_SERVER_BODY: + case DETECT_AL_HTTP_HEADER: + case DETECT_AL_HTTP_RAW_HEADER: + case DETECT_AL_HTTP_METHOD: + case DETECT_AL_HTTP_COOKIE: + case DETECT_AL_HTTP_RAW_URI: cd = (DetectContentData *)pm->ctx; if (cd == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENT, "invalid argument"); @@ -228,48 +219,12 @@ static int DetectNocaseSetup (DetectEngineCtx *de_ctx, Signature *s, char *nulls /* Recreate the context with nocase chars */ BoyerMooreCtxToNocase(cd->bm_ctx, cd->content, cd->content_len); break; - case DETECT_AL_HTTP_CLIENT_BODY: - dhcb =(DetectContentData *) pm->ctx; - dhcb->flags |= DETECT_CONTENT_NOCASE; - /* Recreate the context with nocase chars */ - BoyerMooreCtxToNocase(dhcb->bm_ctx, dhcb->content, dhcb->content_len); - break; - case DETECT_AL_HTTP_HEADER: - dhhd =(DetectContentData *) pm->ctx; - dhhd->flags |= DETECT_CONTENT_NOCASE; - /* Recreate the context with nocase chars */ - BoyerMooreCtxToNocase(dhhd->bm_ctx, dhhd->content, dhhd->content_len); - break; - case DETECT_AL_HTTP_RAW_HEADER: - dhrhd =(DetectContentData *) pm->ctx; - dhrhd->flags |= DETECT_CONTENT_NOCASE; - /* Recreate the context with nocase chars */ - BoyerMooreCtxToNocase(dhrhd->bm_ctx, dhrhd->content, dhrhd->content_len); - break; - case DETECT_AL_HTTP_METHOD: - dhmd =(DetectContentData *) pm->ctx; - dhmd->flags |= DETECT_CONTENT_NOCASE; - /* Recreate the context with nocase chars */ - BoyerMooreCtxToNocase(dhmd->bm_ctx, dhmd->content, dhmd->content_len); - break; - case DETECT_AL_HTTP_COOKIE: - dhcd = (DetectContentData *) pm->ctx; - dhcd->flags |= DETECT_CONTENT_NOCASE; - /* Recreate the context with nocase chars */ - BoyerMooreCtxToNocase(dhcd->bm_ctx, dhcd->content, dhcd->content_len); - break; - case DETECT_AL_HTTP_RAW_URI: - dhrud = (DetectContentData *) pm->ctx; - dhrud->flags |= DETECT_CONTENT_NOCASE; - /* Recreate the context with nocase chars */ - BoyerMooreCtxToNocase(dhrud->bm_ctx, dhrud->content, dhrud->content_len); - break; /* should never happen */ default: - SCLogError(SC_ERR_NOCASE_MISSING_PATTERN, "\"nocase\" needs a" - " preceeding content, uricontent, http_client_body " - "http_header, http_raw_header, http_method, " - "http_cookie, http_raw_uri option"); + SCLogError(SC_ERR_NOCASE_MISSING_PATTERN, "\"nocase\" needs a preceeding " + "content, uricontent, http_client_body, http_server_body, " + "http_header, http_method, http_uri, http_cookie or " + "http_raw_uri option"); SCReturnInt(-1); break; } diff --git a/src/detect-offset.c b/src/detect-offset.c index 82ca82517b..52b6517c86 100644 --- a/src/detect-offset.c +++ b/src/detect-offset.c @@ -70,8 +70,8 @@ int DetectOffsetSetup (DetectEngineCtx *de_ctx, Signature *s, char *offsetstr) case ALPROTO_DCERPC: /* add to the latest "content" keyword from either dmatch or pmatch */ pm = SigMatchGetLastSMFromLists(s, 4, - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_DMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH]); + DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_DMATCH], + DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH]); if (pm == NULL) { SCLogError(SC_ERR_WITHIN_MISSING_CONTENT, "offset needs" "preceeding content option for dcerpc sig"); @@ -83,15 +83,16 @@ int DetectOffsetSetup (DetectEngineCtx *de_ctx, Signature *s, char *offsetstr) break; default: - pm = SigMatchGetLastSMFromLists(s, 16, - 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], - DETECT_AL_HTTP_HEADER, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_AL_HTTP_RAW_HEADER, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_AL_HTTP_METHOD, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_AL_HTTP_COOKIE, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_AL_HTTP_RAW_URI, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]); + pm = SigMatchGetLastSMFromLists(s, 18, + 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], + DETECT_AL_HTTP_SERVER_BODY, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], + DETECT_AL_HTTP_HEADER, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], + DETECT_AL_HTTP_RAW_HEADER, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], + DETECT_AL_HTTP_METHOD, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], + DETECT_AL_HTTP_COOKIE, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], + DETECT_AL_HTTP_RAW_URI, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]); if (pm == NULL) { SCLogError(SC_ERR_WITHIN_MISSING_CONTENT, "offset needs" "preceeding content or uricontent option, http_client_body " @@ -255,6 +256,50 @@ int DetectOffsetSetup (DetectEngineCtx *de_ctx, Signature *s, char *offsetstr) break; + case DETECT_AL_HTTP_SERVER_BODY: + 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; + case DETECT_AL_HTTP_HEADER: cd = (DetectContentData *)pm->ctx; if (cd->flags & DETECT_CONTENT_NEGATED) { diff --git a/src/detect-parse.c b/src/detect-parse.c index 97cf013bce..7c3fcc5204 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -1356,6 +1356,7 @@ static int SigValidate(Signature *s) { DETECT_REPLACE, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], DETECT_REPLACE, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], DETECT_REPLACE, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], + DETECT_REPLACE, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], DETECT_REPLACE, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], DETECT_REPLACE, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], DETECT_REPLACE, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], @@ -1371,6 +1372,7 @@ static int SigValidate(Signature *s) { if (s->sm_lists_tail[DETECT_SM_LIST_UMATCH] || s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH] || s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH] || + s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH] || s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH] || s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH] || s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH] || @@ -1500,6 +1502,8 @@ Signature *SigInit(DetectEngineCtx *de_ctx, char *sigstr) { sig->flags |= SIG_FLAG_STATE_MATCH; if (sig->sm_lists[DETECT_SM_LIST_HCBDMATCH]) sig->flags |= SIG_FLAG_STATE_MATCH; + if (sig->sm_lists[DETECT_SM_LIST_HSBDMATCH]) + sig->flags |= SIG_FLAG_STATE_MATCH; if (sig->sm_lists[DETECT_SM_LIST_HHDMATCH]) sig->flags |= SIG_FLAG_STATE_MATCH; if (sig->sm_lists[DETECT_SM_LIST_HRHDMATCH]) @@ -1706,6 +1710,8 @@ Signature *SigInitReal(DetectEngineCtx *de_ctx, char *sigstr) { sig->flags |= SIG_FLAG_STATE_MATCH; if (sig->sm_lists[DETECT_SM_LIST_HCBDMATCH]) sig->flags |= SIG_FLAG_STATE_MATCH; + if (sig->sm_lists[DETECT_SM_LIST_HSBDMATCH]) + sig->flags |= SIG_FLAG_STATE_MATCH; if (sig->sm_lists[DETECT_SM_LIST_HHDMATCH]) sig->flags |= SIG_FLAG_STATE_MATCH; if (sig->sm_lists[DETECT_SM_LIST_HRHDMATCH]) diff --git a/src/detect-pcre.c b/src/detect-pcre.c index 085f928a80..f3c72c3e68 100644 --- a/src/detect-pcre.c +++ b/src/detect-pcre.c @@ -577,7 +577,7 @@ int DetectPcrePacketPayloadMatch(DetectEngineThreadCtx *det_ctx, Packet *p, Sign DetectPcreData *pe = (DetectPcreData *)sm->ctx; /* If we want to inspect the http body, we will use HTP L7 parser */ - if (pe->flags & DETECT_PCRE_HTTP_BODY_AL) + if (pe->flags & DETECT_PCRE_HTTP_CLIENT_BODY) SCReturnInt(0); if (s->flags & SIG_FLAG_RECURSIVE) { @@ -670,7 +670,7 @@ int DetectPcrePayloadDoMatch(DetectEngineThreadCtx *det_ctx, Signature *s, DetectPcreData *pe = (DetectPcreData *)sm->ctx; /* If we want to inspect the http body, we will use HTP L7 parser */ - if (pe->flags & DETECT_PCRE_HTTP_BODY_AL) + if (pe->flags & DETECT_PCRE_HTTP_CLIENT_BODY) SCReturnInt(0); if (s->flags & SIG_FLAG_RECURSIVE) { @@ -872,8 +872,12 @@ DetectPcreData *DetectPcreParse (char *regexstr) pd->flags |= DETECT_PCRE_MATCH_LIMIT; break; case 'P': - /* snort's option (http body inspection, chunks loaded from HTP) */ - pd->flags |= DETECT_PCRE_HTTP_BODY_AL; + /* snort's option (http request body inspection) */ + pd->flags |= DETECT_PCRE_HTTP_CLIENT_BODY; + break; + case 'S': + /* suricata extension (http response body inspection) */ + pd->flags |= DETECT_PCRE_HTTP_SERVER_BODY; break; default: SCLogError(SC_ERR_UNKNOWN_REGEX_MOD, "unknown regex modifier '%c'", *op); @@ -1043,7 +1047,8 @@ static int DetectPcreSetup (DetectEngineCtx *de_ctx, Signature *s, char *regexst (pd->flags & DETECT_PCRE_HEADER) || (pd->flags & DETECT_PCRE_RAW_HEADER) || (pd->flags & DETECT_PCRE_COOKIE) || - (pd->flags & DETECT_PCRE_HTTP_BODY_AL) || + (pd->flags & DETECT_PCRE_HTTP_CLIENT_BODY) || + (pd->flags & DETECT_PCRE_HTTP_SERVER_BODY) || (pd->flags & DETECT_PCRE_HTTP_RAW_URI) ) { SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "Invalid option. " "DCERPC rule has pcre keyword with http related modifier."); @@ -1090,12 +1095,18 @@ static int DetectPcreSetup (DetectEngineCtx *de_ctx, Signature *s, char *regexst s->flags |= SIG_FLAG_APPLAYER; SigMatchAppendAppLayer(s, sm); - } else if (pd->flags & DETECT_PCRE_HTTP_BODY_AL) { - SCLogDebug("Body inspection modifier set"); + } else if (pd->flags & DETECT_PCRE_HTTP_CLIENT_BODY) { + SCLogDebug("Request body inspection modifier set"); s->flags |= SIG_FLAG_APPLAYER; AppLayerHtpEnableRequestBodyCallback(); SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_HCBDMATCH); + } else if (pd->flags & DETECT_PCRE_HTTP_SERVER_BODY) { + SCLogDebug("Response body inspection modifier set"); + s->flags |= SIG_FLAG_APPLAYER; + AppLayerHtpEnableResponseBodyCallback(); + + SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_HSBDMATCH); } else if (pd->flags & DETECT_PCRE_URI) { s->flags |= SIG_FLAG_APPLAYER; @@ -1124,13 +1135,13 @@ static int DetectPcreSetup (DetectEngineCtx *de_ctx, Signature *s, char *regexst SigMatch *dm = NULL; pm = SigMatchGetLastSMFromLists(s, 6, - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_PMATCH]); + DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], + DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], + DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_PMATCH]); dm = SigMatchGetLastSMFromLists(s, 6, - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_PMATCH]); + DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], + DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], + DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_PMATCH]); if (pm == NULL) { SigMatchAppendDcePayload(s, sm); @@ -1150,14 +1161,15 @@ static int DetectPcreSetup (DetectEngineCtx *de_ctx, Signature *s, char *regexst SCReturnInt(0); } - prev_sm = SigMatchGetLastSMFromLists(s, 14, - DETECT_CONTENT, sm->prev, - DETECT_URICONTENT, sm->prev, - DETECT_AL_HTTP_CLIENT_BODY, sm->prev, - DETECT_AL_HTTP_HEADER, sm->prev, - DETECT_AL_HTTP_RAW_HEADER, sm->prev, - DETECT_AL_HTTP_RAW_URI, sm->prev, - DETECT_PCRE, sm->prev); + prev_sm = SigMatchGetLastSMFromLists(s, 16, + DETECT_CONTENT, sm->prev, + DETECT_URICONTENT, sm->prev, + DETECT_AL_HTTP_CLIENT_BODY, sm->prev, + DETECT_AL_HTTP_SERVER_BODY, sm->prev, + DETECT_AL_HTTP_HEADER, sm->prev, + DETECT_AL_HTTP_RAW_HEADER, sm->prev, + DETECT_AL_HTTP_RAW_URI, sm->prev, + DETECT_PCRE, sm->prev); if (prev_sm == NULL) { if (s->alproto == ALPROTO_DCERPC) { SCLogDebug("No preceding content or pcre keyword. Possible " @@ -1177,6 +1189,7 @@ static int DetectPcreSetup (DetectEngineCtx *de_ctx, Signature *s, char *regexst case DETECT_CONTENT: case DETECT_URICONTENT: case DETECT_AL_HTTP_CLIENT_BODY: + case DETECT_AL_HTTP_SERVER_BODY: case DETECT_AL_HTTP_HEADER: case DETECT_AL_HTTP_RAW_HEADER: case DETECT_AL_HTTP_RAW_URI: diff --git a/src/detect-pcre.h b/src/detect-pcre.h index ce89aeee4f..eae443756d 100644 --- a/src/detect-pcre.h +++ b/src/detect-pcre.h @@ -24,25 +24,27 @@ #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 0x0001 +#define DETECT_PCRE_RAWBYTES 0x0002 +#define DETECT_PCRE_URI 0x0004 -#define DETECT_PCRE_CAPTURE_PKT 0x0008 -#define DETECT_PCRE_CAPTURE_FLOW 0x0010 -#define DETECT_PCRE_MATCH_LIMIT 0x0020 +#define DETECT_PCRE_CAPTURE_PKT 0x0008 +#define DETECT_PCRE_CAPTURE_FLOW 0x0010 +#define DETECT_PCRE_MATCH_LIMIT 0x0020 -#define DETECT_PCRE_HTTP_BODY_AL 0x0040 -#define DETECT_PCRE_RELATIVE_NEXT 0x0080 +#define DETECT_PCRE_HTTP_CLIENT_BODY 0x0040 +#define DETECT_PCRE_HTTP_SERVER_BODY 0x0080 + +#define DETECT_PCRE_RELATIVE_NEXT 0x0100 /* new modifiers 2.8.5.3 support */ -#define DETECT_PCRE_HEADER 0x0100 -#define DETECT_PCRE_RAW_HEADER 0x0200 -#define DETECT_PCRE_COOKIE 0x0400 -#define DETECT_PCRE_METHOD 0x0800 -#define DETECT_PCRE_HTTP_RAW_URI 0x1000 +#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_NEGATE 0x2000 +#define DETECT_PCRE_NEGATE 0x4000 typedef struct DetectPcreData_ { /* pcre options */ @@ -57,7 +59,6 @@ typedef struct DetectPcreData_ { /* prototypes */ int DetectPcrePayloadMatch(DetectEngineThreadCtx *, Signature *, SigMatch *, Packet *, Flow *, uint8_t *, uint32_t); int DetectPcrePacketPayloadMatch(DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); -//int DetectPcrePayloadMatch(DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); int DetectPcrePayloadDoMatch(DetectEngineThreadCtx *, Signature *, SigMatch *, Packet *, uint8_t *, uint16_t); void DetectPcreRegister (void); diff --git a/src/detect-within.c b/src/detect-within.c index a07109233a..330f608f31 100644 --- a/src/detect-within.c +++ b/src/detect-within.c @@ -89,19 +89,19 @@ static int DetectWithinSetup (DetectEngineCtx *de_ctx, Signature *s, char *withi SigMatch *pm2_ots = NULL; dcem = SigMatchGetLastSMFromLists(s, 6, - DETECT_DCE_IFACE, s->sm_lists_tail[DETECT_SM_LIST_AMATCH], - DETECT_DCE_OPNUM, s->sm_lists_tail[DETECT_SM_LIST_AMATCH], - DETECT_DCE_STUB_DATA, s->sm_lists_tail[DETECT_SM_LIST_AMATCH]); + DETECT_DCE_IFACE, s->sm_lists_tail[DETECT_SM_LIST_AMATCH], + DETECT_DCE_OPNUM, s->sm_lists_tail[DETECT_SM_LIST_AMATCH], + DETECT_DCE_STUB_DATA, s->sm_lists_tail[DETECT_SM_LIST_AMATCH]); pm1_ots = SigMatchGetLastSMFromLists(s, 6, - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_PMATCH]); + DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], + DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], + DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_PMATCH]); if (pm1_ots != NULL && pm1_ots->prev != NULL) { pm2_ots = SigMatchGetLastSMFromLists(s, 6, - DETECT_CONTENT, pm1_ots->prev, - DETECT_PCRE, pm1_ots->prev, - DETECT_BYTEJUMP, pm1_ots->prev); + DETECT_CONTENT, pm1_ots->prev, + DETECT_PCRE, pm1_ots->prev, + DETECT_BYTEJUMP, pm1_ots->prev); } dm = SigMatchGetLastSMFromLists(s, 2, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_DMATCH]); @@ -118,10 +118,10 @@ static int DetectWithinSetup (DetectEngineCtx *de_ctx, Signature *s, char *withi if (pm1->idx > dcem->idx) { /* transfer pm1 to dmatch list and within is against this */ SigMatchTransferSigMatchAcrossLists(pm1, - &s->sm_lists[DETECT_SM_LIST_PMATCH], - &s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - &s->sm_lists[DETECT_SM_LIST_DMATCH], - &s->sm_lists_tail[DETECT_SM_LIST_DMATCH]); + &s->sm_lists[DETECT_SM_LIST_PMATCH], + &s->sm_lists_tail[DETECT_SM_LIST_PMATCH], + &s->sm_lists[DETECT_SM_LIST_DMATCH], + &s->sm_lists_tail[DETECT_SM_LIST_DMATCH]); pm = pm1; } else { /* within is against pm1 and we continue this way */ @@ -133,9 +133,9 @@ static int DetectWithinSetup (DetectEngineCtx *de_ctx, Signature *s, char *withi } else if (pm1->idx > dcem->idx) { /* transfer pm1 to dmatch list and within is against this */ SigMatchTransferSigMatchAcrossLists(pm1, - &s->sm_lists[DETECT_SM_LIST_PMATCH], - &s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - &s->sm_lists[DETECT_SM_LIST_DMATCH], + &s->sm_lists[DETECT_SM_LIST_PMATCH], + &s->sm_lists_tail[DETECT_SM_LIST_PMATCH], + &s->sm_lists[DETECT_SM_LIST_DMATCH], &s->sm_lists_tail[DETECT_SM_LIST_DMATCH]); pm = pm1; } else { @@ -152,10 +152,10 @@ static int DetectWithinSetup (DetectEngineCtx *de_ctx, Signature *s, char *withi } else if (pm2_ots == NULL || pm2_ots->idx < dcem->idx) { /* trasnfer pm1 to dmatch list and pm = pm1 */ SigMatchTransferSigMatchAcrossLists(pm1, - &s->sm_lists[DETECT_SM_LIST_PMATCH], - &s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - &s->sm_lists[DETECT_SM_LIST_DMATCH], - &s->sm_lists_tail[DETECT_SM_LIST_DMATCH]); + &s->sm_lists[DETECT_SM_LIST_PMATCH], + &s->sm_lists_tail[DETECT_SM_LIST_PMATCH], + &s->sm_lists[DETECT_SM_LIST_DMATCH], + &s->sm_lists_tail[DETECT_SM_LIST_DMATCH]); pm = pm1; } else { /* within is against pm1, pm = pm1 */ @@ -163,20 +163,21 @@ static int DetectWithinSetup (DetectEngineCtx *de_ctx, Signature *s, char *withi } } } else { - pm = SigMatchGetLastSMFromLists(s, 16, - 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], - DETECT_AL_HTTP_HEADER, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_AL_HTTP_RAW_HEADER, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_AL_HTTP_METHOD, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_AL_HTTP_COOKIE, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_AL_HTTP_RAW_URI, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]); + pm = SigMatchGetLastSMFromLists(s, 18, + 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], + DETECT_AL_HTTP_SERVER_BODY, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], + DETECT_AL_HTTP_HEADER, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], + DETECT_AL_HTTP_RAW_HEADER, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], + DETECT_AL_HTTP_METHOD, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], + DETECT_AL_HTTP_COOKIE, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], + DETECT_AL_HTTP_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_header, http_raw_header, http_method, " - "http_cookie or http_raw_uri option"); + "http_server_body, http_header, http_raw_header, " + "http_method, http_cookie or http_raw_uri option"); if (dubbed) SCFree(str); return -1; @@ -482,6 +483,75 @@ static int DetectWithinSetup (DetectEngineCtx *de_ctx, Signature *s, char *withi break; + case DETECT_AL_HTTP_SERVER_BODY: + cd = (DetectContentData *)pm->ctx; + + 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; + } + } + + 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; + } + } + + cd->flags |= DETECT_CONTENT_WITHIN; + + /* reassigning pm */ + pm = SigMatchGetLastSMFromLists(s, 4, + DETECT_AL_HTTP_SERVER_BODY, pm->prev, + DETECT_PCRE, pm->prev); + if (pm == NULL) { + SCLogError(SC_ERR_DISTANCE_MISSING_CONTENT, "distance for http_server_body " + "needs preceeding http_server_body 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; + case DETECT_AL_HTTP_HEADER: cd = (DetectContentData *)pm->ctx; if (cd->flags & DETECT_CONTENT_NEGATED) { diff --git a/src/detect.c b/src/detect.c index 799f4d2eee..1826b4ea73 100644 --- a/src/detect.c +++ b/src/detect.c @@ -115,6 +115,7 @@ #include "detect-urilen.h" #include "detect-detection-filter.h" #include "detect-http-client-body.h" +#include "detect-http-server-body.h" #include "detect-http-header.h" #include "detect-http-raw-header.h" #include "detect-http-uri.h" @@ -757,6 +758,15 @@ static inline int SigMatchSignaturesBuildMatchArrayAddSignature(DetectEngineThre } } + if (s->flags & SIG_FLAG_MPM_HSBDCONTENT) { + if (!(det_ctx->pmq.pattern_id_bitarray[(s->mpm_http_pattern_id / 8)] & + (1 << (s->mpm_http_pattern_id % 8)))) { + if (!(s->flags & SIG_FLAG_MPM_HSBDCONTENT_NEG)) { + return 0; + } + } + } + if (s->flags & SIG_FLAG_MPM_HHDCONTENT) { if (!(det_ctx->pmq.pattern_id_bitarray[(s->mpm_http_pattern_id / 8)] & (1 << (s->mpm_http_pattern_id % 8)))) { @@ -1222,6 +1232,11 @@ static inline void DetectMpmPrefilter(DetectEngineCtx *de_ctx, DetectEngineRunHttpClientBodyMpm(de_ctx, det_ctx, p->flow, alstate); PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_HCBD); } + if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_HSBD) { + PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_HSBD); + DetectEngineRunHttpServerBodyMpm(de_ctx, det_ctx, p->flow, alstate); + PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_HSBD); + } if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_HHD) { PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_HHD); DetectEngineRunHttpHeaderMpm(det_ctx, p->flow, alstate); @@ -1761,6 +1776,7 @@ end: PacketPatternCleanup(th_v, det_ctx); DetectEngineCleanHCBDBuffers(det_ctx); + DetectEngineCleanHSBDBuffers(det_ctx); DetectEngineCleanHHDBuffers(det_ctx); /* store the found sgh (or NULL) in the flow to save us from looking it @@ -1978,6 +1994,9 @@ int SignatureIsIPOnly(DetectEngineCtx *de_ctx, Signature *s) { if (s->sm_lists[DETECT_SM_LIST_HCBDMATCH] != NULL) return 0; + if (s->sm_lists[DETECT_SM_LIST_HSBDMATCH] != NULL) + return 0; + if (s->sm_lists[DETECT_SM_LIST_HHDMATCH] != NULL) return 0; @@ -2066,6 +2085,7 @@ static int SignatureIsDEOnly(DetectEngineCtx *de_ctx, Signature *s) { s->sm_lists[DETECT_SM_LIST_UMATCH] != NULL || s->sm_lists[DETECT_SM_LIST_AMATCH] != NULL || s->sm_lists[DETECT_SM_LIST_HCBDMATCH] != NULL || + s->sm_lists[DETECT_SM_LIST_HSBDMATCH] != NULL || s->sm_lists[DETECT_SM_LIST_HHDMATCH] != NULL || s->sm_lists[DETECT_SM_LIST_HRHDMATCH] != NULL || s->sm_lists[DETECT_SM_LIST_HMDMATCH] != NULL || @@ -2181,6 +2201,11 @@ static int SignatureCreateMask(Signature *s) { SCLogDebug("sig requires http app state"); } + if (s->sm_lists[DETECT_SM_LIST_HSBDMATCH] != NULL) { + s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; + SCLogDebug("sig requires http app state"); + } + if (s->sm_lists[DETECT_SM_LIST_HHDMATCH] != NULL) { s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; SCLogDebug("sig requires http app state"); @@ -4362,6 +4387,7 @@ void SigTableSetup(void) { DetectHttpHeaderRegister(); DetectHttpRawHeaderRegister(); DetectHttpClientBodyRegister(); + DetectHttpServerBodyRegister(); DetectHttpUriRegister(); DetectHttpRawUriRegister(); DetectAsn1Register(); diff --git a/src/detect.h b/src/detect.h index 2a983f5bf4..2366c4e2ab 100644 --- a/src/detect.h +++ b/src/detect.h @@ -88,6 +88,8 @@ enum { DETECT_SM_LIST_TMATCH, /* list for http_client_body keyword and the ones relative to it */ DETECT_SM_LIST_HCBDMATCH, + /* list for http_server_body keyword and the ones relative to it */ + DETECT_SM_LIST_HSBDMATCH, /* list for http_header keyword and the ones relative to it */ DETECT_SM_LIST_HHDMATCH, /* list for http_raw_header keyword and the ones relative to it */ @@ -218,51 +220,54 @@ typedef struct DetectPort_ { } DetectPort; /* Signature flags */ -#define SIG_FLAG_RECURSIVE (1) /**< recursive capturing enabled */ -#define SIG_FLAG_SRC_ANY (1<<1) /**< source is any */ -#define SIG_FLAG_DST_ANY (1<<2) /**< destination is any */ -#define SIG_FLAG_SP_ANY (1<<3) /**< source port is any */ +#define SIG_FLAG_RECURSIVE (1UL) /**< recursive capturing enabled */ +#define SIG_FLAG_SRC_ANY (1UL<<1) /**< source is any */ +#define SIG_FLAG_DST_ANY (1UL<<2) /**< destination is any */ +#define SIG_FLAG_SP_ANY (1UL<<3) /**< source port is any */ -#define SIG_FLAG_DP_ANY (1<<4) /**< destination port is any */ -#define SIG_FLAG_NOALERT (1<<5) /**< no alert flag is set */ +#define SIG_FLAG_DP_ANY (1UL<<4) /**< destination port is any */ +#define SIG_FLAG_NOALERT (1UL<<5) /**< no alert flag is set */ -#define SIG_FLAG_MPM (1<<6) /**< sig has mpm portion (content) */ -#define SIG_FLAG_MPM_URI (1<<7) /**< sig has mpm portion (uricontent) */ -#define SIG_FLAG_DSIZE (1<<8) /**< signature has a dsize setting */ +#define SIG_FLAG_MPM (1UL<<6) /**< sig has mpm portion (content) */ +#define SIG_FLAG_MPM_URI (1UL<<7) /**< sig has mpm portion (uricontent) */ +#define SIG_FLAG_DSIZE (1UL<<8) /**< signature has a dsize setting */ -#define SIG_FLAG_APPLAYER (1<<9) /**< signature applies to app layer instead of packets */ -#define SIG_FLAG_IPONLY (1<<10) /**< ip only signature */ +#define SIG_FLAG_APPLAYER (1UL<<9) /**< signature applies to app layer instead of packets */ +#define SIG_FLAG_IPONLY (1UL<<10) /**< ip only signature */ -#define SIG_FLAG_STATE_MATCH (1<<11) /**< signature has matches that require stateful inspection */ -#define SIG_FLAG_REQUIRE_PACKET (1<<12) /**< signature is requiring packet match */ -#define SIG_FLAG_MPM_PACKET (1<<13) -#define SIG_FLAG_MPM_PACKET_NEG (1<<14) +#define SIG_FLAG_STATE_MATCH (1UL<<11) /**< signature has matches that require stateful inspection */ +#define SIG_FLAG_REQUIRE_PACKET (1UL<<12) /**< signature is requiring packet match */ +#define SIG_FLAG_MPM_PACKET (1UL<<13) +#define SIG_FLAG_MPM_PACKET_NEG (1UL<<14) -#define SIG_FLAG_MPM_STREAM (1<<15) -#define SIG_FLAG_MPM_STREAM_NEG (1<<16) +#define SIG_FLAG_MPM_STREAM (1UL<<15) +#define SIG_FLAG_MPM_STREAM_NEG (1UL<<16) -#define SIG_FLAG_MPM_URICONTENT (1<<17) -#define SIG_FLAG_MPM_URICONTENT_NEG (1<<18) +#define SIG_FLAG_MPM_URICONTENT (1UL<<17) +#define SIG_FLAG_MPM_URICONTENT_NEG (1UL<<18) -#define SIG_FLAG_MPM_HHDCONTENT (1<<19) -#define SIG_FLAG_MPM_HHDCONTENT_NEG (1<<20) +#define SIG_FLAG_MPM_HHDCONTENT (1UL<<19) +#define SIG_FLAG_MPM_HHDCONTENT_NEG (1UL<<20) -#define SIG_FLAG_MPM_HRHDCONTENT (1<<21) -#define SIG_FLAG_MPM_HRHDCONTENT_NEG (1<<22) +#define SIG_FLAG_MPM_HRHDCONTENT (1UL<<21) +#define SIG_FLAG_MPM_HRHDCONTENT_NEG (1UL<<22) -#define SIG_FLAG_MPM_HCBDCONTENT (1<<23) -#define SIG_FLAG_MPM_HCBDCONTENT_NEG (1<<24) +#define SIG_FLAG_MPM_HCBDCONTENT (1UL<<23) +#define SIG_FLAG_MPM_HCBDCONTENT_NEG (1UL<<24) -#define SIG_FLAG_MPM_HMDCONTENT (1<<25) -#define SIG_FLAG_MPM_HMDCONTENT_NEG (1<<26) +#define SIG_FLAG_MPM_HMDCONTENT (1UL<<25) +#define SIG_FLAG_MPM_HMDCONTENT_NEG (1UL<<26) -#define SIG_FLAG_MPM_HCDCONTENT (1<<27) -#define SIG_FLAG_MPM_HCDCONTENT_NEG (1<<28) +#define SIG_FLAG_MPM_HCDCONTENT (1UL<<27) +#define SIG_FLAG_MPM_HCDCONTENT_NEG (1UL<<28) -#define SIG_FLAG_MPM_HRUDCONTENT (1<<29) -#define SIG_FLAG_MPM_HRUDCONTENT_NEG (1<<30) +#define SIG_FLAG_MPM_HRUDCONTENT (1UL<<29) +#define SIG_FLAG_MPM_HRUDCONTENT_NEG (1UL<<30) -#define SIG_FLAG_REQUIRE_FLOWVAR (1<<31) /**< signature can only match if a flowbit, flowvar or flowint is available. */ +#define SIG_FLAG_REQUIRE_FLOWVAR (1UL<<31) /**< signature can only match if a flowbit, flowvar or flowint is available. */ + +#define SIG_FLAG_MPM_HSBDCONTENT (1UL<<32) +#define SIG_FLAG_MPM_HSBDCONTENT_NEG (1UL<<33) /* signature init flags */ #define SIG_FLAG_DEONLY 1 /**< decode event only signature */ @@ -318,24 +323,24 @@ typedef struct IPOnlyCIDRItem_ { typedef struct SignatureHeader_ { union { struct { - uint32_t flags; - uint16_t mpm_pattern_id_div_8; - uint8_t mpm_pattern_id_mod_8; - SignatureMask mask; + uint64_t flags; }; uint64_t hdr_copy1; }; union { struct { + uint16_t mpm_pattern_id_div_8; + uint8_t mpm_pattern_id_mod_8; + SignatureMask mask; uint16_t alproto; uint16_t mpm_stream_pattern_id_div_8; - uint8_t mpm_stream_pattern_id_mod_8; - SigIntId num; /**< signature number, internal id */ }; uint64_t hdr_copy2; }; union { struct { + uint8_t mpm_stream_pattern_id_mod_8; + SigIntId num; /**< signature number, internal id */ /** pattern in the mpm matcher */ PatIntId mpm_http_pattern_id; }; @@ -359,24 +364,24 @@ typedef struct SigMatch_ { typedef struct Signature_ { union { struct { - uint32_t flags; - uint16_t mpm_pattern_id_div_8; - uint8_t mpm_pattern_id_mod_8; - SignatureMask mask; + uint64_t flags; }; uint64_t hdr_copy1; }; union { struct { + uint16_t mpm_pattern_id_div_8; + uint8_t mpm_pattern_id_mod_8; + SignatureMask mask; uint16_t alproto; uint16_t mpm_stream_pattern_id_div_8; - uint8_t mpm_stream_pattern_id_mod_8; - SigIntId num; /**< signature number, internal id */ }; uint64_t hdr_copy2; }; union { struct { + uint8_t mpm_stream_pattern_id_mod_8; + SigIntId num; /**< signature number, internal id */ PatIntId mpm_http_pattern_id; }; uint64_t hdr_copy3; @@ -664,6 +669,8 @@ typedef struct DetectEngineCtx_ { /* conf parameter that limits the length of the http request body inspected */ int hcbd_buffer_limit; + /* conf parameter that limits the length of the http response body inspected */ + int hsbd_buffer_limit; /* array containing all sgh's in use so we can loop * through it in Stage4. */ @@ -675,6 +682,7 @@ typedef struct DetectEngineCtx_ { int32_t sgh_mpm_context_stream; int32_t sgh_mpm_context_uri; int32_t sgh_mpm_context_hcbd; + int32_t sgh_mpm_context_hsbd; int32_t sgh_mpm_context_hhd; int32_t sgh_mpm_context_hrhd; int32_t sgh_mpm_context_hmd; @@ -739,6 +747,10 @@ typedef struct DetectionEngineThreadCtx_ { uint32_t *hcbd_buffers_len; uint16_t hcbd_buffers_list_len; + uint8_t **hsbd_buffers; + uint32_t *hsbd_buffers_len; + uint16_t hsbd_buffers_list_len; + uint8_t **hhd_buffers; uint32_t *hhd_buffers_len; uint16_t hhd_buffers_list_len; @@ -863,6 +875,8 @@ typedef struct SigTableElmt_ { #define SIG_GROUP_HEAD_MPM_HRUD 0x00200000 #define SIG_GROUP_HEAD_REFERENCED 0x00400000 /**< sgh is being referenced by others, don't clear */ #define SIG_GROUP_HEAD_HAVEFILEMAGIC 0x00800000 +#define SIG_GROUP_HAVEHSBDCONTENT 0x01000000 +#define SIG_GROUP_HEAD_MPM_HSBD 0x02000000 typedef struct SigGroupHeadInitData_ { /* list of content containers @@ -909,6 +923,7 @@ typedef struct SigGroupHead_ { MpmCtx *mpm_stream_ctx; MpmCtx *mpm_uri_ctx; MpmCtx *mpm_hcbd_ctx; + MpmCtx *mpm_hsbd_ctx; MpmCtx *mpm_hhd_ctx; MpmCtx *mpm_hrhd_ctx; MpmCtx *mpm_hmd_ctx; @@ -1017,6 +1032,7 @@ enum { DETECT_AL_HTTP_METHOD, DETECT_AL_URILEN, DETECT_AL_HTTP_CLIENT_BODY, + DETECT_AL_HTTP_SERVER_BODY, DETECT_AL_HTTP_HEADER, DETECT_AL_HTTP_RAW_HEADER, DETECT_AL_HTTP_URI, diff --git a/src/suricata-common.h b/src/suricata-common.h index 6fc2b619e2..36bbae80e6 100644 --- a/src/suricata-common.h +++ b/src/suricata-common.h @@ -178,6 +178,7 @@ typedef enum PacketProfileDetectId_ { PROF_DETECT_MPM_STREAM, /* STREAM MPM */ PROF_DETECT_MPM_URI, PROF_DETECT_MPM_HCBD, + PROF_DETECT_MPM_HSBD, PROF_DETECT_MPM_HHD, PROF_DETECT_MPM_HRHD, PROF_DETECT_MPM_HMD, diff --git a/src/suricata.c b/src/suricata.c index 00dcecd3c3..e45b6f1e20 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -58,6 +58,7 @@ #include "detect-engine-dcepayload.h" #include "detect-engine-uri.h" #include "detect-engine-hcbd.h" +#include "detect-engine-hsbd.h" #include "detect-engine-hhd.h" #include "detect-engine-hrhd.h" #include "detect-engine-hmd.h" @@ -1365,6 +1366,7 @@ int main(int argc, char **argv) DetectRingBufferRegisterTests(); MemcmpRegisterTests(); DetectEngineHttpClientBodyRegisterTests(); + DetectEngineHttpServerBodyRegisterTests(); DetectEngineHttpHeaderRegisterTests(); DetectEngineHttpRawHeaderRegisterTests(); DetectEngineHttpMethodRegisterTests(); diff --git a/src/util-profiling.c b/src/util-profiling.c index 2b8b896083..c875e4c959 100644 --- a/src/util-profiling.c +++ b/src/util-profiling.c @@ -1130,6 +1130,7 @@ const char * PacketProfileDetectIdToString(PacketProfileDetectId id) CASE_CODE (PROF_DETECT_MPM_STREAM); CASE_CODE (PROF_DETECT_MPM_URI); CASE_CODE (PROF_DETECT_MPM_HCBD); + CASE_CODE (PROF_DETECT_MPM_HSBD); CASE_CODE (PROF_DETECT_MPM_HHD); CASE_CODE (PROF_DETECT_MPM_HRHD); CASE_CODE (PROF_DETECT_MPM_HMD);