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

OISF / suricata / 23374838686

21 Mar 2026 07:29AM UTC coverage: 59.341% (-20.0%) from 79.315%
23374838686

Pull #15075

github

web-flow
Merge 90b4e834f into 6587e363a
Pull Request #15075: Stack 8001 v16.4

38 of 70 new or added lines in 10 files covered. (54.29%)

34165 existing lines in 563 files now uncovered.

119621 of 201584 relevant lines covered (59.34%)

650666.92 hits per line

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

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

18
/**
19
 * \file
20
 *
21
 * \author Victor Julien <victor@inliniac.net>
22
 *
23
 * FLOW part of the detection engine.
24
 */
25

26
#include "suricata-common.h"
27
#include "decode.h"
28

29
#include "detect.h"
30
#include "detect-parse.h"
31
#include "detect-engine.h"
32
#include "detect-engine-prefilter-common.h"
33
#include "detect-engine-build.h"
34

35
#include "flow.h"
36
#include "flow-var.h"
37

38
#include "detect-flow.h"
39

40
#include "util-unittest.h"
41
#include "util-unittest-helper.h"
42
#include "util-debug.h"
43

44
/**
45
 * \brief Regex for parsing our flow options
46
 */
47
#define PARSE_REGEX  "^\\s*([A-z_]+)\\s*(?:,\\s*([A-z_]+))?\\s*(?:,\\s*([A-z_]+))?\\s*$"
3✔
48

49
static DetectParseRegex parse_regex;
50

51
int DetectFlowMatch (DetectEngineThreadCtx *, Packet *,
52
        const Signature *, const SigMatchCtx *);
53
static int DetectFlowSetup (DetectEngineCtx *, Signature *, const char *);
54
#ifdef UNITTESTS
55
static void DetectFlowRegisterTests(void);
56
#endif
57
void DetectFlowFree(DetectEngineCtx *, void *);
58

59
static int PrefilterSetupFlow(DetectEngineCtx *de_ctx, SigGroupHead *sgh);
60
static bool PrefilterFlowIsPrefilterable(const Signature *s);
61

62
/**
63
 * \brief Registration function for flow: keyword
64
 */
65
void DetectFlowRegister (void)
66
{
3✔
67
    sigmatch_table[DETECT_FLOW].name = "flow";
3✔
68
    sigmatch_table[DETECT_FLOW].desc = "match on direction and state of the flow";
3✔
69
    sigmatch_table[DETECT_FLOW].url = "/rules/flow-keywords.html#flow";
3✔
70
    sigmatch_table[DETECT_FLOW].Match = DetectFlowMatch;
3✔
71
    sigmatch_table[DETECT_FLOW].Setup = DetectFlowSetup;
3✔
72
    sigmatch_table[DETECT_FLOW].Free  = DetectFlowFree;
3✔
73
    sigmatch_table[DETECT_FLOW].flags = SIGMATCH_SUPPORT_FIREWALL;
3✔
74
#ifdef UNITTESTS
75
    sigmatch_table[DETECT_FLOW].RegisterTests = DetectFlowRegisterTests;
76
#endif
77
    sigmatch_table[DETECT_FLOW].SupportsPrefilter = PrefilterFlowIsPrefilterable;
3✔
78
    sigmatch_table[DETECT_FLOW].SetupPrefilter = PrefilterSetupFlow;
3✔
79
    /* all but pre_flow */
80
    sigmatch_table[DETECT_FLOW].tables =
3✔
81
            DETECT_TABLE_PACKET_PRE_STREAM_FLAG | DETECT_TABLE_PACKET_FILTER_FLAG |
3✔
82
            DETECT_TABLE_PACKET_TD_FLAG | DETECT_TABLE_APP_FILTER_FLAG | DETECT_TABLE_APP_TD_FLAG;
3✔
83

84
    DetectSetupParseRegexes(PARSE_REGEX, &parse_regex);
3✔
85
}
3✔
86

87
/**
88
 * \param pflags packet flags (p->flags)
89
 * \param pflowflags packet flow flags (p->flowflags)
90
 * \param dflags detect flow flags
91
 * \param match_cnt number of matches to trigger
92
 */
93
static inline int FlowMatch(const uint32_t pflags, const uint8_t pflowflags, const uint16_t dflags,
94
        const uint16_t match_cnt)
95
{
33,292✔
96
    uint8_t cnt = 0;
33,292✔
97

98
    if ((dflags & DETECT_FLOW_FLAG_NO_FRAG) &&
33,292✔
99
        (!(pflags & PKT_REBUILT_FRAGMENT))) {
33,292✔
UNCOV
100
        cnt++;
×
101
    } else if ((dflags & DETECT_FLOW_FLAG_ONLY_FRAG) &&
33,292✔
102
        (pflags & PKT_REBUILT_FRAGMENT)) {
33,292✔
UNCOV
103
        cnt++;
×
UNCOV
104
    }
×
105

106
    if ((dflags & DETECT_FLOW_FLAG_TOSERVER) && (pflowflags & FLOW_PKT_TOSERVER)) {
33,292✔
107
        cnt++;
5,480✔
108
    } else if ((dflags & DETECT_FLOW_FLAG_TOCLIENT) && (pflowflags & FLOW_PKT_TOCLIENT)) {
27,812✔
109
        cnt++;
930✔
110
    }
930✔
111

112
    if ((dflags & DETECT_FLOW_FLAG_ESTABLISHED) && (pflowflags & FLOW_PKT_ESTABLISHED)) {
33,292✔
113
        cnt++;
12,188✔
114
    } else if (dflags & DETECT_FLOW_FLAG_NOT_ESTABLISHED && (!(pflowflags & FLOW_PKT_ESTABLISHED))) {
21,104✔
115
        cnt++;
186✔
116
    } else if (dflags & DETECT_FLOW_FLAG_STATELESS) {
20,918✔
117
        cnt++;
17,857✔
118
    }
17,857✔
119

120
    return (match_cnt == cnt) ? 1 : 0;
33,292✔
121
}
33,292✔
122

123
/**
124
 * \brief This function is used to match flow flags set on a packet with those passed via flow:
125
 *
126
 * \param t pointer to thread vars
127
 * \param det_ctx pointer to the pattern matcher thread
128
 * \param p pointer to the current packet
129
 * \param m pointer to the sigmatch that we will cast into DetectFlowData
130
 *
131
 * \retval 0 no match
132
 * \retval 1 match
133
 */
134
int DetectFlowMatch (DetectEngineThreadCtx *det_ctx, Packet *p,
135
        const Signature *s, const SigMatchCtx *ctx)
136
{
15,873✔
137
    SCEnter();
15,873✔
138

139
    SCLogDebug("pkt %p", p);
15,873✔
140

141
    if (p->flowflags & FLOW_PKT_TOSERVER) {
15,873✔
142
        SCLogDebug("FLOW_PKT_TOSERVER");
9,760✔
143
    } else if (p->flowflags & FLOW_PKT_TOCLIENT) {
9,760✔
144
        SCLogDebug("FLOW_PKT_TOCLIENT");
6,113✔
145
    }
6,113✔
146

147
    if (p->flowflags & FLOW_PKT_ESTABLISHED) {
15,873✔
148
        SCLogDebug("FLOW_PKT_ESTABLISHED");
13,337✔
149
    }
13,337✔
150

151
    const DetectFlowData *fd = (const DetectFlowData *)ctx;
15,873✔
152

153
    const int ret = FlowMatch(p->flags, p->flowflags, fd->flags, fd->match_cnt);
15,873✔
154
    SCLogDebug("returning %" PRId32 " fd->match_cnt %" PRId32 " fd->flags 0x%02X p->flowflags 0x%02X",
15,873✔
155
        ret, fd->match_cnt, fd->flags, p->flowflags);
15,873✔
156
    SCReturnInt(ret);
15,873✔
157
}
15,873✔
158

