• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

jasonish / suricata / 23219085698

17 Mar 2026 10:19PM UTC coverage: 79.288% (-0.02%) from 79.305%
23219085698

push

github

jasonish
rust: disable clippy warning for manual c str literals

Disable the clippy warning for not using modern C string
literals. Ubuntu 24.04 still ships cbindgen 0.26.0 that doesn't
support these, so migrating to modern C string literals would require
Ubuntu 24.04 users wishing to build from git to install cbindgen with
cargo.

265860 of 335311 relevant lines covered (79.29%)

5085768.94 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

93.96
/src/detect-engine-frame.c
1
/* Copyright (C) 2021-2023 Open Information Security Foundation
2
 *
3
 * You can copy, redistribute or modify this Program under the terms of
4
 * the GNU General Public License version 2 as published by the Free
5
 * Software Foundation.
6
 *
7
 * This program is distributed in the hope that it will be useful,
8
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10
 * GNU General Public License for more details.
11
 *
12
 * You should have received a copy of the GNU General Public License
13
 * version 2 along with this program; if not, write to the Free Software
14
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15
 * 02110-1301, USA.
16
 */
17

18
/**
19
 * \file
20
 *
21
 * \author Victor Julien <victor@inliniac.net>
22
 *
23
 */
24

25
#include "suricata-common.h"
26
#include "suricata.h"
27

28
#include "app-layer-parser.h"
29
#include "rust.h"
30
#include "app-layer-frames.h"
31

32
#include "detect-engine.h"
33
#include "detect-engine-prefilter.h"
34
#include "detect-engine-content-inspection.h"
35
#include "detect-engine-mpm.h"
36
#include "detect-engine-frame.h"
37

38
#include "stream-tcp.h"
39

40
#include "util-profiling.h"
41
#include "util-validate.h"
42
#include "util-print.h"
43

44
struct FrameStreamData {
45
    // shared between prefilter and inspect
46
    DetectEngineThreadCtx *det_ctx;
47
    const DetectEngineTransforms *transforms;
48
    const Frame *frame;
49
    int list_id;
50
    uint32_t idx; /**< multi buffer idx, incremented for each stream chunk */
51

52
    // inspection only
53
    const DetectEngineFrameInspectionEngine *inspect_engine;
54
    const Signature *s;
55
    int inspect_result; // DETECT_ENGINE_INSPECT_SIG_MATCH / DETECT_ENGINE_INSPECT_SIG_NO_MATCH
56
    Packet *p;
57

58
    // prefilter only
59
    const MpmCtx *mpm_ctx;
60

61
    uint64_t requested_stream_offset;
62
};
63

64
static bool SetupStreamCallbackData(struct FrameStreamData *dst, const TcpSession *ssn,
65
        const TcpStream *stream, DetectEngineThreadCtx *det_ctx,
66
        const DetectEngineTransforms *transforms, const Frames *_frames, const Frame *frame,
67
        const int list_id, const bool eof);
68

69
static bool BufferSetup(struct FrameStreamData *fsd, InspectionBuffer *buffer, const uint8_t *input,
70
        const uint32_t input_len, const uint64_t input_offset);
71
static void BufferSetupUdp(DetectEngineThreadCtx *det_ctx, InspectionBuffer *buffer,
72
        const Frame *frame, const Packet *p, const DetectEngineTransforms *transforms);
73

74
void DetectRunPrefilterFrame(DetectEngineThreadCtx *det_ctx, const SigGroupHead *sgh, Packet *p,
75
        const Frames *frames, const Frame *frame, const AppProto alproto)
76
{
838,991✔
77
    SCLogDebug("pcap_cnt %" PRIu64, PcapPacketCntGet(p));
838,991✔
78
    PrefilterEngine *engine = sgh->frame_engines;
838,991✔
79
    do {
1,098,496✔
80
        if ((engine->alproto == alproto || engine->alproto == ALPROTO_UNKNOWN) &&
1,098,496✔
81
                (engine->ctx.frame_type == frame->type ||
1,098,496✔
82
                        engine->ctx.frame_type == FRAME_ANY_TYPE)) {
886,513✔
83
            SCLogDebug("frame %p engine %p", frame, engine);
291,344✔
84
            PREFILTER_PROFILING_START(det_ctx);
291,344✔
85
            engine->cb.PrefilterFrame(det_ctx, engine->pectx, p, frames, frame);
291,344✔
86
            PREFILTER_PROFILING_END(det_ctx, engine->gid);
291,344✔
87
        }
291,344✔
88
        if (engine->is_last)
1,098,496✔
89
            break;
838,991✔
90
        engine++;
259,505✔
91
    } while (1);
259,505✔
92
}
838,991✔
93

