Coverage Report

Created: 2026-02-14 06:42

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/suricata7/src/detect-flowbits.c
Line
Count
Source
1
/* Copyright (C) 2007-2022 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
 *  \author Breno Silva <breno.silva@gmail.com>
23
 *
24
 * Implements the flowbits keyword
25
 */
26
27
#include "suricata-common.h"
28
#include "decode.h"
29
#include "action-globals.h"
30
#include "detect.h"
31
#include "threads.h"
32
#include "flow.h"
33
#include "flow-bit.h"
34
#include "flow-util.h"
35
#include "detect-flowbits.h"
36
#include "util-spm.h"
37
38
#include "app-layer-parser.h"
39
40
#include "detect-parse.h"
41
#include "detect-engine.h"
42
#include "detect-engine-mpm.h"
43
#include "detect-engine-state.h"
44
#include "detect-engine-build.h"
45
46
#include "util-var-name.h"
47
#include "util-unittest.h"
48
#include "util-debug.h"
49
#include "util-conf.h"
50
51
73
#define PARSE_REGEX         "^([a-z]+)(?:,\\s*(.*))?"
52
static DetectParseRegex parse_regex;
53
54
39.8k
#define MAX_TOKENS 100
55
56
int DetectFlowbitMatch (DetectEngineThreadCtx *, Packet *,
57
        const Signature *, const SigMatchCtx *);
58
static int DetectFlowbitSetup (DetectEngineCtx *, Signature *, const char *);
59
static int FlowbitOrAddData(DetectEngineCtx *, DetectFlowbitsData *, char *);
60
void DetectFlowbitFree (DetectEngineCtx *, void *);
61
#ifdef UNITTESTS
62
void FlowBitsRegisterTests(void);
63
#endif
64
65
void DetectFlowbitsRegister (void)
66
73
{
67
73
    sigmatch_table[DETECT_FLOWBITS].name = "flowbits";
68
73
    sigmatch_table[DETECT_FLOWBITS].desc = "operate on flow flag";
69
73
    sigmatch_table[DETECT_FLOWBITS].url = "/rules/flow-keywords.html#flowbits";
70
73
    sigmatch_table[DETECT_FLOWBITS].Match = DetectFlowbitMatch;
71
73
    sigmatch_table[DETECT_FLOWBITS].Setup = DetectFlowbitSetup;
72
73
    sigmatch_table[DETECT_FLOWBITS].Free  = DetectFlowbitFree;
73
#ifdef UNITTESTS
74
    sigmatch_table[DETECT_FLOWBITS].RegisterTests = FlowBitsRegisterTests;
75
#endif
76
    /* this is compatible to ip-only signatures */
77
73
    sigmatch_table[DETECT_FLOWBITS].flags |= SIGMATCH_IPONLY_COMPAT;
78
79
73
    DetectSetupParseRegexes(PARSE_REGEX, &parse_regex);
80
73
}
81
82
static int FlowbitOrAddData(DetectEngineCtx *de_ctx, DetectFlowbitsData *cd, char *arrptr)
83
16.8k
{
84
16.8k
    char *strarr[MAX_TOKENS];
85
16.8k
    char *token;
86
16.8k
    char *saveptr = NULL;
87
16.8k
    uint8_t i = 0;
88
89
57.8k
    while ((token = strtok_r(arrptr, "|", &saveptr))) {
90
        // Check for leading/trailing spaces in the token
91
41.5k
        while(isspace((unsigned char)*token))
92
5.83k
            token++;
93
41.5k
        if (*token == 0)
94
1.14k
            goto next;
95
40.4k
        char *end = token + strlen(token) - 1;
96
42.0k
        while(end > token && isspace((unsigned char)*end))
97
1.66k
            *(end--) = '\0';
98
99
        // Check for spaces in between the flowbit names
100
40.4k
        if (strchr(token, ' ') != NULL) {
101
528
            SCLogError("Spaces are not allowed in flowbit names.");
102
528
            return -1;
103
528
        }
104
105
39.8k
        if (i == MAX_TOKENS) {
106
1
            SCLogError("Number of flowbits exceeds "
107
1
                       "maximum allowed: %d.",
108
1
                    MAX_TOKENS);
109
1
            return -1;
110
1
        }
111
39.8k
        strarr[i++] = token;
112
41.0k
    next:
113
41.0k
        arrptr = NULL;
114
41.0k
    }
115
16.3k
    if (i == 0) {
116
2
        SCLogError("No valid flowbits specified");
117
2
        return -1;
118
2
    }
119
120
16.3k
    cd->or_list_size = i;
121
16.3k
    cd->or_list = SCCalloc(cd->or_list_size, sizeof(uint32_t));
122
16.3k
    if (unlikely(cd->or_list == NULL))
123
0
        return -1;
124
55.8k
    for (uint8_t j = 0; j < cd->or_list_size ; j++) {
125
39.5k
        cd->or_list[j] = VarNameStoreRegister(strarr[j], VAR_TYPE_FLOW_BIT);
126
39.5k
        de_ctx->max_fb_id = MAX(cd->or_list[j], de_ctx->max_fb_id);
127
39.5k
    }
128
129
16.3k
    return 1;
130
16.3k
}
131
132
static int DetectFlowbitMatchToggle (Packet *p, const DetectFlowbitsData *fd)
133
3.02k
{
134
3.02k
    if (p->flow == NULL)
135
44
        return 0;
136
137
2.98k
    FlowBitToggle(p->flow,fd->idx);
138
139
2.98k
    return 1;
140
3.02k
}
141
142
static int DetectFlowbitMatchUnset (Packet *p, const DetectFlowbitsData *fd)
143
14.5k
{
144
14.5k
    if (p->flow == NULL)
145
569
        return 0;
146
147
13.9k
    FlowBitUnset(p->flow,fd->idx);
148
149
13.9k
    return 1;
150
14.5k
}
151
152
static int DetectFlowbitMatchSet (Packet *p, const DetectFlowbitsData *fd)
153
16.3k
{
154
16.3k
    if (p->flow == NULL)
155
2.94k
        return 0;
156
157
13.3k
    FlowBitSet(p->flow,fd->idx);
158
159
13.3k
    return 1;
160
16.3k
}
161
162
static int DetectFlowbitMatchIsset (Packet *p, const DetectFlowbitsData *fd)
163
153k
{
164
153k
    if (p->flow == NULL)
165
0
        return 0;
166
153k
    if (fd->or_list_size > 0) {
167
172k
        for (uint8_t i = 0; i < fd->or_list_size; i++) {
168
160k
            if (FlowBitIsset(p->flow, fd->or_list[i]) == 1)
169
136k
                return 1;
170
160k
        }
171
11.6k
        return 0;
172
148k
    }
173
174
5.54k
    return FlowBitIsset(p->flow,fd->idx);
175
153k
}
176
177
static int DetectFlowbitMatchIsnotset (Packet *p, const DetectFlowbitsData *fd)
178
186k
{
179
186k
    if (p->flow == NULL)
180
0
        return 0;
181
186k
    if (fd->or_list_size > 0) {
182
280k
        for (uint8_t i = 0; i < fd->or_list_size; i++) {
183
280k
            if (FlowBitIsnotset(p->flow, fd->or_list[i]) == 1)
184
146k
                return 1;
185
280k
        }
186
152
        return 0;
187
146k
    }
188
39.2k
    return FlowBitIsnotset(p->flow,fd->idx);
189
186k
}
190
191
/*
192
 * returns 0: no match
193
 *         1: match
194
 *        -1: error
195
 */
