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

OISF / suricata / 22550902417

01 Mar 2026 07:32PM UTC coverage: 68.401% (-5.3%) from 73.687%
22550902417

Pull #14922

github

web-flow
github-actions: bump actions/upload-artifact from 6.0.0 to 7.0.0

Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 6.0.0 to 7.0.0.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v6...v7)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: 7.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Pull Request #14922: github-actions: bump actions/upload-artifact from 6.0.0 to 7.0.0

218243 of 319063 relevant lines covered (68.4%)

3284926.58 hits per line

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

0.0
/src/detect-engine-prefilter-common.c
1
/* Copyright (C) 2007-2016 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
#include "suricata-common.h"
19
#include "detect-engine-prefilter.h"
20
#include "detect-engine-prefilter-common.h"
21

22
typedef struct PrefilterPacketHeaderHashCtx_ {
23
    PrefilterPacketHeaderValue v1;
24

25
    uint16_t type;  /**< PREFILTER_EXTRA_MATCH_* */
26
    uint16_t value;
27

28
    uint32_t cnt;
29
} PrefilterPacketHeaderHashCtx;
30

31
static uint32_t PrefilterPacketHeaderHashFunc(HashListTable *ht, void *data, uint16_t datalen)
32
{
×
33
    PrefilterPacketHeaderCtx *ctx = data;
×
34
    uint64_t hash = ctx->v1.u64[0] + ctx->v1.u64[1] + ctx->type + ctx->value;
×
35
    hash %= ht->array_size;
×
36
    return (uint32_t)hash;
×
37
}
×
38

39
static char PrefilterPacketHeaderCompareFunc(void *data1, uint16_t len1,
40
                                       void *data2, uint16_t len2)
41
{
×
42
    PrefilterPacketHeaderHashCtx *ctx1 = data1;
×
43
    PrefilterPacketHeaderHashCtx *ctx2 = data2;
×
44
    return (ctx1->v1.u64[0] == ctx2->v1.u64[0] &&
×
45
            ctx1->v1.u64[1] == ctx2->v1.u64[1] &&
×
46
            ctx1->type == ctx2->type &&
×
47
            ctx1->value == ctx2->value);
×
48
}
×
49

50
static void PrefilterPacketHeaderFreeFunc(void *ptr)
51
{
×
52
    SCFree(ptr);
×
53
}
×
54

55
static void PrefilterPacketHeaderFree(void *pectx)
56
{
×
57
    PrefilterPacketHeaderCtx *ctx = pectx;
×
58
    SCFree(ctx->sigs_array);
×
59
    SCFree(ctx);
×
60
}
×
61

62
static void PrefilterPacketU8HashCtxFree(void *vctx)
63
{
×
64
    PrefilterPacketU8HashCtx *ctx = vctx;
×
65
    int i;
×
66
    for (i = 0; i < 256; i++) {
×
67
        SigsArray *sa = ctx->array[i];
×
68
        if (sa == NULL)
×
69
            continue;
×
70
        SCFree(sa->sigs);
×
71
        SCFree(sa);
×
72
    }
×
73
    SCFree(ctx);
×
74
}
×
75

76
static void GetExtraMatch(const Signature *s, uint16_t *type, uint16_t *value)
77
{
×
78
    if (s->sp != NULL && s->sp->next == NULL && s->sp->port == s->sp->port2 &&
×
79
        !(s->sp->flags & PORT_FLAG_NOT))
×
80
    {
×
81
        *type = PREFILTER_EXTRA_MATCH_SRCPORT;
×
82
        *value = s->sp->port;
×
83
    } else if (s->alproto != ALPROTO_UNKNOWN) {
×
84
        *type = PREFILTER_EXTRA_MATCH_ALPROTO;
×
85
        *value = s->alproto;
×
86
    } else if (s->dp != NULL && s->dp->next == NULL && s->dp->port == s->dp->port2 &&
×
87
        !(s->dp->flags & PORT_FLAG_NOT))
×
88
    {
×
89
        *type = PREFILTER_EXTRA_MATCH_DSTPORT;
×
90
        *value = s->dp->port;
×
91
    }
×
92
}
×
93

94
/** \internal
95
 */