94
/* generic mpm for frame engines */
95

96
// TODO same as Generic?
97
typedef struct PrefilterMpmFrameCtx {
98
    int list_id;
99
    const MpmCtx *mpm_ctx;
100
    const DetectEngineTransforms *transforms;
101
} PrefilterMpmFrameCtx;
102

103
static int FrameStreamDataPrefilterFunc(
104
        void *cb_data, const uint8_t *input, const uint32_t input_len, const uint64_t input_offset)
105
{
202,077✔
106
    struct FrameStreamData *fsd = cb_data;
202,077✔
107
    SCLogDebug("prefilter: fsd %p { det_ctx:%p, transforms:%p, frame:%p, list_id:%d, idx:%u, "
202,077✔
108
               "data_offset:%" PRIu64 "}, input: %p, input_len:%u, input_offset:%" PRIu64,
202,077✔
109
            fsd, fsd->det_ctx, fsd->transforms, fsd->frame, fsd->list_id, fsd->idx,
202,077✔
110
            fsd->requested_stream_offset, input, input_len, input_offset);
202,077✔
111
    // PrintRawDataFp(stdout, input, input_len);
112

113
    InspectionBuffer *buffer =
202,077✔
114
            InspectionBufferMultipleForListGet(fsd->det_ctx, fsd->list_id, fsd->idx++);
202,077✔
115
    if (buffer == NULL) {
202,077✔
116
        return 0;
×
117
    }
×
118
    SCLogDebug("buffer %p idx %u", buffer, fsd->idx);
202,077✔
119

120
    const int more_chunks = BufferSetup(fsd, buffer, input, input_len, input_offset);
202,077✔
121

122
    const uint32_t data_len = buffer->inspect_len;
202,077✔
123
    const uint8_t *data = buffer->inspect;
202,077✔
124
    DetectEngineThreadCtx *det_ctx = fsd->det_ctx;
202,077✔
125
    const MpmCtx *mpm_ctx = fsd->mpm_ctx;
202,077✔
126

127
    if (data != NULL && data_len >= mpm_ctx->minlen) {
202,077✔
128
        // PrintRawDataFp(stdout, data, data_len);
129

130
        (void)mpm_table[mpm_ctx->mpm_type].Search(
12,536✔
131
                mpm_ctx, &det_ctx->mtc, &det_ctx->pmq, data, data_len);
12,536✔
132
        SCLogDebug("det_ctx->pmq.rule_id_array_cnt %u", det_ctx->pmq.rule_id_array_cnt);
12,536✔
133
        PREFILTER_PROFILING_ADD_BYTES(det_ctx, data_len);
12,536✔
134
    }
12,536✔
135
    return more_chunks;
202,077✔
136
}
202,077✔
137

138
/** \brief Generic Mpm prefilter callback
139
 *
140
 *  \param det_ctx detection engine thread ctx
141
 *  \param frames container for the frames
142
 *  \param frame frame to inspect
143
 *  \param pectx inspection context
144
 */
145
static void PrefilterMpmFrame(DetectEngineThreadCtx *det_ctx, const void *pectx, Packet *p,
146
        const Frames *frames, const Frame *frame)