196
197
int DetectFlowbitMatch (DetectEngineThreadCtx *det_ctx, Packet *p,
198
        const Signature *s, const SigMatchCtx *ctx)
199
325k
{
200
325k
    const DetectFlowbitsData *fd = (const DetectFlowbitsData *)ctx;
201
325k
    if (fd == NULL)
202
0
        return 0;
203
204
325k
    switch (fd->cmd) {
205
143k
        case DETECT_FLOWBITS_CMD_ISSET:
206
143k
            return DetectFlowbitMatchIsset(p,fd);
207
155k
        case DETECT_FLOWBITS_CMD_ISNOTSET:
208
155k
            return DetectFlowbitMatchIsnotset(p,fd);
209
16.3k
        case DETECT_FLOWBITS_CMD_SET:
210
16.3k
            return DetectFlowbitMatchSet(p,fd);
211
9.35k
        case DETECT_FLOWBITS_CMD_UNSET:
212
9.35k
            return DetectFlowbitMatchUnset(p,fd);
213
1.13k
        case DETECT_FLOWBITS_CMD_TOGGLE:
214
1.13k
            return DetectFlowbitMatchToggle(p,fd);
215
0
        default:
216
0
            SCLogError("unknown cmd %" PRIu32 "", fd->cmd);
217
0
            return 0;
218
325k
    }
219
220
0
    return 0;
221
325k
}
222
223
static int DetectFlowbitParse(const char *str, char *cmd, int cmd_len, char *name,
224
    int name_len)
225
166k
{
226
166k
    int rc;
227
166k
    size_t pcre2len;
228
166k
    pcre2_match_data *match = NULL;
229
230
166k
    int count = DetectParsePcreExec(&parse_regex, &match, str, 0, 0);
231
166k
    if (count != 2 && count != 3) {
232
339
        SCLogError("\"%s\" is not a valid setting for flowbits.", str);
233
339
        goto error;
234
339
    }
235
236
165k
    pcre2len = cmd_len;
237
165k
    rc = pcre2_substring_copy_bynumber(match, 1, (PCRE2_UCHAR8 *)cmd, &pcre2len);
238
165k
    if (rc < 0) {
239
570
        SCLogError("pcre2_substring_copy_bynumber failed");
240
570
        goto error;
241
570
    }
242
243
165k
    if (count == 3) {
244
130k
        pcre2len = name_len;
245
130k
        rc = pcre2_substring_copy_bynumber(match, 2, (PCRE2_UCHAR8 *)name, &pcre2len);
246
130k
        if (rc < 0) {
247
449
            SCLogError("pcre2_substring_copy_bynumber failed");
248
449
            goto error;
249
449
        }
250
251
        /* Trim trailing whitespace. */
252
130k
        while (strlen(name) > 0 && isblank(name[strlen(name) - 1])) {
253
581
            name[strlen(name) - 1] = '\0';
254
581
        }
255
256
130k
        if (strchr(name, '|') == NULL) {
257
            /* Validate name, spaces are not allowed. */
258
1.73M
            for (size_t i = 0; i < strlen(name); i++) {
259
1.64M
                if (isblank(name[i])) {
260
3.89k
                    SCLogError("spaces not allowed in flowbit names");
261
3.89k
                    goto error;
262
3.89k
                }
263
1.64M
            }
264
96.4k
        }
265
130k
    }
266
267
165k
    pcre2_match_data_free(match);
268
161k
    return 1;
269
270
5.24k
error:
271
5.24k
    if (match) {
272
5.24k
        pcre2_match_data_free(match);
273
5.24k
    }
274
5.24k
    return 0;
275
165k
}
276
277
int DetectFlowbitSetup (DetectEngineCtx *de_ctx, Signature *s, const char *rawstr)
278
88.7k
{
279
88.7k
    DetectFlowbitsData *cd = NULL;
280
88.7k
    SigMatch *sm = NULL;
281
88.7k
    uint8_t fb_cmd = 0;
282
88.7k
    char fb_cmd_str[16] = "", fb_name[256] = "";
283
284
88.7k
    if (!DetectFlowbitParse(rawstr, fb_cmd_str, sizeof(fb_cmd_str), fb_name,
285
88.7k
            sizeof(fb_name))) {
286
2.76k
        return -1;
287
2.76k
    }
288
289
86.0k
    if (strcmp(fb_cmd_str,"noalert") == 0) {
290
19.7k
        if (strlen(fb_name) != 0)
291
68
            goto error;
292
19.6k
        s->action &= ~ACTION_ALERT;
293
19.6k
        return 0;
294
66.3k
    } else if (strcmp(fb_cmd_str,"isset") == 0) {
295
26.1k
        fb_cmd = DETECT_FLOWBITS_CMD_ISSET;
296
40.1k
    } else if (strcmp(fb_cmd_str,"isnotset") == 0) {
297
7.22k
        fb_cmd = DETECT_FLOWBITS_CMD_ISNOTSET;
298
32.9k
    } else if (strcmp(fb_cmd_str,"set") == 0) {
299
23.1k
        fb_cmd = DETECT_FLOWBITS_CMD_SET;
300
23.1k
    } else if (strcmp(fb_cmd_str,"unset") == 0) {
301
3.87k
        fb_cmd = DETECT_FLOWBITS_CMD_UNSET;
302
5.89k
    } else if (strcmp(fb_cmd_str,"toggle") == 0) {
303
3.28k
        fb_cmd = DETECT_FLOWBITS_CMD_TOGGLE;
304
3.28k
    } else {
305
2.61k
        SCLogError("ERROR: flowbits action \"%s\" is not supported.", fb_cmd_str);
306
2.61k
        goto error;
307
2.61k
    }
308
309
63.6k
    switch (fb_cmd) {
310
7.22k
        case DETECT_FLOWBITS_CMD_ISNOTSET:
311
33.3k
        case DETECT_FLOWBITS_CMD_ISSET:
312
56.5k
        case DETECT_FLOWBITS_CMD_SET:
313
60.4k
        case DETECT_FLOWBITS_CMD_UNSET:
314
63.6k
        case DETECT_FLOWBITS_CMD_TOGGLE:
315
63.6k
        default:
316
63.6k
            if (strlen(fb_name) == 0)
317
390
                goto error;
318
63.3k
            break;
319
63.6k
    }
320
321
63.3k
    cd = SCCalloc(1, sizeof(DetectFlowbitsData));
322
63.3k
    if (unlikely(cd == NULL))
323
0
        goto error;
324
63.3k
    if (strchr(fb_name, '|') != NULL) {
325
16.8k
        int retval = FlowbitOrAddData(de_ctx, cd, fb_name);
326
16.8k
        if (retval == -1) {
327
531
            goto error;
328
531
        }
329
16.3k
        cd->cmd = fb_cmd;
330
46.4k
    } else {
331
46.4k
        cd->idx = VarNameStoreRegister(fb_name, VAR_TYPE_FLOW_BIT);
332
46.4k
        de_ctx->max_fb_id = MAX(cd->idx, de_ctx->max_fb_id);
333
46.4k
        cd->cmd = fb_cmd;
334
46.4k
        cd->or_list_size = 0;
335
46.4k
        cd->or_list = NULL;
336
46.4k
        SCLogDebug("idx %" PRIu32 ", cmd %s, name %s",
337
46.4k
            cd->idx, fb_cmd_str, strlen(fb_name) ? fb_name : "(none)");
338
46.4k
    }
339
    /* Okay so far so good, lets get this into a SigMatch
340
     * and put it in the Signature. */
341
62.7k
    sm = SigMatchAlloc();
342
62.7k
    if (sm == NULL)
343
0
        goto error;
344
345
62.7k
    sm->type = DETECT_FLOWBITS;
346
62.7k
    sm->ctx = (SigMatchCtx *)cd;
347
348
62.7k
    switch (fb_cmd) {
349
        /* noalert can't happen here */
350
7.12k
        case DETECT_FLOWBITS_CMD_ISNOTSET:
351
32.9k
        case DETECT_FLOWBITS_CMD_ISSET:
352
            /* checks, so packet list */
353
32.9k
            SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH);
354
32.9k
            break;
355
356
22.6k
        case DETECT_FLOWBITS_CMD_SET:
357
26.5k
        case DETECT_FLOWBITS_CMD_UNSET:
358
29.8k
        case DETECT_FLOWBITS_CMD_TOGGLE:
359
            /* modifiers, only run when entire sig has matched */
360
29.8k
            SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_POSTMATCH);
