From 73efb4c70f48eed4b4eb1e62c673e75a321c52f2 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 7 Jun 2011 18:15:03 +0200 Subject: [PATCH] Add a app layer state and stateful detection engine counter that makes sure the stateful inspection is only done when the state changes. --- src/app-layer-parser.c | 26 +++++++++++++++ src/app-layer-parser.h | 4 +++ src/detect-engine-state.c | 66 ++++++++++++++++++++++----------------- src/detect-engine-state.h | 12 ++++--- src/detect.c | 11 +++++-- 5 files changed, 84 insertions(+), 35 deletions(-) diff --git a/src/app-layer-parser.c b/src/app-layer-parser.c index 0eb4293876..b893b92dd8 100644 --- a/src/app-layer-parser.c +++ b/src/app-layer-parser.c @@ -830,6 +830,10 @@ int AppLayerParse(Flow *f, uint8_t proto, uint8_t flags, uint8_t *input, SCReturnInt(-1); } + parser_state_store->version++; + SCLogDebug("app layer state version incremented to %"PRIu16, + parser_state_store->version); + AppLayerParserState *parser_state = NULL; if (flags & STREAM_TOSERVER) { SCLogDebug("to_server msg (flow %p)", f); @@ -1097,6 +1101,28 @@ error: SCReturnInt(-1); } +/** + * \brief get the version of the state in a direction + * + * \param f LOCKED flow + * \param direction STREAM_TOSERVER or STREAM_TOCLIENT + */ +uint16_t AppLayerGetStateVersion(Flow *f) { + SCEnter(); + uint16_t version = 0; + AppLayerParserStateStore *parser_state_store = NULL; + + /* Get the parser state (if any) */ + if (f->aldata != NULL) { + parser_state_store = (AppLayerParserStateStore *)f->aldata[app_layer_sid]; + if (parser_state_store != NULL) { + version = parser_state_store->version; + } + } + + SCReturnUInt(version); +} + /** * \param f LOCKED flow * \param direction STREAM_TOSERVER or STREAM_TOCLIENT diff --git a/src/app-layer-parser.h b/src/app-layer-parser.h index b16735f424..55b34a0b86 100644 --- a/src/app-layer-parser.h +++ b/src/app-layer-parser.h @@ -117,6 +117,9 @@ typedef struct AppLayerParserStateStore_ { * state. As transactions may be cleaned up before the entire state is * freed, id's may "disappear". */ uint16_t base_id; + + uint16_t version; /**< state version, incremented for each update, + * can wrap around */ } AppLayerParserStateStore; typedef struct AppLayerParserTableElement_ { @@ -241,6 +244,7 @@ uint8_t AppLayerRegisterModule(void); uint8_t AppLayerGetStorageSize(void); void AppLayerFreeProbingParsers(AppLayerProbingParser *); +uint16_t AppLayerGetStateVersion(Flow *f); #endif /* __APP_LAYER_PARSER_H__ */ diff --git a/src/detect-engine-state.c b/src/detect-engine-state.c index f1a562b8aa..0eb9f7430f 100644 --- a/src/detect-engine-state.c +++ b/src/detect-engine-state.c @@ -267,18 +267,46 @@ static void DeStateSignatureAppend(DetectEngineState *state, Signature *s, uricontent + app layer sm */ -/** \brief Check if a flow already contains a flow detect state +uint16_t DeStateGetStateVersion(DetectEngineState *de_state, uint8_t direction) { + if (direction & STREAM_TOSERVER) { + SCReturnUInt(de_state->toserver_version); + } else { + SCReturnUInt(de_state->toclient_version); + } +} + +void DeStateStoreStateVersion(DetectEngineState *de_state, uint8_t direction, + uint16_t alversion) +{ + if (direction & STREAM_TOSERVER) { + SCLogDebug("STREAM_TOSERVER updated to %"PRIu16, alversion); + de_state->toserver_version = alversion; + } else { + SCLogDebug("STREAM_TOCLIENT updated to %"PRIu16, alversion); + de_state->toclient_version = alversion; + } +} + +/** + * \brief Check if a flow already contains a flow detect state + * + * \retval 2 has state, but it's not updated * \retval 1 has state * \retval 0 has no state */ -int DeStateFlowHasState(Flow *f) { +int DeStateFlowHasState(Flow *f, uint8_t flags, uint16_t alversion) { SCEnter(); + int r = 0; SCMutexLock(&f->de_state_m); + if (f->de_state == NULL || f->de_state->cnt == 0) r = 0; + else if (DeStateGetStateVersion(f->de_state, flags) == alversion) + r = 2; else r = 1; + SCMutexUnlock(&f->de_state_m); SCReturnInt(r); } @@ -290,7 +318,7 @@ int DeStateFlowHasState(Flow *f) { */ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Signature *s, Flow *f, uint8_t flags, - void *alstate, uint16_t alproto) + void *alstate, uint16_t alproto, uint16_t alversion) { SCEnter(); @@ -451,6 +479,7 @@ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, if (f->de_state != NULL) { /* \todo shift to an array to transfer these match values*/ DeStateSignatureAppend(f->de_state, s, sm, match_flags); + DeStateStoreStateVersion(f->de_state, flags, alversion); } SCMutexUnlock(&f->de_state_m); @@ -462,7 +491,7 @@ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, * \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) + Flow *f, uint8_t flags, void *alstate, uint16_t alproto, uint16_t alversion) { SCEnter(); SigIntId cnt = 0; @@ -481,6 +510,10 @@ int DeStateDetectContinueDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, Dete if (f->de_state == NULL || f->de_state->cnt == 0) goto end; + if (DeStateGetStateVersion(f->de_state, flags) == alversion) { + goto end; + } + /* loop through the stores */ for (store = f->de_state->head; store != NULL; store = store->next) { @@ -701,6 +734,7 @@ next_sig: } } + DeStateStoreStateVersion(f->de_state, flags, alversion); end: SCMutexUnlock(&f->de_state_m); SCReturnInt(0); @@ -725,30 +759,6 @@ int DeStateRestartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngin 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" diff --git a/src/detect-engine-state.h b/src/detect-engine-state.h index 01d9c40f09..d25d9ceeaf 100644 --- a/src/detect-engine-state.h +++ b/src/detect-engine-state.h @@ -42,7 +42,7 @@ #define __DETECT_ENGINE_STATE_H__ /** number of DeStateStoreItem's in one DeStateStore object */ -#define DE_STATE_CHUNK_SIZE 16 +#define DE_STATE_CHUNK_SIZE 15 #define DE_STATE_FLAG_PAYLOAD_MATCH 0x0001 /**< payload part of the sig matched */ #define DE_STATE_FLAG_URI_MATCH 0x0002 /**< uri part of the sig matched */ @@ -92,6 +92,8 @@ typedef struct DetectEngineState_ { DeStateStore *head; /**< signature state storage */ DeStateStore *tail; /**< tail item of the storage list */ SigIntId cnt; /**< number of sigs in the storage */ + uint16_t toclient_version; + uint16_t toserver_version; } DetectEngineState; void DeStateRegisterTests(void); @@ -105,13 +107,15 @@ void DetectEngineStateFree(DetectEngineState *); //void DeStateSignatureAppend(DetectEngineState *, Signature *, SigMatch *, char); -int DeStateFlowHasState(Flow *); +int DeStateFlowHasState(Flow *, uint8_t, uint16_t); int DeStateDetectStartDetection(ThreadVars *, DetectEngineCtx *, - DetectEngineThreadCtx *, Signature *, Flow *, uint8_t, void *, uint16_t); + DetectEngineThreadCtx *, Signature *, Flow *, uint8_t, void *, + uint16_t, uint16_t); int DeStateDetectContinueDetection(ThreadVars *, DetectEngineCtx *, - DetectEngineThreadCtx *, Flow *, uint8_t, void *, uint16_t); + DetectEngineThreadCtx *, Flow *, uint8_t, void *, uint16_t, + uint16_t); const char *DeStateMatchResultToString(DeStateMatchResult); int DeStateUpdateInspectTransactionId(Flow *, char); diff --git a/src/detect.c b/src/detect.c index fb8a7a392b..ead3284979 100644 --- a/src/detect.c +++ b/src/detect.c @@ -1273,6 +1273,7 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh StreamMsg *smsg = NULL; Signature *s = NULL; SigMatch *sm = NULL; + uint16_t alversion = 0; SCEnter(); @@ -1328,6 +1329,7 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh { alstate = AppLayerGetProtoStateFromPacket(p); alproto = AppLayerGetProtoFromPacket(p); + alversion = AppLayerGetStateVersion(p->flow); SCLogDebug("alstate %p, alproto %u", alstate, alproto); } else { SCLogDebug("packet doesn't have established flag set (proto %d)", IP_GET_IPPROTO(p)); @@ -1402,9 +1404,12 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh memset(det_ctx->de_state_sig_array, 0x00, det_ctx->de_state_sig_array_len); /* if applicable, continue stateful detection */ - if (DeStateFlowHasState(p->flow)) { + int state = DeStateFlowHasState(p->flow, flags, alversion); + if (state == 1) { DeStateDetectContinueDetection(th_v, de_ctx, det_ctx, p->flow, - flags, alstate, alproto); + flags, alstate, alproto, alversion); + } else if (state == 2) { + alstate = NULL; } } @@ -1580,7 +1585,7 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh if (det_ctx->de_state_sig_array[s->num] == DE_STATE_MATCH_NOSTATE) { SCLogDebug("stateful app layer match inspection starting"); if (DeStateDetectStartDetection(th_v, de_ctx, det_ctx, s, - p->flow, flags, alstate, alproto) != 1) { + p->flow, flags, alstate, alproto, alversion) != 1) { goto next; } else { if (s->action == ACTION_DROP)