/* 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 Victor Julien */ #include "suricata-common.h" #include "decode.h" #include "detect.h" #include "detect-engine.h" #include "detect-parse.h" #include "detect-engine-state.h" #include "detect-engine-uri.h" #include "detect-engine-dcepayload.h" #include "stream-tcp.h" #include "stream-tcp-private.h" #include "stream-tcp-reassemble.h" #include "app-layer-parser.h" #include "app-layer-protos.h" #include "app-layer-htp.h" #include "util-unittest.h" #include "util-profiling.h" #define CASE_CODE(E) case E: return #E const char *DeStateMatchResultToString(DeStateMatchResult res) { switch (res) { CASE_CODE (DE_STATE_MATCH_FULL); CASE_CODE (DE_STATE_MATCH_PARTIAL); CASE_CODE (DE_STATE_MATCH_STORED); CASE_CODE (DE_STATE_MATCH_NEW); } return NULL; } /** * \brief Alloc a DeStateStore object * \retval d alloc'd object */ DeStateStore *DeStateStoreAlloc(void) { SCEnter(); DeStateStore *d = SCMalloc(sizeof(DeStateStore)); if (d == NULL) { SCReturnPtr(NULL, "DeStateStore"); } memset(d, 0x00, sizeof(DeStateStore)); SCReturnPtr(d, "DeStateStore"); } /** * \brief free a DeStateStore object (recursively) * \param store DeStateStore object to free */ void DeStateStoreFree(DeStateStore *store) { SCEnter(); if (store == NULL) { SCReturn; } if (store->next != NULL) { DeStateStoreFree(store->next); } SCFree(store); SCReturn; } /** * \brief Alloc a DetectEngineState object * \param d alloc'd object */ DetectEngineState *DetectEngineStateAlloc(void) { SCEnter(); DetectEngineState *d = SCMalloc(sizeof(DetectEngineState)); if (d == NULL) { SCReturnPtr(NULL, "DetectEngineState"); } memset(d, 0x00, sizeof(DetectEngineState)); SCMutexInit(&d->m, NULL); SCReturnPtr(d, "DetectEngineState"); } /** * \brief Free a DetectEngineState object * \param state DetectEngineState object to free */ void DetectEngineStateFree(DetectEngineState *state) { if (state == NULL) return; if (state->head != NULL) { DeStateStoreFree(state->head); } SCMutexDestroy(&state->m); SCFree(state); } /** * \brief reset a DetectEngineState state * \param state LOCKED state */ void DetectEngineStateReset(DetectEngineState *state) { SCEnter(); if (state == NULL) { SCReturn; } SCMutexLock(&state->m); if (state->head != NULL) { DeStateStoreFree(state->head); } state->head = NULL; state->tail = NULL; state->cnt = 0; SCMutexUnlock(&state->m); SCReturn; } /** * \brief update the transaction id * \retval 2 current transaction done, new available * \retval 1 current transaction done, no new (yet) * \retval 0 current transaction is not done yet */ int DeStateUpdateInspectTransactionId(Flow *f) { SCEnter(); int r = 0; SCMutexLock(&f->m); r = AppLayerTransactionUpdateInspectId(f); SCMutexUnlock(&f->m); SCReturnInt(r); } /** * \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) */ static void DeStateSignatureAppend(DetectEngineState *state, Signature *s, SigMatch *sm, char uri, char dce) { DeStateStore *store = state->tail; if (store == NULL) { store = DeStateStoreAlloc(); if (store != NULL) { state->head = store; state->tail = store; } } else { if ((state->cnt % DE_STATE_CHUNK_SIZE) == 0) { store = DeStateStoreAlloc(); if (store != NULL) { state->tail->next = store; state->tail = store; } } else { store = state->tail; } } if (store == NULL) { return; } SigIntId idx = state->cnt % DE_STATE_CHUNK_SIZE; store->store[idx].sid = s->num; store->store[idx].flags = 0; if (uri) { store->store[idx].flags |= DE_STATE_FLAG_URI_MATCH; } if (dce) { store->store[idx].flags |= DE_STATE_FLAG_DCE_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); } /* on first detection run: for each (1) app layer signature (2a) at least one app layer sm match OR (2b) content/uri match AND other app layer sigmatches present Cases: multiple app layer sm's content + uricontent content + app layer sm uricontent + app layer sm */ /** \brief Check if a flow already contains a flow detect state * \retval 1 has state * \retval 0 has no state */ int DeStateFlowHasState(Flow *f) { SCEnter(); int r = 0; SCMutexLock(&f->m); if (f->de_state == NULL || f->de_state->cnt == 0) r = 0; else r = 1; SCMutexUnlock(&f->m); SCReturnInt(r); } /** \brief Match app layer sig list against state. Set up state for non matches * and partial matches. * \retval 1 match * \retval 0 no or partial match */ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Signature *s, Flow *f, uint8_t flags, void *alstate, uint16_t alproto) { SCEnter(); SigMatch *sm = s->amatch; int match = 0; int r = 0; char umatch = 0; char uinspect = 0; char dmatch = 0; char dinspect = 0; char appinspect = 0; char appmatch = 0; if (alstate == NULL) { SCReturnInt(0); } SCLogDebug("s->id %"PRIu32, s->id); /* Check the uricontent keywords here. */ if (alproto == ALPROTO_HTTP) { if (s->umatch != NULL) { uinspect = 1; SCLogDebug("inspecting uri"); if (DetectEngineInspectPacketUris(de_ctx, det_ctx, s, f, flags, alstate) == 1) { SCLogDebug("uri matched"); umatch = 1; } else { SCLogDebug("uri inspected but no match"); } } } else if (alproto == ALPROTO_DCERPC) { if (s->dmatch != NULL) { dinspect = 1; SCLogDebug("inspecting dce payload"); if (DetectEngineInspectDcePayload(de_ctx, det_ctx, s, f, flags, alstate) == 1) { SCLogDebug("dce payload matched"); dmatch = 1; } else { SCLogDebug("dce payload inspected but no match"); } } } appinspect = uinspect + dinspect; appmatch = umatch + dmatch; if (s->amatch != NULL) { for ( ; sm != NULL; sm = sm->next) { SCLogDebug("sm %p, sm->next %p", sm, sm->next); if (sigmatch_table[sm->type].AppLayerMatch != NULL && alproto == sigmatch_table[sm->type].alproto) { match = sigmatch_table[sm->type].AppLayerMatch(tv, det_ctx, f, flags, alstate, s, sm); if (match == 0) { break; } else if (sm->next == NULL) { sm = NULL; /* set to NULL as we have a match */ if (!appinspect || (appinspect == appmatch)) { r = 1; } break; } } } } else { if (appinspect > 0 && (appinspect == appmatch)) { r = 1; } } SCLogDebug("detection done, store results: sm %p, uri %d, dce %d", sm, umatch, dmatch); SCMutexLock(&f->m); /* match or no match, we store the state anyway * "sm" here is either NULL (complete match) or * the last SigMatch that didn't match */ if (f->de_state == NULL) { f->de_state = DetectEngineStateAlloc(); } SCMutexUnlock(&f->m); if (f->de_state != NULL) { SCMutexLock(&f->de_state->m); DeStateSignatureAppend(f->de_state, s, sm, umatch, dmatch); SCMutexUnlock(&f->de_state->m); } SCReturnInt(r); } /** \brief Continue DeState detection of the signatures stored in the state. * * \retval 0 all is good */ int DeStateDetectContinueDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, void *alstate, uint16_t alproto) { SCEnter(); SigIntId cnt = 0; SigIntId store_cnt = 0; DeStateStore *store = NULL; char umatch = 0; char uinspect = 0; char dmatch = 0; char dinspect = 0; char appinspect = 0; char appmatch = 0; if (f == NULL || alstate == NULL || alproto == ALPROTO_UNKNOWN) { return 0; } SCMutexLock(&f->de_state->m); if (f->de_state->cnt == 0) goto end; /* loop through the stores */ for (store = f->de_state->head; store != NULL; store = store->next) { /* loop through the sigs in the stores */ for (store_cnt = 0; store_cnt < DE_STATE_CHUNK_SIZE && cnt < f->de_state->cnt; store_cnt++, cnt++) { DeStateStoreItem *item = &store->store[store_cnt]; SCLogDebug("internal id of signature to inspect: %"PRIuMAX, (uintmax_t)item->sid); Signature *s = de_ctx->sig_array[item->sid]; SCLogDebug("id of signature to inspect: %"PRIuMAX, (uintmax_t)s->id); PROFILING_START; /* let's continue detection */ /* first, check uricontent */ if (alproto == ALPROTO_HTTP) { if (s->umatch != NULL) { if (!(item->flags & DE_STATE_FLAG_URI_MATCH)) { SCLogDebug("inspecting uri"); uinspect = 1; if (DetectEngineInspectPacketUris(de_ctx, det_ctx, s, f, flags, alstate) == 1) { SCLogDebug("uri matched"); item->flags |= DE_STATE_FLAG_URI_MATCH; umatch = 1; } else { SCLogDebug("uri inspected but no match"); } } else { SCLogDebug("uri already inspected"); } } } else if (alproto == ALPROTO_DCERPC) { if (s->dmatch != NULL) { if (!(item->flags & DE_STATE_FLAG_DCE_MATCH)) { SCLogDebug("inspecting dce payload"); dinspect = 1; if (DetectEngineInspectDcePayload(de_ctx, det_ctx, s, f, flags, alstate) == 1) { SCLogDebug("dce payload matched"); item->flags |= DE_STATE_FLAG_DCE_MATCH; dmatch = 1; } else { SCLogDebug("dce payload inspected but no match"); } } else { SCLogDebug("dce payload already inspected"); } } } appinspect = uinspect + dinspect; appmatch = umatch + dmatch; SCLogDebug("appinspect %d, appmatch %d", appinspect, appmatch); /* next, check the other sig matches */ if (item->nm != NULL) { SigMatch *sm; int match = 0; for (sm = item->nm; sm != NULL; sm = sm->next) { match = sigmatch_table[sm->type].AppLayerMatch(tv, det_ctx, f, flags, alstate, s, sm); /* no match, break out */ if (match == 0) { item->nm = sm; det_ctx->de_state_sig_array[item->sid] = DE_STATE_MATCH_PARTIAL; SCLogDebug("state set to %s", DeStateMatchResultToString(DE_STATE_MATCH_PARTIAL)); break; /* match, and no more sm's */ } else if (sm->next == NULL) { /* mark the sig as matched */ item->nm = NULL; if (!appinspect || (appinspect == appmatch)) { det_ctx->de_state_sig_array[item->sid] = DE_STATE_MATCH_NEW; SCLogDebug("state set to %s", DeStateMatchResultToString(DE_STATE_MATCH_NEW)); } else { det_ctx->de_state_sig_array[item->sid] = DE_STATE_MATCH_PARTIAL; SCLogDebug("state set to %s", DeStateMatchResultToString(DE_STATE_MATCH_PARTIAL)); } } } } else { if (appinspect > 0 && (appinspect == appmatch)) { det_ctx->de_state_sig_array[item->sid] = DE_STATE_MATCH_NEW; SCLogDebug("state set to %s", DeStateMatchResultToString(DE_STATE_MATCH_NEW)); } else if (uinspect && !umatch) { det_ctx->de_state_sig_array[item->sid] = DE_STATE_MATCH_PARTIAL; SCLogDebug("state set to %s", DeStateMatchResultToString(DE_STATE_MATCH_PARTIAL)); } } SCLogDebug("signature %"PRIu32" match state %s", s->id, DeStateMatchResultToString(det_ctx->de_state_sig_array[item->sid])); RULE_PROFILING_END(s, match); } } end: SCMutexUnlock(&f->de_state->m); SCReturnInt(0); } /** * \brief Restart detection as we're going to inspect a new transaction */ int DeStateRestartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, void *alstate, uint16_t alproto) { SCEnter(); /* first clear the existing state as it belongs * to the previous transaction */ SCMutexLock(&f->m); if (f->de_state != NULL) { SCMutexLock(&f->de_state->m); DetectEngineStateReset(f->de_state); SCMutexUnlock(&f->de_state->m); } SCMutexUnlock(&f->m); SCReturnInt(0); } /** * \retval 1 match * \retval 0 no match */ int DeStateDetectSignature(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Signature *s, Packet *p, uint8_t flags, void *alstate, uint16_t alproto) { SCEnter(); int r = 0; if (p->flow == NULL) { SCReturnInt(0); } /* if there is already a state, continue the inspection of this * signature using that state. */ r = DeStateDetectStartDetection(tv, de_ctx, det_ctx, s, p->flow, flags, alstate, alproto); SCReturnInt(r); } #ifdef UNITTESTS #include "flow-util.h" static int DeStateTest01(void) { SCLogDebug("sizeof(DetectEngineState)\t\t%"PRIuMAX, (uintmax_t)sizeof(DetectEngineState)); SCLogDebug("sizeof(DeStateStore)\t\t\t%"PRIuMAX, (uintmax_t)sizeof(DeStateStore)); SCLogDebug("sizeof(DeStateStoreItem)\t\t%"PRIuMAX"", (uintmax_t)sizeof(DeStateStoreItem)); return 1; } static int DeStateTest02(void) { int result = 0; DetectEngineState *state = DetectEngineStateAlloc(); if (state == NULL) { printf("d == NULL: "); goto end; } Signature s; memset(&s, 0x00, sizeof(s)); s.num = 0; DeStateSignatureAppend(state, &s, NULL, 0, 0); s.num = 11; DeStateSignatureAppend(state, &s, NULL, 0, 0); s.num = 22; DeStateSignatureAppend(state, &s, NULL, 0, 0); s.num = 33; DeStateSignatureAppend(state, &s, NULL, 0, 0); s.num = 44; DeStateSignatureAppend(state, &s, NULL, 0, 0); s.num = 55; DeStateSignatureAppend(state, &s, NULL, 0, 0); s.num = 66; DeStateSignatureAppend(state, &s, NULL, 0, 0); s.num = 77; DeStateSignatureAppend(state, &s, NULL, 0, 0); s.num = 88; DeStateSignatureAppend(state, &s, NULL, 0, 0); s.num = 99; DeStateSignatureAppend(state, &s, NULL, 0, 0); s.num = 100; DeStateSignatureAppend(state, &s, NULL, 0, 0); s.num = 111; DeStateSignatureAppend(state, &s, NULL, 0, 0); s.num = 122; DeStateSignatureAppend(state, &s, NULL, 0, 0); s.num = 133; DeStateSignatureAppend(state, &s, NULL, 0, 0); s.num = 144; DeStateSignatureAppend(state, &s, NULL, 0, 0); s.num = 155; DeStateSignatureAppend(state, &s, NULL, 0, 0); s.num = 166; DeStateSignatureAppend(state, &s, NULL, 0, 0); if (state->head == NULL) { goto end; } if (state->head->store[1].sid != 11) { goto end; } if (state->head->next == NULL) { goto end; } if (state->head->store[15].sid != 155) { goto end; } if (state->head->next->store[0].sid != 166) { goto end; } result = 1; end: if (state != NULL) { DetectEngineStateFree(state); } return result; } static int DeStateTest03(void) { int result = 0; DetectEngineState *state = DetectEngineStateAlloc(); if (state == NULL) { printf("d == NULL: "); goto end; } Signature s; memset(&s, 0x00, sizeof(s)); s.num = 11; DeStateSignatureAppend(state, &s, NULL, 0, 0); s.num = 22; DeStateSignatureAppend(state, &s, NULL, 1, 0); if (state->head == NULL) { goto end; } if (state->head->store[0].sid != 11) { goto end; } if (state->head->store[0].flags & DE_STATE_FLAG_URI_MATCH) { goto end; } if (state->head->store[1].sid != 22) { goto end; } if (!(state->head->store[1].flags & DE_STATE_FLAG_URI_MATCH)) { goto end; } result = 1; end: if (state != NULL) { DetectEngineStateFree(state); } return result; } static int DeStateSigTest01(void) { int result = 0; Signature *s = NULL; DetectEngineThreadCtx *det_ctx = NULL; ThreadVars th_v; Flow f; TcpSession ssn; Packet p; uint8_t httpbuf1[] = "POST / HTTP/1.0\r\n"; uint8_t httpbuf2[] = "User-Agent: Mozilla/1.0\r\n"; uint8_t httpbuf3[] = "Cookie: dummy\r\nContent-Length: 10\r\n\r\n"; uint8_t httpbuf4[] = "Http Body!"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */ uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */ HtpState *http_state = NULL; memset(&th_v, 0, sizeof(th_v)); memset(&p, 0, sizeof(p)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p.src.family = AF_INET; p.dst.family = AF_INET; p.payload = NULL; p.payload_len = 0; p.proto = IPPROTO_TCP; FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.src.family = AF_INET; f.dst.family = AF_INET; p.flow = &f; p.flowflags |= FLOW_PKT_TOSERVER; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); FlowL7DataPtrInit(&f); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any (content:\"POST\"; http_method; content:\"dummy\"; http_cookie; sid:1; rev:1;)"); if (s == NULL) { printf("sig parse failed: "); goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, &p); if (PacketAlertCheck(&p, 1)) { printf("sig 1 alerted: "); goto end; } p.alerts.cnt = 0; r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, &p); if (PacketAlertCheck(&p, 1)) { printf("sig 1 alerted (2): "); goto end; } p.alerts.cnt = 0; r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf3, httplen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, &p); if (!(PacketAlertCheck(&p, 1))) { printf("sig 1 didn't alert: "); goto end; } p.alerts.cnt = 0; r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf4, httplen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, &p); if (PacketAlertCheck(&p, 1)) { printf("signature matched, but shouldn't have: "); goto end; } p.alerts.cnt = 0; result = 1; end: if (http_state != NULL) { HTPStateFree(http_state); } if (det_ctx != NULL) { DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); } if (de_ctx != NULL) { SigGroupCleanup(de_ctx); DetectEngineCtxFree(de_ctx); } FlowL7DataPtrFree(&f); StreamTcpFreeConfig(TRUE); return result; } /** \test multiple pipelined http transactions */ static int DeStateSigTest02(void) { int result = 0; Signature *s = NULL; DetectEngineThreadCtx *det_ctx = NULL; ThreadVars th_v; Flow f; TcpSession ssn; Packet p; uint8_t httpbuf1[] = "POST / HTTP/1.1\r\n"; uint8_t httpbuf2[] = "User-Agent: Mozilla/1.0\r\nContent-Length: 10\r\n"; uint8_t httpbuf3[] = "Cookie: dummy\r\n\r\n"; uint8_t httpbuf4[] = "Http Body!"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */ uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */ uint8_t httpbuf5[] = "GET /?var=val HTTP/1.1\r\n"; uint8_t httpbuf6[] = "User-Agent: Firefox/1.0\r\n"; uint8_t httpbuf7[] = "Cookie: dummy2\r\nContent-Length: 10\r\n\r\nHttp Body!"; uint32_t httplen5 = sizeof(httpbuf5) - 1; /* minus the \0 */ uint32_t httplen6 = sizeof(httpbuf6) - 1; /* minus the \0 */ uint32_t httplen7 = sizeof(httpbuf7) - 1; /* minus the \0 */ memset(&th_v, 0, sizeof(th_v)); memset(&p, 0, sizeof(p)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p.src.family = AF_INET; p.dst.family = AF_INET; p.payload = NULL; p.payload_len = 0; p.proto = IPPROTO_TCP; FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; f.src.family = AF_INET; f.dst.family = AF_INET; p.flow = &f; p.flowflags |= FLOW_PKT_TOSERVER; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); FlowL7DataPtrInit(&f); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"POST\"; http_method; content:\"Mozilla\"; http_header; content:\"dummy\"; http_cookie; sid:1; rev:1;)"); if (s == NULL) { printf("sig parse failed: "); goto end; } s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"GET\"; http_method; content:\"Firefox\"; http_header; content:\"dummy2\"; http_cookie; sid:2; rev:1;)"); if (s == NULL) { printf("sig2 parse failed: "); goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, &p); if (PacketAlertCheck(&p, 1)) { printf("sig 1 alerted: "); goto end; } p.alerts.cnt = 0; r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, &p); if (PacketAlertCheck(&p, 1)) { printf("sig 1 alerted (2): "); goto end; } p.alerts.cnt = 0; r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf3, httplen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, &p); if (!(PacketAlertCheck(&p, 1))) { printf("sig 1 didn't alert: "); goto end; } p.alerts.cnt = 0; r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf4, httplen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, &p); if (PacketAlertCheck(&p, 1)) { printf("signature matched, but shouldn't have: "); goto end; } p.alerts.cnt = 0; r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf5, httplen5); if (r != 0) { printf("toserver chunk 5 returned %" PRId32 ", expected 0: ", r); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, &p); if (PacketAlertCheck(&p, 1)) { printf("sig 1 alerted (5): "); goto end; } p.alerts.cnt = 0; r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf6, httplen6); if (r != 0) { printf("toserver chunk 6 returned %" PRId32 ", expected 0: ", r); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, &p); if ((PacketAlertCheck(&p, 1)) || (PacketAlertCheck(&p, 2))) { printf("sig 1 alerted (request 2, chunk 6): "); goto end; } p.alerts.cnt = 0; SCLogDebug("sending data chunk 7"); r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf7, httplen7); if (r != 0) { printf("toserver chunk 7 returned %" PRId32 ", expected 0: ", r); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, &p); if (!(PacketAlertCheck(&p, 2))) { printf("signature 2 didn't match, but should have: "); goto end; } p.alerts.cnt = 0; result = 1; end: FLOW_DESTROY(&f); if (det_ctx != NULL) { DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); } if (de_ctx != NULL) { SigGroupCleanup(de_ctx); DetectEngineCtxFree(de_ctx); } FlowL7DataPtrFree(&f); StreamTcpFreeConfig(TRUE); return result; } #endif void DeStateRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("DeStateTest01", DeStateTest01, 1); UtRegisterTest("DeStateTest02", DeStateTest02, 1); UtRegisterTest("DeStateTest03", DeStateTest03, 1); UtRegisterTest("DeStateSigTest01", DeStateSigTest01, 1); UtRegisterTest("DeStateSigTest02", DeStateSigTest02, 1); #endif }