96
static int SetupEngineForPacketHeader(DetectEngineCtx *de_ctx, SigGroupHead *sgh, int sm_type,
97
        SignatureMask mask, PrefilterPacketHeaderHashCtx *hctx,
98
        bool (*Compare)(PrefilterPacketHeaderValue v, void *),
99
        void (*Match)(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx))
100
{
×
101
    Signature *s = NULL;
×
102
    uint32_t sig = 0;
×
103
    uint32_t sig_offset = 0;
×
104

105
    PrefilterPacketHeaderCtx *ctx = SCCalloc(1, sizeof(PrefilterPacketHeaderCtx));
×
106
    if (ctx == NULL)
×
107
        return -1;
×
108

109
    ctx->v1 = hctx->v1;
×
110
    ctx->type = hctx->type;
×
111
    ctx->value = hctx->value;
×
112

113
    ctx->sigs_cnt = hctx->cnt;
×
114
    ctx->sigs_array = SCCalloc(ctx->sigs_cnt, sizeof(SigIntId));
×
115
    if (ctx->sigs_array == NULL) {
×
116
        SCFree(ctx);
×
117
        return -1;
×
118
    }
×
119

120
    for (sig = 0; sig < sgh->init->sig_cnt; sig++) {
×
121
        s = sgh->init->match_array[sig];
×
122
        if (s == NULL)
×
123
            continue;
×
124
        if (s->init_data->prefilter_sm == NULL || s->init_data->prefilter_sm->type != sm_type)
×
125
            continue;
×
126

127
        uint16_t type = 0;
×
128
        uint16_t value = 0;
×
129
        GetExtraMatch(s, &type, &value);
×
130

131
        if (Compare(ctx->v1, s->init_data->prefilter_sm->ctx) &&
×
132
            ctx->type == type && ctx->value == value)
×
133
        {
×
134
            SCLogDebug("appending sid %u on %u", s->id, sig_offset);
×
135
            ctx->sigs_array[sig_offset] = s->iid;
×
136
            sig_offset++;
×
137

138
            s->flags |= SIG_FLAG_PREFILTER;
×
139
        }
×
140
    }
×
141

142
    SCLogDebug("%s: ctx %p extra type %u extra value %u, sig cnt %u",
×
143
            sigmatch_table[sm_type].name, ctx, ctx->type, ctx->value,
×
144
            ctx->sigs_cnt);
×
145
    enum SignatureHookPkt hook = SIGNATURE_HOOK_PKT_NOT_SET; // TODO review
×
146
    PrefilterAppendEngine(de_ctx, sgh, Match, mask, hook, ctx, PrefilterPacketHeaderFree,
×
147
            sigmatch_table[sm_type].name);
×
148
    return 0;
×
149
}
×
150

151
/** \internal
152
 *  \brief apply signature to each value */
153
static void ApplyToU8Hash(PrefilterPacketU8HashCtx *ctx, PrefilterPacketHeaderValue v, Signature *s)
154
{
×
155
    switch (v.u8[0]) {
×
156
        case PREFILTER_U8HASH_MODE_EQ:
×
157
            {
×
158
                SigsArray *sa = ctx->array[v.u8[1]];
×
159
                sa->sigs[sa->offset++] = s->iid;
×
160
                break;
×
161
            }
×
162
        case PREFILTER_U8HASH_MODE_LT:
×
163
            {
×
164
                uint8_t x = v.u8[1] - 1;
×
165
                do {
×
166
                    SigsArray *sa = ctx->array[x];
×
167
                    sa->sigs[sa->offset++] = s->iid;
×
168
                } while (x--);
×
169

170
                break;
×
171
        }
×
172
        case DetectUintModeLte: {
×
173
            uint8_t x = v.u8[1];
×
174
            do {
×
175
                SigsArray *sa = ctx->array[x];
×
176
                sa->sigs[sa->offset++] = s->iid;
×
177
            } while (x--);
×
178

179
            break;
×
180
        }
×
181
        case PREFILTER_U8HASH_MODE_GT:
×
182
            {
×
183
                int x = v.u8[1] + 1;
×
184
                do {
×
185
                    SigsArray *sa = ctx->array[x];
×
186
                    sa->sigs[sa->offset++] = s->iid;
×
187
                } while (++x < 256);
×
188

189
                break;
×
190
        }
×
191
        case DetectUintModeGte: {
×
192
            int x = v.u8[1];
×
193
            do {
×
194
                SigsArray *sa = ctx->array[x];
×
195
                sa->sigs[sa->offset++] = s->iid;
×
196
            } while (++x < 256);
×
197

198
            break;
×
199
        }
×
200
        case PREFILTER_U8HASH_MODE_RA:
×
201
            {
×
202
                int x = v.u8[1] + 1;
×
203
                do {
×
204
                    SigsArray *sa = ctx->array[x];
×
205
                    sa->sigs[sa->offset++] = s->iid;
×
206
                } while (++x < v.u8[2]);
×
207

208
                break;
×
209
        }
×
210
        case DetectUintModeNe: {
×
211
            for (uint8_t i = 0; i < UINT8_MAX; i++) {
×
212
                if (i != v.u8[1]) {
×
213
                    SigsArray *sa = ctx->array[i];
×
214
                    sa->sigs[sa->offset++] = s->iid;
×
215
                }
×
216
            }
×
217
            if (UINT8_MAX != v.u8[1]) {
×
218
                SigsArray *sa = ctx->array[UINT8_MAX];
×
219
                sa->sigs[sa->offset++] = s->iid;
×
220
            }
×
221
            break;
×
222
        }
×
223
    }
×
224
}
×
225

