detect/engine: support frames

Implement the low level detect engine support for inspecting frames,
including MPM, transforms and inspect API's.
pull/6809/head
Victor Julien 4 years ago
parent c0ec3984fa
commit f6f124f283

@ -139,6 +139,7 @@ noinst_HEADERS = \
detect-engine-enip.h \
detect-engine-event.h \
detect-engine-file.h \
detect-engine-frame.h \
detect-engine.h \
detect-engine-iponly.h \
detect-engine-loader.h \
@ -725,6 +726,7 @@ libsuricata_c_a_SOURCES = \
detect-engine-enip.c \
detect-engine-event.c \
detect-engine-file.c \
detect-engine-frame.c \
detect-engine-iponly.c \
detect-engine-loader.c \
detect-engine-mpm.c \

@ -1968,6 +1968,7 @@ int SigGroupBuild(DetectEngineCtx *de_ctx)
int r = DetectMpmPrepareBuiltinMpms(de_ctx);
r |= DetectMpmPrepareAppMpms(de_ctx);
r |= DetectMpmPreparePktMpms(de_ctx);
r |= DetectMpmPrepareFrameMpms(de_ctx);
if (r != 0) {
FatalError(SC_ERR_FATAL, "initializing the detection engine failed");
}

@ -1,4 +1,4 @@
/* Copyright (C) 2007-2011 Open Information Security Foundation
/* Copyright (C) 2007-2021 Open Information Security Foundation
*
* You can copy, redistribute or modify this Program under the terms of
* the GNU General Public License version 2 as published by the Free
@ -29,9 +29,10 @@
* we're inspecting
*/
enum {
DETECT_ENGINE_CONTENT_INSPECTION_MODE_PAYLOAD = 0, /* enables 'replace' logic */
DETECT_ENGINE_CONTENT_INSPECTION_MODE_PAYLOAD = 0, /* enables 'replace' logic */
DETECT_ENGINE_CONTENT_INSPECTION_MODE_HEADER,
DETECT_ENGINE_CONTENT_INSPECTION_MODE_STREAM,
DETECT_ENGINE_CONTENT_INSPECTION_MODE_FRAME,
DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE,
};

@ -0,0 +1,357 @@
/* Copyright (C) 2021 Open Information Security Foundation
*
* You can copy, redistribute or modify this Program under the terms of
* the GNU General Public License version 2 as published by the Free
* Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* version 2 along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
/**
* \file
*
* \author Victor Julien <victor@inliniac.net>
*
*/
#include "suricata-common.h"
#include "suricata.h"
#include "app-layer-parser.h"
#include "app-layer-frames.h"
#include "detect-engine.h"
#include "detect-engine-prefilter.h"
#include "detect-engine-content-inspection.h"
#include "detect-engine-mpm.h"
#include "detect-engine-frame.h"
#include "stream-tcp.h"
#include "util-profiling.h"
#include "util-validate.h"
#include "util-print.h"
void DetectRunPrefilterFrame(DetectEngineThreadCtx *det_ctx, const SigGroupHead *sgh, Packet *p,
const Frames *frames, const Frame *frame, const AppProto alproto, const uint32_t idx)
{
SCLogDebug("pcap_cnt %" PRIu64, p->pcap_cnt);
PrefilterEngine *engine = sgh->frame_engines;
do {
BUG_ON(engine->alproto == ALPROTO_UNKNOWN);
if (engine->alproto == alproto && engine->ctx.frame_type == frame->type) {
SCLogDebug("frame %p engine %p", frame, engine);
PREFILTER_PROFILING_START;
engine->cb.PrefilterFrame(det_ctx, engine->pectx, p, frames, frame, idx);
PREFILTER_PROFILING_END(det_ctx, engine->gid);
}
if (engine->is_last)
break;
engine++;
} while (1);
}
/* generic mpm for frame engines */
// TODO same as Generic?
typedef struct PrefilterMpmFrameCtx {
int list_id;
const MpmCtx *mpm_ctx;
const DetectEngineTransforms *transforms;
} PrefilterMpmFrameCtx;
/** \brief Generic Mpm prefilter callback
*
* \param det_ctx detection engine thread ctx
* \param frames container for the frames
* \param frame frame to inspect
* \param pectx inspection context
*/
static void PrefilterMpmFrame(DetectEngineThreadCtx *det_ctx, const void *pectx, Packet *p,
const Frames *frames, const Frame *frame, const uint32_t idx)
{
SCEnter();
const PrefilterMpmFrameCtx *ctx = (const PrefilterMpmFrameCtx *)pectx;
const MpmCtx *mpm_ctx = ctx->mpm_ctx;
SCLogDebug("running on list %d -> frame field type %u", ctx->list_id, frame->type);
// BUG_ON(frame->type != ctx->type);
InspectionBuffer *buffer = DetectFrame2InspectBuffer(
det_ctx, ctx->transforms, p, frames, frame, ctx->list_id, idx, true);
if (buffer == NULL)
return;
const uint32_t data_len = buffer->inspect_len;
const uint8_t *data = buffer->inspect;
SCLogDebug("mpm'ing buffer:");
// SCLogDebug("frame: %p", frame);
// PrintRawDataFp(stdout, data, MIN(32, data_len));
if (data != NULL && data_len >= mpm_ctx->minlen) {
(void)mpm_table[mpm_ctx->mpm_type].Search(
mpm_ctx, &det_ctx->mtcu, &det_ctx->pmq, data, data_len);
SCLogDebug("det_ctx->pmq.rule_id_array_cnt %u", det_ctx->pmq.rule_id_array_cnt);
}
}
static void PrefilterMpmFrameFree(void *ptr)
{
SCFree(ptr);
}
int PrefilterGenericMpmFrameRegister(DetectEngineCtx *de_ctx, SigGroupHead *sgh, MpmCtx *mpm_ctx,
const DetectBufferMpmRegistery *mpm_reg, int list_id)
{
SCEnter();
PrefilterMpmFrameCtx *pectx = SCCalloc(1, sizeof(*pectx));
if (pectx == NULL)
return -1;
pectx->list_id = list_id;
BUG_ON(mpm_reg->frame_v1.alproto == ALPROTO_UNKNOWN);
pectx->mpm_ctx = mpm_ctx;
pectx->transforms = &mpm_reg->transforms;
int r = PrefilterAppendFrameEngine(de_ctx, sgh, PrefilterMpmFrame, mpm_reg->frame_v1.alproto,
mpm_reg->frame_v1.type, pectx, PrefilterMpmFrameFree, mpm_reg->pname);
if (r != 0) {
SCFree(pectx);
}
return r;
}
int DetectRunFrameInspectRule(ThreadVars *tv, DetectEngineThreadCtx *det_ctx, const Signature *s,
Flow *f, Packet *p, const Frames *frames, const Frame *frame, const uint32_t idx)
{
BUG_ON(s->frame_inspect == NULL);
SCLogDebug("inspecting rule %u against frame %p/%" PRIi64 "/%s", s->id, frame, frame->id,
AppLayerParserGetFrameNameById(f->proto, f->alproto, frame->type));
for (DetectEngineFrameInspectionEngine *e = s->frame_inspect; e != NULL; e = e->next) {
if (frame->type == e->type) {
// TODO check alproto, direction?
// TODO there should be only one inspect engine for this frame, ever?
if (e->v1.Callback(det_ctx, e, s, p, frames, frame, idx) == true) {
SCLogDebug("sid %u: e %p Callback returned true", s->id, e);
return true;
}
SCLogDebug("sid %u: e %p Callback returned false", s->id, e);
} else {
SCLogDebug(
"sid %u: e %p not for frame type %u (want %u)", s->id, e, frame->type, e->type);
}
}
return false;
}
InspectionBuffer *DetectFrame2InspectBuffer(DetectEngineThreadCtx *det_ctx,
const DetectEngineTransforms *transforms, Packet *p, const Frames *frames,
const Frame *frame, const int list_id, const uint32_t idx, const bool first)
{
// TODO do we really need multiple buffer support here?
InspectionBuffer *buffer = InspectionBufferMultipleForListGet(det_ctx, list_id, idx);
if (buffer == NULL)
return NULL;
if (!first && buffer->inspect != NULL)
return buffer;
BUG_ON(p->flow == NULL);
BUG_ON(p->flow->protoctx == NULL);
TcpSession *ssn = p->flow->protoctx;
TcpStream *stream;
if (PKT_IS_TOSERVER(p)) {
stream = &ssn->client;
} else {
stream = &ssn->server;
}
/*
stream: [s ]
frame: [r ]
progress: |>p
rel_offset: 10, len 100
progress: 20
avail: 90 (complete)
stream: [s ]
frame: [r ]
progress: |>p
stream: 0, len 59
rel_offset: 10, len 100
progress: 20
avail: 30 (incomplete)
stream: [s ]
frame: [r ]
progress: |>p
stream: 0, len 200
rel_offset: -30, len 100
progress: 20
avail: 50 (complete)
*/
SCLogDebug("frame %" PRIi64 ", len %" PRIi64, frame->id, frame->len);
uint32_t data_len = 0;
const uint8_t *data = NULL;
uint64_t offset = STREAM_BASE_OFFSET(stream);
if (frame->rel_offset > 0 || frames->progress_rel) {
uint64_t frame_offset = 0;
if (frame->rel_offset >= 0) {
frame_offset = MAX((uint64_t)frame->rel_offset, (uint64_t)frames->progress_rel);
} else {
frame_offset = (uint64_t)frames->progress_rel;
}
offset += frame_offset;
}
const bool eof = ssn->state == TCP_CLOSED || PKT_IS_PSEUDOPKT(p);
const uint64_t usable = StreamTcpGetUsable(stream, eof);
if (usable <= offset)
return NULL;
// TODO GAP handling
if (StreamingBufferGetDataAtOffset(&stream->sb, &data, &data_len, offset) == 0) {
return NULL;
}
const uint64_t data_right_edge = offset + data_len;
if (data_right_edge > usable)
data_len = usable - offset;
const int64_t frame_start_abs_offset = frame->rel_offset + (int64_t)STREAM_BASE_OFFSET(stream);
const uint64_t usable_right_edge = MIN(data_right_edge, usable);
bool have_end = false;
if (frame->len > 0) {
const int64_t frame_avail_data_abs = (int64_t)usable_right_edge;
const int64_t frame_end_abs_offset = frame_start_abs_offset + frame->len;
have_end = (int64_t)usable_right_edge >= frame_end_abs_offset;
SCLogDebug("frame_end_abs_offset %" PRIi64 ", usable_right_edge %" PRIu64,
frame_end_abs_offset, usable_right_edge);
const int64_t avail_from_frame = MIN(frame_end_abs_offset, frame_avail_data_abs) - offset;
if (avail_from_frame < (int64_t)data_len) {
SCLogDebug("adjusted data len from %u to %" PRIi64, data_len, avail_from_frame);
data_len = (uint32_t)avail_from_frame;
}
}
const bool have_start = frame_start_abs_offset == (int64_t)offset;
if (data == NULL || data_len == 0) {
return NULL;
}
// TODO use eof too?
SCLogDebug("stream->min_inspect_depth %u", stream->min_inspect_depth);
if (data_len < frame->len && data_len < stream->min_inspect_depth) {
if (ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || ssn->state == TCP_CLOSED ||
stream->flags & STREAMTCP_STREAM_FLAG_DEPTH_REACHED) {
SCLogDebug("EOF use available data: %u bytes", data_len);
} else {
SCLogDebug("not enough data to inspect now: have %u, want %u", data_len,
stream->min_inspect_depth);
return NULL;
}
}
const uint8_t ci_flags =
(have_start ? DETECT_CI_FLAGS_START : 0) | (have_end ? DETECT_CI_FLAGS_END : 0);
SCLogDebug("packet %" PRIu64 " -> frame %p/%" PRIi64 "/%s rel_offset %" PRIi64
" type %u len %" PRIi64 " ci_flags %02x (start:%s, end:%s)",
p->pcap_cnt, frame, frame->id,
AppLayerParserGetFrameNameById(p->flow->proto, p->flow->alproto, frame->type),
frame->rel_offset, frame->type, frame->len, ci_flags,
(ci_flags & DETECT_CI_FLAGS_START) ? "true" : "false",
(ci_flags & DETECT_CI_FLAGS_END) ? "true" : "false");
// PrintRawDataFp(stdout, data, MIN(32,data_len));
InspectionBufferSetupMulti(buffer, transforms, data, data_len);
buffer->inspect_offset = frame->rel_offset < 0 ? -1 * frame->rel_offset : 0; // TODO review/test
buffer->flags = ci_flags;
return buffer;
}
/**
* \brief Do the content inspection & validation for a signature
*
* \param de_ctx Detection engine context
* \param det_ctx Detection engine thread context
* \param s Signature to inspect
* \param p Packet
* \param frame stream frame to inspect
*
* \retval 0 no match.
* \retval 1 match.
*/
int DetectEngineInspectFrameBufferGeneric(DetectEngineThreadCtx *det_ctx,
const DetectEngineFrameInspectionEngine *engine, const Signature *s, Packet *p,
const Frames *frames, const Frame *frame, const uint32_t idx)
{
const int list_id = engine->sm_list;
SCLogDebug("running inspect on %d", list_id);
SCLogDebug("list %d transforms %p", engine->sm_list, engine->v1.transforms);
/* if prefilter didn't already run, we need to consider transformations */
const DetectEngineTransforms *transforms = NULL;
if (!engine->mpm) {
transforms = engine->v1.transforms;
}
const InspectionBuffer *buffer =
DetectFrame2InspectBuffer(det_ctx, transforms, p, frames, frame, list_id, idx, false);
if (unlikely(buffer == NULL)) {
return DETECT_ENGINE_INSPECT_SIG_NO_MATCH;
}
const uint32_t data_len = buffer->inspect_len;
const uint8_t *data = buffer->inspect;
const uint64_t offset = buffer->inspect_offset;
det_ctx->discontinue_matching = 0;
det_ctx->buffer_offset = 0;
det_ctx->inspection_recursion_counter = 0;
#ifdef DEBUG
const uint8_t ci_flags = buffer->flags;
SCLogDebug("frame %p rel_offset %" PRIi64 " type %u len %" PRIi64
" ci_flags %02x (start:%s, end:%s)",
frame, frame->rel_offset, frame->type, frame->len, ci_flags,
(ci_flags & DETECT_CI_FLAGS_START) ? "true" : "false",
(ci_flags & DETECT_CI_FLAGS_END) ? "true" : "false");
SCLogDebug("buffer %p offset %" PRIu64 " len %u ci_flags %02x (start:%s, end:%s)", buffer,
buffer->inspect_offset, buffer->inspect_len, ci_flags,
(ci_flags & DETECT_CI_FLAGS_START) ? "true" : "false",
(ci_flags & DETECT_CI_FLAGS_END) ? "true" : "false");
// PrintRawDataFp(stdout, data, data_len);
// PrintRawDataFp(stdout, data, MIN(64, data_len));
#endif
BUG_ON((int64_t)data_len > frame->len);
// TODO don't call if matching needs frame end and DETECT_CI_FLAGS_END not set
// TODO same for start
int r = DetectEngineContentInspection(det_ctx->de_ctx, det_ctx, s, engine->smd, p, p->flow,
(uint8_t *)data, data_len, offset, buffer->flags,
DETECT_ENGINE_CONTENT_INSPECTION_MODE_FRAME);
if (r == 1) {
return DETECT_ENGINE_INSPECT_SIG_MATCH;
} else {
return DETECT_ENGINE_INSPECT_SIG_NO_MATCH;
}
}