159
/**
160
 * \brief This function is used to parse flow options passed via flow: keyword
161
 *
162
 * \param de_ctx Pointer to the detection engine context
163
 * \param flowstr Pointer to the user provided flow options
164
 * \param[out] parse_flags keyword flags only used during parsing
165
 *
166
 * \retval fd pointer to DetectFlowData on success
167
 * \retval NULL on failure
168
 */
169
static DetectFlowData *DetectFlowParse(
170
        DetectEngineCtx *de_ctx, const char *flowstr, uint16_t *parse_flags)
171
{
190,660✔
172
    DetectFlowData *fd = NULL;
190,660✔
173
    char *args[3] = {NULL,NULL,NULL};
190,660✔
174
    int res = 0;
190,660✔
175
    size_t pcre2len;
190,660✔
176
    char str1[16] = "", str2[16] = "", str3[16] = "";
190,660✔
177
    pcre2_match_data *match = NULL;
190,660✔
178

179
    int ret = DetectParsePcreExec(&parse_regex, &match, flowstr, 0, 0);
190,660✔
180
    if (ret < 1 || ret > 4) {
190,660✔
181
        SCLogError("parse error, ret %" PRId32 ", string %s", ret, flowstr);
9,157✔
182
        goto error;
9,157✔
183
    }
9,157✔
184

185
    if (ret > 1) {
181,503✔
186
        pcre2len = sizeof(str1);
181,503✔
187
        res = SC_Pcre2SubstringCopy(match, 1, (PCRE2_UCHAR8 *)str1, &pcre2len);
181,503✔
188
        if (res < 0) {
181,503✔
189
            SCLogError("pcre2_substring_copy_bynumber failed");
461✔
190
            goto error;
461✔
191
        }
461✔
192
        args[0] = (char *)str1;
181,042✔
193

194
        if (ret > 2) {
181,042✔
195
            pcre2len = sizeof(str2);
80,530✔
196
            res = pcre2_substring_copy_bynumber(match, 2, (PCRE2_UCHAR8 *)str2, &pcre2len);
80,530✔
197
            if (res < 0) {
80,530✔
198
                SCLogError("pcre2_substring_copy_bynumber failed");
40✔
199
                goto error;
40✔
200
            }
40✔
201
            args[1] = (char *)str2;
80,490✔
202
        }
80,490✔
203
        if (ret > 3) {
181,002✔
204
            pcre2len = sizeof(str3);
703✔
205
            res = pcre2_substring_copy_bynumber(match, 3, (PCRE2_UCHAR8 *)str3, &pcre2len);
703✔
206
            if (res < 0) {
703✔
207
                SCLogError("pcre2_substring_copy_bynumber failed");
23✔
208
                goto error;
23✔
209
            }
23✔
210
            args[2] = (char *)str3;
680✔
211
        }
680✔
212
    }
181,002✔
213

214
    fd = SCMalloc(sizeof(DetectFlowData));
180,979✔
215
    if (unlikely(fd == NULL))
180,979✔
216
        goto error;
×
217
    fd->flags = 0;
180,979✔
218
    fd->match_cnt = 0;
180,979✔
219

220
    for (int i = 0; i < (ret - 1); i++) {
435,298✔
221
        if (args[i]) {
260,473✔
222
            /* inspect our options and set the flags */
223
            if (strcasecmp(args[i], "established") == 0) {
260,473✔
224
                if (fd->flags & DETECT_FLOW_FLAG_ESTABLISHED) {
119,414✔
225
                    SCLogError("DETECT_FLOW_FLAG_ESTABLISHED flag is already set");
41✔
226
                    goto error;
41✔
227
                } else if (fd->flags & DETECT_FLOW_FLAG_NOT_ESTABLISHED) {
119,373✔
UNCOV
228
                    SCLogError("cannot set DETECT_FLOW_FLAG_ESTABLISHED, "
×
UNCOV
229
                               "DETECT_FLOW_FLAG_NOT_ESTABLISHED already set");
×
UNCOV
230
                    goto error;
×
231
                } else if (fd->flags & DETECT_FLOW_FLAG_STATELESS) {
119,373✔
232
                    SCLogError("DETECT_FLOW_FLAG_STATELESS already set");
83✔
233
                    goto error;
83✔
234
                }
83✔
235
                fd->flags |= DETECT_FLOW_FLAG_ESTABLISHED;
119,290✔
236
                fd->match_cnt++;
119,290✔
237
            } else if (strcasecmp(args[i], "not_established") == 0) {
141,059✔
238
                if (fd->flags & DETECT_FLOW_FLAG_NOT_ESTABLISHED) {
915✔
239
                    SCLogError("DETECT_FLOW_FLAG_NOT_ESTABLISHED flag is already set");
×
240
                    goto error;
×
241
                } else if (fd->flags & DETECT_FLOW_FLAG_ESTABLISHED) {
915✔
UNCOV
242
                    SCLogError("cannot set DETECT_FLOW_FLAG_NOT_ESTABLISHED, "
×
UNCOV
243
                               "DETECT_FLOW_FLAG_ESTABLISHED already set");
×
UNCOV
244
                    goto error;
×
UNCOV
245
                }
×
246
                fd->flags |= DETECT_FLOW_FLAG_NOT_ESTABLISHED;
915✔
247
                fd->match_cnt++;
915✔
248
            } else if (strcasecmp(args[i], "stateless") == 0) {
140,144✔
249
                if (fd->flags & DETECT_FLOW_FLAG_STATELESS) {
3,896✔
250
                    SCLogError("DETECT_FLOW_FLAG_STATELESS flag is already set");
79✔
251
                    goto error;
79✔
252
                } else if (fd->flags & DETECT_FLOW_FLAG_ESTABLISHED) {
3,817✔
253
                    SCLogError("cannot set DETECT_FLOW_FLAG_STATELESS, "
1✔
254
                               "DETECT_FLOW_FLAG_ESTABLISHED already set");
1✔
255
                    goto error;
1✔
256
                }
1✔
257
                fd->flags |= DETECT_FLOW_FLAG_STATELESS;
3,816✔
258
                fd->match_cnt++;
3,816✔
259
            } else if (strcasecmp(args[i], "to_client") == 0 || strcasecmp(args[i], "from_server") == 0) {
136,248✔
260
                if (fd->flags & DETECT_FLOW_FLAG_TOCLIENT) {
33,508✔
261
                    SCLogError("cannot set DETECT_FLOW_FLAG_TOCLIENT flag is already set");
26✔
262
                    goto error;
26✔
263
                } else if (fd->flags & DETECT_FLOW_FLAG_TOSERVER) {
33,482✔
264
                    SCLogError("cannot set to_client, DETECT_FLOW_FLAG_TOSERVER already set");
35✔
265
                    goto error;
35✔
266
                }
35✔
267
                fd->flags |= DETECT_FLOW_FLAG_TOCLIENT;
33,447✔
268
                fd->match_cnt++;
33,447✔
269
            } else if (strcasecmp(args[i], "to_server") == 0 || strcasecmp(args[i], "from_client") == 0){
102,740✔
270
                if (fd->flags & DETECT_FLOW_FLAG_TOSERVER) {
95,244✔
271
                    SCLogError("cannot set DETECT_FLOW_FLAG_TOSERVER flag is already set");
169✔
272
                    goto error;
169✔
273
                } else if (fd->flags & DETECT_FLOW_FLAG_TOCLIENT) {
95,075✔
274
                    SCLogError("cannot set to_server, DETECT_FLOW_FLAG_TO_CLIENT flag already set");
44✔
275
                    goto error;
44✔
276
                }
44✔
277
                fd->flags |= DETECT_FLOW_FLAG_TOSERVER;
95,031✔
278
                fd->match_cnt++;
95,031✔
279
            } else if (strcasecmp(args[i], "no_frag") == 0) {
95,031✔
280
                if (fd->flags & DETECT_FLOW_FLAG_NO_FRAG) {
18✔
281
                    SCLogError("cannot set no_frag flag is already set");
×
282
                    goto error;
×
283
                } else if (fd->flags & DETECT_FLOW_FLAG_ONLY_FRAG) {
18✔
284
                    SCLogError("cannot set no_frag flag, only_frag already set");
×
285
                    goto error;
×
286
                }
×
287
                fd->flags |= DETECT_FLOW_FLAG_NO_FRAG;
18✔
288
                fd->match_cnt++;
18✔
289
            } else if (strcasecmp(args[i], "only_frag") == 0) {
7,478✔
290
                if (fd->flags & DETECT_FLOW_FLAG_ONLY_FRAG) {
23✔
291
                    SCLogError("cannot set only_frag flag is already set");
×
292
                    goto error;
×
293
                } else if (fd->flags & DETECT_FLOW_FLAG_NO_FRAG) {
23✔
UNCOV
294
                    SCLogError("cannot set only_frag flag, no_frag already set");
×
UNCOV
295
                    goto error;
×
UNCOV
296
                }
×
297
                fd->flags |= DETECT_FLOW_FLAG_ONLY_FRAG;
23✔
298
                fd->match_cnt++;
23✔
299

300
                /* special case: these only affect parsing, not matching */
301

302
            } else if (strcasecmp(args[i], "only_stream") == 0) {
7,455✔
303
                if (*parse_flags & DETECT_FLOW_FLAG_ONLYSTREAM) {
1,556✔
304
                    SCLogError("cannot set only_stream flag is already set");
×
305
                    goto error;
×
306
                } else if (*parse_flags & DETECT_FLOW_FLAG_NOSTREAM) {
1,556✔
307
                    SCLogError(
×
308
                            "cannot set only_stream flag, DETECT_FLOW_FLAG_NOSTREAM already set");
×
309
                    goto error;
×
310
                }
×
311
                *parse_flags |= DETECT_FLOW_FLAG_ONLYSTREAM;
1,556✔
312
            } else if (strcasecmp(args[i], "no_stream") == 0) {
5,899✔
313
                if (*parse_flags & DETECT_FLOW_FLAG_NOSTREAM) {
223✔
314
                    SCLogError("cannot set no_stream flag is already set");
×
315
                    goto error;
×
316
                } else if (*parse_flags & DETECT_FLOW_FLAG_ONLYSTREAM) {
223✔
317
                    SCLogError(
×
318
                            "cannot set no_stream flag, DETECT_FLOW_FLAG_ONLYSTREAM already set");
×
319
                    goto error;
×
320
                }
×
321
                *parse_flags |= DETECT_FLOW_FLAG_NOSTREAM;
223✔
322
            } else {
5,676✔
323
                SCLogError("invalid flow option \"%s\"", args[i]);
5,676✔
324
                goto error;
5,676✔
325
            }
5,676✔
326
        }
260,473✔
327
    }
260,473✔
328
    pcre2_match_data_free(match);
180,979✔
329
    return fd;
174,825✔
330

331
error:
15,835✔
332
    if (match) {
15,835✔
333
        pcre2_match_data_free(match);
15,835✔
334
    }
15,835✔
335
    if (fd != NULL)
15,835✔
336
        DetectFlowFree(de_ctx, fd);
6,154✔
337
    return NULL;
15,835✔
338

339
}
180,979✔
340

