]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
detect/frames: improve IPS and GAP handling 8482/head
authorVictor Julien <vjulien@oisf.net>
Thu, 26 Jan 2023 14:40:49 +0000 (15:40 +0100)
committerVictor Julien <vjulien@oisf.net>
Sat, 28 Jan 2023 11:46:41 +0000 (12:46 +0100)
Inspect individual chunks in lossy traffic.

Don't use the frame idx as the inspection buffer idx. Engines are running
per frame, so multi inspection can be used for stream chunks instead.

Ticket: #4977.

src/detect-engine-frame.c
src/detect-engine-frame.h
src/detect.c
src/detect.h

index 33d78ced7a2d31076729682f9e1212efcd413794..ee86387a443370c72781978380ff74a88fc9938e 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2021 Open Information Security Foundation
+/* Copyright (C) 2021-2023 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 "util-validate.h"
 #include "util-print.h"
 
-static 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);
+struct FrameStreamData {
+    // shared between prefilter and inspect
+    DetectEngineThreadCtx *det_ctx;
+    const DetectEngineTransforms *transforms;
+    const Frame *frame;
+    int list_id;
+    uint32_t idx; /**< multi buffer idx, incremented for each stream chunk */
+
+    // inspection only
+    const DetectEngineFrameInspectionEngine *inspect_engine;
+    const Signature *s;
+    int inspect_result; // DETECT_ENGINE_INSPECT_SIG_MATCH / DETECT_ENGINE_INSPECT_SIG_NO_MATCH
+    Packet *p;
+
+    // prefilter only
+    const MpmCtx *mpm_ctx;
+
+    uint64_t requested_stream_offset;
+};
+
+static bool SetupStreamCallbackData(struct FrameStreamData *dst, const TcpSession *ssn,
+        const TcpStream *stream, DetectEngineThreadCtx *det_ctx,
+        const DetectEngineTransforms *transforms, const Frames *_frames, const Frame *frame,
+        const int list_id, const bool eof);
+
+static bool BufferSetup(struct FrameStreamData *fsd, InspectionBuffer *buffer, const uint8_t *input,
+        const uint32_t input_len, const uint64_t input_offset);
+static void BufferSetupUdp(InspectionBuffer *buffer, const Frame *frame, const Packet *p,
+        const DetectEngineTransforms *transforms);
 
 void DetectRunPrefilterFrame(DetectEngineThreadCtx *det_ctx, const SigGroupHead *sgh, Packet *p,
-        const Frames *frames, const Frame *frame, const AppProto alproto, const uint32_t idx)
+        const Frames *frames, const Frame *frame, const AppProto alproto)
 {
     SCLogDebug("pcap_cnt %" PRIu64, p->pcap_cnt);
     PrefilterEngine *engine = sgh->frame_engines;
@@ -54,7 +80,7 @@ void DetectRunPrefilterFrame(DetectEngineThreadCtx *det_ctx, const SigGroupHead
         if (engine->alproto == alproto && engine->ctx.frame_type == frame->type) {
             SCLogDebug("frame %p engine %p", frame, engine);
             PREFILTER_PROFILING_START(det_ctx);
-            engine->cb.PrefilterFrame(det_ctx, engine->pectx, p, frames, frame, idx);
+            engine->cb.PrefilterFrame(det_ctx, engine->pectx, p, frames, frame);
             PREFILTER_PROFILING_END(det_ctx, engine->gid);
         }
         if (engine->is_last)
@@ -72,6 +98,41 @@ typedef struct PrefilterMpmFrameCtx {
     const DetectEngineTransforms *transforms;
 } PrefilterMpmFrameCtx;
 
+static int FrameStreamDataPrefilterFunc(
+        void *cb_data, const uint8_t *input, const uint32_t input_len, const uint64_t input_offset)
+{
+    struct FrameStreamData *fsd = cb_data;
+    SCLogDebug("prefilter: fsd %p { det_ctx:%p, transforms:%p, frame:%p, list_id:%d, idx:%u, "
+               "data_offset:%" PRIu64 "}, input: %p, input_len:%u, input_offset:%" PRIu64,
+            fsd, fsd->det_ctx, fsd->transforms, fsd->frame, fsd->list_id, fsd->idx,
+            fsd->requested_stream_offset, input, input_len, input_offset);
+    // PrintRawDataFp(stdout, input, input_len);
+
+    InspectionBuffer *buffer =
+            InspectionBufferMultipleForListGet(fsd->det_ctx, fsd->list_id, fsd->idx++);
+    if (buffer == NULL) {
+        return 0;
+    }
+    SCLogDebug("buffer %p idx %u", buffer, fsd->idx);
+
+    const int more_chunks = BufferSetup(fsd, buffer, input, input_len, input_offset);
+
+    const uint32_t data_len = buffer->inspect_len;
+    const uint8_t *data = buffer->inspect;
+    DetectEngineThreadCtx *det_ctx = fsd->det_ctx;
+    const MpmCtx *mpm_ctx = fsd->mpm_ctx;
+
+    if (data != NULL && data_len >= mpm_ctx->minlen) {
+        // PrintRawDataFp(stdout, data, data_len);
+
+        (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);
+        PREFILTER_PROFILING_ADD_BYTES(det_ctx, data_len);
+    }
+    return more_chunks;
+}
+
 /** \brief Generic Mpm prefilter callback
  *
  *  \param det_ctx detection engine thread ctx
@@ -80,34 +141,62 @@ typedef struct PrefilterMpmFrameCtx {
  *  \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)
+        const Frames *frames, const Frame *frame)
 {
     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;
-    DEBUG_VALIDATE_BUG_ON(frame->len >= 0 && buffer->orig_len > frame->len);
 
-    const uint32_t data_len = buffer->inspect_len;
-    const uint8_t *data = buffer->inspect;
+    SCLogDebug("packet:%" PRIu64 ", prefilter running on list %d -> frame field type %u",
+            p->pcap_cnt, ctx->list_id, frame->type);
+    if (p->proto == IPPROTO_UDP) {
+        // TODO can we use single here? Could it conflict with TCP?
+        InspectionBuffer *buffer = InspectionBufferMultipleForListGet(det_ctx, ctx->list_id, 0);
+        if (buffer == NULL)
+            return;
+        DEBUG_VALIDATE_BUG_ON(frame->offset >= p->payload_len);
+        if (frame->offset >= p->payload_len)
+            return;
+
+        BufferSetupUdp(buffer, frame, p, ctx->transforms);
+        const uint32_t data_len = buffer->inspect_len;
+        const uint8_t *data = buffer->inspect;
+
+        // PrintRawDataFp(stdout, data, 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);
+            PREFILTER_PROFILING_ADD_BYTES(det_ctx, data_len);
+        }
+    } else if (p->proto == IPPROTO_TCP) {
+        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;
+        }
+        const bool eof = ssn->state == TCP_CLOSED || PKT_IS_PSEUDOPKT(p);
 
-    SCLogDebug("mpm'ing buffer:");
-    SCLogDebug("frame: %p", frame);
-    // PrintRawDataFp(stdout, data, MIN(32, data_len));
+        struct FrameStreamData fsd;
+        memset(&fsd, 0, sizeof(fsd));
+        fsd.mpm_ctx = mpm_ctx;
 
-    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);
-        PREFILTER_PROFILING_ADD_BYTES(det_ctx, data_len);
+        if (SetupStreamCallbackData(&fsd, ssn, stream, det_ctx, ctx->transforms, frames, frame,
+                    ctx->list_id, eof) == true) {
+            StreamReassembleForFrame(ssn, stream, FrameStreamDataPrefilterFunc, &fsd,
+                    fsd.requested_stream_offset, eof);
+        }
+    } else {
+        DEBUG_VALIDATE_BUG_ON(1);
     }
+    SCLogDebug("packet:%" PRIu64
+               ", prefilter done running on list %d -> frame field type %u; have %u matches",
+            p->pcap_cnt, ctx->list_id, frame->type, det_ctx->pmq.rule_id_array_cnt);
 }
 
 static void PrefilterMpmFrameFree(void *ptr)
@@ -136,7 +225,7 @@ int PrefilterGenericMpmFrameRegister(DetectEngineCtx *de_ctx, SigGroupHead *sgh,
 }
 
 int DetectRunFrameInspectRule(ThreadVars *tv, DetectEngineThreadCtx *det_ctx, const Signature *s,
-        Flow *f, Packet *p, const Frames *frames, const Frame *frame, const uint32_t idx)
+        Flow *f, Packet *p, const Frames *frames, const Frame *frame)
 {
     BUG_ON(s->frame_inspect == NULL);
 
@@ -149,7 +238,7 @@ int DetectRunFrameInspectRule(ThreadVars *tv, DetectEngineThreadCtx *det_ctx, co
 
             // 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) {
+            if (e->v1.Callback(det_ctx, e, s, p, frames, frame) == true) {
                 SCLogDebug("sid %u: e %p Callback returned true", s->id, e);
                 return true;
             }
@@ -162,18 +251,9 @@ int DetectRunFrameInspectRule(ThreadVars *tv, DetectEngineThreadCtx *det_ctx, co
     return false;
 }
 
-/** \internal
- *  \brief setup buffer based on frame in UDP payload
- */
-static InspectionBuffer *DetectFrame2InspectBufferUdp(DetectEngineThreadCtx *det_ctx,
-        const DetectEngineTransforms *transforms, Packet *p, InspectionBuffer *buffer,
-        const Frames *frames, const Frame *frame, const int list_id, const uint32_t idx,
-        const bool first)
+static void BufferSetupUdp(InspectionBuffer *buffer, const Frame *frame, const Packet *p,
+        const DetectEngineTransforms *transforms)
 {
-    DEBUG_VALIDATE_BUG_ON(frame->offset >= p->payload_len);
-    if (frame->offset >= p->payload_len)
-        return NULL;
-
     uint8_t ci_flags = DETECT_CI_FLAGS_START;
     uint32_t frame_len;
     if (frame->len == -1) {
@@ -194,43 +274,64 @@ static InspectionBuffer *DetectFrame2InspectBufferUdp(DetectEngineThreadCtx *det
             p->pcap_cnt, frame, frame->id,
             AppLayerParserGetFrameNameById(p->flow->proto, p->flow->alproto, frame->type),
             frame->offset, frame->type, frame->len);
-    // PrintRawDataFp(stdout, data, MIN(64,data_len));
 
     InspectionBufferSetupMulti(buffer, transforms, data, data_len);
     buffer->inspect_offset = 0;
     buffer->flags = ci_flags;
-    return buffer;
 }
 
-struct FrameStreamData {
-    DetectEngineThreadCtx *det_ctx;
-    const DetectEngineTransforms *transforms;
-    const Frame *frame;
-    int list_id;
-    uint32_t idx;
-    uint64_t data_offset;
-    uint64_t frame_offset;
-    /** buffer is set if callback was successful */
-    InspectionBuffer *buffer;
-};
-
-static int FrameStreamDataFunc(
-        void *cb_data, const uint8_t *input, const uint32_t input_len, const uint64_t offset)
+/** \internal
+ *  \brief setup buffer based on frame in UDP payload
+ */
+static int DetectFrameInspectUdp(DetectEngineThreadCtx *det_ctx,
+        const DetectEngineFrameInspectionEngine *engine, const Signature *s,
+        const DetectEngineTransforms *transforms, Packet *p, const Frames *_frames,
+        const Frame *frame, const int list_id)
 {
-    struct FrameStreamData *fsd = cb_data;
-    SCLogDebug("fsd %p { det_ctx:%p, transforms:%p, frame:%p, list_id:%d, idx:%u, "
-               "data_offset:%" PRIu64 ", frame_offset:%" PRIu64
-               " }, input: %p, input_len:%u, offset:%" PRIu64,
-            fsd, fsd->det_ctx, fsd->transforms, fsd->frame, fsd->list_id, fsd->idx,
-            fsd->data_offset, fsd->frame_offset, input, input_len, offset);
-    // PrintRawDataFp(stdout, input, input_len);
+    SCLogDebug("packet:%" PRIu64 ", inspect: s:%p s->id:%u, transforms:%p", p->pcap_cnt, s, s->id,
+            transforms);
 
-    InspectionBuffer *buffer =
-            InspectionBufferMultipleForListGet(fsd->det_ctx, fsd->list_id, fsd->idx);
-    BUG_ON(buffer == NULL);
-    SCLogDebug("buffer %p", buffer);
+    // TODO can we use single here? Could it conflict with TCP?
+    InspectionBuffer *buffer = InspectionBufferMultipleForListGet(det_ctx, list_id, 0);
+    if (buffer == NULL)
+        return DETECT_ENGINE_INSPECT_SIG_NO_MATCH;
+
+    DEBUG_VALIDATE_BUG_ON(frame->offset >= p->payload_len);
+    if (frame->offset >= p->payload_len)
+        return DETECT_ENGINE_INSPECT_SIG_NO_MATCH;
+
+    if (!buffer->initialized)
+        BufferSetupUdp(buffer, frame, p, transforms);
+    DEBUG_VALIDATE_BUG_ON(!buffer->initialized);
+    if (buffer->inspect == NULL)
+        return DETECT_ENGINE_INSPECT_SIG_NO_MATCH;
+
+    const uint32_t data_len = buffer->inspect_len;
+    const uint8_t *data = buffer->inspect;
+
+    // PrintRawDataFp(stdout, data, data_len);
 
+    int r = DetectEngineContentInspection(det_ctx->de_ctx, det_ctx, s, engine->smd, p, p->flow,
+            (uint8_t *)data, data_len, 0, buffer->flags,
+            DETECT_ENGINE_CONTENT_INSPECTION_MODE_FRAME);
+    if (r == 1) {
+        SCLogDebug("match!");
+        return DETECT_ENGINE_INSPECT_SIG_MATCH;
+    } else {
+        return DETECT_ENGINE_INSPECT_SIG_NO_MATCH;
+    }
+}
+
+/**
+ *  \retval bool true if callback should run again */
+static bool BufferSetup(struct FrameStreamData *fsd, InspectionBuffer *buffer, const uint8_t *input,
+        const uint32_t input_len, const uint64_t input_offset)
+{
     const Frame *frame = fsd->frame;
+    /* so: relative to start of stream */
+    const uint64_t so_input_re = input_offset + input_len;
+    const uint64_t so_frame_re =
+            frame->offset + (uint64_t)frame->len; // TODO if eof, set to available data?
     SCLogDebug("frame offset:%" PRIu64, frame->offset);
     const uint8_t *data = input;
     uint8_t ci_flags = 0;
@@ -239,7 +340,7 @@ static int FrameStreamDataFunc(
     /* fo: frame offset; offset relative to start of the frame */
     uint64_t fo_inspect_offset = 0;
 
-    if (frame->offset == 0 && offset == 0) {
+    if (frame->offset == 0 && input_offset == 0) {
         ci_flags |= DETECT_CI_FLAGS_START;
         SCLogDebug("have frame data start");
 
@@ -254,10 +355,10 @@ static int FrameStreamDataFunc(
         }
     } else {
         const uint64_t so_frame_inspect_offset = frame->inspect_progress + frame->offset;
-        const uint64_t so_inspect_offset = MAX(offset, so_frame_inspect_offset);
+        const uint64_t so_inspect_offset = MAX(input_offset, so_frame_inspect_offset);
         fo_inspect_offset = so_inspect_offset - frame->offset;
 
-        if (frame->offset >= offset) {
+        if (frame->offset >= input_offset) {
             ci_flags |= DETECT_CI_FLAGS_START;
             SCLogDebug("have frame data start");
         }
@@ -265,17 +366,12 @@ static int FrameStreamDataFunc(
             if (fo_inspect_offset >= (uint64_t)frame->len) {
                 SCLogDebug("data entirely past frame (%" PRIu64 " > %" PRIi64 ")",
                         fo_inspect_offset, frame->len);
-                return 1;
+                return false;
             }
 
-            /* so: relative to start of stream */
-            const uint64_t so_frame_offset = frame->offset;
-            const uint64_t so_frame_re = so_frame_offset + (uint64_t)frame->len;
-            const uint64_t so_input_re = offset + input_len;
-
             /* in: relative to start of input data */
-            BUG_ON(so_inspect_offset < offset);
-            const uint32_t in_data_offset = so_inspect_offset - offset;
+            BUG_ON(so_inspect_offset < input_offset);
+            const uint32_t in_data_offset = so_inspect_offset - input_offset;
             data += in_data_offset;
 
             uint32_t in_data_excess = 0;
@@ -287,58 +383,127 @@ static int FrameStreamDataFunc(
             data_len = input_len - in_data_offset - in_data_excess;
         } else {
             /* in: relative to start of input data */
-            BUG_ON(so_inspect_offset < offset);
-            const uint32_t in_data_offset = so_inspect_offset - offset;
+            BUG_ON(so_inspect_offset < input_offset);
+            const uint32_t in_data_offset = so_inspect_offset - input_offset;
             data += in_data_offset;
             data_len = input_len - in_data_offset;
         }
     }
     // PrintRawDataFp(stdout, data, data_len);
+    SCLogDebug("fsd->transforms %p", fsd->transforms);
     InspectionBufferSetupMulti(buffer, fsd->transforms, data, data_len);
     SCLogDebug("inspect_offset %" PRIu64, fo_inspect_offset);
     buffer->inspect_offset = fo_inspect_offset;
     buffer->flags = ci_flags;
-    fsd->buffer = buffer;
-    fsd->det_ctx->frame_inspect_progress =
-            MAX(fo_inspect_offset + data_len, fsd->det_ctx->frame_inspect_progress);
-    return 1; // for now only the first chunk
+
+    if (frame->len >= 0 && so_input_re >= so_frame_re) {
+        SCLogDebug("have the full frame, we can set progress accordingly (%" PRIu64 " > %" PRIu64
+                   ")",
+                so_input_re, so_frame_re);
+        fsd->det_ctx->frame_inspect_progress =
+                MAX(fo_inspect_offset + data_len, fsd->det_ctx->frame_inspect_progress);
+    } else {
+        fsd->det_ctx->frame_inspect_progress =
+                MAX(fo_inspect_offset + data_len, fsd->det_ctx->frame_inspect_progress);
+        /* in IPS mode keep a sliding window */
+        const bool ips = StreamTcpInlineMode();
+        if (ips) {
+            if (fsd->det_ctx->frame_inspect_progress < 2500)
+                fsd->det_ctx->frame_inspect_progress = 0;
+            else
+                fsd->det_ctx->frame_inspect_progress -= 2500;
+        }
+        SCLogDebug("ips %s inspect_progress %" PRIu64, BOOL2STR(ips),
+                fsd->det_ctx->frame_inspect_progress);
+    }
+
+    /* keep going as long as there is possibly still data for this frame */
+    const bool ret = (frame->len >= 0 && so_input_re >= so_frame_re);
+    SCLogDebug("buffer set up, more to do: %s", BOOL2STR(ret));
+    return ret;
 }
 
-static 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)
+static int FrameStreamDataInspectFunc(
+        void *cb_data, const uint8_t *input, const uint32_t input_len, const uint64_t input_offset)
 {
-    // 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;
+    struct FrameStreamData *fsd = cb_data;
+    SCLogDebug("inspect: fsd %p { det_ctx:%p, transforms:%p, s:%p, s->id:%u, frame:%p, list_id:%d, "
+               "idx:%u, "
+               "requested_stream_offset:%" PRIu64
+               "}, input: %p, input_len:%u, input_offset:%" PRIu64,
+            fsd, fsd->det_ctx, fsd->transforms, fsd->s, fsd->s->id, fsd->frame, fsd->list_id,
+            fsd->idx, fsd->requested_stream_offset, input, input_len, input_offset);
+    // PrintRawDataFp(stdout, input, input_len);
 
-    BUG_ON(p->flow == NULL);
+    InspectionBuffer *buffer =
+            InspectionBufferMultipleForListGet(fsd->det_ctx, fsd->list_id, fsd->idx++);
+    if (buffer == NULL) {
+        return 0;
+    }
+    SCLogDebug("buffer %p idx %u", buffer, fsd->idx);
 
-    if (p->proto == IPPROTO_UDP) {
-        return DetectFrame2InspectBufferUdp(
-                det_ctx, transforms, p, buffer, frames, frame, list_id, idx, first);
+    /* if we've not done so already, set up the buffer */
+    int more_chunks = 1;
+    if (!buffer->initialized) {
+        more_chunks = BufferSetup(fsd, buffer, input, input_len, input_offset);
+    }
+    DEBUG_VALIDATE_BUG_ON(!buffer->initialized);
+    if (buffer->inspect == NULL) {
+        return more_chunks;
     }
 
-    BUG_ON(p->flow->protoctx == NULL);
-    TcpSession *ssn = p->flow->protoctx;
-    TcpStream *stream;
-    if (PKT_IS_TOSERVER(p)) {
-        stream = &ssn->client;
+    const uint32_t data_len = buffer->inspect_len;
+    const uint8_t *data = buffer->inspect;
+    const uint64_t data_offset = buffer->inspect_offset;
+    DetectEngineThreadCtx *det_ctx = fsd->det_ctx;
+    det_ctx->discontinue_matching = 0;
+    det_ctx->buffer_offset = 0;
+    det_ctx->inspection_recursion_counter = 0;
+
+    const DetectEngineFrameInspectionEngine *engine = fsd->inspect_engine;
+    const Signature *s = fsd->s;
+    Packet *p = fsd->p;
+
+#ifdef DEBUG
+    const uint8_t ci_flags = buffer->flags;
+    SCLogDebug("frame %p offset %" PRIu64 " type %u len %" PRIi64
+               " ci_flags %02x (start:%s, end:%s)",
+            fsd->frame, fsd->frame->offset, fsd->frame->type, fsd->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(fsd->frame->len > 0 && (int64_t)data_len > fsd->frame->len);
+
+    int r = DetectEngineContentInspection(det_ctx->de_ctx, det_ctx, s, engine->smd, p, p->flow,
+            (uint8_t *)data, data_len, data_offset, buffer->flags,
+            DETECT_ENGINE_CONTENT_INSPECTION_MODE_FRAME);
+    if (r == 1) {
+        SCLogDebug("DETECT_ENGINE_INSPECT_SIG_MATCH");
+        fsd->inspect_result = DETECT_ENGINE_INSPECT_SIG_MATCH;
     } else {
-        stream = &ssn->server;
+        SCLogDebug("DETECT_ENGINE_INSPECT_SIG_NO_MATCH");
     }
+    return more_chunks;
+}
 
-    SCLogDebug("frame %" PRIi64 ", len %" PRIi64 ", offset %" PRIu64, frame->id, frame->len,
-            frame->offset);
+static bool SetupStreamCallbackData(struct FrameStreamData *dst, const TcpSession *ssn,
+        const TcpStream *stream, DetectEngineThreadCtx *det_ctx,
+        const DetectEngineTransforms *transforms, const Frames *_frames, const Frame *frame,
+        const int list_id, const bool eof)
+{
+    SCLogDebug("frame %" PRIi64 ", len %" PRIi64 ", offset %" PRIu64 ", inspect_progress %" PRIu64,
+            frame->id, frame->len, frame->offset, frame->inspect_progress);
 
     const uint64_t frame_offset = frame->offset;
-    const bool eof = ssn->state == TCP_CLOSED || PKT_IS_PSEUDOPKT(p);
-    const uint64_t usable = StreamTcpGetUsable(stream, eof);
+    const uint64_t usable = StreamDataRightEdge(stream, eof);
     if (usable <= frame_offset)
-        return NULL;
+        return false;
 
     uint64_t want = frame->inspect_progress;
     if (frame->len == -1) {
@@ -356,26 +521,31 @@ static InspectionBuffer *DetectFrame2InspectBuffer(DetectEngineThreadCtx *det_ct
         }
     }
 
+    const bool ips = StreamTcpInlineMode();
+
     const uint64_t have = usable;
-    if (have < want) {
+    if (!ips && have < want) {
         SCLogDebug("wanted %" PRIu64 " bytes, got %" PRIu64, want, have);
-        return NULL;
+        return false;
     }
 
     const uint64_t available_data = usable - STREAM_BASE_OFFSET(stream);
     SCLogDebug("check inspection for having 2500 bytes: %" PRIu64, available_data);
-    if (!eof && available_data < 2500 && (frame->len < 0 || frame->len > (int64_t)available_data)) {
+    if (!ips && !eof && available_data < 2500 &&
+            (frame->len < 0 || frame->len > (int64_t)available_data)) {
         SCLogDebug("skip inspection until we have 2500 bytes (have %" PRIu64 ")", available_data);
-        return NULL;
+        return false;
     }
 
-    const uint64_t offset = MAX(STREAM_BASE_OFFSET(stream), frame->offset);
-
-    struct FrameStreamData fsd = { det_ctx, transforms, frame, list_id, idx,
-        STREAM_BASE_OFFSET(stream), MAX(frame->inspect_progress, frame->offset), NULL };
-    StreamReassembleForFrame(ssn, stream, FrameStreamDataFunc, &fsd, offset, eof);
+    const uint64_t offset =
+            MAX(STREAM_BASE_OFFSET(stream), frame->offset + frame->inspect_progress);
 
-    return fsd.buffer;
+    dst->det_ctx = det_ctx;
+    dst->transforms = transforms;
+    dst->frame = frame;
+    dst->list_id = list_id;
+    dst->requested_stream_offset = offset;
+    return true;
 }
 
 /**
@@ -392,56 +562,48 @@ static InspectionBuffer *DetectFrame2InspectBuffer(DetectEngineThreadCtx *det_ct
  */
 int DetectEngineInspectFrameBufferGeneric(DetectEngineThreadCtx *det_ctx,
         const DetectEngineFrameInspectionEngine *engine, const Signature *s, Packet *p,
-        const Frames *frames, const Frame *frame, const uint32_t idx)
+        const Frames *frames, const Frame *frame)
 {
-    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 int list_id = engine->sm_list;
+    SCLogDebug("running inspect on %d", list_id);
 
-    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;
+    if (p->proto == IPPROTO_UDP) {
+        return DetectFrameInspectUdp(det_ctx, engine, s, transforms, p, frames, frame, list_id);
     }
+    DEBUG_VALIDATE_BUG_ON(p->proto != IPPROTO_TCP);
 
-    const uint32_t data_len = buffer->inspect_len;
-    const uint8_t *data = buffer->inspect;
-    const uint64_t offset = buffer->inspect_offset;
+    SCLogDebug("packet:%" PRIu64 ", frame->id:%" PRIu64
+               ", list:%d, transforms:%p, s:%p, s->id:%u, engine:%p",
+            p->pcap_cnt, frame->id, engine->sm_list, engine->v1.transforms, s, s->id, engine);
 
-    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 offset %" PRIu64 " type %u len %" PRIi64
-               " ci_flags %02x (start:%s, end:%s)",
-            frame, frame->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(frame->len > 0 && (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;
+    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;
+    }
+    const bool eof = ssn->state == TCP_CLOSED || PKT_IS_PSEUDOPKT(p);
+
+    struct FrameStreamData fsd;
+    memset(&fsd, 0, sizeof(fsd));
+    fsd.inspect_engine = engine;
+    fsd.s = s;
+    fsd.inspect_result = DETECT_ENGINE_INSPECT_SIG_NO_MATCH;
+    fsd.p = p;
+
+    if (SetupStreamCallbackData(
+                &fsd, ssn, stream, det_ctx, transforms, frames, frame, list_id, eof) == false) {
         return DETECT_ENGINE_INSPECT_SIG_NO_MATCH;
     }
+    StreamReassembleForFrame(
+            ssn, stream, FrameStreamDataInspectFunc, &fsd, fsd.requested_stream_offset, eof);
+
+    return fsd.inspect_result;
 }
index 9fe2385b150fcf859c946a4608c1b3c113ba335c..391a6eebda5b23fb21e620190e26348cf386f354 100644 (file)
 #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);
+        const Frames *frames, const Frame *frame, const AppProto alproto);
 int DetectRunFrameInspectRule(ThreadVars *tv, DetectEngineThreadCtx *det_ctx, const Signature *s,
-        Flow *f, Packet *p, const Frames *frames, const Frame *frame, const uint32_t idx);
+        Flow *f, Packet *p, const Frames *frames, const Frame *frame);
 
 int PrefilterGenericMpmFrameRegister(DetectEngineCtx *de_ctx, SigGroupHead *sgh, MpmCtx *mpm_ctx,
         const DetectBufferMpmRegistery *mpm_reg, int list_id);
 int DetectEngineInspectFrameBufferGeneric(DetectEngineThreadCtx *det_ctx,
         const DetectEngineFrameInspectionEngine *engine, const Signature *s, Packet *p,
-        const Frames *frames, const Frame *frame, const uint32_t idx);
+        const Frames *frames, const Frame *frame);
index 69bb66955fa1d82e1fe076be2208a0823a348a75..e195570877ede858592b3516d0cf2e3817095b10 100644 (file)
@@ -1577,7 +1577,7 @@ static void DetectRunFrames(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngin
         /* 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);
+            DetectRunPrefilterFrame(det_ctx, sgh, p, frames, frame, alproto);
             //            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);
@@ -1641,7 +1641,7 @@ static void DetectRunFrames(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngin
             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);
+                r = DetectRunFrameInspectRule(tv, det_ctx, s, f, p, frames, frame);
                 if (r == 1) {
                     /* match */
                     DetectRunPostMatch(tv, det_ctx, p, s);
index e91ab2c46dd50f1cc160334217b63c8aa33d2d26..5f6d90242b9a71ee501ab15bceb3ab00a72851be 100644 (file)
@@ -463,7 +463,7 @@ struct DetectEngineFrameInspectionEngine;
  */
 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);
+        Packet *p, const struct Frames *frames, const struct Frame *frame);
 
 typedef struct DetectEngineFrameInspectionEngine {
     AppProto alproto;
@@ -1298,7 +1298,7 @@ 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);
+        const struct Frames *frames, const struct Frame *frame);
 
 typedef struct AppLayerTxData AppLayerTxData;
 typedef void (*PrefilterTxFn)(DetectEngineThreadCtx *det_ctx, const void *pectx, Packet *p, Flow *f,