@ -0,0 +1,39 @@
/* Copyright (C) 2021 Open Information Security Foundation
*
* You can copy, redistribute or modify this Program under the terms of
* the GNU General Public License version 2 as published by the Free
* Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* version 2 along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
/**
* \file
*
* \author Victor Julien <victor@inliniac.net>
*
*/
#include "app-layer-frames.h"
void DetectRunPrefilterFrame(DetectEngineThreadCtx *det_ctx, const SigGroupHead *sgh, Packet *p,
const Frames *frames, const Frame *frame, const AppProto alproto, const uint32_t idx);
int DetectRunFrameInspectRule(ThreadVars *tv, DetectEngineThreadCtx *det_ctx, const Signature *s,
Flow *f, Packet *p, const Frames *frames, const Frame *frame, const uint32_t idx);
int PrefilterGenericMpmFrameRegister(DetectEngineCtx *de_ctx, SigGroupHead *sgh, MpmCtx *mpm_ctx,
const DetectBufferMpmRegistery *mpm_reg, int list_id);
InspectionBuffer *DetectFrame2InspectBuffer(DetectEngineThreadCtx *det_ctx,
const DetectEngineTransforms *transforms, Packet *p, const Frames *frames,
const Frame *frame, const int list_id, const uint32_t idx, const bool first);
int DetectEngineInspectFrameBufferGeneric(DetectEngineThreadCtx *det_ctx,
const DetectEngineFrameInspectionEngine *engine, const Signature *s, Packet *p,
const Frames *frames, const Frame *frame, const uint32_t idx);

