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

OISF / suricata / 22550902417

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

Pull #14922

github

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

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

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

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

218243 of 319063 relevant lines covered (68.4%)

3284926.58 hits per line

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

94.92
/src/detect-fast-pattern.c
1
/* Copyright (C) 2007-2021 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 Anoop Saldanha <anoopsaldanha@gmail.com>
22
 *
23
 * Implements the fast_pattern keyword
24
 */
25

26
#include "suricata-common.h"
27
#include "detect.h"
28
#include "flow.h"
29
#include "detect-content.h"
30
#include "detect-parse.h"
31
#include "detect-engine.h"
32
#include "detect-engine-mpm.h"
33
#include "detect-engine-build.h"
34
#include "detect-fast-pattern.h"
35

36
#include "util-error.h"
37
#include "util-byte.h"
38
#include "util-debug.h"
39
#include "util-unittest.h"
40
#include "util-unittest-helper.h"
41

42
#define PARSE_REGEX "^(\\s*only\\s*)|\\s*([0-9]+)\\s*,\\s*([0-9]+)\\s*$"
37✔
43

44
static DetectParseRegex parse_regex;
45

46
static int DetectFastPatternSetup(DetectEngineCtx *, Signature *, const char *);
47
#ifdef UNITTESTS
48
static void DetectFastPatternRegisterTests(void);
49
#endif
50

51
/* holds the list of sm match lists that need to be searched for a keyword
52
 * that has fp support */
53
static SCFPSupportSMList *g_fp_support_smlist_list = NULL;
54

55
/**
56
 * \brief Checks if a particular buffer is in the list
57
 *        of lists that need to be searched for a keyword that has fp support.
58
 *
59
 * \param list_id The list id.
60
 *
61
 * \retval 1 If supported.
62
 * \retval 0 If not.
63
 */
64
int FastPatternSupportEnabledForSigMatchList(const DetectEngineCtx *de_ctx,
65
        const int list_id)
66
{
49,735✔
67
    if (de_ctx->fp_support_smlist_list == NULL) {
49,735✔
68
        return 0;
×
69
    }
×
70

71
    if (list_id == DETECT_SM_LIST_PMATCH)
49,735✔
72
        return 1;
5,556✔
73

74
    return DetectEngineBufferTypeSupportsMpmGetById(de_ctx, list_id);
44,179✔
75
}
49,735✔
76

77
static void Add(SCFPSupportSMList **list, const int list_id, const int priority)
78
{
14,073✔
79
    SCFPSupportSMList *ip = NULL;
14,073✔
80
    /* insertion point - ip */
81
    for (SCFPSupportSMList *tmp = *list; tmp != NULL; tmp = tmp->next) {
896,099✔
82
        if (list_id == tmp->list_id) {
895,967✔
83
            SCLogDebug("SM list already registered.");
7,963✔
84
            return;
7,963✔
85
        }
7,963✔
86

87
        /* We need a strict check to be sure that the current list
88
         * was not already registered
89
         * and other lists with the same priority hide it.
90
         */
91
        if (priority < tmp->priority)
888,004✔
92
            break;
5,978✔
93

94
        ip = tmp;
882,026✔
95
    }
882,026✔
96

97
    if (*list == NULL) {
6,110✔
98
        SCFPSupportSMList *new = SCCalloc(1, sizeof(SCFPSupportSMList));
38✔
99
        if (unlikely(new == NULL))
38✔
100
            exit(EXIT_FAILURE);
×
101
        new->list_id = list_id;
38✔
102
        new->priority = priority;
38✔
103

104
        *list = new;
38✔
105
        return;
38✔
106
    }
38✔
107

108
    SCFPSupportSMList *new = SCCalloc(1, sizeof(SCFPSupportSMList));
6,072✔
109
    if (unlikely(new == NULL))
6,072✔
110
        exit(EXIT_FAILURE);
×
111
    new->list_id = list_id;
6,072✔
112
    new->priority = priority;
6,072✔
113
    if (ip == NULL) {
6,072✔
114
        new->next = *list;
73✔
115
        *list = new;
73✔
116
    } else {
5,999✔
117
        new->next = ip->next;
5,999✔
118
        ip->next = new;
5,999✔
119
    }
5,999✔
120
}
6,072✔
121

122
/**
123
 * \brief Lets one add a sm list id to be searched for potential fp supported
124
 *        keywords later.
125
 *
126
 * \param list_id SM list id.
127
 * \param priority Priority for this list.
128
 */
129
void SupportFastPatternForSigMatchList(int list_id, int priority)
130
{
14,060✔
131
    Add(&g_fp_support_smlist_list, list_id, priority);
14,060✔
132
}
14,060✔
133

134
void DetectEngineRegisterFastPatternForId(DetectEngineCtx *de_ctx, int list_id, int priority)
135
{
13✔
136
    Add(&de_ctx->fp_support_smlist_list, list_id, priority);
13✔
137
}
13✔
138

139
/**
140
 * \brief Registers the keywords(SMs) that should be given fp support.
141
 */
142
void SupportFastPatternForSigMatchTypes(void)
143
{
37✔
144
    SupportFastPatternForSigMatchList(DETECT_SM_LIST_PMATCH, 3);
37✔
145

146
    /* other types are handled by DetectMpmAppLayerRegister() */
147
}
37✔
148

149
void DetectEngineInitializeFastPatternList(DetectEngineCtx *de_ctx)
150
{
1,563✔
151
    SCFPSupportSMList *last = NULL;
1,563✔
152
    for (SCFPSupportSMList *tmp = g_fp_support_smlist_list; tmp != NULL; tmp = tmp->next) {
259,426✔
153
        SCFPSupportSMList *n = SCCalloc(1, sizeof(*n));
257,860✔
154
        if (n == NULL) {
257,860✔
155
            FatalError("out of memory: %s", strerror(errno));
×
156
        }
×
157
        n->list_id = tmp->list_id;
257,860✔
158
        n->priority = tmp->priority;
257,860✔
159

160
        // append
161
        if (de_ctx->fp_support_smlist_list == NULL) {
257,860✔
162
            last = de_ctx->fp_support_smlist_list = n;
1,563✔
163
        } else {
256,297✔
164
            BUG_ON(last == NULL);
256,297✔
165
            last->next = n;
256,300✔
166
            last = n;
256,300✔
167
        }
256,300✔
168
    }
257,860✔
169
}
1,563✔
170

171
void DetectEngineFreeFastPatternList(DetectEngineCtx *de_ctx)
172
{
1,559✔
173
    for (SCFPSupportSMList *tmp = de_ctx->fp_support_smlist_list; tmp != NULL;) {
258,635✔
174
        SCFPSupportSMList *next = tmp->next;
257,076✔
175
        SCFree(tmp);
257,076✔
176
        tmp = next;
257,076✔
177
    }
257,076✔
178
    de_ctx->fp_support_smlist_list = NULL;
1,559✔
179
}
1,559✔
180

181
/**
182
 * \brief Registration function for fast_pattern keyword
183
 */
184
void DetectFastPatternRegister(void)
185
{
37✔
186
    sigmatch_table[DETECT_FAST_PATTERN].name = "fast_pattern";
37✔
187
    sigmatch_table[DETECT_FAST_PATTERN].desc = "force using preceding content in the multi pattern matcher";
37✔
188
    sigmatch_table[DETECT_FAST_PATTERN].url = "/rules/prefilter-keywords.html#fast-pattern";
37✔
189
    sigmatch_table[DETECT_FAST_PATTERN].Match = NULL;
37✔
190
    sigmatch_table[DETECT_FAST_PATTERN].Setup = DetectFastPatternSetup;
37✔
191
    sigmatch_table[DETECT_FAST_PATTERN].Free  = NULL;
37✔
192
#ifdef UNITTESTS
3✔
193
    sigmatch_table[DETECT_FAST_PATTERN].RegisterTests = DetectFastPatternRegisterTests;
3✔
194
#endif
3✔
195
    sigmatch_table[DETECT_FAST_PATTERN].flags |= SIGMATCH_OPTIONAL_OPT;
37✔
196

197
    DetectSetupParseRegexes(PARSE_REGEX, &parse_regex);
37✔
198
}
37✔
199

200
/**
201
 * \brief Configures the previous content context for a fast_pattern modifier
202
 *        keyword used in the rule.
203
 *
204
 * \param de_ctx   Pointer to the Detection Engine Context.
205
 * \param s        Pointer to the Signature to which the current keyword belongs.
206
 * \param arg      May hold an argument
207
 *
208
 * \retval  0 On success.
209
 * \retval -1 On failure.
210
 */