361
29.8k
            break;
362
363
        // suppress coverity warning as scan-build-7 warns w/o this.
364
        // coverity[deadcode : FALSE]
365
0
        default:
366
0
            goto error;
367
62.7k
    }
368
369
62.7k
    return 0;
370
371
3.60k
error:
372
3.60k
    if (cd != NULL)
373
531
        DetectFlowbitFree(de_ctx, cd);
374
3.60k
    if (sm != NULL)
375
0
        SCFree(sm);
376
3.60k
    return -1;
377
62.7k
}
378
379
void DetectFlowbitFree (DetectEngineCtx *de_ctx, void *ptr)
380
125k
{
381
125k
    DetectFlowbitsData *fd = (DetectFlowbitsData *)ptr;
382
125k
    if (fd == NULL)
383
0
        return;
384
125k
    VarNameStoreUnregister(fd->idx, VAR_TYPE_FLOW_BIT);
385
125k
    if (fd->or_list != NULL) {
386
113k
        for (uint8_t i = 0; i < fd->or_list_size; i++) {
387
80.4k
            VarNameStoreUnregister(fd->or_list[i], VAR_TYPE_FLOW_BIT);
388
80.4k
        }
389
32.7k
        SCFree(fd->or_list);
390
32.7k
    }
391
125k
    SCFree(fd);
392
125k
}
393
394
struct FBAnalyze {
395
    uint16_t cnts[DETECT_FLOWBITS_CMD_MAX];
396
    uint16_t state_cnts[DETECT_FLOWBITS_CMD_MAX];
397
398
    uint32_t *set_sids;
399
    uint32_t set_sids_idx;
400
    uint32_t set_sids_size;
401
402
    uint32_t *isset_sids;
403
    uint32_t isset_sids_idx;
404
    uint32_t isset_sids_size;
405
406
    uint32_t *isnotset_sids;
407
    uint32_t isnotset_sids_idx;
408
    uint32_t isnotset_sids_size;
409
410
    uint32_t *unset_sids;
411
    uint32_t unset_sids_idx;
412
    uint32_t unset_sids_size;
413
414
    uint32_t *toggle_sids;
415
    uint32_t toggle_sids_idx;
416
    uint32_t toggle_sids_size;
417
};
418
419
extern bool rule_engine_analysis_set;
420
static void DetectFlowbitsAnalyzeDump(const DetectEngineCtx *de_ctx,
421
        struct FBAnalyze *array, uint32_t elements);
