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

jasonish / suricata / 22802647571

07 Mar 2026 04:23PM UTC coverage: 75.827% (-3.4%) from 79.233%
22802647571

push

github

jasonish
github-ci: add schema ordering check for yaml schema

253365 of 334137 relevant lines covered (75.83%)

3384729.69 hits per line

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

72.86
/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
{
124✔
33
    PrefilterPacketHeaderCtx *ctx = data;
124✔
34
    uint64_t hash = ctx->v1.u64[0] + ctx->v1.u64[1] + ctx->type + ctx->value;
124✔
35
    hash %= ht->array_size;
124✔
36
    return (uint32_t)hash;
124✔
37
}
124✔
38

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

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

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

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

76
static void GetExtraMatch(const Signature *s, uint16_t *type, uint16_t *value)
77
{
148✔
78
    if (s->sp != NULL && s->sp->next == NULL && s->sp->port == s->sp->port2 &&
148✔
79
        !(s->sp->flags & PORT_FLAG_NOT))
148✔
80
    {
×
81
        *type = PREFILTER_EXTRA_MATCH_SRCPORT;
×
82
        *value = s->sp->port;
×
83
    } else if (s->alproto != ALPROTO_UNKNOWN) {
148✔
84
        *type = PREFILTER_EXTRA_MATCH_ALPROTO;
6✔
85
        *value = s->alproto;
6✔
86
    } else if (s->dp != NULL && s->dp->next == NULL && s->dp->port == s->dp->port2 &&
142✔
87
        !(s->dp->flags & PORT_FLAG_NOT))
142✔
88
    {
×
89
        *type = PREFILTER_EXTRA_MATCH_DSTPORT;
×
90
        *value = s->dp->port;
×
91
    }
×
92
}
148✔
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
{
52✔
101
    Signature *s = NULL;
52✔
102
    uint32_t sig = 0;
52✔
103
    uint32_t sig_offset = 0;
52✔
104

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

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

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

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

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

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

138
            s->flags |= SIG_FLAG_PREFILTER;
52✔
139
        }
52✔
140
    }
86✔
141

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

151
/** \internal
152
 *  \brief apply signature to each value */