211
static int DetectFastPatternSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg)
212
{
18,588✔
213
    int res = 0;
18,588✔
214
    size_t pcre2len;
18,588✔
215
    char arg_substr[128] = "";
18,588✔
216
    DetectContentData *cd = NULL;
18,588✔
217
    pcre2_match_data *match = NULL;
18,588✔
218

219
    SigMatch *pm1 = DetectGetLastSMFromMpmLists(de_ctx, s);
18,588✔
220
    SigMatch *pm2 = SCDetectGetLastSMFromLists(s, DETECT_CONTENT, -1);
18,588✔
221
    if (pm1 == NULL && pm2 == NULL) {
18,588✔
222
        SCLogError("fast_pattern found inside "
×
223
                   "the rule, without a content context. Please use a "
×
224
                   "content based keyword before using fast_pattern");
×
225
        return -1;
×
226
    }
×
227

228
    SigMatch *pm = NULL;
18,588✔
229
    if (pm1 && pm2) {
18,588✔
230
        if (pm1->idx > pm2->idx)
16,394✔
231
            pm = pm1;
×
232
        else
16,394✔
233
            pm = pm2;
16,394✔
234
    } else if (pm1 && !pm2) {
16,394✔
235
        pm = pm1;
×
236
    } else {
2,194✔
237
        pm = pm2;
2,194✔
238
    }
2,194✔
239

240
    if (s->flags & SIG_FLAG_TXBOTHDIR && s->init_data->curbuf != NULL) {
18,588✔
241
        if (DetectBufferToClient(de_ctx, s->init_data->curbuf->id, s->alproto)) {
×
242
            if (s->init_data->init_flags & SIG_FLAG_INIT_TXDIR_STREAMING_TOSERVER) {
×
243
                SCLogError("fast_pattern cannot be used on to_client keyword for "
×
244
                           "transactional rule with a streaming buffer to server %u",
×
245
                        s->id);
×
246
                goto error;
×
247
            }
×
248
            s->init_data->init_flags |= SIG_FLAG_INIT_TXDIR_FAST_TOCLIENT;
×
249
        }
×
250
    }
×
251

252
    cd = (DetectContentData *)pm->ctx;
18,588✔
253
    if ((cd->flags & DETECT_CONTENT_NEGATED) &&
18,588✔
254
        ((cd->flags & DETECT_CONTENT_DISTANCE) ||
18,588✔
255
         (cd->flags & DETECT_CONTENT_WITHIN) ||
84✔
256
         (cd->flags & DETECT_CONTENT_OFFSET) ||
84✔
257
         (cd->flags & DETECT_CONTENT_DEPTH))) {
84✔
258

259
        /* we can't have any of these if we are having "only" */
260
        SCLogError("fast_pattern; cannot be "
×
261
                   "used with negated content, along with relative modifiers");
×
262
        goto error;
×
263
    }
×
264

265
    if (arg == NULL|| strcmp(arg, "") == 0) {
18,588✔
266
        if (cd->flags & DETECT_CONTENT_FAST_PATTERN) {
18,164✔
267
            SCLogError("can't use multiple fast_pattern "
×
268
                       "options for the same content");
×
269
            goto error;
×
270
        }
×
271
        else { /*allow only one content to have fast_pattern modifier*/
18,164✔
272
            for (uint32_t list_id = 0; list_id < DETECT_SM_LIST_MAX; list_id++) {
145,312✔
273
                SigMatch *sm = NULL;
127,148✔
274
                for (sm = s->init_data->smlists[list_id]; sm != NULL; sm = sm->next) {
146,721✔
275
                    if (sm->type == DETECT_CONTENT) {
19,573✔
276
                        DetectContentData *tmp_cd = (DetectContentData *)sm->ctx;
3,206✔
277
                        if (tmp_cd->flags & DETECT_CONTENT_FAST_PATTERN) {
3,206✔
278
                            SCLogError("fast_pattern "
×
279
                                       "can be used on only one content in a rule");
×
280
                            goto error;
×
281
                        }
×
282
                    }
3,206✔
283
                }
19,573✔
284
            }
127,148✔
285
        }
18,164✔
286
        if (SigMatchListSMBelongsTo(s, pm) == DETECT_SM_LIST_BASE64_DATA) {
18,164✔
287
            SCLogError("fast_pattern cannot be used with base64_data");
×
288
            goto error;
×
289
        }
×
290
        cd->flags |= DETECT_CONTENT_FAST_PATTERN;
18,164✔
291
        return 0;
18,164✔
292
    }
18,164✔
293

294
    /* Execute the regex and populate args with captures. */
295
    int ret = DetectParsePcreExec(&parse_regex, &match, arg, 0, 0);
424✔
296
    /* fast pattern only */
297
    if (ret == 2) {
424✔
298
        if ((cd->flags & DETECT_CONTENT_NEGATED) ||
220✔
299
            (cd->flags & DETECT_CONTENT_DISTANCE) ||
220✔
300
            (cd->flags & DETECT_CONTENT_WITHIN) ||
220✔
301
            (cd->flags & DETECT_CONTENT_OFFSET) ||
220✔
302
            (cd->flags & DETECT_CONTENT_DEPTH)) {
220✔
303

304
            /* we can't have any of these if we are having "only" */
305
            SCLogError("fast_pattern: only; cannot be "
61✔
306
                       "used with negated content or with any of the relative "
61✔
307
                       "modifiers like distance, within, offset, depth");
61✔
308
            goto error;
61✔
309
        }
61✔
310
        cd->flags |= DETECT_CONTENT_FAST_PATTERN_ONLY;
159✔
311

312
        /* fast pattern chop */
313
    } else if (ret == 4) {
204✔
314
        pcre2len = sizeof(arg_substr);
179✔
315
        res = pcre2_substring_copy_bynumber(match, 2, (PCRE2_UCHAR8 *)arg_substr, &pcre2len);
179✔
316
        if (res < 0) {
179✔
317
            SCLogError("pcre2_substring_copy_bynumber failed "
×
318
                       "for fast_pattern offset");
×
319
            goto error;
×
320
        }
×
321
        uint16_t offset;
179✔
322
        if (StringParseUint16(&offset, 10, 0, (const char *)arg_substr) <= 0) {
179✔
323
            SCLogError("Invalid fast pattern offset:"
12✔
324
                       " \"%s\"",
12✔
325
                    arg_substr);
12✔
326
            goto error;
12✔
327
        }
12✔
328

329
        pcre2len = sizeof(arg_substr);
167✔
330
        res = pcre2_substring_copy_bynumber(match, 3, (PCRE2_UCHAR8 *)arg_substr, &pcre2len);
167✔
331
        if (res < 0) {
167✔
332
            SCLogError("pcre2_substring_copy_bynumber failed "
×
333
                       "for fast_pattern offset");
×
334
            goto error;
×
335
        }
×
336
        uint16_t length;
167✔
337
        if (StringParseUint16(&length, 10, 0, (const char *)arg_substr) <= 0) {
167✔
338
            SCLogError("Invalid value for fast "
12✔
339
                       "pattern: \"%s\"",
12✔
340
                    arg_substr);
12✔
341
            goto error;
12✔
342
        }
12✔
343

344
        // Avoiding integer overflow
345
        if (offset > (65535 - length)) {
155✔
346
            SCLogError("Fast pattern (length + offset) "
24✔
347
                       "exceeds limit pattern length limit");
24✔
348
            goto error;
24✔
349
        }
24✔
350

351
        if (offset + length > cd->content_len) {
131✔
352
            SCLogError("Fast pattern (length + "
25✔
353
                       "offset (%u)) exceeds pattern length (%u)",
25✔
354
                    offset + length, cd->content_len);
25✔
355
            goto error;
25✔
356
        }
25✔
357

358
        cd->fp_chop_offset = offset;
106✔
359
        cd->fp_chop_len = length;
106✔
360
        cd->flags |= DETECT_CONTENT_FAST_PATTERN_CHOP;
106✔
361

362
    } else {
106✔
363
        SCLogError("parse error, ret %" PRId32 ", string %s", ret, arg);
25✔
364
        goto error;
25✔
365
    }
25✔
366

367
    cd->flags |= DETECT_CONTENT_FAST_PATTERN;
265✔
368

369
    pcre2_match_data_free(match);
265✔
370
    return 0;
265✔
371

372
 error:
159✔
373
     if (match) {
159✔
374
         pcre2_match_data_free(match);
159✔
375
     }
159✔
376
    return -1;
159✔
377
}
424✔
378

379
/*----------------------------------Unittests---------------------------------*/
380

381
#ifdef UNITTESTS
382
#include "detect-engine-alert.h"
383
#include "detect-engine-buffer.h"
384
static SigMatch *GetMatches(Signature *s, const int list)
385
{
197✔
386
    SigMatch *sm = DetectBufferGetFirstSigMatch(s, list);
197✔
387
    if (sm == NULL && list < DETECT_SM_LIST_MAX) {
197✔
388
        sm = s->init_data->smlists[list];
16✔
389
    }
16✔
390
    return sm;
197✔
391
}
197✔
392