422
423
int DetectFlowbitsAnalyze(DetectEngineCtx *de_ctx)
424
67.5k
{
425
67.5k
    const uint32_t max_fb_id = de_ctx->max_fb_id;
426
67.5k
    if (max_fb_id == 0)
427
64.9k
        return 0;
428
429
2.65k
#define MAX_SIDS 8
430
2.65k
    uint32_t array_size = max_fb_id + 1;
431
2.65k
    struct FBAnalyze *array = SCCalloc(array_size, sizeof(struct FBAnalyze));
432
433
2.65k
    if (array == NULL) {
434
0
        SCLogError("Unable to allocate flowbit analyze array");
435
0
        return -1;
436
0
    }
437
438
2.65k
    SCLogDebug("fb analyzer array size: %"PRIu64,
439
2.65k
            (uint64_t)(array_size * sizeof(struct FBAnalyze)));
440
441
    /* fill flowbit array, updating counters per sig */
442
33.9k
    for (uint32_t i = 0; i < de_ctx->sig_array_len; i++) {
443
31.2k
        const Signature *s = de_ctx->sig_array[i];
444
445
        /* see if the signature uses stateful matching */
446
31.2k
        bool has_state = (s->init_data->buffer_index != 0);
447
448
50.4k
        for (const SigMatch *sm = s->init_data->smlists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) {
449
19.1k
            switch (sm->type) {
450
3.09k
                case DETECT_FLOWBITS:
451
3.09k
                {
452
                    /* figure out the flowbit action */
453
3.09k
                    const DetectFlowbitsData *fb = (DetectFlowbitsData *)sm->ctx;
454
                    // Handle flowbit array in case of ORed flowbits
455
5.54k
                    for (uint8_t k = 0; k < fb->or_list_size; k++) {
456
2.44k
                        array[fb->or_list[k]].cnts[fb->cmd]++;
457
2.44k
                        if (has_state)
458
283
                            array[fb->or_list[k]].state_cnts[fb->cmd]++;
459
2.44k
                        if (fb->cmd == DETECT_FLOWBITS_CMD_ISSET) {
460
2.12k
                            if (array[fb->or_list[k]].isset_sids_idx >= array[fb->or_list[k]].isset_sids_size) {
461
1.39k
                                uint32_t old_size = array[fb->or_list[k]].isset_sids_size;
462
1.39k
                                uint32_t new_size = MAX(2 * old_size, MAX_SIDS);
463
464
1.39k
                                void *ptr = SCRealloc(array[fb->or_list[k]].isset_sids, new_size * sizeof(uint32_t));
465
1.39k
                                if (ptr == NULL)
466
0
                                    goto end;
467
1.39k
                                array[fb->or_list[k]].isset_sids_size = new_size;
468
1.39k
                                array[fb->or_list[k]].isset_sids = ptr;
469
1.39k
                            }
470
471
2.12k
                            array[fb->or_list[k]].isset_sids[array[fb->or_list[k]].isset_sids_idx] = s->num;
472
2.12k
                            array[fb->or_list[k]].isset_sids_idx++;
473
2.12k
                        } else if (fb->cmd == DETECT_FLOWBITS_CMD_ISNOTSET) {
474
318
                            if (array[fb->or_list[k]].isnotset_sids_idx >= array[fb->or_list[k]].isnotset_sids_size) {
475
277
                                uint32_t old_size = array[fb->or_list[k]].isnotset_sids_size;
476
277
                                uint32_t new_size = MAX(2 * old_size, MAX_SIDS);
477
478
277
                                void *ptr = SCRealloc(array[fb->or_list[k]].isnotset_sids, new_size * sizeof(uint32_t));
479
277
                                if (ptr == NULL)
480
0
                                    goto end;
481
277
                                array[fb->or_list[k]].isnotset_sids_size = new_size;
482
277
                                array[fb->or_list[k]].isnotset_sids = ptr;
483
277
                            }
484
485
318
                            array[fb->or_list[k]].isnotset_sids[array[fb->or_list[k]].isnotset_sids_idx] = s->num;
486
318
                            array[fb->or_list[k]].isnotset_sids_idx++;
487
318
                        }
488
2.44k
                    }
489
3.09k
                    if (fb->or_list_size == 0) {
490
2.08k
                        array[fb->idx].cnts[fb->cmd]++;
491
2.08k
                        if (has_state)
492
285
                            array[fb->idx].state_cnts[fb->cmd]++;
493
2.08k
                        if (fb->cmd == DETECT_FLOWBITS_CMD_ISSET) {
494
1.24k
                            if (array[fb->idx].isset_sids_idx >= array[fb->idx].isset_sids_size) {
495
911
                                uint32_t old_size = array[fb->idx].isset_sids_size;
496
911
                                uint32_t new_size = MAX(2 * old_size, MAX_SIDS);
497
498
911
                                void *ptr = SCRealloc(array[fb->idx].isset_sids, new_size * sizeof(uint32_t));
499
911
                                if (ptr == NULL)
500
0
                                    goto end;
501
911
                                array[fb->idx].isset_sids_size = new_size;
502
911
                                array[fb->idx].isset_sids = ptr;
503
911
                            }
504
505
1.24k
                            array[fb->idx].isset_sids[array[fb->idx].isset_sids_idx] = s->num;
506
1.24k
                            array[fb->idx].isset_sids_idx++;
507
1.24k
                        } else if (fb->cmd == DETECT_FLOWBITS_CMD_ISNOTSET) {
508
836
                            if (array[fb->idx].isnotset_sids_idx >= array[fb->idx].isnotset_sids_size) {
509
545
                                uint32_t old_size = array[fb->idx].isnotset_sids_size;
510
545
                                uint32_t new_size = MAX(2 * old_size, MAX_SIDS);
511
512
545
                                void *ptr = SCRealloc(array[fb->idx].isnotset_sids, new_size * sizeof(uint32_t));
513
545
                                if (ptr == NULL)
514
0
                                    goto end;
515
545
                                array[fb->idx].isnotset_sids_size = new_size;
516
545
                                array[fb->idx].isnotset_sids = ptr;
517
545
                            }
518
519
836
                            array[fb->idx].isnotset_sids[array[fb->idx].isnotset_sids_idx] = s->num;
520
836
                            array[fb->idx].isnotset_sids_idx++;
521
836
                        }
522
2.08k
                    }
523
3.09k
                }
524
19.1k
            }
525
19.1k
        }
526
39.2k
        for (const SigMatch *sm = s->init_data->smlists[DETECT_SM_LIST_POSTMATCH] ; sm != NULL; sm = sm->next) {
527
7.98k
            switch (sm->type) {
528
4.54k
                case DETECT_FLOWBITS:
529
4.54k
                {
530
                    /* figure out what flowbit action */
531
4.54k
                    const DetectFlowbitsData *fb = (DetectFlowbitsData *)sm->ctx;
532
4.54k
                    array[fb->idx].cnts[fb->cmd]++;
533
4.54k
                    if (has_state)
534
1.65k
                        array[fb->idx].state_cnts[fb->cmd]++;
535
4.54k
                    if (fb->cmd == DETECT_FLOWBITS_CMD_SET) {
536
3.42k
                        if (array[fb->idx].set_sids_idx >= array[fb->idx].set_sids_size) {
537
1.99k
                            uint32_t old_size = array[fb->idx].set_sids_size;
538
1.99k
                            uint32_t new_size = MAX(2 * old_size, MAX_SIDS);
539
540
1.99k
                            void *ptr = SCRealloc(array[fb->idx].set_sids, new_size * sizeof(uint32_t));
541
1.99k
                            if (ptr == NULL)
542
0
                                goto end;
543
1.99k
                            array[fb->idx].set_sids_size = new_size;
544
1.99k
                            array[fb->idx].set_sids = ptr;
545
1.99k
                        }
546
547
3.42k
                        array[fb->idx].set_sids[array[fb->idx].set_sids_idx] = s->num;
548
3.42k
                        array[fb->idx].set_sids_idx++;
549
3.42k
                    }
550
1.12k
                    else if (fb->cmd == DETECT_FLOWBITS_CMD_UNSET) {
551
979
                        if (array[fb->idx].unset_sids_idx >= array[fb->idx].unset_sids_size) {
552
334
                            uint32_t old_size = array[fb->idx].unset_sids_size;
553
334
                            uint32_t new_size = MAX(2 * old_size, MAX_SIDS);
554
555
334
                            void *ptr = SCRealloc(array[fb->idx].unset_sids, new_size * sizeof(uint32_t));
556
334
                            if (ptr == NULL)
557
0
                                goto end;
558
334
                            array[fb->idx].unset_sids_size = new_size;
559
334
                            array[fb->idx].unset_sids = ptr;
560
334
                        }
561
562
979
                        array[fb->idx].unset_sids[array[fb->idx].unset_sids_idx] = s->num;
563
979
                        array[fb->idx].unset_sids_idx++;
564
979
                    }
565
142
                    else if (fb->cmd == DETECT_FLOWBITS_CMD_TOGGLE) {
566
142
                        if (array[fb->idx].toggle_sids_idx >= array[fb->idx].toggle_sids_size) {
567
128
                            uint32_t old_size = array[fb->idx].toggle_sids_size;
568
128
                            uint32_t new_size = MAX(2 * old_size, MAX_SIDS);
569
570
128
                            void *ptr = SCRealloc(array[fb->idx].toggle_sids, new_size * sizeof(uint32_t));
571
128
                            if (ptr == NULL)
572
0
                                goto end;
573
128
                            array[fb->idx].toggle_sids_size = new_size;
574
128
                            array[fb->idx].toggle_sids = ptr;
575
128
                        }
576
577
142
                        array[fb->idx].toggle_sids[array[fb->idx].toggle_sids_idx] = s->num;
578
142
                        array[fb->idx].toggle_sids_idx++;
579
142
                    }
580
4.54k
                }
581
7.98k
            }
582
7.98k
        }
583
31.2k
    }
584
585
    /* walk array to see if all bits make sense */
586
1.74M
    for (uint32_t i = 0; i < array_size; i++) {
587
1.74M
        const char *varname = VarNameStoreSetupLookup(i, VAR_TYPE_FLOW_BIT);
588
1.74M
        if (varname == NULL)
589
716k
            continue;
590
591
1.74M
        bool to_state = false;
592
593
1.02M
        if (array[i].cnts[DETECT_FLOWBITS_CMD_ISSET] &&
594
2.29k
            array[i].cnts[DETECT_FLOWBITS_CMD_TOGGLE] == 0 &&
595
2.24k
            array[i].cnts[DETECT_FLOWBITS_CMD_SET] == 0) {
596
597
2.19k
            const Signature *s = de_ctx->sig_array[array[i].isset_sids[0]];
598
2.19k
            SCLogWarning("flowbit '%s' is checked but not "
599
2.19k
                         "set. Checked in %u and %u other sigs",
600
2.19k
                    varname, s->id, array[i].isset_sids_idx - 1);
601
2.19k
        }
602
1.02M
        if (array[i].state_cnts[DETECT_FLOWBITS_CMD_ISSET] &&
603
209
            array[i].state_cnts[DETECT_FLOWBITS_CMD_SET] == 0)
604
208
        {
605
208
            SCLogDebug("flowbit %s/%u: isset in state, set not in state", varname, i);
606
208
        }
607
608
        /* if signature depends on 'stateful' flowbits, then turn the
609
         * sig into a stateful sig itself */
610
1.02M
        if (array[i].cnts[DETECT_FLOWBITS_CMD_ISSET] > 0 &&
611
2.29k
            array[i].state_cnts[DETECT_FLOWBITS_CMD_ISSET] == 0 &&
612
2.08k
            array[i].state_cnts[DETECT_FLOWBITS_CMD_SET])
613
4
        {
614
4
            SCLogDebug("flowbit %s/%u: isset not in state, set in state", varname, i);
615
4
            to_state = true;
616
4
        }
617
618
1.02M
        SCLogDebug("ALL flowbit %s/%u: sets %u toggles %u unsets %u isnotsets %u issets %u", varname, i,
619
1.02M
                array[i].cnts[DETECT_FLOWBITS_CMD_SET], array[i].cnts[DETECT_FLOWBITS_CMD_TOGGLE],
620
1.02M
                array[i].cnts[DETECT_FLOWBITS_CMD_UNSET], array[i].cnts[DETECT_FLOWBITS_CMD_ISNOTSET],
621
1.02M
                array[i].cnts[DETECT_FLOWBITS_CMD_ISSET]);
622
1.02M
        SCLogDebug("STATE flowbit %s/%u: sets %u toggles %u unsets %u isnotsets %u issets %u", varname, i,
623
1.02M
                array[i].state_cnts[DETECT_FLOWBITS_CMD_SET], array[i].state_cnts[DETECT_FLOWBITS_CMD_TOGGLE],
624
1.02M
                array[i].state_cnts[DETECT_FLOWBITS_CMD_UNSET], array[i].state_cnts[DETECT_FLOWBITS_CMD_ISNOTSET],
625
1.02M
                array[i].state_cnts[DETECT_FLOWBITS_CMD_ISSET]);
626
1.03M
        for (uint32_t x = 0; x < array[i].set_sids_idx; x++) {
627
3.18k
            SCLogDebug("SET flowbit %s/%u: SID %u", varname, i,
628
3.18k
                    de_ctx->sig_array[array[i].set_sids[x]]->id);
629
3.18k
        }
630
1.03M
        for (uint32_t x = 0; x < array[i].isset_sids_idx; x++) {
631
3.37k
            Signature *s = de_ctx->sig_array[array[i].isset_sids[x]];
632
3.37k
            SCLogDebug("GET flowbit %s/%u: SID %u", varname, i, s->id);
633
634
3.37k
            if (to_state) {
635
4
                s->init_data->init_flags |= SIG_FLAG_INIT_STATE_MATCH;
636
4
                SCLogDebug("made SID %u stateful because it depends on "
637
4
                        "stateful rules that set flowbit %s", s->id, varname);
638
4
            }
639
3.37k
        }
640
1.02M
    }
641
642
2.65k
    if (rule_engine_analysis_set) {
643
0
        DetectFlowbitsAnalyzeDump(de_ctx, array, array_size);
644
0
    }
645
646
2.65k
end:
647
1.74M
    for (uint32_t i = 0; i < array_size; i++) {
648
1.74M
        SCFree(array[i].set_sids);
649
1.74M
        SCFree(array[i].unset_sids);
650
1.74M
        SCFree(array[i].isset_sids);
651
1.74M
        SCFree(array[i].isnotset_sids);
652
1.74M
        SCFree(array[i].toggle_sids);
653
1.74M
    }
654
2.65k
    SCFree(array);
655
656
2.65k
    return 0;
657
2.65k
}
658
659
SCMutex g_flowbits_dump_write_m = SCMUTEX_INITIALIZER;
660
static void DetectFlowbitsAnalyzeDump(const DetectEngineCtx *de_ctx,
661
        struct FBAnalyze *array, uint32_t elements)