226
/** \internal
227
 *  \brief turn values into a u8 hash map
228
 *  \todo improve error handling
229
 *  \todo deduplicate sigs arrays
230
 */
231
static int SetupEngineForPacketHeaderPrefilterPacketU8HashCtx(DetectEngineCtx *de_ctx,
232
        SigGroupHead *sgh, int sm_type, SignatureMask mask, uint32_t *counts,
233
        void (*Set)(PrefilterPacketHeaderValue *v, void *),
234
        bool (*Compare)(PrefilterPacketHeaderValue v, void *),
235
        void (*Match)(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx))
236
{
×
237
    Signature *s = NULL;
×
238
    uint32_t sig = 0;
×
239
    uint32_t cnt = 0;
×
240

241
    PrefilterPacketU8HashCtx *ctx = SCCalloc(1, sizeof(PrefilterPacketU8HashCtx));
×
242
    if (ctx == NULL)
×
243
        return -1;
×
244

245
    int set_cnt = 0;
×
246
    for (int i = 0; i < 256; i++) {
×
247
        if (counts[i] == 0)
×
248
            continue;
×
249
        ctx->array[i] = SCCalloc(1, sizeof(SigsArray));
×
250
        BUG_ON(ctx->array[i] == NULL);
×
251

252
        ctx->array[i]->cnt = counts[i];
×
253
        ctx->array[i]->sigs = SCCalloc(ctx->array[i]->cnt, sizeof(SigIntId));
×
254
        BUG_ON(ctx->array[i]->sigs == NULL);
×
255
        set_cnt++;
×
256
    }
×
257
    if (set_cnt == 0) {
×
258
        /* not an error */
259
        PrefilterPacketU8HashCtxFree(ctx);
×
260
        return 0;
×
261
    }
×
262

263
    for (sig = 0; sig < sgh->init->sig_cnt; sig++) {
×
264
        s = sgh->init->match_array[sig];
×
265
        if (s == NULL)
×
266
            continue;
×
267
        if (s->init_data->prefilter_sm == NULL || s->init_data->prefilter_sm->type != sm_type)
×
268
            continue;
×
269

270
        PrefilterPacketHeaderValue v;
×
271
        memset(&v, 0, sizeof(v));
×
272
        Set(&v, s->init_data->prefilter_sm->ctx);
×
273

274
        ApplyToU8Hash(ctx, v, s);
×
275
        s->flags |= SIG_FLAG_PREFILTER;
×
276
        cnt++;
×
277
    }
×
278

279
    if (cnt) {
×
280
        enum SignatureHookPkt hook = SIGNATURE_HOOK_PKT_NOT_SET; // TODO review
×
281
        PrefilterAppendEngine(de_ctx, sgh, Match, mask, hook, ctx, PrefilterPacketU8HashCtxFree,
×
282
                sigmatch_table[sm_type].name);
×
283
    } else {
×
284
        PrefilterPacketU8HashCtxFree(ctx);
×
285
    }
×
286
    return 0;
×
287
}
×
288

289
/** \internal
290
 *  \brief setup a engine for each unique value
291
 */
