Coverage Report

Created: 2026-03-31 07:45

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
48.6k
#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
20.3k
{
84
20.3k
    char *strarr[MAX_TOKENS];
85
20.3k
    char *token;
86
20.3k
    char *saveptr = NULL;
87
20.3k
    uint8_t i = 0;
88
89
70.4k
    while ((token = strtok_r(arrptr, "|", &saveptr))) {
90
        // Check for leading/trailing spaces in the token
91
50.7k
        while(isspace((unsigned char)*token))
92
6.41k
            token++;
93
50.7k
        if (*token == 0)
94
1.37k
            goto next;
95
49.3k
        char *end = token + strlen(token) - 1;
96
51.3k
        while(end > token && isspace((unsigned char)*end))
97
2.02k
            *(end--) = '\0';
98
99
        // Check for spaces in between the flowbit names
100
49.3k
        if (strchr(token, ' ') != NULL) {
101
633
            SCLogError("Spaces are not allowed in flowbit names.");
102
633
            return -1;
103
633
        }
104
105
48.6k
        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
48.6k
        strarr[i++] = token;
112
50.0k
    next:
113
50.0k
        arrptr = NULL;
114
50.0k
    }
115
19.7k
    if (i == 0) {
116
3
        SCLogError("No valid flowbits specified");
117
3
        return -1;
118
3
    }
119
120
19.7k
    cd->or_list_size = i;
121
19.7k
    cd->or_list = SCCalloc(cd->or_list_size, sizeof(uint32_t));
122
19.7k
    if (unlikely(cd->or_list == NULL))
123
0
        return -1;
124
67.9k
    for (uint8_t j = 0; j < cd->or_list_size ; j++) {
125
48.2k
        cd->or_list[j] = VarNameStoreRegister(strarr[j], VAR_TYPE_FLOW_BIT);
126
48.2k
        de_ctx->max_fb_id = MAX(cd->or_list[j], de_ctx->max_fb_id);
127
48.2k
    }
128
129
19.7k
    return 1;
130
19.7k
}
131
132
static int DetectFlowbitMatchToggle (Packet *p, const DetectFlowbitsData *fd)
133
4.76k
{
134
4.76k
    if (p->flow == NULL)
135
85
        return 0;
136
137
4.67k
    FlowBitToggle(p->flow,fd->idx);
138
139
4.67k
    return 1;
140
4.76k
}
141
142
static int DetectFlowbitMatchUnset (Packet *p, const DetectFlowbitsData *fd)
143
9.84k
{
144
9.84k
    if (p->flow == NULL)
145
444
        return 0;
146
147
9.40k
    FlowBitUnset(p->flow,fd->idx);
148
149
9.40k
    return 1;
150
9.84k
}
151
152
static int DetectFlowbitMatchSet (Packet *p, const DetectFlowbitsData *fd)
153
18.9k
{
154
18.9k
    if (p->flow == NULL)
155
3.82k
        return 0;
156
157
15.1k
    FlowBitSet(p->flow,fd->idx);
158
159
15.1k
    return 1;
160
18.9k
}
161
162
static int DetectFlowbitMatchIsset (Packet *p, const DetectFlowbitsData *fd)
163
26.2k
{
164
26.2k
    if (p->flow == NULL)
165
0
        return 0;
166
26.2k
    if (fd->or_list_size > 0) {
167
60.9k
        for (uint8_t i = 0; i < fd->or_list_size; i++) {
168
42.1k
            if (FlowBitIsset(p->flow, fd->or_list[i]) == 1)
169
4.07k
                return 1;
170
42.1k
        }
171
18.7k
        return 0;
172
22.8k
    }
173
174
3.35k
    return FlowBitIsset(p->flow,fd->idx);
175
26.2k
}
176
177
static int DetectFlowbitMatchIsnotset (Packet *p, const DetectFlowbitsData *fd)
178
55.6k
{
179
55.6k
    if (p->flow == NULL)
180
0
        return 0;
181
55.6k
    if (fd->or_list_size > 0) {
182
20.5k
        for (uint8_t i = 0; i < fd->or_list_size; i++) {
183
20.3k
            if (FlowBitIsnotset(p->flow, fd->or_list[i]) == 1)
184
17.7k
                return 1;
185
20.3k
        }
186
271
        return 0;
187
17.9k
    }
188
37.7k
    return FlowBitIsnotset(p->flow,fd->idx);
189
55.6k
}
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
73.7k
{
200
73.7k
    const DetectFlowbitsData *fd = (const DetectFlowbitsData *)ctx;
201
73.7k
    if (fd == NULL)
202
0
        return 0;
203
204
73.7k
    switch (fd->cmd) {
205
15.3k
        case DETECT_FLOWBITS_CMD_ISSET:
206
15.3k
            return DetectFlowbitMatchIsset(p,fd);
207
30.6k
        case DETECT_FLOWBITS_CMD_ISNOTSET:
208
30.6k
            return DetectFlowbitMatchIsnotset(p,fd);
209
18.9k
        case DETECT_FLOWBITS_CMD_SET:
210
18.9k
            return DetectFlowbitMatchSet(p,fd);
211
6.54k
        case DETECT_FLOWBITS_CMD_UNSET:
212
6.54k
            return DetectFlowbitMatchUnset(p,fd);
213
2.23k
        case DETECT_FLOWBITS_CMD_TOGGLE:
214
2.23k
            return DetectFlowbitMatchToggle(p,fd);
215
0
        default:
216
0
            SCLogError("unknown cmd %" PRIu32 "", fd->cmd);
217
0
            return 0;
218
73.7k
    }
219
220
0
    return 0;
221
73.7k
}
222
223
static int DetectFlowbitParse(const char *str, char *cmd, int cmd_len, char *name,
224
    int name_len)