147
{
208,072✔
148
    SCEnter();
208,072✔
149

150
    const PrefilterMpmFrameCtx *ctx = (const PrefilterMpmFrameCtx *)pectx;
208,072✔
151
    const MpmCtx *mpm_ctx = ctx->mpm_ctx;
208,072✔
152

153
    SCLogDebug("packet:%" PRIu64 ", prefilter running on list %d -> frame field type %u",
208,072✔
154
            PcapPacketCntGet(p), ctx->list_id, frame->type);
208,072✔
155
    if (p->proto == IPPROTO_UDP) {
208,072✔
156
        // TODO can we use single here? Could it conflict with TCP?
157
        InspectionBuffer *buffer = InspectionBufferMultipleForListGet(det_ctx, ctx->list_id, 0);
524✔
158
        if (buffer == NULL)
524✔
159
            return;
×
160
        DEBUG_VALIDATE_BUG_ON(frame->offset >= p->payload_len);
524✔
161
        if (frame->offset >= p->payload_len)
524✔
162
            return;
×
163

164
        BufferSetupUdp(det_ctx, buffer, frame, p, ctx->transforms);
524✔
165
        const uint32_t data_len = buffer->inspect_len;
524✔
166
        const uint8_t *data = buffer->inspect;
524✔
167

168
        // PrintRawDataFp(stdout, data, data_len);
169

170
        if (data != NULL && data_len >= mpm_ctx->minlen) {
524✔
171
            (void)mpm_table[mpm_ctx->mpm_type].Search(
523✔
172
                    mpm_ctx, &det_ctx->mtc, &det_ctx->pmq, data, data_len);
523✔
173
            SCLogDebug("det_ctx->pmq.rule_id_array_cnt %u", det_ctx->pmq.rule_id_array_cnt);
523✔
174
            PREFILTER_PROFILING_ADD_BYTES(det_ctx, data_len);
523✔
175
        }
523✔
176
    } else if (p->proto == IPPROTO_TCP) {
207,548✔
177
        DEBUG_VALIDATE_BUG_ON(p->flow->protoctx == NULL);
207,548✔
178
        TcpSession *ssn = p->flow->protoctx;
207,548✔
179
        TcpStream *stream;
207,548✔
180
        if (PKT_IS_TOSERVER(p)) {
207,548✔
181
            stream = &ssn->client;
129,449✔
182
        } else {
129,449✔
183
            stream = &ssn->server;
78,099✔
184
        }
78,099✔
185
        const bool eof = ssn->state == TCP_CLOSED || PKT_IS_PSEUDOPKT(p);
207,548✔
186

187
        struct FrameStreamData fsd;
207,548✔
188
        memset(&fsd, 0, sizeof(fsd));
207,548✔
189
        fsd.mpm_ctx = mpm_ctx;
207,548✔
190

191
        if (SetupStreamCallbackData(&fsd, ssn, stream, det_ctx, ctx->transforms, frames, frame,
207,548✔
192
                    ctx->list_id, eof)) {
207,548✔
193
            StreamReassembleForFrame(ssn, stream, FrameStreamDataPrefilterFunc, &fsd,
151,521✔
194
                    fsd.requested_stream_offset, eof);
151,521✔
195
        }
151,521✔
196
    } else {
207,548✔
197
        DEBUG_VALIDATE_BUG_ON(1);
×
198
    }
×
199
    SCLogDebug("packet:%" PRIu64
208,072✔
200
               ", prefilter done running on list %d -> frame field type %u; have %u matches",
208,072✔
201
            PcapPacketCntGet(p), ctx->list_id, frame->type, det_ctx->pmq.rule_id_array_cnt);
208,072✔
202
}
208,072✔
203

204
static void PrefilterMpmFrameFree(void *ptr)
205
{
7,362✔
206
    SCFree(ptr);
7,362✔
207
}
7,362✔
208

209
int PrefilterGenericMpmFrameRegister(DetectEngineCtx *de_ctx, SigGroupHead *sgh, MpmCtx *mpm_ctx,
210
        const DetectBufferMpmRegistry *mpm_reg, int list_id)
211
{
7,362✔
212
    SCEnter();
7,362✔
213
    PrefilterMpmFrameCtx *pectx = SCCalloc(1, sizeof(*pectx));
7,362✔
214
    if (pectx == NULL)
7,362✔
215
        return -1;
×
216
    pectx->list_id = list_id;
7,362✔
217
    BUG_ON(mpm_reg->frame_v1.alproto == ALPROTO_UNKNOWN);
7,362✔
218
    pectx->mpm_ctx = mpm_ctx;
7,362✔
219
    pectx->transforms = &mpm_reg->transforms;
7,362✔
220

221
    int r = PrefilterAppendFrameEngine(de_ctx, sgh, PrefilterMpmFrame, mpm_reg->frame_v1.alproto,
7,362✔
222
            mpm_reg->frame_v1.type, pectx, PrefilterMpmFrameFree, mpm_reg->pname);
7,362✔
223
    if (r != 0) {
7,362✔
224
        SCFree(pectx);
×
225
    }
×
226
    return r;
7,362✔
227
}
7,362✔
228

229
bool DetectRunFrameInspectRule(ThreadVars *tv, DetectEngineThreadCtx *det_ctx, const Signature *s,
230
        Flow *f, Packet *p, const Frames *frames, const Frame *frame)