662
0
{
663
0
    JsonBuilder *js = jb_new_object();
664
0
    if (js == NULL)
665
0
        return;
666
667
0
    jb_open_array(js, "flowbits");
668
0
    for (uint32_t x = 0; x < elements; x++) {
669
0
        const char *varname = VarNameStoreSetupLookup(x, VAR_TYPE_FLOW_BIT);
670
0
        if (varname == NULL)
671
0
            continue;
672
673
0
        const struct FBAnalyze *e = &array[x];
674
675
0
        jb_start_object(js);
676
0
        jb_set_string(js, "name", varname);
677
0
        jb_set_uint(js, "internal_id", x);
678
0
        jb_set_uint(js, "set_cnt", e->cnts[DETECT_FLOWBITS_CMD_SET]);
679
0
        jb_set_uint(js, "unset_cnt", e->cnts[DETECT_FLOWBITS_CMD_UNSET]);
680
0
        jb_set_uint(js, "toggle_cnt", e->cnts[DETECT_FLOWBITS_CMD_TOGGLE]);
681
0
        jb_set_uint(js, "isset_cnt", e->cnts[DETECT_FLOWBITS_CMD_ISSET]);
682
0
        jb_set_uint(js, "isnotset_cnt", e->cnts[DETECT_FLOWBITS_CMD_ISNOTSET]);
683
684
        // sets
685
0
        if (e->cnts[DETECT_FLOWBITS_CMD_SET]) {
686
0
            jb_open_array(js, "sets");
687
0
            for (uint32_t i = 0; i < e->set_sids_idx; i++) {
688
0
                const Signature *s = de_ctx->sig_array[e->set_sids[i]];
689
0
                jb_append_uint(js, s->id);
690
0
            }
691
0
            jb_close(js);
692
0
        }
693
        // gets
694
0
        if (e->cnts[DETECT_FLOWBITS_CMD_ISSET]) {
695
0
            jb_open_array(js, "isset");
696
0
            for (uint32_t i = 0; i < e->isset_sids_idx; i++) {
697
0
                const Signature *s = de_ctx->sig_array[e->isset_sids[i]];
698
0
                jb_append_uint(js, s->id);
699
0
            }
700
0
            jb_close(js);
701
0
        }
702
        // isnotset
703
0
        if (e->cnts[DETECT_FLOWBITS_CMD_ISNOTSET]) {
704
0
            jb_open_array(js, "isnotset");
705
0
            for (uint32_t i = 0; i < e->isnotset_sids_idx; i++) {
706
0
                const Signature *s = de_ctx->sig_array[e->isnotset_sids[i]];
707
0
                jb_append_uint(js, s->id);
708
0
            }
709
0
            jb_close(js);
710
0
        }
711
        // unset
712
0
        if (e->cnts[DETECT_FLOWBITS_CMD_UNSET]) {
713
0
            jb_open_array(js, "unset");
714
0
            for (uint32_t i = 0; i < e->unset_sids_idx; i++) {
715
0
                const Signature *s = de_ctx->sig_array[e->unset_sids[i]];
716
0
                jb_append_uint(js, s->id);
717
0
            }
718
0
            jb_close(js);
719
0
        }
720
        // toggle
721
0
        if (e->cnts[DETECT_FLOWBITS_CMD_TOGGLE]) {
722
0
            jb_open_array(js, "toggle");
723
0
            for (uint32_t i = 0; i < e->toggle_sids_idx; i++) {
724
0
                const Signature *s = de_ctx->sig_array[e->toggle_sids[i]];
725
0
                jb_append_uint(js, s->id);
726
0
            }
727
0
            jb_close(js);
728
0
        }
729
0
        jb_close(js);
730
0
    }
731
0
    jb_close(js); // array
732
0
    jb_close(js); // object
733
734
0
    const char *filename = "flowbits.json";
735
0
    const char *log_dir = ConfigGetLogDirectory();
736
0
    char log_path[PATH_MAX] = "";
737
0
    snprintf(log_path, sizeof(log_path), "%s/%s", log_dir, filename);
738
739
0
    SCMutexLock(&g_flowbits_dump_write_m);
740
0
    FILE *fp = fopen(log_path, "w");
741
0
    if (fp != NULL) {
742
0
        fwrite(jb_ptr(js), jb_len(js), 1, fp);
743
0
        fprintf(fp, "\n");
744
0
        fclose(fp);
745
0
    }
746
0
    SCMutexUnlock(&g_flowbits_dump_write_m);
747
748
0
    jb_free(js);
749
0
}
750
751
#ifdef UNITTESTS
752
753
static int FlowBitsTestParse01(void)
754
{
755
    char command[16] = "", name[16] = "";
756
757
    /* Single argument version. */
758
    FAIL_IF(!DetectFlowbitParse("noalert", command, sizeof(command), name,
759
            sizeof(name)));
760
    FAIL_IF(strcmp(command, "noalert") != 0);
761
762
    /* No leading or trailing spaces. */
763
    FAIL_IF(!DetectFlowbitParse("set,flowbit", command, sizeof(command), name,
764
            sizeof(name)));
765
    FAIL_IF(strcmp(command, "set") != 0);
766
    FAIL_IF(strcmp(name, "flowbit") != 0);
767
768
    /* Leading space. */
769
    FAIL_IF(!DetectFlowbitParse("set, flowbit", command, sizeof(command), name,
770
            sizeof(name)));
771
    FAIL_IF(strcmp(command, "set") != 0);
772
    FAIL_IF(strcmp(name, "flowbit") != 0);
773
774
    /* Trailing space. */
775
    FAIL_IF(!DetectFlowbitParse("set,flowbit ", command, sizeof(command), name,
776
            sizeof(name)));
777
    FAIL_IF(strcmp(command, "set") != 0);
778
    FAIL_IF(strcmp(name, "flowbit") != 0);
779
780
    /* Leading and trailing space. */
781
    FAIL_IF(!DetectFlowbitParse("set, flowbit ", command, sizeof(command), name,
782
            sizeof(name)));
783
    FAIL_IF(strcmp(command, "set") != 0);
784
    FAIL_IF(strcmp(name, "flowbit") != 0);
785
786
    /* Spaces are not allowed in the name. */
787
    FAIL_IF(DetectFlowbitParse("set,namewith space", command, sizeof(command),
788
            name, sizeof(name)));
789
790
    PASS;
791
}
792
793
/**
794
 * \test FlowBitsTestSig01 is a test for a valid noalert flowbits option
795
 *
796
 *  \retval 1 on success
797
 *  \retval 0 on failure
798
 */