341
int DetectFlowSetupImplicit(Signature *s, uint32_t flags)
342
{
313,796✔
343
#define SIG_FLAG_BOTH (SIG_FLAG_TOSERVER|SIG_FLAG_TOCLIENT)
627,592✔
344
    BUG_ON(flags == 0);
313,796✔
345
    BUG_ON(flags & ~SIG_FLAG_BOTH);
313,796✔
346
    BUG_ON((flags & SIG_FLAG_BOTH) == SIG_FLAG_BOTH);
313,796✔
347

348
    SCLogDebug("want %08x", flags & SIG_FLAG_BOTH);
313,796✔
349
    SCLogDebug("have %08x", s->flags & SIG_FLAG_BOTH);
313,796✔
350

351
    if (flags & SIG_FLAG_TOSERVER) {
313,796✔
352
        if ((s->flags & SIG_FLAG_BOTH) == SIG_FLAG_BOTH) {
267,678✔
353
            /* both is set if we just have 'flow:established' */
354
            s->flags &= ~SIG_FLAG_TOCLIENT;
250,568✔
355
        } else if (s->flags & SIG_FLAG_TOCLIENT) {
250,568✔
356
            return -1;
635✔
357
        }
635✔
358
        s->flags |= SIG_FLAG_TOSERVER;
267,043✔
359
    } else {
267,043✔
360
        if ((s->flags & SIG_FLAG_BOTH) == SIG_FLAG_BOTH) {
46,118✔
361
            /* both is set if we just have 'flow:established' */
362
            s->flags &= ~SIG_FLAG_TOSERVER;
44,443✔
363
        } else if (s->flags & SIG_FLAG_TOSERVER) {
44,443✔
364
            return -1;
12✔
365
        }
12✔
366
        s->flags |= SIG_FLAG_TOCLIENT;
46,106✔
367
    }
46,106✔
368
    return 0;
313,149✔
369
#undef SIG_FLAG_BOTH
313,796✔
370
}
313,796✔
371

372
/**
373
 * \brief this function is used to add the parsed flowdata into the current signature
374
 *
375
 * \param de_ctx pointer to the Detection Engine Context
376
 * \param s pointer to the Current Signature
377
 * \param flowstr pointer to the user provided flow options
378
 *
379
 * \retval 0 on Success
380
 * \retval -1 on Failure
381
 */