231
{
29,347✔
232
    DEBUG_VALIDATE_BUG_ON(s->frame_inspect == NULL);
29,347✔
233

234
    SCLogDebug("inspecting rule %u against frame %p/%" PRIi64 "/%s", s->id, frame, frame->id,
29,347✔
235
            AppLayerParserGetFrameNameById(f->proto, f->alproto, frame->type));
29,347✔
236

237
    for (DetectEngineFrameInspectionEngine *e = s->frame_inspect; e != NULL; e = e->next) {
56,475✔
238
        if (frame->type == e->type) {
29,712✔
239
            // TODO check alproto, direction?
240

241
            // TODO there should be only one inspect engine for this frame, ever?
242

243
            if (e->v1.Callback(det_ctx, e, s, p, frames, frame)) {
29,712✔
244
                SCLogDebug("sid %u: e %p Callback returned true", s->id, e);
2,584✔
245
                return true;
2,584✔
246
            }
2,584✔
247
            SCLogDebug("sid %u: e %p Callback returned false", s->id, e);
27,128✔
248
        } else {
27,128✔
249
            SCLogDebug(
×
250
                    "sid %u: e %p not for frame type %u (want %u)", s->id, e, frame->type, e->type);
×
251
        }
×
252
    }
29,712✔
253
    return false;
26,763✔
254
}
29,347✔
255

256
static void BufferSetupUdp(DetectEngineThreadCtx *det_ctx, InspectionBuffer *buffer,
257
        const Frame *frame, const Packet *p, const DetectEngineTransforms *transforms)
258
{
524✔
259
    uint8_t ci_flags = DETECT_CI_FLAGS_START;
524✔
260
    uint32_t frame_len;
524✔
261
    if (frame->len == -1) {
524✔
262
        frame_len = (uint32_t)(p->payload_len - frame->offset);
×
263
    } else {
524✔
264
        frame_len = (uint32_t)frame->len;
524✔
265
    }
524✔
266
    if (frame->offset + frame_len > p->payload_len) {
524✔
267
        frame_len = (uint32_t)(p->payload_len - frame->offset);
×
268
    } else {
524✔
269
        ci_flags |= DETECT_CI_FLAGS_END;
524✔
270
    }
524✔
271
    const uint8_t *data = p->payload + frame->offset;
524✔
272
    const uint32_t data_len = frame_len;
524✔
273

274
    SCLogDebug("packet %" PRIu64 " -> frame %p/%" PRIi64 "/%s offset %" PRIu64
524✔
275
               " type %u len %" PRIi64,
524✔
276
            PcapPacketCntGet(p), frame, frame->id,
524✔
277
            AppLayerParserGetFrameNameById(p->flow->proto, p->flow->alproto, frame->type),
524✔
278
            frame->offset, frame->type, frame->len);
524✔
279

280
    InspectionBufferSetupMulti(det_ctx, buffer, transforms, data, data_len);
524✔
281
    buffer->inspect_offset = 0;
524✔
282
    buffer->flags = ci_flags;
524✔
283
}
524✔
284

285
/** \internal
286
 *  \brief setup buffer based on frame in UDP payload
287
 */
288
static int DetectFrameInspectUdp(DetectEngineThreadCtx *det_ctx,
289
        const DetectEngineFrameInspectionEngine *engine, const Signature *s,
290
        const DetectEngineTransforms *transforms, Packet *p, const Frames *_frames,
291
        const Frame *frame, const int list_id)
292
{
424✔
293
    SCLogDebug("packet:%" PRIu64 ", inspect: s:%p s->id:%u, transforms:%p", PcapPacketCntGet(p), s,
424✔
294
            s->id, transforms);
424✔
295

296
    // TODO can we use single here? Could it conflict with TCP?
297
    InspectionBuffer *buffer = InspectionBufferMultipleForListGet(det_ctx, list_id, 0);
424✔
298
    if (buffer == NULL)
424✔
299
        return DETECT_ENGINE_INSPECT_SIG_NO_MATCH;
×
300

301
    DEBUG_VALIDATE_BUG_ON(frame->offset >= p->payload_len);
424✔
302
    if (frame->offset >= p->payload_len)
424✔
303
        return DETECT_ENGINE_INSPECT_SIG_NO_MATCH;
×
304

305
    if (!buffer->initialized)
424✔
306
        BufferSetupUdp(det_ctx, buffer, frame, p, transforms);
×
307
    DEBUG_VALIDATE_BUG_ON(!buffer->initialized);
424✔
308
    if (buffer->inspect == NULL)
424✔
309
        return DETECT_ENGINE_INSPECT_SIG_NO_MATCH;
×
310

311
    const bool match = DetectEngineContentInspection(det_ctx->de_ctx, det_ctx, s, engine->smd, p,
424✔
312
            p->flow, buffer->inspect, buffer->inspect_len, 0, buffer->flags,
424✔
313
            DETECT_ENGINE_CONTENT_INSPECTION_MODE_FRAME);
424✔
314
    if (match) {
424✔
315
        SCLogDebug("match!");
419✔
316
        return DETECT_ENGINE_INSPECT_SIG_MATCH;
419✔
317
    } else {
419✔
318
        return DETECT_ENGINE_INSPECT_SIG_NO_MATCH;
5✔
319
    }
5✔
320
}
424✔
321