799
800
static int FlowBitsTestSig01(void)
801
{
802
    Signature *s = NULL;
803
    DetectEngineCtx *de_ctx = NULL;
804
805
    de_ctx = DetectEngineCtxInit();
806
    FAIL_IF_NULL(de_ctx);
807
808
    de_ctx->flags |= DE_QUIET;
809
810
    s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Noalert\"; flowbits:noalert,wrongusage; content:\"GET \"; sid:1;)");
811
    FAIL_IF_NOT_NULL(s);
812
813
    SigGroupBuild(de_ctx);
814
    DetectEngineCtxFree(de_ctx);
815
    PASS;
816
}
817
818
/**
819
 * \test FlowBitsTestSig02 is a test for a valid isset,set,isnotset,unset,toggle flowbits options
820
 *
821
 *  \retval 1 on success
822
 *  \retval 0 on failure
823
 */
824
825
static int FlowBitsTestSig02(void)
826
{
827
    Signature *s = NULL;
828
    ThreadVars th_v;
829
    DetectEngineCtx *de_ctx = NULL;
830
831
    memset(&th_v, 0, sizeof(th_v));
832
833
    de_ctx = DetectEngineCtxInit();
834
    FAIL_IF_NULL(de_ctx);
835
836
    de_ctx->flags |= DE_QUIET;
837
838
    s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"isset rule need an option\"; flowbits:isset; content:\"GET \"; sid:1;)");
