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 \
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 \
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");
}
-/* 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
* 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,
};
--- /dev/null
+/* 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;
+ }
+}
--- /dev/null
+/* 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);
-/* 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
* 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
*
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.
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;
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;
}
}
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;
+ }
}
}
}
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);
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);
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;
}
}
+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.
*
*/
PrepareAppMpms(de_ctx, sh);
PreparePktMpms(de_ctx, sh);
+ PrepareFrameMpms(de_ctx, sh);
return 0;
}
#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);
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;
-/* 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
#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"
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;
}
}
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)
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 */
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) {
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;
}
}
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
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;
}
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++;
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)
} 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. */
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,
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);
}
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
}
}
+/** \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 */
}
}
+/** \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
*
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) {
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;
}
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++)
}
}
+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);
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);
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);
PrefilterInit(de_ctx);
DetectMpmInitializeAppMpms(de_ctx);
DetectAppLayerInspectEngineCopyListToDetectCtx(de_ctx);
+ DetectMpmInitializeFrameMpms(de_ctx);
+ DetectFrameInspectEngineCopyListToDetectCtx(de_ctx);
DetectMpmInitializePktMpms(de_ctx);
DetectPktInspectEngineCopyListToDetectCtx(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);
}
}
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 {
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);
#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);
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);
/* 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);
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);
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,
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);
/* 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);
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 */
}
}
+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
/* 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
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);
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
DetectEngineAppInspectionEngine *app_inspect;
DetectEnginePktInspectionEngine *pkt_inspect;
+ DetectEngineFrameInspectionEngine *frame_inspect;
/* Matching structures for the built-ins. The others are in
* their inspect engines. */
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,
};
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;
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;
} 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;
* 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;
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;
/** 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. */
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 */
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;
PrefilterEngine *pkt_engines;
PrefilterEngine *payload_engines;
PrefilterEngine *tx_engines;
+ PrefilterEngine *frame_engines;
/* ptr to our init data we only use at... init :) */
SigGroupHeadInitData *init;
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,
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);