322
/**
323
 *  \retval bool true if callback should run again */
324
static bool BufferSetup(struct FrameStreamData *fsd, InspectionBuffer *buffer, const uint8_t *input,
325
        const uint32_t input_len, const uint64_t input_offset)
326
{
229,326✔
327
    const Frame *frame = fsd->frame;
229,326✔
328
    /* so: relative to start of stream */
329
    const uint64_t so_input_re = input_offset + input_len;
229,326✔
330
    const uint64_t so_frame_re =
229,326✔
331
            frame->offset + (uint64_t)frame->len; // TODO if eof, set to available data?
229,326✔
332
    SCLogDebug("frame offset:%" PRIu64, frame->offset);
229,326✔
333
    const uint8_t *data = input;
229,326✔
334
    uint8_t ci_flags = 0;
229,326✔
335
    uint32_t data_len;
229,326✔
336

337
    /* fo: frame offset; offset relative to start of the frame */
338
    uint64_t fo_inspect_offset = 0;
229,326✔
339

340
    if (frame->offset == 0 && input_offset == 0) {
229,326✔
341
        ci_flags |= DETECT_CI_FLAGS_START;
815✔
342
        SCLogDebug("have frame data start");
815✔
343

344
        if (frame->len >= 0) {
815✔
345
            data_len = MIN(input_len, (uint32_t)frame->len);
290✔
346
            if (data_len == frame->len) {
290✔
347
                ci_flags |= DETECT_CI_FLAGS_END;
231✔
348
                SCLogDebug("have frame data end");
231✔
349
            }
231✔
350
        } else {
722✔
351
            data_len = input_len;
525✔
352
        }
525✔
353
    } else {
228,511✔
354
        const uint64_t so_frame_inspect_offset = frame->inspect_progress + frame->offset;
228,511✔
355
        const uint64_t so_inspect_offset = MAX(input_offset, so_frame_inspect_offset);
228,511✔
356
        fo_inspect_offset = so_inspect_offset - frame->offset;
228,511✔
357

358
        if (frame->offset >= input_offset) {
228,511✔
359
            ci_flags |= DETECT_CI_FLAGS_START;
12,792✔
360
            SCLogDebug("have frame data start");
12,792✔
361
        }
12,792✔
362
        if (frame->len >= 0) {
228,511✔
363
            if (fo_inspect_offset >= (uint64_t)frame->len) {
228,340✔
364
                SCLogDebug("data entirely past frame (%" PRIu64 " > %" PRIi64 ")",
215,357✔
365
                        fo_inspect_offset, frame->len);
215,357✔
366
                InspectionBufferSetupMultiEmpty(buffer);
215,357✔
367
                return false;
215,357✔
368
            }
215,357✔
369

370
            /* in: relative to start of input data */
371
            DEBUG_VALIDATE_BUG_ON(so_inspect_offset < input_offset);
12,983✔
372
            DEBUG_VALIDATE_BUG_ON(so_inspect_offset - input_offset > UINT32_MAX);
12,983✔
373
            const uint32_t in_data_offset = (uint32_t)(so_inspect_offset - input_offset);
12,983✔
374
            data += in_data_offset;
12,983✔
375

376
            uint32_t in_data_excess = 0;
12,983✔
377
            if (so_input_re >= so_frame_re) {
12,983✔
378
                ci_flags |= DETECT_CI_FLAGS_END;
12,501✔
379
                SCLogDebug("have frame data end");
12,501✔
380
                DEBUG_VALIDATE_BUG_ON(so_input_re - so_frame_re > UINT32_MAX);
12,501✔
381
                in_data_excess = (uint32_t)(so_input_re - so_frame_re);
12,501✔
382
            }
12,501✔
383
            data_len = input_len - in_data_offset - in_data_excess;
12,983✔
384
        } else {
12,983✔
385
            /* in: relative to start of input data */
386
            DEBUG_VALIDATE_BUG_ON(so_inspect_offset < input_offset);
171✔
387
            DEBUG_VALIDATE_BUG_ON(so_inspect_offset - input_offset > UINT32_MAX);
171✔
388
            const uint32_t in_data_offset = (uint32_t)(so_inspect_offset - input_offset);
171✔
389
            data += in_data_offset;
171✔
390
            data_len = input_len - in_data_offset;
171✔
391
        }
171✔
392
    }
228,511✔
393
    // PrintRawDataFp(stdout, data, data_len);
394
    SCLogDebug("fsd->transforms %p", fsd->transforms);
13,969✔
395
    InspectionBufferSetupMulti(fsd->det_ctx, buffer, fsd->transforms, data, data_len);
13,969✔
396
    SCLogDebug("inspect_offset %" PRIu64, fo_inspect_offset);
13,969✔
397
    buffer->inspect_offset = fo_inspect_offset;
13,969✔
398
    buffer->flags = ci_flags;
13,969✔
399

400
    if (frame->len >= 0 && so_input_re >= so_frame_re) {
13,969✔
401
        SCLogDebug("have the full frame, we can set progress accordingly (%" PRIu64 " > %" PRIu64
12,732✔
402
                   ")",
12,732✔
403
                so_input_re, so_frame_re);
12,732✔
404
        fsd->det_ctx->frame_inspect_progress =
12,732✔
405
                MAX(fo_inspect_offset + data_len, fsd->det_ctx->frame_inspect_progress);
12,732✔
406
    } else {
12,732✔
407
        fsd->det_ctx->frame_inspect_progress =
1,237✔
408
                MAX(fo_inspect_offset + data_len, fsd->det_ctx->frame_inspect_progress);
1,237✔
409
        /* in IPS mode keep a sliding window */
410
        const bool ips = StreamTcpInlineMode();
1,237✔
411
        if (ips) {
1,237✔
412
            if (fsd->det_ctx->frame_inspect_progress < 2500)
778✔
413
                fsd->det_ctx->frame_inspect_progress = 0;
762✔
414
            else
16✔
415
                fsd->det_ctx->frame_inspect_progress -= 2500;
16✔
416
        }
778✔
417
        SCLogDebug("ips %s inspect_progress %" PRIu64, BOOL2STR(ips),
1,237✔
418
                fsd->det_ctx->frame_inspect_progress);
1,237✔
419
    }
1,237✔
420

421
    /* keep going as long as there is possibly still data for this frame */
422
    const bool ret = (frame->len >= 0 && so_input_re >= so_frame_re);
13,969✔
423
    SCLogDebug("buffer set up, more to do: %s", BOOL2STR(ret));
13,969✔
424
    return ret;
13,969✔
425
}
229,326✔
426