292
static void SetupSingle(DetectEngineCtx *de_ctx, HashListTable *hash_table, SigGroupHead *sgh,
293
        int sm_type, SignatureMask mask, bool (*Compare)(PrefilterPacketHeaderValue v, void *),
294
        void (*Match)(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx))
295
{
×
296
    HashListTableBucket *hb = HashListTableGetListHead(hash_table);
×
297
    for ( ; hb != NULL; hb = HashListTableGetListNext(hb)) {
×
298
        PrefilterPacketHeaderHashCtx *ctx = HashListTableGetListData(hb);
×
299

300
        SetupEngineForPacketHeader(de_ctx, sgh, sm_type, mask, ctx, Compare, Match);
×
301
    }
×
302
}
×
303

304
/** \internal
305
 *  \brief setup a single engine with a hash map for u8 values
306
 */
307
static void SetupU8Hash(DetectEngineCtx *de_ctx, HashListTable *hash_table, SigGroupHead *sgh,
308
        int sm_type, SignatureMask mask, void (*Set)(PrefilterPacketHeaderValue *v, void *),
309
        bool (*Compare)(PrefilterPacketHeaderValue v, void *),
310
        void (*Match)(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx))
311
{
×
312
    uint32_t counts[256];
×
313
    memset(&counts, 0, sizeof(counts));
×
314

315
    HashListTableBucket *hb = HashListTableGetListHead(hash_table);
×
316
    for ( ; hb != NULL; hb = HashListTableGetListNext(hb)) {
×
317
        PrefilterPacketHeaderHashCtx *ctx = HashListTableGetListData(hb);
×
318

319
        switch (ctx->v1.u8[0]) {
×
320
            case PREFILTER_U8HASH_MODE_EQ:
×
321
                counts[ctx->v1.u8[1]] += ctx->cnt;
×
322
                break;
×
323
            case PREFILTER_U8HASH_MODE_LT:
×
324
            {
×
325
                uint8_t v = ctx->v1.u8[1];
×
326
                while (v > 0) {
×
327
                    v--;
×
328
                    counts[v] += ctx->cnt;
×
329
                }
×
330

331
                break;
×
332
            }
×
333
            case DetectUintModeLte: {
×
334
                uint8_t v = ctx->v1.u8[1];
×
335
                counts[v] += ctx->cnt;
×
336
                while (v > 0) {
×
337
                    v--;
×
338
                    counts[v] += ctx->cnt;
×
339
                }
×
340

341
                break;
×
342
            }
×
343
            case PREFILTER_U8HASH_MODE_GT:
×
344
            {
×
345
                uint8_t v = ctx->v1.u8[1];
×
346
                while (v < UINT8_MAX) {
×
347
                    v++;
×
348
                    counts[v] += ctx->cnt;
×
349
                }
×
350

351
                break;
×
352
            }
×
353
            case DetectUintModeGte: {
×
354
                uint8_t v = ctx->v1.u8[1];
×
355
                counts[v] += ctx->cnt;
×
356
                while (v < UINT8_MAX) {
×
357
                    v++;
×
358
                    counts[v] += ctx->cnt;
×
359
                }
×
360

361
                break;
×
362
            }
×
363
            case PREFILTER_U8HASH_MODE_RA:
×
364
            {
×
365
                if (ctx->v1.u8[1] < ctx->v1.u8[2]) {
×
366
                    // ctx->v1.u8[1] is not UINT8_MAX
367
                    uint8_t v = ctx->v1.u8[1] + 1;
×
368
                    while (v < ctx->v1.u8[2]) {
×
369
                        counts[v] += ctx->cnt;
×
370
                        v++;
×
371
                    }
×
372
                }
×
373
                break;
×
374
            }
×
375
            case DetectUintModeNe: {
×
376
                for (uint8_t i = 0; i < UINT8_MAX; i++) {
×
377
                    if (i != ctx->v1.u8[1]) {
×
378
                        counts[i] += ctx->cnt;
×
379
                    }
×
380
                }
×
381
                if (UINT8_MAX != ctx->v1.u8[1]) {
×
382
                    counts[UINT8_MAX] += ctx->cnt;
×
383
                }
×
384
                break;
×
385
            }
×
386
            default:
×
387
                SCLogWarning("Prefilter not implemented for mode 0x%x", ctx->v1.u8[0]);
×
388
        }
×
389
    }
×
390

391
    SetupEngineForPacketHeaderPrefilterPacketU8HashCtx(
×
392
            de_ctx, sgh, sm_type, mask, counts, Set, Compare, Match);
×
393
}
×
394

