mirror of
https://github.com/OISF/suricata.git
synced 2026-10-11 22:09:53 +00:00
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.
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
+26
-5
@@ -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(
|
||||
|
||||
@@ -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,
|
||||
|
||||
+123
-74
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
+51
-9
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
+36
-4
@@ -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;
|
||||
}
|
||||
|
||||
+12
-3
@@ -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;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user