427
static int FrameStreamDataInspectFunc(
428
        void *cb_data, const uint8_t *input, const uint32_t input_len, const uint64_t input_offset)
429
{
29,316✔
430
    struct FrameStreamData *fsd = cb_data;
29,316✔
431
    SCLogDebug("inspect: fsd %p { det_ctx:%p, transforms:%p, s:%p, s->id:%u, frame:%p, list_id:%d, "
29,316✔
432
               "idx:%u, "
29,316✔
433
               "requested_stream_offset:%" PRIu64
29,316✔
434
               "}, input: %p, input_len:%u, input_offset:%" PRIu64,
29,316✔
435
            fsd, fsd->det_ctx, fsd->transforms, fsd->s, fsd->s->id, fsd->frame, fsd->list_id,
29,316✔
436
            fsd->idx, fsd->requested_stream_offset, input, input_len, input_offset);
29,316✔
437
    // PrintRawDataFp(stdout, input, input_len);
438

439
    InspectionBuffer *buffer =
29,316✔
440
            InspectionBufferMultipleForListGet(fsd->det_ctx, fsd->list_id, fsd->idx++);
29,316✔
441
    if (buffer == NULL) {
29,316✔
442
        return 0;
×
443
    }
×
444
    SCLogDebug("buffer %p idx %u", buffer, fsd->idx);
29,316✔
445

446
    /* if we've not done so already, set up the buffer */
447
    int more_chunks = 1;
29,316✔
448
    if (!buffer->initialized) {
29,316✔
449
        more_chunks = BufferSetup(fsd, buffer, input, input_len, input_offset);
27,249✔
450
    }
27,249✔
451
    DEBUG_VALIDATE_BUG_ON(!buffer->initialized);
29,316✔
452
    if (buffer->inspect == NULL) {
29,316✔
453
        return more_chunks;
26,463✔
454
    }
26,463✔
455

456
    const uint32_t data_len = buffer->inspect_len;
2,853✔
457
    const uint8_t *data = buffer->inspect;
2,853✔
458
    const uint64_t data_offset = buffer->inspect_offset;
2,853✔
459
    DetectEngineThreadCtx *det_ctx = fsd->det_ctx;
2,853✔
460

461
    const DetectEngineFrameInspectionEngine *engine = fsd->inspect_engine;
2,853✔
462
    const Signature *s = fsd->s;
2,853✔
463
    Packet *p = fsd->p;
2,853✔
464

465
#ifdef DEBUG
466
    const uint8_t ci_flags = buffer->flags;
467
    SCLogDebug("frame %p offset %" PRIu64 " type %u len %" PRIi64
468
               " ci_flags %02x (start:%s, end:%s)",
469
            fsd->frame, fsd->frame->offset, fsd->frame->type, fsd->frame->len, ci_flags,
470
            (ci_flags & DETECT_CI_FLAGS_START) ? "true" : "false",
471
            (ci_flags & DETECT_CI_FLAGS_END) ? "true" : "false");
472
    SCLogDebug("buffer %p offset %" PRIu64 " len %u ci_flags %02x (start:%s, end:%s)", buffer,
473
            buffer->inspect_offset, buffer->inspect_len, ci_flags,
474
            (ci_flags & DETECT_CI_FLAGS_START) ? "true" : "false",
475
            (ci_flags & DETECT_CI_FLAGS_END) ? "true" : "false");
476
    // PrintRawDataFp(stdout, data, data_len);
477
    // PrintRawDataFp(stdout, data, MIN(64, data_len));
478
#endif
479
    DEBUG_VALIDATE_BUG_ON(fsd->frame->len > 0 && (int64_t)data_len > fsd->frame->len);
2,853✔
480

481
    const bool match = DetectEngineContentInspection(det_ctx->de_ctx, det_ctx, s, engine->smd, p,
2,853✔
482
            p->flow, data, data_len, data_offset, buffer->flags,
2,853✔
483
            DETECT_ENGINE_CONTENT_INSPECTION_MODE_FRAME);
2,853✔
484
    if (match) {
2,853✔
485
        SCLogDebug("DETECT_ENGINE_INSPECT_SIG_MATCH");
2,165✔
486
        fsd->inspect_result = DETECT_ENGINE_INSPECT_SIG_MATCH;
2,165✔
487
    } else {
2,165✔
488
        SCLogDebug("DETECT_ENGINE_INSPECT_SIG_NO_MATCH");
688✔
489
    }
688✔
490
    return more_chunks;
2,853✔
491
}
29,316✔
492

