Add a app layer state and stateful detection engine counter that makes sure the stateful inspection is only done when the state changes.

remotes/origin/master-1.1.x
Victor Julien 14 years ago
parent 50aceb11eb
commit 73efb4c70f

@ -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

@ -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__ */

@ -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"

@ -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);

@ -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)

Loading…
Cancel
Save