225
167k
{
226
167k
    int rc;
227
167k
    size_t pcre2len;
228
167k
    pcre2_match_data *match = NULL;
229
230
167k
    int count = DetectParsePcreExec(&parse_regex, &match, str, 0, 0);
231
167k
    if (count != 2 && count != 3) {
232
301
        SCLogError("\"%s\" is not a valid setting for flowbits.", str);
233
301
        goto error;
234
301
    }
235
236
167k
    pcre2len = cmd_len;
237
167k
    rc = pcre2_substring_copy_bynumber(match, 1, (PCRE2_UCHAR8 *)cmd, &pcre2len);
238
167k
    if (rc < 0) {
239
411
        SCLogError("pcre2_substring_copy_bynumber failed");
240
411
        goto error;
241
411
    }
242
243
166k
    if (count == 3) {
244
132k
        pcre2len = name_len;
245
132k
        rc = pcre2_substring_copy_bynumber(match, 2, (PCRE2_UCHAR8 *)name, &pcre2len);
246
132k
        if (rc < 0) {
247
449
            SCLogError("pcre2_substring_copy_bynumber failed");
248
449
            goto error;
249
449
        }
250
251
        /* Trim trailing whitespace. */
252
132k
        while (strlen(name) > 0 && isblank(name[strlen(name) - 1])) {
253
512
            name[strlen(name) - 1] = '\0';
254
512
        }
255
256
132k
        if (strchr(name, '|') == NULL) {
257
            /* Validate name, spaces are not allowed. */
258
1.86M
            for (size_t i = 0; i < strlen(name); i++) {
259
1.76M
                if (isblank(name[i])) {
260
4.32k
                    SCLogError("spaces not allowed in flowbit names");
261
4.32k
                    goto error;
262
4.32k
                }
263
1.76M
            }
264
100k
        }
265
132k
    }
266
267
166k
    pcre2_match_data_free(match);
268
162k
    return 1;
269
270
5.48k
error:
271
5.48k
    if (match) {
272
5.48k
        pcre2_match_data_free(match);
273
5.48k
    }
274
5.48k
    return 0;
275
166k
}
276
277
int DetectFlowbitSetup (DetectEngineCtx *de_ctx, Signature *s, const char *rawstr)
278
102k
{
279
102k
    DetectFlowbitsData *cd = NULL;
280
102k
    SigMatch *sm = NULL;
281
102k
    uint8_t fb_cmd = 0;
282
102k
    char fb_cmd_str[16] = "", fb_name[256] = "";
283
284
102k
    if (!DetectFlowbitParse(rawstr, fb_cmd_str, sizeof(fb_cmd_str), fb_name,
285
102k
            sizeof(fb_name))) {
286
3.38k
        return -1;
287
3.38k
    }
288
289
99.2k
    if (strcmp(fb_cmd_str,"noalert") == 0) {
290
21.0k
        if (strlen(fb_name) != 0)
291
75
            goto error;
292
20.9k
        s->action &= ~ACTION_ALERT;
293
20.9k
        return 0;
294
78.1k
    } else if (strcmp(fb_cmd_str,"isset") == 0) {
295
32.2k
        fb_cmd = DETECT_FLOWBITS_CMD_ISSET;
296
45.8k
    } else if (strcmp(fb_cmd_str,"isnotset") == 0) {
297
9.10k
        fb_cmd = DETECT_FLOWBITS_CMD_ISNOTSET;
298
36.7k
    } else if (strcmp(fb_cmd_str,"set") == 0) {
299
23.8k
        fb_cmd = DETECT_FLOWBITS_CMD_SET;
300
23.8k
    } else if (strcmp(fb_cmd_str,"unset") == 0) {
301
4.93k
        fb_cmd = DETECT_FLOWBITS_CMD_UNSET;
302
8.03k
    } else if (strcmp(fb_cmd_str,"toggle") == 0) {
303
3.87k
        fb_cmd = DETECT_FLOWBITS_CMD_TOGGLE;
304
4.16k
    } else {
305
4.16k
        SCLogError("ERROR: flowbits action \"%s\" is not supported.", fb_cmd_str);
306
4.16k
        goto error;
307
4.16k
    }
308
309
73.9k
    switch (fb_cmd) {
310
9.10k
        case DETECT_FLOWBITS_CMD_ISNOTSET:
311
41.3k
        case DETECT_FLOWBITS_CMD_ISSET:
312
65.1k
        case DETECT_FLOWBITS_CMD_SET:
313
70.1k
        case DETECT_FLOWBITS_CMD_UNSET:
314
73.9k
        case DETECT_FLOWBITS_CMD_TOGGLE:
315
73.9k
        default:
316
73.9k
            if (strlen(fb_name) == 0)
317
665
                goto error;
318
73.3k
            break;
319
73.9k
    }
320
321
73.3k
    cd = SCCalloc(1, sizeof(DetectFlowbitsData));
322
73.3k
    if (unlikely(cd == NULL))
323
0
        goto error;
324
73.3k
    if (strchr(fb_name, '|') != NULL) {
325
20.3k
        int retval = FlowbitOrAddData(de_ctx, cd, fb_name);
326
20.3k
        if (retval == -1) {
327
637
            goto error;
328
637
        }
329
19.7k
        cd->cmd = fb_cmd;
330
52.9k
    } else {
331
52.9k
        cd->idx = VarNameStoreRegister(fb_name, VAR_TYPE_FLOW_BIT);
332
52.9k
        de_ctx->max_fb_id = MAX(cd->idx, de_ctx->max_fb_id);
333
52.9k
        cd->cmd = fb_cmd;
334
52.9k
        cd->or_list_size = 0;
335
52.9k
        cd->or_list = NULL;
336
52.9k
        SCLogDebug("idx %" PRIu32 ", cmd %s, name %s",
337
52.9k
            cd->idx, fb_cmd_str, strlen(fb_name) ? fb_name : "(none)");
338
52.9k
    }
339
    /* Okay so far so good, lets get this into a SigMatch
340
     * and put it in the Signature. */
341
72.6k
    sm = SigMatchAlloc();
342
72.6k
    if (sm == NULL)
343
0
        goto error;
344
345
72.6k
    sm->type = DETECT_FLOWBITS;
346
72.6k
    sm->ctx = (SigMatchCtx *)cd;
347
348
72.6k
    switch (fb_cmd) {
349
        /* noalert can't happen here */
350
8.89k
        case DETECT_FLOWBITS_CMD_ISNOTSET:
351
40.5k
        case DETECT_FLOWBITS_CMD_ISSET:
352
            /* checks, so packet list */
353
40.5k
            SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH);
354
40.5k
            break;
355
356
23.3k
        case DETECT_FLOWBITS_CMD_SET:
357
28.2k
        case DETECT_FLOWBITS_CMD_UNSET:
358
32.1k
        case DETECT_FLOWBITS_CMD_TOGGLE:
359
            /* modifiers, only run when entire sig has matched */
360
32.1k
            SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_POSTMATCH);