839
    FAIL_IF_NOT_NULL(s);
840
841
    s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"isnotset rule need an option\"; flowbits:isnotset; content:\"GET \"; sid:2;)");
842
    FAIL_IF_NOT_NULL(s);
843
844
    s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"set rule need an option\"; flowbits:set; content:\"GET \"; sid:3;)");
845
    FAIL_IF_NOT_NULL(s);
846
847
    s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"unset rule need an option\"; flowbits:unset; content:\"GET \"; sid:4;)");
848
    FAIL_IF_NOT_NULL(s);
849
850
    s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"toggle rule need an option\"; flowbits:toggle; content:\"GET \"; sid:5;)");
851
    FAIL_IF_NOT_NULL(s);
852
853
    s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"!set is not an option\"; flowbits:!set,myerr; content:\"GET \"; sid:6;)");
854
    FAIL_IF_NOT_NULL(s);
855
856
    SigGroupBuild(de_ctx);
857
    DetectEngineCtxFree(de_ctx);
858
859
    PASS;
860
}
861
862
/**
863
 * \test FlowBitsTestSig03 is a test for a invalid flowbits option
864
 *
865
 *  \retval 1 on success
866
 *  \retval 0 on failure
867
 */
868
869
static int FlowBitsTestSig03(void)
870
{
871
    Signature *s = NULL;
872
    DetectEngineCtx *de_ctx = NULL;
873
874
    de_ctx = DetectEngineCtxInit();
875
    FAIL_IF_NULL(de_ctx);
876
877
    de_ctx->flags |= DE_QUIET;
878
879
    s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Unknown cmd\"; flowbits:wrongcmd; content:\"GET \"; sid:1;)");
880
    FAIL_IF_NOT_NULL(s);
881
882
    SigGroupBuild(de_ctx);
883
    DetectEngineCtxFree(de_ctx);
884
    PASS;
885
}
886
887
/**
888
 * \test FlowBitsTestSig04 is a test check idx value
889
 *
890
 *  \retval 1 on success
891
 *  \retval 0 on failure
892
 */
893
894
static int FlowBitsTestSig04(void)
895
{
896
    Signature *s = NULL;
897
    DetectEngineCtx *de_ctx = NULL;
898
    int idx = 0;
899
    de_ctx = DetectEngineCtxInit();
900
    FAIL_IF_NULL(de_ctx);
901
902
    de_ctx->flags |= DE_QUIET;
903
904
    s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"isset option\"; flowbits:isset,fbt; content:\"GET \"; sid:1;)");
905
    FAIL_IF_NULL(s);
906
907
    idx = VarNameStoreRegister("fbt", VAR_TYPE_FLOW_BIT);
908
    FAIL_IF(idx == 0);
909
910
    SigGroupBuild(de_ctx);
911
    DetectEngineCtxFree(de_ctx);
912
    PASS;
913
}
914
915
/**
916
 * \test FlowBitsTestSig05 is a test check noalert flag
917
 *
918
 *  \retval 1 on success
919
 *  \retval 0 on failure
920
 */
921
922
static int FlowBitsTestSig05(void)
923
{
924
    Signature *s = NULL;
925
    DetectEngineCtx *de_ctx = NULL;
926
927
    de_ctx = DetectEngineCtxInit();
928
    FAIL_IF_NULL(de_ctx);
929
930
    de_ctx->flags |= DE_QUIET;
931
932
    s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Noalert\"; flowbits:noalert; content:\"GET \"; sid:1;)");
933
    FAIL_IF_NULL(s);
934
    FAIL_IF((s->action & ACTION_ALERT) != 0);
935
936
    SigGroupBuild(de_ctx);
937
    DetectEngineCtxFree(de_ctx);
938
    PASS;
939
}
940
941
/**
942
 * \test FlowBitsTestSig06 is a test set flowbits option
943
 *
944
 *  \retval 1 on success
945
 *  \retval 0 on failure
946
 */
947
948
static int FlowBitsTestSig06(void)
949
{
950
    uint8_t *buf = (uint8_t *)
951
                    "GET /one/ HTTP/1.1\r\n"
952
                    "Host: one.example.org\r\n"
953
                    "\r\n";
954
    uint16_t buflen = strlen((char *)buf);
955
    Packet *p = PacketGetFromAlloc();
956
    FAIL_IF_NULL(p);
957
    Signature *s = NULL;
958
    ThreadVars th_v;
959
    DetectEngineThreadCtx *det_ctx = NULL;
960
    DetectEngineCtx *de_ctx = NULL;
961
    Flow f;
962
    GenericVar flowvar, *gv = NULL;
963
    int result = 0;
964
    uint32_t idx = 0;
965
966
    memset(&th_v, 0, sizeof(th_v));
967
    memset(&f, 0, sizeof(Flow));
968
    memset(&flowvar, 0, sizeof(GenericVar));
969
970
    FLOW_INITIALIZE(&f);
971
    p->flow = &f;
972
    p->flow->flowvar = &flowvar;
973
974
    p->src.family = AF_INET;
975
    p->dst.family = AF_INET;
976
    p->payload = buf;
977
    p->payload_len = buflen;
978
    p->proto = IPPROTO_TCP;
979
    p->flags |= PKT_HAS_FLOW;
980
    p->flowflags |= (FLOW_PKT_TOSERVER | FLOW_PKT_TOSERVER_FIRST);
981
982
    de_ctx = DetectEngineCtxInit();
983
    FAIL_IF_NULL(de_ctx);
984
985
    de_ctx->flags |= DE_QUIET;
986
987
    s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit set\"; flowbits:set,myflow; sid:10;)");
988
    FAIL_IF_NULL(s);
989
990
    idx = VarNameStoreRegister("myflow", VAR_TYPE_FLOW_BIT);
991
    SigGroupBuild(de_ctx);
992
    DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
993
994
    SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
995
996
    gv = p->flow->flowvar;
997
    FAIL_IF_NULL(gv);
998
    for ( ; gv != NULL; gv = gv->next) {
999
        if (gv->type == DETECT_FLOWBITS && gv->idx == idx) {
1000
                result = 1;
1001
        }
1002
    }
1003
    FAIL_IF_NOT(result);
1004
1005
    DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
