diff --git a/src/Makefile.am b/src/Makefile.am index ee1c823821..ce7d7ca611 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -63,6 +63,7 @@ detect-engine-iponly.c detect-engine-iponly.h \ 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-state.c detect-engine-state.h \ detect-parse.c detect-parse.h \ detect-ack.c detect-ack.h \ diff --git a/src/app-layer-htp.c b/src/app-layer-htp.c index c77a93818b..57c6c525ba 100644 --- a/src/app-layer-htp.c +++ b/src/app-layer-htp.c @@ -25,6 +25,7 @@ * This file provides a HTTP protocol support for the engine using HTP library. */ +#include "suricata.h" #include "suricata-common.h" #include "debug.h" #include "decode.h" @@ -70,6 +71,7 @@ struct HTPCfgRec_ { static SCRadixTree *cfgtree; /** List of HTP configurations. */ static HTPCfgRec cfglist; +static HTPCfgRec cfglist_backup; #ifdef DEBUG static SCMutex htp_state_mem_lock = PTHREAD_MUTEX_INITIALIZER; @@ -537,7 +539,7 @@ static int HTPHandleResponseData(Flow *f, void *htp_state, * \param len length of the chunk pointed by data * \retval none */ -void HtpBodyAppendChunk(HtpBody *body, uint8_t *data, uint32_t len) +void HtpBodyAppendChunk(SCHtpTxUserData *htud, HtpBody *body, uint8_t *data, uint32_t len) { SCEnter(); @@ -560,6 +562,7 @@ void HtpBodyAppendChunk(HtpBody *body, uint8_t *data, uint32_t len) } memcpy(bd->data, data, len); + htud->content_len_so_far = len; body->first = body->last = bd; body->nchunks++; bd->next = NULL; @@ -570,6 +573,11 @@ void HtpBodyAppendChunk(HtpBody *body, uint8_t *data, uint32_t len) /* Weird, but sometimes htp lib calls the callback * more than once for the same chunk, with more * len, so updating the len */ + if (body->last->len > len) + htud->content_len_so_far -= (body->last->len - len); + else + htud->content_len_so_far += (len - body->last->len); + body->last->len = len; bd = body->last; @@ -593,6 +601,7 @@ void HtpBodyAppendChunk(HtpBody *body, uint8_t *data, uint32_t len) } memcpy(bd->data, data, len); + htud->content_len_so_far += len; body->last->next = bd; body->last = bd; body->nchunks++; @@ -696,13 +705,17 @@ int HTPCallbackRequestBodyData(htp_tx_data_t *d) htud->body.operation = HTP_BODY_NONE; htud->body.pcre_flags = HTP_PCRE_NONE; + htp_header_t *cl = table_getc(d->tx->request_headers, "content-length"); + if (cl != NULL) + htud->content_len = htp_parse_content_length(cl->value); + /* Set the user data for handling body chunks on this transaction */ htp_tx_set_user_data(d->tx, htud); } htud->body.operation = HTP_BODY_REQUEST; - HtpBodyAppendChunk(&htud->body, (uint8_t*)d->data, (uint32_t)d->len); + HtpBodyAppendChunk(htud, &htud->body, (uint8_t*)d->data, (uint32_t)d->len); htud->body.pcre_flags = HTP_PCRE_NONE; if (SCLogDebugEnabled()) { HtpBodyPrint(&htud->body); @@ -1021,6 +1034,22 @@ static void HTPConfigure(void) SCReturn; } +static void HtpConfigCreateBackup(void) +{ + cfglist_backup.cfg = cfglist.cfg; + cfglist_backup.next = cfglist.next; + + return; +} + +static void HtpConfigRestoreBackup(void) +{ + cfglist.cfg = cfglist_backup.cfg; + cfglist.next = cfglist_backup.next; + + return; +} + /** * \brief Register the HTTP protocol and state handling functions to APP layer * of the engine. @@ -1753,6 +1782,7 @@ libhtp:\n\ ConfCreateContextBackup(); ConfInit(); + HtpConfigCreateBackup(); ConfYamlLoadString(input, strlen(input)); @@ -1816,8 +1846,10 @@ libhtp:\n\ ret = 1; end: + HTPFreeConfig(); ConfDeInit(); ConfRestoreContextBackup(); + HtpConfigRestoreBackup(); return ret; } @@ -1858,6 +1890,7 @@ libhtp:\n\ ConfCreateContextBackup(); ConfInit(); + HtpConfigCreateBackup(); ConfYamlLoadString(input, strlen(input)); @@ -1922,8 +1955,10 @@ libhtp:\n\ } end: + HTPFreeConfig(); ConfDeInit(); ConfRestoreContextBackup(); + HtpConfigRestoreBackup(); FlowL7DataPtrFree(&f); StreamTcpFreeConfig(TRUE); diff --git a/src/app-layer-htp.h b/src/app-layer-htp.h index 67572fe9f2..b91ec654c7 100644 --- a/src/app-layer-htp.h +++ b/src/app-layer-htp.h @@ -85,7 +85,12 @@ typedef struct HtpBody_ { /** Now the Body Chunks will be stored per transaction, at * the tx user data */ typedef struct SCHtpTxUserData_ { - HtpBody body; /**< Body of the request (if any) */ + /* Body of the request (if any) */ + HtpBody body; + /* Holds the length of the htp request body */ + uint32_t content_len; + /* Holds the length of the htp request body seen so far */ + uint32_t content_len_so_far; } SCHtpTxUserData; typedef struct HtpState_ { diff --git a/src/detect-depth.c b/src/detect-depth.c index 53c7698bb0..cbb9f5b837 100644 --- a/src/detect-depth.c +++ b/src/detect-depth.c @@ -83,12 +83,13 @@ static int DetectDepthSetup (DetectEngineCtx *de_ctx, Signature *s, char *depths break; default: - pm = SigMatchGetLastSMFromLists(s, 4, + pm = SigMatchGetLastSMFromLists(s, 6, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_URICONTENT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH]); + DETECT_URICONTENT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], + DETECT_AL_HTTP_CLIENT_BODY, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]); if (pm == NULL) { SCLogError(SC_ERR_DEPTH_MISSING_CONTENT, "depth needs " - "preceeding content or uricontent option"); + "preceeding content or uricontent option or http_client_body option"); if (dubbed) SCFree(str); return -1; @@ -167,6 +168,20 @@ static int DetectDepthSetup (DetectEngineCtx *de_ctx, Signature *s, char *depths break; + case DETECT_AL_HTTP_CLIENT_BODY: + cd = (DetectContentData *)pm->ctx; + cd->depth = (uint32_t)atoi(str); + if (cd->depth < cd->content_len) { + cd->depth = cd->content_len; + SCLogDebug("depth increased to %"PRIu32" to match pattern len ", + cd->depth); + } + /* Now update the real limit, as depth is relative to the offset */ + cd->depth += cd->offset; + cd->flags |= DETECT_CONTENT_DEPTH; + + break; + default: SCLogError(SC_ERR_DEPTH_MISSING_CONTENT, "depth needs a preceeding " "content (or uricontent) option"); diff --git a/src/detect-distance.c b/src/detect-distance.c index 1fc03e2771..4c975caae7 100644 --- a/src/detect-distance.c +++ b/src/detect-distance.c @@ -163,12 +163,14 @@ static int DetectDistanceSetup (DetectEngineCtx *de_ctx, Signature *s, } } } else { - pm = SigMatchGetLastSMFromLists(s, 4, + pm = SigMatchGetLastSMFromLists(s, 6, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_URICONTENT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH]); + DETECT_URICONTENT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], + DETECT_AL_HTTP_CLIENT_BODY, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]); + if (pm == NULL) { SCLogError(SC_ERR_WITHIN_MISSING_CONTENT, "within needs" - "preceeding content or uricontent option"); + "preceeding content or uricontent option or http_client_body options"); if (dubbed) SCFree(str); return -1; @@ -361,6 +363,29 @@ static int DetectDistanceSetup (DetectEngineCtx *de_ctx, Signature *s, break; + case DETECT_AL_HTTP_CLIENT_BODY: + cd = (DetectContentData *)pm->ctx; + cd->distance = strtol(str, NULL, 10); + if (cd->flags & DETECT_CONTENT_WITHIN) { + if ((cd->distance + cd->content_len) > cd->within) { + cd->within = cd->distance + cd->content_len; + } + } + + cd->flags |= DETECT_CONTENT_DISTANCE; + + pm = SigMatchGetLastSMFromLists(s, 2, + DETECT_AL_HTTP_CLIENT_BODY, pm->prev); + if (pm == NULL) { + SCLogError(SC_ERR_DISTANCE_MISSING_CONTENT, "distance for http_client_body " + "needs preceeding http_client_body content"); + goto error; + } + + ((DetectContentData *)pm->ctx)->flags |= DETECT_CONTENT_RELATIVE_NEXT; + + break; + default: SCLogError(SC_ERR_DISTANCE_MISSING_CONTENT, "distance needs two " "preceeding content or uricontent options"); diff --git a/src/detect-engine-hcbd.c b/src/detect-engine-hcbd.c new file mode 100644 index 0000000000..a8723b9266 --- /dev/null +++ b/src/detect-engine-hcbd.c @@ -0,0 +1,2285 @@ +/* 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 + */ + +#include "suricata-common.h" +#include "suricata.h" +#include "decode.h" + +#include "detect.h" +#include "detect-engine.h" +#include "detect-parse.h" +#include "detect-engine-state.h" +#include "detect-uricontent.h" +#include "detect-urilen.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 uricontent. + * + * 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 uricontent payload to inspect. + * \param payload_len Length of the uricontent payload. + * + * \retval 0 no match. + * \retval 1 match. + */ +static int DoInspectHttpClientBody(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_CLIENT_BODY) { + if (payload_len == 0) { + SCReturnInt(0); + } + + DetectContentData *cd = (DetectContentData *)sm->ctx; + SCLogDebug("inspecting content %"PRIu32" payload_len %"PRIu32, cd->id, payload_len); + + /* rule parsers should take care of this */ + BUG_ON(cd->depth != 0 && cd->depth <= cd->offset); + + /* 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)) { + depth = prev_payload_offset + cd->within; + } + } + + 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; + BUG_ON(spayload_len > payload_len); + + /* 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; + } + + BUG_ON(sm->next == NULL); + SCLogDebug("uricontent %"PRIu32, cd->id); + + /* see if the next payload keywords match. If not, we will + * search for another occurence of this uricontent and see + * if the others match then until we run out of matches */ + int r = DoInspectHttpClientBody(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 { + /* we should never get here, but bail out just in case */ + BUG_ON(1); + } + + 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 = DoInspectHttpClientBody(de_ctx, det_ctx, s, sm->next, payload, + payload_len); + SCReturnInt(r); + } else { + SCReturnInt(1); + } +} + +/** + * \brief Do the http_client_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 DetectEngineInspectHttpClientBody(DetectEngineCtx *de_ctx, + DetectEngineThreadCtx *det_ctx, + Signature *s, Flow *f, uint8_t flags, + void *alstate) +{ + SCEnter(); + int r = 0; + HtpState *htp_state = NULL; + + htp_state = (HtpState *)alstate; + if (htp_state == NULL) { + SCLogDebug("no HTTP state"); + SCReturnInt(0); + } + + /* locking the flow, we will inspect the htp state */ + SCMutexLock(&f->m); + + if (htp_state->connp == NULL) { + SCLogDebug("HTP state has no connp"); + goto end; + } + + size_t idx = 0; + for ( ; idx < list_size(htp_state->connp->conn->transactions); idx++) + { + htp_tx_t *tx = list_get(htp_state->connp->conn->transactions, idx); + if (tx == NULL) + continue; + + SCHtpTxUserData *htud = (SCHtpTxUserData *) htp_tx_get_user_data(tx); + if (htud == NULL) + continue; + + HtpBodyChunk *cur = htud->body.first; + + if (htud->body.nchunks == 0) { + SCLogDebug("No http chunks to inspect"); + goto end; + } else { + /* no chunks?!! get out of here */ + if (cur == NULL) { + SCLogDebug("No http chunks to inspect"); + goto end; + } + + /* this applies only for the client request body like the keyword name says */ + if (htud->body.operation != HTP_BODY_REQUEST) { + SCLogDebug("htp chunk not a request chunk"); + goto end; + } + + if (htud->content_len != htud->content_len_so_far) + continue; + + uint8_t *chunks_buffer = NULL; + uint32_t total_chunks_len = 0; + while (cur != NULL) { + /* \todo Currently we limit the body length we inspect. We + * should change to handling chunks statefully */ + if (total_chunks_len > 20000) + break; + total_chunks_len += cur->len; + if ( (chunks_buffer = SCRealloc(chunks_buffer, total_chunks_len)) == NULL) { + return 0; + } + memcpy(chunks_buffer + total_chunks_len - cur->len, cur->data, cur->len); + cur = cur->next; + } + + r = DoInspectHttpClientBody(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_HCBDMATCH], + chunks_buffer, total_chunks_len); + SCFree(chunks_buffer); + if (r == 1) { + break; + } + } + } + +end: + SCMutexUnlock(&f->m); + SCReturnInt(r); +} + +/***********************************Unittests**********************************/ + +#ifdef UNITTESTS + +static int DetectEngineHttpClientBodyTest01(void) +{ + TcpSession ssn; + Packet *p1 = NULL; + Packet *p2 = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http1_buf[] = + "GET /index.html HTTP/1.1\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" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1"; + uint8_t http2_buf[] = + "This is dummy message body2"; + uint32_t http1_len = sizeof(http1_buf) - 1; + uint32_t http2_len = sizeof(http2_buf) - 1; + int result = 0; + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.src.family = AF_INET; + f.dst.family = AF_INET; + + p1->flow = &f; + p1->flowflags |= FLOW_PKT_TOSERVER; + p1->flowflags |= FLOW_PKT_ESTABLISHED; + p1->flags |= PKT_HAS_FLOW; + p2->flow = &f; + p2->flowflags |= FLOW_PKT_TOSERVER; + p2->flowflags |= FLOW_PKT_ESTABLISHED; + p2->flags |= PKT_HAS_FLOW; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + FlowL7DataPtrInit(&f); + + 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:body1This; http_client_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(&f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + goto end; + } + + http_state = f.aldata[AlpGetStateIdx(ALPROTO_HTTP)]; + 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(&f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + + if (!(PacketAlertCheck(p2, 1))) { + printf("sid 1 didn't match but should have"); + goto end; + } + + result = 1; + +end: + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + FlowL7DataPtrFree(&f); + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p1, 1); + UTHFreePackets(&p2, 1); + return result; +} + +static int DetectEngineHttpClientBodyTest02(void) +{ + TcpSession ssn; + Packet *p1 = NULL; + Packet *p2 = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http1_buf[] = + "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 19\r\n" + "\r\n" + "This is dummy body1"; + uint32_t http1_len = sizeof(http1_buf) - 1; + int result = 0; + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.src.family = AF_INET; + f.dst.family = AF_INET; + + p1->flow = &f; + p1->flowflags |= FLOW_PKT_TOSERVER; + p1->flowflags |= FLOW_PKT_ESTABLISHED; + p1->flags |= PKT_HAS_FLOW; + p2->flow = &f; + p2->flowflags |= FLOW_PKT_TOSERVER; + p2->flowflags |= FLOW_PKT_ESTABLISHED; + p2->flags |= PKT_HAS_FLOW; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + FlowL7DataPtrInit(&f); + + 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:body1; http_client_body; offset:5; " + "sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + int r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + goto end; + } + + http_state = f.aldata[AlpGetStateIdx(ALPROTO_HTTP)]; + 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); + + FlowL7DataPtrFree(&f); + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p1, 1); + UTHFreePackets(&p2, 1); + return result; +} + +static int DetectEngineHttpClientBodyTest03(void) +{ + TcpSession ssn; + Packet *p1 = NULL; + Packet *p2 = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http1_buf[] = + "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1"; + uint8_t http2_buf[] = + "This is dummy message body2"; + uint32_t http1_len = sizeof(http1_buf) - 1; + uint32_t http2_len = sizeof(http2_buf) - 1; + int result = 0; + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.src.family = AF_INET; + f.dst.family = AF_INET; + + p1->flow = &f; + p1->flowflags |= FLOW_PKT_TOSERVER; + p1->flowflags |= FLOW_PKT_ESTABLISHED; + p1->flags |= PKT_HAS_FLOW; + p2->flow = &f; + p2->flowflags |= FLOW_PKT_TOSERVER; + p2->flowflags |= FLOW_PKT_ESTABLISHED; + p2->flags |= PKT_HAS_FLOW; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + FlowL7DataPtrInit(&f); + + 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:body1; http_client_body; offset:16; " + "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(&f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + goto end; + } + + http_state = f.aldata[AlpGetStateIdx(ALPROTO_HTTP)]; + 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(&f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + + if (PacketAlertCheck(p2, 1)) { + printf("sid 1 didn't match but should have"); + goto end; + } + + result = 1; + +end: + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + FlowL7DataPtrFree(&f); + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p1, 1); + UTHFreePackets(&p2, 1); + return result; +} + +static int DetectEngineHttpClientBodyTest04(void) +{ + TcpSession ssn; + Packet *p1 = NULL; + Packet *p2 = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http1_buf[] = + "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1"; + uint8_t http2_buf[] = + "This is dummy message body2"; + uint32_t http1_len = sizeof(http1_buf) - 1; + uint32_t http2_len = sizeof(http2_buf) - 1; + int result = 0; + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.src.family = AF_INET; + f.dst.family = AF_INET; + + p1->flow = &f; + p1->flowflags |= FLOW_PKT_TOSERVER; + p1->flowflags |= FLOW_PKT_ESTABLISHED; + p1->flags |= PKT_HAS_FLOW; + p2->flow = &f; + p2->flowflags |= FLOW_PKT_TOSERVER; + p2->flowflags |= FLOW_PKT_ESTABLISHED; + p2->flags |= PKT_HAS_FLOW; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + FlowL7DataPtrInit(&f); + + 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:!body1; http_client_body; offset:16; " + "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(&f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + goto end; + } + + http_state = f.aldata[AlpGetStateIdx(ALPROTO_HTTP)]; + 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(&f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + + if (!PacketAlertCheck(p2, 1)) { + printf("sid 1 didn't match but should have"); + goto end; + } + + result = 1; + +end: + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + FlowL7DataPtrFree(&f); + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p1, 1); + UTHFreePackets(&p2, 1); + return result; +} + +static int DetectEngineHttpClientBodyTest05(void) +{ + TcpSession ssn; + Packet *p1 = NULL; + Packet *p2 = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http1_buf[] = + "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1"; + uint8_t http2_buf[] = + "This is dummy message body2"; + uint32_t http1_len = sizeof(http1_buf) - 1; + uint32_t http2_len = sizeof(http2_buf) - 1; + int result = 0; + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.src.family = AF_INET; + f.dst.family = AF_INET; + + p1->flow = &f; + p1->flowflags |= FLOW_PKT_TOSERVER; + p1->flowflags |= FLOW_PKT_ESTABLISHED; + p1->flags |= PKT_HAS_FLOW; + p2->flow = &f; + p2->flowflags |= FLOW_PKT_TOSERVER; + p2->flowflags |= FLOW_PKT_ESTABLISHED; + p2->flags |= PKT_HAS_FLOW; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + FlowL7DataPtrInit(&f); + + 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:body1; http_client_body; depth:25; " + "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(&f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + goto end; + } + + http_state = f.aldata[AlpGetStateIdx(ALPROTO_HTTP)]; + 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(&f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + + if (!PacketAlertCheck(p2, 1)) { + printf("sid 1 didn't match but should have"); + goto end; + } + + result = 1; + +end: + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + FlowL7DataPtrFree(&f); + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p1, 1); + UTHFreePackets(&p2, 1); + return result; +} + +static int DetectEngineHttpClientBodyTest06(void) +{ + TcpSession ssn; + Packet *p1 = NULL; + Packet *p2 = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http1_buf[] = + "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1"; + uint8_t http2_buf[] = + "This is dummy message body2"; + uint32_t http1_len = sizeof(http1_buf) - 1; + uint32_t http2_len = sizeof(http2_buf) - 1; + int result = 0; + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.src.family = AF_INET; + f.dst.family = AF_INET; + + p1->flow = &f; + p1->flowflags |= FLOW_PKT_TOSERVER; + p1->flowflags |= FLOW_PKT_ESTABLISHED; + p1->flags |= PKT_HAS_FLOW; + p2->flow = &f; + p2->flowflags |= FLOW_PKT_TOSERVER; + p2->flowflags |= FLOW_PKT_ESTABLISHED; + p2->flags |= PKT_HAS_FLOW; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + FlowL7DataPtrInit(&f); + + 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:!body1; http_client_body; depth:25; " + "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(&f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + goto end; + } + + http_state = f.aldata[AlpGetStateIdx(ALPROTO_HTTP)]; + 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(&f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + + if (PacketAlertCheck(p2, 1)) { + printf("sid 1 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); + + FlowL7DataPtrFree(&f); + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p1, 1); + UTHFreePackets(&p2, 1); + return result; +} + +static int DetectEngineHttpClientBodyTest07(void) +{ + TcpSession ssn; + Packet *p1 = NULL; + Packet *p2 = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http1_buf[] = + "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1"; + uint8_t http2_buf[] = + "This is dummy message body2"; + uint32_t http1_len = sizeof(http1_buf) - 1; + uint32_t http2_len = sizeof(http2_buf) - 1; + int result = 0; + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.src.family = AF_INET; + f.dst.family = AF_INET; + + p1->flow = &f; + p1->flowflags |= FLOW_PKT_TOSERVER; + p1->flowflags |= FLOW_PKT_ESTABLISHED; + p1->flags |= PKT_HAS_FLOW; + p2->flow = &f; + p2->flowflags |= FLOW_PKT_TOSERVER; + p2->flowflags |= FLOW_PKT_ESTABLISHED; + p2->flags |= PKT_HAS_FLOW; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + FlowL7DataPtrInit(&f); + + 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:!body1; http_client_body; depth:15; " + "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(&f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + goto end; + } + + http_state = f.aldata[AlpGetStateIdx(ALPROTO_HTTP)]; + 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(&f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + + if (!PacketAlertCheck(p2, 1)) { + printf("sid 1 didn't match but should have"); + goto end; + } + + result = 1; + +end: + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + FlowL7DataPtrFree(&f); + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p1, 1); + UTHFreePackets(&p2, 1); + return result; +} + +static int DetectEngineHttpClientBodyTest08(void) +{ + TcpSession ssn; + Packet *p1 = NULL; + Packet *p2 = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http1_buf[] = + "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1"; + uint8_t http2_buf[] = + "This is dummy message body2"; + uint32_t http1_len = sizeof(http1_buf) - 1; + uint32_t http2_len = sizeof(http2_buf) - 1; + int result = 0; + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.src.family = AF_INET; + f.dst.family = AF_INET; + + p1->flow = &f; + p1->flowflags |= FLOW_PKT_TOSERVER; + p1->flowflags |= FLOW_PKT_ESTABLISHED; + p1->flags |= PKT_HAS_FLOW; + p2->flow = &f; + p2->flowflags |= FLOW_PKT_TOSERVER; + p2->flowflags |= FLOW_PKT_ESTABLISHED; + p2->flags |= PKT_HAS_FLOW; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + FlowL7DataPtrInit(&f); + + 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:!body1; http_client_body; depth:25; " + "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(&f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + goto end; + } + + http_state = f.aldata[AlpGetStateIdx(ALPROTO_HTTP)]; + 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(&f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + + if (PacketAlertCheck(p2, 1)) { + printf("sid 1 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); + + FlowL7DataPtrFree(&f); + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p1, 1); + UTHFreePackets(&p2, 1); + return result; +} + +static int DetectEngineHttpClientBodyTest09(void) +{ + TcpSession ssn; + Packet *p1 = NULL; + Packet *p2 = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http1_buf[] = + "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1"; + uint8_t http2_buf[] = + "This is dummy message body2"; + uint32_t http1_len = sizeof(http1_buf) - 1; + uint32_t http2_len = sizeof(http2_buf) - 1; + int result = 0; + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.src.family = AF_INET; + f.dst.family = AF_INET; + + p1->flow = &f; + p1->flowflags |= FLOW_PKT_TOSERVER; + p1->flowflags |= FLOW_PKT_ESTABLISHED; + p1->flags |= PKT_HAS_FLOW; + p2->flow = &f; + p2->flowflags |= FLOW_PKT_TOSERVER; + p2->flowflags |= FLOW_PKT_ESTABLISHED; + p2->flags |= PKT_HAS_FLOW; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + FlowL7DataPtrInit(&f); + + 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:body1; http_client_body; " + "content:This; http_client_body; within:5; " + "sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + int r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + goto end; + } + + http_state = f.aldata[AlpGetStateIdx(ALPROTO_HTTP)]; + 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(&f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + + if (!PacketAlertCheck(p2, 1)) { + printf("sid 1 didn't match but should have"); + goto end; + } + + result = 1; + +end: + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + FlowL7DataPtrFree(&f); + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p1, 1); + UTHFreePackets(&p2, 1); + return result; +} + +static int DetectEngineHttpClientBodyTest10(void) +{ + TcpSession ssn; + Packet *p1 = NULL; + Packet *p2 = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http1_buf[] = + "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1"; + uint8_t http2_buf[] = + "This is dummy message body2"; + uint32_t http1_len = sizeof(http1_buf) - 1; + uint32_t http2_len = sizeof(http2_buf) - 1; + int result = 0; + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.src.family = AF_INET; + f.dst.family = AF_INET; + + p1->flow = &f; + p1->flowflags |= FLOW_PKT_TOSERVER; + p1->flowflags |= FLOW_PKT_ESTABLISHED; + p1->flags |= PKT_HAS_FLOW; + p2->flow = &f; + p2->flowflags |= FLOW_PKT_TOSERVER; + p2->flowflags |= FLOW_PKT_ESTABLISHED; + p2->flags |= PKT_HAS_FLOW; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + FlowL7DataPtrInit(&f); + + 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:body1; http_client_body; " + "content:!boom; http_client_body; within:5; " + "sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + int r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + goto end; + } + + http_state = f.aldata[AlpGetStateIdx(ALPROTO_HTTP)]; + 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(&f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + + if (!PacketAlertCheck(p2, 1)) { + printf("sid 1 didn't match but should have"); + goto end; + } + + result = 1; + +end: + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + FlowL7DataPtrFree(&f); + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p1, 1); + UTHFreePackets(&p2, 1); + return result; +} + +static int DetectEngineHttpClientBodyTest11(void) +{ + TcpSession ssn; + Packet *p1 = NULL; + Packet *p2 = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http1_buf[] = + "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1"; + uint8_t http2_buf[] = + "This is dummy message body2"; + uint32_t http1_len = sizeof(http1_buf) - 1; + uint32_t http2_len = sizeof(http2_buf) - 1; + int result = 0; + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.src.family = AF_INET; + f.dst.family = AF_INET; + + p1->flow = &f; + p1->flowflags |= FLOW_PKT_TOSERVER; + p1->flowflags |= FLOW_PKT_ESTABLISHED; + p1->flags |= PKT_HAS_FLOW; + p2->flow = &f; + p2->flowflags |= FLOW_PKT_TOSERVER; + p2->flowflags |= FLOW_PKT_ESTABLISHED; + p2->flags |= PKT_HAS_FLOW; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + FlowL7DataPtrInit(&f); + + 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:body1; http_client_body; " + "content:boom; http_client_body; within:5; " + "sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + int r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + goto end; + } + + http_state = f.aldata[AlpGetStateIdx(ALPROTO_HTTP)]; + 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(&f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + + if (PacketAlertCheck(p2, 1)) { + printf("sid 1 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); + + FlowL7DataPtrFree(&f); + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p1, 1); + UTHFreePackets(&p2, 1); + return result; +} + +static int DetectEngineHttpClientBodyTest12(void) +{ + TcpSession ssn; + Packet *p1 = NULL; + Packet *p2 = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http1_buf[] = + "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1"; + uint8_t http2_buf[] = + "This is dummy message body2"; + uint32_t http1_len = sizeof(http1_buf) - 1; + uint32_t http2_len = sizeof(http2_buf) - 1; + int result = 0; + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.src.family = AF_INET; + f.dst.family = AF_INET; + + p1->flow = &f; + p1->flowflags |= FLOW_PKT_TOSERVER; + p1->flowflags |= FLOW_PKT_ESTABLISHED; + p1->flags |= PKT_HAS_FLOW; + p2->flow = &f; + p2->flowflags |= FLOW_PKT_TOSERVER; + p2->flowflags |= FLOW_PKT_ESTABLISHED; + p2->flags |= PKT_HAS_FLOW; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + FlowL7DataPtrInit(&f); + + 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:body1; http_client_body; " + "content:!This; http_client_body; within:5; " + "sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + int r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + goto end; + } + + http_state = f.aldata[AlpGetStateIdx(ALPROTO_HTTP)]; + 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(&f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + + if (PacketAlertCheck(p2, 1)) { + printf("sid 1 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); + + FlowL7DataPtrFree(&f); + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p1, 1); + UTHFreePackets(&p2, 1); + return result; +} + +static int DetectEngineHttpClientBodyTest13(void) +{ + TcpSession ssn; + Packet *p1 = NULL; + Packet *p2 = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http1_buf[] = + "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1"; + uint8_t http2_buf[] = + "This is dummy message body2"; + uint32_t http1_len = sizeof(http1_buf) - 1; + uint32_t http2_len = sizeof(http2_buf) - 1; + int result = 0; + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.src.family = AF_INET; + f.dst.family = AF_INET; + + p1->flow = &f; + p1->flowflags |= FLOW_PKT_TOSERVER; + p1->flowflags |= FLOW_PKT_ESTABLISHED; + p1->flags |= PKT_HAS_FLOW; + p2->flow = &f; + p2->flowflags |= FLOW_PKT_TOSERVER; + p2->flowflags |= FLOW_PKT_ESTABLISHED; + p2->flags |= PKT_HAS_FLOW; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + FlowL7DataPtrInit(&f); + + 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:body1; http_client_body; " + "content:dummy; http_client_body; distance:5; " + "sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + int r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + goto end; + } + + http_state = f.aldata[AlpGetStateIdx(ALPROTO_HTTP)]; + 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(&f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + + if (!PacketAlertCheck(p2, 1)) { + printf("sid 1 didn't match but should have"); + goto end; + } + + result = 1; + +end: + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + FlowL7DataPtrFree(&f); + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p1, 1); + UTHFreePackets(&p2, 1); + return result; +} + +static int DetectEngineHttpClientBodyTest14(void) +{ + TcpSession ssn; + Packet *p1 = NULL; + Packet *p2 = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http1_buf[] = + "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1"; + uint8_t http2_buf[] = + "This is dummy message body2"; + uint32_t http1_len = sizeof(http1_buf) - 1; + uint32_t http2_len = sizeof(http2_buf) - 1; + int result = 0; + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.src.family = AF_INET; + f.dst.family = AF_INET; + + p1->flow = &f; + p1->flowflags |= FLOW_PKT_TOSERVER; + p1->flowflags |= FLOW_PKT_ESTABLISHED; + p1->flags |= PKT_HAS_FLOW; + p2->flow = &f; + p2->flowflags |= FLOW_PKT_TOSERVER; + p2->flowflags |= FLOW_PKT_ESTABLISHED; + p2->flags |= PKT_HAS_FLOW; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + FlowL7DataPtrInit(&f); + + 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:body1; http_client_body; " + "content:!dummy; http_client_body; distance:10; " + "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(&f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + goto end; + } + + http_state = f.aldata[AlpGetStateIdx(ALPROTO_HTTP)]; + 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(&f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + + if (!PacketAlertCheck(p2, 1)) { + printf("sid 1 didn't match but should have"); + goto end; + } + + result = 1; + +end: + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + FlowL7DataPtrFree(&f); + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p1, 1); + UTHFreePackets(&p2, 1); + return result; +} + +static int DetectEngineHttpClientBodyTest15(void) +{ + TcpSession ssn; + Packet *p1 = NULL; + Packet *p2 = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http1_buf[] = + "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1"; + uint8_t http2_buf[] = + "This is dummy message body2"; + uint32_t http1_len = sizeof(http1_buf) - 1; + uint32_t http2_len = sizeof(http2_buf) - 1; + int result = 0; + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.src.family = AF_INET; + f.dst.family = AF_INET; + + p1->flow = &f; + p1->flowflags |= FLOW_PKT_TOSERVER; + p1->flowflags |= FLOW_PKT_ESTABLISHED; + p1->flags |= PKT_HAS_FLOW; + p2->flow = &f; + p2->flowflags |= FLOW_PKT_TOSERVER; + p2->flowflags |= FLOW_PKT_ESTABLISHED; + p2->flags |= PKT_HAS_FLOW; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + FlowL7DataPtrInit(&f); + + 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:body1; http_client_body; " + "content:dummy; http_client_body; distance:10; " + "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(&f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + goto end; + } + + http_state = f.aldata[AlpGetStateIdx(ALPROTO_HTTP)]; + 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(&f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + + if (PacketAlertCheck(p2, 1)) { + printf("sid 1 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); + + FlowL7DataPtrFree(&f); + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p1, 1); + UTHFreePackets(&p2, 1); + return result; +} + +static int DetectEngineHttpClientBodyTest16(void) +{ + TcpSession ssn; + Packet *p1 = NULL; + Packet *p2 = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http1_buf[] = + "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1"; + uint8_t http2_buf[] = + "This is dummy message body2"; + uint32_t http1_len = sizeof(http1_buf) - 1; + uint32_t http2_len = sizeof(http2_buf) - 1; + int result = 0; + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.src.family = AF_INET; + f.dst.family = AF_INET; + + p1->flow = &f; + p1->flowflags |= FLOW_PKT_TOSERVER; + p1->flowflags |= FLOW_PKT_ESTABLISHED; + p1->flags |= PKT_HAS_FLOW; + p2->flow = &f; + p2->flowflags |= FLOW_PKT_TOSERVER; + p2->flowflags |= FLOW_PKT_ESTABLISHED; + p2->flags |= PKT_HAS_FLOW; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + FlowL7DataPtrInit(&f); + + 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:body1; http_client_body; " + "content:!dummy; http_client_body; distance:5; " + "sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + int r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + goto end; + } + + http_state = f.aldata[AlpGetStateIdx(ALPROTO_HTTP)]; + 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(&f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + + if (PacketAlertCheck(p2, 1)) { + printf("sid 1 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); + + FlowL7DataPtrFree(&f); + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p1, 1); + UTHFreePackets(&p2, 1); + return result; +} + +#endif /* UNITTESTS */ + +void HttpClientBodyRegisterTests(void) +{ + +#ifdef UNITTESTS + UtRegisterTest("DetectEngineHttpClientBodyTest01", + DetectEngineHttpClientBodyTest01, 1); + UtRegisterTest("DetectEngineHttpClientBodyTest02", + DetectEngineHttpClientBodyTest02, 1); + UtRegisterTest("DetectEngineHttpClientBodyTest03", + DetectEngineHttpClientBodyTest03, 1); + UtRegisterTest("DetectEngineHttpClientBodyTest04", + DetectEngineHttpClientBodyTest04, 1); + UtRegisterTest("DetectEngineHttpClientBodyTest05", + DetectEngineHttpClientBodyTest05, 1); + UtRegisterTest("DetectEngineHttpClientBodyTest06", + DetectEngineHttpClientBodyTest06, 1); + UtRegisterTest("DetectEngineHttpClientBodyTest07", + DetectEngineHttpClientBodyTest07, 1); + UtRegisterTest("DetectEngineHttpClientBodyTest08", + DetectEngineHttpClientBodyTest08, 1); + UtRegisterTest("DetectEngineHttpClientBodyTest09", + DetectEngineHttpClientBodyTest09, 1); + UtRegisterTest("DetectEngineHttpClientBodyTest10", + DetectEngineHttpClientBodyTest10, 1); + UtRegisterTest("DetectEngineHttpClientBodyTest11", + DetectEngineHttpClientBodyTest11, 1); + UtRegisterTest("DetectEngineHttpClientBodyTest12", + DetectEngineHttpClientBodyTest12, 1); + UtRegisterTest("DetectEngineHttpClientBodyTest13", + DetectEngineHttpClientBodyTest13, 1); + UtRegisterTest("DetectEngineHttpClientBodyTest14", + DetectEngineHttpClientBodyTest14, 1); + UtRegisterTest("DetectEngineHttpClientBodyTest15", + DetectEngineHttpClientBodyTest15, 1); + UtRegisterTest("DetectEngineHttpClientBodyTest16", + DetectEngineHttpClientBodyTest16, 1); +#endif /* UNITTESTS */ + + return; +} diff --git a/src/detect-engine-hcbd.h b/src/detect-engine-hcbd.h new file mode 100644 index 0000000000..47a927773a --- /dev/null +++ b/src/detect-engine-hcbd.h @@ -0,0 +1,31 @@ +/* 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_HCBD_H__ +#define __DETECT_ENGINE_HCBD_H__ + +int DetectEngineInspectHttpClientBody(DetectEngineCtx *, DetectEngineThreadCtx *, + Signature *, Flow *, uint8_t, void *); +void HttpClientBodyRegisterTests(void); + +#endif /* __DETECT_ENGINE_HCBD_H__ */ + diff --git a/src/detect-engine-state.c b/src/detect-engine-state.c index dda76cc6b2..6a710ddf8e 100644 --- a/src/detect-engine-state.c +++ b/src/detect-engine-state.c @@ -31,6 +31,7 @@ #include "detect-engine-state.h" #include "detect-engine-uri.h" +#include "detect-engine-hcbd.h" #include "detect-engine-dcepayload.h" #include "stream-tcp.h" @@ -194,15 +195,16 @@ int DeStateUpdateInspectTransactionId(Flow *f, char direction) { } /** - * \brief Append a signature to the detect engine state + * \brief Append a signature to the detect engine state * - * \param state the detect engine state - * \param s signature - * \param sm sigmatch - * \param uri did uri already match (if any) - * \param dce did dce already match (if any) + * \param state the detect engine state + * \param s signature + * \param sm sigmatch + * \param uri did uri already match (if any) + * \param dce did dce already match (if any) + * \param hcbd did http client body already match (if any) */ -static void DeStateSignatureAppend(DetectEngineState *state, Signature *s, SigMatch *sm, char uri, char dce) { +static void DeStateSignatureAppend(DetectEngineState *state, Signature *s, SigMatch *sm, char uri, char dce, char hcbd) { DeStateStore *store = state->tail; if (store == NULL) { @@ -236,12 +238,17 @@ static void DeStateSignatureAppend(DetectEngineState *state, Signature *s, SigMa if (dce) { store->store[idx].flags |= DE_STATE_FLAG_DCE_MATCH; } + if (hcbd) { + store->store[idx].flags |= DE_STATE_FLAG_HCBD_MATCH; + } store->store[idx].nm = sm; state->cnt++; SCLogDebug("store %p idx %"PRIuMAX" cnt %"PRIuMAX" sig id %"PRIuMAX"", store, (uintmax_t)idx, (uintmax_t)state->cnt, (uintmax_t)store->store[idx].sid); + + return; } @@ -293,6 +300,8 @@ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, int r = 0; char umatch = 0; char uinspect = 0; + char hcbdmatch = 0; + char hcbdinspect = 0; char dmatch = 0; char dinspect = 0; char appinspect = 0; @@ -320,6 +329,14 @@ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, SCLogDebug("uri inspected but no match"); } } + if (s->sm_lists[DETECT_SM_LIST_HCBDMATCH] != NULL) { + hcbdinspect = 1; + if (DetectEngineInspectHttpClientBody(de_ctx, det_ctx, s, f, + flags, alstate) == 1) { + hcbdmatch = 1; + } + SCLogDebug("inspecting http client body"); + } } else if (alproto == ALPROTO_DCERPC || alproto == ALPROTO_SMB || alproto == ALPROTO_SMB2) { if (s->sm_lists[DETECT_SM_LIST_DMATCH] != NULL) { dinspect = 1; @@ -350,8 +367,8 @@ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, } } - appinspect = uinspect + dinspect; - appmatch = umatch + dmatch; + appinspect = uinspect + dinspect + hcbdinspect; + appmatch = umatch + dmatch + hcbdmatch; if (s->sm_lists[DETECT_SM_LIST_AMATCH] != NULL) { for ( ; sm != NULL; sm = sm->next) { @@ -393,8 +410,8 @@ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, } } - SCLogDebug("detection done, store results: sm %p, uri %d, dce %d", - sm, umatch, dmatch); + SCLogDebug("detection done, store results: sm %p, uri %d, dce %d", hcbd %d, + sm, umatch, dmatch, hcbdmatch); SCMutexLock(&f->de_state_m); /* match or no match, we store the state anyway @@ -404,7 +421,7 @@ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, f->de_state = DetectEngineStateAlloc(); } if (f->de_state != NULL) { - DeStateSignatureAppend(f->de_state, s, sm, umatch, dmatch); + DeStateSignatureAppend(f->de_state, s, sm, umatch, dmatch, hcbdmatch); } SCMutexUnlock(&f->de_state_m); @@ -426,6 +443,8 @@ int DeStateDetectContinueDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, Dete int match = 0; char umatch = 0; char uinspect = 0; + char hcbdmatch = 0; + char hcbdinspect = 0; char dmatch = 0; char dinspect = 0; char appinspect = 0; @@ -452,6 +471,8 @@ int DeStateDetectContinueDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, Dete umatch = 0; uinspect = 0; + hcbdmatch = 0; + hcbdinspect = 0; dmatch = 0; dinspect = 0; appinspect = 0; @@ -495,6 +516,19 @@ int DeStateDetectContinueDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, Dete SCLogDebug("uri already inspected"); } } + if (s->sm_lists[DETECT_SM_LIST_HCBDMATCH] != NULL) { + if (!(item->flags & DE_STATE_FLAG_HCBD_MATCH)) { + SCLogDebug("inspecting http client body data"); + hcbdinspect = 1; + + if (DetectEngineInspectHttpClientBody(de_ctx, det_ctx, s, f, + flags, alstate) == 1) { + SCLogDebug("uri matched"); + item->flags |= DE_STATE_FLAG_HCBD_MATCH; + hcbdmatch = 1; + } + } + } } else if (alproto == ALPROTO_DCERPC || alproto == ALPROTO_SMB || alproto == ALPROTO_SMB2) { if (s->sm_lists[DETECT_SM_LIST_DMATCH] != NULL) { if (!(item->flags & DE_STATE_FLAG_DCE_MATCH)) { @@ -532,8 +566,8 @@ int DeStateDetectContinueDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, Dete } - appinspect = uinspect + dinspect; - appmatch = umatch + dmatch; + appinspect = uinspect + dinspect + hcbdinspect; + appmatch = umatch + dmatch + hcbdmatch; SCLogDebug("appinspect %d, appmatch %d", appinspect, appmatch); /* next, check the other sig matches */ @@ -673,39 +707,39 @@ static int DeStateTest02(void) { memset(&s, 0x00, sizeof(s)); s.num = 0; - DeStateSignatureAppend(state, &s, NULL, 0, 0); + DeStateSignatureAppend(state, &s, NULL, 0, 0, 0); s.num = 11; - DeStateSignatureAppend(state, &s, NULL, 0, 0); + DeStateSignatureAppend(state, &s, NULL, 0, 0, 0); s.num = 22; - DeStateSignatureAppend(state, &s, NULL, 0, 0); + DeStateSignatureAppend(state, &s, NULL, 0, 0, 0); s.num = 33; - DeStateSignatureAppend(state, &s, NULL, 0, 0); + DeStateSignatureAppend(state, &s, NULL, 0, 0, 0); s.num = 44; - DeStateSignatureAppend(state, &s, NULL, 0, 0); + DeStateSignatureAppend(state, &s, NULL, 0, 0, 0); s.num = 55; - DeStateSignatureAppend(state, &s, NULL, 0, 0); + DeStateSignatureAppend(state, &s, NULL, 0, 0, 0); s.num = 66; - DeStateSignatureAppend(state, &s, NULL, 0, 0); + DeStateSignatureAppend(state, &s, NULL, 0, 0, 0); s.num = 77; - DeStateSignatureAppend(state, &s, NULL, 0, 0); + DeStateSignatureAppend(state, &s, NULL, 0, 0, 0); s.num = 88; - DeStateSignatureAppend(state, &s, NULL, 0, 0); + DeStateSignatureAppend(state, &s, NULL, 0, 0, 0); s.num = 99; - DeStateSignatureAppend(state, &s, NULL, 0, 0); + DeStateSignatureAppend(state, &s, NULL, 0, 0, 0); s.num = 100; - DeStateSignatureAppend(state, &s, NULL, 0, 0); + DeStateSignatureAppend(state, &s, NULL, 0, 0, 0); s.num = 111; - DeStateSignatureAppend(state, &s, NULL, 0, 0); + DeStateSignatureAppend(state, &s, NULL, 0, 0, 0); s.num = 122; - DeStateSignatureAppend(state, &s, NULL, 0, 0); + DeStateSignatureAppend(state, &s, NULL, 0, 0, 0); s.num = 133; - DeStateSignatureAppend(state, &s, NULL, 0, 0); + DeStateSignatureAppend(state, &s, NULL, 0, 0, 0); s.num = 144; - DeStateSignatureAppend(state, &s, NULL, 0, 0); + DeStateSignatureAppend(state, &s, NULL, 0, 0, 0); s.num = 155; - DeStateSignatureAppend(state, &s, NULL, 0, 0); + DeStateSignatureAppend(state, &s, NULL, 0, 0, 0); s.num = 166; - DeStateSignatureAppend(state, &s, NULL, 0, 0); + DeStateSignatureAppend(state, &s, NULL, 0, 0, 0); if (state->head == NULL) { goto end; @@ -748,9 +782,9 @@ static int DeStateTest03(void) { memset(&s, 0x00, sizeof(s)); s.num = 11; - DeStateSignatureAppend(state, &s, NULL, 0, 0); + DeStateSignatureAppend(state, &s, NULL, 0, 0, 0); s.num = 22; - DeStateSignatureAppend(state, &s, NULL, 1, 0); + DeStateSignatureAppend(state, &s, NULL, 1, 0, 0); if (state->head == NULL) { goto end; diff --git a/src/detect-engine-state.h b/src/detect-engine-state.h index 63f813e119..dba2504971 100644 --- a/src/detect-engine-state.h +++ b/src/detect-engine-state.h @@ -47,7 +47,8 @@ #define DE_STATE_FLAG_PAYLOAD_MATCH 0x01 /**< payload part of the sig matched */ #define DE_STATE_FLAG_URI_MATCH 0x02 /**< uri part of the sig matched */ #define DE_STATE_FLAG_DCE_MATCH 0x04 /**< dce payload inspection part matched */ -#define DE_STATE_FLAG_FULL_MATCH 0x08 /**< sig already fully matched */ +#define DE_STATE_FLAG_HCBD_MATCH 0x08 /**< hcbd payload inspection part matched */ +#define DE_STATE_FLAG_FULL_MATCH 0x10 /**< sig already fully matched */ /** per signature detection engine state */ typedef enum { diff --git a/src/detect-http-client-body.c b/src/detect-http-client-body.c index 1512a43101..67b46c5997 100644 --- a/src/detect-http-client-body.c +++ b/src/detect-http-client-body.c @@ -64,11 +64,11 @@ void DetectHttpClientBodyRegister(void) { sigmatch_table[DETECT_AL_HTTP_CLIENT_BODY].name = "http_client_body"; sigmatch_table[DETECT_AL_HTTP_CLIENT_BODY].Match = NULL; - sigmatch_table[DETECT_AL_HTTP_CLIENT_BODY].AppLayerMatch = DetectHttpClientBodyMatch; - sigmatch_table[DETECT_AL_HTTP_CLIENT_BODY].alproto = ALPROTO_HTTP; + sigmatch_table[DETECT_AL_HTTP_CLIENT_BODY].AppLayerMatch = NULL; sigmatch_table[DETECT_AL_HTTP_CLIENT_BODY].Setup = DetectHttpClientBodySetup; sigmatch_table[DETECT_AL_HTTP_CLIENT_BODY].Free = DetectHttpClientBodyFree; sigmatch_table[DETECT_AL_HTTP_CLIENT_BODY].RegisterTests = DetectHttpClientBodyRegisterTests; + sigmatch_table[DETECT_AL_HTTP_CLIENT_BODY].alproto = ALPROTO_HTTP; sigmatch_table[DETECT_AL_HTTP_CLIENT_BODY].flags |= SIGMATCH_PAYLOAD ; } @@ -235,39 +235,34 @@ int DetectHttpClientBodySetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) goto error; } - /* setup the HttpClientBodyData's data from content data structure's data */ - hcbd = SCMalloc(sizeof(DetectContentData)); - if (hcbd == NULL) - goto error; - memset(hcbd, 0, sizeof(DetectContentData)); - - /* transfer the pattern details from the content struct to the clientbody struct */ - hcbd->content = ((DetectContentData *)sm->ctx)->content; - hcbd->content_len = ((DetectContentData *)sm->ctx)->content_len; - hcbd->flags |= (((DetectContentData *)sm->ctx)->flags & DETECT_CONTENT_NOCASE) ? - DETECT_CONTENT_NOCASE : 0; - hcbd->flags |= (((DetectContentData *)sm->ctx)->flags & DETECT_CONTENT_NEGATED) ? - DETECT_CONTENT_NEGATED : 0; - //hcbd->id = ((DetectContentData *)sm->ctx)->id; - hcbd->id = DetectPatternGetId(de_ctx->mpm_pattern_id_store, hcbd, DETECT_AL_HTTP_CLIENT_BODY); - hcbd->bm_ctx = ((DetectContentData *)sm->ctx)->bm_ctx; - - nm = SigMatchAlloc(); - if (nm == NULL) { - SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); - goto error; + DetectContentData *cd = (DetectContentData *)sm->ctx; + if (cd->flags & DETECT_CONTENT_WITHIN || cd->flags & DETECT_CONTENT_DISTANCE) { + SigMatch *pm = SigMatchGetLastSMFromLists(s, 2, + DETECT_CONTENT, sm->prev); + /* pm is never NULL. So no NULL check */ + DetectContentData *tmp_cd = (DetectContentData *)pm->ctx; + tmp_cd->flags &= ~DETECT_CONTENT_RELATIVE_NEXT; + + pm = SigMatchGetLastSMFromLists(s, 2, + DETECT_AL_HTTP_CLIENT_BODY, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]); + if (pm == NULL) { + SCLogError(SC_ERR_INVALID_SIGNATURE, "http_client_body seen with a " + "distance or within without a previous http_client_body " + "content. Invalidating signature."); + goto error; + } + tmp_cd = (DetectContentData *)pm->ctx; + tmp_cd->flags |= DETECT_CONTENT_RELATIVE_NEXT; } - nm->type = DETECT_AL_HTTP_CLIENT_BODY; - nm->ctx = (void *)hcbd; + cd->id = DetectPatternGetId(de_ctx->mpm_pattern_id_store, cd, DETECT_AL_HTTP_CLIENT_BODY); + sm->type = DETECT_AL_HTTP_CLIENT_BODY; - /* pull the previous content from the pmatch list, append - * the new match to the match list */ - SigMatchReplaceContent(s, sm, nm); - - /* free the old content sigmatch, the content pattern memory - * is taken over by the new sigmatch */ - SCFree(sm->ctx); - SCFree(sm); + /* transfer the sm from the pmatch list to hcbdmatch list */ + SigMatchTransferSigMatchAcrossLists(sm, + &s->sm_lists[DETECT_SM_LIST_PMATCH], + &s->sm_lists_tail[DETECT_SM_LIST_PMATCH], + &s->sm_lists[DETECT_SM_LIST_HCBDMATCH], + &s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]); /* flag the signature to indicate that we scan the app layer data */ s->flags |= SIG_FLAG_APPLAYER; @@ -484,7 +479,7 @@ static int DetectHttpClientBodyTest06(void) "Content-Type: text/html\r\n" "Content-Length: 26\r\n" "\r\n" - "This is dummy message body\r\n"; + "This is dummy message body"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; @@ -581,11 +576,11 @@ static int DetectHttpClientBodyTest07(void) "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" "Content-Type: text/html\r\n" - "Content-Length: 67\r\n" + "Content-Length: 54\r\n" "\r\n" "This is dummy message body1"; uint8_t http2_buf[] = - "This is dummy message body2\r\n"; + "This is dummy message body2"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; @@ -647,8 +642,8 @@ static int DetectHttpClientBodyTest07(void) /* 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: "); + if (PacketAlertCheck(p1, 1)) { + printf("sid 1 matched on p1 but shouldn't have: "); goto end; } @@ -660,13 +655,11 @@ static int DetectHttpClientBodyTest07(void) /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); -/* VJ right now we won't inspect the body another time if it - already matched once. Later we will take care of that. if (!(PacketAlertCheck(p2, 1))) { printf("sid 1 didn't match on p2 but should have: "); goto end; } -*/ + result = 1; end: if (de_ctx != NULL) @@ -703,11 +696,11 @@ static int DetectHttpClientBodyTest08(void) "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" "Content-Type: text/html\r\n" - "Content-Length: 67\r\n" + "Content-Length: 46\r\n" "\r\n" "This is dummy body1"; uint8_t http2_buf[] = - "This is dummy message body2\r\n"; + "This is dummy message body2"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; @@ -827,11 +820,11 @@ static int DetectHttpClientBodyTest09(void) "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" "Content-Type: text/html\r\n" - "Content-Length: 67\r\n" + "Content-Length: 46\r\n" "\r\n" "This is dummy body1"; uint8_t http2_buf[] = - "This is dummy message body2\r\n"; + "This is dummy message body2"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; @@ -951,11 +944,11 @@ static int DetectHttpClientBodyTest10(void) "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" "Content-Type: text/html\r\n" - "Content-Length: 67\r\n" + "Content-Length: 46\r\n" "\r\n" "This is dummy bodY1"; uint8_t http2_buf[] = - "This is dummy message body2\r\n"; + "This is dummy message body2"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; @@ -1075,7 +1068,7 @@ static int DetectHttpClientBodyTest11(void) "Content-Type: text/html\r\n" "Content-Length: 26\r\n" "\r\n" - "This is dummy message body\r\n"; + "This is dummy message body"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; @@ -1173,7 +1166,7 @@ static int DetectHttpClientBodyTest12(void) "Content-Type: text/html\r\n" "Content-Length: 26\r\n" "\r\n" - "This is dummy message body\r\n"; + "This is dummy message body"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; @@ -1269,9 +1262,9 @@ static int DetectHttpClientBodyTest13(void) "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" "Content-Type: text/html\r\n" - "Content-Length: 100\r\n" + "Content-Length: 55\r\n" "\r\n" - "longbufferabcdefghijklmnopqrstuvwxyz0123456789bufferend\r\n"; + "longbufferabcdefghijklmnopqrstuvwxyz0123456789bufferend"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; @@ -1793,13 +1786,13 @@ int DetectHttpClientBodyTest16(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_AMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_AMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH] == NULL) { + printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH] == NULL\n"); goto end; } DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; - DetectContentData *hcbd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_AMATCH]->ctx; + DetectContentData *hcbd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; if (cd->id == hcbd->id) goto end; @@ -1832,13 +1825,13 @@ int DetectHttpClientBodyTest17(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_AMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_AMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH] == NULL) { + printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH] == NULL\n"); goto end; } DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; - DetectContentData *hcbd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_AMATCH]->ctx; + DetectContentData *hcbd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; if (cd->id == hcbd->id) goto end; @@ -1871,13 +1864,13 @@ int DetectHttpClientBodyTest18(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_AMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_AMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH] == NULL) { + printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH] == NULL\n"); goto end; } DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; - DetectContentData *hcbd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_AMATCH]->ctx; + DetectContentData *hcbd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; if (cd->id != 0 || hcbd->id != 1) goto end; @@ -1910,13 +1903,13 @@ int DetectHttpClientBodyTest19(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_AMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_AMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH] == NULL) { + printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH] == NULL\n"); goto end; } DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; - DetectContentData *hcbd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_AMATCH]->ctx; + DetectContentData *hcbd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; if (cd->id != 1 || hcbd->id != 0) goto end; @@ -1950,14 +1943,14 @@ int DetectHttpClientBodyTest20(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_AMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_AMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH] == NULL) { + printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH] == NULL\n"); goto end; } DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; - DetectContentData *hcbd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_AMATCH]->ctx; - DetectContentData *hcbd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_AMATCH]->prev->ctx; + DetectContentData *hcbd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; + DetectContentData *hcbd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; if (cd->id != 1 || hcbd1->id != 0 || hcbd2->id != 0) goto end; @@ -1991,14 +1984,14 @@ int DetectHttpClientBodyTest21(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_AMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_AMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH] == NULL) { + printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH] == NULL\n"); goto end; } DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; - DetectContentData *hcbd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_AMATCH]->ctx; - DetectContentData *hcbd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_AMATCH]->prev->ctx; + DetectContentData *hcbd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; + DetectContentData *hcbd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; if (cd->id != 2 || hcbd1->id != 0 || hcbd2->id != 0) goto end; diff --git a/src/detect-nocase.c b/src/detect-nocase.c index 73ccd1de91..11fded0845 100644 --- a/src/detect-nocase.c +++ b/src/detect-nocase.c @@ -65,101 +65,101 @@ void DetectNocaseRegister (void) { * \retval sm sigmatch of either content or uricontent that is the last * or NULL if none was found */ -static SigMatch *SigMatchGetLastNocasePattern(Signature *s) { - SCEnter(); - - BUG_ON(s == NULL); - - SigMatch *co_sm = DetectContentGetLastPattern(s->sm_lists_tail[DETECT_SM_LIST_PMATCH]); - SigMatch *ur_sm = SigMatchGetLastSM(s->sm_lists_tail[DETECT_SM_LIST_UMATCH], DETECT_URICONTENT); - /* http client body SigMatch */ - SigMatch *hcbd_sm = SigMatchGetLastSM(s->sm_lists_tail[DETECT_SM_LIST_AMATCH], DETECT_AL_HTTP_CLIENT_BODY); - /* http cookie SigMatch */ - SigMatch *hcd_sm = SigMatchGetLastSM(s->sm_lists_tail[DETECT_SM_LIST_AMATCH], DETECT_AL_HTTP_COOKIE); - /* http header SigMatch */ - SigMatch *hhd_sm = SigMatchGetLastSM(s->sm_lists_tail[DETECT_SM_LIST_AMATCH], DETECT_AL_HTTP_HEADER); - /* http method SigMatch */ - SigMatch *hmd_sm = SigMatchGetLastSM(s->sm_lists_tail[DETECT_SM_LIST_AMATCH], DETECT_AL_HTTP_METHOD); - - SigMatch *temp_sm = NULL; - - SigMatch **sm_list = NULL; - uint8_t sm_list_count = 0; - - if (co_sm != NULL) { - sm_list_count++; - if ( (sm_list = SCRealloc(sm_list, sizeof(SigMatch *) * sm_list_count)) == NULL) { - SCLogError(SC_ERR_FATAL, "Fatal error encountered in SigMatchGetLastNocasePattern. Exiting..."); - exit(EXIT_FAILURE); - } - sm_list[sm_list_count - 1] = co_sm; - } - if (ur_sm != NULL) { - sm_list_count++; - if ( (sm_list = SCRealloc(sm_list, sizeof(SigMatch *) * sm_list_count)) == NULL) { - SCLogError(SC_ERR_FATAL, "Fatal error encountered in SigMatchGetLastNocasePattern. Exiting..."); - exit(EXIT_FAILURE); - } - sm_list[sm_list_count - 1] = ur_sm; - } - if (hcbd_sm != NULL) { - sm_list_count++; - if ( (sm_list = SCRealloc(sm_list, sizeof(SigMatch *) * sm_list_count)) == NULL) { - SCLogError(SC_ERR_FATAL, "Fatal error encountered in SigMatchGetLastNocasePattern. Exiting..."); - exit(EXIT_FAILURE); - } - sm_list[sm_list_count - 1] = hcbd_sm; - } - if (hcd_sm != NULL) { - sm_list_count++; - if ( (sm_list = SCRealloc(sm_list, sizeof(SigMatch *) * sm_list_count)) == NULL) { - SCLogError(SC_ERR_FATAL, "Fatal error encountered in SigMatchGetLastNocasePattern. Exiting..."); - exit(EXIT_FAILURE); - } - sm_list[sm_list_count - 1] = hcd_sm; - } - if (hhd_sm != NULL) { - sm_list_count++; - if ( (sm_list = SCRealloc(sm_list, sizeof(SigMatch *) * sm_list_count)) == NULL) { - SCLogError(SC_ERR_FATAL, "Fatal error encountered in SigMatchGetLastNocasePattern. Exiting..."); - exit(EXIT_FAILURE); - } - sm_list[sm_list_count - 1] = hhd_sm; - } - - if (hmd_sm != NULL) { - sm_list_count++; - if ( (sm_list = SCRealloc(sm_list, sizeof(SigMatch *) * sm_list_count)) == NULL) { - SCLogError(SC_ERR_FATAL, "Fatal error encountered in SigMatchGetLastNocasePattern. Exiting..."); - exit(EXIT_FAILURE); - } - sm_list[sm_list_count - 1] = hmd_sm; - } - - if (sm_list_count == 0) - SCReturnPtr(NULL, "SigMatch"); - - /* find the highest idx sm, so we apply to the last sm that we support */ - int i = 0, j = 0; - int swapped = 1; - while (swapped) { - swapped = 0; - for (j = i; j < sm_list_count - 1; j++) { - if (sm_list[j]->idx < sm_list[j + 1]->idx) { - temp_sm = sm_list[j]; - sm_list[j] = sm_list[j + 1]; - sm_list[j + 1] = temp_sm; - swapped = 1; - i++; - } - } - } - - temp_sm = sm_list[0]; - SCFree(sm_list); - - SCReturnPtr(temp_sm, "SigMatch"); -} +//static SigMatch *SigMatchGetLastNocasePattern(Signature *s) { +// SCEnter(); +// +// BUG_ON(s == NULL); +// +// SigMatch *co_sm = DetectContentGetLastPattern(s->sm_lists_tail[DETECT_SM_LIST_PMATCH]); +// SigMatch *ur_sm = SigMatchGetLastSM(s->sm_lists_tail[DETECT_SM_LIST_UMATCH], DETECT_URICONTENT); +// /* http client body SigMatch */ +// SigMatch *hcbd_sm = SigMatchGetLastSM(s->sm_lists_tail[DETECT_SM_LIST_AMATCH], DETECT_AL_HTTP_CLIENT_BODY); +// /* http cookie SigMatch */ +// SigMatch *hcd_sm = SigMatchGetLastSM(s->sm_lists_tail[DETECT_SM_LIST_AMATCH], DETECT_AL_HTTP_COOKIE); +// /* http header SigMatch */ +// SigMatch *hhd_sm = SigMatchGetLastSM(s->sm_lists_tail[DETECT_SM_LIST_AMATCH], DETECT_AL_HTTP_HEADER); +// /* http method SigMatch */ +// SigMatch *hmd_sm = SigMatchGetLastSM(s->sm_lists_tail[DETECT_SM_LIST_AMATCH], DETECT_AL_HTTP_METHOD); +// +// SigMatch *temp_sm = NULL; +// +// SigMatch **sm_list = NULL; +// uint8_t sm_list_count = 0; +// +// if (co_sm != NULL) { +// sm_list_count++; +// if ( (sm_list = SCRealloc(sm_list, sizeof(SigMatch *) * sm_list_count)) == NULL) { +// SCLogError(SC_ERR_FATAL, "Fatal error encountered in SigMatchGetLastNocasePattern. Exiting..."); +// exit(EXIT_FAILURE); +// } +// sm_list[sm_list_count - 1] = co_sm; +// } +// if (ur_sm != NULL) { +// sm_list_count++; +// if ( (sm_list = SCRealloc(sm_list, sizeof(SigMatch *) * sm_list_count)) == NULL) { +// SCLogError(SC_ERR_FATAL, "Fatal error encountered in SigMatchGetLastNocasePattern. Exiting..."); +// exit(EXIT_FAILURE); +// } +// sm_list[sm_list_count - 1] = ur_sm; +// } +// if (hcbd_sm != NULL) { +// sm_list_count++; +// if ( (sm_list = SCRealloc(sm_list, sizeof(SigMatch *) * sm_list_count)) == NULL) { +// SCLogError(SC_ERR_FATAL, "Fatal error encountered in SigMatchGetLastNocasePattern. Exiting..."); +// exit(EXIT_FAILURE); +// } +// sm_list[sm_list_count - 1] = hcbd_sm; +// } +// if (hcd_sm != NULL) { +// sm_list_count++; +// if ( (sm_list = SCRealloc(sm_list, sizeof(SigMatch *) * sm_list_count)) == NULL) { +// SCLogError(SC_ERR_FATAL, "Fatal error encountered in SigMatchGetLastNocasePattern. Exiting..."); +// exit(EXIT_FAILURE); +// } +// sm_list[sm_list_count - 1] = hcd_sm; +// } +// if (hhd_sm != NULL) { +// sm_list_count++; +// if ( (sm_list = SCRealloc(sm_list, sizeof(SigMatch *) * sm_list_count)) == NULL) { +// SCLogError(SC_ERR_FATAL, "Fatal error encountered in SigMatchGetLastNocasePattern. Exiting..."); +// exit(EXIT_FAILURE); +// } +// sm_list[sm_list_count - 1] = hhd_sm; +// } +// +// if (hmd_sm != NULL) { +// sm_list_count++; +// if ( (sm_list = SCRealloc(sm_list, sizeof(SigMatch *) * sm_list_count)) == NULL) { +// SCLogError(SC_ERR_FATAL, "Fatal error encountered in SigMatchGetLastNocasePattern. Exiting..."); +// exit(EXIT_FAILURE); +// } +// sm_list[sm_list_count - 1] = hmd_sm; +// } +// +// if (sm_list_count == 0) +// SCReturnPtr(NULL, "SigMatch"); +// +// /* find the highest idx sm, so we apply to the last sm that we support */ +// int i = 0, j = 0; +// int swapped = 1; +// while (swapped) { +// swapped = 0; +// for (j = i; j < sm_list_count - 1; j++) { +// if (sm_list[j]->idx < sm_list[j + 1]->idx) { +// temp_sm = sm_list[j]; +// sm_list[j] = sm_list[j + 1]; +// sm_list[j + 1] = temp_sm; +// swapped = 1; +// i++; +// } +// } +// } +// +// temp_sm = sm_list[0]; +// SCFree(sm_list); +// +// SCReturnPtr(temp_sm, "SigMatch"); +//} /** * \internal @@ -180,7 +180,14 @@ 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 = SigMatchGetLastNocasePattern(s); + SigMatch *pm = SigMatchGetLastSMFromLists(s, 12, + 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_COOKIE, s->sm_lists_tail[DETECT_SM_LIST_AMATCH], + DETECT_AL_HTTP_HEADER, s->sm_lists_tail[DETECT_SM_LIST_AMATCH], + DETECT_AL_HTTP_METHOD, s->sm_lists_tail[DETECT_SM_LIST_AMATCH]); 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 option"); @@ -244,4 +251,3 @@ static int DetectNocaseSetup (DetectEngineCtx *de_ctx, Signature *s, char *nulls SCReturnInt(0); } - diff --git a/src/detect-offset.c b/src/detect-offset.c index 6db6a81cc3..bded9abc8e 100644 --- a/src/detect-offset.c +++ b/src/detect-offset.c @@ -80,12 +80,13 @@ int DetectOffsetSetup (DetectEngineCtx *de_ctx, Signature *s, char *offsetstr) break; default: - pm = SigMatchGetLastSMFromLists(s, 4, + pm = SigMatchGetLastSMFromLists(s, 6, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_URICONTENT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH]); + DETECT_URICONTENT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], + DETECT_AL_HTTP_CLIENT_BODY, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]); if (pm == NULL) { - SCLogError(SC_ERR_WITHIN_MISSING_CONTENT, "distance needs" - "preceeding content or uricontent option"); + SCLogError(SC_ERR_WITHIN_MISSING_CONTENT, "offset needs" + "preceeding content or uricontent option or http_client_body option"); if (dubbed) SCFree(str); return -1; @@ -94,6 +95,7 @@ int DetectOffsetSetup (DetectEngineCtx *de_ctx, Signature *s, char *offsetstr) break; } + /* we can remove this switch now with the unified structure */ DetectContentData *ud = NULL; DetectContentData *cd = NULL; switch (pm->type) { @@ -173,6 +175,23 @@ int DetectOffsetSetup (DetectEngineCtx *de_ctx, Signature *s, char *offsetstr) break; + case DETECT_AL_HTTP_CLIENT_BODY: + cd = (DetectContentData *)pm->ctx; + cd->offset = (uint32_t)atoi(str); + if (cd->depth != 0) { + if (cd->depth < cd->content_len) { + SCLogDebug("depth increased to %"PRIu32" to match pattern len", + cd->content_len); + cd->depth = cd->content_len; + } + /* Updating the depth as is relative to the offset */ + cd->depth += cd->offset; + } + + cd->flags |= DETECT_CONTENT_OFFSET; + + break; + default: SCLogError(SC_ERR_OFFSET_MISSING_CONTENT, "offset needs a preceeding" " content or uricontent option"); diff --git a/src/detect-parse.c b/src/detect-parse.c index a9745ad8dc..99854854d0 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -1361,6 +1361,8 @@ Signature *SigInit(DetectEngineCtx *de_ctx, char *sigstr) { sig->flags |= SIG_FLAG_AMATCH; if (sig->sm_lists[DETECT_SM_LIST_AMATCH]) sig->flags |= SIG_FLAG_AMATCH; + if (sig->sm_lists[DETECT_SM_LIST_HCBDMATCH]) + sig->flags |= SIG_FLAG_HCBDMATCH; SCLogDebug("sig %"PRIu32" SIG_FLAG_APPLAYER: %s, SIG_FLAG_PACKET: %s", sig->id, sig->flags & SIG_FLAG_APPLAYER ? "set" : "not set", diff --git a/src/detect-within.c b/src/detect-within.c index a7603d3a43..f6bb73e822 100644 --- a/src/detect-within.c +++ b/src/detect-within.c @@ -169,12 +169,13 @@ static int DetectWithinSetup (DetectEngineCtx *de_ctx, Signature *s, char *withi } } } else { - pm = SigMatchGetLastSMFromLists(s, 4, + pm = SigMatchGetLastSMFromLists(s, 6, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_URICONTENT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH]); + DETECT_URICONTENT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], + DETECT_AL_HTTP_CLIENT_BODY, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]); if (pm == NULL) { SCLogError(SC_ERR_WITHIN_MISSING_CONTENT, "within needs" - "preceeding content or uricontent option"); + "preceeding content or uricontent or http_client_body option"); if (dubbed) SCFree(str); return -1; @@ -382,8 +383,32 @@ static int DetectWithinSetup (DetectEngineCtx *de_ctx, Signature *s, char *withi } } + break; - break; + case DETECT_AL_HTTP_CLIENT_BODY: + cd = (DetectContentData *)pm->ctx; + 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", ud->within, + ud->content_len); + goto error; + } + + cd->flags |= DETECT_CONTENT_WITHIN; + + pm = SigMatchGetLastSMFromLists(s, 2, + DETECT_AL_HTTP_CLIENT_BODY, pm->prev); + if (pm == NULL) { + SCLogError(SC_ERR_DISTANCE_MISSING_CONTENT, "distance for http_client_body " + "needs preceeding http_client_body content"); + goto error; + } + + ((DetectContentData *)pm->ctx)->flags |= DETECT_CONTENT_RELATIVE_NEXT; + + break; default: SCLogError(SC_ERR_WITHIN_MISSING_CONTENT, "within needs two " diff --git a/src/detect.c b/src/detect.c index c0bba99a04..c9ab200154 100644 --- a/src/detect.c +++ b/src/detect.c @@ -681,7 +681,7 @@ static void SigMatchSignaturesBuildMatchArray(DetectEngineCtx *de_ctx, /* de_state check, filter out all signatures that already had a match before * or just partially match */ if (s->flags & SIG_FLAG_AMATCH || s->flags & SIG_FLAG_UMATCH || - s->flags & SIG_FLAG_DMATCH) + s->flags & SIG_FLAG_DMATCH || s->flags & SIG_FLAG_HCBDMATCH) { /* we run after DeStateDetectContinueDetection, so we might have * state NEW here. In that case we'd want to continue detection @@ -1144,7 +1144,10 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh SCLogDebug("s->sm_lists[DETECT_SM_LIST_AMATCH] %p, s->sm_lists[DETECT_SM_LIST_UMATCH] %p, s->sm_lists[DETECT_SM_LIST_DMATCH] %p", s->sm_lists[DETECT_SM_LIST_AMATCH], s->sm_lists[DETECT_SM_LIST_UMATCH], s->sm_lists[DETECT_SM_LIST_DMATCH]); - if (s->sm_lists[DETECT_SM_LIST_AMATCH] != NULL || s->sm_lists[DETECT_SM_LIST_UMATCH] != NULL || s->sm_lists[DETECT_SM_LIST_DMATCH] != NULL) { + if (s->sm_lists[DETECT_SM_LIST_AMATCH] != NULL || + s->sm_lists[DETECT_SM_LIST_UMATCH] != NULL || + s->sm_lists[DETECT_SM_LIST_DMATCH] != NULL || + s->sm_lists[DETECT_SM_LIST_HCBDMATCH]) { if (alstate == NULL) { SCLogDebug("state matches but no state, we can't match"); goto next; @@ -1451,6 +1454,9 @@ int SignatureIsIPOnly(DetectEngineCtx *de_ctx, Signature *s) { if (s->sm_lists[DETECT_SM_LIST_UMATCH] != NULL) return 0; + if (s->sm_lists[DETECT_SM_LIST_HCBDMATCH] != NULL) + return 0; + if (s->sm_lists[DETECT_SM_LIST_AMATCH] != NULL) return 0; @@ -1522,6 +1528,9 @@ static int SignatureIsDEOnly(DetectEngineCtx *de_ctx, Signature *s) { if (s->sm_lists[DETECT_SM_LIST_AMATCH] != NULL) return 0; + if (s->sm_lists[DETECT_SM_LIST_HCBDMATCH] != NULL) + return 0; + SigMatch *sm = s->sm_lists[DETECT_SM_LIST_MATCH]; /* check for conflicting keywords */ for ( ;sm != NULL; sm = sm->next) { @@ -1606,7 +1615,12 @@ static int SignatureCreateMask(Signature *s) { if (s->sm_lists[DETECT_SM_LIST_UMATCH] != NULL) { s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; - SCLogDebug("sig requires dce http state"); + SCLogDebug("sig requires http state"); + } + + if (s->sm_lists[DETECT_SM_LIST_HCBDMATCH] != NULL) { + s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; + SCLogDebug("sig requires http app state"); } SigMatch *sm; diff --git a/src/detect.h b/src/detect.h index edb633ebd7..3b54c3decb 100644 --- a/src/detect.h +++ b/src/detect.h @@ -86,6 +86,7 @@ enum { DETECT_SM_LIST_AMATCH, DETECT_SM_LIST_DMATCH, DETECT_SM_LIST_TMATCH, + DETECT_SM_LIST_HCBDMATCH, DETECT_SM_LIST_MAX, }; @@ -227,13 +228,14 @@ typedef struct DetectPort_ { #define SIG_FLAG_UMATCH 0x00040000 #define SIG_FLAG_AMATCH 0x00080000 #define SIG_FLAG_DMATCH 0x00100000 +#define SIG_FLAG_HCBDMATCH 0x00200000 -#define SIG_FLAG_MPM_PACKET 0x00200000 -#define SIG_FLAG_MPM_STREAM 0x00400000 -#define SIG_FLAG_MPM_URICONTENT 0x00800000 -#define SIG_FLAG_MPM_URICONTENT_NEG 0x01000000 +#define SIG_FLAG_MPM_PACKET 0x00400000 +#define SIG_FLAG_MPM_STREAM 0x00800000 +#define SIG_FLAG_MPM_URICONTENT 0x01000000 +#define SIG_FLAG_MPM_URICONTENT_NEG 0x02000000 -#define SIG_FLAG_HAS_NO_PKT_AND_STREAM_CONTENT 0x02000000 +#define SIG_FLAG_HAS_NO_PKT_AND_STREAM_CONTENT 0x04000000 /* signature mask flags */ #define SIG_MASK_REQUIRE_PAYLOAD 0x01 diff --git a/src/suricata.c b/src/suricata.c index 72ef763258..1b304081f2 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -53,6 +53,7 @@ #include "detect-engine-payload.h" #include "detect-engine-dcepayload.h" #include "detect-engine-uri.h" +#include "detect-engine-hcbd.h" #include "detect-engine-state.h" #include "detect-engine-tag.h" #include "detect-fast-pattern.h" @@ -942,7 +943,6 @@ int main(int argc, char **argv) TmqhFlowRegisterTests(); FlowRegisterTests(); SCSigRegisterSignatureOrderingTests(); - SCLogRegisterTests(); SCRadixRegisterTests(); DefragRegisterTests(); SigGroupHeadRegisterTests(); @@ -968,7 +968,9 @@ int main(int argc, char **argv) DeStateRegisterTests(); DetectRingBufferRegisterTests(); MemcmpRegisterTests(); + HttpClientBodyRegisterTests(); DetectEngineRegisterTests(); + SCLogRegisterTests(); if (list_unittests) { UtListTests(regex_arg); }