@ -1,4 +1,4 @@
/* Copyright (C) 2007-2014 Open Information Security Foundation
/* Copyright (C) 2007-2021 Open Information Security Foundation
*
* You can copy, redistribute or modify this Program under the terms of
* the GNU General Public License version 2 as published by the Free
@ -79,8 +79,8 @@ const char *builtin_mpms[] = {
* Keywords are registered at engine start up
*/
static DetectBufferMpmRegistery *g_mpm_list[DETECT_BUFFER_MPM_TYPE_SIZE] = { NULL, NULL };
static int g_mpm_list_cnt[DETECT_BUFFER_MPM_TYPE_SIZE] = { 0, 0 };
static DetectBufferMpmRegistery *g_mpm_list[DETECT_BUFFER_MPM_TYPE_SIZE] = { NULL, NULL, NULL };
static int g_mpm_list_cnt[DETECT_BUFFER_MPM_TYPE_SIZE] = { 0, 0, 0 };
/** \brief register a MPM engine
*
@ -287,6 +287,237 @@ int DetectMpmPrepareAppMpms(DetectEngineCtx *de_ctx)
return r;
}
/** \brief register a MPM engine
*
* \note to be used at start up / registration only. Errors are fatal.
*/
void DetectFrameMpmRegister(const char *name, int direction, int priority,
int (*PrefilterRegister)(DetectEngineCtx *de_ctx, SigGroupHead *sgh, MpmCtx *mpm_ctx,
const DetectBufferMpmRegistery *mpm_reg, int list_id),
AppProto alproto, uint8_t type)
{
SCLogDebug("registering %s/%d/%p/%s/%u", name, priority, PrefilterRegister,
AppProtoToString(alproto), type);
DetectBufferTypeSupportsMpm(name);
DetectBufferTypeSupportsFrames(name);
DetectBufferTypeSupportsTransformations(name);
int sm_list = DetectBufferTypeGetByName(name);
if (sm_list == -1) {
FatalError(SC_ERR_INITIALIZATION, "MPM engine registration for %s failed", name);
}
DetectBufferMpmRegistery *am = SCCalloc(1, sizeof(*am));
BUG_ON(am == NULL);
am->name = name;
snprintf(am->pname, sizeof(am->pname), "%s", am->name);
am->sm_list = sm_list;
am->direction = direction;
am->priority = priority;
am->type = DETECT_BUFFER_MPM_TYPE_FRAME;
am->PrefilterRegisterWithListId = PrefilterRegister;
am->frame_v1.alproto = alproto;
am->frame_v1.type = type;
SCLogDebug("type %u", type);
SCLogDebug("am type %u", am->frame_v1.type);
if (g_mpm_list[DETECT_BUFFER_MPM_TYPE_FRAME] == NULL) {
g_mpm_list[DETECT_BUFFER_MPM_TYPE_FRAME] = am;
} else {
DetectBufferMpmRegistery *t = g_mpm_list[DETECT_BUFFER_MPM_TYPE_FRAME];
while (t->next != NULL) {
t = t->next;
}
t->next = am;
am->id = t->id + 1;
}
g_mpm_list_cnt[DETECT_BUFFER_MPM_TYPE_FRAME]++;
SupportFastPatternForSigMatchList(sm_list, priority);
SCLogDebug("%s/%d done", name, sm_list);
}
/** \brief copy a mpm engine from parent_id, add in transforms */
void DetectFrameMpmRegisterByParentId(DetectEngineCtx *de_ctx, const int id, const int parent_id,
DetectEngineTransforms *transforms)
{
SCLogDebug("registering %d/%d", id, parent_id);
DetectBufferMpmRegistery *t = de_ctx->frame_mpms_list;
while (t) {
if (t->sm_list == parent_id) {
DetectBufferMpmRegistery *am = SCCalloc(1, sizeof(*am));
BUG_ON(am == NULL);
am->name = t->name;
snprintf(am->pname, sizeof(am->pname), "%s#%d", am->name, id);
am->sm_list = id; // use new id
am->sm_list_base = t->sm_list;
am->type = DETECT_BUFFER_MPM_TYPE_FRAME;
am->PrefilterRegisterWithListId = t->PrefilterRegisterWithListId;
am->frame_v1 = t->frame_v1;
SCLogDebug("am type %u", am->frame_v1.type);
am->priority = t->priority;
am->direction = t->direction;
am->sgh_mpm_context = t->sgh_mpm_context;
am->next = t->next;
if (transforms) {
memcpy(&am->transforms, transforms, sizeof(*transforms));
}
am->id = de_ctx->frame_mpms_list_cnt++;
DetectEngineRegisterFastPatternForId(de_ctx, am->sm_list, am->priority);
t->next = am;
SCLogDebug("copied mpm registration for %s id %u "
"with parent %u",
t->name, id, parent_id);
t = am;
}
t = t->next;
}
}
void DetectEngineFrameMpmRegister(DetectEngineCtx *de_ctx, const char *name, int direction,
int priority,
int (*PrefilterRegister)(DetectEngineCtx *de_ctx, SigGroupHead *sgh, MpmCtx *mpm_ctx,
const DetectBufferMpmRegistery *mpm_reg, int list_id),
AppProto alproto, uint8_t type)
{
SCLogDebug("registering %s/%d/%p/%s/%u", name, priority, PrefilterRegister,
AppProtoToString(alproto), type);
const int sm_list = DetectEngineBufferTypeRegister(de_ctx, name);
if (sm_list < 0) {
FatalError(SC_ERR_INITIALIZATION, "MPM engine registration for %s failed", name);
}
DetectEngineBufferTypeSupportsMpm(de_ctx, name);
DetectEngineBufferTypeSupportsFrames(de_ctx, name);
DetectEngineBufferTypeSupportsTransformations(de_ctx, name);
DetectBufferMpmRegistery *am = SCCalloc(1, sizeof(*am));
BUG_ON(am == NULL);
am->name = name;
snprintf(am->pname, sizeof(am->pname), "%s", am->name);
am->sm_list = sm_list;
am->direction = direction;
am->priority = priority;
am->type = DETECT_BUFFER_MPM_TYPE_FRAME;
am->PrefilterRegisterWithListId = PrefilterRegister;
am->frame_v1.alproto = alproto;
am->frame_v1.type = type;
// TODO is it ok to do this here?
/* default to whatever the global setting is */
int shared = (de_ctx->sgh_mpm_ctx_cnf == ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE);
/* see if we use a unique or shared mpm ctx for this type */
int confshared = 0;
if (ConfGetBool("detect.mpm.frame.shared", &confshared) == 1)
shared = confshared;
if (shared == 0) {
am->sgh_mpm_context = MPM_CTX_FACTORY_UNIQUE_CONTEXT;
} else {
am->sgh_mpm_context = MpmFactoryRegisterMpmCtxProfile(de_ctx, am->name, am->sm_list);
}
if (de_ctx->frame_mpms_list == NULL) {
de_ctx->frame_mpms_list = am;
} else {
DetectBufferMpmRegistery *t = de_ctx->frame_mpms_list;
while (t->next != NULL) {
t = t->next;
}
t->next = am;
}
de_ctx->frame_mpms_list_cnt++;
DetectEngineRegisterFastPatternForId(de_ctx, sm_list, priority);
SCLogDebug("%s/%d done", name, sm_list);
}
void DetectMpmInitializeFrameMpms(DetectEngineCtx *de_ctx)
{
const DetectBufferMpmRegistery *list = g_mpm_list[DETECT_BUFFER_MPM_TYPE_FRAME];
while (list != NULL) {
DetectBufferMpmRegistery *n = SCCalloc(1, sizeof(*n));
BUG_ON(n == NULL);
*n = *list;
n->next = NULL;
if (de_ctx->frame_mpms_list == NULL) {
de_ctx->frame_mpms_list = n;
} else {
DetectBufferMpmRegistery *t = de_ctx->frame_mpms_list;
while (t->next != NULL) {
t = t->next;
}
t->next = n;
}
/* default to whatever the global setting is */
int shared = (de_ctx->sgh_mpm_ctx_cnf == ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE);
/* see if we use a unique or shared mpm ctx for this type */
int confshared = 0;
char confstring[256] = "detect.mpm.";
strlcat(confstring, n->name, sizeof(confstring));
strlcat(confstring, ".shared", sizeof(confstring));
if (ConfGetBool(confstring, &confshared) == 1)
shared = confshared;
if (shared == 0) {
if (!(de_ctx->flags & DE_QUIET)) {
SCLogPerf("using unique mpm ctx' for %s", n->name);
}
n->sgh_mpm_context = MPM_CTX_FACTORY_UNIQUE_CONTEXT;
} else {
if (!(de_ctx->flags & DE_QUIET)) {
SCLogPerf("using shared mpm ctx' for %s", n->name);
}
n->sgh_mpm_context = MpmFactoryRegisterMpmCtxProfile(de_ctx, n->name, n->sm_list);
}
list = list->next;
}
de_ctx->frame_mpms_list_cnt = g_mpm_list_cnt[DETECT_BUFFER_MPM_TYPE_FRAME];
SCLogDebug("mpm: de_ctx frame_mpms_list %p %u", de_ctx->frame_mpms_list,
de_ctx->frame_mpms_list_cnt);
}
/**
* \brief initialize mpm contexts for applayer buffers that are in
* "single or "shared" mode.
*/
int DetectMpmPrepareFrameMpms(DetectEngineCtx *de_ctx)
{
SCLogDebug("preparing frame mpm");
int r = 0;
const DetectBufferMpmRegistery *am = de_ctx->frame_mpms_list;
while (am != NULL) {
SCLogDebug("am %p %s sgh_mpm_context %d", am, am->name, am->sgh_mpm_context);
SCLogDebug("%s", am->name);
if (am->sgh_mpm_context != MPM_CTX_FACTORY_UNIQUE_CONTEXT) {
int dir = (am->direction == SIG_FLAG_TOSERVER) ? 1 : 0;
MpmCtx *mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, am->sgh_mpm_context, dir);
SCLogDebug("%s: %d mpm_Ctx %p", am->name, r, mpm_ctx);
if (mpm_ctx != NULL) {
if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) {
r |= mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx);
SCLogDebug("%s: %d", am->name, r);
}
}
}
am = am->next;
}
return r;
}
/** \brief register a MPM engine
*
* \note to be used at start up / registration only. Errors are fatal.
@ -1119,6 +1350,9 @@ void MpmStoreReportStats(const DetectEngineCtx *de_ctx)
int pkt_mpms_cnt = de_ctx->buffer_type_id;
uint32_t pktstats[pkt_mpms_cnt + 1]; // +1 to silence scan-build
memset(&pktstats, 0x00, sizeof(pktstats));
int frame_mpms_cnt = de_ctx->buffer_type_id;
uint32_t framestats[frame_mpms_cnt + 1]; // +1 to silence scan-build
memset(&framestats, 0x00, sizeof(framestats));
for (htb = HashListTableGetListHead(de_ctx->mpm_hash_table);
htb != NULL;
@ -1151,6 +1385,12 @@ void MpmStoreReportStats(const DetectEngineCtx *de_ctx)
ms->mpm_ctx);
appstats[am->sm_list]++;
break;
case DETECT_BUFFER_MPM_TYPE_FRAME:
SCLogDebug("%s: %u patterns. Min %u, Max %u. Ctx %p", am->name,
ms->mpm_ctx->pattern_cnt, ms->mpm_ctx->minlen, ms->mpm_ctx->maxlen,
ms->mpm_ctx);
framestats[am->sm_list]++;
break;
case DETECT_BUFFER_MPM_TYPE_SIZE:
break;
}
@ -1180,6 +1420,14 @@ void MpmStoreReportStats(const DetectEngineCtx *de_ctx)
}
pm = pm->next;
}
const DetectBufferMpmRegistery *um = de_ctx->frame_mpms_list;
while (um != NULL) {
if (framestats[um->sm_list] > 0) {
const char *name = um->name;
SCLogPerf("Frame MPM \"%s\": %u", name, framestats[um->sm_list]);
}
um = um->next;
}
}
}
@ -1235,8 +1483,9 @@ static void MpmStoreSetup(const DetectEngineCtx *de_ctx, MpmStore *ms)
}
ms->mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, ms->sgh_mpm_context, dir);
if (ms->mpm_ctx == NULL)
if (ms->mpm_ctx == NULL) {
return;
}
MpmInitCtx(ms->mpm_ctx, de_ctx->mpm_matcher);
@ -1246,8 +1495,10 @@ static void MpmStoreSetup(const DetectEngineCtx *de_ctx, MpmStore *ms)
s = de_ctx->sig_array[sig];
if (s == NULL)
continue;
if ((s->flags & ms->direction) == 0)
if ((s->flags & ms->direction) == 0) {
SCLogDebug("s->flags %x ms->direction %x", s->flags, ms->direction);
continue;
}
if (s->init_data->mpm_sm == NULL)
continue;
int list = SigMatchListSMBelongsTo(s, s->init_data->mpm_sm);
@ -1578,6 +1829,77 @@ static MpmStore *MpmStorePrepareBufferPkt(DetectEngineCtx *de_ctx,
return NULL;
}
static MpmStore *MpmStorePrepareBufferFrame(
DetectEngineCtx *de_ctx, SigGroupHead *sgh, const DetectBufferMpmRegistery *am)
{
const Signature *s = NULL;
uint32_t sig;
uint32_t cnt = 0;
uint32_t max_sid = DetectEngineGetMaxSigId(de_ctx) / 8 + 1;
uint8_t sids_array[max_sid];
memset(sids_array, 0x00, max_sid);
SCLogDebug("handling %s for list %d", am->name, am->sm_list);
for (sig = 0; sig < sgh->init->sig_cnt; sig++) {
s = sgh->init->match_array[sig];
if (s == NULL)
continue;
if (s->init_data->mpm_sm == NULL)
continue;
if ((s->flags & am->direction) == 0)
continue;
int list = SigMatchListSMBelongsTo(s, s->init_data->mpm_sm);
if (list < 0)
continue;
if (list != am->sm_list)
continue;
sids_array[s->num / 8] |= 1 << (s->num % 8);
cnt++;
}
if (cnt == 0)
return NULL;
MpmStore lookup = { sids_array, max_sid, am->direction, MPMB_MAX, am->sm_list, 0, NULL };
SCLogDebug("am->sm_list %d", am->sm_list);
MpmStore *result = MpmStoreLookup(de_ctx, &lookup);
if (result == NULL) {
SCLogDebug("new unique mpm for %s: %u patterns", am->name, cnt);
MpmStore *copy = SCCalloc(1, sizeof(MpmStore));
if (copy == NULL)
return NULL;
uint8_t *sids = SCCalloc(1, max_sid);
if (sids == NULL) {
SCFree(copy);
return NULL;
}
memcpy(sids, sids_array, max_sid);
copy->sid_array = sids;
copy->sid_array_size = max_sid;
copy->buffer = MPMB_MAX;
copy->direction = am->direction;
copy->sm_list = am->sm_list;
copy->sgh_mpm_context = am->sgh_mpm_context;
MpmStoreSetup(de_ctx, copy);
MpmStoreAdd(de_ctx, copy);
return copy;
} else {
SCLogDebug("using existing mpm %p", result);
return result;
}
return NULL;
}
static void SetRawReassemblyFlag(DetectEngineCtx *de_ctx, SigGroupHead *sgh)
{
const Signature *s = NULL;
@ -1663,6 +1985,39 @@ static void PreparePktMpms(DetectEngineCtx *de_ctx, SigGroupHead *sh)
}
}
static void PrepareFrameMpms(DetectEngineCtx *de_ctx, SigGroupHead *sh)
{
if (de_ctx->frame_mpms_list_cnt == 0)
return;
sh->init->frame_mpms = SCCalloc(de_ctx->frame_mpms_list_cnt, sizeof(MpmCtx *));
BUG_ON(sh->init->frame_mpms == NULL);
DetectBufferMpmRegistery *a = de_ctx->frame_mpms_list;
while (a != NULL) {
SCLogDebug("a %s direction %d PrefilterRegisterWithListId %p", a->name, a->direction,
a->PrefilterRegisterWithListId);
MpmStore *mpm_store = MpmStorePrepareBufferFrame(de_ctx, sh, a);
if (mpm_store != NULL) {
sh->init->frame_mpms[a->id] = mpm_store->mpm_ctx;
SCLogDebug("a %p a->name %s a->reg->PrefilterRegisterWithListId %p "
"mpm_store->mpm_ctx %p",
a, a->name, a->PrefilterRegisterWithListId, mpm_store->mpm_ctx);
/* if we have just certain types of negated patterns,
* mpm_ctx can be NULL */
SCLogDebug("mpm_store %p mpm_ctx %p", mpm_store, mpm_store->mpm_ctx);
if (a->PrefilterRegisterWithListId && mpm_store->mpm_ctx) {
BUG_ON(a->PrefilterRegisterWithListId(
de_ctx, sh, mpm_store->mpm_ctx, a, a->sm_list) != 0);
SCLogDebug("mpm %s %d set up", a->name, a->sm_list);
}
}
a = a->next;
}
}
/** \brief Prepare the pattern matcher ctx in a sig group head.
*
*/
@ -1718,6 +2073,7 @@ int PatternMatchPrepareGroup(DetectEngineCtx *de_ctx, SigGroupHead *sh)
PrepareAppMpms(de_ctx, sh);
PreparePktMpms(de_ctx, sh);
PrepareFrameMpms(de_ctx, sh);
return 0;
}

