From 95365ce05b5305fc5c37978f477c702e918e03cd Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 6 Jun 2026 14:29:57 +0200 Subject: [PATCH] detect: support per tx sub states Support for per transaction sub states: different state machines per transaction type. Skip engines not belonging to our substate. Store tx_type in DetectTransaction. Each protocol supporting sub states will register states from 1 and up. To support: Ticket: #8386. --- rust/sys/src/sys.rs | 13 +++ src/detect-engine-analyzer.c | 4 + src/detect-engine-helper.c | 31 ++++++ src/detect-engine-helper.h | 5 + src/detect-engine-mpm.c | 31 +++++- src/detect-engine-mpm.h | 7 ++ src/detect-engine-prefilter.c | 197 +++++++++++++++++++++------------- src/detect-engine-prefilter.h | 6 ++ src/detect-engine.c | 60 +++++++++-- src/detect-engine.h | 11 ++ src/detect.c | 40 ++++++- src/detect.h | 15 ++- 12 files changed, 325 insertions(+), 95 deletions(-) diff --git a/rust/sys/src/sys.rs b/rust/sys/src/sys.rs index 87b741df19..b13890f6b9 100644 --- a/rust/sys/src/sys.rs +++ b/rust/sys/src/sys.rs @@ -894,6 +894,12 @@ extern "C" { alproto: AppProto, direction: u8, GetData: InspectionSingleBufferGetDataPtr, ) -> ::std::os::raw::c_int; } +extern "C" { + pub fn SCDetectHelperBufferProgressRegisterSubState( + name: *const ::std::os::raw::c_char, alproto: AppProto, direction: u8, sub_state: u8, + progress: u8, + ) -> ::std::os::raw::c_int; +} extern "C" { pub fn SCDetectRegisterMpmGeneric( name: *const ::std::os::raw::c_char, desc: *const ::std::os::raw::c_char, @@ -918,6 +924,13 @@ extern "C" { alproto: AppProto, direction: u8, GetData: InspectionMultiBufferGetDataPtr, progress: u8, ) -> ::std::os::raw::c_int; } +extern "C" { + pub fn SCDetectHelperMultiBufferProgressMpmRegisterSubState( + name: *const ::std::os::raw::c_char, desc: *const ::std::os::raw::c_char, + alproto: AppProto, direction: u8, GetData: InspectionMultiBufferGetDataPtr, sub_state: u8, + progress: u8, + ) -> ::std::os::raw::c_int; +} extern "C" { pub fn SCDetectHelperTransformRegister( kw: *const SCTransformTableElmt, diff --git a/src/detect-engine-analyzer.c b/src/detect-engine-analyzer.c index 2fabf6d788..6b60916d8d 100644 --- a/src/detect-engine-analyzer.c +++ b/src/detect-engine-analyzer.c @@ -58,6 +58,7 @@ #include "detect-icmp-id.h" #include "detect-tcp-window.h" #include "detect-app-layer-protocol.h" +#include "app-layer-parser.h" static int rule_warnings_only = 0; @@ -1460,6 +1461,9 @@ void EngineAnalysisRules2(const DetectEngineCtx *de_ctx, const Signature *s) SCJbSetBool(ctx.js, "is_mpm", app->mpm); SCJbSetString(ctx.js, "app_proto", AppProtoToString(app->alproto)); SCJbSetUint(ctx.js, "progress", app->progress); + if (app->sub_state) + SCJbSetString(ctx.js, "sub_state", + AppLayerParserGetSubStateName(app->alproto, app->sub_state)); if (app->v2.transforms != NULL) { SCJbOpenArray(ctx.js, "transforms"); diff --git a/src/detect-engine-helper.c b/src/detect-engine-helper.c index 070db436a8..edd8b45069 100644 --- a/src/detect-engine-helper.c +++ b/src/detect-engine-helper.c @@ -45,6 +45,20 @@ int SCDetectHelperBufferProgressRegister( return DetectBufferTypeRegister(name); } +int SCDetectHelperBufferProgressRegisterSubState( + const char *name, AppProto alproto, uint8_t direction, uint8_t sub_state, uint8_t progress) +{ + if (direction & STREAM_TOSERVER) { + DetectAppLayerInspectEngineRegisterSubState(name, alproto, SIG_FLAG_TOSERVER, sub_state, + (uint8_t)progress, DetectEngineInspectGenericList, NULL); + } + if (direction & STREAM_TOCLIENT) { + DetectAppLayerInspectEngineRegisterSubState(name, alproto, SIG_FLAG_TOCLIENT, sub_state, + (uint8_t)progress, DetectEngineInspectGenericList, NULL); + } + return DetectBufferTypeRegister(name); +} + int SCDetectHelperBufferMpmRegister(const char *name, const char *desc, AppProto alproto, uint8_t direction, InspectionSingleBufferGetDataPtr GetData) { @@ -117,6 +131,23 @@ int SCDetectHelperMultiBufferProgressMpmRegister(const char *name, const char *d return DetectBufferTypeGetByName(name); } +int SCDetectHelperMultiBufferProgressMpmRegisterSubState(const char *name, const char *desc, + AppProto alproto, uint8_t direction, InspectionMultiBufferGetDataPtr GetData, + uint8_t sub_state, uint8_t progress) +{ + if (direction & STREAM_TOSERVER) { + DetectAppLayerMultiRegisterSubState( + name, alproto, SIG_FLAG_TOSERVER, sub_state, progress, GetData, 2); + } + if (direction & STREAM_TOCLIENT) { + DetectAppLayerMultiRegisterSubState( + name, alproto, SIG_FLAG_TOCLIENT, sub_state, progress, GetData, 2); + } + DetectBufferTypeSupportsMultiInstance(name); + DetectBufferTypeSetDescriptionByName(name, desc); + return DetectBufferTypeGetByName(name); +} + int SCDetectHelperMultiBufferMpmRegister(const char *name, const char *desc, AppProto alproto, uint8_t direction, InspectionMultiBufferGetDataPtr GetData) { diff --git a/src/detect-engine-helper.h b/src/detect-engine-helper.h index 6df807923b..bf52a7ade8 100644 --- a/src/detect-engine-helper.h +++ b/src/detect-engine-helper.h @@ -85,6 +85,8 @@ int SCDetectHelperBufferProgressRegister( int SCDetectHelperBufferMpmRegister(const char *name, const char *desc, AppProto alproto, uint8_t direction, InspectionSingleBufferGetDataPtr GetData); +int SCDetectHelperBufferProgressRegisterSubState( + const char *name, AppProto alproto, uint8_t direction, uint8_t sub_state, uint8_t progress); int SCDetectRegisterMpmGeneric(const char *name, const char *desc, AppProto alproto, uint8_t direction, InspectionBufferGetDataPtr GetData, uint8_t progress); int SCDetectHelperBufferProgressMpmRegister(const char *name, const char *desc, AppProto alproto, @@ -94,6 +96,9 @@ int SCDetectHelperMultiBufferMpmRegister(const char *name, const char *desc, App int SCDetectHelperMultiBufferProgressMpmRegister(const char *name, const char *desc, AppProto alproto, uint8_t direction, InspectionMultiBufferGetDataPtr GetData, uint8_t progress); +int SCDetectHelperMultiBufferProgressMpmRegisterSubState(const char *name, const char *desc, + AppProto alproto, uint8_t direction, InspectionMultiBufferGetDataPtr GetData, + uint8_t sub_state, uint8_t progress); int SCDetectHelperTransformRegister(const SCTransformTableElmt *kw); diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index f1fa15bc87..4490d271d5 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -89,7 +89,8 @@ static int g_mpm_list_cnt[DETECT_BUFFER_MPM_TYPE_SIZE] = { 0, 0, 0 }; static void RegisterInternal(const char *name, int direction, int priority, PrefilterRegisterFunc PrefilterRegister, InspectionBufferGetDataPtr GetData, InspectionSingleBufferGetDataPtr GetDataSingle, - InspectionMultiBufferGetDataPtr GetMultiData, AppProto alproto, uint8_t tx_min_progress) + InspectionMultiBufferGetDataPtr GetMultiData, AppProto alproto, uint8_t sub_state, + uint8_t tx_min_progress) { SCLogDebug("registering %s/%d/%d/%p/%p/%u/%d", name, direction, priority, PrefilterRegister, GetData, alproto, tx_min_progress); @@ -109,7 +110,7 @@ static void RegisterInternal(const char *name, int direction, int priority, // every HTTP2 can be accessed from DOH2 if (alproto == ALPROTO_HTTP2 || alproto == ALPROTO_DNS) { RegisterInternal(name, direction, priority, PrefilterRegister, GetData, GetDataSingle, - GetMultiData, ALPROTO_DOH2, tx_min_progress); + GetMultiData, ALPROTO_DOH2, sub_state, tx_min_progress); } DetectBufferMpmRegistry *am = SCCalloc(1, sizeof(*am)); BUG_ON(am == NULL); @@ -132,6 +133,7 @@ static void RegisterInternal(const char *name, int direction, int priority, } am->app_v2.alproto = alproto; am->app_v2.tx_min_progress = tx_min_progress; + am->app_v2.sub_state = sub_state; if (g_mpm_list[DETECT_BUFFER_MPM_TYPE_APP] == NULL) { g_mpm_list[DETECT_BUFFER_MPM_TYPE_APP] = am; @@ -147,21 +149,31 @@ static void RegisterInternal(const char *name, int direction, int priority, g_mpm_list_cnt[DETECT_BUFFER_MPM_TYPE_APP]++; SupportFastPatternForSigMatchList(sm_list, priority); + SCLogDebug("%s: sub_state %u", name, am->app_v2.sub_state); } void DetectAppLayerMpmRegister(const char *name, int direction, int priority, PrefilterRegisterFunc PrefilterRegister, InspectionBufferGetDataPtr GetData, AppProto alproto, uint8_t tx_min_progress) { - RegisterInternal(name, direction, priority, PrefilterRegister, GetData, NULL, NULL, alproto, + RegisterInternal(name, direction, priority, PrefilterRegister, GetData, NULL, NULL, alproto, 0, tx_min_progress); } +void DetectAppLayerMpmRegisterSubState(const char *name, int direction, int priority, + PrefilterRegisterFunc PrefilterRegister, InspectionBufferGetDataPtr GetData, + AppProto alproto, uint8_t sub_state, uint8_t tx_min_progress) +{ + SCLogDebug("%s: sub_state %u", name, sub_state); + RegisterInternal(name, direction, priority, PrefilterRegister, GetData, NULL, NULL, alproto, + sub_state, tx_min_progress); +} + void DetectAppLayerMpmRegisterSingle(const char *name, int direction, int priority, PrefilterRegisterFunc PrefilterRegister, InspectionSingleBufferGetDataPtr GetData, AppProto alproto, uint8_t tx_min_progress) { - RegisterInternal(name, direction, priority, PrefilterRegister, NULL, GetData, NULL, alproto, + RegisterInternal(name, direction, priority, PrefilterRegister, NULL, GetData, NULL, alproto, 0, tx_min_progress); } @@ -169,10 +181,18 @@ void DetectAppLayerMpmMultiRegister(const char *name, int direction, int priorit PrefilterRegisterFunc PrefilterRegister, InspectionMultiBufferGetDataPtr GetData, AppProto alproto, uint8_t tx_min_progress) { - RegisterInternal(name, direction, priority, PrefilterRegister, NULL, NULL, GetData, alproto, + RegisterInternal(name, direction, priority, PrefilterRegister, NULL, NULL, GetData, alproto, 0, tx_min_progress); } +void DetectAppLayerMpmMultiRegisterSubState(const char *name, int direction, int priority, + PrefilterRegisterFunc PrefilterRegister, InspectionMultiBufferGetDataPtr GetData, + AppProto alproto, uint8_t sub_state, uint8_t tx_min_progress) +{ + RegisterInternal(name, direction, priority, PrefilterRegister, NULL, NULL, GetData, alproto, + sub_state, tx_min_progress); +} + /** \internal * \brief build basic profiling name (pname) making sure the id is always fully printed */ @@ -263,6 +283,7 @@ void DetectAppLayerMpmRegisterByParentId(DetectEngineCtx *de_ctx, am->app_v2.GetData = t->app_v2.GetData; am->app_v2.alproto = t->app_v2.alproto; am->app_v2.tx_min_progress = t->app_v2.tx_min_progress; + am->app_v2.sub_state = t->app_v2.sub_state; am->priority = t->priority; am->sgh_mpm_context = t->sgh_mpm_context; am->sgh_mpm_context = MpmFactoryRegisterMpmCtxProfile( diff --git a/src/detect-engine-mpm.h b/src/detect-engine-mpm.h index 0df2c4a8e0..489d0b742c 100644 --- a/src/detect-engine-mpm.h +++ b/src/detect-engine-mpm.h @@ -87,12 +87,19 @@ typedef int (*PrefilterRegisterFunc)(DetectEngineCtx *de_ctx, SigGroupHead *sgh, void DetectAppLayerMpmRegister(const char *name, int direction, int priority, PrefilterRegisterFunc PrefilterRegister, InspectionBufferGetDataPtr GetData, AppProto alproto, uint8_t tx_min_progress); +void DetectAppLayerMpmRegisterSubState(const char *name, int direction, int priority, + PrefilterRegisterFunc PrefilterRegister, InspectionBufferGetDataPtr GetData, + AppProto alproto, uint8_t sub_state, uint8_t tx_min_progress); void DetectAppLayerMpmRegisterSingle(const char *name, int direction, int priority, PrefilterRegisterFunc PrefilterRegister, InspectionSingleBufferGetDataPtr GetData, AppProto alproto, uint8_t tx_min_progress); void DetectAppLayerMpmMultiRegister(const char *name, int direction, int priority, PrefilterRegisterFunc PrefilterRegister, InspectionMultiBufferGetDataPtr GetData, AppProto alproto, uint8_t tx_min_progress); +/** As DetectAppLayerMpmMultiRegister, but with a sub state argument */ +void DetectAppLayerMpmMultiRegisterSubState(const char *name, int direction, int priority, + PrefilterRegisterFunc PrefilterRegister, InspectionMultiBufferGetDataPtr GetData, + AppProto alproto, uint8_t sub_state, uint8_t tx_min_progress); void DetectAppLayerMpmRegisterByParentId( DetectEngineCtx *de_ctx, const int id, const int parent_id, diff --git a/src/detect-engine-prefilter.c b/src/detect-engine-prefilter.c index e7e5d70113..ab64fc19cd 100644 --- a/src/detect-engine-prefilter.c +++ b/src/detect-engine-prefilter.c @@ -104,11 +104,20 @@ void DetectRunPrefilterTx(DetectEngineThreadCtx *det_ctx, /* reset rule store */ det_ctx->pmq.rule_id_array_cnt = 0; - SCLogDebug("packet %" PRIu64 " tx %p progress %d tx->detect_progress %02x", PcapPacketCntGet(p), - tx->tx_ptr, tx->tx_progress, tx->detect_progress); + SCLogDebug("packet %" PRIu64 " tx %p id %" PRIu64 " progress %d tx->detect_progress %02x", + PcapPacketCntGet(p), tx->tx_ptr, tx->tx_id, tx->tx_progress, tx->detect_progress); PrefilterEngine *engine = sgh->tx_engines; do { + SCLogDebug("%" PRIu64 ": engine %p for %s progress %u sub_state %u tx %u", + PcapPacketCntGet(p), engine, AppProtoToString(engine->alproto), + engine->ctx.app.tx_min_progress, engine->ctx.app.sub_state, tx->tx_type); + if (engine->alproto != ALPROTO_UNKNOWN && engine->ctx.app.sub_state != tx->tx_type) { + SCLogDebug("%" PRIu64 ": engine %p sub_state %u mismatch with tx %u", + PcapPacketCntGet(p), engine, engine->ctx.app.sub_state, tx->tx_type); + // not for the tx sub state + goto next; + } // based on flow alproto, and engine, we get right tx_ptr void *tx_ptr = DetectGetInnerTx(tx->tx_ptr, alproto, engine->alproto, flow_flags); if (tx_ptr == NULL) { @@ -116,30 +125,31 @@ void DetectRunPrefilterTx(DetectEngineThreadCtx *det_ctx, goto next; } - if (engine->ctx.tx_min_progress != -1) { + if (engine->ctx.app.tx_min_progress != -1) { #ifdef DEBUG const char *pname = AppLayerParserGetStateNameById(ipproto, engine->alproto, - engine->ctx.tx_min_progress, flow_flags & (STREAM_TOSERVER | STREAM_TOCLIENT)); - SCLogDebug("engine %p min_progress %d %s:%s", engine, engine->ctx.tx_min_progress, + engine->ctx.app.tx_min_progress, + flow_flags & (STREAM_TOSERVER | STREAM_TOCLIENT)); + SCLogDebug("engine %p min_progress %d %s:%s", engine, engine->ctx.app.tx_min_progress, AppProtoToString(engine->alproto), pname); #endif /* if engine needs tx state to be higher, break out. */ - if (engine->ctx.tx_min_progress > tx->tx_progress) + if (engine->ctx.app.tx_min_progress > tx->tx_progress) break; - if (tx->tx_progress > engine->ctx.tx_min_progress) { - SCLogDebug("tx->tx_progress %u > engine->ctx.tx_min_progress %d", tx->tx_progress, - engine->ctx.tx_min_progress); + if (tx->tx_progress > engine->ctx.app.tx_min_progress) { + SCLogDebug("tx->tx_progress %u > engine->ctx.app.tx_min_progress %d", + tx->tx_progress, engine->ctx.app.tx_min_progress); /* if state value is at or beyond engine state, we can skip it. It means we ran at * least once already. */ - if (tx->detect_progress > engine->ctx.tx_min_progress) { + if (tx->detect_progress > engine->ctx.app.tx_min_progress) { SCLogDebug("tx already marked progress as beyond engine: %u > %u", - tx->detect_progress, engine->ctx.tx_min_progress); + tx->detect_progress, engine->ctx.app.tx_min_progress); goto next; } else { - SCLogDebug("tx->tx_progress %u > engine->ctx.tx_min_progress %d: " + SCLogDebug("tx->tx_progress %u > engine->ctx.app.tx_min_progress %d: " "tx->detect_progress %u", - tx->tx_progress, engine->ctx.tx_min_progress, tx->detect_progress); + tx->tx_progress, engine->ctx.app.tx_min_progress, tx->detect_progress); } } #ifdef DEBUG @@ -150,21 +160,21 @@ void DetectRunPrefilterTx(DetectEngineThreadCtx *det_ctx, tx->tx_data_ptr, flow_flags); PREFILTER_PROFILING_END(det_ctx, engine->gid); SCLogDebug("engine %p min_progress %d %s:%s: results %u", engine, - engine->ctx.tx_min_progress, AppProtoToString(engine->alproto), pname, + engine->ctx.app.tx_min_progress, AppProtoToString(engine->alproto), pname, det_ctx->pmq.rule_id_array_cnt - old); - if (tx->tx_progress > engine->ctx.tx_min_progress && engine->is_last_for_progress && + if (tx->tx_progress > engine->ctx.app.tx_min_progress && engine->is_last_for_progress && tx->tx_ptr == tx_ptr) { /* track with an offset of one, so that tx->progress 0 complete is tracked * as 1, progress 1 as 2, etc. This is to allow 0 to mean: nothing tracked, even * though a parser may use 0 as a valid value. */ // tx->tx_ptr == tx_ptr ensures we do not use a dns engine progress // to update a HTTP2 tx detect_progress in case of DOH2 - tx->detect_progress = engine->ctx.tx_min_progress + 1; - SCLogDebug("tx->tx_progress %d engine->ctx.tx_min_progress %d " + tx->detect_progress = engine->ctx.app.tx_min_progress + 1; + SCLogDebug("tx->tx_progress %d engine->ctx.app.tx_min_progress %d " "engine->is_last_for_progress %d => tx->detect_progress updated to %02x", - tx->tx_progress, engine->ctx.tx_min_progress, engine->is_last_for_progress, - tx->detect_progress); + tx->tx_progress, engine->ctx.app.tx_min_progress, + engine->is_last_for_progress, tx->detect_progress); } } else { PREFILTER_PROFILING_START(det_ctx); @@ -353,9 +363,9 @@ int PrefilterAppendPayloadEngine(DetectEngineCtx *de_ctx, SigGroupHead *sgh, return 0; } -int PrefilterAppendTxEngine(DetectEngineCtx *de_ctx, SigGroupHead *sgh, - PrefilterTxFn PrefilterTxFunc, AppProto alproto, int8_t tx_min_progress, void *pectx, - void (*FreeFunc)(void *pectx), const char *name) +int PrefilterAppendTxEngineSubState(DetectEngineCtx *de_ctx, SigGroupHead *sgh, + PrefilterTxFn PrefilterTxFunc, AppProto alproto, uint8_t sub_state, + const int8_t tx_min_progress, void *pectx, void (*FreeFunc)(void *pectx), const char *name) { if (sgh == NULL || PrefilterTxFunc == NULL || pectx == NULL) return -1; @@ -369,6 +379,7 @@ int PrefilterAppendTxEngine(DetectEngineCtx *de_ctx, SigGroupHead *sgh, e->pectx = pectx; e->alproto = alproto; e->tx_min_progress = tx_min_progress; + e->sub_state = sub_state; e->Free = FreeFunc; if (sgh->init->tx_engines == NULL) { @@ -385,9 +396,18 @@ int PrefilterAppendTxEngine(DetectEngineCtx *de_ctx, SigGroupHead *sgh, e->name = name; e->gid = PrefilterStoreGetId(de_ctx, e->name, e->Free); + SCLogDebug("%s: sub_state %u", name, e->sub_state); return 0; } +int PrefilterAppendTxEngine(DetectEngineCtx *de_ctx, SigGroupHead *sgh, + PrefilterTxFn PrefilterTxFunc, AppProto alproto, const int8_t tx_min_progress, void *pectx, + void (*FreeFunc)(void *pectx), const char *name) +{ + return PrefilterAppendTxEngineSubState( + de_ctx, sgh, PrefilterTxFunc, alproto, 0, tx_min_progress, pectx, FreeFunc, name); +} + int PrefilterAppendFrameEngine(DetectEngineCtx *de_ctx, SigGroupHead *sgh, PrefilterFrameFn PrefilterFrameFunc, AppProto alproto, uint8_t frame_type, void *pectx, void (*FreeFunc)(void *pectx), const char *name) @@ -520,14 +540,18 @@ static int PrefilterSetupRuleGroupSortHelper(const void *a, const void *b) { const PrefilterEngine *s0 = a; const PrefilterEngine *s1 = b; - if (s1->ctx.tx_min_progress == s0->ctx.tx_min_progress) { - if (s1->alproto == s0->alproto) { - return s0->local_id > s1->local_id ? 1 : -1; + if (s1->ctx.app.sub_state == s0->ctx.app.sub_state) { + if (s1->ctx.app.tx_min_progress == s0->ctx.app.tx_min_progress) { + if (s1->alproto == s0->alproto) { + return s0->local_id > s1->local_id ? 1 : -1; + } else { + return s0->alproto > s1->alproto ? 1 : -1; + } } else { - return s0->alproto > s1->alproto ? 1 : -1; + return s0->ctx.app.tx_min_progress > s1->ctx.app.tx_min_progress ? 1 : -1; } } else { - return s0->ctx.tx_min_progress > s1->ctx.tx_min_progress ? 1 : -1; + return s0->ctx.app.sub_state > s1->ctx.app.sub_state ? 1 : -1; } } @@ -701,6 +725,7 @@ static void NonPFNamesFree(void *data) struct TxNonPFData { AppProto alproto; + uint8_t sub_state; int dir; /**< 0: toserver, 1: toclient */ uint8_t progress; /**< progress state value to register at */ int sig_list; /**< special handling: normally 0, but for special cases (app-layer-state, @@ -713,15 +738,15 @@ struct TxNonPFData { static uint32_t TxNonPFHash(HashListTable *h, void *data, uint16_t _len) { struct TxNonPFData *d = data; - return (d->alproto + d->progress + d->dir + d->sig_list) % h->array_size; + return (d->alproto + d->sub_state + d->progress + d->dir + d->sig_list) % h->array_size; } static char TxNonPFCompare(void *data1, uint16_t _len1, void *data2, uint16_t len2) { struct TxNonPFData *d1 = data1; struct TxNonPFData *d2 = data2; - return d1->alproto == d2->alproto && d1->progress == d2->progress && d1->dir == d2->dir && - d1->sig_list == d2->sig_list; + return d1->alproto == d2->alproto && d1->sub_state == d2->sub_state && + d1->progress == d2->progress && d1->dir == d2->dir && d1->sig_list == d2->sig_list; } static void TxNonPFFree(void *data) @@ -732,13 +757,14 @@ static void TxNonPFFree(void *data) } static int TxNonPFAddSig(DetectEngineCtx *de_ctx, HashListTable *tx_engines_hash, - const AppProto alproto, const int dir, const uint8_t progress, const int sig_list, - const char *name, const Signature *s) + const AppProto alproto, const uint8_t sub_state, const int dir, const uint8_t progress, + const int sig_list, const char *name, const Signature *s) { const uint32_t max_sids = DetectEngineGetMaxSigId(de_ctx); struct TxNonPFData lookup = { .alproto = alproto, + .sub_state = sub_state, .dir = dir, .progress = progress, .sig_list = sig_list, @@ -770,6 +796,7 @@ static int TxNonPFAddSig(DetectEngineCtx *de_ctx, HashListTable *tx_engines_hash return -1; } add->dir = dir; + add->sub_state = sub_state; add->alproto = alproto; add->progress = progress; add->sig_list = sig_list; @@ -950,8 +977,9 @@ static int SetupNonPrefilter(DetectEngineCtx *de_ctx, SigGroupHead *sgh) } const int sm_list = DetectEngineAppHookToSmlist( s->alproto, state, dir == 0 ? STREAM_TOSERVER : STREAM_TOCLIENT); - if (TxNonPFAddSig(de_ctx, tx_engines_hash, s->alproto, dir, state, sm_list, pname, - s) != 0) { + uint8_t sub_state = s->init_data->hook.t.app.sub_state; + if (TxNonPFAddSig(de_ctx, tx_engines_hash, s->alproto, sub_state, dir, state, + sm_list, pname, s) != 0) { goto error; } tx_non_pf = true; @@ -1014,7 +1042,8 @@ static int SetupNonPrefilter(DetectEngineCtx *de_ctx, SigGroupHead *sgh) int sig_list = 0; if (list_id == app_state_list_id) sig_list = app_state_list_id; - if (TxNonPFAddSig(de_ctx, tx_engines_hash, app->alproto, app->dir, + const uint8_t sub_state = app->sub_state; + if (TxNonPFAddSig(de_ctx, tx_engines_hash, app->alproto, sub_state, app->dir, app->progress, sig_list, buf->name, s) != 0) { goto error; } @@ -1035,7 +1064,8 @@ static int SetupNonPrefilter(DetectEngineCtx *de_ctx, SigGroupHead *sgh) s->alproto, s->init_data->hook.t.app.app_progress, dir == 0 ? STREAM_TOSERVER : STREAM_TOCLIENT); - if (TxNonPFAddSig(de_ctx, tx_engines_hash, s->alproto, dir, + uint8_t sub_state = s->init_data->hook.t.app.sub_state; + if (TxNonPFAddSig(de_ctx, tx_engines_hash, s->alproto, sub_state, dir, s->init_data->hook.t.app.app_progress, s->init_data->hook.sm_list, pname, s) != 0) { goto error; @@ -1129,8 +1159,8 @@ static int SetupNonPrefilter(DetectEngineCtx *de_ctx, SigGroupHead *sgh) for (uint32_t i = 0; i < t->sigs_cnt; i++) { data->array[i] = t->sigs[i].sid; } - if (PrefilterAppendTxEngine(de_ctx, sgh, PrefilterTxNonPF, t->alproto, engine_progress, - (void *)data, PrefilterNonPFDataFree, t->engine_name) < 0) { + if (PrefilterAppendTxEngineSubState(de_ctx, sgh, PrefilterTxNonPF, t->alproto, t->sub_state, + engine_progress, (void *)data, PrefilterNonPFDataFree, t->engine_name) < 0) { SCFree(data); goto error; } @@ -1308,7 +1338,8 @@ int PrefilterSetupRuleGroup(DetectEngineCtx *de_ctx, SigGroupHead *sgh) for (el = sgh->init->tx_engines ; el != NULL; el = el->next) { e->local_id = local_id++; e->alproto = el->alproto; - e->ctx.tx_min_progress = el->tx_min_progress; + e->ctx.app.tx_min_progress = el->tx_min_progress; + e->ctx.app.sub_state = el->sub_state; e->cb.PrefilterTx = el->PrefilterTx; e->pectx = el->pectx; el->pectx = NULL; // e now owns the ctx @@ -1323,45 +1354,58 @@ int PrefilterSetupRuleGroup(DetectEngineCtx *de_ctx, SigGroupHead *sgh) sgh->tx_engines[local_id - 1].is_last_for_progress = true; PrefilterEngine *engine; - /* per alproto to set is_last_for_progress per alproto because the inspect * loop skips over engines that are not the correct alproto */ for (AppProto a = ALPROTO_FAILED + 1; a < g_alproto_max; a++) { - int last_tx_progress = 0; - bool last_tx_progress_set = false; - PrefilterEngine *prev_engine = NULL; - engine = sgh->tx_engines; - do { - if (engine->ctx.tx_min_progress != -1) - BUG_ON(engine->ctx.tx_min_progress < last_tx_progress); - if (engine->alproto == a) { - if (last_tx_progress_set && engine->ctx.tx_min_progress > last_tx_progress) { - if (prev_engine) { - prev_engine->is_last_for_progress = true; - } - } + /* loop over sub-states. Protocols not supporting sub-states + * will just use 0. */ + const uint8_t max_sub_state = AppLayerParserGetMaxSubState(a); + for (uint8_t sub = 0; sub <= max_sub_state; sub++) { + int last_tx_progress = 0; + bool last_tx_progress_set = false; + PrefilterEngine *prev_engine = NULL; + engine = sgh->tx_engines; + do { + if (engine->ctx.app.sub_state == sub) { + if (engine->ctx.app.tx_min_progress != -1) + BUG_ON(engine->ctx.app.tx_min_progress < last_tx_progress); + if (engine->alproto == a) { + if (last_tx_progress_set && + engine->ctx.app.tx_min_progress > last_tx_progress) { + if (prev_engine) { + prev_engine->is_last_for_progress = true; + } + } - last_tx_progress_set = true; - prev_engine = engine; - } else { - if (prev_engine) { - prev_engine->is_last_for_progress = true; + last_tx_progress_set = true; + prev_engine = engine; + if (!engine->is_last) { + PrefilterEngine *next_engine = engine + 1; + engine->is_last_for_progress = + (next_engine->ctx.app.sub_state != sub); + } + + } else { + if (prev_engine) { + prev_engine->is_last_for_progress = true; + } + } + last_tx_progress = engine->ctx.app.tx_min_progress; } - } - last_tx_progress = engine->ctx.tx_min_progress; - if (engine->is_last) - break; - engine++; - } while (1); + if (engine->is_last) + break; + engine++; + } while (1); + } } #ifdef DEBUG SCLogDebug("sgh %p", sgh); engine = sgh->tx_engines; do { - SCLogDebug("engine: gid %u alproto %s tx_min_progress %d is_last %s " + SCLogDebug("engine: gid %u alproto %s sub_state %u tx_min_progress %d is_last %s " "is_last_for_progress %s", - engine->gid, AppProtoToString(engine->alproto), engine->ctx.tx_min_progress, - engine->is_last ? "true" : "false", + engine->gid, AppProtoToString(engine->alproto), engine->ctx.app.sub_state, + engine->ctx.app.tx_min_progress, engine->is_last ? "true" : "false", engine->is_last_for_progress ? "true" : "false"); if (engine->is_last) break; @@ -1622,9 +1666,10 @@ int PrefilterGenericMpmRegister(DetectEngineCtx *de_ctx, SigGroupHead *sgh, MpmC pectx->mpm_ctx = mpm_ctx; pectx->transforms = &mpm_reg->transforms; - int r = PrefilterAppendTxEngine(de_ctx, sgh, PrefilterMpm, - mpm_reg->app_v2.alproto, mpm_reg->app_v2.tx_min_progress, - pectx, PrefilterGenericMpmFree, mpm_reg->pname); + SCLogDebug("mpm_reg %s sub_state %u", mpm_reg->name, mpm_reg->app_v2.sub_state); + int r = PrefilterAppendTxEngineSubState(de_ctx, sgh, PrefilterMpm, mpm_reg->app_v2.alproto, + mpm_reg->app_v2.sub_state, mpm_reg->app_v2.tx_min_progress, pectx, + PrefilterGenericMpmFree, mpm_reg->pname); if (r != 0) { SCFree(pectx); } @@ -1643,8 +1688,10 @@ int PrefilterSingleMpmRegister(DetectEngineCtx *de_ctx, SigGroupHead *sgh, MpmCt pectx->mpm_ctx = mpm_ctx; pectx->transforms = &mpm_reg->transforms; - int r = PrefilterAppendTxEngine(de_ctx, sgh, PrefilterMpmTxSingle, mpm_reg->app_v2.alproto, - mpm_reg->app_v2.tx_min_progress, pectx, PrefilterGenericMpmFree, mpm_reg->pname); + SCLogDebug("mpm_reg %s sub_state %u", mpm_reg->name, mpm_reg->app_v2.sub_state); + int r = PrefilterAppendTxEngineSubState(de_ctx, sgh, PrefilterMpmTxSingle, + mpm_reg->app_v2.alproto, mpm_reg->app_v2.sub_state, mpm_reg->app_v2.tx_min_progress, + pectx, PrefilterGenericMpmFree, mpm_reg->pname); if (r != 0) { SCFree(pectx); } @@ -1696,8 +1743,10 @@ int PrefilterMultiGenericMpmRegister(DetectEngineCtx *de_ctx, SigGroupHead *sgh, pectx->mpm_ctx = mpm_ctx; pectx->transforms = &mpm_reg->transforms; - int r = PrefilterAppendTxEngine(de_ctx, sgh, PrefilterMultiMpm, mpm_reg->app_v2.alproto, - mpm_reg->app_v2.tx_min_progress, pectx, PrefilterMultiGenericMpmFree, mpm_reg->pname); + SCLogDebug("mpm_reg %s sub_state %u", mpm_reg->name, mpm_reg->app_v2.sub_state); + int r = PrefilterAppendTxEngineSubState(de_ctx, sgh, PrefilterMultiMpm, mpm_reg->app_v2.alproto, + mpm_reg->app_v2.sub_state, mpm_reg->app_v2.tx_min_progress, pectx, + PrefilterMultiGenericMpmFree, mpm_reg->pname); if (r != 0) { SCFree(pectx); } diff --git a/src/detect-engine-prefilter.h b/src/detect-engine-prefilter.h index 43e738ef37..662a518042 100644 --- a/src/detect-engine-prefilter.h +++ b/src/detect-engine-prefilter.h @@ -43,6 +43,9 @@ typedef struct DetectTransaction_ { const uint8_t tx_progress; const uint8_t tx_end_state; bool is_last; /* is this the last tx? */ + + /** app-layer specific transaction type (for sub-state support). 0 if not used. */ + const uint8_t tx_type; } DetectTransaction; typedef struct PrefilterStore_ { @@ -63,6 +66,9 @@ void PrefilterPostRuleMatch( int PrefilterAppendPayloadEngine(DetectEngineCtx *de_ctx, SigGroupHead *sgh, PrefilterPktFn PrefilterFunc, void *pectx, void (*FreeFunc)(void *pectx), const char *name); +int PrefilterAppendTxEngineSubState(DetectEngineCtx *de_ctx, SigGroupHead *sgh, + PrefilterTxFn PrefilterTxFunc, AppProto alproto, uint8_t sub_state, + const int8_t tx_min_progress, void *pectx, void (*FreeFunc)(void *pectx), const char *name); int PrefilterAppendTxEngine(DetectEngineCtx *de_ctx, SigGroupHead *sgh, PrefilterTxFn PrefilterTxFunc, const AppProto alproto, const int8_t tx_min_progress, void *pectx, void (*FreeFunc)(void *pectx), const char *name); diff --git a/src/detect-engine.c b/src/detect-engine.c index 237372db84..70ee94ec15 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -198,8 +198,8 @@ void DetectPktInspectEngineRegister(const char *name, * * \note errors are fatal */ static void AppLayerInspectEngineRegisterInternal(const char *name, AppProto alproto, uint32_t dir, - uint8_t progress, InspectEngineFuncPtr Callback, InspectionBufferGetDataPtr GetData, - InspectionSingleBufferGetDataPtr GetDataSingle, + uint8_t sub_state, uint8_t progress, InspectEngineFuncPtr Callback, + InspectionBufferGetDataPtr GetData, InspectionSingleBufferGetDataPtr GetDataSingle, InspectionMultiBufferGetDataPtr GetMultiData) { BUG_ON(progress >= 48); @@ -212,7 +212,8 @@ static void AppLayerInspectEngineRegisterInternal(const char *name, AppProto alp SCLogDebug("name %s id %d", name, sm_list); if ((alproto == ALPROTO_FAILED) || (!(dir == SIG_FLAG_TOSERVER || dir == SIG_FLAG_TOCLIENT)) || - (sm_list < DETECT_SM_LIST_MATCH) || (sm_list >= SHRT_MAX) || (Callback == NULL)) { + (sm_list < DETECT_SM_LIST_MATCH) || (sm_list >= SHRT_MAX) || (progress >= 48) || + (Callback == NULL)) { SCLogError("Invalid arguments"); BUG_ON(1); } else if (Callback == DetectEngineInspectBufferGeneric && GetData == NULL) { @@ -237,8 +238,8 @@ static void AppLayerInspectEngineRegisterInternal(const char *name, AppProto alp } // every DNS or HTTP2 can be accessed from DOH2 if (alproto == ALPROTO_HTTP2 || alproto == ALPROTO_DNS) { - AppLayerInspectEngineRegisterInternal( - name, ALPROTO_DOH2, dir, progress, Callback, GetData, GetDataSingle, GetMultiData); + AppLayerInspectEngineRegisterInternal(name, ALPROTO_DOH2, dir, sub_state, progress, + Callback, GetData, GetDataSingle, GetMultiData); } DetectEngineAppInspectionEngine *new_engine = @@ -251,6 +252,7 @@ static void AppLayerInspectEngineRegisterInternal(const char *name, AppProto alp new_engine->sm_list = (uint16_t)sm_list; new_engine->sm_list_base = (uint16_t)sm_list; new_engine->progress = progress; + new_engine->sub_state = sub_state; new_engine->v2.Callback = Callback; if (Callback == DetectEngineInspectBufferGeneric) { new_engine->v2.GetData = GetData; @@ -283,7 +285,8 @@ void DetectAppLayerInspectEngineRegister(const char *name, AppProto alproto, uin const int sm_list = DetectBufferTypeGetByName(name); if (t->sm_list == sm_list && t->alproto == alproto && t_direction == dir && - t->progress == progress && t->v2.Callback == Callback && t->v2.GetData == GetData) { + t->sub_state == 0 && t->progress == progress && t->v2.Callback == Callback && + t->v2.GetData == GetData) { DEBUG_VALIDATE_BUG_ON(1); return; } @@ -291,9 +294,32 @@ void DetectAppLayerInspectEngineRegister(const char *name, AppProto alproto, uin } AppLayerInspectEngineRegisterInternal( - name, alproto, dir, progress, Callback, GetData, NULL, NULL); + name, alproto, dir, 0, (uint8_t)progress, Callback, GetData, NULL, NULL); } +void DetectAppLayerInspectEngineRegisterSubState(const char *name, AppProto alproto, uint32_t dir, + uint8_t sub_state, uint8_t progress, InspectEngineFuncPtr Callback, + InspectionBufferGetDataPtr GetData) +{ + /* before adding, check that we don't add a duplicate entry, which will + * propagate all the way into the packet runtime if allowed. */ + DetectEngineAppInspectionEngine *t = g_app_inspect_engines; + while (t != NULL) { + const uint32_t t_direction = t->dir == 0 ? SIG_FLAG_TOSERVER : SIG_FLAG_TOCLIENT; + const int sm_list = DetectBufferTypeGetByName(name); + + if (t->sm_list == sm_list && t->alproto == alproto && t_direction == dir && + t->sub_state == sub_state && t->progress == progress && + t->v2.Callback == Callback && t->v2.GetData == GetData) { + DEBUG_VALIDATE_BUG_ON(1); + return; + } + t = t->next; + } + + AppLayerInspectEngineRegisterInternal( + name, alproto, dir, sub_state, progress, Callback, GetData, NULL, NULL); +} void DetectAppLayerInspectEngineRegisterSingle(const char *name, AppProto alproto, uint32_t dir, uint8_t progress, InspectEngineFuncPtr Callback, InspectionSingleBufferGetDataPtr GetData) { @@ -314,7 +340,7 @@ void DetectAppLayerInspectEngineRegisterSingle(const char *name, AppProto alprot } AppLayerInspectEngineRegisterInternal( - name, alproto, dir, progress, Callback, NULL, GetData, NULL); + name, alproto, dir, 0, (uint8_t)progress, Callback, NULL, GetData, NULL); } /* copy an inspect engine with transforms to a new list id. */ @@ -337,6 +363,7 @@ static void DetectAppLayerInspectEngineCopy( DEBUG_VALIDATE_BUG_ON(sm_list < 0 || sm_list > UINT16_MAX); new_engine->sm_list_base = (uint16_t)sm_list; new_engine->progress = t->progress; + new_engine->sub_state = t->sub_state; new_engine->v2 = t->v2; new_engine->v2.transforms = transforms; /* assign transforms */ @@ -370,6 +397,7 @@ static void DetectAppLayerInspectEngineCopyListToDetectCtx(DetectEngineCtx *de_c new_engine->sm_list = t->sm_list; new_engine->sm_list_base = t->sm_list; new_engine->progress = t->progress; + new_engine->sub_state = t->sub_state; new_engine->v2 = t->v2; if (list == NULL) { @@ -753,6 +781,7 @@ static void AppendAppInspectEngine(DetectEngineCtx *de_ctx, new_engine->smd = smd; new_engine->match_on_null = smd ? DetectContentInspectionMatchOnAbsentBuffer(smd) : false; new_engine->progress = t->progress; + new_engine->sub_state = t->sub_state; new_engine->v2 = t->v2; SCLogDebug("sm_list %d new_engine->v2 %p/%p/%p", new_engine->sm_list, new_engine->v2.Callback, new_engine->v2.GetData, new_engine->v2.transforms); @@ -903,6 +932,7 @@ int DetectEngineAppInspectionEngine2Signature(DetectEngineCtx *de_ctx, Signature DetectEngineAppInspectionEngine t = { .alproto = s->init_data->hook.t.app.alproto, .progress = state, + .sub_state = s->init_data->hook.t.app.sub_state, .sm_list = (uint16_t)sm_list, .sm_list_base = (uint16_t)sm_list, .dir = dir, @@ -985,6 +1015,7 @@ int DetectEngineAppInspectionEngine2Signature(DetectEngineCtx *de_ctx, Signature DetectEngineAppInspectionEngine t = { .alproto = s->init_data->hook.t.app.alproto, .progress = s->init_data->hook.t.app.app_progress, + .sub_state = s->init_data->hook.t.app.sub_state, .sm_list = (uint16_t)s->init_data->hook.sm_list, .sm_list_base = (uint16_t)s->init_data->hook.sm_list, .dir = dir, @@ -2202,12 +2233,23 @@ uint8_t DetectEngineInspectBufferGeneric(DetectEngineCtx *de_ctx, DetectEngineTh } } +// wrapper for both DetectAppLayerInspectEngineRegister and DetectAppLayerMpmRegister +// with cast of callback function +void DetectAppLayerMultiRegisterSubState(const char *name, AppProto alproto, uint32_t dir, + uint8_t sub_state, uint8_t progress, InspectionMultiBufferGetDataPtr GetData, int priority) +{ + AppLayerInspectEngineRegisterInternal(name, alproto, dir, sub_state, progress, + DetectEngineInspectMultiBufferGeneric, NULL, NULL, GetData); + DetectAppLayerMpmMultiRegisterSubState(name, dir, priority, PrefilterMultiGenericMpmRegister, + GetData, alproto, sub_state, progress); +} + // wrapper for both DetectAppLayerInspectEngineRegister and DetectAppLayerMpmRegister // with cast of callback function void DetectAppLayerMultiRegister(const char *name, AppProto alproto, uint32_t dir, uint8_t progress, InspectionMultiBufferGetDataPtr GetData, int priority) { - AppLayerInspectEngineRegisterInternal(name, alproto, dir, progress, + AppLayerInspectEngineRegisterInternal(name, alproto, dir, 0, (uint8_t)progress, DetectEngineInspectMultiBufferGeneric, NULL, NULL, GetData); DetectAppLayerMpmMultiRegister( name, dir, priority, PrefilterMultiGenericMpmRegister, GetData, alproto, progress); diff --git a/src/detect-engine.h b/src/detect-engine.h index 9e11dba0ba..12d95411d5 100644 --- a/src/detect-engine.h +++ b/src/detect-engine.h @@ -162,9 +162,20 @@ int DetectEngineInspectPktBufferGeneric( void DetectAppLayerInspectEngineRegister(const char *name, AppProto alproto, uint32_t dir, uint8_t progress, InspectEngineFuncPtr Callback2, InspectionBufferGetDataPtr GetData); +/** + * \brief register an app inspection engine for a tx type + * \param type the tx type + */ +void DetectAppLayerInspectEngineRegisterSubState(const char *name, AppProto alproto, uint32_t dir, + uint8_t type, uint8_t progress, InspectEngineFuncPtr Callback2, + InspectionBufferGetDataPtr GetData); + void DetectAppLayerInspectEngineRegisterSingle(const char *name, AppProto alproto, uint32_t dir, uint8_t progress, InspectEngineFuncPtr Callback2, InspectionSingleBufferGetDataPtr GetData); +void DetectAppLayerMultiRegisterSubState(const char *name, AppProto alproto, uint32_t dir, + uint8_t sub_state, uint8_t progress, InspectionMultiBufferGetDataPtr GetData, int priority); + void DetectAppLayerMultiRegister(const char *name, AppProto alproto, uint32_t dir, uint8_t progress, InspectionMultiBufferGetDataPtr GetData, int priority); diff --git a/src/detect.c b/src/detect.c index 410518742b..0d3688c224 100644 --- a/src/detect.c +++ b/src/detect.c @@ -1328,14 +1328,33 @@ static int DetectRunTxInspectRule(ThreadVars *tv, DetectEngineCtx *de_ctx, const DetectEngineAppInspectionEngine *engine = s->app_inspect; do { TRACE_SID_TXS(s->id, tx, "engine %p inspect_flags %x", engine, inspect_flags); + // also if it is not the same direction, but // this is a transactional signature, and we are toclient if (!(inspect_flags & BIT_U32(engine->id)) && (direction == engine->dir || ((s->flags & SIG_FLAG_TXBOTHDIR) && direction == 1))) { + if (engine->alproto != ALPROTO_UNKNOWN && // app-layer-events is registered for each + // proto this way + tx->tx_type != engine->sub_state) { + TRACE_SID_TXS(s->id, tx, + "skip because engine alproto %s sub_state %u != tx_type %u (engine " + "progress %u)", + AppProtoToString(engine->alproto), engine->sub_state, tx->tx_type, + engine->progress); + engine = engine->next; + continue; + } + TRACE_SID_TXS(s->id, tx, + "inspecting engine alproto %s sub_state %u == tx_type %u (engine progress %u)", + AppProtoToString(engine->alproto), engine->sub_state, tx->tx_type, + engine->progress); + void *tx_ptr = DetectGetInnerTx(tx->tx_ptr, f->alproto, engine->alproto, flow_flags); if (tx_ptr == NULL) { + TRACE_SID_TXS(s->id, tx, "no tx_ptr after DetectGetInnerTx"); if (engine->alproto != ALPROTO_UNKNOWN) { + TRACE_SID_TXS(s->id, tx, "no tx_ptr skip engine"); /* special case: file_data on 'alert tcp' will have engines * in the list that are not for us. */ engine = engine->next; @@ -1344,6 +1363,7 @@ static int DetectRunTxInspectRule(ThreadVars *tv, DetectEngineCtx *de_ctx, tx_ptr = tx->tx_ptr; } } + TRACE_SID_TXS(s->id, tx, "tx_ptr %p", tx_ptr); /* engines are sorted per progress, except that the one with * mpm/prefilter enabled is first */ @@ -1434,6 +1454,8 @@ static int DetectRunTxInspectRule(ThreadVars *tv, DetectEngineCtx *de_ctx, break; } else if (!(inspect_flags & BIT_U32(engine->id)) && s->flags & SIG_FLAG_TXBOTHDIR && direction != engine->dir) { + TRACE_SID_TXS(s->id, tx, "handle bidir engine"); + // for transactional rules, the engines on the opposite direction // are ordered by progress on the different side // so we have a two mixed-up lists, and we skip the elements @@ -1517,7 +1539,7 @@ static int DetectRunTxInspectRule(ThreadVars *tv, DetectEngineCtx *de_ctx, #define NO_TX \ { \ - NULL, 0, NULL, NULL, 0, 0, 0, 0, false, \ + NULL, 0, NULL, NULL, 0, 0, 0, 0, false, 0, \ } /** \internal @@ -1530,11 +1552,16 @@ static DetectTransaction GetDetectTx(const uint8_t ipproto, const AppProto alpro DEBUG_VALIDATE_BUG_ON(tx_end_state >= 48); AppLayerTxData *txd = AppLayerParserGetTxData(ipproto, alproto, tx_ptr); - const int tx_progress = AppLayerParserGetStateProgress(ipproto, alproto, tx_ptr, flow_flags); + const uint8_t tx_progress = + (uint8_t)AppLayerParserGetStateProgress(ipproto, alproto, tx_ptr, flow_flags); DEBUG_VALIDATE_BUG_ON(tx_progress >= 48); + const uint8_t e_tx_end_state = txd->tx_type == 0 ? (uint8_t)tx_end_state + : (flow_flags & STREAM_TOSERVER) ? txd->tx_type_eop_ts + : txd->tx_type_eop_tc; + bool updated = (flow_flags & STREAM_TOSERVER) ? txd->updated_ts : txd->updated_tc; - if (!updated && tx_progress < tx_end_state && ((flow_flags & STREAM_EOF) == 0)) { + if (!updated && tx_progress < e_tx_end_state && ((flow_flags & STREAM_EOF) == 0)) { DetectTransaction no_tx = NO_TX; return no_tx; } @@ -1555,6 +1582,10 @@ static DetectTransaction GetDetectTx(const uint8_t ipproto, const AppProto alpro return no_tx; } + if (txd->tx_type != 0) { + SCLogDebug("using tx_type %u", txd->tx_type); + } + const uint8_t detect_progress = (flow_flags & STREAM_TOSERVER) ? txd->detect_progress_ts : txd->detect_progress_tc; @@ -1570,8 +1601,9 @@ static DetectTransaction GetDetectTx(const uint8_t ipproto, const AppProto alpro .detect_progress = detect_progress, .detect_progress_orig = detect_progress, .tx_progress = (uint8_t)tx_progress, - .tx_end_state = (uint8_t)tx_end_state, + .tx_end_state = e_tx_end_state, .is_last = false, + .tx_type = txd->tx_type, }; return tx; } diff --git a/src/detect.h b/src/detect.h index 285d8ee65e..d0f4456701 100644 --- a/src/detect.h +++ b/src/detect.h @@ -424,6 +424,7 @@ typedef struct DetectEngineAppInspectionEngine_ { uint16_t sm_list; uint16_t sm_list_base; /**< base buffer being transformed */ uint8_t progress; + uint8_t sub_state; /**< matches tx type */ struct { union { @@ -578,6 +579,8 @@ typedef struct SignatureHook_ { union { struct { AppProto alproto; + /** sub state for a specific transaction type or 0 if not used */ + uint8_t sub_state; /** progress value of the app-layer hook specified in the rule. Sets the app_proto * specific progress value. */ uint8_t app_progress; @@ -796,6 +799,7 @@ typedef struct DetectBufferMpmRegistry_ { }; AppProto alproto; uint8_t tx_min_progress; + uint8_t sub_state; } app_v2; /* pkt matching: use if type == DETECT_BUFFER_MPM_TYPE_PKT */ @@ -1594,6 +1598,8 @@ typedef struct PrefilterEngineList_ { SignatureMask pkt_mask; /**< mask for pkt engines */ + uint8_t sub_state; + enum SignatureHookPkt pkt_hook; /** Context for matching. Might be MpmCtx for MPM engines, other ctx' @@ -1627,9 +1633,12 @@ typedef struct PrefilterEngine_ { SignatureMask mask; /**< mask for pkt engines */ uint8_t hook; /**< enum SignatureHookPkt */ } pkt; - /** Minimal Tx progress we need before running the engine. Only used - * with Tx Engine. Set to -1 for all states. */ - int8_t tx_min_progress; + struct { + /** Minimal Tx progress we need before running the engine. Only used + * with Tx Engine. Set to -1 for all states. */ + int8_t tx_min_progress; + uint8_t sub_state; + } app; uint8_t frame_type; } ctx;