153
static void ApplyToU8Hash(PrefilterPacketU8HashCtx *ctx, PrefilterPacketHeaderValue v, Signature *s)
154
{
10✔
155
    switch (v.u8[0]) {
10✔
156
        case PREFILTER_U8HASH_MODE_EQ:
7✔
157
            {
7✔
158
                SigsArray *sa = ctx->array[v.u8[1]];
7✔
159
                sa->sigs[sa->offset++] = s->iid;
7✔
160
                break;
7✔
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: {
1✔
173
            uint8_t x = v.u8[1];
1✔
174
            do {
9✔
175
                SigsArray *sa = ctx->array[x];
9✔
176
                sa->sigs[sa->offset++] = s->iid;
9✔
177
            } while (x--);
9✔
178

179
            break;
1✔
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: {
1✔
192
            int x = v.u8[1];
1✔
193
            do {
248✔
194
                SigsArray *sa = ctx->array[x];
248✔
195
                sa->sigs[sa->offset++] = s->iid;
248✔
196
            } while (++x < 256);
248✔
197

198
            break;
1✔
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: {
1✔
211
            for (uint8_t i = 0; i < UINT8_MAX; i++) {
256✔
212
                if (i != v.u8[1]) {
255✔
213
                    SigsArray *sa = ctx->array[i];
254✔
214
                    sa->sigs[sa->offset++] = s->iid;
254✔
215
                }
254✔
216
            }
255✔
217
            if (UINT8_MAX != v.u8[1]) {
1✔
218
                SigsArray *sa = ctx->array[UINT8_MAX];
1✔
219
                sa->sigs[sa->offset++] = s->iid;
1✔
220
            }
1✔
221
            break;
1✔
222
        }
×
223
    }
10✔
224
}
10✔
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
{
50✔
237
    Signature *s = NULL;
50✔
238
    uint32_t sig = 0;
50✔
239
    uint32_t cnt = 0;
50✔
240

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

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

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

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

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

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

279
    if (cnt) {
7✔
280
        enum SignatureHookPkt hook = SIGNATURE_HOOK_PKT_NOT_SET; // TODO review
7✔
281
        PrefilterAppendEngine(de_ctx, sgh, Match, mask, hook, ctx, PrefilterPacketU8HashCtxFree,
7✔
282
                sigmatch_table[sm_type].name);
7✔
283
    } else {
7✔
284
        PrefilterPacketU8HashCtxFree(ctx);
×
285
    }
×
286
    return 0;
7✔
287
}
50✔
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
{
241✔
296
    HashListTableBucket *hb = HashListTableGetListHead(hash_table);
241✔
297
    for ( ; hb != NULL; hb = HashListTableGetListNext(hb)) {
293✔
298
        PrefilterPacketHeaderHashCtx *ctx = HashListTableGetListData(hb);
52✔
299

300
        SetupEngineForPacketHeader(de_ctx, sgh, sm_type, mask, ctx, Compare, Match);
52✔
301
    }
52✔
302
}
241✔
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
{
50✔
312
    uint32_t counts[256];
50✔
313
    memset(&counts, 0, sizeof(counts));
50✔
314

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

319
        switch (ctx->v1.u8[0]) {
10✔
320
            case PREFILTER_U8HASH_MODE_EQ:
7✔
321
                counts[ctx->v1.u8[1]] += ctx->cnt;
7✔
322
                break;
7✔
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: {
1✔
334
                uint8_t v = ctx->v1.u8[1];
1✔
335
                counts[v] += ctx->cnt;
1✔
336
                while (v > 0) {
9✔
337
                    v--;
8✔
338
                    counts[v] += ctx->cnt;
8✔
339
                }
8✔
340

341
                break;
1✔
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: {
1✔
354
                uint8_t v = ctx->v1.u8[1];
1✔
355
                counts[v] += ctx->cnt;
1✔
356
                while (v < UINT8_MAX) {
248✔
357
                    v++;
247✔
358
                    counts[v] += ctx->cnt;
247✔
359
                }
247✔
360

361
                break;
1✔
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: {
1✔
376
                for (uint8_t i = 0; i < UINT8_MAX; i++) {
256✔
377
                    if (i != ctx->v1.u8[1]) {
255✔
378
                        counts[i] += ctx->cnt;
254✔
379
                    }
254✔
380
                }
255✔
381
                if (UINT8_MAX != ctx->v1.u8[1]) {
1✔
382
                    counts[UINT8_MAX] += ctx->cnt;
1✔
383
                }
1✔
384
                break;
1✔
385
            }
×
386
            default:
×
387
                SCLogWarning("Prefilter not implemented for mode 0x%x", ctx->v1.u8[0]);
×
388
        }
10✔
389
    }
10✔
390

391
    SetupEngineForPacketHeaderPrefilterPacketU8HashCtx(
50✔
392
            de_ctx, sgh, sm_type, mask, counts, Set, Compare, Match);
50✔
393
}
50✔
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
{
291✔
400
    Signature *s = NULL;
291✔
401
    uint32_t sig = 0;
291✔
402

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

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

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

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

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

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

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

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

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

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

455
    HashListTableFree(hash_table);
291✔
456
    return 0;
291✔
457
error:
×
458
    HashListTableFree(hash_table);
×
459
    return -1;
×
460
}
291✔
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
{
50✔
467
    return PrefilterSetupPacketHeaderCommon(de_ctx, sgh, sm_type, mask, Set, Compare, Match, true);
50✔
468
}
50✔
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
{
241✔
475
    return PrefilterSetupPacketHeaderCommon(de_ctx, sgh, sm_type, mask, Set, Compare, Match, false);
476
}
241✔
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