361
32.1k
            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
72.6k
    }
368
369
72.6k
    return 0;
370
371
5.53k
error:
372
5.53k
    if (cd != NULL)
373
637
        DetectFlowbitFree(de_ctx, cd);
374
5.53k
    if (sm != NULL)
375
0
        SCFree(sm);
376
5.53k
    return -1;
377
72.6k
}
378
379
void DetectFlowbitFree (DetectEngineCtx *de_ctx, void *ptr)
380
126k
{
381
126k
    DetectFlowbitsData *fd = (DetectFlowbitsData *)ptr;
382
126k
    if (fd == NULL)
383
0
        return;
384
126k
    VarNameStoreUnregister(fd->idx, VAR_TYPE_FLOW_BIT);
385
126k
    if (fd->or_list != NULL) {
386
108k
        for (uint8_t i = 0; i < fd->or_list_size; i++) {
387
77.0k
            VarNameStoreUnregister(fd->or_list[i], VAR_TYPE_FLOW_BIT);
388
77.0k
        }
389
31.0k
        SCFree(fd->or_list);
390
31.0k
    }
391
126k
    SCFree(fd);
392
126k
}
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
74.5k
{
425
74.5k
    const uint32_t max_fb_id = de_ctx->max_fb_id;
426
74.5k
    if (max_fb_id == 0)
427
71.2k
        return 0;
428
429
3.26k
#define MAX_SIDS 8
430
3.26k
    uint32_t array_size = max_fb_id + 1;
431
3.26k
    struct FBAnalyze *array = SCCalloc(array_size, sizeof(struct FBAnalyze));
432
433
3.26k
    if (array == NULL) {
434
0
        SCLogError("Unable to allocate flowbit analyze array");
435
0
        return -1;
436
0
    }
437
438
3.26k
    SCLogDebug("fb analyzer array size: %"PRIu64,
439
3.26k
            (uint64_t)(array_size * sizeof(struct FBAnalyze)));
440
441
    /* fill flowbit array, updating counters per sig */
442
44.1k
    for (uint32_t i = 0; i < de_ctx->sig_array_len; i++) {
443
40.8k
        const Signature *s = de_ctx->sig_array[i];
444
445
        /* see if the signature uses stateful matching */
446
40.8k
        bool has_state = (s->init_data->buffer_index != 0);
447
448
64.6k
        for (const SigMatch *sm = s->init_data->smlists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) {
449
23.8k
            switch (sm->type) {
450
3.55k
                case DETECT_FLOWBITS:
451
3.55k
                {
452
                    /* figure out the flowbit action */
453
3.55k
                    const DetectFlowbitsData *fb = (DetectFlowbitsData *)sm->ctx;
454
                    // Handle flowbit array in case of ORed flowbits
455
6.35k
                    for (uint8_t k = 0; k < fb->or_list_size; k++) {
456
2.80k
                        array[fb->or_list[k]].cnts[fb->cmd]++;
457
2.80k
                        if (has_state)
458
260
                            array[fb->or_list[k]].state_cnts[fb->cmd]++;
459
2.80k
                        if (fb->cmd == DETECT_FLOWBITS_CMD_ISSET) {
460
2.41k
                            if (array[fb->or_list[k]].isset_sids_idx >= array[fb->or_list[k]].isset_sids_size) {
461
1.66k
                                uint32_t old_size = array[fb->or_list[k]].isset_sids_size;
462
1.66k
                                uint32_t new_size = MAX(2 * old_size, MAX_SIDS);
463
464
1.66k
                                void *ptr = SCRealloc(array[fb->or_list[k]].isset_sids, new_size * sizeof(uint32_t));
465
1.66k
                                if (ptr == NULL)
466
0
                                    goto end;
467
1.66k
                                array[fb->or_list[k]].isset_sids_size = new_size;
468
1.66k
                                array[fb->or_list[k]].isset_sids = ptr;
469
1.66k
                            }
470
471
2.41k
                            array[fb->or_list[k]].isset_sids[array[fb->or_list[k]].isset_sids_idx] = s->num;
472
2.41k
                            array[fb->or_list[k]].isset_sids_idx++;
473
2.41k
                        } else if (fb->cmd == DETECT_FLOWBITS_CMD_ISNOTSET) {
474
388
                            if (array[fb->or_list[k]].isnotset_sids_idx >= array[fb->or_list[k]].isnotset_sids_size) {
475
352
                                uint32_t old_size = array[fb->or_list[k]].isnotset_sids_size;
476
352
                                uint32_t new_size = MAX(2 * old_size, MAX_SIDS);
477
478
352
                                void *ptr = SCRealloc(array[fb->or_list[k]].isnotset_sids, new_size * sizeof(uint32_t));
479
352
                                if (ptr == NULL)
480
0
                                    goto end;
481
352
                                array[fb->or_list[k]].isnotset_sids_size = new_size;
482
352
                                array[fb->or_list[k]].isnotset_sids = ptr;
483
352
                            }
484
485
388
                            array[fb->or_list[k]].isnotset_sids[array[fb->or_list[k]].isnotset_sids_idx] = s->num;
486
388
                            array[fb->or_list[k]].isnotset_sids_idx++;
487
388
                        }
488
2.80k
                    }
489
3.55k
                    if (fb->or_list_size == 0) {
490
2.36k
                        array[fb->idx].cnts[fb->cmd]++;
491
2.36k
                        if (has_state)
492
370
                            array[fb->idx].state_cnts[fb->cmd]++;
493
2.36k
                        if (fb->cmd == DETECT_FLOWBITS_CMD_ISSET) {
494
1.44k
                            if (array[fb->idx].isset_sids_idx >= array[fb->idx].isset_sids_size) {
495
1.06k
                                uint32_t old_size = array[fb->idx].isset_sids_size;
496
1.06k
                                uint32_t new_size = MAX(2 * old_size, MAX_SIDS);
497
498
1.06k
                                void *ptr = SCRealloc(array[fb->idx].isset_sids, new_size * sizeof(uint32_t));
499
1.06k
                                if (ptr == NULL)
500
0
                                    goto end;
501
1.06k
                                array[fb->idx].isset_sids_size = new_size;
502
1.06k
                                array[fb->idx].isset_sids = ptr;
503
1.06k
                            }
504
505
1.44k
                            array[fb->idx].isset_sids[array[fb->idx].isset_sids_idx] = s->num;
506
1.44k
                            array[fb->idx].isset_sids_idx++;
507
1.44k
                        } else if (fb->cmd == DETECT_FLOWBITS_CMD_ISNOTSET) {
508
913
                            if (array[fb->idx].isnotset_sids_idx >= array[fb->idx].isnotset_sids_size) {
509
639
                                uint32_t old_size = array[fb->idx].isnotset_sids_size;
510
639
                                uint32_t new_size = MAX(2 * old_size, MAX_SIDS);
511
512
639
                                void *ptr = SCRealloc(array[fb->idx].isnotset_sids, new_size * sizeof(uint32_t));
513
639
                                if (ptr == NULL)
514
0
                                    goto end;
515
639
                                array[fb->idx].isnotset_sids_size = new_size;
516
639
                                array[fb->idx].isnotset_sids = ptr;
517
639
                            }
518
519
913
                            array[fb->idx].isnotset_sids[array[fb->idx].isnotset_sids_idx] = s->num;
520
913
                            array[fb->idx].isnotset_sids_idx++;
521
913
                        }
522
2.36k
                    }
523
3.55k
                }
524
23.8k
            }
525
23.8k
        }
526
50.2k
        for (const SigMatch *sm = s->init_data->smlists[DETECT_SM_LIST_POSTMATCH] ; sm != NULL; sm = sm->next) {
527
9.37k
            switch (sm->type) {
528
4.92k
                case DETECT_FLOWBITS:
529
4.92k
                {
530
                    /* figure out what flowbit action */
531
4.92k
                    const DetectFlowbitsData *fb = (DetectFlowbitsData *)sm->ctx;
532
4.92k
                    array[fb->idx].cnts[fb->cmd]++;
533
4.92k
                    if (has_state)
534
1.66k
                        array[fb->idx].state_cnts[fb->cmd]++;
535
4.92k
                    if (fb->cmd == DETECT_FLOWBITS_CMD_SET) {
536
3.75k
                        if (array[fb->idx].set_sids_idx >= array[fb->idx].set_sids_size) {
537
2.38k
                            uint32_t old_size = array[fb->idx].set_sids_size;
538
2.38k
                            uint32_t new_size = MAX(2 * old_size, MAX_SIDS);
539
540
2.38k
                            void *ptr = SCRealloc(array[fb->idx].set_sids, new_size * sizeof(uint32_t));
541
2.38k
                            if (ptr == NULL)
542
0
                                goto end;
543
2.38k
                            array[fb->idx].set_sids_size = new_size;
544
2.38k
                            array[fb->idx].set_sids = ptr;
545
2.38k
                        }
546
547
3.75k
                        array[fb->idx].set_sids[array[fb->idx].set_sids_idx] = s->num;
548
3.75k
                        array[fb->idx].set_sids_idx++;
549
3.75k
                    }
550
1.17k
                    else if (fb->cmd == DETECT_FLOWBITS_CMD_UNSET) {
551
991
                        if (array[fb->idx].unset_sids_idx >= array[fb->idx].unset_sids_size) {
552
376
                            uint32_t old_size = array[fb->idx].unset_sids_size;
553
376
                            uint32_t new_size = MAX(2 * old_size, MAX_SIDS);
554
555
376
                            void *ptr = SCRealloc(array[fb->idx].unset_sids, new_size * sizeof(uint32_t));
556
376
                            if (ptr == NULL)
557
0
                                goto end;
558
376
                            array[fb->idx].unset_sids_size = new_size;
559
376
                            array[fb->idx].unset_sids = ptr;
560
376
                        }
561
562
991
                        array[fb->idx].unset_sids[array[fb->idx].unset_sids_idx] = s->num;
563
991
                        array[fb->idx].unset_sids_idx++;
564
991
                    }
565
182
                    else if (fb->cmd == DETECT_FLOWBITS_CMD_TOGGLE) {
566
182
                        if (array[fb->idx].toggle_sids_idx >= array[fb->idx].toggle_sids_size) {
567
174
                            uint32_t old_size = array[fb->idx].toggle_sids_size;
568
174
                            uint32_t new_size = MAX(2 * old_size, MAX_SIDS);
569
570
174
                            void *ptr = SCRealloc(array[fb->idx].toggle_sids, new_size * sizeof(uint32_t));
571
174
                            if (ptr == NULL)
572
0
                                goto end;
573
174
                            array[fb->idx].toggle_sids_size = new_size;
574
174
                            array[fb->idx].toggle_sids = ptr;
575
174
                        }
576
577
182
                        array[fb->idx].toggle_sids[array[fb->idx].toggle_sids_idx] = s->num;
578
182
                        array[fb->idx].toggle_sids_idx++;
579
182
                    }
580
4.92k
                }
581
9.37k
            }
582
9.37k
        }
583
40.8k
    }
584
585
    /* walk array to see if all bits make sense */
586
2.38M
    for (uint32_t i = 0; i < array_size; i++) {
587
2.38M
        const char *varname = VarNameStoreSetupLookup(i, VAR_TYPE_FLOW_BIT);
588
2.38M
        if (varname == NULL)
589
999k
            continue;
590
591
2.38M
        bool to_state = false;
592
593
1.38M
        if (array[i].cnts[DETECT_FLOWBITS_CMD_ISSET] &&
594
2.71k
            array[i].cnts[DETECT_FLOWBITS_CMD_TOGGLE] == 0 &&
595
2.65k
            array[i].cnts[DETECT_FLOWBITS_CMD_SET] == 0) {
596
597
2.58k
            const Signature *s = de_ctx->sig_array[array[i].isset_sids[0]];
598
2.58k
            SCLogWarning("flowbit '%s' is checked but not "
599
2.58k
                         "set. Checked in %u and %u other sigs",
600
2.58k
                    varname, s->id, array[i].isset_sids_idx - 1);
601
2.58k
        }
602
1.38M
        if (array[i].state_cnts[DETECT_FLOWBITS_CMD_ISSET] &&
603
214
            array[i].state_cnts[DETECT_FLOWBITS_CMD_SET] == 0)
604
214
        {
605
214
            SCLogDebug("flowbit %s/%u: isset in state, set not in state", varname, i);
606
214
        }
607
608
        /* if signature depends on 'stateful' flowbits, then turn the
609
         * sig into a stateful sig itself */
610
1.38M
        if (array[i].cnts[DETECT_FLOWBITS_CMD_ISSET] > 0 &&
611
2.71k
            array[i].state_cnts[DETECT_FLOWBITS_CMD_ISSET] == 0 &&
612
2.50k
            array[i].state_cnts[DETECT_FLOWBITS_CMD_SET])
613
2
        {
614
2
            SCLogDebug("flowbit %s/%u: isset not in state, set in state", varname, i);
615
2
            to_state = true;
616
2
        }
617
618
1.38M
        SCLogDebug("ALL flowbit %s/%u: sets %u toggles %u unsets %u isnotsets %u issets %u", varname, i,
619
1.38M
                array[i].cnts[DETECT_FLOWBITS_CMD_SET], array[i].cnts[DETECT_FLOWBITS_CMD_TOGGLE],
620
1.38M
                array[i].cnts[DETECT_FLOWBITS_CMD_UNSET], array[i].cnts[DETECT_FLOWBITS_CMD_ISNOTSET],
621
1.38M
                array[i].cnts[DETECT_FLOWBITS_CMD_ISSET]);
622
1.38M
        SCLogDebug("STATE flowbit %s/%u: sets %u toggles %u unsets %u isnotsets %u issets %u", varname, i,
623
1.38M
                array[i].state_cnts[DETECT_FLOWBITS_CMD_SET], array[i].state_cnts[DETECT_FLOWBITS_CMD_TOGGLE],
624
1.38M
                array[i].state_cnts[DETECT_FLOWBITS_CMD_UNSET], array[i].state_cnts[DETECT_FLOWBITS_CMD_ISNOTSET],
625
1.38M
                array[i].state_cnts[DETECT_FLOWBITS_CMD_ISSET]);
626
1.38M
        for (uint32_t x = 0; x < array[i].set_sids_idx; x++) {
627
3.36k
            SCLogDebug("SET flowbit %s/%u: SID %u", varname, i,
628
3.36k
                    de_ctx->sig_array[array[i].set_sids[x]]->id);
629
3.36k
        }
630
1.38M
        for (uint32_t x = 0; x < array[i].isset_sids_idx; x++) {
631
3.85k
            Signature *s = de_ctx->sig_array[array[i].isset_sids[x]];
632
3.85k
            SCLogDebug("GET flowbit %s/%u: SID %u", varname, i, s->id);
633
634
3.85k
            if (to_state) {
635
2
                s->init_data->init_flags |= SIG_FLAG_INIT_STATE_MATCH;
636
2
                SCLogDebug("made SID %u stateful because it depends on "
637
2
                        "stateful rules that set flowbit %s", s->id, varname);
638
2
            }
639
3.85k
        }
640
1.38M
    }
641
642
3.26k
    if (rule_engine_analysis_set) {
643
0
        DetectFlowbitsAnalyzeDump(de_ctx, array, array_size);
644
0
    }
645
646
3.26k
end:
647
2.38M
    for (uint32_t i = 0; i < array_size; i++) {
648
2.38M
        SCFree(array[i].set_sids);
649
2.38M
        SCFree(array[i].unset_sids);
650
2.38M
        SCFree(array[i].isset_sids);
651
2.38M
        SCFree(array[i].isnotset_sids);
652
2.38M
        SCFree(array[i].toggle_sids);
653
2.38M
    }
654
3.26k
    SCFree(array);
655
656
3.26k
    return 0;
657
3.26k
}
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 */