@ -32,6 +32,8 @@
#include "stream.h"
void DetectMpmInitializeFrameMpms(DetectEngineCtx *de_ctx);
int DetectMpmPrepareFrameMpms(DetectEngineCtx *de_ctx);
void DetectMpmInitializePktMpms(DetectEngineCtx *de_ctx);
int DetectMpmPreparePktMpms(DetectEngineCtx *de_ctx);
void DetectMpmInitializeAppMpms(DetectEngineCtx *de_ctx);
@ -112,11 +114,24 @@ void DetectPktMpmRegisterByParentId(DetectEngineCtx *de_ctx,
const int id, const int parent_id,
DetectEngineTransforms *transforms);
void DetectFrameMpmRegister(const char *name, int direction, int priority,
int (*PrefilterRegister)(DetectEngineCtx *de_ctx, SigGroupHead *sgh, MpmCtx *mpm_ctx,
const DetectBufferMpmRegistery *mpm_reg, int list_id),
AppProto alproto, uint8_t type);
void DetectFrameMpmRegisterByParentId(DetectEngineCtx *de_ctx, const int id, const int parent_id,
DetectEngineTransforms *transforms);
void DetectEngineFrameMpmRegister(DetectEngineCtx *de_ctx, const char *name, int direction,
int priority,
int (*PrefilterRegister)(DetectEngineCtx *de_ctx, SigGroupHead *sgh, MpmCtx *mpm_ctx,
const DetectBufferMpmRegistery *mpm_reg, int list_id),
AppProto alproto, uint8_t type);
int PrefilterGenericMpmPktRegister(DetectEngineCtx *de_ctx,
SigGroupHead *sgh, MpmCtx *mpm_ctx,
const DetectBufferMpmRegistery *mpm_reg, int list_id);
int PrefilterGenericMpmFrameRegister(DetectEngineCtx *de_ctx, SigGroupHead *sgh, MpmCtx *mpm_ctx,
const DetectBufferMpmRegistery *mpm_reg, int list_id);
typedef struct PrefilterMpmListId {
int list_id;

@ -1,4 +1,4 @@
/* Copyright (C) 2016 Open Information Security Foundation
/* Copyright (C) 2016-2021 Open Information Security Foundation
*
* You can copy, redistribute or modify this Program under the terms of
* the GNU General Public License version 2 as published by the Free
@ -47,8 +47,10 @@
#include "suricata-common.h"
#include "suricata.h"
#include "detect-engine.h"
#include "detect-engine-prefilter.h"
#include "detect-engine-mpm.h"
#include "detect-engine-frame.h"
#include "app-layer-parser.h"
#include "app-layer-htp.h"
@ -107,10 +109,10 @@ void DetectRunPrefilterTx(DetectEngineThreadCtx *det_ctx,
do {
if (engine->alproto != alproto)
goto next;
if (engine->tx_min_progress > tx->tx_progress)
if (engine->ctx.tx_min_progress > tx->tx_progress)
break;
if (tx->tx_progress > engine->tx_min_progress) {
if (tx->prefilter_flags & BIT_U64(engine->tx_min_progress)) {
if (tx->tx_progress > engine->ctx.tx_min_progress) {
if (tx->prefilter_flags & BIT_U64(engine->ctx.tx_min_progress)) {
goto next;
}
}
@ -120,8 +122,8 @@ void DetectRunPrefilterTx(DetectEngineThreadCtx *det_ctx,
p, p->flow, tx->tx_ptr, tx->tx_id, flow_flags);
PREFILTER_PROFILING_END(det_ctx, engine->gid);
if (tx->tx_progress > engine->tx_min_progress && engine->is_last_for_progress) {
tx->prefilter_flags |= BIT_U64(engine->tx_min_progress);
if (tx->tx_progress > engine->ctx.tx_min_progress && engine->is_last_for_progress) {
tx->prefilter_flags |= BIT_U64(engine->ctx.tx_min_progress);
}
next:
if (engine->is_last)
@ -142,7 +144,16 @@ void Prefilter(DetectEngineThreadCtx *det_ctx, const SigGroupHead *sgh,
Packet *p, const uint8_t flags)
{
SCEnter();
#if 0
/* TODO review this check */
SCLogDebug("sgh %p frame_engines %p", sgh, sgh->frame_engines);
if (p->proto == IPPROTO_TCP && sgh->frame_engines && p->flow &&
p->flow->alproto != ALPROTO_UNKNOWN && p->flow->alparser != NULL) {
PACKET_PROFILING_DETECT_START(p, PROF_DETECT_PF_RECORD);
PrefilterFrames(det_ctx, sgh, p, flags, p->flow->alproto);
PACKET_PROFILING_DETECT_END(p, PROF_DETECT_PF_RECORD);
}
#endif
if (sgh->pkt_engines) {
PACKET_PROFILING_DETECT_START(p, PROF_DETECT_PF_PKT);
/* run packet engines */
@ -295,6 +306,41 @@ int PrefilterAppendTxEngine(DetectEngineCtx *de_ctx, SigGroupHead *sgh,
return 0;
}
int PrefilterAppendFrameEngine(DetectEngineCtx *de_ctx, SigGroupHead *sgh,
PrefilterFrameFn PrefilterFrameFunc, AppProto alproto, uint8_t frame_type, void *pectx,
void (*FreeFunc)(void *pectx), const char *name)
{
if (sgh == NULL || PrefilterFrameFunc == NULL || pectx == NULL)
return -1;
PrefilterEngineList *e = SCMallocAligned(sizeof(*e), CLS);
if (e == NULL)
return -1;
memset(e, 0x00, sizeof(*e));
e->frame_type = frame_type;
e->alproto = alproto;
e->PrefilterFrame = PrefilterFrameFunc;
e->pectx = pectx;
e->Free = FreeFunc;
if (sgh->init->frame_engines == NULL) {
sgh->init->frame_engines = e;
} else {
PrefilterEngineList *t = sgh->init->frame_engines;
while (t->next != NULL) {
t = t->next;
}
t->next = e;
e->id = t->id + 1;
}
e->name = name;
e->gid = PrefilterStoreGetId(de_ctx, e->name, e->Free);
return 0;
}
static void PrefilterFreeEngineList(PrefilterEngineList *e)
{
if (e->Free && e->pectx) {
@ -345,20 +391,24 @@ void PrefilterCleanupRuleGroup(const DetectEngineCtx *de_ctx, SigGroupHead *sgh)
PrefilterFreeEngines(de_ctx, sgh->tx_engines);
sgh->tx_engines = NULL;
}
if (sgh->frame_engines) {
PrefilterFreeEngines(de_ctx, sgh->frame_engines);
sgh->frame_engines = NULL;
}
}
static int PrefilterSetupRuleGroupSortHelper(const void *a, const void *b)
{
const PrefilterEngine *s0 = a;
const PrefilterEngine *s1 = b;
if (s1->tx_min_progress == s0->tx_min_progress) {
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;
} else {
return s0->alproto > s1->alproto ? 1 : -1;
}
} else {
return s0->tx_min_progress > s1->tx_min_progress ? 1 : -1;
return s0->ctx.tx_min_progress > s1->ctx.tx_min_progress ? 1 : -1;
}
}
@ -453,7 +503,7 @@ void 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->tx_min_progress = el->tx_min_progress;
e->ctx.tx_min_progress = el->tx_min_progress;
e->cb.PrefilterTx = el->PrefilterTx;
e->pectx = el->pectx;
el->pectx = NULL; // e now owns the ctx
@ -477,9 +527,9 @@ void PrefilterSetupRuleGroup(DetectEngineCtx *de_ctx, SigGroupHead *sgh)
PrefilterEngine *prev_engine = NULL;
engine = sgh->tx_engines;
do {
BUG_ON(engine->tx_min_progress < last_tx_progress);
BUG_ON(engine->ctx.tx_min_progress < last_tx_progress);
if (engine->alproto == a) {
if (last_tx_progress_set && engine->tx_min_progress > last_tx_progress) {
if (last_tx_progress_set && engine->ctx.tx_min_progress > last_tx_progress) {
if (prev_engine) {
prev_engine->is_last_for_progress = true;
}
@ -492,7 +542,7 @@ void PrefilterSetupRuleGroup(DetectEngineCtx *de_ctx, SigGroupHead *sgh)
prev_engine->is_last_for_progress = true;
}
}
last_tx_progress = engine->tx_min_progress;
last_tx_progress = engine->ctx.tx_min_progress;
if (engine->is_last)
break;
engine++;
@ -504,7 +554,7 @@ void PrefilterSetupRuleGroup(DetectEngineCtx *de_ctx, SigGroupHead *sgh)
do {
SCLogDebug("engine: gid %u alproto %s tx_min_progress %d is_last %s "
"is_last_for_progress %s",
engine->gid, AppProtoToString(engine->alproto), engine->tx_min_progress,
engine->gid, AppProtoToString(engine->alproto), engine->ctx.tx_min_progress,
engine->is_last ? "true" : "false",
engine->is_last_for_progress ? "true" : "false");
if (engine->is_last)
@ -513,6 +563,33 @@ void PrefilterSetupRuleGroup(DetectEngineCtx *de_ctx, SigGroupHead *sgh)
} while (1);
#endif
}
if (sgh->init->frame_engines != NULL) {
uint32_t cnt = 0;
for (el = sgh->init->frame_engines; el != NULL; el = el->next) {
cnt++;
de_ctx->prefilter_maxid = MAX(de_ctx->prefilter_maxid, el->gid);
}
sgh->frame_engines = SCMallocAligned(cnt * sizeof(PrefilterEngine), CLS);
if (sgh->frame_engines == NULL) {
return;
}
memset(sgh->frame_engines, 0x00, (cnt * sizeof(PrefilterEngine)));
PrefilterEngine *e = sgh->frame_engines;
for (el = sgh->init->frame_engines; el != NULL; el = el->next) {
e->local_id = el->id;
e->ctx.frame_type = el->frame_type;
e->cb.PrefilterFrame = el->PrefilterFrame;
e->alproto = el->alproto;
e->pectx = el->pectx;
el->pectx = NULL; // e now owns the ctx
e->gid = el->gid;
if (el->next == NULL) {
e->is_last = TRUE;
}
e++;
}
}
}
/* hash table for assigning a unique id to each engine type. */

@ -44,12 +44,13 @@ int PrefilterAppendPayloadEngine(DetectEngineCtx *de_ctx, SigGroupHead *sgh,
void *pectx, void (*FreeFunc)(void *pectx),
const char *name);
int PrefilterAppendTxEngine(DetectEngineCtx *de_ctx, SigGroupHead *sgh,
void (*PrefilterTx)(DetectEngineThreadCtx *det_ctx, const void *pectx,
Packet *p, Flow *f, void *tx,
const uint64_t idx, const uint8_t flags),
const AppProto alproto, const int tx_min_progress,
void *pectx, void (*FreeFunc)(void *pectx),
const char *name);
void (*PrefilterTx)(DetectEngineThreadCtx *det_ctx, const void *pectx, Packet *p, Flow *f,
void *tx, const uint64_t idx, const uint8_t flags),
const AppProto alproto, const int tx_min_progress, void *pectx,
void (*FreeFunc)(void *pectx), const char *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);
void DetectRunPrefilterTx(DetectEngineThreadCtx *det_ctx,
const SigGroupHead *sgh,

@ -71,10 +71,14 @@ void SigGroupHeadInitDataFree(SigGroupHeadInitData *sghid)
if (sghid->pkt_mpms != NULL) {
SCFree(sghid->pkt_mpms);
}
if (sghid->frame_mpms != NULL) {
SCFree(sghid->frame_mpms);
}
PrefilterFreeEnginesList(sghid->tx_engines);
PrefilterFreeEnginesList(sghid->pkt_engines);
PrefilterFreeEnginesList(sghid->payload_engines);
PrefilterFreeEnginesList(sghid->frame_engines);
SCFree(sghid);
}