393
static int DetectFastPatternStickySingle(const char *sticky, const int list)
394
{
13✔
395
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
13✔
396
    FAIL_IF_NULL(de_ctx);
13✔
397
    char string[1024];
13✔
398
    snprintf(string, sizeof(string),
13✔
399
            "alert tcp any any -> any any "
13✔
400
            "(%s%scontent:\"one\"; fast_pattern; sid:1;)",
13✔
401
            sticky ? sticky : "", sticky ? "; " : " ");
13✔
402
    Signature *s = DetectEngineAppendSig(de_ctx, string);
13✔
403
    FAIL_IF_NULL(s);
13✔
404
    SigMatch *sm = GetMatches(s, list);
13✔
405
    FAIL_IF_NULL(sm);
13✔
406
    FAIL_IF_NOT(sm->type == DETECT_CONTENT);
13✔
407
    DetectContentData *cd = (DetectContentData *)sm->ctx;
13✔
408
    FAIL_IF_NOT(DETECT_CONTENT_IS_SINGLE(cd));
13✔
409
    FAIL_IF_NOT((cd->flags & DETECT_CONTENT_FAST_PATTERN) == DETECT_CONTENT_FAST_PATTERN);
13✔
410
    DetectEngineCtxFree(de_ctx);
13✔
411
    PASS;
13✔
412
}
13✔
413

414
static int DetectFastPatternModifierSingle(const char *sticky, const int list)
415
{
12✔
416
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
12✔
417
    FAIL_IF_NULL(de_ctx);
12✔
418
    char string[1024];
12✔
419
    snprintf(string, sizeof(string),
12✔
420
            "alert tcp any any -> any any "
12✔
421
            "(content:\"one\"; %s%sfast_pattern; sid:1;)",
12✔
422
            sticky ? sticky : "", sticky ? "; " : " ");
12✔
423
    Signature *s = DetectEngineAppendSig(de_ctx, string);
12✔
424
    FAIL_IF_NULL(s);
12✔
425
    SigMatch *sm = GetMatches(s, list);
12✔
426
    FAIL_IF_NULL(sm);
12✔
427
    FAIL_IF_NOT(sm->type == DETECT_CONTENT);
12✔
428
    DetectContentData *cd = (DetectContentData *)sm->ctx;
12✔
429
    FAIL_IF_NOT(DETECT_CONTENT_IS_SINGLE(cd));
12✔
430
    FAIL_IF_NOT((cd->flags & DETECT_CONTENT_FAST_PATTERN) == DETECT_CONTENT_FAST_PATTERN);
12✔
431
    DetectEngineCtxFree(de_ctx);
12✔
432
    PASS;
12✔
433
}
12✔
434

435
static int DetectFastPatternStickySingleNoFP(const char *sticky, const int list)
436
{
13✔
437
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
13✔
438
    FAIL_IF_NULL(de_ctx);
13✔
439
    char string[1024];
13✔
440
    snprintf(string, sizeof(string),
13✔
441
            "alert tcp any any -> any any "
13✔
442
            "(%s%scontent:\"one\"; sid:1;)",
13✔
443
            sticky ? sticky : "", sticky ? "; " : " ");
13✔
444
    Signature *s = DetectEngineAppendSig(de_ctx, string);
13✔
445
    FAIL_IF_NULL(s);
13✔
446
    SigMatch *sm = GetMatches(s, list);
13✔
447
    FAIL_IF_NULL(sm);
13✔
448
    FAIL_IF_NOT(sm->type == DETECT_CONTENT);
13✔
449
    DetectContentData *cd = (DetectContentData *)sm->ctx;
13✔
450
    FAIL_IF_NOT(DETECT_CONTENT_IS_SINGLE(cd));
13✔
451
    FAIL_IF_NOT((cd->flags & DETECT_CONTENT_FAST_PATTERN) == 0);
13✔
452
    DetectEngineCtxFree(de_ctx);
13✔
453
    PASS;
13✔
454
}
13✔
455

456
static int DetectFastPatternModifierSingleNoFP(const char *sticky, const int list)
457
{
12✔
458
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
12✔
459
    FAIL_IF_NULL(de_ctx);
12✔
460
    char string[1024];
12✔
461
    snprintf(string, sizeof(string),
12✔
462
            "alert tcp any any -> any any "
12✔
463
            "(content:\"one\"; %s%ssid:1;)",
12✔
464
            sticky ? sticky : "", sticky ? "; " : " ");
12✔
465
    Signature *s = DetectEngineAppendSig(de_ctx, string);
12✔
466
    FAIL_IF_NULL(s);
12✔
467
    SigMatch *sm = GetMatches(s, list);
12✔
468
    FAIL_IF_NULL(sm);
12✔
469
    FAIL_IF_NOT(sm->type == DETECT_CONTENT);
12✔
470
    DetectContentData *cd = (DetectContentData *)sm->ctx;
12✔
471
    FAIL_IF_NOT(DETECT_CONTENT_IS_SINGLE(cd));
12✔
472
    FAIL_IF_NOT((cd->flags & DETECT_CONTENT_FAST_PATTERN) == 0);
12✔
473
    DetectEngineCtxFree(de_ctx);
12✔
474
    PASS;
12✔
475
}
12✔
476

477
static int DetectFastPatternStickySingleBadArg(const char *sticky)
478
{
13✔
479
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
13✔
480
    FAIL_IF_NULL(de_ctx);
13✔
481
    char string[1024];
13✔
482
    /* bogus argument to fast_pattern */
483
    snprintf(string, sizeof(string),
13✔
484
            "alert tcp any any -> any any "
13✔
485
            "(%s%scontent:\"one\"; fast_pattern:boo; sid:1;)",
13✔
486
            sticky ? sticky : "", sticky ? "; " : " ");
13✔
487
    Signature *s = DetectEngineAppendSig(de_ctx, string);
13✔
488
    FAIL_IF_NOT_NULL(s);
13✔
489
    /* fast_pattern only with distance */
490
    snprintf(string, sizeof(string),
13✔
491
            "alert tcp any any -> any any "
13✔
492
            "(%s%scontent:\"one\"; fast_pattern:only; content:\"two\"; distance:10; sid:1;)",
13✔
493
            sticky ? sticky : "", sticky ? "; " : " ");
13✔
494
    s = DetectEngineAppendSig(de_ctx, string);
13✔
495
    FAIL_IF_NOT_NULL(s);
13✔
496
    /* fast_pattern only with distance */
497
    snprintf(string, sizeof(string),
13✔
498
            "alert tcp any any -> any any "
13✔
499
            "(%s%scontent:\"one\"; content:\"two\"; fast_pattern:only; distance:10; sid:1;)",
13✔
500
            sticky ? sticky : "", sticky ? "; " : " ");
13✔
501
    s = DetectEngineAppendSig(de_ctx, string);
13✔
502
    FAIL_IF_NOT_NULL(s);
13✔
503
    /* fast_pattern only with distance */
504
    snprintf(string, sizeof(string),
13✔
505
            "alert tcp any any -> any any "
13✔
506
            "(%s%scontent:\"one\"; content:\"two\"; distance:10; fast_pattern:only; sid:1;)",
13✔
507
            sticky ? sticky : "", sticky ? "; " : " ");
13✔
508
    s = DetectEngineAppendSig(de_ctx, string);
13✔
509
    FAIL_IF_NOT_NULL(s);
13✔
510
    /* fast_pattern chop with invalid values */
511
    snprintf(string, sizeof(string),
13✔
512
            "alert tcp any any -> any any "
13✔
513
            "(%s%scontent:\"one\"; fast_pattern:5,6; sid:1;)",
13✔
514
            sticky ? sticky : "", sticky ? "; " : " ");
13✔
515
    s = DetectEngineAppendSig(de_ctx, string);
13✔
516
    FAIL_IF_NOT_NULL(s);
13✔
517
    DetectEngineCtxFree(de_ctx);
13✔
518
    PASS;
13✔
519
}
13✔
520