382
int DetectFlowSetup (DetectEngineCtx *de_ctx, Signature *s, const char *flowstr)
383
{
191,480✔
384
    uint16_t parse_flags = 0;
191,480✔
385

386
    /* ensure only one flow option */
387
    if (s->init_data->init_flags & SIG_FLAG_INIT_FLOW) {
191,480✔
388
        SCLogError("A signature may have only one flow option.");
820✔
389
        return -1;
820✔
390
    }
820✔
391

392
    DetectFlowData *fd = DetectFlowParse(de_ctx, flowstr, &parse_flags);
190,660✔
393
    if (fd == NULL)
190,660✔
394
        return -1;
15,835✔
395

396
    bool appendsm = true;
190,660✔
397
    /* set the signature direction flags */
398
    if (fd->flags & DETECT_FLOW_FLAG_TOSERVER) {
174,825✔
399
        if (s->flags & SIG_FLAG_TXBOTHDIR) {
94,573✔
400
            SCLogError(
12✔
401
                    "rule %u means to use both directions, cannot specify a flow direction", s->id);
12✔
402
            goto error;
12✔
403
        }
12✔
404
        if (s->flags & SIG_FLAG_TOCLIENT) {
94,561✔
405
            SCLogError("rule %u has flow to_server but a hook to_client", s->id);
2✔
406
            goto error;
2✔
407
        }
2✔
408
        s->flags |= SIG_FLAG_TOSERVER;
94,559✔
409
    } else if (fd->flags & DETECT_FLOW_FLAG_TOCLIENT) {
94,559✔
410
        if (s->flags & SIG_FLAG_TXBOTHDIR) {
33,154✔
411
            SCLogError(
2✔
412
                    "rule %u means to use both directions, cannot specify a flow direction", s->id);
2✔
413
            goto error;
2✔
414
        }
2✔
415
        if (s->flags & SIG_FLAG_TOSERVER) {
33,152✔
416
            SCLogError("rule %u has flow to_client but a hook to_server", s->id);
1✔
417
            goto error;
1✔
418
        }
1✔
419
        s->flags |= SIG_FLAG_TOCLIENT;
33,151✔
420
    } else {
47,098✔
421
        /* if direction wasn't already set, e.g. by rule hook, assume both */
422
        if ((s->flags & (SIG_FLAG_TOSERVER | SIG_FLAG_TOCLIENT)) == 0) {
47,098✔
423
            s->flags |= SIG_FLAG_TOSERVER;
47,067✔
424
            s->flags |= SIG_FLAG_TOCLIENT;
47,067✔
425
        }
47,067✔
426
    }
47,098✔
427
    if (fd->flags == 0 || fd->flags == DETECT_FLOW_FLAG_TOSERVER ||
174,808✔
428
            fd->flags == DETECT_FLOW_FLAG_TOCLIENT) {
174,808✔
429
        /* no direct flow is needed for just direction,
430
         * no sigmatch is needed either. */
431
        appendsm = false;
52,177✔
432
    } else {
122,631✔
433
        s->init_data->init_flags |= SIG_FLAG_INIT_FLOW;
122,631✔
434
    }
122,631✔
435

436
    if (appendsm) {
174,808✔
437
        if (SCSigMatchAppendSMToList(
122,631✔
438
                    de_ctx, s, DETECT_FLOW, (SigMatchCtx *)fd, DETECT_SM_LIST_MATCH) == NULL) {
122,631✔
439
            goto error;
×
440
        }
×
441
    } else {
122,631✔
442
        DetectFlowFree(de_ctx, fd);
52,177✔
443
    }
52,177✔
444

445
    if (parse_flags & DETECT_FLOW_FLAG_ONLYSTREAM) {
174,808✔
446
        s->flags |= (SIG_FLAG_REQUIRE_STREAM | SIG_FLAG_REQUIRE_STREAM_ONLY);
1,556✔
447
    }
1,556✔
448
    if (parse_flags & DETECT_FLOW_FLAG_NOSTREAM) {
174,808✔
449
        s->flags |= SIG_FLAG_REQUIRE_PACKET;
223✔
450
    }
223✔
451
    return 0;
174,808✔
452

453
error:
17✔
454
    if (fd != NULL)
17✔
455
        DetectFlowFree(de_ctx, fd);
17✔
456
    return -1;
17✔
457

458
}
174,808✔
459

460
/**
461
 * \brief this function will free memory associated with DetectFlowData
462
 *
463
 * \param fd pointer to DetectFlowData
464
 */
465
void DetectFlowFree(DetectEngineCtx *de_ctx, void *ptr)
466
{
180,979✔
467
    DetectFlowData *fd = (DetectFlowData *)ptr;
180,979✔
468
    SCFree(fd);
180,979✔
469
}
180,979✔
470

471
static void
472
PrefilterPacketFlowMatch(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx)
473
{
19,874✔
474
    SCEnter();
19,874✔
475

476
    const PrefilterPacketHeaderCtx *ctx = pectx;
19,874✔
477

478
    if (!PrefilterPacketHeaderExtraMatch(ctx, p))
19,874✔
479
        return;
2,455✔
480

481
    if (FlowMatch(p->flags, p->flowflags, ctx->v1.u16[0], ctx->v1.u16[1])) {
17,419✔
482
        SCLogDebug("match: adding sids");
17,419✔
483
        PrefilterAddSids(&det_ctx->pmq, ctx->sigs_array, ctx->sigs_cnt);
17,419✔
484
    }
17,419✔
485
    SCReturn;
17,419✔
486
}
19,874✔
487

488
static void
489
PrefilterPacketFlowSet(PrefilterPacketHeaderValue *v, void *smctx)
490
{
5,511✔
491
    const DetectFlowData *fb = smctx;
5,511✔
492
    v->u16[0] = fb->flags;
5,511✔
493
    v->u16[1] = fb->match_cnt;
5,511✔
494
}
5,511✔
495

496
static bool
497
PrefilterPacketFlowCompare(PrefilterPacketHeaderValue v, void *smctx)
498
{
3,185✔
499
    const DetectFlowData *fb = smctx;
3,185✔
500
    if (v.u16[0] == fb->flags && v.u16[1] == fb->match_cnt) {
3,185✔
501
        return true;
3,185✔
502
    }
3,185✔
503
    return false;
×
504
}
3,185✔
505

506
static int PrefilterSetupFlow(DetectEngineCtx *de_ctx, SigGroupHead *sgh)
507
{
4,175✔
508
    return PrefilterSetupPacketHeader(de_ctx, sgh, DETECT_FLOW, 0, PrefilterPacketFlowSet,
4,175✔
509
            PrefilterPacketFlowCompare, PrefilterPacketFlowMatch);
4,175✔
510
}
4,175✔
511

512
static bool PrefilterFlowIsPrefilterable(const Signature *s)
513
{
×
514
    return PrefilterIsPrefilterableById(s, DETECT_FLOW);
×
515
}
×
516

517
#ifdef UNITTESTS
518
#include "detect-engine-alert.h"
519

520
/**
521
 * \test DetectFlowTestParse01 is a test to make sure that we return "something"
522
 *  when given valid flow opt
523
 */
524
static int DetectFlowTestParse01 (void)
525
{
526
    uint16_t parsed_flags = 0;
527
    DetectFlowData *fd = DetectFlowParse(NULL, "established", &parsed_flags);
528
    FAIL_IF_NULL(fd);
529
    FAIL_IF_NOT(parsed_flags == 0);
530
    DetectFlowFree(NULL, fd);
531
    PASS;
532
}
533

534
/**
535
 * \test DetectFlowTestParse02 is a test for setting the established flow opt
536
 */
537
static int DetectFlowTestParse02 (void)
538
{
539
    uint16_t parsed_flags = 0;
540
    DetectFlowData *fd = DetectFlowParse(NULL, "established", &parsed_flags);
541
    FAIL_IF_NULL(fd);
542
    FAIL_IF_NOT(fd->flags == DETECT_FLOW_FLAG_ESTABLISHED &&
543
        fd->match_cnt == 1);
544
    DetectFlowFree(NULL, fd);
545
    PASS;
546
}
547

548
/**
549
 * \test DetectFlowTestParse03 is a test for setting the stateless flow opt
550
 */
551
static int DetectFlowTestParse03 (void)
552
{
553
    uint16_t parsed_flags = 0;
554
    DetectFlowData *fd = DetectFlowParse(NULL, "stateless", &parsed_flags);
555
    FAIL_IF_NULL(fd);
556
    FAIL_IF_NOT(fd->flags == DETECT_FLOW_FLAG_STATELESS && fd->match_cnt == 1);
557
    DetectFlowFree(NULL, fd);
558
    PASS;
559
}
560

561
/**
562
 * \test DetectFlowTestParse04 is a test for setting the to_client flow opt
563
 */