395
static int PrefilterSetupPacketHeaderCommon(DetectEngineCtx *de_ctx, SigGroupHead *sgh, int sm_type,
396
        SignatureMask mask, void (*Set)(PrefilterPacketHeaderValue *v, void *),
397
        bool (*Compare)(PrefilterPacketHeaderValue v, void *),
398
        void (*Match)(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx), bool u8hash)
399
{
×
400
    Signature *s = NULL;
×
401
    uint32_t sig = 0;
×
402

403
    if (sgh == NULL)
×
404
        return 0;
×
405

406
    /* first count how many engines we will need */
407

408
    HashListTable *hash_table = HashListTableInit(4096,
×
409
            PrefilterPacketHeaderHashFunc,
×
410
            PrefilterPacketHeaderCompareFunc,
×
411
            PrefilterPacketHeaderFreeFunc);
×
412
    if (hash_table == NULL)
×
413
        return -1;
×
414

415
    for (sig = 0; sig < sgh->init->sig_cnt; sig++) {
×
416
        s = sgh->init->match_array[sig];
×
417
        if (s == NULL)
×
418
            continue;
×
419
        if (s->init_data->prefilter_sm == NULL || s->init_data->prefilter_sm->type != sm_type)
×
420
            continue;
×
421

422
        PrefilterPacketHeaderHashCtx ctx;
×
423
        memset(&ctx, 0, sizeof(ctx));
×
424
        Set(&ctx.v1, s->init_data->prefilter_sm->ctx);
×
425

426
        GetExtraMatch(s, &ctx.type, &ctx.value);
×
427

428
        PrefilterPacketHeaderHashCtx *rctx = HashListTableLookup(hash_table, (void *)&ctx, 0);
×
429
        if (rctx != 0) {
×
430
            rctx->cnt++;
×
431
        } else {
×
432
            PrefilterPacketHeaderHashCtx *actx = SCCalloc(1, sizeof(*actx));
×
433
            if (actx == NULL)
×
434
                goto error;
×
435

436
            Set(&actx->v1, s->init_data->prefilter_sm->ctx);
×
437
            actx->cnt = 1;
×
438
            actx->type = ctx.type;
×
439
            actx->value = ctx.value;
×
440

441
            int ret = HashListTableAdd(hash_table, actx, 0);
×
442
            if (ret != 0) {
×
443
                SCFree(actx);
×
444
                goto error;
×
445
            }
×
446
        }
×
447
    }
×
448

449
    if (!u8hash) {
×
450
        SetupSingle(de_ctx, hash_table, sgh, sm_type, mask, Compare, Match);
×
451
    } else {
×
452
        SetupU8Hash(de_ctx, hash_table, sgh, sm_type, mask, Set, Compare, Match);
×
453
    }
×
454

455
    HashListTableFree(hash_table);
×
456
    return 0;
×
457
error:
×
458
    HashListTableFree(hash_table);
×
459
    return -1;
×
460
}
×
461

462
int PrefilterSetupPacketHeaderU8Hash(DetectEngineCtx *de_ctx, SigGroupHead *sgh, int sm_type,
463
        SignatureMask mask, void (*Set)(PrefilterPacketHeaderValue *v, void *),
464
        bool (*Compare)(PrefilterPacketHeaderValue v, void *),
465
        void (*Match)(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx))
466
{
×
467
    return PrefilterSetupPacketHeaderCommon(de_ctx, sgh, sm_type, mask, Set, Compare, Match, true);
×
468
}
×
469

470
int PrefilterSetupPacketHeader(DetectEngineCtx *de_ctx, SigGroupHead *sgh, int sm_type,
471
        SignatureMask mask, void (*Set)(PrefilterPacketHeaderValue *v, void *),
472
        bool (*Compare)(PrefilterPacketHeaderValue v, void *),
473
        void (*Match)(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx))
474
{
×
475
    return PrefilterSetupPacketHeaderCommon(de_ctx, sgh, sm_type, mask, Set, Compare, Match, false);
476
}
×
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