1006
    DetectEngineCtxFree(de_ctx);
1007
1008
    FLOW_DESTROY(&f);
1009
1010
    SCFree(p);
1011
    PASS;
1012
}
1013
1014
/**
1015
 * \test FlowBitsTestSig07 is a test unset flowbits option
1016
 *
1017
 *  \retval 1 on success
1018
 *  \retval 0 on failure
1019
 */
1020
1021
static int FlowBitsTestSig07(void)
1022
{
1023
    uint8_t *buf = (uint8_t *)
1024
                    "GET /one/ HTTP/1.1\r\n"
1025
                    "Host: one.example.org\r\n"
1026
                    "\r\n";
1027
    uint16_t buflen = strlen((char *)buf);
1028
    Packet *p = PacketGetFromAlloc();
1029
    FAIL_IF_NULL(p);
1030
    Signature *s = NULL;
1031
    ThreadVars th_v;
1032
    DetectEngineThreadCtx *det_ctx = NULL;
1033
    DetectEngineCtx *de_ctx = NULL;
1034
    Flow f;
1035
    GenericVar flowvar, *gv = NULL;
1036
    int result = 0;
1037
    uint32_t idx = 0;
1038
1039
    memset(&th_v, 0, sizeof(th_v));
1040
    memset(&f, 0, sizeof(Flow));
1041
    memset(&flowvar, 0, sizeof(GenericVar));
1042
1043
    FLOW_INITIALIZE(&f);
1044
    p->flow = &f;
1045
    p->flow->flowvar = &flowvar;
1046
1047
    p->src.family = AF_INET;
1048
    p->dst.family = AF_INET;
1049
    p->payload = buf;
1050
    p->payload_len = buflen;
1051
    p->proto = IPPROTO_TCP;
1052
1053
    de_ctx = DetectEngineCtxInit();
1054
    FAIL_IF_NULL(de_ctx);
1055
1056
    de_ctx->flags |= DE_QUIET;
1057
1058
    s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit set\"; flowbits:set,myflow2; sid:10;)");
1059
    FAIL_IF_NULL(s);
1060
1061
    s = s->next = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit unset\"; flowbits:unset,myflow2; sid:11;)");
1062
    FAIL_IF_NULL(s);
1063
1064
    idx = VarNameStoreRegister("myflow", VAR_TYPE_FLOW_BIT);
1065
    SigGroupBuild(de_ctx);
1066
    DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
1067
1068
    SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1069
1070
    gv = p->flow->flowvar;
1071
    FAIL_IF_NULL(gv);
1072
1073
    for ( ; gv != NULL; gv = gv->next) {
1074
        if (gv->type == DETECT_FLOWBITS && gv->idx == idx) {
1075
                result = 1;
1076
        }
1077
    }
1078
    FAIL_IF(result);
1079
1080
    DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
1081
    DetectEngineCtxFree(de_ctx);
1082
1083
    FLOW_DESTROY(&f);
1084
1085
    SCFree(p);
1086
    PASS;
1087
}
1088
1089
/**
1090
 * \test FlowBitsTestSig08 is a test toggle flowbits option
1091
 *
1092
 *  \retval 1 on success
1093
 *  \retval 0 on failure
1094
 */
1095
1096
static int FlowBitsTestSig08(void)
1097
{
1098
    uint8_t *buf = (uint8_t *)
1099
                    "GET /one/ HTTP/1.1\r\n"
1100
                    "Host: one.example.org\r\n"
1101
                    "\r\n";
1102
    uint16_t buflen = strlen((char *)buf);
1103
    Packet *p = PacketGetFromAlloc();
1104
    if (unlikely(p == NULL))
1105
        return 0;
1106
    Signature *s = NULL;
1107
    ThreadVars th_v;
1108
    DetectEngineThreadCtx *det_ctx = NULL;
1109
    DetectEngineCtx *de_ctx = NULL;
1110
    Flow f;
1111
    GenericVar flowvar, *gv = NULL;
1112
    int result = 0;
1113
    uint32_t idx = 0;
1114
1115
    memset(&th_v, 0, sizeof(th_v));
1116
    memset(&f, 0, sizeof(Flow));
1117
    memset(&flowvar, 0, sizeof(GenericVar));
1118
1119
    FLOW_INITIALIZE(&f);
1120
    p->flow = &f;
1121
    p->flow->flowvar = &flowvar;
1122
1123
    p->src.family = AF_INET;
1124
    p->dst.family = AF_INET;
1125
    p->payload = buf;
1126
    p->payload_len = buflen;
1127
    p->proto = IPPROTO_TCP;
1128
1129
    de_ctx = DetectEngineCtxInit();
1130
    FAIL_IF_NULL(de_ctx);
1131
1132
    de_ctx->flags |= DE_QUIET;
1133
1134
    s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit set\"; flowbits:set,myflow2; sid:10;)");
1135
    FAIL_IF_NULL(s);
1136
1137
    s = s->next  = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit unset\"; flowbits:toggle,myflow2; sid:11;)");
1138
    FAIL_IF_NULL(s);
1139
1140
    idx = VarNameStoreRegister("myflow", VAR_TYPE_FLOW_BIT);
1141
    SigGroupBuild(de_ctx);
1142
    DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
1143
1144
    SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1145
1146
    gv = p->flow->flowvar;
1147
    FAIL_IF_NULL(gv);
1148
1149
    for ( ; gv != NULL; gv = gv->next) {
1150
        if (gv->type == DETECT_FLOWBITS && gv->idx == idx) {
1151
                result = 1;
1152
        }
1153
    }
1154
    FAIL_IF(result);
1155
1156
    DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
1157
    DetectEngineCtxFree(de_ctx);
1158
1159
    FLOW_DESTROY(&f);
1160
1161
    SCFree(p);
1162
    PASS;
1163
}
1164
1165
/**
1166
 * \brief this function registers unit tests for FlowBits
1167
 */
1168
void FlowBitsRegisterTests(void)
1169
{
1170
    UtRegisterTest("FlowBitsTestParse01", FlowBitsTestParse01);
1171
    UtRegisterTest("FlowBitsTestSig01", FlowBitsTestSig01);
1172
    UtRegisterTest("FlowBitsTestSig02", FlowBitsTestSig02);
1173
    UtRegisterTest("FlowBitsTestSig03", FlowBitsTestSig03);
1174
    UtRegisterTest("FlowBitsTestSig04", FlowBitsTestSig04);
1175
    UtRegisterTest("FlowBitsTestSig05", FlowBitsTestSig05);
1176
    UtRegisterTest("FlowBitsTestSig06", FlowBitsTestSig06);
1177
    UtRegisterTest("FlowBitsTestSig07", FlowBitsTestSig07);
1178
    UtRegisterTest("FlowBitsTestSig08", FlowBitsTestSig08);
1179
}
1180
#endif /* UNITTESTS */