564
static int DetectFlowTestParse04 (void)
565
{
566
    uint16_t parsed_flags = 0;
567
    DetectFlowData *fd = DetectFlowParse(NULL, "to_client", &parsed_flags);
568
    FAIL_IF_NULL(fd);
569
    FAIL_IF_NOT(fd->flags == DETECT_FLOW_FLAG_TOCLIENT && fd->match_cnt == 1);
570
    DetectFlowFree(NULL, fd);
571
    PASS;
572
}
573

574
/**
575
 * \test DetectFlowTestParse05 is a test for setting the to_server flow opt
576
 */
577
static int DetectFlowTestParse05 (void)
578
{
579
    uint16_t parsed_flags = 0;
580
    DetectFlowData *fd = DetectFlowParse(NULL, "to_server", &parsed_flags);
581
    FAIL_IF_NULL(fd);
582
    FAIL_IF_NOT(fd->flags == DETECT_FLOW_FLAG_TOSERVER && fd->match_cnt == 1);
583
    DetectFlowFree(NULL, fd);
584
    PASS;
585
}
586

587
/**
588
 * \test DetectFlowTestParse06 is a test for setting the from_server flow opt
589
 */
590
static int DetectFlowTestParse06 (void)
591
{
592
    uint16_t parsed_flags = 0;
593
    DetectFlowData *fd = DetectFlowParse(NULL, "from_server", &parsed_flags);
594
    FAIL_IF_NULL(fd);
595
    FAIL_IF_NOT(fd->flags == DETECT_FLOW_FLAG_TOCLIENT && fd->match_cnt == 1);
596
    DetectFlowFree(NULL, fd);
597
    PASS;
598
}
599

600
/**
601
 * \test DetectFlowTestParse07 is a test for setting the from_client flow opt
602
 */
603
static int DetectFlowTestParse07 (void)
604
{
605
    uint16_t parsed_flags = 0;
606
    DetectFlowData *fd = DetectFlowParse(NULL, "from_client", &parsed_flags);
607
    FAIL_IF_NULL(fd);
608
    FAIL_IF_NOT(fd->flags == DETECT_FLOW_FLAG_TOSERVER && fd->match_cnt == 1);
609
    DetectFlowFree(NULL, fd);
610
    PASS;
611
}
612

613
/**
614
 * \test DetectFlowTestParse08 is a test for setting the established,to_client flow opts
615
 */
616
static int DetectFlowTestParse08 (void)
617
{
618
    uint16_t parsed_flags = 0;
619
    DetectFlowData *fd = DetectFlowParse(NULL, "established,to_client", &parsed_flags);
620
    FAIL_IF_NULL(fd);
621
    FAIL_IF_NOT(fd->flags & DETECT_FLOW_FLAG_ESTABLISHED && fd->flags & DETECT_FLOW_FLAG_TOCLIENT && fd->match_cnt == 2);
622
    DetectFlowFree(NULL, fd);
623
    PASS;
624
}
625

626
/**
627
 * \test DetectFlowTestParse09 is a test for setting the to_client,stateless flow opts (order of state,dir reversed)
628
 */
629
static int DetectFlowTestParse09 (void)
630
{
631
    uint16_t parsed_flags = 0;
632
    DetectFlowData *fd = DetectFlowParse(NULL, "to_client,stateless", &parsed_flags);
633
    FAIL_IF_NULL(fd);
634
    FAIL_IF_NOT(fd->flags & DETECT_FLOW_FLAG_STATELESS &&
635
        fd->flags & DETECT_FLOW_FLAG_TOCLIENT &&
636
        fd->match_cnt == 2);
637
    DetectFlowFree(NULL, fd);
638
    PASS;
639
}
640

641
/**
642
 * \test DetectFlowTestParse10 is a test for setting the from_server,stateless flow opts (order of state,dir reversed)
643
 */
644
static int DetectFlowTestParse10 (void)
645
{
646
    uint16_t parsed_flags = 0;
647
    DetectFlowData *fd = DetectFlowParse(NULL, "from_server,stateless", &parsed_flags);
648
    FAIL_IF_NULL(fd);
649
    FAIL_IF_NOT(fd->flags & DETECT_FLOW_FLAG_STATELESS &&
650
        fd->flags & DETECT_FLOW_FLAG_TOCLIENT &&
651
        fd->match_cnt == 2);
652
    DetectFlowFree(NULL, fd);
653
    PASS;
654
}
655

656
/**
657
 * \test DetectFlowTestParse11 is a test for setting the from_server,stateless flow opts with spaces all around
658
 */
659
static int DetectFlowTestParse11 (void)
660
{
661
    uint16_t parsed_flags = 0;
662
    DetectFlowData *fd = DetectFlowParse(NULL, " from_server , stateless ", &parsed_flags);
663
    FAIL_IF_NULL(fd);
664
    FAIL_IF_NOT(fd->flags & DETECT_FLOW_FLAG_STATELESS &&
665
        fd->flags & DETECT_FLOW_FLAG_TOCLIENT &&
666
        fd->match_cnt == 2);
667
    DetectFlowFree(NULL, fd);
668
    PASS;
669
}
670

671
/**
672
 * \test DetectFlowTestParseNocase01 is a test to make sure that we return "something"
673
 *  when given valid flow opt
674
 */
675
static int DetectFlowTestParseNocase01 (void)
676
{
677
    uint16_t parsed_flags = 0;
678
    DetectFlowData *fd = DetectFlowParse(NULL, "ESTABLISHED", &parsed_flags);
679
    FAIL_IF_NULL(fd);
680
    DetectFlowFree(NULL, fd);
681
    PASS;
682
}
683

684
/**
685
 * \test DetectFlowTestParseNocase02 is a test for setting the established flow opt
686
 */
687
static int DetectFlowTestParseNocase02 (void)
688
{
689
    uint16_t parsed_flags = 0;
690
    DetectFlowData *fd = DetectFlowParse(NULL, "ESTABLISHED", &parsed_flags);
691
    FAIL_IF_NULL(fd);
692
    FAIL_IF_NOT(fd->flags == DETECT_FLOW_FLAG_ESTABLISHED &&
693
        fd->match_cnt == 1);
694
    DetectFlowFree(NULL, fd);
695
    PASS;
696
}
697

698
/**
699
 * \test DetectFlowTestParseNocase03 is a test for setting the stateless flow opt
700
 */
701
static int DetectFlowTestParseNocase03 (void)
702
{
703
    uint16_t parsed_flags = 0;
704
    DetectFlowData *fd = DetectFlowParse(NULL, "STATELESS", &parsed_flags);
705
    FAIL_IF_NULL(fd);
706
    FAIL_IF_NOT(fd->flags == DETECT_FLOW_FLAG_STATELESS && fd->match_cnt == 1);
707
    DetectFlowFree(NULL, fd);
708
    PASS;
709
}
710

711
/**
712
 * \test DetectFlowTestParseNocase04 is a test for setting the to_client flow opt
713
 */
714
static int DetectFlowTestParseNocase04 (void)
715
{
716
    uint16_t parsed_flags = 0;
717
    DetectFlowData *fd = DetectFlowParse(NULL, "TO_CLIENT", &parsed_flags);
718
    FAIL_IF_NULL(fd);
719
    FAIL_IF_NOT(fd->flags == DETECT_FLOW_FLAG_TOCLIENT && fd->match_cnt == 1);
720
    DetectFlowFree(NULL, fd);
721
    PASS;
722
}
723

724
/**
725
 * \test DetectFlowTestParseNocase05 is a test for setting the to_server flow opt
726
 */
727
static int DetectFlowTestParseNocase05 (void)
728
{
729
    uint16_t parsed_flags = 0;
730
    DetectFlowData *fd = DetectFlowParse(NULL, "TO_SERVER", &parsed_flags);
731
    FAIL_IF_NULL(fd);
732
    FAIL_IF_NOT(fd->flags == DETECT_FLOW_FLAG_TOSERVER && fd->match_cnt == 1);
733
    DetectFlowFree(NULL, fd);
734
    PASS;
735
}
736

737
/**
738
 * \test DetectFlowTestParseNocase06 is a test for setting the from_server flow opt
739
 */
740
static int DetectFlowTestParseNocase06 (void)
741
{
742
    uint16_t parsed_flags = 0;
743
    DetectFlowData *fd = DetectFlowParse(NULL, "FROM_SERVER", &parsed_flags);
744
    FAIL_IF_NULL(fd);
745
    FAIL_IF_NOT(fd->flags == DETECT_FLOW_FLAG_TOCLIENT && fd->match_cnt == 1);
746
    DetectFlowFree(NULL, fd);
747
    PASS;
748
}
749

750
/**
751
 * \test DetectFlowTestParseNocase07 is a test for setting the from_client flow opt
752
 */
753
static int DetectFlowTestParseNocase07 (void)
754
{
755
    uint16_t parsed_flags = 0;
756
    DetectFlowData *fd = DetectFlowParse(NULL, "FROM_CLIENT", &parsed_flags);
757
    FAIL_IF_NULL(fd);
758
    FAIL_IF_NOT(fd->flags == DETECT_FLOW_FLAG_TOSERVER && fd->match_cnt == 1);
759
    DetectFlowFree(NULL, fd);
760
    PASS;
761
}
762

763
/**
764
 * \test DetectFlowTestParseNocase08 is a test for setting the established,to_client flow opts
765
 */
766
static int DetectFlowTestParseNocase08 (void)
767
{
768
    uint16_t parsed_flags = 0;
769
    DetectFlowData *fd = DetectFlowParse(NULL, "ESTABLISHED,TO_CLIENT", &parsed_flags);
770
    FAIL_IF_NULL(fd);
771
    FAIL_IF_NOT(fd->flags & DETECT_FLOW_FLAG_ESTABLISHED &&
772
        fd->flags & DETECT_FLOW_FLAG_TOCLIENT &&
773
        fd->match_cnt == 2);
774
    DetectFlowFree(NULL, fd);
775
    PASS;
776
}
777

778
/**
779
 * \test DetectFlowTestParseNocase09 is a test for setting the to_client,stateless flow opts (order of state,dir reversed)
780
 */
781
static int DetectFlowTestParseNocase09 (void)
782
{
783
    uint16_t parsed_flags = 0;
784
    DetectFlowData *fd = DetectFlowParse(NULL, "TO_CLIENT,STATELESS", &parsed_flags);
785
    FAIL_IF_NULL(fd);
786
    FAIL_IF_NOT(fd->flags & DETECT_FLOW_FLAG_STATELESS &&
787
        fd->flags & DETECT_FLOW_FLAG_TOCLIENT &&
788
        fd->match_cnt == 2);
789
    DetectFlowFree(NULL, fd);
790
    PASS;
791
}
792

793
/**
794
 * \test DetectFlowTestParseNocase10 is a test for setting the from_server,stateless flow opts (order of state,dir reversed)
795
 */
796
static int DetectFlowTestParseNocase10 (void)
797
{
798
    uint16_t parsed_flags = 0;
799
    DetectFlowData *fd = DetectFlowParse(NULL, "FROM_SERVER,STATELESS", &parsed_flags);
800
    FAIL_IF_NULL(fd);
801
    FAIL_IF_NOT(fd->flags & DETECT_FLOW_FLAG_STATELESS &&
802
        fd->flags & DETECT_FLOW_FLAG_TOCLIENT &&
803
        fd->match_cnt == 2);
804
    DetectFlowFree(NULL, fd);
805
    PASS;
806
}
807

808
/**
809
 * \test DetectFlowTestParseNocase11 is a test for setting the from_server,stateless flow opts with spaces all around
810
 */
811
static int DetectFlowTestParseNocase11 (void)
812
{
813
    uint16_t parsed_flags = 0;
814
    DetectFlowData *fd = DetectFlowParse(NULL, " FROM_SERVER , STATELESS ", &parsed_flags);
815
    FAIL_IF_NULL(fd);
816
    FAIL_IF_NOT(fd->flags & DETECT_FLOW_FLAG_STATELESS &&
817
        fd->flags & DETECT_FLOW_FLAG_TOCLIENT &&
818
        fd->match_cnt == 2);
819
    DetectFlowFree(NULL, fd);
820
    PASS;
821
}
822

823
/**
824
 * \test DetectFlowTestParse12 is a test for setting an invalid separator :
825
 */
826
static int DetectFlowTestParse12 (void)
827
{
828
    uint16_t parsed_flags = 0;
829
    DetectFlowData *fd = DetectFlowParse(NULL, "from_server:stateless", &parsed_flags);
830
    FAIL_IF_NOT_NULL(fd);
831
    PASS;
832
}
833

834
/**
835
 * \test DetectFlowTestParse13 is a test for an invalid option
836
 */
837
static int DetectFlowTestParse13 (void)
838
{
839
    uint16_t parsed_flags = 0;
840
    DetectFlowData *fd = DetectFlowParse(NULL, "invalidoptiontest", &parsed_flags);
841
    FAIL_IF_NOT_NULL(fd);
842
    PASS;
843
}
844

845
/**
846
 * \test DetectFlowTestParse14 is a test for a empty option
847
 */
848
static int DetectFlowTestParse14 (void)
849
{
850
    uint16_t parsed_flags = 0;
851
    DetectFlowData *fd = DetectFlowParse(NULL, "", &parsed_flags);
852
    FAIL_IF_NOT_NULL(fd);
853
    PASS;
854
}
855

856
/**
857
 * \test DetectFlowTestParse15 is a test for an invalid combo of options established,stateless
858
 */
859
static int DetectFlowTestParse15 (void)
860
{
861
    uint16_t parsed_flags = 0;
862
    DetectFlowData *fd = DetectFlowParse(NULL, "established,stateless", &parsed_flags);
863
    FAIL_IF_NOT_NULL(fd);
864
    PASS;
865
}
866

867
/**
868
 * \test DetectFlowTestParse16 is a test for an invalid combo of options to_client,to_server
869
 */
870
static int DetectFlowTestParse16 (void)
871
{
872
    uint16_t parsed_flags = 0;
873
    DetectFlowData *fd = DetectFlowParse(NULL, "to_client,to_server", &parsed_flags);
874
    FAIL_IF_NOT_NULL(fd);
875
    PASS;
876
}
877

878
/**
879
 * \test DetectFlowTestParse16 is a test for an invalid combo of options to_client,from_server
880
 * flowbit flags are the same
881
 */
882
static int DetectFlowTestParse17 (void)
883
{
884
    uint16_t parsed_flags = 0;
885
    DetectFlowData *fd = DetectFlowParse(NULL, "to_client,from_server", &parsed_flags);
886
    FAIL_IF_NOT_NULL(fd);
887
    PASS;
888
}
889

890
/**
891
 * \test DetectFlowTestParse18 is a test for setting the from_server,stateless,only_stream flow opts (order of state,dir reversed)
892
 */
893
static int DetectFlowTestParse18 (void)
894
{
895
    uint16_t parsed_flags = 0;
896
    DetectFlowData *fd =
897
            DetectFlowParse(NULL, "from_server,established,only_stream", &parsed_flags);
898
    FAIL_IF_NULL(fd);
899
    FAIL_IF_NOT(fd->flags & DETECT_FLOW_FLAG_ESTABLISHED && fd->flags & DETECT_FLOW_FLAG_TOCLIENT);
900
    FAIL_IF_NOT(parsed_flags == DETECT_FLOW_FLAG_ONLYSTREAM);
901
    FAIL_IF_NOT(fd->match_cnt == 2);
902
    DetectFlowFree(NULL, fd);
903
    PASS;
904
}
905

906
/**
907
 * \test DetectFlowTestParseNocase18 is a test for setting the from_server,stateless,only_stream flow opts (order of state,dir reversed)
908
 */
909
static int DetectFlowTestParseNocase18 (void)
910
{
911
    uint16_t parsed_flags = 0;
912
    DetectFlowData *fd =
913
            DetectFlowParse(NULL, "FROM_SERVER,ESTABLISHED,ONLY_STREAM", &parsed_flags);
914
    FAIL_IF_NULL(fd);
915
    FAIL_IF_NOT(fd->flags & DETECT_FLOW_FLAG_ESTABLISHED && fd->flags & DETECT_FLOW_FLAG_TOCLIENT);
916
    FAIL_IF_NOT(parsed_flags == DETECT_FLOW_FLAG_ONLYSTREAM);
917
    FAIL_IF_NOT(fd->match_cnt == 2);
918
    DetectFlowFree(NULL, fd);
919
    PASS;
920
}
921

922

923
/**
924
 * \test DetectFlowTestParse19 is a test for one to many options passed to DetectFlowParse
925
 */
926
static int DetectFlowTestParse19 (void)
927
{
928
    uint16_t parsed_flags = 0;
929
    DetectFlowData *fd =
930
            DetectFlowParse(NULL, "from_server,established,only_stream,a", &parsed_flags);
931
    FAIL_IF_NOT_NULL(fd);
932
    PASS;
933
}
934

935
/**
936
 * \test DetectFlowTestParse20 is a test for setting from_server, established, no_stream
937
 */
938
static int DetectFlowTestParse20 (void)
939
{
940
    uint16_t parsed_flags = 0;
941
    DetectFlowData *fd = DetectFlowParse(NULL, "from_server,established,no_stream", &parsed_flags);
942
    FAIL_IF_NULL(fd);
943
    FAIL_IF_NOT(fd->flags & DETECT_FLOW_FLAG_ESTABLISHED && fd->flags & DETECT_FLOW_FLAG_TOCLIENT);
944
    FAIL_IF_NOT(parsed_flags == DETECT_FLOW_FLAG_NOSTREAM);
945
    FAIL_IF_NOT(fd->match_cnt == 2);
946
    DetectFlowFree(NULL, fd);
947
    PASS;
948
}
949

950
/**
951
 * \test DetectFlowTestParse20 is a test for setting from_server, established, no_stream
952
 */
953
static int DetectFlowTestParseNocase20 (void)
954
{
955
    uint16_t parsed_flags = 0;
956
    DetectFlowData *fd = DetectFlowParse(NULL, "FROM_SERVER,ESTABLISHED,NO_STREAM", &parsed_flags);
957
    FAIL_IF_NULL(fd);
958
    FAIL_IF_NOT(fd->flags & DETECT_FLOW_FLAG_ESTABLISHED && fd->flags & DETECT_FLOW_FLAG_TOCLIENT);
959
    FAIL_IF_NOT(parsed_flags == DETECT_FLOW_FLAG_NOSTREAM);
960
    FAIL_IF_NOT(fd->match_cnt == 2);
961
    DetectFlowFree(NULL, fd);
962
    PASS;
963
}
964

965
/**
966
 * \test DetectFlowTestParse21 is a test for an invalid opt between to valid opts
967
 */
968
static int DetectFlowTestParse21 (void)
969
{
970
    uint16_t parsed_flags = 0;
971
    DetectFlowData *fd = DetectFlowParse(NULL, "from_server,a,no_stream", &parsed_flags);
972
    FAIL_IF_NOT_NULL(fd);
973
    PASS;
974
}
975

976
/**
977
 * \test DetectFlowTestParse22 is a test for setting the established,not_established flow opts both
978
 */
979
static int DetectFlowTestParse22(void)
980
{
981
    uint16_t parsed_flags = 0;
982
    DetectFlowData *fd = DetectFlowParse(NULL, "established,not_established", &parsed_flags);
983
    FAIL_IF_NOT_NULL(fd);
984
    fd = DetectFlowParse(NULL, "not_established,established", &parsed_flags);
985
    FAIL_IF_NOT_NULL(fd);
986
    PASS;
987
}
988

989
static int DetectFlowSigTest01(void)
990
{
991
    uint8_t *buf = (uint8_t *)"supernovaduper";
992
    uint16_t buflen = strlen((char *)buf);
993
    ThreadVars th_v;
994
    DecodeThreadVars dtv;
995
    memset(&dtv, 0, sizeof(DecodeThreadVars));
996
    memset(&th_v, 0, sizeof(th_v));
997
    StatsThreadInit(&th_v.stats);
998

999
    Packet *p = UTHBuildPacket(buf, buflen, IPPROTO_TCP);
1000
    FAIL_IF_NULL(p);
1001

1002
    const char *sig1 = "alert tcp any any -> any any (msg:\"dummy\"; "
1003
        "content:\"nova\"; flow:no_stream; sid:1;)";
1004

1005
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1006
    FAIL_IF_NULL(de_ctx);
1007
    de_ctx->flags |= DE_QUIET;
1008

1009
    de_ctx->sig_list = SigInit(de_ctx, sig1);
1010
    FAIL_IF_NULL(de_ctx->sig_list);
1011

1012
    SigGroupBuild(de_ctx);
1013
    DetectEngineThreadCtx *det_ctx = NULL;
1014
    DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
1015
    FAIL_IF_NULL(det_ctx);
1016

1017
    SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1018
    FAIL_IF(PacketAlertCheck(p, 1) != 1);
1019

1020
    DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
1021
    DetectEngineCtxFree(de_ctx);
1022
    UTHFreePacket(p);
1023

1024
    StatsThreadCleanup(&th_v.stats);
1025
    PASS;
1026
}
1027

1028
/**
1029
 * \test Test parsing of the not_established keyword.
1030
 */
1031
static int DetectFlowTestParseNotEstablished(void)
1032
{
1033
    uint16_t parsed_flags = 0;
1034
    DetectFlowData *fd = DetectFlowParse(NULL, "not_established", &parsed_flags);
1035
    FAIL_IF_NULL(fd);
1036
    FAIL_IF_NOT(fd->flags & DETECT_FLOW_FLAG_NOT_ESTABLISHED);
1037
    DetectFlowFree(NULL, fd);
1038
    PASS;
1039
}
1040

1041
/**
1042
 * \test Test parsing of the "no_frag" flow argument.
1043
 */
1044
static int DetectFlowTestParseNoFrag(void)
1045
{
1046
    uint16_t parsed_flags = 0;
1047
    DetectFlowData *fd = DetectFlowParse(NULL, "no_frag", &parsed_flags);
1048
    FAIL_IF_NULL(fd);
1049
    FAIL_IF_NOT(fd->flags & DETECT_FLOW_FLAG_NO_FRAG);
1050
    DetectFlowFree(NULL, fd);
1051
    PASS;
1052
}
1053

1054
/**
1055
 * \test Test parsing of the "only_frag" flow argument.
1056
 */
1057
static int DetectFlowTestParseOnlyFrag(void)
1058
{
1059
    uint16_t parsed_flags = 0;
1060
    DetectFlowData *fd = DetectFlowParse(NULL, "only_frag", &parsed_flags);
1061
    FAIL_IF_NULL(fd);
1062
    FAIL_IF_NOT(fd->flags & DETECT_FLOW_FLAG_ONLY_FRAG);
1063
    DetectFlowFree(NULL, fd);
1064
    PASS;
1065
}
1066

1067
/**
1068
 * \test Test that parsing of only_frag and no_frag together fails.
1069
 */
1070
static int DetectFlowTestParseNoFragOnlyFrag(void)
1071
{
1072
    uint16_t parsed_flags = 0;
1073
    DetectFlowData *fd = DetectFlowParse(NULL, "no_frag,only_frag", &parsed_flags);
1074
    FAIL_IF_NOT_NULL(fd);
1075
    PASS;
1076
}
1077

1078
/**
1079
 * \test Test no_frag matching.
1080
 */
1081
static int DetectFlowTestNoFragMatch(void)
1082
{
1083
    uint16_t parsed_flags = 0;
1084
    uint32_t pflags = 0;
1085
    DetectFlowData *fd = DetectFlowParse(NULL, "no_frag", &parsed_flags);
1086
    FAIL_IF_NULL(fd);
1087
    FAIL_IF_NOT(fd->flags & DETECT_FLOW_FLAG_NO_FRAG);
1088
    FAIL_IF_NOT(fd->match_cnt == 1);
1089
    FAIL_IF_NOT(FlowMatch(pflags, 0, fd->flags, fd->match_cnt));
1090
    pflags |= PKT_REBUILT_FRAGMENT;
1091
    FAIL_IF(FlowMatch(pflags, 0, fd->flags, fd->match_cnt));
1092
    DetectFlowFree(NULL, fd);
1093
    PASS;
1094
}
1095

1096
/**
1097
 * \test Test only_frag matching.
1098
 */
1099
static int DetectFlowTestOnlyFragMatch(void)
1100
{
1101
    uint16_t parsed_flags = 0;
1102
    uint32_t pflags = 0;
1103
    DetectFlowData *fd = DetectFlowParse(NULL, "only_frag", &parsed_flags);
1104
    FAIL_IF_NULL(fd);
1105
    FAIL_IF_NOT(fd->flags & DETECT_FLOW_FLAG_ONLY_FRAG);
1106
    FAIL_IF_NOT(fd->match_cnt == 1);
1107
    FAIL_IF(FlowMatch(pflags, 0, fd->flags, fd->match_cnt));
1108
    pflags |= PKT_REBUILT_FRAGMENT;
1109
    FAIL_IF_NOT(FlowMatch(pflags, 0, fd->flags, fd->match_cnt));
1110
    DetectFlowFree(NULL, fd);
1111
    PASS;
1112
}
1113

1114
/**
1115
 * \brief this function registers unit tests for DetectFlow
1116
 */
1117
static void DetectFlowRegisterTests(void)
1118
{
1119
    UtRegisterTest("DetectFlowTestParse01", DetectFlowTestParse01);
1120
    UtRegisterTest("DetectFlowTestParse02", DetectFlowTestParse02);
1121
    UtRegisterTest("DetectFlowTestParse03", DetectFlowTestParse03);
1122
    UtRegisterTest("DetectFlowTestParse04", DetectFlowTestParse04);
1123
    UtRegisterTest("DetectFlowTestParse05", DetectFlowTestParse05);
1124
    UtRegisterTest("DetectFlowTestParse06", DetectFlowTestParse06);
1125
    UtRegisterTest("DetectFlowTestParse07", DetectFlowTestParse07);
1126
    UtRegisterTest("DetectFlowTestParse08", DetectFlowTestParse08);
1127
    UtRegisterTest("DetectFlowTestParse09", DetectFlowTestParse09);
1128
    UtRegisterTest("DetectFlowTestParse10", DetectFlowTestParse10);
1129
    UtRegisterTest("DetectFlowTestParse11", DetectFlowTestParse11);
1130
    UtRegisterTest("DetectFlowTestParseNocase01", DetectFlowTestParseNocase01);
1131
    UtRegisterTest("DetectFlowTestParseNocase02", DetectFlowTestParseNocase02);
1132
    UtRegisterTest("DetectFlowTestParseNocase03", DetectFlowTestParseNocase03);
1133
    UtRegisterTest("DetectFlowTestParseNocase04", DetectFlowTestParseNocase04);
1134
    UtRegisterTest("DetectFlowTestParseNocase05", DetectFlowTestParseNocase05);
1135
    UtRegisterTest("DetectFlowTestParseNocase06", DetectFlowTestParseNocase06);
1136
    UtRegisterTest("DetectFlowTestParseNocase07", DetectFlowTestParseNocase07);
1137
    UtRegisterTest("DetectFlowTestParseNocase08", DetectFlowTestParseNocase08);
1138
    UtRegisterTest("DetectFlowTestParseNocase09", DetectFlowTestParseNocase09);
1139
    UtRegisterTest("DetectFlowTestParseNocase10", DetectFlowTestParseNocase10);
1140
    UtRegisterTest("DetectFlowTestParseNocase11", DetectFlowTestParseNocase11);
1141
    UtRegisterTest("DetectFlowTestParse12", DetectFlowTestParse12);
1142
    UtRegisterTest("DetectFlowTestParse13", DetectFlowTestParse13);
1143
    UtRegisterTest("DetectFlowTestParse14", DetectFlowTestParse14);
1144
    UtRegisterTest("DetectFlowTestParse15", DetectFlowTestParse15);
1145
    UtRegisterTest("DetectFlowTestParse16", DetectFlowTestParse16);
1146
    UtRegisterTest("DetectFlowTestParse17", DetectFlowTestParse17);
1147
    UtRegisterTest("DetectFlowTestParse18", DetectFlowTestParse18);
1148
    UtRegisterTest("DetectFlowTestParseNocase18", DetectFlowTestParseNocase18);
1149
    UtRegisterTest("DetectFlowTestParse19", DetectFlowTestParse19);
1150
    UtRegisterTest("DetectFlowTestParse20", DetectFlowTestParse20);
1151
    UtRegisterTest("DetectFlowTestParseNocase20", DetectFlowTestParseNocase20);
1152
    UtRegisterTest("DetectFlowTestParse21", DetectFlowTestParse21);
1153
    UtRegisterTest("DetectFlowTestParse22", DetectFlowTestParse22);
1154
    UtRegisterTest("DetectFlowTestParseNotEstablished",
1155
        DetectFlowTestParseNotEstablished);
1156
    UtRegisterTest("DetectFlowTestParseNoFrag", DetectFlowTestParseNoFrag);
1157
    UtRegisterTest("DetectFlowTestParseOnlyFrag",
1158
        DetectFlowTestParseOnlyFrag);
1159
    UtRegisterTest("DetectFlowTestParseNoFragOnlyFrag",
1160
        DetectFlowTestParseNoFragOnlyFrag);
1161
    UtRegisterTest("DetectFlowTestNoFragMatch", DetectFlowTestNoFragMatch);
1162
    UtRegisterTest("DetectFlowTestOnlyFragMatch", DetectFlowTestOnlyFragMatch);
1163

1164
    UtRegisterTest("DetectFlowSigTest01", DetectFlowSigTest01);
1165
}
1166
#endif /* UNITTESTS */
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