493
static bool SetupStreamCallbackData(struct FrameStreamData *dst, const TcpSession *ssn,
494
        const TcpStream *stream, DetectEngineThreadCtx *det_ctx,
495
        const DetectEngineTransforms *transforms, const Frames *_frames, const Frame *frame,
496
        const int list_id, const bool eof)
497
{
236,836✔
498
    SCLogDebug("frame %" PRIi64 ", len %" PRIi64 ", offset %" PRIu64 ", inspect_progress %" PRIu64,
236,836✔
499
            frame->id, frame->len, frame->offset, frame->inspect_progress);
236,836✔
500

501
    const uint64_t frame_offset = frame->offset;
236,836✔
502
    const uint64_t usable = StreamDataRightEdge(stream, eof);
236,836✔
503
    if (usable <= frame_offset)
236,836✔
504
        return false;
16✔
505

506
    uint64_t want = frame->inspect_progress;
236,820✔
507
    if (frame->len == -1) {
236,820✔
508
        if (eof) {
56,691✔
509
            want = usable;
60✔
510
        } else {
56,631✔
511
            want += 2500;
56,631✔
512
        }
56,631✔
513
    } else {
180,129✔
514
        /* don't have the full frame yet */
515
        if (frame->offset + frame->len > usable) {
180,129✔
516
            want += 2500;
580✔
517
        } else {
179,549✔
518
            want = frame->offset + frame->len;
179,549✔
519
        }
179,549✔
520
    }
180,129✔
521

522
    const bool ips = StreamTcpInlineMode();
236,820✔
523

524
    const uint64_t have = usable;
236,820✔
525
    if (!ips && have < want) {
236,820✔
526
        SCLogDebug("wanted %" PRIu64 " bytes, got %" PRIu64, want, have);
56,073✔
527
        return false;
56,073✔
528
    }
56,073✔
529

530
    const uint64_t available_data = usable - STREAM_BASE_OFFSET(stream);
180,747✔
531
    SCLogDebug("check inspection for having 2500 bytes: %" PRIu64, available_data);
180,747✔
532
    if (!ips && !eof && available_data < 2500 &&
180,747✔
533
            (frame->len < 0 || frame->len > (int64_t)available_data)) {
180,747✔
534
        SCLogDebug("skip inspection until we have 2500 bytes (have %" PRIu64 ")", available_data);
×
535
        return false;
×
536
    }
×
537

538
    const uint64_t offset =
180,747✔
539
            MAX(STREAM_BASE_OFFSET(stream), frame->offset + frame->inspect_progress);
180,747✔
540

541
    dst->det_ctx = det_ctx;
180,747✔
542
    dst->transforms = transforms;
180,747✔
543
    dst->frame = frame;
180,747✔
544
    dst->list_id = list_id;
180,747✔
545
    dst->requested_stream_offset = offset;
180,747✔
546
    return true;
180,747✔
547
}
180,747✔
548