@ -100,6 +100,7 @@ static uint32_t DetectEngineTentantGetIdFromPcap(const void *ctx, const Packet *
static DetectEngineAppInspectionEngine *g_app_inspect_engines = NULL;
static DetectEnginePktInspectionEngine *g_pkt_inspect_engines = NULL;
static DetectEngineFrameInspectionEngine *g_frame_inspect_engines = NULL;
SCEnumCharMap det_ctx_event_table[] = {
#ifdef UNITTESTS
@ -169,6 +170,54 @@ void DetectPktInspectEngineRegister(const char *name,
}
}
/** \brief register inspect engine at start up time
*
* \note errors are fatal */
void DetectFrameInspectEngineRegister(const char *name, int dir,
InspectionBufferFrameInspectFunc Callback, AppProto alproto, uint8_t type)
{
DetectBufferTypeRegister(name);
const int sm_list = DetectBufferTypeGetByName(name);
if (sm_list == -1) {
FatalError(SC_ERR_INITIALIZATION, "failed to register inspect engine %s", name);
}
if ((sm_list < DETECT_SM_LIST_MATCH) || (sm_list >= SHRT_MAX) || (Callback == NULL)) {
SCLogError(SC_ERR_INVALID_ARGUMENTS, "Invalid arguments");
BUG_ON(1);
}
int direction;
if (dir == SIG_FLAG_TOSERVER) {
direction = 0;
} else {
direction = 1;
}
DetectEngineFrameInspectionEngine *new_engine = SCCalloc(1, sizeof(*new_engine));
if (unlikely(new_engine == NULL)) {
FatalError(SC_ERR_INITIALIZATION, "failed to register inspect engine %s: %s", name,
strerror(errno));
}
new_engine->sm_list = sm_list;
new_engine->sm_list_base = sm_list;
new_engine->dir = direction;
new_engine->v1.Callback = Callback;
new_engine->alproto = alproto;
new_engine->type = type;
if (g_frame_inspect_engines == NULL) {
g_frame_inspect_engines = new_engine;
} else {
DetectEngineFrameInspectionEngine *t = g_frame_inspect_engines;
while (t->next != NULL) {
t = t->next;
}
t->next = new_engine;
}
}
/** \brief register inspect engine at start up time
*
* \note errors are fatal */
@ -361,6 +410,123 @@ static void DetectPktInspectEngineCopyListToDetectCtx(DetectEngineCtx *de_ctx)
}
}
/** \brief register inspect engine at start up time
*
* \note errors are fatal */
void DetectEngineFrameInspectEngineRegister(DetectEngineCtx *de_ctx, const char *name, int dir,
InspectionBufferFrameInspectFunc Callback, AppProto alproto, uint8_t type)
{
const int sm_list = DetectEngineBufferTypeRegister(de_ctx, name);
if (sm_list < 0) {
FatalError(SC_ERR_INITIALIZATION, "failed to register inspect engine %s", name);
}
if ((sm_list < DETECT_SM_LIST_MATCH) || (sm_list >= SHRT_MAX) || (Callback == NULL)) {
SCLogError(SC_ERR_INVALID_ARGUMENTS, "Invalid arguments");
BUG_ON(1);
}
int direction;
if (dir == SIG_FLAG_TOSERVER) {
direction = 0;
} else {
direction = 1;
}
DetectEngineFrameInspectionEngine *new_engine = SCCalloc(1, sizeof(*new_engine));
if (unlikely(new_engine == NULL)) {
FatalError(SC_ERR_INITIALIZATION, "failed to register inspect engine %s: %s", name,
strerror(errno));
}
new_engine->sm_list = sm_list;
new_engine->sm_list_base = sm_list;
new_engine->dir = direction;
new_engine->v1.Callback = Callback;
new_engine->alproto = alproto;
new_engine->type = type;
if (de_ctx->frame_inspect_engines == NULL) {
de_ctx->frame_inspect_engines = new_engine;
} else {
DetectEngineFrameInspectionEngine *list = de_ctx->frame_inspect_engines;
while (list->next != NULL) {
list = list->next;
}
list->next = new_engine;
}
}
/* copy an inspect engine with transforms to a new list id. */
static void DetectFrameInspectEngineCopy(DetectEngineCtx *de_ctx, int sm_list, int new_list,
const DetectEngineTransforms *transforms)
{
/* take the list from the detect engine as the buffers can be registered
* dynamically. */
const DetectEngineFrameInspectionEngine *t = de_ctx->frame_inspect_engines;
while (t) {
if (t->sm_list == sm_list) {
DetectEngineFrameInspectionEngine *new_engine =
SCCalloc(1, sizeof(DetectEngineFrameInspectionEngine));
if (unlikely(new_engine == NULL)) {
exit(EXIT_FAILURE);
}
new_engine->sm_list = new_list; /* use new list id */
new_engine->sm_list_base = sm_list;
new_engine->dir = t->dir;
new_engine->alproto = t->alproto;
new_engine->type = t->type;
new_engine->v1 = t->v1;
new_engine->v1.transforms = transforms; /* assign transforms */
if (de_ctx->frame_inspect_engines == NULL) {
de_ctx->frame_inspect_engines = new_engine;
} else {
DetectEngineFrameInspectionEngine *list = de_ctx->frame_inspect_engines;
while (list->next != NULL) {
list = list->next;
}
list->next = new_engine;
}
}
t = t->next;
}
}
/* copy inspect engines from global registrations to de_ctx list */
static void DetectFrameInspectEngineCopyListToDetectCtx(DetectEngineCtx *de_ctx)
{
const DetectEngineFrameInspectionEngine *t = g_frame_inspect_engines;
while (t) {
SCLogDebug("engine %p", t);
DetectEngineFrameInspectionEngine *new_engine =
SCCalloc(1, sizeof(DetectEngineFrameInspectionEngine));
if (unlikely(new_engine == NULL)) {
exit(EXIT_FAILURE);
}
new_engine->sm_list = t->sm_list;
new_engine->sm_list_base = t->sm_list;
new_engine->dir = t->dir;
new_engine->alproto = t->alproto;
new_engine->type = t->type;
new_engine->v1 = t->v1;
if (de_ctx->frame_inspect_engines == NULL) {
de_ctx->frame_inspect_engines = new_engine;
} else {
DetectEngineFrameInspectionEngine *list = de_ctx->frame_inspect_engines;
while (list->next != NULL) {
list = list->next;
}
list->next = new_engine;
}
t = t->next;
}
}
/** \internal
* \brief append the stream inspection
*
@ -435,6 +601,63 @@ int DetectEngineAppInspectionEngine2Signature(DetectEngineCtx *de_ctx, Signature
SCLogDebug("ptrs[%d] is set", i);
}
/* set up inspect engines */
const DetectEngineFrameInspectionEngine *u = de_ctx->frame_inspect_engines;
while (u != NULL) {
SCLogDebug("u %p sm_list %u nlists %u ptrs[] %p", u, u->sm_list, nlists,
u->sm_list < nlists ? ptrs[u->sm_list] : NULL);
if (u->sm_list < nlists && ptrs[u->sm_list] != NULL) {
bool prepend = false;
if (u->alproto == ALPROTO_UNKNOWN) {
/* special case, inspect engine applies to all protocols */
} else if (s->alproto != ALPROTO_UNKNOWN && !AppProtoEquals(s->alproto, u->alproto))
goto next_engine;
if (s->flags & SIG_FLAG_TOSERVER && !(s->flags & SIG_FLAG_TOCLIENT)) {
if (u->dir == 1)
goto next_engine;
} else if (s->flags & SIG_FLAG_TOCLIENT && !(s->flags & SIG_FLAG_TOSERVER)) {
if (u->dir == 0)
goto next_engine;
}
DetectEngineFrameInspectionEngine *new_engine =
SCCalloc(1, sizeof(DetectEngineFrameInspectionEngine));
if (unlikely(new_engine == NULL)) {
exit(EXIT_FAILURE);
}
if (mpm_list == u->sm_list) {
SCLogDebug("%s is mpm", DetectEngineBufferTypeGetNameById(de_ctx, u->sm_list));
prepend = true;
new_engine->mpm = true;
}
new_engine->type = u->type;
new_engine->sm_list = u->sm_list;
new_engine->sm_list_base = u->sm_list_base;
new_engine->smd = ptrs[new_engine->sm_list];
new_engine->v1 = u->v1;
SCLogDebug("sm_list %d new_engine->v1 %p/%p", new_engine->sm_list,
new_engine->v1.Callback, new_engine->v1.transforms);
if (s->frame_inspect == NULL) {
s->frame_inspect = new_engine;
} else if (prepend) {
new_engine->next = s->frame_inspect;
s->frame_inspect = new_engine;
} else {
DetectEngineFrameInspectionEngine *a = s->frame_inspect;
while (a->next != NULL) {
a = a->next;
}
new_engine->next = a->next;
a->next = new_engine;
}
}
next_engine:
u = u->next;
}
/* set up pkt inspect engines */
const DetectEnginePktInspectionEngine *e = de_ctx->pkt_inspect_engines;
while (e != NULL) {
@ -628,8 +851,14 @@ void DetectEngineAppInspectionEngineSignatureFree(DetectEngineCtx *de_ctx, Signa
nlists = MAX(e->sm_list + 1, nlists);
e = e->next;
}
DetectEngineFrameInspectionEngine *u = s->frame_inspect;
while (u) {
nlists = MAX(u->sm_list + 1, nlists);
u = u->next;
}
if (nlists == 0) {
BUG_ON(s->pkt_inspect);
BUG_ON(s->frame_inspect);
return;
}
@ -652,6 +881,13 @@ void DetectEngineAppInspectionEngineSignatureFree(DetectEngineCtx *de_ctx, Signa
SCFree(e);
e = next;
}
u = s->frame_inspect;
while (u) {
DetectEngineFrameInspectionEngine *next = u->next;
ptrs[u->sm_list] = u->smd;
SCFree(u);
u = next;
}
/* free the smds */
for (int i = 0; i < nlists; i++)
@ -804,6 +1040,16 @@ int DetectBufferTypeRegister(const char *name)
}
}
void DetectBufferTypeSupportsFrames(const char *name)
{
BUG_ON(g_buffer_type_reg_closed);
DetectBufferTypeRegister(name);
DetectBufferType *exists = DetectBufferTypeLookupByName(name);
BUG_ON(!exists);
exists->frame = true;
SCLogDebug("%p %s -- %d supports frame inspection", exists, name, exists->id);
}
void DetectBufferTypeSupportsPacket(const char *name)
{
BUG_ON(g_buffer_type_reg_closed);
@ -887,6 +1133,40 @@ static int DetectEngineBufferTypeAdd(DetectEngineCtx *de_ctx, const char *string
return map->id;
}
int DetectEngineBufferTypeRegisterWithFrameEngines(DetectEngineCtx *de_ctx, const char *name,
const int direction, const AppProto alproto, const uint8_t frame_type)
{
DetectBufferType *exists = DetectEngineBufferTypeLookupByName(de_ctx, name);
if (exists) {
return exists->id;
}
const int buffer_id = DetectEngineBufferTypeAdd(de_ctx, name);
if (buffer_id < 0) {
return -1;
}
/* TODO hack we need the map to get the name. Should we return the map at reg? */
const DetectBufferType *map = DetectEngineBufferTypeGetById(de_ctx, buffer_id);
BUG_ON(!map);
/* register MPM/inspect engines */
if (direction & SIG_FLAG_TOSERVER) {
DetectEngineFrameMpmRegister(de_ctx, map->name, SIG_FLAG_TOSERVER, 2,
PrefilterGenericMpmFrameRegister, alproto, frame_type);
DetectEngineFrameInspectEngineRegister(de_ctx, map->name, SIG_FLAG_TOSERVER,
DetectEngineInspectFrameBufferGeneric, alproto, frame_type);
}
if (direction & SIG_FLAG_TOCLIENT) {
DetectEngineFrameMpmRegister(de_ctx, map->name, SIG_FLAG_TOCLIENT, 2,
PrefilterGenericMpmFrameRegister, alproto, frame_type);
DetectEngineFrameInspectEngineRegister(de_ctx, map->name, SIG_FLAG_TOCLIENT,
DetectEngineInspectFrameBufferGeneric, alproto, frame_type);
}
return buffer_id;
}
int DetectEngineBufferTypeRegister(DetectEngineCtx *de_ctx, const char *name)
{
DetectBufferType *exists = DetectEngineBufferTypeLookupByName(de_ctx, name);
@ -926,6 +1206,14 @@ const char *DetectBufferTypeGetDescriptionByName(const char *name)
return exists->description;
}
void DetectEngineBufferTypeSupportsFrames(DetectEngineCtx *de_ctx, const char *name)
{
DetectBufferType *exists = DetectEngineBufferTypeLookupByName(de_ctx, name);
BUG_ON(!exists);
exists->frame = true;
SCLogDebug("%p %s -- %d supports frame inspection", exists, name, exists->id);
}
void DetectEngineBufferTypeSupportsPacket(DetectEngineCtx *de_ctx, const char *name)
{
DetectBufferType *exists = DetectEngineBufferTypeLookupByName(de_ctx, name);
@ -1310,6 +1598,8 @@ static void DetectBufferTypeSetupDetectEngine(DetectEngineCtx *de_ctx)
PrefilterInit(de_ctx);
DetectMpmInitializeAppMpms(de_ctx);
DetectAppLayerInspectEngineCopyListToDetectCtx(de_ctx);
DetectMpmInitializeFrameMpms(de_ctx);
DetectFrameInspectEngineCopyListToDetectCtx(de_ctx);
DetectMpmInitializePktMpms(de_ctx);
DetectPktInspectEngineCopyListToDetectCtx(de_ctx);
}
@ -1346,6 +1636,18 @@ static void DetectBufferTypeFreeDetectEngine(DetectEngineCtx *de_ctx)
SCFree(pmlist);
pmlist = next;
}
DetectEngineFrameInspectionEngine *framelist = de_ctx->frame_inspect_engines;
while (framelist) {
DetectEngineFrameInspectionEngine *next = framelist->next;
SCFree(framelist);
framelist = next;
}
DetectBufferMpmRegistery *framemlist = de_ctx->frame_mpms_list;
while (framemlist) {
DetectBufferMpmRegistery *next = framemlist->next;
SCFree(framemlist);
framemlist = next;
}
PrefilterDeinit(de_ctx);
}
}
@ -1400,9 +1702,12 @@ int DetectEngineBufferTypeGetByIdTransforms(
map->transforms = t;
map->mpm = base_map->mpm;
map->packet = base_map->packet;
map->frame = base_map->frame;
map->SetupCallback = base_map->SetupCallback;
map->ValidateCallback = base_map->ValidateCallback;
if (map->packet) {
if (map->frame) {
DetectFrameMpmRegisterByParentId(de_ctx, map->id, map->parent_id, &map->transforms);
} else if (map->packet) {
DetectPktMpmRegisterByParentId(de_ctx,
map->id, map->parent_id, &map->transforms);
} else {
@ -1415,7 +1720,9 @@ int DetectEngineBufferTypeGetByIdTransforms(
SCLogDebug("buffer %s registered with id %d, parent %d", map->name, map->id, map->parent_id);
de_ctx->buffer_type_id++;
if (map->packet) {
if (map->frame) {
DetectFrameInspectEngineCopy(de_ctx, map->parent_id, map->id, &map->transforms);
} else if (map->packet) {
DetectPktInspectEngineCopy(de_ctx, map->parent_id, map->id, &map->transforms);
} else {
DetectAppLayerInspectEngineCopy(de_ctx, map->parent_id, map->id, &map->transforms);

@ -28,6 +28,8 @@
#include "tm-threads.h"
#include "flow-private.h"
#include "detect-engine-frame.h"
void InspectionBufferInit(InspectionBuffer *buffer, uint32_t initial_size);
void InspectionBufferSetup(DetectEngineThreadCtx *det_ctx, const int list_id,
InspectionBuffer *buffer, const uint8_t *data, const uint32_t data_len);
@ -49,6 +51,7 @@ int DetectBufferTypeRegister(const char *name);
int DetectBufferTypeGetByName(const char *name);
void DetectBufferTypeSupportsMpm(const char *name);
void DetectBufferTypeSupportsPacket(const char *name);
void DetectBufferTypeSupportsFrames(const char *name);
void DetectBufferTypeSupportsTransformations(const char *name);
int DetectBufferTypeMaxId(void);
void DetectBufferTypeCloseRegistration(void);
@ -61,6 +64,8 @@ void DetectBufferTypeRegisterValidateCallback(const char *name,
/* detect engine related buffer funcs */
int DetectEngineBufferTypeRegisterWithFrameEngines(DetectEngineCtx *de_ctx, const char *name,
const int direction, const AppProto alproto, const uint8_t frame_type);
int DetectEngineBufferTypeRegister(DetectEngineCtx *de_ctx, const char *name);
const char *DetectEngineBufferTypeGetNameById(const DetectEngineCtx *de_ctx, const int id);
const DetectBufferType *DetectEngineBufferTypeGetById(const DetectEngineCtx *de_ctx, const int id);
@ -75,6 +80,7 @@ bool DetectEngineBufferRunValidateCallback(
const DetectEngineCtx *de_ctx, const int id, const Signature *s, const char **sigerror);
bool DetectEngineBufferTypeValidateTransform(DetectEngineCtx *de_ctx, int sm_list,
const uint8_t *content, uint16_t content_len, const char **namestr);
void DetectEngineBufferTypeSupportsFrames(DetectEngineCtx *de_ctx, const char *name);
void DetectEngineBufferTypeSupportsPacket(DetectEngineCtx *de_ctx, const char *name);
void DetectEngineBufferTypeSupportsMpm(DetectEngineCtx *de_ctx, const char *name);
void DetectEngineBufferTypeSupportsTransformations(DetectEngineCtx *de_ctx, const char *name);
@ -161,9 +167,16 @@ void DetectPktInspectEngineRegister(const char *name,
InspectionBufferGetPktDataPtr GetPktData,
InspectionBufferPktInspectFunc Callback);
void DetectFrameInspectEngineRegister(const char *name, int dir,
InspectionBufferFrameInspectFunc Callback, AppProto alproto, uint8_t type);
void DetectEngineFrameInspectEngineRegister(DetectEngineCtx *de_ctx, const char *name, int dir,
InspectionBufferFrameInspectFunc Callback, AppProto alproto, uint8_t type);
int DetectEngineAppInspectionEngine2Signature(DetectEngineCtx *de_ctx, Signature *s);
void DetectEngineAppInspectionEngineSignatureFree(DetectEngineCtx *, Signature *s);
bool DetectEngineFrameInspectionRun(ThreadVars *tv, DetectEngineThreadCtx *det_ctx,
const Signature *s, Flow *f, Packet *p, uint8_t *alert_flags);
bool DetectEnginePktInspectionRun(ThreadVars *tv,
DetectEngineThreadCtx *det_ctx, const Signature *s,
Flow *f, Packet *p,

@ -84,6 +84,8 @@ static inline void DetectRulePacketRules(ThreadVars * const tv,
static void DetectRunTx(ThreadVars *tv, DetectEngineCtx *de_ctx,
DetectEngineThreadCtx *det_ctx, Packet *p,
Flow *f, DetectRunScratchpad *scratch);
static void DetectRunFrames(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx,
Packet *p, Flow *f, DetectRunScratchpad *scratch);
static inline void DetectRunPostRules(ThreadVars *tv, DetectEngineCtx *de_ctx,
DetectEngineThreadCtx *det_ctx, Packet * const p, Flow * const pflow,
DetectRunScratchpad *scratch);
@ -136,6 +138,15 @@ static void DetectRun(ThreadVars *th_v,
/* run tx/state inspection. Don't call for ICMP error msgs. */
if (pflow && pflow->alstate && likely(pflow->proto == p->proto)) {
if (p->proto == IPPROTO_TCP) {
const TcpSession *ssn = p->flow->protoctx;
if (ssn && (ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED) == 0) {
// PACKET_PROFILING_DETECT_START(p, PROF_DETECT_TX);
DetectRunFrames(th_v, de_ctx, det_ctx, p, pflow, &scratch);
// PACKET_PROFILING_DETECT_END(p, PROF_DETECT_TX);
}
}
PACKET_PROFILING_DETECT_START(p, PROF_DETECT_TX);
DetectRunTx(th_v, de_ctx, det_ctx, p, pflow, &scratch);
PACKET_PROFILING_DETECT_END(p, PROF_DETECT_TX);
@ -749,6 +760,9 @@ static inline void DetectRulePacketRules(
if (s->app_inspect != NULL) {
goto next; // handle sig in DetectRunTx
}
if (s->frame_inspect != NULL) {
goto next; // handle sig in DetectRunFrame
}
/* don't run mask check for stateful rules.
* There we depend on prefilter */
@ -1517,6 +1531,114 @@ next:
}
}
static void DetectRunFrames(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx,
Packet *p, Flow *f, DetectRunScratchpad *scratch)
{
const SigGroupHead *const sgh = scratch->sgh;
const AppProto alproto = f->alproto;
FramesContainer *frames_container = AppLayerFramesGetContainer(f);
if (frames_container == NULL) {
return;
}
Frames *frames;
if (PKT_IS_TOSERVER(p)) {
frames = &frames_container->toserver;
} else {
frames = &frames_container->toclient;
}
for (uint32_t idx = 0; idx < frames->cnt; idx++) {
SCLogDebug("frame %u", idx);
const Frame *frame = FrameGetByIndex(frames, idx);
if (frame == NULL) {
continue;
}
uint32_t array_idx = 0;
uint32_t total_rules = det_ctx->match_array_cnt;
/* run prefilter engines and merge results into a candidates array */
if (sgh->frame_engines) {
// PACKET_PROFILING_DETECT_START(p, PROF_DETECT_PF_TX);
DetectRunPrefilterFrame(det_ctx, sgh, p, frames, frame, alproto, idx);
// PACKET_PROFILING_DETECT_END(p, PROF_DETECT_PF_TX);
SCLogDebug("%p/%" PRIi64 " rules added from prefilter: %u candidates", frame, frame->id,
det_ctx->pmq.rule_id_array_cnt);
total_rules += det_ctx->pmq.rule_id_array_cnt;
if (!(RuleMatchCandidateTxArrayHasSpace(
det_ctx, total_rules))) { // TODO is it safe to overload?
RuleMatchCandidateTxArrayExpand(det_ctx, total_rules);
}
for (uint32_t i = 0; i < det_ctx->pmq.rule_id_array_cnt; i++) {
const Signature *s = de_ctx->sig_array[det_ctx->pmq.rule_id_array[i]];
const SigIntId id = s->num;
det_ctx->tx_candidates[array_idx].s = s;
det_ctx->tx_candidates[array_idx].id = id;
det_ctx->tx_candidates[array_idx].flags = NULL;
det_ctx->tx_candidates[array_idx].stream_reset = 0;
array_idx++;
}
PMQ_RESET(&det_ctx->pmq);
}
/* merge 'state' rules from the regular prefilter */
uint32_t x = array_idx;
for (uint32_t i = 0; i < det_ctx->match_array_cnt; i++) {
const Signature *s = det_ctx->match_array[i];
if (s->frame_inspect != NULL) {
const SigIntId id = s->num;
det_ctx->tx_candidates[array_idx].s = s;
det_ctx->tx_candidates[array_idx].id = id;
det_ctx->tx_candidates[array_idx].flags = NULL;
det_ctx->tx_candidates[array_idx].stream_reset = 0;
array_idx++;
SCLogDebug("%p/%" PRIi64 " rule %u (%u) added from 'match' list", frame, frame->id,
s->id, id);
}
}
SCLogDebug("%p/%" PRIi64 " rules added from 'match' list: %u", frame, frame->id,
array_idx - x);
(void)x;
/* run rules: inspect the match candidates */
for (uint32_t i = 0; i < array_idx; i++) {
const Signature *s = det_ctx->tx_candidates[i].s;
SCLogDebug("%p/%" PRIi64 " inspecting: sid %u (%u)", frame, frame->id, s->id, s->num);
/* start new inspection */
SCLogDebug("%p/%" PRIi64 " Start sid %u", frame, frame->id, s->id);
/* call individual rule inspection */
RULE_PROFILING_START(p);
int r = DetectRunInspectRuleHeader(p, f, s, s->flags, s->proto.flags);
if (r == 1) {
r = DetectRunFrameInspectRule(tv, det_ctx, s, f, p, frames, frame, idx);
if (r == 1) {
/* match */
DetectRunPostMatch(tv, det_ctx, p, s);
const uint8_t alert_flags =
(PACKET_ALERT_FLAG_STATE_MATCH | PACKET_ALERT_FLAG_FRAME);
// TODO set tx id if the frame has it
det_ctx->flags |= DETECT_ENGINE_THREAD_CTX_FRAME_ID_SET;
det_ctx->frame_id = frame->id;
SCLogDebug(
"%p/%" PRIi64 " sig %u (%u) matched", frame, frame->id, s->id, s->num);
PacketAlertAppend(det_ctx, s, p, 0, alert_flags); // TODO tx id frame field
}
}
DetectVarProcessList(det_ctx, p->flow, p);
RULE_PROFILING_END(det_ctx, s, r, p);
}
InspectionBufferClean(det_ctx);
}
}
static DetectEngineThreadCtx *GetTenantById(HashTable *h, uint32_t id)
{
/* technically we need to pass a DetectEngineThreadCtx struct with the

@ -279,6 +279,7 @@ typedef struct DetectPort_ {
/* for now a uint8_t is enough */
#define SignatureMask uint8_t
#define DETECT_ENGINE_THREAD_CTX_FRAME_ID_SET 0x0001
#define DETECT_ENGINE_THREAD_CTX_STREAM_CONTENT_MATCH 0x0004
#define FILE_SIG_NEED_FILE 0x01
@ -423,6 +424,7 @@ typedef struct DetectBufferType_ {
int parent_id;
bool mpm;
bool packet; /**< compat to packet matches */
bool frame; /**< is about Frame inspection */
bool supports_transforms;
void (*SetupCallback)(const struct DetectEngineCtx_ *, struct Signature_ *);
bool (*ValidateCallback)(const struct Signature_ *, const char **sigerror);
@ -460,6 +462,33 @@ typedef struct DetectEnginePktInspectionEngine {
struct DetectEnginePktInspectionEngine *next;
} DetectEnginePktInspectionEngine;
struct Frame;
struct Frames;
struct DetectEngineFrameInspectionEngine;
/**
* \param alert_flags[out] for setting PACKET_ALERT_FLAG_*
*/
typedef int (*InspectionBufferFrameInspectFunc)(struct DetectEngineThreadCtx_ *,
const struct DetectEngineFrameInspectionEngine *engine, const struct Signature_ *s,
Packet *p, const struct Frames *frames, const struct Frame *frame, const uint32_t idx);
typedef struct DetectEngineFrameInspectionEngine {
AppProto alproto;
uint8_t dir;
uint8_t type;
bool mpm;
uint16_t sm_list;
uint16_t sm_list_base;
struct {
InspectionBufferFrameInspectFunc Callback;
/** pointer to the transforms in the 'DetectBuffer entry for this list */
const DetectEngineTransforms *transforms;
} v1;
SigMatchData *smd;
struct DetectEngineFrameInspectionEngine *next;
} DetectEngineFrameInspectionEngine;
#ifdef UNITTESTS
#define sm_lists init_data->smlists
#define sm_lists_tail init_data->smlists_tail
@ -565,6 +594,7 @@ typedef struct Signature_ {
DetectEngineAppInspectionEngine *app_inspect;
DetectEnginePktInspectionEngine *pkt_inspect;
DetectEngineFrameInspectionEngine *frame_inspect;
/* Matching structures for the built-ins. The others are in
* their inspect engines. */
@ -593,6 +623,7 @@ typedef struct Signature_ {
enum DetectBufferMpmType {
DETECT_BUFFER_MPM_TYPE_PKT,
DETECT_BUFFER_MPM_TYPE_APP,
DETECT_BUFFER_MPM_TYPE_FRAME,
/* must be last */
DETECT_BUFFER_MPM_TYPE_SIZE,
};
@ -629,6 +660,12 @@ typedef struct DetectBufferMpmRegistery_ {
const struct DetectBufferMpmRegistery_ *mpm_reg, int list_id);
InspectionBufferGetPktDataPtr GetData;
} pkt_v1;
/* frame matching: use if type == DETECT_BUFFER_MPM_TYPE_FRAME */
struct {
AppProto alproto;
uint8_t type;
} frame_v1;
};
struct DetectBufferMpmRegistery_ *next;
@ -933,6 +970,9 @@ typedef struct DetectEngineCtx_ {
DetectEnginePktInspectionEngine *pkt_inspect_engines;
DetectBufferMpmRegistery *pkt_mpms_list;
uint32_t pkt_mpms_list_cnt;
DetectEngineFrameInspectionEngine *frame_inspect_engines;
DetectBufferMpmRegistery *frame_mpms_list;
uint32_t frame_mpms_list_cnt;
uint32_t prefilter_id;
HashListTable *prefilter_hash_table;
@ -1269,6 +1309,9 @@ typedef struct MpmStore_ {
} MpmStore;
typedef void (*PrefilterFrameFn)(DetectEngineThreadCtx *det_ctx, const void *pectx, Packet *p,
const struct Frames *frames, const struct Frame *frame, const uint32_t idx);
typedef struct PrefilterEngineList_ {
uint16_t id;
@ -1278,6 +1321,8 @@ typedef struct PrefilterEngineList_ {
* with Tx Engine */
uint8_t tx_min_progress;
uint8_t frame_type;
/** Context for matching. Might be MpmCtx for MPM engines, other ctx'
* for other engines. */
void *pectx;
@ -1286,6 +1331,7 @@ typedef struct PrefilterEngineList_ {
void (*PrefilterTx)(DetectEngineThreadCtx *det_ctx, const void *pectx,
Packet *p, Flow *f, void *tx,
const uint64_t idx, const uint8_t flags);
PrefilterFrameFn PrefilterFrame;
struct PrefilterEngineList_ *next;
@ -1302,9 +1348,13 @@ typedef struct PrefilterEngine_ {
/** App Proto this engine applies to: only used with Tx Engines */
AppProto alproto;
/** Minimal Tx progress we need before running the engine. Only used
* with Tx Engine */
uint8_t tx_min_progress;
union {
/** Minimal Tx progress we need before running the engine. Only used
* with Tx Engine */
uint8_t tx_min_progress;
uint8_t frame_type;
} ctx;
/** Context for matching. Might be MpmCtx for MPM engines, other ctx'
* for other engines. */
@ -1315,6 +1365,7 @@ typedef struct PrefilterEngine_ {
void (*PrefilterTx)(DetectEngineThreadCtx *det_ctx, const void *pectx,
Packet *p, Flow *f, void *tx,
const uint64_t idx, const uint8_t flags);
PrefilterFrameFn PrefilterFrame;
} cb;
/* global id for this prefilter */
@ -1335,10 +1386,12 @@ typedef struct SigGroupHeadInitData_ {
MpmCtx **app_mpms;
MpmCtx **pkt_mpms;
MpmCtx **frame_mpms;
PrefilterEngineList *pkt_engines;
PrefilterEngineList *payload_engines;
PrefilterEngineList *tx_engines;
PrefilterEngineList *frame_engines;
/** number of sigs in this group */
SigIntId sig_cnt;
@ -1371,6 +1424,7 @@ typedef struct SigGroupHead_ {
PrefilterEngine *pkt_engines;
PrefilterEngine *payload_engines;
PrefilterEngine *tx_engines;
PrefilterEngine *frame_engines;
/* ptr to our init data we only use at... init :) */
SigGroupHeadInitData *init;

@ -422,6 +422,7 @@ typedef enum PacketProfileDetectId_ {
PROF_DETECT_PF_PKT,
PROF_DETECT_PF_PAYLOAD,
PROF_DETECT_PF_TX,
PROF_DETECT_PF_RECORD,
PROF_DETECT_PF_SORT1,
PROF_DETECT_PF_SORT2,
PROF_DETECT_NONMPMLIST,

@ -1267,6 +1267,7 @@ const char * PacketProfileDetectIdToString(PacketProfileDetectId id)
CASE_CODE (PROF_DETECT_PF_PKT);
CASE_CODE (PROF_DETECT_PF_PAYLOAD);
CASE_CODE (PROF_DETECT_PF_TX);
CASE_CODE(PROF_DETECT_PF_RECORD);
CASE_CODE (PROF_DETECT_PF_SORT1);
CASE_CODE (PROF_DETECT_PF_SORT2);
CASE_CODE (PROF_DETECT_NONMPMLIST);

Loading…
Cancel
Save