521
static int DetectFastPatternModifierBadRules(const char *sticky)
522
{
12✔
523
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
12✔
524
    FAIL_IF_NULL(de_ctx);
12✔
525
    char string[1024];
12✔
526
    /* bogus argument to fast_pattern */
527
    snprintf(string, sizeof(string),
12✔
528
            "alert tcp any any -> any any "
12✔
529
            "(content:\"one\"; %s%sfast_pattern:boo; sid:1;)",
12✔
530
            sticky ? sticky : "", sticky ? "; " : " ");
12✔
531
    Signature *s = DetectEngineAppendSig(de_ctx, string);
12✔
532
    FAIL_IF_NOT_NULL(s);
12✔
533
    /* fast_pattern only with distance */
534
    snprintf(string, sizeof(string),
12✔
535
            "alert tcp any any -> any any "
12✔
536
            "(content:\"one\"; %s%sfast_pattern:only; content:\"two\"; %s%sdistance:10; sid:1;)",
12✔
537
            sticky ? sticky : "", sticky ? "; " : " ", sticky ? sticky : "", sticky ? "; " : " ");
12✔
538
    s = DetectEngineAppendSig(de_ctx, string);
12✔
539
    FAIL_IF_NOT_NULL(s);
12✔
540
#if 0 // TODO bug?
541
    /* fast_pattern only with distance */
542
    snprintf(string, sizeof(string), "alert tcp any any -> any any "
543
            "(content:\"one\"; %s%s content:\"two\"; %s%sdistance:10; fast_pattern:only; sid:1;)",
544
            sticky ? sticky : "", sticky ? "; " : " ", sticky ? sticky : "", sticky ? "; " : " ");
545
    s = DetectEngineAppendSig(de_ctx, string);
546
    FAIL_IF_NOT_NULL(s);
547
#endif
548
    /* fast_pattern only with within */
549
    snprintf(string, sizeof(string),
12✔
550
            "alert tcp any any -> any any "
12✔
551
            "(content:\"one\"; %s%sfast_pattern:only; content:\"two\"; %s%swithin:10; sid:1;)",
12✔
552
            sticky ? sticky : "", sticky ? "; " : " ", sticky ? sticky : "", sticky ? "; " : " ");
12✔
553
    s = DetectEngineAppendSig(de_ctx, string);
12✔
554
    FAIL_IF_NOT_NULL(s);
12✔
555
    /* fast_pattern only with within */
556
    snprintf(string, sizeof(string),
12✔
557
            "alert tcp any any -> any any "
12✔
558
            "(content:\"one\"; %s%s content:\"two\"; %s%swithin:10; fast_pattern:only; sid:1;)",
12✔
559
            sticky ? sticky : "", sticky ? "; " : " ", sticky ? sticky : "", sticky ? "; " : " ");
12✔
560
    s = DetectEngineAppendSig(de_ctx, string);
12✔
561
    FAIL_IF_NOT_NULL(s);
12✔
562
    /* fast_pattern only with offset */
563
    snprintf(string, sizeof(string),
12✔
564
            "alert tcp any any -> any any "
12✔
565
            "(content:\"one\"; %s%sfast_pattern:only; offset:10; sid:1;)",
12✔
566
            sticky ? sticky : "", sticky ? "; " : " ");
12✔
567
    s = DetectEngineAppendSig(de_ctx, string);
12✔
568
    FAIL_IF_NOT_NULL(s);
12✔
569
    /* fast_pattern only with offset */
570
    snprintf(string, sizeof(string),
12✔
571
            "alert tcp any any -> any any "
12✔
572
            "(content:\"one\"; %s%s offset:10; fast_pattern:only; sid:1;)",
12✔
573
            sticky ? sticky : "", sticky ? "; " : " ");
12✔
574
    s = DetectEngineAppendSig(de_ctx, string);
12✔
575
    FAIL_IF_NOT_NULL(s);
12✔
576
    /* fast_pattern only with depth */
577
    snprintf(string, sizeof(string),
12✔
578
            "alert tcp any any -> any any "
12✔
579
            "(content:\"one\"; %s%sfast_pattern:only; depth:10; sid:1;)",
12✔
580
            sticky ? sticky : "", sticky ? "; " : " ");
12✔
581
    s = DetectEngineAppendSig(de_ctx, string);
12✔
582
    FAIL_IF_NOT_NULL(s);
12✔
583
    /* fast_pattern only with depth */
584
    snprintf(string, sizeof(string),
12✔
585
            "alert tcp any any -> any any "
12✔
586
            "(content:\"one\"; %s%s depth:10; fast_pattern:only; sid:1;)",
12✔
587
            sticky ? sticky : "", sticky ? "; " : " ");
12✔
588
    s = DetectEngineAppendSig(de_ctx, string);
12✔
589
    FAIL_IF_NOT_NULL(s);
12✔
590
    /* fast_pattern only negate */
591
    snprintf(string, sizeof(string),
12✔
592
            "alert tcp any any -> any any "
12✔
593
            "(content:\"one\"; %s%s content:!\"two\"; %s%sfast_pattern:only; sid:1;)",
12✔
594
            sticky ? sticky : "", sticky ? "; " : " ", sticky ? sticky : "", sticky ? "; " : " ");
12✔
595
    s = DetectEngineAppendSig(de_ctx, string);
12✔
596
    FAIL_IF_NOT_NULL(s);
12✔
597
    /* fast_pattern chop with invalid values */
598
    snprintf(string, sizeof(string),
12✔
599
            "alert tcp any any -> any any "
12✔
600
            "(content:\"one\"; %s%sfast_pattern:5,6; sid:1;)",
12✔
601
            sticky ? sticky : "", sticky ? "; " : " ");
12✔
602
    s = DetectEngineAppendSig(de_ctx, string);
12✔
603
    FAIL_IF_NOT_NULL(s);
12✔
604
    /* fast_pattern chop with invalid values */
605
    snprintf(string, sizeof(string),
12✔
606
            "alert tcp any any -> any any "
12✔
607
            "(content:\"one\"; %s%sfast_pattern:65977,2; sid:1;)",
12✔
608
            sticky ? sticky : "", sticky ? "; " : " ");
12✔
609
    s = DetectEngineAppendSig(de_ctx, string);
12✔
610
    FAIL_IF_NOT_NULL(s);
12✔
611
    /* fast_pattern chop with invalid values */
612
    snprintf(string, sizeof(string),
12✔
613
            "alert tcp any any -> any any "
12✔
614
            "(content:\"one\"; %s%sfast_pattern:2,65977; sid:1;)",
12✔
615
            sticky ? sticky : "", sticky ? "; " : " ");
12✔
616
    s = DetectEngineAppendSig(de_ctx, string);
12✔
617
    FAIL_IF_NOT_NULL(s);
12✔
618
    /* fast_pattern chop with invalid values */
619
    snprintf(string, sizeof(string),
12✔
620
            "alert tcp any any -> any any "
12✔
621
            "(content:\"one\"; %s%sfast_pattern:2,65534; sid:1;)",
12✔
622
            sticky ? sticky : "", sticky ? "; " : " ");
12✔
623
    s = DetectEngineAppendSig(de_ctx, string);
12✔
624
    FAIL_IF_NOT_NULL(s);
12✔
625
    /* fast_pattern chop with invalid values */
626
    snprintf(string, sizeof(string),
12✔
627
            "alert tcp any any -> any any "
12✔
628
            "(content:\"one\"; %s%sfast_pattern:65534,2; sid:1;)",
12✔
629
            sticky ? sticky : "", sticky ? "; " : " ");
12✔
630
    s = DetectEngineAppendSig(de_ctx, string);
12✔
631
    FAIL_IF_NOT_NULL(s);
12✔
632
    /* negated fast_pattern with distance */
633
    snprintf(string, sizeof(string),
12✔
634
            "alert tcp any any -> any any "
12✔
635
            "(content:\"one\"; %s%scontent:!\"two\"; fast_pattern:1,2; %s%sdistance:10; sid:1;)",
12✔
636
            sticky ? sticky : "", sticky ? "; " : " ", sticky ? sticky : "", sticky ? "; " : " ");
12✔
637
    s = DetectEngineAppendSig(de_ctx, string);
12✔
638
    FAIL_IF_NOT_NULL(s);
12✔
639
    /* negated fast_pattern with within */
640
    snprintf(string, sizeof(string),
12✔
641
            "alert tcp any any -> any any "
12✔
642
            "(content:\"one\"; %s%scontent:!\"two\"; fast_pattern:1,2; %s%swithin:10; sid:1;)",
12✔
643
            sticky ? sticky : "", sticky ? "; " : " ", sticky ? sticky : "", sticky ? "; " : " ");
12✔
644
    s = DetectEngineAppendSig(de_ctx, string);
12✔
645
    FAIL_IF_NOT_NULL(s);
12✔
646
    /* negated fast_pattern with depth */
647
    snprintf(string, sizeof(string),
12✔
648
            "alert tcp any any -> any any "
12✔
649
            "(content:\"one\"; %s%scontent:!\"two\"; fast_pattern:1,2; %s%sdepth:10; sid:1;)",
12✔
650
            sticky ? sticky : "", sticky ? "; " : " ", sticky ? sticky : "", sticky ? "; " : " ");
12✔
651
    s = DetectEngineAppendSig(de_ctx, string);
12✔
652
    FAIL_IF_NOT_NULL(s);
12✔
653
    /* negated fast_pattern with offset */
654
    snprintf(string, sizeof(string),
12✔
655
            "alert tcp any any -> any any "
12✔
656
            "(content:\"one\"; %s%scontent:!\"two\"; fast_pattern:1,2; %s%soffset:10; sid:1;)",
12✔
657
            sticky ? sticky : "", sticky ? "; " : " ", sticky ? sticky : "", sticky ? "; " : " ");
12✔
658
    s = DetectEngineAppendSig(de_ctx, string);
12✔
659
    FAIL_IF_NOT_NULL(s);
12✔
660
    DetectEngineCtxFree(de_ctx);
12✔
661
    PASS;
12✔
662
}
12✔
663

664
static int DetectFastPatternStickySingleFPOnly(const char *sticky, const int list)
665
{
13✔
666
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
13✔
667
    FAIL_IF_NULL(de_ctx);
13✔
668
    char string[1024];
13✔
669
    snprintf(string, sizeof(string),
13✔
670
            "alert tcp any any -> any any "
13✔
671
            "(%s%scontent:\"one\"; fast_pattern:only; sid:1;)",
13✔
672
            sticky ? sticky : "", sticky ? "; " : " ");
13✔
673
    Signature *s = DetectEngineAppendSig(de_ctx, string);
13✔
674
    FAIL_IF_NULL(s);
13✔
675
    SigMatch *sm = GetMatches(s, list);
13✔
676
    FAIL_IF_NULL(sm);
13✔
677
    FAIL_IF_NOT(sm->type == DETECT_CONTENT);
13✔
678
    DetectContentData *cd = (DetectContentData *)sm->ctx;
13✔
679
    FAIL_IF_NOT(DETECT_CONTENT_IS_SINGLE(cd));
13✔
680
    FAIL_IF_NOT((cd->flags & (DETECT_CONTENT_FAST_PATTERN | DETECT_CONTENT_FAST_PATTERN_ONLY)) ==
13✔
681
                (DETECT_CONTENT_FAST_PATTERN | DETECT_CONTENT_FAST_PATTERN_ONLY));
13✔
682
    DetectEngineCtxFree(de_ctx);
13✔
683
    PASS;
13✔
684
}
13✔
685

686
static int DetectFastPatternModifierFPOnly(const char *sticky, const int list)
687
{
12✔
688
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
12✔
689
    FAIL_IF_NULL(de_ctx);
12✔
690
    char string[1024];
12✔
691
    snprintf(string, sizeof(string),
12✔
692
            "alert tcp any any -> any any "
12✔
693
            "(content:\"one\"; %s%sfast_pattern:only; sid:1;)",
12✔
694
            sticky ? sticky : "", sticky ? "; " : " ");
12✔
695
    Signature *s = DetectEngineAppendSig(de_ctx, string);
12✔
696
    FAIL_IF_NULL(s);
12✔
697
    SigMatch *sm = GetMatches(s, list);
12✔
698
    FAIL_IF_NULL(sm);
12✔
699
    FAIL_IF_NOT(sm->type == DETECT_CONTENT);
12✔
700
    DetectContentData *cd = (DetectContentData *)sm->ctx;
12✔
701
    FAIL_IF_NOT(DETECT_CONTENT_IS_SINGLE(cd));
12✔
702
    FAIL_IF_NOT((cd->flags & (DETECT_CONTENT_FAST_PATTERN | DETECT_CONTENT_FAST_PATTERN_ONLY)) ==
12✔
703
                (DETECT_CONTENT_FAST_PATTERN | DETECT_CONTENT_FAST_PATTERN_ONLY));
12✔
704

705
    snprintf(string, sizeof(string),
12✔
706
            "alert tcp any any -> any any "
12✔
707
            "(content:\"one\"; %s%scontent:\"two\"; %s%sfast_pattern:only; sid:2;)",
12✔
708
            sticky ? sticky : "", sticky ? "; " : " ", sticky ? sticky : "", sticky ? "; " : " ");
12✔
709
    s = DetectEngineAppendSig(de_ctx, string);
12✔
710
    FAIL_IF_NULL(s);
12✔
711
    sm = GetMatches(s, list);
12✔
712
    FAIL_IF_NULL(sm);
12✔
713
    FAIL_IF_NULL(sm->next);
12✔
714
    FAIL_IF_NOT(sm->type == DETECT_CONTENT);
12✔
715
    cd = (DetectContentData *)sm->ctx;
12✔
716
    FAIL_IF_NOT(DETECT_CONTENT_IS_SINGLE(cd));
12✔
717
    FAIL_IF_NOT(
12✔
718
            (cd->flags & (DETECT_CONTENT_FAST_PATTERN | DETECT_CONTENT_FAST_PATTERN_ONLY)) == 0);
12✔
719
    sm = sm->next;
12✔
720
    FAIL_IF_NOT(sm->type == DETECT_CONTENT);
12✔
721
    cd = (DetectContentData *)sm->ctx;
12✔
722
    FAIL_IF_NOT(DETECT_CONTENT_IS_SINGLE(cd));
12✔
723
    FAIL_IF_NOT((cd->flags & (DETECT_CONTENT_FAST_PATTERN | DETECT_CONTENT_FAST_PATTERN_ONLY)) ==
12✔
724
                (DETECT_CONTENT_FAST_PATTERN | DETECT_CONTENT_FAST_PATTERN_ONLY));
12✔
725

726
    snprintf(string, sizeof(string),
12✔
727
            "alert tcp any any -> any any "
12✔
728
            "(content:\"one\"; %s%scontent:\"two\"; distance:10; %s%scontent:\"three\"; "
12✔
729
            "%s%sfast_pattern:only; sid:3;)",
12✔
730
            sticky ? sticky : "", sticky ? "; " : " ", sticky ? sticky : "", sticky ? "; " : " ",
12✔
731
            sticky ? sticky : "", sticky ? "; " : " ");
12✔
732
    s = DetectEngineAppendSig(de_ctx, string);
12✔
733
    FAIL_IF_NULL(s);
12✔
734
    sm = GetMatches(s, list);
12✔
735
    FAIL_IF_NULL(sm);
12✔
736
    FAIL_IF_NULL(sm->next);
12✔
737
    FAIL_IF_NOT(sm->type == DETECT_CONTENT);
12✔
738
    cd = (DetectContentData *)sm->ctx;
12✔
739
    FAIL_IF(DETECT_CONTENT_IS_SINGLE(cd));
12✔
740
    FAIL_IF_NOT(
12✔
741
            (cd->flags & (DETECT_CONTENT_FAST_PATTERN | DETECT_CONTENT_FAST_PATTERN_ONLY)) == 0);
12✔
742
    sm = sm->next;
12✔
743
    FAIL_IF_NULL(sm->next);
12✔
744
    FAIL_IF_NOT(sm->type == DETECT_CONTENT);
12✔
745
    cd = (DetectContentData *)sm->ctx;
12✔
746
    FAIL_IF(DETECT_CONTENT_IS_SINGLE(cd));
12✔
747
    FAIL_IF_NOT(
12✔
748
            (cd->flags & (DETECT_CONTENT_FAST_PATTERN | DETECT_CONTENT_FAST_PATTERN_ONLY)) == 0);
12✔
749
    sm = sm->next;
12✔
750
    FAIL_IF_NOT_NULL(sm->next);
12✔
751
    FAIL_IF_NOT(sm->type == DETECT_CONTENT);
12✔
752
    cd = (DetectContentData *)sm->ctx;
12✔
753
    FAIL_IF_NOT(DETECT_CONTENT_IS_SINGLE(cd));
12✔
754
    FAIL_IF_NOT((cd->flags & (DETECT_CONTENT_FAST_PATTERN | DETECT_CONTENT_FAST_PATTERN_ONLY)) ==
12✔
755
                (DETECT_CONTENT_FAST_PATTERN | DETECT_CONTENT_FAST_PATTERN_ONLY));
12✔
756

757
    snprintf(string, sizeof(string),
12✔
758
            "alert tcp any any -> any any "
12✔
759
            "(content:\"one\"; %s%scontent:\"two\"; within:10; %s%scontent:\"three\"; "
12✔
760
            "%s%sfast_pattern:only; sid:4;)",
12✔
761
            sticky ? sticky : "", sticky ? "; " : " ", sticky ? sticky : "", sticky ? "; " : " ",
12✔
762
            sticky ? sticky : "", sticky ? "; " : " ");
12✔
763
    s = DetectEngineAppendSig(de_ctx, string);
12✔
764
    FAIL_IF_NULL(s);
12✔
765
    sm = GetMatches(s, list);
12✔
766
    FAIL_IF_NULL(sm);
12✔
767
    FAIL_IF_NULL(sm->next);
12✔
768
    FAIL_IF_NOT(sm->type == DETECT_CONTENT);
12✔
769
    cd = (DetectContentData *)sm->ctx;
12✔
770
    FAIL_IF(DETECT_CONTENT_IS_SINGLE(cd));
12✔
771
    FAIL_IF_NOT(
12✔
772
            (cd->flags & (DETECT_CONTENT_FAST_PATTERN | DETECT_CONTENT_FAST_PATTERN_ONLY)) == 0);
12✔
773
    sm = sm->next;
12✔
774
    FAIL_IF_NULL(sm->next);
12✔
775
    FAIL_IF_NOT(sm->type == DETECT_CONTENT);
12✔
776
    cd = (DetectContentData *)sm->ctx;
12✔
777
    FAIL_IF(DETECT_CONTENT_IS_SINGLE(cd));
12✔
778
    FAIL_IF_NOT(
12✔
779
            (cd->flags & (DETECT_CONTENT_FAST_PATTERN | DETECT_CONTENT_FAST_PATTERN_ONLY)) == 0);
12✔
780
    sm = sm->next;
12✔
781
    FAIL_IF_NOT_NULL(sm->next);
12✔
782
    FAIL_IF_NOT(sm->type == DETECT_CONTENT);
12✔
783
    cd = (DetectContentData *)sm->ctx;
12✔
784
    FAIL_IF_NOT(DETECT_CONTENT_IS_SINGLE(cd));
12✔
785
    FAIL_IF_NOT((cd->flags & (DETECT_CONTENT_FAST_PATTERN | DETECT_CONTENT_FAST_PATTERN_ONLY)) ==
12✔
786
                (DETECT_CONTENT_FAST_PATTERN | DETECT_CONTENT_FAST_PATTERN_ONLY));
12✔
787

788
    snprintf(string, sizeof(string),
12✔
789
            "alert tcp any any -> any any "
12✔
790
            "(content:\"one\"; %s%scontent:\"two\"; offset:10; %s%scontent:\"three\"; "
12✔
791
            "%s%sfast_pattern:only; sid:5;)",
12✔
792
            sticky ? sticky : "", sticky ? "; " : " ", sticky ? sticky : "", sticky ? "; " : " ",
12✔
793
            sticky ? sticky : "", sticky ? "; " : " ");
12✔
794
    s = DetectEngineAppendSig(de_ctx, string);
12✔
795
    FAIL_IF_NULL(s);
12✔
796
    sm = GetMatches(s, list);
12✔
797
    FAIL_IF_NULL(sm);
12✔
798
    FAIL_IF_NULL(sm->next);
12✔
799
    FAIL_IF_NOT(sm->type == DETECT_CONTENT);
12✔
800
    cd = (DetectContentData *)sm->ctx;
12✔
801
    FAIL_IF_NOT(DETECT_CONTENT_IS_SINGLE(cd));
12✔
802
    FAIL_IF_NOT(
12✔
803
            (cd->flags & (DETECT_CONTENT_FAST_PATTERN | DETECT_CONTENT_FAST_PATTERN_ONLY)) == 0);
12✔
804
    sm = sm->next;
12✔
805
    FAIL_IF_NULL(sm->next);
12✔
806
    FAIL_IF_NOT(sm->type == DETECT_CONTENT);
12✔
807
    cd = (DetectContentData *)sm->ctx;
12✔
808
    FAIL_IF(DETECT_CONTENT_IS_SINGLE(cd));
12✔
809
    FAIL_IF_NOT(
12✔
810
            (cd->flags & (DETECT_CONTENT_FAST_PATTERN | DETECT_CONTENT_FAST_PATTERN_ONLY)) == 0);
12✔
811
    sm = sm->next;
12✔
812
    FAIL_IF_NOT_NULL(sm->next);
12✔
813
    FAIL_IF_NOT(sm->type == DETECT_CONTENT);
12✔
814
    cd = (DetectContentData *)sm->ctx;
12✔
815
    FAIL_IF_NOT(DETECT_CONTENT_IS_SINGLE(cd));
12✔
816
    FAIL_IF_NOT((cd->flags & (DETECT_CONTENT_FAST_PATTERN | DETECT_CONTENT_FAST_PATTERN_ONLY)) ==
12✔
817
                (DETECT_CONTENT_FAST_PATTERN | DETECT_CONTENT_FAST_PATTERN_ONLY));
12✔
818

819
    snprintf(string, sizeof(string),
12✔
820
            "alert tcp any any -> any any "
12✔
821
            "(content:\"one\"; %s%scontent:\"two\"; depth:10; %s%scontent:\"three\"; "
12✔
822
            "%s%sfast_pattern:only; sid:6;)",
12✔
823
            sticky ? sticky : "", sticky ? "; " : " ", sticky ? sticky : "", sticky ? "; " : " ",
12✔
824
            sticky ? sticky : "", sticky ? "; " : " ");
12✔
825
    s = DetectEngineAppendSig(de_ctx, string);
12✔
826
    FAIL_IF_NULL(s);
12✔
827
    sm = GetMatches(s, list);
12✔
828
    FAIL_IF_NULL(sm);
12✔
829
    FAIL_IF_NULL(sm->next);
12✔
830
    FAIL_IF_NOT(sm->type == DETECT_CONTENT);
12✔
831
    cd = (DetectContentData *)sm->ctx;
12✔
832
    FAIL_IF_NOT(DETECT_CONTENT_IS_SINGLE(cd));
12✔
833
    FAIL_IF_NOT(
12✔
834
            (cd->flags & (DETECT_CONTENT_FAST_PATTERN | DETECT_CONTENT_FAST_PATTERN_ONLY)) == 0);
12✔
835
    sm = sm->next;
12✔
836
    FAIL_IF_NULL(sm->next);
12✔
837
    FAIL_IF_NOT(sm->type == DETECT_CONTENT);
12✔
838
    cd = (DetectContentData *)sm->ctx;
12✔
839
    FAIL_IF(DETECT_CONTENT_IS_SINGLE(cd));
12✔
840
    FAIL_IF_NOT(
12✔
841
            (cd->flags & (DETECT_CONTENT_FAST_PATTERN | DETECT_CONTENT_FAST_PATTERN_ONLY)) == 0);
12✔
842
    sm = sm->next;
12✔
843
    FAIL_IF_NOT_NULL(sm->next);
12✔
844
    FAIL_IF_NOT(sm->type == DETECT_CONTENT);
12✔
845
    cd = (DetectContentData *)sm->ctx;
12✔
846
    FAIL_IF_NOT(DETECT_CONTENT_IS_SINGLE(cd));
12✔
847
    FAIL_IF_NOT((cd->flags & (DETECT_CONTENT_FAST_PATTERN | DETECT_CONTENT_FAST_PATTERN_ONLY)) ==
12✔
848
                (DETECT_CONTENT_FAST_PATTERN | DETECT_CONTENT_FAST_PATTERN_ONLY));
12✔
849

850
    snprintf(string, sizeof(string),
12✔
851
            "alert tcp any any -> any any "
12✔
852
            "(content:!\"one\"; %s%sfast_pattern; content:\"two\"; depth:10; %s%ssid:7;)",
12✔
853
            sticky ? sticky : "", sticky ? "; " : " ", sticky ? sticky : "", sticky ? "; " : " ");
12✔
854
    s = DetectEngineAppendSig(de_ctx, string);
12✔
855
    FAIL_IF_NULL(s);
12✔
856
    sm = GetMatches(s, list);
12✔
857
    FAIL_IF_NULL(sm);
12✔
858
    FAIL_IF_NULL(sm->next);
12✔
859
    FAIL_IF_NOT(sm->type == DETECT_CONTENT);
12✔
860
    cd = (DetectContentData *)sm->ctx;
12✔
861
    FAIL_IF_NOT(DETECT_CONTENT_IS_SINGLE(cd));
12✔
862
    FAIL_IF_NOT((cd->flags & (DETECT_CONTENT_FAST_PATTERN | DETECT_CONTENT_FAST_PATTERN_ONLY |
12✔
863
                                     DETECT_CONTENT_NEGATED)) ==
12✔
864
                (DETECT_CONTENT_FAST_PATTERN | DETECT_CONTENT_NEGATED));
12✔
865
    sm = sm->next;
12✔
866
    FAIL_IF_NOT_NULL(sm->next);
12✔
867
    FAIL_IF_NOT(sm->type == DETECT_CONTENT);
12✔
868
    cd = (DetectContentData *)sm->ctx;
12✔
869
    FAIL_IF(DETECT_CONTENT_IS_SINGLE(cd));
12✔
870
    FAIL_IF_NOT(
12✔
871
            (cd->flags & (DETECT_CONTENT_FAST_PATTERN | DETECT_CONTENT_FAST_PATTERN_ONLY)) == 0);
12✔
872

873
    DetectEngineCtxFree(de_ctx);
12✔
874
    PASS;
12✔
875
}
12✔
876

877
static int DetectFastPatternStickyFPChop(const char *sticky, const int list)
878
{
13✔
879
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
13✔
880
    FAIL_IF_NULL(de_ctx);
13✔
881
    char string[1024];
13✔
882
    snprintf(string, sizeof(string),
13✔
883
            "alert tcp any any -> any any "
13✔
884
            "(%s%scontent:\"onetwothree\"; fast_pattern:3,4; sid:1;)",
13✔
885
            sticky ? sticky : "", sticky ? "; " : " ");
13✔
886
    Signature *s = DetectEngineAppendSig(de_ctx, string);
13✔
887
    FAIL_IF_NULL(s);
13✔
888
    SigMatch *sm = GetMatches(s, list);
13✔
889
    FAIL_IF_NULL(sm);
13✔
890
    FAIL_IF_NOT(sm->type == DETECT_CONTENT);
13✔
891
    DetectContentData *cd = (DetectContentData *)sm->ctx;
13✔
892
    FAIL_IF_NOT(DETECT_CONTENT_IS_SINGLE(cd));
13✔
893
    FAIL_IF_NOT((cd->flags & (DETECT_CONTENT_FAST_PATTERN | DETECT_CONTENT_FAST_PATTERN_CHOP |
13✔
894
                                     DETECT_CONTENT_FAST_PATTERN_ONLY)) ==
13✔
895
                (DETECT_CONTENT_FAST_PATTERN | DETECT_CONTENT_FAST_PATTERN_CHOP));
13✔
896
    FAIL_IF_NOT(cd->fp_chop_offset == 3);
13✔
897
    FAIL_IF_NOT(cd->fp_chop_len == 4);
13✔
898

899
    snprintf(string, sizeof(string),
13✔
900
            "alert tcp any any -> any any "
13✔
901
            "(%s%scontent:\"onetwothree\"; fast_pattern:3,4; content:\"xyz\"; distance:10; sid:2;)",
13✔
902
            sticky ? sticky : "", sticky ? "; " : " ");
13✔
903
    s = DetectEngineAppendSig(de_ctx, string);
13✔
904
    FAIL_IF_NULL(s);
13✔
905
    sm = GetMatches(s, list);
13✔
906
    FAIL_IF_NULL(sm);
13✔
907
    FAIL_IF_NOT(sm->type == DETECT_CONTENT);
13✔
908
    cd = (DetectContentData *)sm->ctx;
13✔
909
    FAIL_IF(DETECT_CONTENT_IS_SINGLE(cd));
13✔
910
    FAIL_IF_NOT((cd->flags & (DETECT_CONTENT_FAST_PATTERN | DETECT_CONTENT_FAST_PATTERN_CHOP |
13✔
911
                                     DETECT_CONTENT_FAST_PATTERN_ONLY)) ==
13✔
912
                (DETECT_CONTENT_FAST_PATTERN | DETECT_CONTENT_FAST_PATTERN_CHOP));
13✔
913
    FAIL_IF_NOT(cd->fp_chop_offset == 3);
13✔
914
    FAIL_IF_NOT(cd->fp_chop_len == 4);
13✔
915

916
    DetectEngineCtxFree(de_ctx);
13✔
917
    PASS;
13✔
918
}
13✔
919

920
static int DetectFastPatternModifierFPChop(const char *sticky, const int list)
921
{
12✔
922
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
12✔
923
    FAIL_IF_NULL(de_ctx);
12✔
924
    char string[1024];
12✔
925
    snprintf(string, sizeof(string),
12✔
926
            "alert tcp any any -> any any "
12✔
927
            "(content:\"onetwothree\"; %s%sfast_pattern:3,4; sid:1;)",
12✔
928
            sticky ? sticky : "", sticky ? "; " : " ");
12✔
929
    Signature *s = DetectEngineAppendSig(de_ctx, string);
12✔
930
    FAIL_IF_NULL(s);
12✔
931
    SigMatch *sm = GetMatches(s, list);
12✔
932
    FAIL_IF_NULL(sm);
12✔
933
    FAIL_IF_NOT(sm->type == DETECT_CONTENT);
12✔
934
    DetectContentData *cd = (DetectContentData *)sm->ctx;
12✔
935
    FAIL_IF_NOT(DETECT_CONTENT_IS_SINGLE(cd));
12✔
936
    FAIL_IF_NOT((cd->flags & (DETECT_CONTENT_FAST_PATTERN | DETECT_CONTENT_FAST_PATTERN_CHOP |
12✔
937
                                     DETECT_CONTENT_FAST_PATTERN_ONLY)) ==
12✔
938
                (DETECT_CONTENT_FAST_PATTERN | DETECT_CONTENT_FAST_PATTERN_CHOP));
12✔
939
    FAIL_IF_NOT(cd->fp_chop_offset == 3);
12✔
940
    FAIL_IF_NOT(cd->fp_chop_len == 4);
12✔
941

942
    snprintf(string, sizeof(string),
12✔
943
            "alert tcp any any -> any any "
12✔
944
            "(content:!\"onetwothree\"; %s%sfast_pattern:3,4; sid:2;)",
12✔
945
            sticky ? sticky : "", sticky ? "; " : " ");
12✔
946
    s = DetectEngineAppendSig(de_ctx, string);
12✔
947
    FAIL_IF_NULL(s);
12✔
948
    sm = GetMatches(s, list);
12✔
949
    FAIL_IF_NULL(sm);
12✔
950
    FAIL_IF_NOT(sm->type == DETECT_CONTENT);
12✔
951
    cd = (DetectContentData *)sm->ctx;
12✔
952
    FAIL_IF_NOT(DETECT_CONTENT_IS_SINGLE(cd));
12✔
953
    FAIL_IF_NOT((cd->flags & (DETECT_CONTENT_NEGATED | DETECT_CONTENT_FAST_PATTERN |
12✔
954
                                     DETECT_CONTENT_FAST_PATTERN_CHOP |
12✔
955
                                     DETECT_CONTENT_FAST_PATTERN_ONLY)) ==
12✔
956
                (DETECT_CONTENT_NEGATED | DETECT_CONTENT_FAST_PATTERN |
12✔
957
                        DETECT_CONTENT_FAST_PATTERN_CHOP));
12✔
958
    FAIL_IF_NOT(cd->fp_chop_offset == 3);
12✔
959
    FAIL_IF_NOT(cd->fp_chop_len == 4);
12✔
960

961
    DetectEngineCtxFree(de_ctx);
12✔
962
    PASS;
12✔
963
}
12✔
964

965
/**
966
 * \test Checks if a fast_pattern is registered in a Signature
967
 */
968
static int DetectFastPatternTest01(void)
969
{
1✔
970
    FAIL_IF_NOT(DetectFastPatternStickySingle(NULL, DETECT_SM_LIST_PMATCH));
1✔
971
    FAIL_IF_NOT(DetectFastPatternModifierSingle(NULL, DETECT_SM_LIST_PMATCH));
1✔
972
    FAIL_IF_NOT(DetectFastPatternStickySingleNoFP(NULL, DETECT_SM_LIST_PMATCH));
1✔
973
    FAIL_IF_NOT(DetectFastPatternModifierSingleNoFP(NULL, DETECT_SM_LIST_PMATCH));
1✔
974
    FAIL_IF_NOT(DetectFastPatternStickySingleBadArg(NULL));
1✔
975
    FAIL_IF_NOT(DetectFastPatternModifierBadRules(NULL));
1✔
976
    FAIL_IF_NOT(DetectFastPatternStickySingleFPOnly(NULL, DETECT_SM_LIST_PMATCH));
1✔
977
    FAIL_IF_NOT(DetectFastPatternModifierFPOnly(NULL, DETECT_SM_LIST_PMATCH));
1✔
978
    FAIL_IF_NOT(DetectFastPatternStickyFPChop(NULL, DETECT_SM_LIST_PMATCH));
1✔
979
    FAIL_IF_NOT(DetectFastPatternModifierFPChop(NULL, DETECT_SM_LIST_PMATCH));
1✔
980

981
    struct {
1✔
982
        const char *buffer_name;
1✔
983
        const char *sb_name;
1✔
984
        const char *mod_name;
1✔
985
    } keywords[] = {
1✔
986
        { "file_data", "file.data", NULL },
1✔
987
        { "http_uri", "http.uri", "http_uri" },
1✔
988
        { "http_raw_uri", "http.uri.raw", "http_raw_uri" },
1✔
989
        { "http_user_agent", "http.user_agent", "http_user_agent" },
1✔
990
        { "http_header", "http.header", "http_header" },
1✔
991
        // http_raw_header requires sigs to have a direction
992
        //{ "http_raw_header", "http.header.raw", "http_raw_header" },
993
        { "http_method", "http.method", "http_method" },
1✔
994
        { "http_cookie", "http.cookie", "http_cookie" },
1✔
995
        { "http_host", "http.host", "http_host" },
1✔
996
        { "http_raw_host", "http.host.raw", "http_raw_host" },
1✔
997
        { "http_stat_code", "http.stat_code", "http_stat_code" },
1✔
998
        { "http_stat_msg", "http.stat_msg", "http_stat_msg" },
1✔
999
        { "http_client_body", "http.request_body", "http_client_body" },
1✔
1000
        { NULL, NULL, NULL },
1✔
1001
    };
1✔
1002

1003
    for (int i = 0; keywords[i].buffer_name != NULL; i++) {
13✔
1004
        const int list_id = DetectBufferTypeGetByName(keywords[i].buffer_name);
12✔
1005
        FAIL_IF(list_id == -1);
12✔
1006

1007
        const char *k = keywords[i].sb_name;
12✔
1008
        if (k) {
12✔
1009
            FAIL_IF_NOT(DetectFastPatternStickySingle(k, list_id));
12✔
1010
            FAIL_IF_NOT(DetectFastPatternStickySingleNoFP(k, list_id));
12✔
1011
            FAIL_IF_NOT(DetectFastPatternStickySingleBadArg(k));
12✔
1012
            FAIL_IF_NOT(DetectFastPatternStickySingleFPOnly(k, list_id));
12✔
1013
            FAIL_IF_NOT(DetectFastPatternStickyFPChop(k, list_id));
12✔
1014
        }
12✔
1015
        k = keywords[i].mod_name;
12✔
1016
        if (k) {
12✔
1017
            FAIL_IF_NOT(DetectFastPatternModifierSingle(k, list_id));
11✔
1018
            FAIL_IF_NOT(DetectFastPatternModifierSingleNoFP(k, list_id));
11✔
1019
            FAIL_IF_NOT(DetectFastPatternModifierBadRules(k));
11✔
1020
            FAIL_IF_NOT(DetectFastPatternModifierFPOnly(k, list_id));
11✔
1021
            FAIL_IF_NOT(DetectFastPatternModifierFPChop(k, list_id));
11✔
1022
        }
11✔
1023
    }
12✔
1024

1025
    PASS;
1✔
1026
}
1✔
1027

1028
/**
1029
 * \test Checks to make sure that other sigs work that should when fast_pattern is inspecting on the
1030
 * same payload
1031
 *
1032
 */
1033
static int DetectFastPatternTest14(void)
1034
{
1✔
1035
    uint8_t *buf = (uint8_t *)"Dummy is our name.  Oh yes.  From right here "
1✔
1036
                              "right now, all the way to hangover.  right.  strings5_imp now here "
1✔
1037
                              "comes our dark knight strings_string5.  Yes here is our dark knight";
1✔
1038
    uint16_t buflen = strlen((char *)buf);
1✔
1039
    ThreadVars th_v;
1✔
1040
    DetectEngineThreadCtx *det_ctx = NULL;
1✔
1041

1042
    memset(&th_v, 0, sizeof(th_v));
1✔
1043
    StatsThreadInit(&th_v.stats);
1✔
1044
    Packet *p = UTHBuildPacket(buf, buflen, IPPROTO_TCP);
1✔
1045
    FAIL_IF_NULL(p);
1✔
1046

1047
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
1048
    FAIL_IF_NULL(de_ctx);
1✔
1049
    de_ctx->flags |= DE_QUIET;
1✔
1050

1051
    FlowInitConfig(FLOW_QUIET);
1✔
1052

1053
    Signature *s = DetectEngineAppendSig(de_ctx,
1✔
1054
            "alert tcp any any -> any any "
1✔
1055
            "(msg:\"fast_pattern test\"; content:\"strings_string5\"; content:\"knight\"; "
1✔
1056
            "fast_pattern; sid:1;)");
1✔
1057
    FAIL_IF_NULL(s);
1✔
1058

1059
    s = DetectEngineAppendSig(de_ctx,
1✔
1060
            "alert tcp any any -> any any "
1✔
1061
            "(msg:\"test different content\"; content:\"Dummy is our name\"; sid:2;)");
1✔
1062
    FAIL_IF_NULL(s);
1✔
1063

1064
    SigGroupBuild(de_ctx);
1✔
1065
    DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
1✔
1066

1067
    SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1✔
1068
    FAIL_IF_NOT(PacketAlertCheck(p, 1));
1✔
1069
    FAIL_IF_NOT(PacketAlertCheck(p, 2));
1✔
1070

1071
    UTHFreePackets(&p, 1);
1✔
1072
    DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
1✔
1073
    DetectEngineCtxFree(de_ctx);
1✔
1074
    FlowShutdown();
1✔
1075
    StatsThreadCleanup(&th_v.stats);
1✔
1076
    PASS;
1✔
1077
}
1✔
1078

1079
/**
1080
 * Unittest to check
1081
 * - if we assign different content_ids to duplicate patterns, but one of the
1082
 *   patterns has a fast_pattern chop set.
1083
 * - if 2 unique patterns get unique ids.
1084
 * - if 2 duplicate patterns, with no chop set get unique ids.
1085
 */
1086
static int DetectFastPatternTest671(void)
1087
{
1✔
1088
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
1089
    FAIL_IF_NULL(de_ctx);
1✔
1090
    de_ctx->flags |= DE_QUIET;
1✔
1091

1092
    Signature *s[6];
1✔
1093
    s[0] = DetectEngineAppendSig(
1✔
1094
            de_ctx, "alert tcp any any -> any any (content:\"onetwothreefour\"; sid:1;)");
1✔
1095
    FAIL_IF_NULL(s[0]);
1✔
1096
    s[1] = DetectEngineAppendSig(
1✔
1097
            de_ctx, "alert tcp any any -> any any (content:\"onetwothreefour\"; sid:2;)");
1✔
1098
    FAIL_IF_NULL(s[1]);
1✔
1099
    s[2] = DetectEngineAppendSig(
1✔
1100
            de_ctx, "alert tcp any any -> any any (content:\"uniquepattern\"; sid:3;)");
1✔
1101
    FAIL_IF_NULL(s[2]);
1✔
1102
    s[3] = DetectEngineAppendSig(de_ctx,
1✔
1103
            "alert tcp any any -> any any (content:\"onetwothreefour\"; fast_pattern:3,5; sid:4;)");
1✔
1104
    FAIL_IF_NULL(s[3]);
1✔
1105
    s[4] = DetectEngineAppendSig(
1✔
1106
            de_ctx, "alert tcp any any -> any any (content:\"twoth\"; sid:5;)");
1✔
1107
    FAIL_IF_NULL(s[4]);
1✔
1108
    s[5] = DetectEngineAppendSig(de_ctx,
1✔
1109
            "alert tcp any any -> any any (content:\"onetwothreefour\"; fast_pattern:0,15; "
1✔
1110
            "sid:6;)");
1✔
1111
    FAIL_IF_NULL(s[5]);
1✔
1112

1113
    SigGroupBuild(de_ctx);
1✔
1114

1115
    SigMatchData *smd = s[0]->sm_arrays[DETECT_SM_LIST_PMATCH];
1✔
1116
    DetectContentData *cd = (DetectContentData *)smd->ctx;
1✔
1117
    FAIL_IF(cd->id != 0);
1✔
1118

1119
    smd = s[1]->sm_arrays[DETECT_SM_LIST_PMATCH];
1✔
1120
    cd = (DetectContentData *)smd->ctx;
1✔
1121
    FAIL_IF(cd->id != 0);
1✔
1122

1123
    smd = s[2]->sm_arrays[DETECT_SM_LIST_PMATCH];
1✔
1124
    cd = (DetectContentData *)smd->ctx;
1✔
1125
    FAIL_IF(cd->id != 2);
1✔
1126

1127
    smd = s[3]->sm_arrays[DETECT_SM_LIST_PMATCH];
1✔
1128
    cd = (DetectContentData *)smd->ctx;
1✔
1129
    FAIL_IF(cd->id != 1);
1✔
1130

1131
    smd = s[4]->sm_arrays[DETECT_SM_LIST_PMATCH];
1✔
1132
    cd = (DetectContentData *)smd->ctx;
1✔
1133
    FAIL_IF(cd->id != 1);
1✔
1134

1135
    smd = s[5]->sm_arrays[DETECT_SM_LIST_PMATCH];
1✔
1136
    cd = (DetectContentData *)smd->ctx;
1✔
1137
    FAIL_IF(cd->id != 0);
1✔
1138

1139
    DetectEngineCtxFree(de_ctx);
1✔
1140
    PASS;
1✔
1141
}
1✔
1142

1143
static int DetectFastPatternPrefilter(void)
1144
{
1✔
1145
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
1146
    FAIL_IF_NULL(de_ctx);
1✔
1147
    const char *string = "alert tcp any any -> any any "
1✔
1148
                         "(content:\"one\"; prefilter; sid:1;)";
1✔
1149
    Signature *s = DetectEngineAppendSig(de_ctx, string);
1✔
1150
    FAIL_IF_NULL(s);
1✔
1151
    SigMatch *sm = s->init_data->smlists[DETECT_SM_LIST_PMATCH];
1✔
1152
    FAIL_IF_NULL(sm);
1✔
1153
    FAIL_IF_NOT(sm->type == DETECT_CONTENT);
1✔
1154
    DetectContentData *cd = (DetectContentData *)sm->ctx;
1✔
1155
    FAIL_IF_NOT(DETECT_CONTENT_IS_SINGLE(cd));
1✔
1156
    FAIL_IF_NOT((cd->flags & DETECT_CONTENT_FAST_PATTERN) == DETECT_CONTENT_FAST_PATTERN);
1✔
1157
    DetectEngineCtxFree(de_ctx);
1✔
1158
    PASS;
1✔
1159
}
1✔
1160

1161
static void DetectFastPatternRegisterTests(void)
1162
{
1✔
1163
    UtRegisterTest("DetectFastPatternTest01", DetectFastPatternTest01);
1✔
1164
    UtRegisterTest("DetectFastPatternTest14", DetectFastPatternTest14);
1✔
1165
    /* Unittest to check
1166
     * - if we assign different content_ids to duplicate patterns, but one of the
1167
     *   patterns has a fast_pattern chop set.
1168
     * - if 2 unique patterns get unique ids.
1169
     * - if 2 duplicate patterns, with no chop set get unique ids.
1170
     */
1171
    UtRegisterTest("DetectFastPatternTest671", DetectFastPatternTest671);
1✔
1172

1173
    UtRegisterTest("DetectFastPatternPrefilter", DetectFastPatternPrefilter);
1✔
1174
}
1✔
1175
#endif
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