549
/**
550
 * \brief Do the content inspection & validation for a signature
551
 *
552
 * \param de_ctx Detection engine context
553
 * \param det_ctx Detection engine thread context
554
 * \param s Signature to inspect
555
 * \param p Packet
556
 * \param frame stream frame to inspect
557
 *
558
 * \retval 0 no match.
559
 * \retval 1 match.
560
 */
561
int DetectEngineInspectFrameBufferGeneric(DetectEngineThreadCtx *det_ctx,
562
        const DetectEngineFrameInspectionEngine *engine, const Signature *s, Packet *p,
563
        const Frames *frames, const Frame *frame)
564
{
29,712✔
565
    /* if prefilter didn't already run, we need to consider transformations */
566
    const DetectEngineTransforms *transforms = NULL;
29,712✔
567
    if (!engine->mpm) {
29,712✔
568
        transforms = engine->v1.transforms;
272✔
569
    }
272✔
570
    const int list_id = engine->sm_list;
29,712✔
571
    SCLogDebug("running inspect on %d", list_id);
29,712✔
572

573
    if (p->proto == IPPROTO_UDP) {
29,712✔
574
        return DetectFrameInspectUdp(det_ctx, engine, s, transforms, p, frames, frame, list_id);
424✔
575
    }
424✔
576
    DEBUG_VALIDATE_BUG_ON(p->proto != IPPROTO_TCP);
29,288✔
577

578
    SCLogDebug("packet:%" PRIu64 ", frame->id:%" PRIu64
29,288✔
579
               ", list:%d, transforms:%p, s:%p, s->id:%u, engine:%p",
29,288✔
580
            PcapPacketCntGet(p), frame->id, engine->sm_list, engine->v1.transforms, s, s->id,
29,288✔
581
            engine);
29,288✔
582

583
    DEBUG_VALIDATE_BUG_ON(p->flow->protoctx == NULL);
29,288✔
584
    TcpSession *ssn = p->flow->protoctx;
29,288✔
585
    TcpStream *stream;
29,288✔
586
    if (PKT_IS_TOSERVER(p)) {
29,288✔
587
        stream = &ssn->client;
28,656✔
588
    } else {
28,656✔
589
        stream = &ssn->server;
632✔
590
    }
632✔
591
    const bool eof = ssn->state == TCP_CLOSED || PKT_IS_PSEUDOPKT(p);
29,288✔
592

593
    struct FrameStreamData fsd;
29,288✔
594
    memset(&fsd, 0, sizeof(fsd));
29,288✔
595
    fsd.inspect_engine = engine;
29,288✔
596
    fsd.s = s;
29,288✔
597
    fsd.inspect_result = DETECT_ENGINE_INSPECT_SIG_NO_MATCH;
29,288✔
598
    fsd.p = p;
29,288✔
599

600
    if (!SetupStreamCallbackData(
29,288✔
601
                &fsd, ssn, stream, det_ctx, transforms, frames, frame, list_id, eof)) {
29,288✔
602
        return DETECT_ENGINE_INSPECT_SIG_NO_MATCH;
62✔
603
    }
62✔
604
    StreamReassembleForFrame(
29,226✔
605
            ssn, stream, FrameStreamDataInspectFunc, &fsd, fsd.requested_stream_offset, eof);
29,226✔
606

607
    return fsd.inspect_result;
29,226✔
608
}
29,288✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc