Coverage Report

Created: 2026-06-30 07:20

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/suricata7/src/detect-content.c
Line
Count
Source
1
/* Copyright (C) 2007-2022 Open Information Security Foundation
2
 *
3
 * You can copy, redistribute or modify this Program under the terms of
4
 * the GNU General Public License version 2 as published by the Free
5
 * Software Foundation.
6
 *
7
 * This program is distributed in the hope that it will be useful,
8
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10
 * GNU General Public License for more details.
11
 *
12
 * You should have received a copy of the GNU General Public License
13
 * version 2 along with this program; if not, write to the Free Software
14
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15
 * 02110-1301, USA.
16
 */
17
18
/**
19
 * \file
20
 *
21
 * \author Victor Julien <victor@inliniac.net>
22
 *
23
 * Simple content match part of the detection engine.
24
 */
25
26
#include "suricata-common.h"
27
#include "decode.h"
28
#include "detect.h"
29
#include "detect-content.h"
30
#include "detect-uricontent.h"
31
#include "detect-engine-mpm.h"
32
#include "detect-engine.h"
33
#include "detect-engine-build.h"
34
#include "detect-engine-state.h"
35
#include "detect-parse.h"
36
#include "detect-pcre.h"
37
#include "util-mpm.h"
38
#include "flow.h"
39
#include "flow-util.h"
40
#include "flow-var.h"
41
#include "detect-flow.h"
42
#include "app-layer.h"
43
#include "util-unittest.h"
44
#include "util-print.h"
45
#include "util-debug.h"
46
#include "util-spm.h"
47
#include "threads.h"
48
#include "util-unittest-helper.h"
49
#include "pkt-var.h"
50
#include "host.h"
51
#include "util-profiling.h"
52
#include "detect-dsize.h"
53
54
#ifdef UNITTESTS
55
static void DetectContentRegisterTests(void);
56
#endif
57
58
void DetectContentRegister (void)
59
75
{
60
75
    sigmatch_table[DETECT_CONTENT].name = "content";
61
75
    sigmatch_table[DETECT_CONTENT].desc = "match on payload content";
62
75
    sigmatch_table[DETECT_CONTENT].url = "/rules/payload-keywords.html#content";
63
75
    sigmatch_table[DETECT_CONTENT].Match = NULL;
64
75
    sigmatch_table[DETECT_CONTENT].Setup = DetectContentSetup;
65
75
    sigmatch_table[DETECT_CONTENT].Free  = DetectContentFree;
66
#ifdef UNITTESTS
67
    sigmatch_table[DETECT_CONTENT].RegisterTests = DetectContentRegisterTests;
68
#endif
69
75
    sigmatch_table[DETECT_CONTENT].flags = (SIGMATCH_QUOTES_MANDATORY|SIGMATCH_HANDLE_NEGATION);
70
75
}
71
72
/**
73
 *  \brief Parse a content string, ie "abc|DE|fgh"
74
 *
75
 *  \param content_str null terminated string containing the content
76
 *  \param result result pointer to pass the fully parsed byte array
77
 *  \param result_len size of the resulted data
78
 *  \param flags flags to be set by this parsing function
79
 *
80
 *  \retval -1 error
81
 *  \retval 0 ok
82
 */
83
int DetectContentDataParse(const char *keyword, const char *contentstr,
84
        uint8_t **pstr, uint16_t *plen)
85
589k
{
86
589k
    char *str = NULL;
87
589k
    size_t slen = 0;
88
89
589k
    slen = strlen(contentstr);
90
589k
    if (slen == 0) {
91
5
        return -1;
92
5
    }
93
589k
    uint8_t buffer[slen + 1];
94
589k
    strlcpy((char *)&buffer, contentstr, slen + 1);
95
589k
    str = (char *)buffer;
96
97
589k
    SCLogDebug("\"%s\", len %" PRIuMAX, str, (uintmax_t)slen);
98
99
    //SCLogDebug("DetectContentParse: \"%s\", len %" PRIu32 "", str, len);
100
589k
    char converted = 0;
101
102
589k
    {
103
589k
        size_t i, x;
104
589k
        uint8_t bin = 0;
105
589k
        uint8_t escape = 0;
106
589k
        uint8_t binstr[3] = "";
107
589k
        uint8_t binpos = 0;
108
589k
        uint16_t bin_count = 0;
109
110
8.79M
        for (i = 0, x = 0; i < slen; i++) {
111
            // SCLogDebug("str[%02u]: %c", i, str[i]);
112
8.22M
            if (str[i] == '|') {
113
397k
                bin_count++;
114
397k
                if (bin) {
115
194k
                    if (binpos > 0) {
116
1.06k
                        SCLogError("Incomplete hex code in content - %s. Invalidating signature.",
117
1.06k
                                contentstr);
118
1.06k
                        goto error;
119
1.06k
                    }
120
193k
                    bin = 0;
121
202k
                } else {
122
202k
                    bin = 1;
123
202k
                }
124
7.82M
            } else if(!escape && str[i] == '\\') {
125
61.9k
                escape = 1;
126
7.76M
            } else {
127
7.76M
                if (bin) {
128
1.91M
                    if (isdigit((unsigned char)str[i]) ||
129
804k
                            str[i] == 'A' || str[i] == 'a' ||
130
717k
                            str[i] == 'B' || str[i] == 'b' ||
131
681k
                            str[i] == 'C' || str[i] == 'c' ||
132
636k
                            str[i] == 'D' || str[i] == 'd' ||
133
596k
                            str[i] == 'E' || str[i] == 'e' ||
134
524k
                            str[i] == 'F' || str[i] == 'f')
135
1.46M
                    {
136
                        // SCLogDebug("part of binary: %c", str[i]);
137
138
1.46M
                        binstr[binpos] = (char)str[i];
139
1.46M
                        binpos++;
140
141
1.46M
                        if (binpos == 2) {
142
728k
                            uint8_t c = strtol((char *)binstr, (char **) NULL, 16) & 0xFF;
143
728k
                            binpos = 0;
144
728k
                            str[x] = c;
145
728k
                            x++;
146
728k
                            converted = 1;
147
728k
                        }
148
1.46M
                    } else if (str[i] == ' ') {
149
                        // SCLogDebug("space as part of binary string");
150
445k
                    }
151
11.8k
                    else if (str[i] != ',') {
152
7.21k
                        SCLogError("Invalid hex code in "
153
7.21k
                                   "content - %s, hex %c. Invalidating signature.",
154
7.21k
                                contentstr, str[i]);
155
7.21k
                        goto error;
156
7.21k
                    }
157
5.84M
                } else if (escape) {
158
61.7k
                    if (str[i] == ':' ||
159
58.6k
                        str[i] == ';' ||
160
56.5k
                        str[i] == '\\' ||
161
3.81k
                        str[i] == '\"')
162
58.5k
                    {
163
58.5k
                        str[x] = str[i];
164
58.5k
                        x++;
165
58.5k
                    } else {
166
3.20k
                        SCLogError("'%c' has to be escaped", str[i - 1]);
167
3.20k
                        goto error;
168
3.20k
                    }
169
58.5k
                    escape = 0;
170
58.5k
                    converted = 1;
171
5.78M
                } else if (str[i] == '"') {
172
5.45k
                    SCLogError("Invalid unescaped double quote within content section.");
173
5.45k
                    goto error;
174
5.77M
                } else {
175
5.77M
                    str[x] = str[i];
176
5.77M
                    x++;
177
5.77M
                }
178
7.76M
            }
179
8.22M
        }
180
181
572k
        if (bin_count % 2 != 0) {
182
749
            SCLogError("Invalid hex code assembly in "
183
749
                       "%s - %s.  Invalidating signature.",
184
749
                    keyword, contentstr);
185
749
            goto error;
186
749
        }
187
188
571k
        if (converted) {
189
181k
            slen = x;
190
181k
        }
191
571k
    }
192
193
571k
    if (slen) {
194
571k
        uint8_t *ptr = SCCalloc(1, slen);
195
571k
        if (ptr == NULL) {
196
0
            return -1;
197
0
        }
198
571k
        memcpy(ptr, str, slen);
199
200
571k
        *plen = (uint16_t)slen;
201
571k
        *pstr = ptr;
202
571k
        return 0;
203
571k
    }
204
17.6k
error:
205
17.6k
    return -1;
206
571k
}
207
/**
208
 * \brief DetectContentParse
209
 * \initonly
210
 */
211
DetectContentData *DetectContentParse(SpmGlobalThreadCtx *spm_global_thread_ctx,
212
                                      const char *contentstr)
213
579k
{
214
579k
    DetectContentData *cd = NULL;
215
579k
    uint8_t *content = NULL;
216
579k
    uint16_t len = 0;
217
579k
    int ret;
218
219
579k
    ret = DetectContentDataParse("content", contentstr, &content, &len);
220
579k
    if (ret == -1) {
221
17.4k
        return NULL;
222
17.4k
    }
223
224
561k
    cd = SCCalloc(1, sizeof(DetectContentData) + len);
225
561k
    if (unlikely(cd == NULL)) {
226
0
        SCFree(content);
227
0
        exit(EXIT_FAILURE);
228
0
    }
229
230
561k
    cd->content = (uint8_t *)cd + sizeof(DetectContentData);
231
561k
    memcpy(cd->content, content, len);
232
561k
    cd->content_len = len;
233
234
    /* Prepare SPM search context. */
235
561k
    cd->spm_ctx = SpmInitCtx(cd->content, cd->content_len, 0,
236
561k
                             spm_global_thread_ctx);
237
561k
    if (cd->spm_ctx == NULL) {
238
0
        SCFree(content);
239
0
        SCFree(cd);
240
0
        return NULL;
241
0
    }
242
243
561k
    cd->depth = 0;
244
561k
    cd->offset = 0;
245
561k
    cd->within = 0;
246
561k
    cd->distance = 0;
247
248
561k
    SCFree(content);
249
561k
    return cd;
250
251
561k
}
252
253
DetectContentData *DetectContentParseEncloseQuotes(SpmGlobalThreadCtx *spm_global_thread_ctx,
254
                                                   const char *contentstr)
255
9.49k
{
256
9.49k
    return DetectContentParse(spm_global_thread_ctx, contentstr);
257
9.49k
}
258
259
/**
260
 * \brief Helper function to print a DetectContentData
261
 */
262
void DetectContentPrint(DetectContentData *cd)
263
1.08M
{
264
1.08M
    int i = 0;
265
1.08M
    if (cd == NULL) {
266
0
        SCLogDebug("DetectContentData \"cd\" is NULL");
267
0
        return;
268
0
    }
269
1.08M
    char *tmpstr = SCMalloc(sizeof(char) * cd->content_len + 1);
270
1.08M
    if (tmpstr != NULL) {
271
12.9M
        for (i = 0; i < cd->content_len; i++) {
272
11.8M
            if (isprint(cd->content[i]))
273
11.0M
                tmpstr[i] = cd->content[i];
274
752k
            else
275
752k
                tmpstr[i] = '.';
276
11.8M
        }
277
1.08M
        tmpstr[i] = '\0';
278
1.08M
        SCLogDebug("Content: \"%s\"", tmpstr);
279
1.08M
        SCFree(tmpstr);
280
1.08M
    } else {
281
0
        SCLogDebug("Content: ");
282
0
        for (i = 0; i < cd->content_len; i++)
283
0
            SCLogDebug("%c", cd->content[i]);
284
0
    }
285
286
1.08M
    SCLogDebug("Content_id: %"PRIu32, cd->id);
287
1.08M
    SCLogDebug("Content_len: %"PRIu16, cd->content_len);
288
1.08M
    SCLogDebug("Depth: %"PRIu16, cd->depth);
289
1.08M
    SCLogDebug("Offset: %"PRIu16, cd->offset);
290
1.08M
    SCLogDebug("Within: %"PRIi32, cd->within);
291
1.08M
    SCLogDebug("Distance: %"PRIi32, cd->distance);
292
1.08M
    SCLogDebug("flags: %u ", cd->flags);
293
1.08M
    SCLogDebug("negated: %s ", cd->flags & DETECT_CONTENT_NEGATED ? "true" : "false");
294
1.08M
    SCLogDebug("relative match next: %s ", cd->flags & DETECT_CONTENT_RELATIVE_NEXT ? "true" : "false");
295
296
1.08M
    if (cd->replace && cd->replace_len) {
297
0
        char *tmprstr = SCMalloc(sizeof(char) * cd->replace_len + 1);
298
299
0
        if (tmprstr != NULL) {
300
0
            for (i = 0; i < cd->replace_len; i++) {
301
0
                if (isprint(cd->replace[i]))
302
0
                    tmprstr[i] = cd->replace[i];
303
0
                else
304
0
                    tmprstr[i] = '.';
305
0
            }
306
0
            tmprstr[i] = '\0';
307
0
            SCLogDebug("Replace: \"%s\"", tmprstr);
308
0
            SCFree(tmprstr);
309
0
        } else {
310
0
            SCLogDebug("Replace: ");
311
0
            for (i = 0; i < cd->replace_len; i++)
312
0
                SCLogDebug("%c", cd->replace[i]);
313
0
        }
314
0
    }
315
1.08M
    SCLogDebug("-----------");
316
1.08M
}
317
318
/**
319
 * \brief Function to setup a content pattern.
320
 *
321
 * \param de_ctx pointer to the current detection_engine
322
 * \param s pointer to the current Signature
323
 * \param m pointer to the last parsed SigMatch
324
 * \param contentstr pointer to the current keyword content string
325
 * \retval -1 if error
326
 * \retval 0 if all was ok
327
 */
328
int DetectContentSetup(DetectEngineCtx *de_ctx, Signature *s, const char *contentstr)
329
575k
{
330
575k
    DetectContentData *cd = DetectContentParse(de_ctx->spm_global_thread_ctx, contentstr);
331
575k
    if (cd == NULL)
332
17.4k
        goto error;
333
558k
    if (s->init_data->negated == true) {
334
29.9k
        cd->flags |= DETECT_CONTENT_NEGATED;
335
29.9k
    }
336
337
558k
    DetectContentPrint(cd);
338
339
558k
    if (DetectBufferGetActiveList(de_ctx, s) == -1)
340
2
        goto error;
341
342
558k
    int sm_list = s->init_data->list;
343
558k
    if (sm_list == DETECT_SM_LIST_NOTSET) {
344
326k
        sm_list = DETECT_SM_LIST_PMATCH;
345
326k
    } else if (sm_list > DETECT_SM_LIST_MAX &&
346
194k
            0 == (cd->flags & DETECT_CONTENT_NEGATED)) {
347
        /* Check transform compatibility */
348
184k
        const char *tstr;
349
184k
        if (!DetectEngineBufferTypeValidateTransform(
350
184k
                    de_ctx, sm_list, cd->content, cd->content_len, &tstr)) {
351
2.46k
            SCLogError("content string \"%s\" incompatible with %s transform", contentstr, tstr);
352
2.46k
            goto error;
353
2.46k
        }
354
184k
    }
355
356
555k
    SigMatch *sm = SigMatchAlloc();
357
555k
    if (sm == NULL)
358
0
        goto error;
359
555k
    sm->ctx = (void *)cd;
360
555k
    sm->type = DETECT_CONTENT;
361
555k
    SigMatchAppendSMToList(s, sm, sm_list);
362
363
555k
    return 0;
364
365
19.9k
error:
366
19.9k
    DetectContentFree(de_ctx, cd);
367
19.9k
    return -1;
368
555k
}
369
370
/**
371
 * \brief this function will SCFree memory associated with DetectContentData
372
 *
373
 * \param cd pointer to DetectContentData
374
 */
375
void DetectContentFree(DetectEngineCtx *de_ctx, void *ptr)
376
1.11M
{
377
1.11M
    SCEnter();
378
1.11M
    DetectContentData *cd = (DetectContentData *)ptr;
379
380
1.11M
    if (cd == NULL)
381
34.0k
        SCReturn;
382
383
1.08M
    if (cd->replace)
384
0
        SCFree(cd->replace);
385
1.08M
    SpmDestroyCtx(cd->spm_ctx);
386
387
1.08M
    SCFree(cd);
388
1.08M
    SCReturn;
389
1.11M
}
390
391
/*
392
 *  \brief Determine the size needed to accommodate the content
393
 *  elements of a signature
394
 *  \param s signature to get dsize value from
395
 *  \param max_size Maximum buffer/data size allowed.
396
 *  \param list signature match list.
397
 *  \param len Maximum length required
398
 *  \param offset Maximum offset encountered
399
 *
400
 *  Note that negated content does not contribute to the maximum
401
 *  required size value. However, each negated content's values
402
 *  must not exceed the size value.
403
 *
404
 *  Values from negated content blocks are used to determine if the
405
 *  negated content block requires a value that exceeds "max_size". The
406
 *  distance and within values from negated content blocks are added to
407
 *  the running total of required content size to see if the max_size
408
 *  would be exceeded.
409
 *
410
 *  - Non-negated content contributes to the required size (content length, distance)
411
 *  - Negated content values are checked but not accumulated for the required size.
412
 */
413
void SigParseRequiredContentSize(
414
        const Signature *s, const int max_size, const SigMatch *sm, int *len, int *offset)
415
43.1k
{
416
43.1k
    int max_offset = 0, total_len = 0;
417
43.1k
    bool first = true;
418
    // define it first, and override it unless in DETECT_CONTENT_NEGATED edge case
419
43.1k
    *offset = 0;
420
151k
    for (; sm != NULL; sm = sm->next) {
421
108k
        if (sm->type != DETECT_CONTENT || sm->ctx == NULL) {
422
49.0k
            continue;
423
49.0k
        }
424
425
59.6k
        DetectContentData *cd = (DetectContentData *)sm->ctx;
426
59.6k
        SCLogDebug("content_len %d; negated: %s; distance: %d, offset: %d, depth: %d",
427
59.6k
                cd->content_len, cd->flags & DETECT_CONTENT_NEGATED ? "yes" : "no", cd->distance,
428
59.6k
                cd->offset, cd->depth);
429
430
59.6k
        if (!first) {
431
            /* only count content with relative modifiers */
432
21.4k
            if (!((cd->flags & DETECT_CONTENT_DISTANCE) || (cd->flags & DETECT_CONTENT_WITHIN)))
433
13.7k
                continue;
434
435
7.65k
            if (cd->flags & DETECT_CONTENT_NEGATED) {
436
                /* Check if distance/within cause max to be exceeded */
437
1.33k
                int check = total_len + cd->distance + cd->within;
438
1.33k
                if (max_size < check) {
439
128
                    *len = check;
440
128
                    return;
441
128
                }
442
443
1.20k
                continue;
444
1.33k
            }
445
7.65k
        }
446
44.5k
        SCLogDebug("content_len %d; distance: %d, offset: %d, depth: %d", cd->content_len,
447
44.5k
                cd->distance, cd->offset, cd->depth);
448
44.5k
        total_len += cd->content_len + cd->distance;
449
44.5k
        max_offset = MAX(max_offset, cd->offset);
450
44.5k
        first = false;
451
44.5k
    }
452
453
42.9k
    *len = total_len;
454
42.9k
    *offset = max_offset;
455
42.9k
}
456
457
/**
458
 *  \retval true valid
459
 *  \retval false invalid
460
 */
461
bool DetectContentPMATCHValidateCallback(const Signature *s)
462
314k
{
463
314k
    if (!(s->flags & SIG_FLAG_DSIZE)) {
464
304k
        return true;
465
304k
    }
466
467
10.2k
    int max_right_edge_i = SigParseGetMaxDsize(s);
468
10.2k
    if (max_right_edge_i < 0) {
469
1.01k
        return true;
470
1.01k
    }
471
472
9.27k
    uint32_t max_right_edge = (uint32_t)max_right_edge_i;
473
474
9.27k
    int min_dsize_required = SigParseMaxRequiredDsize(s);
475
9.27k
    if (min_dsize_required >= 0) {
476
2.95k
        SCLogDebug("min_dsize %d; max_right_edge %d", min_dsize_required, max_right_edge);
477
2.95k
        if ((uint32_t)min_dsize_required > max_right_edge) {
478
2.95k
            SCLogError("signature can't match as required content length %d exceeds dsize value %d",
479
2.95k
                    min_dsize_required, max_right_edge);
480
2.95k
            return false;
481
2.95k
        }
482
2.95k
    }
483
484
6.31k
    return true;
485
9.27k
}
486
487
/** \brief apply depth/offset and distance/within to content matches
488
 *
489
 *  The idea is that any limitation we can set is a win, as the mpm
490
 *  can use this to reduce match candidates.
491
 *
492
 *  E.g. if we have 'content:"1"; depth:1; content:"2"; distance:0; within:1;'
493
 *  we know that we can add 'offset:1; depth:2;' to the 2nd condition. This
494
 *  will then be used in mpm if the 2nd condition would be selected for mpm.
495
 *
496
 *  Another example: 'content:"1"; depth:1; content:"2"; distance:0;'. Here we
497
 *  cannot set a depth, but we can set an offset of 'offset:1;'. This will
498
 *  make the mpm a bit more precise.
499
 */
500
static void PropagateLimits(Signature *s, SigMatch *sm_head)
501
372k
{
502
372k
#define VALIDATE(e)                                                                                \
503
372k
    if (!(e)) {                                                                                    \
504
103
        return;                                                                                    \
505
103
    }
506
372k
    uint16_t offset = 0;
507
372k
    uint16_t offset_plus_pat = 0;
508
372k
    uint16_t depth = 0;
509
372k
    bool has_active_depth_chain = false;
510
511
372k
    bool has_depth = false;
512
372k
    bool has_ends_with = false;
513
372k
    uint16_t ends_with_depth = 0;
514
515
796k
    for (SigMatch *sm = sm_head; sm != NULL; sm = sm->next) {
516
424k
        switch (sm->type) {
517
141k
            case DETECT_CONTENT: {
518
141k
                DetectContentData *cd = (DetectContentData *)sm->ctx;
519
141k
                if ((cd->flags & (DETECT_CONTENT_DEPTH | DETECT_CONTENT_OFFSET |
520
141k
                                         DETECT_CONTENT_WITHIN | DETECT_CONTENT_DISTANCE)) == 0) {
521
103k
                    offset = depth = 0;
522
103k
                    offset_plus_pat = cd->content_len;
523
103k
                    SCLogDebug("reset");
524
103k
                    has_active_depth_chain = false;
525
103k
                    continue;
526
103k
                }
527
37.8k
                if (sm->prev == NULL) {
528
13.9k
                    if (cd->distance >= 0 && cd->distance <= (int32_t)USHRT_MAX &&
529
13.0k
                            cd->within >= 0 && cd->within <= (int32_t)USHRT_MAX) {
530
13.0k
                        if (cd->flags & DETECT_CONTENT_DISTANCE) {
531
1.59k
                            if (cd->distance > 0)
532
618
                                cd->flags |= DETECT_CONTENT_OFFSET;
533
1.59k
                            cd->flags &= ~DETECT_CONTENT_DISTANCE;
534
1.59k
                            cd->offset = (uint16_t)cd->distance;
535
1.59k
                            cd->distance = 0;
536
1.59k
                            cd->flags |= DETECT_CONTENT_DISTANCE2OFFSET;
537
1.59k
                        }
538
13.0k
                        if (cd->flags & DETECT_CONTENT_WITHIN) {
539
3.38k
                            cd->flags |= DETECT_CONTENT_DEPTH;
540
3.38k
                            cd->flags &= ~DETECT_CONTENT_WITHIN;
541
3.38k
                            cd->depth = (uint16_t)cd->within + cd->offset;
542
3.38k
                            cd->within = 0;
543
3.38k
                            cd->flags |= DETECT_CONTENT_WITHIN2DEPTH;
544
3.38k
                        }
545
13.0k
                    }
546
13.9k
                }
547
548
37.8k
                if (cd->flags & DETECT_CONTENT_NEGATED) {
549
5.50k
                    offset = depth = 0;
550
5.50k
                    offset_plus_pat = 0;
551
5.50k
                    SCLogDebug("reset because of negation");
552
5.50k
                    has_active_depth_chain = false;
553
5.50k
                    continue;
554
5.50k
                }
555
556
32.3k
                if (cd->depth) {
557
14.6k
                    has_depth = true;
558
14.6k
                    has_active_depth_chain = true;
559
14.6k
                }
560
561
32.3k
                SCLogDebug("sm %p depth %u offset %u distance %d within %d", sm, cd->depth,
562
32.3k
                        cd->offset, cd->distance, cd->within);
563
32.3k
                SCLogDebug("stored: offset %u depth %u offset_plus_pat %u", offset, depth,
564
32.3k
                        offset_plus_pat);
565
566
32.3k
                if ((cd->flags & (DETECT_DEPTH | DETECT_CONTENT_WITHIN)) == 0) {
567
7.38k
                    if (depth)
568
499
                        SCLogDebug("no within, reset depth");
569
7.38k
                    depth = 0;
570
7.38k
                    has_active_depth_chain = false;
571
7.38k
                }
572
32.3k
                if ((cd->flags & DETECT_CONTENT_DISTANCE) == 0) {
573
20.7k
                    if (offset_plus_pat)
574
5.54k
                        SCLogDebug("no distance, reset offset_plus_pat & offset");
575
20.7k
                    offset_plus_pat = offset = 0;
576
20.7k
                }
577
578
32.3k
                SCLogDebug("stored: offset %u depth %u offset_plus_pat %u "
579
32.3k
                           "has_active_depth_chain %s",
580
32.3k
                        offset, depth, offset_plus_pat, has_active_depth_chain ? "true" : "false");
581
32.3k
                if (cd->flags & DETECT_CONTENT_DISTANCE) {
582
11.5k
                    if (cd->distance >= 0) {
583
6.43k
                        VALIDATE((uint32_t)offset_plus_pat + cd->distance <= UINT16_MAX);
584
6.35k
                        offset = cd->offset = (uint16_t)(offset_plus_pat + cd->distance);
585
6.35k
                        SCLogDebug("distance %d: updated content to have offset %u", cd->distance,
586
6.35k
                                cd->offset);
587
6.35k
                    } else {
588
5.14k
                        if (abs(cd->distance) > offset_plus_pat)
589
4.65k
                            offset = cd->offset = 0;
590
494
                        else
591
494
                            offset = cd->offset = (uint16_t)(offset_plus_pat + cd->distance);
592
5.14k
                        offset_plus_pat = offset + cd->content_len;
593
5.14k
                        SCLogDebug("distance %d: updated content to have offset %u", cd->distance,
594
5.14k
                                cd->offset);
595
5.14k
                    }
596
11.5k
                }
597
32.2k
                if (has_active_depth_chain) {
598
17.0k
                    if (offset_plus_pat && cd->flags & DETECT_CONTENT_WITHIN && cd->within >= 0) {
599
1.20k
                        if (depth && depth > offset_plus_pat) {
600
824
                            int32_t dist = 0;
601
824
                            if (cd->flags & DETECT_CONTENT_DISTANCE && cd->distance > 0) {
602
683
                                dist = cd->distance;
603
683
                                SCLogDebug(
604
683
                                        "distance to add: %u. depth + dist %u", dist, depth + dist);
605
683
                            }
606
824
                            SCLogDebug("depth %u + cd->within %u", depth, cd->within);
607
824
                            VALIDATE(depth + cd->within + dist >= 0 &&
608
824
                                     depth + cd->within + dist <= UINT16_MAX);
609
805
                            depth = cd->depth = (uint16_t)(depth + cd->within + dist);
610
805
                        } else if ((cd->flags & DETECT_CONTENT_DISTANCE_VAR) == 0) {
611
                            // we cannot know the depth yet if it comes from a var
612
373
                            SCLogDebug("offset %u + cd->within %u", offset, cd->within);
613
373
                            VALIDATE(depth + cd->within >= 0 && depth + cd->within <= UINT16_MAX);
614
373
                            depth = cd->depth = (uint16_t)(offset + cd->within);
615
373
                        }
616
1.19k
                        SCLogDebug("updated content to have depth %u", cd->depth);
617
15.8k
                    } else {
618
15.8k
                        if (cd->depth == 0 && depth != 0) {
619
1.35k
                            if (cd->within > 0) {
620
868
                                SCLogDebug("within %d distance %d", cd->within, cd->distance);
621
868
                                if (cd->flags & DETECT_CONTENT_DISTANCE && cd->distance >= 0) {
622
0
                                    VALIDATE(offset_plus_pat + cd->distance >= 0 &&
623
0
                                             offset_plus_pat + cd->distance <= UINT16_MAX);
624
0
                                    cd->offset = (uint16_t)(offset_plus_pat + cd->distance);
625
0
                                    SCLogDebug("updated content to have offset %u", cd->offset);
626
0
                                }
627
628
868
                                VALIDATE(depth + cd->within >= 0 &&
629
868
                                         depth + cd->within <= UINT16_MAX);
630
865
                                depth = cd->depth = (uint16_t)(cd->within + depth);
631
865
                                SCLogDebug("updated content to have depth %u", cd->depth);
632
633
865
                                if (cd->flags & DETECT_CONTENT_ENDS_WITH) {
634
0
                                    has_ends_with = true;
635
0
                                    if (ends_with_depth == 0)
636
0
                                        ends_with_depth = depth;
637
0
                                    ends_with_depth = MIN(ends_with_depth, depth);
638
0
                                }
639
865
                            }
640
1.35k
                        }
641
15.8k
                    }
642
17.0k
                }
643
32.2k
                if (cd->offset == 0) { // && offset != 0) {
644
23.4k
                    if (cd->flags & DETECT_CONTENT_DISTANCE && cd->distance >= 0) {
645
473
                        cd->offset = offset_plus_pat;
646
473
                        SCLogDebug("update content to have offset %u", cd->offset);
647
473
                    }
648
23.4k
                }
649
650
32.2k
                if ((cd->flags & (DETECT_CONTENT_DEPTH | DETECT_CONTENT_OFFSET |
651
32.2k
                                         DETECT_CONTENT_WITHIN | DETECT_CONTENT_DISTANCE)) ==
652
32.2k
                                (DETECT_CONTENT_DISTANCE | DETECT_CONTENT_WITHIN) ||
653
29.4k
                        (cd->flags & (DETECT_CONTENT_DEPTH | DETECT_CONTENT_OFFSET |
654
29.4k
                                             DETECT_CONTENT_WITHIN | DETECT_CONTENT_DISTANCE)) ==
655
29.4k
                                (DETECT_CONTENT_DISTANCE)) {
656
11.3k
                    if (cd->distance >= 0) {
657
                        // only distance
658
6.20k
                        VALIDATE((uint32_t)offset_plus_pat + cd->distance <= UINT16_MAX);
659
6.20k
                        offset = cd->offset = (uint16_t)(offset_plus_pat + cd->distance);
660
6.20k
                        offset_plus_pat = offset + cd->content_len;
661
6.20k
                        SCLogDebug("offset %u offset_plus_pat %u", offset, offset_plus_pat);
662
6.20k
                    }
663
11.3k
                }
664
32.2k
                if (cd->flags & DETECT_CONTENT_OFFSET) {
665
3.94k
                    offset = cd->offset;
666
3.94k
                    offset_plus_pat = offset + cd->content_len;
667
3.94k
                    SCLogDebug("stored offset %u offset_plus_pat %u", offset, offset_plus_pat);
668
3.94k
                }
669
32.2k
                if (cd->depth) {
670
16.5k
                    depth = cd->depth;
671
16.5k
                    SCLogDebug("stored depth now %u", depth);
672
16.5k
                    offset_plus_pat = offset + cd->content_len;
673
16.5k
                    if (cd->flags & DETECT_CONTENT_ENDS_WITH) {
674
504
                        has_ends_with = true;
675
504
                        if (ends_with_depth == 0)
676
480
                            ends_with_depth = depth;
677
504
                        ends_with_depth = MIN(ends_with_depth, depth);
678
504
                    }
679
16.5k
                }
680
32.2k
                if ((cd->flags & (DETECT_CONTENT_WITHIN | DETECT_CONTENT_DEPTH)) == 0) {
681
10.1k
                    has_active_depth_chain = false;
682
10.1k
                    depth = 0;
683
10.1k
                }
684
32.2k
                break;
685
32.2k
            }
686
159k
            case DETECT_PCRE: {
687
                // relative could leave offset_plus_pat set.
688
159k
                const DetectPcreData *pd = (const DetectPcreData *)sm->ctx;
689
159k
                if (pd->flags & DETECT_PCRE_RELATIVE) {
690
6.38k
                    depth = 0;
691
152k
                } else {
692
152k
                    SCLogDebug("non-anchored PCRE not supported, reset offset_plus_pat & offset");
693
152k
                    offset_plus_pat = offset = depth = 0;
694
152k
                }
695
159k
                has_active_depth_chain = false;
696
159k
                break;
697
32.2k
            }
698
123k
            default:
699
123k
                SCLogDebug("keyword not supported, reset offset_plus_pat & offset");
700
123k
                offset_plus_pat = offset = depth = 0;
701
123k
                has_active_depth_chain = false;
702
123k
                break;
703
424k
        }
704
424k
    }
705
    /* apply anchored 'ends with' as depth to all patterns */
706
371k
    if (has_depth && has_ends_with) {
707
2.58k
        for (SigMatch *sm = sm_head; sm != NULL; sm = sm->next) {
708
2.10k
            switch (sm->type) {
709
2.02k
                case DETECT_CONTENT: {
710
2.02k
                    DetectContentData *cd = (DetectContentData *)sm->ctx;
711
2.02k
                    if (cd->depth == 0)
712
631
                        cd->depth = ends_with_depth;
713
2.02k
                    cd->depth = MIN(ends_with_depth, cd->depth);
714
2.02k
                    if (cd->depth)
715
2.02k
                        cd->flags |= DETECT_CONTENT_DEPTH;
716
2.02k
                    break;
717
0
                }
718
2.10k
            }
719
2.10k
        }
720
480
    }
721
371k
#undef VALIDATE
722
371k
}
723
724
void DetectContentPropagateLimits(Signature *s)
725
241k
{
726
241k
    PropagateLimits(s, s->init_data->smlists[DETECT_SM_LIST_PMATCH]);
727
372k
    for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
728
130k
        PropagateLimits(s, s->init_data->buffers[x].head);
729
130k
    }
730
241k
}
731
732
static inline bool NeedsAsHex(uint8_t c)
733
8.92M
{
734
8.92M
    if (!isprint(c))
735
251k
        return true;
736
737
8.67M
    switch (c) {
738
25.1k
        case '/':
739
140k
        case ';':
740
448k
        case ':':
741
461k
        case '\\':
742
1.26M
        case ' ':
743
1.27M
        case '|':
744
1.27M
        case '"':
745
1.28M
        case '`':
746
1.30M
        case '\'':
747
1.30M
            return true;
748
8.67M
    }
749
7.37M
    return false;
750
8.67M
}
751
752
void DetectContentPatternPrettyPrint(const DetectContentData *cd, char *str, size_t str_len)
753
442k
{
754
442k
    bool hex = false;
755
9.37M
    for (uint16_t i = 0; i < cd->content_len; i++) {
756
8.92M
        if (NeedsAsHex(cd->content[i])) {
757
1.55M
            char hex_str[4];
758
1.55M
            snprintf(hex_str, sizeof(hex_str), "%s%02X", !hex ? "|" : " ", cd->content[i]);
759
1.55M
            strlcat(str, hex_str, str_len);
760
1.55M
            hex = true;
761
7.37M
        } else {
762
7.37M
            char p_str[3];
763
7.37M
            snprintf(p_str, sizeof(p_str), "%s%c", hex ? "|" : "", cd->content[i]);
764
7.37M
            strlcat(str, p_str, str_len);
765
7.37M
            hex = false;
766
7.37M
        }
767
8.92M
    }
768
442k
    if (hex) {
769
34.8k
        strlcat(str, "|", str_len);
770
34.8k
    }
771
442k
}
772
773
int DetectContentConvertToNocase(DetectEngineCtx *de_ctx, DetectContentData *cd)
774
151k
{
775
151k
    if (cd->flags & DETECT_CONTENT_NOCASE) {
776
510
        SCLogError("can't use multiple nocase modifiers with the same content");
777
510
        return -1;
778
510
    }
779
780
    /* for consistency in later use (e.g. by MPM construction and hashing),
781
     * coerce the content string to lower-case. */
782
2.46M
    for (uint8_t *c = cd->content; c < cd->content + cd->content_len; c++) {
783
2.31M
        *c = u8_tolower(*c);
784
2.31M
    }
785
786
151k
    cd->flags |= DETECT_CONTENT_NOCASE;
787
    /* Recreate the context with nocase chars */
788
151k
    SpmDestroyCtx(cd->spm_ctx);
789
151k
    cd->spm_ctx = SpmInitCtx(cd->content, cd->content_len, 1, de_ctx->spm_global_thread_ctx);
790
151k
    if (cd->spm_ctx == NULL) {
791
0
        return -1;
792
0
    }
793
151k
    return 0;
794
151k
}
795
796
#ifdef UNITTESTS /* UNITTESTS */
797
#include "detect-engine-alert.h"
798
#include "packet.h"
799
800
static bool TestLastContent(const Signature *s, uint16_t o, uint16_t d)
801
{
802
    const SigMatch *sm = s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH];
803
    if (!sm) {
804
        SCLogDebug("no sm");
805
        return false;
806
    }
807
    if (!(sm->type == DETECT_CONTENT)) {
808
        SCLogDebug("not content");
809
        return false;
810
    }
811
    const DetectContentData *cd = (const DetectContentData *)sm->ctx;
812
    if (o != cd->offset) {
813
        SCLogDebug("offset mismatch %u != %u", o, cd->offset);
814
        return false;
815
    }
816
    if (d != cd->depth) {
817
        SCLogDebug("depth mismatch %u != %u", d, cd->depth);
818
        return false;
819
    }
820
    return true;
821
}
822
823
#define TEST_RUN(sig, o, d)                                                                        \
824
    {                                                                                              \
825
        SCLogDebug("TEST_RUN start: '%s'", (sig));                                                 \
826
        DetectEngineCtx *de_ctx = DetectEngineCtxInit();                                           \
827
        FAIL_IF_NULL(de_ctx);                                                                      \
828
        de_ctx->flags |= DE_QUIET;                                                                 \
829
        char rule[2048];                                                                           \
830
        snprintf(rule, sizeof(rule), "alert tcp any any -> any any (%s sid:1; rev:1;)", (sig));    \
831
        Signature *s = DetectEngineAppendSig(de_ctx, rule);                                        \
832
        FAIL_IF_NULL(s);                                                                           \
833
        SigAddressPrepareStage1(de_ctx);                                                           \
834
        bool res = TestLastContent(s, (o), (d));                                                   \
835
        FAIL_IF(res == false);                                                                     \
836
        DetectEngineCtxFree(de_ctx);                                                               \
837
    }
838
839
#define TEST_DONE \
840
    PASS
841
842
/** \test test propagation of depth/offset/distance/within */
843
static int DetectContentDepthTest01(void)
844
{
845
    // straight depth/offset
846
    TEST_RUN("content:\"abc\"; offset:1; depth:3;", 1, 4);
847
    // dsize applied as depth
848
    TEST_RUN("dsize:10; content:\"abc\";", 0, 10);
849
    TEST_RUN("dsize:<10; content:\"abc\";", 0, 10);
850
    TEST_RUN("dsize:5<>10; content:\"abc\";", 0, 10);
851
852
    // relative match, directly following anchored content
853
    TEST_RUN("content:\"abc\"; depth:3; content:\"xyz\"; distance:0; within:3; ", 3, 6);
854
    // relative match, directly following anchored content
855
    TEST_RUN("content:\"abc\"; offset:3; depth:3; content:\"xyz\"; distance:0; within:3; ", 6, 9);
856
    TEST_RUN("content:\"abc\"; depth:6; content:\"xyz\"; distance:0; within:3; ", 3, 9);
857
858
    // multiple relative matches after anchored content
859
    TEST_RUN("content:\"abc\"; depth:3; content:\"klm\"; distance:0; within:3; content:\"xyz\"; distance:0; within:3; ", 6, 9);
860
    // test 'reset' due to unanchored content
861
    TEST_RUN("content:\"abc\"; depth:3; content:\"klm\"; content:\"xyz\"; distance:0; within:3; ", 3, 0);
862
    // test 'reset' due to unanchored pcre
863
    TEST_RUN("content:\"abc\"; depth:3; pcre:/\"klm\"/; content:\"xyz\"; distance:0; within:3; ", 0, 0);
864
    // test relative pcre. We can use previous offset+pattern len
865
    TEST_RUN("content:\"abc\"; depth:3; pcre:/\"klm\"/R; content:\"xyz\"; distance:0; within:3; ", 3, 0);
866
    TEST_RUN("content:\"abc\"; offset:3; depth:3; pcre:/\"klm\"/R; content:\"xyz\"; distance:0; within:3; ", 6, 0);
867
868
    TEST_RUN("content:\"abc\"; depth:3; content:\"klm\"; within:3; content:\"xyz\"; within:3; ", 0, 9);
869
870
    TEST_RUN("content:\"abc\"; depth:3; content:\"klm\"; distance:0; content:\"xyz\"; distance:0; ", 6, 0);
871
872
    // tests to see if anchored 'ends_with' is applied to other content as depth
873
    TEST_RUN("content:\"abc\"; depth:6; isdataat:!1,relative; content:\"klm\";", 0, 6);
874
    TEST_RUN("content:\"abc\"; depth:3; content:\"klm\"; within:3; content:\"xyz\"; within:3; isdataat:!1,relative; content:\"def\"; ", 0, 9);
875
876
    TEST_RUN("content:\"|03|\"; depth:1; content:\"|e0|\"; distance:4; within:1;", 5, 6);
877
    TEST_RUN("content:\"|03|\"; depth:1; content:\"|e0|\"; distance:4; within:1; content:\"Cookie|3a|\"; distance:5; within:7;", 11, 18);
878
879
    TEST_RUN("content:\"this\"; content:\"is\"; within:6; content:\"big\"; within:8; content:\"string\"; within:8;", 0, 0);
880
881
    TEST_RUN("dsize:<80; content:!\"|00 22 02 00|\"; depth: 4; content:\"|00 00 04|\"; distance:8; within:3; content:\"|00 00 00 00 00|\"; distance:6; within:5;", 17, 80);
882
    TEST_RUN("content:!\"|00 22 02 00|\"; depth: 4; content:\"|00 00 04|\"; distance:8; within:3; content:\"|00 00 00 00 00|\"; distance:6; within:5;", 17, 0);
883
884
    TEST_RUN("content:\"|0d 0a 0d 0a|\"; content:\"code=\"; distance:0;", 4, 0);
885
    TEST_RUN("content:\"|0d 0a 0d 0a|\"; content:\"code=\"; distance:0; content:\"xploit.class\"; distance:2; within:18;", 11, 0);
886
887
    TEST_RUN("content:\"|16 03|\"; depth:2; content:\"|55 04 0a|\"; distance:0;", 2, 0);
888
    TEST_RUN("content:\"|16 03|\"; depth:2; content:\"|55 04 0a|\"; distance:0; content:\"|0d|LogMeIn, Inc.\"; distance:1; within:14;", 6, 0);
889
    TEST_RUN("content:\"|16 03|\"; depth:2; content:\"|55 04 0a|\"; distance:0; content:\"|0d|LogMeIn, Inc.\"; distance:1; within:14; content:\".app\";", 0, 0);
890
891
    TEST_RUN("content:\"=\"; offset:4; depth:9;", 4, 13);
892
    // low end: offset 4 + patlen 1 = 5. So 5 + distance 55 = 60.
893
    // hi end: depth '13' (4+9) + distance 55 = 68 + within 2 = 70
894
    TEST_RUN("content:\"=\"; offset:4; depth:9; content:\"=&\"; distance:55; within:2;", 60, 70);
895
896
    // distance value is too high so we bail and not set anything on this content
897
    TEST_RUN("content:\"0123456789\"; content:\"abcdef\"; distance:1048576;", 0, 0);
898
899
    // Bug #5162.
900
    TEST_RUN("content:\"SMB\"; depth:8; content:\"|09 00|\"; distance:8; within:2;", 11, 18);
901
    TEST_RUN("content:\"SMB\"; depth:8; content:\"|09 00|\"; distance:8; within:2; content:\"|05 "
902
             "00 00|\"; distance:0;",
903
            13, 0);
904
    TEST_RUN("content:\"SMB\"; depth:8; content:\"|09 00|\"; distance:8; within:2; content:\"|05 "
905
             "00 00|\"; distance:0; content:\"|0c 00|\"; distance:19; within:2;",
906
            35, 0);
907
    TEST_RUN("content:\"SMB\"; depth:8; content:\"|09 00|\"; distance:8; within:2; content:\"|05 "
908
             "00 00|\"; distance:0; content:\"|0c 00|\"; distance:19; within:2; content:\"|15 00 "
909
             "00 00|\"; distance:20; within:4;",
910
            57, 0);
911
912
    TEST_DONE;
913
}
914
915
/**
916
 * \brief Print list of DETECT_CONTENT SigMatch's allocated in a
917
 * SigMatch list, from the current sm to the end
918
 * \param sm pointer to the current SigMatch to start printing from
919
 */
920
static void DetectContentPrintAll(SigMatch *sm)
921
{
922
#ifdef DEBUG
923
    if (SCLogDebugEnabled()) {
924
        int i = 0;
925
926
        if (sm == NULL)
927
            return;
928
929
        SigMatch *first_sm = sm;
930
931
       /* Print all of them */
932
        for (; first_sm != NULL; first_sm = first_sm->next) {
933
            if (first_sm->type == DETECT_CONTENT) {
934
                SCLogDebug("Printing SigMatch DETECT_CONTENT %d", ++i);
935
                DetectContentPrint((DetectContentData*)first_sm->ctx);
936
            }
937
        }
938
    }
939
#endif /* DEBUG */
940
}
941
942
static int g_file_data_buffer_id = 0;
943
static int g_dce_stub_data_buffer_id = 0;
944
945
/**
946
 * \test DetectContentParseTest01 this is a test to make sure we can deal with escaped colons
947
 */
948
static int DetectContentParseTest01 (void)
949
{
950
    int result = 1;
951
    DetectContentData *cd = NULL;
952
    const char *teststring = "abc\\:def";
953
    const char *teststringparsed = "abc:def";
954
955
    uint8_t spm_matcher = SinglePatternMatchDefaultMatcher();
956
    SpmGlobalThreadCtx *spm_global_thread_ctx = SpmInitGlobalThreadCtx(spm_matcher);
957
    FAIL_IF(spm_global_thread_ctx == NULL);
958
959
    cd = DetectContentParse(spm_global_thread_ctx, teststring);
960
    if (cd != NULL) {
961
        if (memcmp(cd->content, teststringparsed, strlen(teststringparsed)) != 0) {
962
            SCLogDebug("expected %s got ", teststringparsed);
963
            PrintRawUriFp(stdout,cd->content,cd->content_len);
964
            SCLogDebug(": ");
965
            result = 0;
966
            DetectContentFree(NULL, cd);
967
        }
968
    } else {
969
        SCLogDebug("expected %s got NULL: ", teststringparsed);
970
        result = 0;
971
    }
972
    SpmDestroyGlobalThreadCtx(spm_global_thread_ctx);
973
    return result;
974
}
975
976
/**
977
 * \test DetectContentParseTest02 this is a test to make sure we can deal with escaped semi-colons
978
 */
979
static int DetectContentParseTest02 (void)
980
{
981
    int result = 1;
982
    DetectContentData *cd = NULL;
983
    const char *teststring = "abc\\;def";
984
    const char *teststringparsed = "abc;def";
985
986
    uint8_t spm_matcher = SinglePatternMatchDefaultMatcher();
987
    SpmGlobalThreadCtx *spm_global_thread_ctx = SpmInitGlobalThreadCtx(spm_matcher);
988
    FAIL_IF(spm_global_thread_ctx == NULL);
989
990
    cd = DetectContentParse(spm_global_thread_ctx, teststring);
991
    if (cd != NULL) {
992
        if (memcmp(cd->content, teststringparsed, strlen(teststringparsed)) != 0) {
993
            SCLogDebug("expected %s got ", teststringparsed);
994
            PrintRawUriFp(stdout,cd->content,cd->content_len);
995
            SCLogDebug(": ");
996
            result = 0;
997
            DetectContentFree(NULL, cd);
998
        }
999
    } else {
1000
        SCLogDebug("expected %s got NULL: ", teststringparsed);
1001
        result = 0;
1002
    }
1003
    SpmDestroyGlobalThreadCtx(spm_global_thread_ctx);
1004
    return result;
1005
}
1006
1007
/**
1008
 * \test DetectContentParseTest03 this is a test to make sure we can deal with escaped double-quotes
1009
 */
1010
static int DetectContentParseTest03 (void)
1011
{
1012
    int result = 1;
1013
    DetectContentData *cd = NULL;
1014
    const char *teststring = "abc\\\"def";
1015
    const char *teststringparsed = "abc\"def";
1016
1017
    uint8_t spm_matcher = SinglePatternMatchDefaultMatcher();
1018
    SpmGlobalThreadCtx *spm_global_thread_ctx = SpmInitGlobalThreadCtx(spm_matcher);
1019
    FAIL_IF(spm_global_thread_ctx == NULL);
1020
1021
    cd = DetectContentParse(spm_global_thread_ctx, teststring);
1022
    if (cd != NULL) {
1023
        if (memcmp(cd->content, teststringparsed, strlen(teststringparsed)) != 0) {
1024
            SCLogDebug("expected %s got ", teststringparsed);
1025
            PrintRawUriFp(stdout,cd->content,cd->content_len);
1026
            SCLogDebug(": ");
1027
            result = 0;
1028
            DetectContentFree(NULL, cd);
1029
        }
1030
    } else {
1031
        SCLogDebug("expected %s got NULL: ", teststringparsed);
1032
        result = 0;
1033
    }
1034
    SpmDestroyGlobalThreadCtx(spm_global_thread_ctx);
1035
    return result;
1036
}
1037
1038
/**
1039
 * \test DetectContentParseTest04 this is a test to make sure we can deal with escaped backslashes
1040
 */
1041
static int DetectContentParseTest04 (void)
1042
{
1043
    int result = 1;
1044
    DetectContentData *cd = NULL;
1045
    const char *teststring = "abc\\\\def";
1046
    const char *teststringparsed = "abc\\def";
1047
1048
    uint8_t spm_matcher = SinglePatternMatchDefaultMatcher();
1049
    SpmGlobalThreadCtx *spm_global_thread_ctx = SpmInitGlobalThreadCtx(spm_matcher);
1050
    FAIL_IF(spm_global_thread_ctx == NULL);
1051
1052
    cd = DetectContentParse(spm_global_thread_ctx, teststring);
1053
    if (cd != NULL) {
1054
        uint16_t len = (cd->content_len > strlen(teststringparsed));
1055
        if (memcmp(cd->content, teststringparsed, len) != 0) {
1056
            SCLogDebug("expected %s got ", teststringparsed);
1057
            PrintRawUriFp(stdout,cd->content,cd->content_len);
1058
            SCLogDebug(": ");
1059
            result = 0;
1060
            DetectContentFree(NULL, cd);
1061
        }
1062
    } else {
1063
        SCLogDebug("expected %s got NULL: ", teststringparsed);
1064
        result = 0;
1065
    }
1066
    SpmDestroyGlobalThreadCtx(spm_global_thread_ctx);
1067
    return result;
1068
}
1069
1070
/**
1071
 * \test DetectContentParseTest05 test illegal escape
1072
 */
1073
static int DetectContentParseTest05 (void)
1074
{
1075
    int result = 1;
1076
    DetectContentData *cd = NULL;
1077
    const char *teststring = "abc\\def";
1078
1079
    uint8_t spm_matcher = SinglePatternMatchDefaultMatcher();
1080
    SpmGlobalThreadCtx *spm_global_thread_ctx = SpmInitGlobalThreadCtx(spm_matcher);
1081
    FAIL_IF(spm_global_thread_ctx == NULL);
1082
1083
    cd = DetectContentParse(spm_global_thread_ctx, teststring);
1084
    if (cd != NULL) {
1085
        SCLogDebug("expected NULL got ");
1086
        PrintRawUriFp(stdout,cd->content,cd->content_len);
1087
        SCLogDebug(": ");
1088
        result = 0;
1089
        DetectContentFree(NULL, cd);
1090
    }
1091
    SpmDestroyGlobalThreadCtx(spm_global_thread_ctx);
1092
    return result;
1093
}
1094
1095
/**
1096
 * \test DetectContentParseTest06 test a binary content
1097
 */
1098
static int DetectContentParseTest06 (void)
1099
{
1100
    int result = 1;
1101
    DetectContentData *cd = NULL;
1102
    const char *teststring = "a|42|c|44|e|46|";
1103
    const char *teststringparsed = "abcdef";
1104
1105
    uint8_t spm_matcher = SinglePatternMatchDefaultMatcher();
1106
    SpmGlobalThreadCtx *spm_global_thread_ctx = SpmInitGlobalThreadCtx(spm_matcher);
1107
    FAIL_IF(spm_global_thread_ctx == NULL);
1108
1109
    cd = DetectContentParse(spm_global_thread_ctx, teststring);
1110
    if (cd != NULL) {
1111
        uint16_t len = (cd->content_len > strlen(teststringparsed));
1112
        if (memcmp(cd->content, teststringparsed, len) != 0) {
1113
            SCLogDebug("expected %s got ", teststringparsed);
1114
            PrintRawUriFp(stdout,cd->content,cd->content_len);
1115
            SCLogDebug(": ");
1116
            result = 0;
1117
            DetectContentFree(NULL, cd);
1118
        }
1119
    } else {
1120
        SCLogDebug("expected %s got NULL: ", teststringparsed);
1121
        result = 0;
1122
    }
1123
    SpmDestroyGlobalThreadCtx(spm_global_thread_ctx);
1124
    return result;
1125
}
1126
1127
/**
1128
 * \test DetectContentParseTest07 test an empty content
1129
 */
1130
static int DetectContentParseTest07 (void)
1131
{
1132
    int result = 1;
1133
    DetectContentData *cd = NULL;
1134
    const char *teststring = "";
1135
1136
    uint8_t spm_matcher = SinglePatternMatchDefaultMatcher();
1137
    SpmGlobalThreadCtx *spm_global_thread_ctx = SpmInitGlobalThreadCtx(spm_matcher);
1138
    FAIL_IF(spm_global_thread_ctx == NULL);
1139
1140
    cd = DetectContentParse(spm_global_thread_ctx, teststring);
1141
    if (cd != NULL) {
1142
        SCLogDebug("expected NULL got %p: ", cd);
1143
        result = 0;
1144
        DetectContentFree(NULL, cd);
1145
    }
1146
    SpmDestroyGlobalThreadCtx(spm_global_thread_ctx);
1147
    return result;
1148
}
1149
1150
/**
1151
 * \test DetectContentParseTest08 test an empty content
1152
 */
1153
static int DetectContentParseTest08 (void)
1154
{
1155
    int result = 1;
1156
    DetectContentData *cd = NULL;
1157
    const char *teststring = "";
1158
1159
    uint8_t spm_matcher = SinglePatternMatchDefaultMatcher();
1160
    SpmGlobalThreadCtx *spm_global_thread_ctx = SpmInitGlobalThreadCtx(spm_matcher);
1161
    FAIL_IF(spm_global_thread_ctx == NULL);
1162
1163
    cd = DetectContentParse(spm_global_thread_ctx, teststring);
1164
    if (cd != NULL) {
1165
        SCLogDebug("expected NULL got %p: ", cd);
1166
        result = 0;
1167
        DetectContentFree(NULL, cd);
1168
    }
1169
    SpmDestroyGlobalThreadCtx(spm_global_thread_ctx);
1170
    return result;
1171
}
1172
1173
/**
1174
 * \test Test packet Matches
1175
 * \param raw_eth_pkt pointer to the ethernet packet
1176
 * \param pktsize size of the packet
1177
 * \param sig pointer to the signature to test
1178
 * \param sid sid number of the signature
1179
 * \retval return 1 if match
1180
 * \retval return 0 if not
1181
 */
1182
static int DetectContentLongPatternMatchTest(uint8_t *raw_eth_pkt, uint16_t pktsize, const char *sig,
1183
                      uint32_t sid)
1184
{
1185
    int result = 0;
1186
1187
    Packet *p = PacketGetFromAlloc();
1188
    if (unlikely(p == NULL))
1189
        return 0;
1190
    DecodeThreadVars dtv;
1191
1192
    ThreadVars th_v;
1193
    DetectEngineThreadCtx *det_ctx = NULL;
1194
1195
    memset(&dtv, 0, sizeof(DecodeThreadVars));
1196
    memset(&th_v, 0, sizeof(th_v));
1197
1198
    FlowInitConfig(FLOW_QUIET);
1199
    DecodeEthernet(&th_v, &dtv, p, raw_eth_pkt, pktsize);
1200
1201
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1202
    if (de_ctx == NULL) {
1203
        goto end;
1204
    }
1205
1206
    de_ctx->flags |= DE_QUIET;
1207
1208
    de_ctx->sig_list = SigInit(de_ctx, sig);
1209
    if (de_ctx->sig_list == NULL) {
1210
        goto end;
1211
    }
1212
    de_ctx->sig_list->next = NULL;
1213
1214
    if (de_ctx->sig_list->init_data->smlists_tail[DETECT_SM_LIST_PMATCH]->type == DETECT_CONTENT) {
1215
        DetectContentData *co = (DetectContentData *)de_ctx->sig_list->init_data
1216
                                        ->smlists_tail[DETECT_SM_LIST_PMATCH]
1217
                                        ->ctx;
1218
        if (co->flags & DETECT_CONTENT_RELATIVE_NEXT) {
1219
            printf("relative next flag set on final match which is content: ");
1220
            goto end;
1221
        }
1222
    }
1223
1224
    SCLogDebug("---DetectContentLongPatternMatchTest---");
1225
    DetectContentPrintAll(de_ctx->sig_list->init_data->smlists[DETECT_SM_LIST_MATCH]);
1226
1227
    SigGroupBuild(de_ctx);
1228
    DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
1229
1230
    SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1231
    if (PacketAlertCheck(p, sid) != 1) {
1232
        goto end;
1233
    }
1234
1235
    result = 1;
1236
end:
1237
    if (de_ctx != NULL)
1238
    {
1239
        SigGroupCleanup(de_ctx);
1240
        SigCleanSignatures(de_ctx);
1241
        if (det_ctx != NULL)
1242
            DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
1243
        DetectEngineCtxFree(de_ctx);
1244
    }
1245
    PacketRecycle(p);
1246
    FlowShutdown();
1247
1248
    SCFree(p);
1249
    return result;
1250
}
1251
1252
/**
1253
 * \brief Wrapper for DetectContentLongPatternMatchTest
1254
 */
1255
static int DetectContentLongPatternMatchTestWrp(const char *sig, uint32_t sid)
1256
{
1257
    /** Real packet with the following tcp data:
1258
     * "Hi, this is a big test to check content matches of splitted"
1259
     * "patterns between multiple chunks!"
1260
     * (without quotes! :) )
1261
     */
1262
    uint8_t raw_eth_pkt[] = {
1263
        0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,
1264
        0x00,0x00,0x00,0x00,0x08,0x00,0x45,0x00,
1265
        0x00,0x85,0x00,0x01,0x00,0x00,0x40,0x06,
1266
        0x7c,0x70,0x7f,0x00,0x00,0x01,0x7f,0x00,
1267
        0x00,0x01,0x00,0x14,0x00,0x50,0x00,0x00,
1268
        0x00,0x00,0x00,0x00,0x00,0x00,0x50,0x02,
1269
        0x20,0x00,0xc9,0xad,0x00,0x00,0x48,0x69,
1270
        0x2c,0x20,0x74,0x68,0x69,0x73,0x20,0x69,
1271
        0x73,0x20,0x61,0x20,0x62,0x69,0x67,0x20,
1272
        0x74,0x65,0x73,0x74,0x20,0x74,0x6f,0x20,
1273
        0x63,0x68,0x65,0x63,0x6b,0x20,0x63,0x6f,
1274
        0x6e,0x74,0x65,0x6e,0x74,0x20,0x6d,0x61,
1275
        0x74,0x63,0x68,0x65,0x73,0x20,0x6f,0x66,
1276
        0x20,0x73,0x70,0x6c,0x69,0x74,0x74,0x65,
1277
        0x64,0x20,0x70,0x61,0x74,0x74,0x65,0x72,
1278
        0x6e,0x73,0x20,0x62,0x65,0x74,0x77,0x65,
1279
        0x65,0x6e,0x20,0x6d,0x75,0x6c,0x74,0x69,
1280
        0x70,0x6c,0x65,0x20,0x63,0x68,0x75,0x6e,
1281
        0x6b,0x73,0x21 }; /* end raw_eth_pkt */
1282
1283
    return DetectContentLongPatternMatchTest(raw_eth_pkt, (uint16_t)sizeof(raw_eth_pkt),
1284
                             sig, sid);
1285
}
1286
1287
/**
1288
 * \test Check if we match a normal pattern (not splitted)
1289
 */
1290
static int DetectContentLongPatternMatchTest01(void)
1291
{
1292
    const char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";"
1293
                " content:\"Hi, this is a big test\"; sid:1;)";
1294
    return DetectContentLongPatternMatchTestWrp(sig, 1);
1295
}
1296
1297
/**
1298
 * \test Check if we match a splitted pattern
1299
 */
1300
static int DetectContentLongPatternMatchTest02(void)
1301
{
1302
    const char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";"
1303
                " content:\"Hi, this is a big test to check content matches of"
1304
                " splitted patterns between multiple chunks!\"; sid:1;)";
1305
    return DetectContentLongPatternMatchTestWrp(sig, 1);
1306
}
1307
1308
/**
1309
 * \test Check that we don't match the signature if one of the splitted
1310
 * chunks doesn't match the packet
1311
 */
1312
static int DetectContentLongPatternMatchTest03(void)
1313
{
1314
    /** The last chunk of the content should not match */
1315
    const char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";"
1316
                " content:\"Hi, this is a big test to check content matches of"
1317
                " splitted patterns between multiple splitted chunks!\"; sid:1;)";
1318
    return (DetectContentLongPatternMatchTestWrp(sig, 1) == 0) ? 1: 0;
1319
}
1320
1321
/**
1322
 * \test Check if we match multiple content (not splitted)
1323
 */
1324
static int DetectContentLongPatternMatchTest04(void)
1325
{
1326
    const char *sig = "alert tcp any any -> any any (msg:\"Nothing..\"; "
1327
                " content:\"Hi, this is\"; depth:15 ;content:\"a big test\"; "
1328
                " within:15; content:\"to check content matches of\"; "
1329
                " within:30; content:\"splitted patterns\"; distance:1; "
1330
                " within:30; "
1331
                " sid:1;)";
1332
    return DetectContentLongPatternMatchTestWrp(sig, 1);
1333
}
1334
1335
/**
1336
 * \test Check that we match packets with multiple chunks and not chunks
1337
 * Here we should specify only contents that fit in 32 bytes
1338
 * Each of them with their modifier values
1339
 */
1340
static int DetectContentLongPatternMatchTest05(void)
1341
{
1342
    const char *sig = "alert tcp any any -> any any (msg:\"Nothing..\"; "
1343
                " content:\"Hi, this is a big\"; depth:17; "
1344
                " isdataat:30, relative; "
1345
                " content:\"test\"; within: 5; distance:1; "
1346
                " isdataat:15, relative; "
1347
                " content:\"of splitted\"; within:37; distance:15; "
1348
                " isdataat:20,relative; "
1349
                " content:\"patterns\"; within:9; distance:1; "
1350
                " isdataat:10, relative; "
1351
                " sid:1;)";
1352
    return DetectContentLongPatternMatchTestWrp(sig, 1);
1353
}
1354
1355
/**
1356
 * \test Check that we match packets with multiple chunks and not chunks
1357
 * Here we should specify contents that fit and contents that must be splitted
1358
 * Each of them with their modifier values
1359
 */
1360
static int DetectContentLongPatternMatchTest06(void)
1361
{
1362
    const char *sig = "alert tcp any any -> any any (msg:\"Nothing..\"; "
1363
                " content:\"Hi, this is a big test to check cont\"; depth:36;"
1364
                " content:\"ent matches\"; within:11; distance:0; "
1365
                " content:\"of splitted patterns between multiple\"; "
1366
                " within:38; distance:1; "
1367
                " content:\"chunks!\"; within: 8; distance:1; "
1368
                " sid:1;)";
1369
    return DetectContentLongPatternMatchTestWrp(sig, 1);
1370
}
1371
1372
/**
1373
 * \test Check if we match contents that are in the payload
1374
 * but not in the same order as specified in the signature
1375
 */
1376
static int DetectContentLongPatternMatchTest07(void)
1377
{
1378
    const char *sig = "alert tcp any any -> any any (msg:\"Nothing..\"; "
1379
                " content:\"chunks!\"; "
1380
                " content:\"content matches\"; offset:32; depth:47; "
1381
                " content:\"of splitted patterns between multiple\"; "
1382
                " content:\"Hi, this is a big\"; offset:0; depth:17; "
1383
                " sid:1;)";
1384
    return DetectContentLongPatternMatchTestWrp(sig, 1);
1385
}
1386
1387
/**
1388
 * \test Check if we match contents that are in the payload
1389
 * but not in the same order as specified in the signature
1390
 */
1391
static int DetectContentLongPatternMatchTest08(void)
1392
{
1393
    const char *sig = "alert tcp any any -> any any (msg:\"Nothing..\"; "
1394
                " content:\"ent matches\"; "
1395
                " content:\"of splitted patterns between multiple\"; "
1396
                " within:38; distance:1; "
1397
                " content:\"chunks!\"; within: 8; distance:1; "
1398
                " content:\"Hi, this is a big test to check cont\"; depth:36;"
1399
                " sid:1;)";
1400
    return DetectContentLongPatternMatchTestWrp(sig, 1);
1401
}
1402
1403
/**
1404
 * \test Check if we match contents that are in the payload
1405
 * but not in the same order as specified in the signature
1406
 */
1407
static int DetectContentLongPatternMatchTest09(void)
1408
{
1409
    const char *sig = "alert tcp any any -> any any (msg:\"Nothing..\"; "
1410
                " content:\"ent matches\"; "
1411
                " content:\"of splitted patterns between multiple\"; "
1412
                " offset:47; depth:85; "
1413
                " content:\"chunks!\"; within: 8; distance:1; "
1414
                " content:\"Hi, this is a big test to chec\"; depth:36;"
1415
                " content:\"k cont\"; distance:0; within:6;"
1416
                " sid:1;)";
1417
    return DetectContentLongPatternMatchTestWrp(sig, 1);
1418
}
1419
1420
/**
1421
 * \test Check if we match two consecutive simple contents
1422
 */
1423
static int DetectContentLongPatternMatchTest10(void)
1424
{
1425
    const char *sig = "alert tcp any any -> any any (msg:\"Nothing..\"; "
1426
                " content:\"Hi, this is a big test to check \"; "
1427
                " content:\"con\"; "
1428
                " sid:1;)";
1429
    return DetectContentLongPatternMatchTestWrp(sig, 1);
1430
}
1431
1432
/**
1433
 * \test Check if we match two contents of length 1
1434
 */
1435
static int DetectContentLongPatternMatchTest11(void)
1436
{
1437
    const char *sig = "alert tcp any any -> any any (msg:\"Nothing..\"; "
1438
                " content:\"H\"; "
1439
                " content:\"i\"; "
1440
                " sid:1;)";
1441
    return DetectContentLongPatternMatchTestWrp(sig, 1);
1442
}
1443
1444
static int DetectContentParseTest09(void)
1445
{
1446
    DetectContentData *cd = NULL;
1447
    const char *teststring = "boo";
1448
1449
    uint8_t spm_matcher = SinglePatternMatchDefaultMatcher();
1450
    SpmGlobalThreadCtx *spm_global_thread_ctx = SpmInitGlobalThreadCtx(spm_matcher);
1451
    FAIL_IF(spm_global_thread_ctx == NULL);
1452
1453
    cd = DetectContentParse(spm_global_thread_ctx, teststring);
1454
    FAIL_IF_NULL(cd);
1455
    DetectContentFree(NULL, cd);
1456
    SpmDestroyGlobalThreadCtx(spm_global_thread_ctx);
1457
    PASS;
1458
}
1459
1460
/**
1461
 * \test Test cases where if within specified is < content length we invalidate
1462
 *       the sig.
1463
 */
1464
static int DetectContentParseTest17(void)
1465
{
1466
    int result = 0;
1467
    const char *sigstr = "alert tcp any any -> any any (msg:\"Dummy\"; "
1468
        "content:\"one\"; content:\"two\"; within:2; sid:1;)";
1469
1470
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1471
    if (de_ctx == NULL)
1472
        goto end;
1473
1474
    de_ctx->sig_list = SigInit(de_ctx, sigstr);
1475
    if (de_ctx->sig_list != NULL)
1476
        goto end;
1477
1478
    result = 1;
1479
1480
end:
1481
    SigCleanSignatures(de_ctx);
1482
    if (de_ctx != NULL)
1483
        DetectEngineCtxFree(de_ctx);
1484
    return result;
1485
}
1486
1487
/**
1488
 * \test Test content for dce sig.
1489
 */
1490
static int DetectContentParseTest18(void)
1491
{
1492
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1493
    FAIL_IF_NULL(de_ctx);
1494
1495
    Signature *s = SigAlloc();
1496
    FAIL_IF_NULL(s);
1497
    FAIL_IF(DetectSignatureSetAppProto(s, ALPROTO_DCERPC) < 0);
1498
    FAIL_IF_NOT(DetectContentSetup(de_ctx, s, "one") == 0);
1499
    FAIL_IF(DetectBufferIsPresent(s, g_dce_stub_data_buffer_id));
1500
    FAIL_IF_NOT(s->init_data->smlists[DETECT_SM_LIST_PMATCH] != NULL);
1501
    SigFree(de_ctx, s);
1502
1503
    s = SigAlloc();
1504
    FAIL_IF_NULL(s);
1505
    FAIL_IF_NOT(DetectContentSetup(de_ctx, s, "one") == 0);
1506
    FAIL_IF(DetectBufferIsPresent(s, g_dce_stub_data_buffer_id));
1507
    FAIL_IF_NOT(s->init_data->smlists[DETECT_SM_LIST_PMATCH] != NULL);
1508
    SigFree(de_ctx, s);
1509
1510
    DetectEngineCtxFree(de_ctx);
1511
    PASS;
1512
}
1513
1514
/**
1515
 * \test Test content for dce sig.
1516
 */
1517
1518
static int DetectContentParseTest19(void)
1519
{
1520
1521
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1522
    FAIL_IF_NULL(de_ctx);
1523
    de_ctx->flags |= DE_QUIET;
1524
1525
    Signature *s =
1526
            DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any "
1527
                                          "(msg:\"Testing dce iface, stub_data with content\"; "
1528
                                          "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; "
1529
                                          "dce_stub_data; "
1530
                                          "content:\"one\"; distance:0; sid:1;)");
1531
    FAIL_IF_NULL(s);
1532
1533
    SigMatch *sm = DetectBufferGetFirstSigMatch(s, g_dce_stub_data_buffer_id);
1534
    FAIL_IF_NULL(sm);
1535
    FAIL_IF_NOT(sm->type == DETECT_CONTENT);
1536
    FAIL_IF_NOT(s->init_data->smlists[DETECT_SM_LIST_PMATCH] == NULL);
1537
1538
    DetectContentData *data = (DetectContentData *)sm->ctx;
1539
    FAIL_IF_NOT(data->flags == DETECT_CONTENT_DISTANCE);
1540
1541
    s = DetectEngineAppendSig(de_ctx,
1542
            "alert tcp any any -> any any "
1543
            "(msg:\"Testing dce iface, stub_data with contents & distance, within\"; "
1544
            "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; "
1545
            "dce_stub_data; "
1546
            "content:\"one\"; distance:0; content:\"two\"; within:10; sid:2;)");
1547
    FAIL_IF_NULL(s);
1548
    sm = DetectBufferGetFirstSigMatch(s, g_dce_stub_data_buffer_id);
1549
    FAIL_IF_NULL(sm);
1550
    FAIL_IF_NOT(sm->type == DETECT_CONTENT);
1551
    FAIL_IF_NULL(sm->next);
1552
    sm = sm->next;
1553
    FAIL_IF_NOT(sm->type == DETECT_CONTENT);
1554
    FAIL_IF_NOT(s->init_data->smlists[DETECT_SM_LIST_PMATCH] == NULL);
1555
1556
    data = (DetectContentData *)sm->ctx;
1557
    FAIL_IF_NOT(data->flags == DETECT_CONTENT_WITHIN);
1558
    FAIL_IF_NOT(data->within == 10);
1559
1560
    s = DetectEngineAppendSig(de_ctx,
1561
            "alert tcp any any -> any any "
1562
            "(msg:\"Testing dce iface, stub with contents, distance, within\"; "
1563
            "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; "
1564
            "dce_stub_data; "
1565
            "content:\"one\"; distance:0; "
1566
            "content:\"two\"; within:10; distance:2; sid:3;)");
1567
    FAIL_IF_NULL(s);
1568
    sm = DetectBufferGetFirstSigMatch(s, g_dce_stub_data_buffer_id);
1569
    FAIL_IF_NULL(sm);
1570
    FAIL_IF_NOT(sm->type == DETECT_CONTENT);
1571
    FAIL_IF_NULL(sm->next);
1572
    sm = sm->next;
1573
    FAIL_IF_NOT(sm->type == DETECT_CONTENT);
1574
    data = (DetectContentData *)sm->ctx;
1575
    FAIL_IF_NOT(data->flags == (DETECT_CONTENT_WITHIN | DETECT_CONTENT_DISTANCE));
1576
    FAIL_IF_NOT(data->within == 10);
1577
    FAIL_IF_NOT(data->distance == 2);
1578
    FAIL_IF_NOT(s->init_data->smlists[DETECT_SM_LIST_PMATCH] == NULL);
1579
1580
    s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any "
1581
                                      "(msg:\"Testing content\"; "
1582
                                      "content:\"one\"; sid:4;)");
1583
    FAIL_IF_NULL(s);
1584
    FAIL_IF(DetectBufferIsPresent(s, g_dce_stub_data_buffer_id));
1585
    FAIL_IF(s->init_data->smlists[DETECT_SM_LIST_PMATCH] == NULL);
1586
1587
    DetectEngineCtxFree(de_ctx);
1588
    PASS;
1589
}
1590
1591
/**
1592
 * \test Test content for dce sig.
1593
 */
1594
static int DetectContentParseTest20(void)
1595
{
1596
    DetectEngineCtx *de_ctx = NULL;
1597
    int result = 1;
1598
1599
    de_ctx = DetectEngineCtxInit();
1600
    if (de_ctx == NULL)
1601
        goto end;
1602
1603
    de_ctx->flags |= DE_QUIET;
1604
    de_ctx->sig_list = SigInit(de_ctx,
1605
                               "alert udp any any -> any any "
1606
                               "(msg:\"test\"; content:\"\"; sid:238012;)");
1607
    if (de_ctx->sig_list != NULL) {
1608
        result = 0;
1609
        goto end;
1610
    }
1611
1612
 end:
1613
    SigGroupCleanup(de_ctx);
1614
    SigCleanSignatures(de_ctx);
1615
    DetectEngineCtxFree(de_ctx);
1616
1617
    return result;
1618
}
1619
1620
/**
1621
 * \test Parsing test
1622
 */
1623
static int DetectContentParseTest21(void)
1624
{
1625
    DetectEngineCtx *de_ctx = NULL;
1626
    int result = 1;
1627
1628
    de_ctx = DetectEngineCtxInit();
1629
    if (de_ctx == NULL)
1630
        goto end;
1631
1632
    de_ctx->flags |= DE_QUIET;
1633
    de_ctx->sig_list = SigInit(de_ctx,
1634
                               "alert udp any any -> any any "
1635
                               "(msg:\"test\"; content:\"; sid:238012;)");
1636
    if (de_ctx->sig_list != NULL) {
1637
        result = 0;
1638
        goto end;
1639
    }
1640
1641
 end:
1642
    SigGroupCleanup(de_ctx);
1643
    SigCleanSignatures(de_ctx);
1644
    DetectEngineCtxFree(de_ctx);
1645
1646
    return result;
1647
}
1648
1649
/**
1650
 * \test Parsing test
1651
 */
1652
static int DetectContentParseTest22(void)
1653
{
1654
    DetectEngineCtx *de_ctx = NULL;
1655
    int result = 1;
1656
1657
    de_ctx = DetectEngineCtxInit();
1658
    if (de_ctx == NULL)
1659
        goto end;
1660
1661
    de_ctx->flags |= DE_QUIET;
1662
    de_ctx->sig_list = SigInit(de_ctx,
1663
                               "alert udp any any -> any any "
1664
                               "(msg:\"test\"; content:\"boo; sid:238012;)");
1665
    if (de_ctx->sig_list != NULL) {
1666
        result = 0;
1667
        goto end;
1668
    }
1669
1670
 end:
1671
    SigGroupCleanup(de_ctx);
1672
    SigCleanSignatures(de_ctx);
1673
    DetectEngineCtxFree(de_ctx);
1674
1675
    return result;
1676
}
1677
1678
/**
1679
 * \test Parsing test
1680
 */
1681
static int DetectContentParseTest23(void)
1682
{
1683
    DetectEngineCtx *de_ctx = NULL;
1684
    int result = 1;
1685
1686
    de_ctx = DetectEngineCtxInit();
1687
    if (de_ctx == NULL)
1688
        goto end;
1689
1690
    de_ctx->flags |= DE_QUIET;
1691
    de_ctx->sig_list = SigInit(de_ctx,
1692
                               "alert udp any any -> any any "
1693
                               "(msg:\"test\"; content:boo\"; sid:238012;)");
1694
    if (de_ctx->sig_list != NULL) {
1695
        result = 0;
1696
        goto end;
1697
    }
1698
1699
 end:
1700
    SigGroupCleanup(de_ctx);
1701
    SigCleanSignatures(de_ctx);
1702
    DetectEngineCtxFree(de_ctx);
1703
1704
    return result;
1705
}
1706
1707
/**
1708
 * \test Parsing test
1709
 */
1710
static int DetectContentParseTest24(void)
1711
{
1712
    DetectEngineCtx *de_ctx = NULL;
1713
    DetectContentData *cd = 0;
1714
    Signature *s = NULL;
1715
    int result = 1;
1716
1717
    de_ctx = DetectEngineCtxInit();
1718
    if (de_ctx == NULL)
1719
        goto end;
1720
1721
    de_ctx->flags |= DE_QUIET;
1722
    s = de_ctx->sig_list = SigInit(de_ctx,
1723
                                   "alert udp any any -> any any "
1724
                                   "(msg:\"test\"; content:    !\"boo\"; sid:238012;)");
1725
    if (de_ctx->sig_list == NULL) {
1726
        printf("de_ctx->sig_list == NULL: ");
1727
        result = 0;
1728
        goto end;
1729
    }
1730
1731
    if (s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH] == NULL ||
1732
            s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH]->ctx == NULL) {
1733
        printf("de_ctx->pmatch_tail == NULL || de_ctx->pmatch_tail->ctx == NULL: ");
1734
        result = 0;
1735
        goto end;
1736
    }
1737
1738
    cd = (DetectContentData *)s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH]->ctx;
1739
    result = (strncmp("boo", (char *)cd->content, cd->content_len) == 0);
1740
1741
end:
1742
    SigGroupCleanup(de_ctx);
1743
    SigCleanSignatures(de_ctx);
1744
    DetectEngineCtxFree(de_ctx);
1745
1746
    return result;
1747
}
1748
1749
/**
1750
 * \test Parsing test
1751
 */
1752
static int DetectContentParseTest25(void)
1753
{
1754
    DetectEngineCtx *de_ctx = NULL;
1755
    int result = 1;
1756
1757
    de_ctx = DetectEngineCtxInit();
1758
    if (de_ctx == NULL)
1759
        goto end;
1760
1761
    de_ctx->flags |= DE_QUIET;
1762
    de_ctx->sig_list = SigInit(de_ctx,
1763
                               "alert udp any any -> any any "
1764
                               "(msg:\"test\"; content:\"|\"; sid:1;)");
1765
    if (de_ctx->sig_list != NULL) {
1766
        result = 0;
1767
        goto end;
1768
    }
1769
1770
 end:
1771
    SigGroupCleanup(de_ctx);
1772
    SigCleanSignatures(de_ctx);
1773
    DetectEngineCtxFree(de_ctx);
1774
1775
    return result;
1776
}
1777
1778
/**
1779
 * \test Parsing test
1780
 */
1781
static int DetectContentParseTest26(void)
1782
{
1783
    DetectEngineCtx *de_ctx = NULL;
1784
    int result = 1;
1785
1786
    de_ctx = DetectEngineCtxInit();
1787
    if (de_ctx == NULL)
1788
        goto end;
1789
1790
    de_ctx->flags |= DE_QUIET;
1791
    de_ctx->sig_list = SigInit(de_ctx,
1792
                               "alert udp any any -> any any "
1793
                               "(msg:\"test\"; content:\"|af\"; sid:1;)");
1794
    if (de_ctx->sig_list != NULL) {
1795
        result = 0;
1796
        goto end;
1797
    }
1798
1799
 end:
1800
    SigGroupCleanup(de_ctx);
1801
    SigCleanSignatures(de_ctx);
1802
    DetectEngineCtxFree(de_ctx);
1803
1804
    return result;
1805
}
1806
1807
/**
1808
 * \test Parsing test
1809
 */
1810
static int DetectContentParseTest27(void)
1811
{
1812
    DetectEngineCtx *de_ctx = NULL;
1813
    int result = 1;
1814
1815
    de_ctx = DetectEngineCtxInit();
1816
    if (de_ctx == NULL)
1817
        goto end;
1818
1819
    de_ctx->flags |= DE_QUIET;
1820
    de_ctx->sig_list = SigInit(de_ctx,
1821
                               "alert udp any any -> any any "
1822
                               "(msg:\"test\"; content:\"af|\"; sid:1;)");
1823
    if (de_ctx->sig_list != NULL) {
1824
        result = 0;
1825
        goto end;
1826
    }
1827
1828
 end:
1829
    SigGroupCleanup(de_ctx);
1830
    SigCleanSignatures(de_ctx);
1831
    DetectEngineCtxFree(de_ctx);
1832
1833
    return result;
1834
}
1835
1836
/**
1837
 * \test Parsing test
1838
 */
1839
static int DetectContentParseTest28(void)
1840
{
1841
    DetectEngineCtx *de_ctx = NULL;
1842
    int result = 1;
1843
1844
    de_ctx = DetectEngineCtxInit();
1845
    if (de_ctx == NULL)
1846
        goto end;
1847
1848
    de_ctx->flags |= DE_QUIET;
1849
    de_ctx->sig_list = SigInit(de_ctx,
1850
                               "alert udp any any -> any any "
1851
                               "(msg:\"test\"; content:\"|af|\"; sid:1;)");
1852
    if (de_ctx->sig_list == NULL) {
1853
        result = 0;
1854
        goto end;
1855
    }
1856
1857
 end:
1858
    SigGroupCleanup(de_ctx);
1859
    SigCleanSignatures(de_ctx);
1860
    DetectEngineCtxFree(de_ctx);
1861
1862
    return result;
1863
}
1864
1865
/**
1866
 * \test Parsing test
1867
 */
1868
static int DetectContentParseTest29(void)
1869
{
1870
    DetectEngineCtx *de_ctx = NULL;
1871
    int result = 1;
1872
1873
    de_ctx = DetectEngineCtxInit();
1874
    if (de_ctx == NULL)
1875
        goto end;
1876
1877
    de_ctx->flags |= DE_QUIET;
1878
    de_ctx->sig_list = SigInit(de_ctx,
1879
                               "alert udp any any -> any any "
1880
                               "(msg:\"test\"; content:\"aast|\"; sid:1;)");
1881
    if (de_ctx->sig_list != NULL) {
1882
        result = 0;
1883
        goto end;
1884
    }
1885
1886
 end:
1887
    SigGroupCleanup(de_ctx);
1888
    SigCleanSignatures(de_ctx);
1889
    DetectEngineCtxFree(de_ctx);
1890
1891
    return result;
1892
}
1893
1894
/**
1895
 * \test Parsing test
1896
 */
1897
static int DetectContentParseTest30(void)
1898
{
1899
    DetectEngineCtx *de_ctx = NULL;
1900
    int result = 1;
1901
1902
    de_ctx = DetectEngineCtxInit();
1903
    if (de_ctx == NULL)
1904
        goto end;
1905
1906
    de_ctx->flags |= DE_QUIET;
1907
    de_ctx->sig_list = SigInit(de_ctx,
1908
                               "alert udp any any -> any any "
1909
                               "(msg:\"test\"; content:\"aast|af\"; sid:1;)");
1910
    if (de_ctx->sig_list != NULL) {
1911
        result = 0;
1912
        goto end;
1913
    }
1914
1915
 end:
1916
    SigGroupCleanup(de_ctx);
1917
    SigCleanSignatures(de_ctx);
1918
    DetectEngineCtxFree(de_ctx);
1919
1920
    return result;
1921
}
1922
1923
/**
1924
 * \test Parsing test
1925
 */
1926
static int DetectContentParseTest31(void)
1927
{
1928
    DetectEngineCtx *de_ctx = NULL;
1929
    int result = 1;
1930
1931
    de_ctx = DetectEngineCtxInit();
1932
    if (de_ctx == NULL)
1933
        goto end;
1934
1935
    de_ctx->flags |= DE_QUIET;
1936
    de_ctx->sig_list = SigInit(de_ctx,
1937
                               "alert udp any any -> any any "
1938
                               "(msg:\"test\"; content:\"aast|af|\"; sid:1;)");
1939
    if (de_ctx->sig_list == NULL) {
1940
        result = 0;
1941
        goto end;
1942
    }
1943
1944
 end:
1945
    SigGroupCleanup(de_ctx);
1946
    SigCleanSignatures(de_ctx);
1947
    DetectEngineCtxFree(de_ctx);
1948
1949
    return result;
1950
}
1951
1952
/**
1953
 * \test Parsing test
1954
 */
1955
static int DetectContentParseTest32(void)
1956
{
1957
    DetectEngineCtx *de_ctx = NULL;
1958
    int result = 1;
1959
1960
    de_ctx = DetectEngineCtxInit();
1961
    if (de_ctx == NULL)
1962
        goto end;
1963
1964
    de_ctx->flags |= DE_QUIET;
1965
    de_ctx->sig_list = SigInit(de_ctx,
1966
                               "alert udp any any -> any any "
1967
                               "(msg:\"test\"; content:\"|af|asdf\"; sid:1;)");
1968
    if (de_ctx->sig_list == NULL) {
1969
        result = 0;
1970
        goto end;
1971
    }
1972
1973
 end:
1974
    SigGroupCleanup(de_ctx);
1975
    SigCleanSignatures(de_ctx);
1976
    DetectEngineCtxFree(de_ctx);
1977
1978
    return result;
1979
}
1980
1981
/**
1982
 * \test Parsing test
1983
 */
1984
static int DetectContentParseTest33(void)
1985
{
1986
    DetectEngineCtx *de_ctx = NULL;
1987
    int result = 1;
1988
1989
    de_ctx = DetectEngineCtxInit();
1990
    if (de_ctx == NULL)
1991
        goto end;
1992
1993
    de_ctx->flags |= DE_QUIET;
1994
    de_ctx->sig_list = SigInit(de_ctx,
1995
                               "alert udp any any -> any any "
1996
                               "(msg:\"test\"; content:\"|af|af|\"; sid:1;)");
1997
    if (de_ctx->sig_list != NULL) {
1998
        result = 0;
1999
        goto end;
2000
    }
2001
2002
 end:
2003
    SigGroupCleanup(de_ctx);
2004
    SigCleanSignatures(de_ctx);
2005
    DetectEngineCtxFree(de_ctx);
2006
2007
    return result;
2008
}
2009
2010
/**
2011
 * \test Parsing test
2012
 */
2013
static int DetectContentParseTest34(void)
2014
{
2015
    DetectEngineCtx *de_ctx = NULL;
2016
    int result = 1;
2017
2018
    de_ctx = DetectEngineCtxInit();
2019
    if (de_ctx == NULL)
2020
        goto end;
2021
2022
    de_ctx->flags |= DE_QUIET;
2023
    de_ctx->sig_list = SigInit(de_ctx,
2024
                               "alert udp any any -> any any "
2025
                               "(msg:\"test\"; content:\"|af|af|af\"; sid:1;)");
2026
    if (de_ctx->sig_list != NULL) {
2027
        result = 0;
2028
        goto end;
2029
    }
2030
2031
 end:
2032
    SigGroupCleanup(de_ctx);
2033
    SigCleanSignatures(de_ctx);
2034
    DetectEngineCtxFree(de_ctx);
2035
2036
    return result;
2037
}
2038
2039
/**
2040
 * \test Parsing test
2041
 */
2042
static int DetectContentParseTest35(void)
2043
{
2044
    DetectEngineCtx *de_ctx = NULL;
2045
    int result = 1;
2046
2047
    de_ctx = DetectEngineCtxInit();
2048
    if (de_ctx == NULL)
2049
        goto end;
2050
2051
    de_ctx->flags |= DE_QUIET;
2052
    de_ctx->sig_list = SigInit(de_ctx,
2053
                               "alert udp any any -> any any "
2054
                               "(msg:\"test\"; content:\"|af|af|af|\"; sid:1;)");
2055
    if (de_ctx->sig_list == NULL) {
2056
        result = 0;
2057
        goto end;
2058
    }
2059
2060
 end:
2061
    SigGroupCleanup(de_ctx);
2062
    SigCleanSignatures(de_ctx);
2063
    DetectEngineCtxFree(de_ctx);
2064
2065
    return result;
2066
}
2067
2068
static int SigTestPositiveTestContent(const char *rule, uint8_t *buf)
2069
{
2070
    uint16_t buflen = strlen((char *)buf);
2071
    ThreadVars th_v;
2072
    DetectEngineThreadCtx *det_ctx = NULL;
2073
2074
    memset(&th_v, 0, sizeof(th_v));
2075
    Packet *p = UTHBuildPacket(buf, buflen, IPPROTO_TCP);
2076
    FAIL_IF_NULL(p);
2077
2078
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
2079
    FAIL_IF_NULL(de_ctx);
2080
    de_ctx->flags |= DE_QUIET;
2081
2082
    de_ctx->sig_list = SigInit(de_ctx, rule);
2083
    FAIL_IF_NULL(de_ctx->sig_list);
2084
2085
    SigGroupBuild(de_ctx);
2086
    DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
2087
    FAIL_IF_NULL(det_ctx);
2088
2089
    SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
2090
2091
    FAIL_IF(PacketAlertCheck(p, 1) != 1);
2092
2093
    DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
2094
    DetectEngineCtxFree(de_ctx);
2095
2096
    UTHFreePackets(&p, 1);
2097
    PASS;
2098
}
2099
2100
static int DetectContentParseTest41(void)
2101
{
2102
    int result = 1;
2103
    DetectContentData *cd = NULL;
2104
    int patlen = 255;
2105
    char *teststring = SCMalloc(sizeof(char) * (patlen + 1));
2106
    if (unlikely(teststring == NULL))
2107
        return 0;
2108
    int idx = 0;
2109
    for (int i = 0; i < patlen; idx++, i++) {
2110
        teststring[idx] = 'a';
2111
    }
2112
    teststring[idx++] = '\0';
2113
2114
    uint8_t spm_matcher = SinglePatternMatchDefaultMatcher();
2115
    SpmGlobalThreadCtx *spm_global_thread_ctx = SpmInitGlobalThreadCtx(spm_matcher);
2116
    FAIL_IF(spm_global_thread_ctx == NULL);
2117
2118
    cd = DetectContentParse(spm_global_thread_ctx, teststring);
2119
    if (cd == NULL) {
2120
        SCLogDebug("expected not NULL");
2121
        result = 0;
2122
    }
2123
2124
    SpmDestroyGlobalThreadCtx(spm_global_thread_ctx);
2125
    SCFree(teststring);
2126
    DetectContentFree(NULL, cd);
2127
    return result;
2128
}
2129
2130
/**
2131
 * Tests that content lengths > 255 are supported.
2132
 */
2133
static int DetectContentParseTest42(void)
2134
{
2135
    int result = 1;
2136
    DetectContentData *cd = NULL;
2137
    int patlen = 256;
2138
    char *teststring = SCMalloc(sizeof(char) * (patlen + 1));
2139
    if (unlikely(teststring == NULL))
2140
        return 0;
2141
    int idx = 0;
2142
    for (int i = 0; i < patlen; idx++, i++) {
2143
        teststring[idx] = 'a';
2144
    }
2145
    teststring[idx++] = '\0';
2146
2147
    uint8_t spm_matcher = SinglePatternMatchDefaultMatcher();
2148
    SpmGlobalThreadCtx *spm_global_thread_ctx = SpmInitGlobalThreadCtx(spm_matcher);
2149
    FAIL_IF(spm_global_thread_ctx == NULL);
2150
2151
    cd = DetectContentParse(spm_global_thread_ctx, teststring);
2152
    if (cd == NULL) {
2153
        SCLogDebug("expected not NULL");
2154
        result = 0;
2155
    }
2156
2157
    SpmDestroyGlobalThreadCtx(spm_global_thread_ctx);
2158
    SCFree(teststring);
2159
    DetectContentFree(NULL, cd);
2160
    return result;
2161
}
2162
2163
static int DetectContentParseTest43(void)
2164
{
2165
    int result = 1;
2166
    DetectContentData *cd = NULL;
2167
    int patlen = 258;
2168
    char *teststring = SCMalloc(sizeof(char) * (patlen + 1));
2169
    if (unlikely(teststring == NULL))
2170
        return 0;
2171
    int idx = 0;
2172
    teststring[idx++] = '|';
2173
    teststring[idx++] = '4';
2174
    teststring[idx++] = '6';
2175
    teststring[idx++] = '|';
2176
    for (int i = 0; i < (patlen - 4); idx++, i++) {
2177
        teststring[idx] = 'a';
2178
    }
2179
    teststring[idx++] = '\0';
2180
2181
    uint8_t spm_matcher = SinglePatternMatchDefaultMatcher();
2182
    SpmGlobalThreadCtx *spm_global_thread_ctx = SpmInitGlobalThreadCtx(spm_matcher);
2183
    FAIL_IF(spm_global_thread_ctx == NULL);
2184
2185
    cd = DetectContentParse(spm_global_thread_ctx, teststring);
2186
    if (cd == NULL) {
2187
        SCLogDebug("expected not NULL");
2188
        result = 0;
2189
    }
2190
2191
    SpmDestroyGlobalThreadCtx(spm_global_thread_ctx);
2192
    SCFree(teststring);
2193
    DetectContentFree(NULL, cd);
2194
    return result;
2195
}
2196
2197
/**
2198
 * Tests that content lengths > 255 are supported.
2199
 */
2200
static int DetectContentParseTest44(void)
2201
{
2202
    int result = 1;
2203
    DetectContentData *cd = NULL;
2204
    int patlen = 259;
2205
    char *teststring = SCMalloc(sizeof(char) * (patlen + 1));
2206
    if (unlikely(teststring == NULL))
2207
        return 0;
2208
    int idx = 0;
2209
    teststring[idx++] = '|';
2210
    teststring[idx++] = '4';
2211
    teststring[idx++] = '6';
2212
    teststring[idx++] = '|';
2213
    for (int i = 0; i < (patlen - 4); idx++, i++) {
2214
        teststring[idx] = 'a';
2215
    }
2216
    teststring[idx++] = '\0';
2217
2218
    uint8_t spm_matcher = SinglePatternMatchDefaultMatcher();
2219
    SpmGlobalThreadCtx *spm_global_thread_ctx = SpmInitGlobalThreadCtx(spm_matcher);
2220
    FAIL_IF(spm_global_thread_ctx == NULL);
2221
2222
    cd = DetectContentParse(spm_global_thread_ctx, teststring);
2223
    if (cd == NULL) {
2224
        SCLogDebug("expected not NULL");
2225
        result = 0;
2226
    }
2227
2228
    SpmDestroyGlobalThreadCtx(spm_global_thread_ctx);
2229
    SCFree(teststring);
2230
    DetectContentFree(NULL, cd);
2231
    return result;
2232
}
2233
2234
/**
2235
 * \test Parsing test to check for unescaped quote within content section
2236
 */
2237
static int DetectContentParseTest45(void)
2238
{
2239
    DetectEngineCtx *de_ctx = NULL;
2240
2241
    de_ctx = DetectEngineCtxInit();
2242
    FAIL_IF_NULL(de_ctx);
2243
2244
    de_ctx->flags |= DE_QUIET;
2245
    de_ctx->sig_list = SigInit(de_ctx,
2246
                               "alert tcp any any -> any any "
2247
                               "(msg:\"test\"; content:\"|ff|\" content:\"TEST\"; sid:1;)");
2248
    FAIL_IF_NOT_NULL(de_ctx->sig_list);
2249
2250
    DetectEngineCtxFree(de_ctx);
2251
2252
    PASS;
2253
}
2254
2255
static int SigTestNegativeTestContent(const char *rule, uint8_t *buf)
2256
{
2257
    uint16_t buflen = strlen((char *)buf);
2258
    Packet *p = NULL;
2259
    ThreadVars th_v;
2260
    DetectEngineThreadCtx *det_ctx = NULL;
2261
    int result = 0;
2262
    memset(&th_v, 0, sizeof(th_v));
2263
2264
    p = UTHBuildPacket(buf, buflen, IPPROTO_TCP);
2265
2266
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
2267
    if (de_ctx == NULL)
2268
        goto end;
2269
2270
    de_ctx->flags |= DE_QUIET;
2271
2272
    de_ctx->sig_list = SigInit(de_ctx, rule);
2273
    if (de_ctx->sig_list == NULL) {
2274
        goto end;
2275
    }
2276
2277
    SigGroupBuild(de_ctx);
2278
    DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
2279
2280
    SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
2281
    if (PacketAlertCheck(p, 1) != 0) {
2282
        goto end;
2283
    }
2284
2285
    result = 1;
2286
end:
2287
    if (det_ctx != NULL) {
2288
        DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
2289
    }
2290
    if (de_ctx != NULL) {
2291
        SigGroupCleanup(de_ctx);
2292
        SigCleanSignatures(de_ctx);
2293
        DetectEngineCtxFree(de_ctx);
2294
    }
2295
    UTHFreePackets(&p, 1);
2296
    return result;
2297
}
2298
2299
/**
2300
 * \test A positive test that checks that the content string doesn't contain
2301
 *       the negated content
2302
 */
2303
static int SigTest41TestNegatedContent(void)
2304
{
2305
    return SigTestPositiveTestContent("alert tcp any any -> any any "
2306
            "(msg:\"HTTP URI cap\"; content:!\"GES\"; sid:1;)",
2307
2308
            (uint8_t *)"GET /one/ HTTP/1.1\r\n Host: one.example.org\r\n\r\n\r\n"
2309
            "GET /two/ HTTP/1.1\r\nHost: two.example.org\r\n\r\n\r\n");
2310
}
2311
2312
/**
2313
 * \test crash condition: as packet has no direction, it defaults to toclient
2314
 *       in stream ctx inspection of packet. There a null ptr deref happens
2315
 * We don't care about the match/nomatch here.
2316
 */
2317
static int SigTest41aTestNegatedContent(void)
2318
{
2319
    (void)SigTestPositiveTestContent("alert tcp any any -> any any (msg:\"HTTP URI cap\"; flow:to_server; content:\"GET\"; sid:1;)", (uint8_t *)"GET /one/ HTTP/1.1\r\n Host: one.example.org\r\n\r\n\r\nGET /two/ HTTP/1.1\r\nHost: two.example.org\r\n\r\n\r\n");
2320
    return 1;
2321
}
2322
2323
2324
/**
2325
 * \test A positive test that checks that the content string doesn't contain
2326
 *       the negated content within the specified depth
2327
 */
2328
static int SigTest42TestNegatedContent(void)
2329
{
2330
    return SigTestPositiveTestContent(
2331
            "alert tcp any any -> any any (content:!\"eeeeeeeeeee\"; depth:22; offset:35; sid:1;)",
2332
            (uint8_t *)"aaa bbbb cccc dddddddd eeeeeeeeeee ffffffffff gggggggg hhhhhhhh");
2333
}
2334
2335
/**
2336
 * \test A negative test that checks that the content string doesn't contain
2337
 *       the negated content within the specified depth, and also after the
2338
 *       specified offset. Since the content is there, the match fails.
2339
 *
2340
 *       Match is at offset:23, depth:34
2341
 */
2342
static int SigTest43TestNegatedContent(void)
2343
{
2344
    return SigTestNegativeTestContent(
2345
            "alert tcp any any -> any any (content:!\"eeeeeeeeeee\"; depth:34; offset:23; sid:1;)",
2346
            (uint8_t *)"aaa bbbb cccc dddddddd eeeeeeeeeee ffffffffff gggggggg hhhhhhhh");
2347
}
2348
2349
/**
2350
 * \test A negative test that checks that the content string doesn't contain
2351
 *       the negated content after the specified offset and within the specified
2352
 *       depth.
2353
 */
2354
static int SigTest44TestNegatedContent(void)
2355
{
2356
    return SigTestPositiveTestContent(
2357
            "alert tcp any any -> any any (content:!\"eeeeeeeeeee\"; offset:40; depth:35; sid:1;)",
2358
            (uint8_t *)"aaa bbbb cccc dddddddd eeeeeeeeeee ffffffffff gggggggg hhhhhhhh");
2359
}
2360
2361
/**
2362
 * \test A positive test that uses a combination of content string with negated
2363
 *       content string
2364
 */
2365
static int SigTest45TestNegatedContent(void)
2366
{
2367
    return SigTestPositiveTestContent("alert tcp any any -> any any (content:\"aaa\"; depth:5; "
2368
                                      "content:!\"eeeeeeeeeee\"; depth:23; sid:1;)",
2369
            (uint8_t *)"aaa bbbb cccc dddddddd eeeeeeeeeee ffffffffff gggggggg hhhhhhhh");
2370
}
2371
2372
/**
2373
 * \test A negative test that uses a combination of content string with negated
2374
 *       content string, with we receiving a failure for 'onee' itself.
2375
 */
2376
static int SigTest46TestNegatedContent(void)
2377
{
2378
    return SigTestNegativeTestContent("alert tcp any any -> any any (content:\"aaaE\"; "
2379
                                      "content:!\"eeeeeeeeeee\"; depth:23; sid:1;)",
2380
            (uint8_t *)"aaa bbbb cccc dddddddd eeeeeeeeeee ffffffffff gggggggg hhhhhhhh");
2381
}
2382
2383
/**
2384
 * \test A negative test that uses a combination of content string with negated
2385
 *       content string, with we receiving a failure of first content's offset
2386
 *       condition
2387
 */
2388
static int SigTest47TestNegatedContent(void)
2389
{
2390
    return SigTestNegativeTestContent("alert tcp any any -> any any (content:\"aaa\"; offset:5; "
2391
                                      "content:!\"eeeeeeeeeee\"; depth:23; sid:1;)",
2392
            (uint8_t *)"aaa bbbb cccc dddddddd eeeeeeeeeee ffffffffff gggggggg hhhhhhhh");
2393
}
2394
2395
/**
2396
 * \test A positive test that checks that we don't have a negated content within
2397
 *       the specified length from the previous content match.
2398
 */
2399
static int SigTest48TestNegatedContent(void)
2400
{
2401
    return SigTestPositiveTestContent(
2402
            "alert tcp any any -> any any (content:\"GET\"; content:!\"GES\"; within:26; sid:1;)",
2403
            (uint8_t *)"GET /one/ HTTP/1.1\r\n Host: one.example.org\r\n\r\n\r\nGET /two/ "
2404
                       "HTTP/1.1\r\nHost: two.example.org\r\n\r\n\r\n");
2405
}
2406
2407
/**
2408
 * \test A negative test that checks the combined use of content and negated
2409
 *        content with the use of within
2410
 */
2411
static int SigTest49TestNegatedContent(void)
2412
{
2413
    return SigTestNegativeTestContent(
2414
            "alert tcp any any -> any any (content:\"GET\"; content:!\"Host\"; within:26; sid:1;)",
2415
            (uint8_t *)"GET /one/ HTTP/1.1\r\n Host: one.example.org\r\n\r\n\r\nGET /two/ "
2416
                       "HTTP/1.1\r\nHost: two.example.org\r\n\r\n\r\n");
2417
}
2418
2419
/**
2420
 * \test A positive test that checks the combined use of content and negated
2421
 *        content with the use of distance
2422
 */
2423
static int SigTest50TestNegatedContent(void)
2424
{
2425
    return SigTestPositiveTestContent(
2426
            "alert tcp any any -> any any (content:\"GET\"; content:!\"GES\"; distance:25; sid:1;)",
2427
            (uint8_t *)"GET /one/ HTTP/1.1\r\n Host: one.example.org\r\n\r\n\r\nGET /two/ "
2428
                       "HTTP/1.1\r\nHost: two.example.org\r\n\r\n\r\n");
2429
}
2430
2431
/**
2432
 * \test A negative test that checks the combined use of content and negated
2433
 *       content with the use of distance
2434
 *
2435
 * First GET at offset 0
2436
 * First Host at offset 21
2437
 */
2438
static int SigTest51TestNegatedContent(void)
2439
{
2440
    return SigTestNegativeTestContent("alert tcp any any -> any any (content:\"GET\"; content:!\"Host\"; distance:17; sid:1;)", (uint8_t *)"GET /one/ HTTP/1.1\r\nHost: one.example.org\r\n\r\n\r\nGET /two/ HTTP/1.1\r\nHost: two.example.org\r\n\r\n\r\n");
2441
}
2442
2443
/**
2444
 * \test A negative test that checks the combined use of content and negated
2445
 *       content, with the content not being present
2446
 */
2447
static int SigTest52TestNegatedContent(void)
2448
{
2449
    return SigTestNegativeTestContent(
2450
            "alert tcp any any -> any any (content:\"GES\"; content:!\"BOO\"; sid:1;)",
2451
            (uint8_t *)"GET /one/ HTTP/1.1\r\n Host: one.example.org\r\n\r\n\r\nGET /two/ "
2452
                       "HTTP/1.1\r\nHost: two.example.org\r\n\r\n\r\n");
2453
}
2454
2455
/**
2456
 * \test A negative test that checks the combined use of content and negated
2457
 *       content, in the presence of within
2458
 */
2459
static int SigTest53TestNegatedContent(void)
2460
{
2461
    return SigTestNegativeTestContent(
2462
            "alert tcp any any -> any any (content:\"aaa\"; content:!\"Ggggg\"; within:56; sid:1;)",
2463
            (uint8_t *)"aaa bbbb cccc dddddddd eeeeeeeeeee ffffffffff Ggggggggg hhhhhhhh");
2464
}
2465
2466
/**
2467
 * \test A positive test that checks the combined use of content and negated
2468
 *       content, in the presence of within
2469
 */
2470
static int SigTest54TestNegatedContent(void)
2471
{
2472
    return SigTestPositiveTestContent("alert tcp any any -> any any (content:\"aaa\"; "
2473
                                      "content:!\"gggggg\"; within:20; sid:1;)",
2474
            (uint8_t *)"aaa bbbb cccc dddddddd eeeeeeeeeee ffffffffff ggggggggg hhhhhhhh");
2475
}
2476
2477
/**
2478
 * \test A negative test that checks the use of negated content along with
2479
 *       the presence of depth
2480
 */
2481
static int SigTest55TestNegatedContent(void)
2482
{
2483
    return SigTestNegativeTestContent(
2484
            "alert tcp any any -> any any (content:!\"aaa\"; depth:5; sid:1;)",
2485
            (uint8_t *)"aaa bbbb cccc dddddddd eeeeeeeeeee ffffffffff gggggggg hhhhhhhh");
2486
}
2487
2488
/**
2489
 * \test A positive test that checks the combined use of 2 contents in the
2490
 *       presence of within
2491
 */
2492
static int SigTest56TestNegatedContent(void)
2493
{
2494
    return SigTestPositiveTestContent(
2495
            "alert tcp any any -> any any (content:\"aaa\"; content:\"Ggggg\"; within:56; sid:1;)",
2496
            (uint8_t *)"aaa bbbb cccc dddddddd eeeeeeeeeee ffffffffff Gggggggg hhhhhhhh");
2497
}
2498
2499
/**
2500
 * \test A negative test that checks the combined use of content and negated
2501
 *       content, in the presence of within
2502
 */
2503
static int SigTest57TestNegatedContent(void)
2504
{
2505
    return SigTestNegativeTestContent(
2506
            "alert tcp any any -> any any (content:\"aaa\"; content:!\"Ggggg\"; within:56; sid:1;)",
2507
            (uint8_t *)"aaa bbbb cccc dddddddd eeeeeeeeeee ffffffffff Ggggggggg hhhhhhhh");
2508
}
2509
2510
/**
2511
 * \test A positive test that checks the combined use of content and negated
2512
 *       content, in the presence of distance
2513
 */
2514
static int SigTest58TestNegatedContent(void)
2515
{
2516
    return SigTestPositiveTestContent("alert tcp any any -> any any (content:\"aaa\"; "
2517
                                      "content:!\"Ggggg\"; distance:57; sid:1;)",
2518
            (uint8_t *)"aaa bbbb cccc dddddddd eeeeeeeeeee ffffffffff Ggggggggg hhhhhhhh");
2519
}
2520
2521
/**
2522
 * \test A negative test that checks the combined use of content and negated
2523
 *       content, in the presence of distance
2524
 */
2525
static int SigTest59TestNegatedContent(void)
2526
{
2527
    return SigTestNegativeTestContent("alert tcp any any -> any any (content:\"aaa\"; "
2528
                                      "content:!\"Gggg\"; distance:30; sid:1;)",
2529
            (uint8_t *)"aaa bbbb cccc dddddddd eeeeeeeeeee ffffffffff Ggggggggg hhhhhhhh");
2530
}
2531
2532
static int SigTest60TestNegatedContent(void)
2533
{
2534
    return SigTestNegativeTestContent(
2535
            "alert tcp any any -> any any (content:!\"aaa\"; content:\"Ggggg\"; sid:1;)",
2536
            (uint8_t *)"aaa bbbb cccc dddddddd eeeeeeeeeee ffffffffff Ggggggggg hhhhhhhh");
2537
}
2538
2539
static int SigTest61TestNegatedContent(void)
2540
{
2541
    return SigTestPositiveTestContent("alert tcp any any -> any any (content:\"aaa\"; depth:10; "
2542
                                      "content:!\"Ggggg\"; within:30; sid:1;)",
2543
            (uint8_t *)"aaa bbbb cccc dddddddd eeeeeeeeeee ffffffffff Ggggggggg hhhhhhhh");
2544
}
2545
2546
/** \test Test negation in combination with within and depth
2547
 *
2548
 *  Match of "aaa" at offset:0, depth:3
2549
 *  Match of "Gggggg" at offset:46, depth:52
2550
 *
2551
 *  This signature should not match for the test to pass.
2552
 */
2553
static int SigTest62TestNegatedContent(void)
2554
{
2555
    return SigTestNegativeTestContent("alert tcp any any -> any any (content:\"aaa\"; depth:10; "
2556
                                      "content:!\"Gggggg\"; within:49; sid:1;)",
2557
            (uint8_t *)"aaa bbbb cccc dddddddd eeeeeeeeeee ffffffffff Ggggggggg hhhhhhhh");
2558
}
2559
2560
static int SigTest63TestNegatedContent(void)
2561
{
2562
    return SigTestNegativeTestContent("alert tcp any any -> any any (content:\"aaa\"; depth:10; "
2563
                                      "content:!\"Gggggg\"; within:56; sid:1;)",
2564
            (uint8_t *)"aaa bbbb cccc dddddddd eeeeeeeeeee ffffffffff Ggggggggg hhhhhhhh");
2565
}
2566
2567
static int SigTest64TestNegatedContent(void)
2568
{
2569
    return SigTestPositiveTestContent("alert tcp any any -> any any (content:\"aaa\"; depth:10; "
2570
                                      "content:!\"Gggggg\"; within:30; sid:1;)",
2571
            (uint8_t *)"aaa bbbb cccc dddddddd eeeeeeeeeee ffffffffff Ggggggggg hhhhhhhh");
2572
}
2573
2574
/** \test Test negation in combination with within and depth
2575
 *
2576
 *  Match of "aaa" at offset:0, depth:3
2577
 *  Match of "gggggg" at offset:46, depth:52
2578
 *
2579
 *  This signature should not match for the test to pass.
2580
 */
2581
static int SigTest65TestNegatedContent(void)
2582
{
2583
    return SigTestNegativeTestContent("alert tcp any any -> any any (content:\"aaa\"; depth:10; "
2584
                                      "content:!\"Gggggg\"; distance:0; within:49; sid:1;)",
2585
            (uint8_t *)"aaa bbbb cccc dddddddd eeeeeeeeeee ffffffffff Ggggggggg hhhhhhhh");
2586
}
2587
2588
static int SigTest66TestNegatedContent(void)
2589
{
2590
    return SigTestPositiveTestContent("alert tcp any any -> any any (content:\"aaa\"; depth:10; "
2591
                                      "content:!\"Gggggg\"; within:30; sid:1;)",
2592
            (uint8_t *)"aaa bbbb cccc dddddddd eeeeeeeeeee ffffffffff Ggggggggg hhhhhhhh");
2593
}
2594
2595
static int SigTest67TestNegatedContent(void)
2596
{
2597
    return SigTestNegativeTestContent("alert tcp any any -> any any (content:\"aaa\"; depth:10; "
2598
                                      "content:!\"XXXX\"; within:56; sid:1;)",
2599
            (uint8_t *)"aaa bbbb cccc XXXXdddd eeeeeeeeeee ffffffffff XXXXggggg hhhhhhhh");
2600
}
2601
2602
static int SigTest68TestNegatedContent(void)
2603
{
2604
    return SigTestPositiveTestContent(
2605
            "alert tcp any any -> any any (content:\"aaa\"; depth:10; content:\"cccc\"; offset:8; "
2606
            "content:!\"Gggggg\"; within:28; content:\"hhhhhhhh\"; sid:1;)",
2607
            (uint8_t *)"aaa bbbb cccc dddddddd eeeeeeeeeee ffffffffff Ggggggggg hhhhhhhh");
2608
}
2609
2610
static int SigTest69TestNegatedContent(void)
2611
{
2612
    return SigTestNegativeTestContent(
2613
            "alert tcp any any -> any any (content:\"aaa\"; depth:10; content:\"cccc\"; offset:8; "
2614
            "content:!\"Gggggg\"; within:48; content:\"hhhhhhhh\"; sid:1;)",
2615
            (uint8_t *)"aaa bbbb cccc dddddddd eeeeeeeeeee ffffffffff Ggggggggg hhhhhhhh");
2616
}
2617
2618
static int SigTest70TestNegatedContent(void)
2619
{
2620
    return SigTestNegativeTestContent("alert tcp any any -> any any (content:\"aaa\"; "
2621
                                      "content:!\"Gggggg\"; within:52; sid:1;)",
2622
            (uint8_t *)"aaa bbbb cccc dddddddd eeeeeeeeeee ffffffffff Ggggggggg hhhhhhhh");
2623
}
2624
2625
/** \test within and distance */
2626
static int SigTest71TestNegatedContent(void)
2627
{
2628
    return SigTestNegativeTestContent("alert tcp any any -> any any (content:\"aaa\"; "
2629
                                      "content:!\"Gggggg\"; within:40; distance:43; sid:1;)",
2630
            (uint8_t *)"aaa bbbb cccc dddddddd eeeeeeeeeee ffffffffff Ggggggggg hhhhhhhh");
2631
}
2632
2633
static int SigTest72TestNegatedContent(void)
2634
{
2635
    return SigTestNegativeTestContent("alert tcp any any -> any any (content:\"aaa\"; "
2636
                                      "content:!\"Gggggg\"; within:49; distance:43; sid:1;)",
2637
            (uint8_t *)"aaa bbbb cccc dddddddd eeeeeeeeeee ffffffffff Ggggggggg hhhhhhhh");
2638
}
2639
2640
static int SigTest73TestNegatedContent(void)
2641
{
2642
    return SigTestNegativeTestContent("alert tcp any any -> any any (content:\"aaa\"; depth:5; "
2643
                                      "content:!\"eeeeeeeeeee\"; depth:35; sid:1;)",
2644
            (uint8_t *)"aaa bbbb cccc dddddddd eeeeeeeeeee ffffffffff ggggggggg hhhhhhhh");
2645
}
2646
2647
static int SigTest74TestNegatedContent(void)
2648
{
2649
    return SigTestPositiveTestContent("alert tcp any any -> any any (msg:\"HTTP URI cap\"; content:\"USER\"; content:!\"PASS\"; sid:1;)",  (uint8_t *)"USER apple");
2650
}
2651
2652
static int SigTest75TestNegatedContent(void)
2653
{
2654
    return SigTestPositiveTestContent("alert tcp any any -> any any (msg:\"HTTP URI cap\"; content:\"USER\"; content:\"!PASS\"; sid:1;)",  (uint8_t *)"USER !PASS");
2655
}
2656
2657
static int SigTest76TestBug134(void)
2658
{
2659
    uint8_t *buf = (uint8_t *)"test detect ${IFS} in traffic";
2660
    uint16_t buflen = strlen((char *)buf);
2661
    Packet *p = UTHBuildPacket( buf, buflen, IPPROTO_TCP);
2662
    int result = 0;
2663
    Flow f;
2664
2665
    memset(&f, 0, sizeof(Flow));
2666
    FLOW_INITIALIZE(&f);
2667
2668
    p->dp = 515;
2669
    p->flowflags |= FLOW_PKT_ESTABLISHED;
2670
    p->flowflags |= FLOW_PKT_TOSERVER;
2671
    p->flow = &f;
2672
    p->flags |= PKT_HAS_FLOW;
2673
2674
    char sig[] = "alert tcp any any -> any 515 "
2675
            "(msg:\"detect IFS\"; flow:to_server,established; content:\"${IFS}\";"
2676
            " depth:50; offset:0; sid:900091; rev:1;)";
2677
    if (UTHPacketMatchSigMpm(p, sig, MPM_AC) == 0) {
2678
        result = 0;
2679
        goto end;
2680
    }
2681
2682
    result = 1;
2683
end:
2684
    if (p != NULL)
2685
        UTHFreePacket(p);
2686
2687
    FLOW_DESTROY(&f);
2688
    return result;
2689
}
2690
2691
static int SigTest77TestBug139(void)
2692
{
2693
    uint8_t buf[] = {
2694
        0x12, 0x23, 0x34, 0x35, 0x52, 0x52, 0x24, 0x42, 0x22, 0x24,
2695
        0x52, 0x24, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x34 };
2696
    uint16_t buflen = sizeof(buf);
2697
    Packet *p = UTHBuildPacket( buf, buflen, IPPROTO_UDP);
2698
    int result = 0;
2699
2700
    p->dp = 53;
2701
    char sig[] = "alert udp any any -> any 53 (msg:\"dns testing\";"
2702
                    " content:\"|00 00|\"; depth:5; offset:13; sid:9436601;"
2703
                    " rev:1;)";
2704
    if (UTHPacketMatchSigMpm(p, sig, MPM_AC) == 0) {
2705
        result = 0;
2706
        goto end;
2707
    }
2708
2709
    result = 1;
2710
end:
2711
    if (p != NULL)
2712
        UTHFreePacket(p);
2713
    return result;
2714
}
2715
2716
static int DetectLongContentTestCommon(const char *sig, uint32_t sid)
2717
{
2718
    /* Packet with 512 A's in it for testing long content. */
2719
    static uint8_t pkt[739] = {
2720
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2721
        0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x45, 0x00,
2722
        0x02, 0xd5, 0x4a, 0x18, 0x40, 0x00, 0x40, 0x06,
2723
        0xd7, 0xd6, 0x0a, 0x10, 0x01, 0x0b, 0x0a, 0x10,
2724
        0x01, 0x0a, 0xdb, 0x36, 0x00, 0x50, 0xca, 0xc5,
2725
        0xcc, 0xd1, 0x95, 0x77, 0x0f, 0x7d, 0x80, 0x18,
2726
        0x00, 0xe5, 0x77, 0x9d, 0x00, 0x00, 0x01, 0x01,
2727
        0x08, 0x0a, 0x1d, 0xe0, 0x86, 0xc6, 0xfc, 0x73,
2728
        0x49, 0xf3, 0x50, 0x4f, 0x53, 0x54, 0x20, 0x2f,
2729
        0x20, 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e,
2730
        0x31, 0x0d, 0x0a, 0x55, 0x73, 0x65, 0x72, 0x2d,
2731
        0x41, 0x67, 0x65, 0x6e, 0x74, 0x3a, 0x20, 0x63,
2732
        0x75, 0x72, 0x6c, 0x2f, 0x37, 0x2e, 0x33, 0x37,
2733
        0x2e, 0x30, 0x0d, 0x0a, 0x48, 0x6f, 0x73, 0x74,
2734
        0x3a, 0x20, 0x31, 0x30, 0x2e, 0x31, 0x36, 0x2e,
2735
        0x31, 0x2e, 0x31, 0x30, 0x0d, 0x0a, 0x41, 0x63,
2736
        0x63, 0x65, 0x70, 0x74, 0x3a, 0x20, 0x2a, 0x2f,
2737
        0x2a, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, 0x74, 0x65,
2738
        0x6e, 0x74, 0x2d, 0x4c, 0x65, 0x6e, 0x67, 0x74,
2739
        0x68, 0x3a, 0x20, 0x35, 0x32, 0x38, 0x0d, 0x0a,
2740
        0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d,
2741
        0x54, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x61, 0x70,
2742
        0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f,
2743
        0x6e, 0x2f, 0x78, 0x2d, 0x77, 0x77, 0x77, 0x2d,
2744
        0x66, 0x6f, 0x72, 0x6d, 0x2d, 0x75, 0x72, 0x6c,
2745
        0x65, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x64, 0x0d,
2746
        0x0a, 0x0d, 0x0a, 0x58, 0x58, 0x58, 0x58, 0x58,
2747
        0x58, 0x58, 0x58, 0x41, 0x41, 0x41, 0x41, 0x41,
2748
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2749
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2750
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2751
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2752
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2753
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2754
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2755
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2756
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2757
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2758
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2759
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2760
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2761
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2762
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2763
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2764
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2765
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2766
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2767
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2768
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2769
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2770
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2771
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2772
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2773
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2774
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2775
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2776
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2777
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2778
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2779
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2780
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2781
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2782
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2783
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2784
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2785
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2786
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2787
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2788
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2789
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2790
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2791
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2792
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2793
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2794
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2795
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2796
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2797
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2798
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2799
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2800
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2801
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2802
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2803
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2804
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2805
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2806
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2807
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2808
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2809
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2810
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2811
        0x41, 0x41, 0x41, 0x58, 0x58, 0x58, 0x58, 0x58,
2812
        0x58, 0x58, 0x58
2813
    };
2814
2815
    return DetectContentLongPatternMatchTest(pkt, (uint16_t)sizeof(pkt), sig,
2816
        sid);
2817
}
2818
2819
static int DetectLongContentTest1(void)
2820
{
2821
    /* Signature with 256 A's. */
2822
    const char *sig = "alert tcp any any -> any any (msg:\"Test Rule\"; content:\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\"; sid:1;)";
2823
2824
    return DetectLongContentTestCommon(sig, 1);
2825
}
2826
2827
static int DetectLongContentTest2(void)
2828
{
2829
    /* Signature with 512 A's. */
2830
    const char *sig = "alert tcp any any -> any any (msg:\"Test Rule\"; content:\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\"; sid:1;)";
2831
2832
    return DetectLongContentTestCommon(sig, 1);
2833
}
2834
2835
static int DetectLongContentTest3(void)
2836
{
2837
    /* Signature with 513 A's. */
2838
    const char *sig = "alert tcp any any -> any any (msg:\"Test Rule\"; content:\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\"; sid:1;)";
2839
2840
    return !DetectLongContentTestCommon(sig, 1);
2841
}
2842
2843
static int DetectBadBinContent(void)
2844
{
2845
    DetectEngineCtx *de_ctx = NULL;
2846
    de_ctx = DetectEngineCtxInit();
2847
    FAIL_IF_NULL(de_ctx);
2848
    de_ctx->flags |= DE_QUIET;
2849
    FAIL_IF_NOT_NULL(DetectEngineAppendSig(
2850
            de_ctx, "alert tcp any any -> any any (msg:\"test\"; content:\"|a|\"; sid:1;)"));
2851
    FAIL_IF_NOT_NULL(DetectEngineAppendSig(
2852
            de_ctx, "alert tcp any any -> any any (msg:\"test\"; content:\"|aa b|\"; sid:1;)"));
2853
    FAIL_IF_NOT_NULL(DetectEngineAppendSig(
2854
            de_ctx, "alert tcp any any -> any any (msg:\"test\"; content:\"|aa bz|\"; sid:1;)"));
2855
    /* https://redmine.openinfosecfoundation.org/issues/5201 */
2856
    FAIL_IF_NOT_NULL(DetectEngineAppendSig(
2857
            de_ctx, "alert tcp any any -> any any (msg:\"test\"; content:\"|22 2 22|\"; sid:1;)"));
2858
    DetectEngineCtxFree(de_ctx);
2859
    PASS;
2860
}
2861
2862
/**
2863
 * \brief this function registers unit tests for DetectContent
2864
 */
2865
static void DetectContentRegisterTests(void)
2866
{
2867
    g_file_data_buffer_id = DetectBufferTypeGetByName("file_data");
2868
    g_dce_stub_data_buffer_id = DetectBufferTypeGetByName("dce_stub_data");
2869
2870
    UtRegisterTest("DetectContentDepthTest01", DetectContentDepthTest01);
2871
2872
    UtRegisterTest("DetectContentParseTest01", DetectContentParseTest01);
2873
    UtRegisterTest("DetectContentParseTest02", DetectContentParseTest02);
2874
    UtRegisterTest("DetectContentParseTest03", DetectContentParseTest03);
2875
    UtRegisterTest("DetectContentParseTest04", DetectContentParseTest04);
2876
    UtRegisterTest("DetectContentParseTest05", DetectContentParseTest05);
2877
    UtRegisterTest("DetectContentParseTest06", DetectContentParseTest06);
2878
    UtRegisterTest("DetectContentParseTest07", DetectContentParseTest07);
2879
    UtRegisterTest("DetectContentParseTest08", DetectContentParseTest08);
2880
    UtRegisterTest("DetectContentParseTest09", DetectContentParseTest09);
2881
    UtRegisterTest("DetectContentParseTest17", DetectContentParseTest17);
2882
    UtRegisterTest("DetectContentParseTest18", DetectContentParseTest18);
2883
    UtRegisterTest("DetectContentParseTest19", DetectContentParseTest19);
2884
    UtRegisterTest("DetectContentParseTest20", DetectContentParseTest20);
2885
    UtRegisterTest("DetectContentParseTest21", DetectContentParseTest21);
2886
    UtRegisterTest("DetectContentParseTest22", DetectContentParseTest22);
2887
    UtRegisterTest("DetectContentParseTest23", DetectContentParseTest23);
2888
    UtRegisterTest("DetectContentParseTest24", DetectContentParseTest24);
2889
    UtRegisterTest("DetectContentParseTest25", DetectContentParseTest25);
2890
    UtRegisterTest("DetectContentParseTest26", DetectContentParseTest26);
2891
    UtRegisterTest("DetectContentParseTest27", DetectContentParseTest27);
2892
    UtRegisterTest("DetectContentParseTest28", DetectContentParseTest28);
2893
    UtRegisterTest("DetectContentParseTest29", DetectContentParseTest29);
2894
    UtRegisterTest("DetectContentParseTest30", DetectContentParseTest30);
2895
    UtRegisterTest("DetectContentParseTest31", DetectContentParseTest31);
2896
    UtRegisterTest("DetectContentParseTest32", DetectContentParseTest32);
2897
    UtRegisterTest("DetectContentParseTest33", DetectContentParseTest33);
2898
    UtRegisterTest("DetectContentParseTest34", DetectContentParseTest34);
2899
    UtRegisterTest("DetectContentParseTest35", DetectContentParseTest35);
2900
    UtRegisterTest("DetectContentParseTest41", DetectContentParseTest41);
2901
    UtRegisterTest("DetectContentParseTest42", DetectContentParseTest42);
2902
    UtRegisterTest("DetectContentParseTest43", DetectContentParseTest43);
2903
    UtRegisterTest("DetectContentParseTest44", DetectContentParseTest44);
2904
    UtRegisterTest("DetectContentParseTest45", DetectContentParseTest45);
2905
2906
    /* The reals */
2907
    UtRegisterTest("DetectContentLongPatternMatchTest01",
2908
                   DetectContentLongPatternMatchTest01);
2909
    UtRegisterTest("DetectContentLongPatternMatchTest02",
2910
                   DetectContentLongPatternMatchTest02);
2911
    UtRegisterTest("DetectContentLongPatternMatchTest03",
2912
                   DetectContentLongPatternMatchTest03);
2913
    UtRegisterTest("DetectContentLongPatternMatchTest04",
2914
                   DetectContentLongPatternMatchTest04);
2915
    UtRegisterTest("DetectContentLongPatternMatchTest05",
2916
                   DetectContentLongPatternMatchTest05);
2917
    UtRegisterTest("DetectContentLongPatternMatchTest06",
2918
                   DetectContentLongPatternMatchTest06);
2919
    UtRegisterTest("DetectContentLongPatternMatchTest07",
2920
                   DetectContentLongPatternMatchTest07);
2921
    UtRegisterTest("DetectContentLongPatternMatchTest08",
2922
                   DetectContentLongPatternMatchTest08);
2923
    UtRegisterTest("DetectContentLongPatternMatchTest09",
2924
                   DetectContentLongPatternMatchTest09);
2925
    UtRegisterTest("DetectContentLongPatternMatchTest10",
2926
                   DetectContentLongPatternMatchTest10);
2927
    UtRegisterTest("DetectContentLongPatternMatchTest11",
2928
                   DetectContentLongPatternMatchTest11);
2929
2930
    /* Negated content tests */
2931
    UtRegisterTest("SigTest41TestNegatedContent", SigTest41TestNegatedContent);
2932
    UtRegisterTest("SigTest41aTestNegatedContent",
2933
                   SigTest41aTestNegatedContent);
2934
    UtRegisterTest("SigTest42TestNegatedContent", SigTest42TestNegatedContent);
2935
    UtRegisterTest("SigTest43TestNegatedContent", SigTest43TestNegatedContent);
2936
    UtRegisterTest("SigTest44TestNegatedContent", SigTest44TestNegatedContent);
2937
    UtRegisterTest("SigTest45TestNegatedContent", SigTest45TestNegatedContent);
2938
    UtRegisterTest("SigTest46TestNegatedContent", SigTest46TestNegatedContent);
2939
    UtRegisterTest("SigTest47TestNegatedContent", SigTest47TestNegatedContent);
2940
    UtRegisterTest("SigTest48TestNegatedContent", SigTest48TestNegatedContent);
2941
    UtRegisterTest("SigTest49TestNegatedContent", SigTest49TestNegatedContent);
2942
    UtRegisterTest("SigTest50TestNegatedContent", SigTest50TestNegatedContent);
2943
    UtRegisterTest("SigTest51TestNegatedContent", SigTest51TestNegatedContent);
2944
    UtRegisterTest("SigTest52TestNegatedContent", SigTest52TestNegatedContent);
2945
    UtRegisterTest("SigTest53TestNegatedContent", SigTest53TestNegatedContent);
2946
    UtRegisterTest("SigTest54TestNegatedContent", SigTest54TestNegatedContent);
2947
    UtRegisterTest("SigTest55TestNegatedContent", SigTest55TestNegatedContent);
2948
    UtRegisterTest("SigTest56TestNegatedContent", SigTest56TestNegatedContent);
2949
    UtRegisterTest("SigTest57TestNegatedContent", SigTest57TestNegatedContent);
2950
    UtRegisterTest("SigTest58TestNegatedContent", SigTest58TestNegatedContent);
2951
    UtRegisterTest("SigTest59TestNegatedContent", SigTest59TestNegatedContent);
2952
    UtRegisterTest("SigTest60TestNegatedContent", SigTest60TestNegatedContent);
2953
    UtRegisterTest("SigTest61TestNegatedContent", SigTest61TestNegatedContent);
2954
    UtRegisterTest("SigTest62TestNegatedContent", SigTest62TestNegatedContent);
2955
    UtRegisterTest("SigTest63TestNegatedContent", SigTest63TestNegatedContent);
2956
    UtRegisterTest("SigTest64TestNegatedContent", SigTest64TestNegatedContent);
2957
    UtRegisterTest("SigTest65TestNegatedContent", SigTest65TestNegatedContent);
2958
    UtRegisterTest("SigTest66TestNegatedContent", SigTest66TestNegatedContent);
2959
    UtRegisterTest("SigTest67TestNegatedContent", SigTest67TestNegatedContent);
2960
    UtRegisterTest("SigTest68TestNegatedContent", SigTest68TestNegatedContent);
2961
    UtRegisterTest("SigTest69TestNegatedContent", SigTest69TestNegatedContent);
2962
    UtRegisterTest("SigTest70TestNegatedContent", SigTest70TestNegatedContent);
2963
    UtRegisterTest("SigTest71TestNegatedContent", SigTest71TestNegatedContent);
2964
    UtRegisterTest("SigTest72TestNegatedContent", SigTest72TestNegatedContent);
2965
    UtRegisterTest("SigTest73TestNegatedContent", SigTest73TestNegatedContent);
2966
    UtRegisterTest("SigTest74TestNegatedContent", SigTest74TestNegatedContent);
2967
    UtRegisterTest("SigTest75TestNegatedContent", SigTest75TestNegatedContent);
2968
2969
    UtRegisterTest("SigTest76TestBug134", SigTest76TestBug134);
2970
    UtRegisterTest("SigTest77TestBug139", SigTest77TestBug139);
2971
2972
    UtRegisterTest("DetectLongContentTest1", DetectLongContentTest1);
2973
    UtRegisterTest("DetectLongContentTest2", DetectLongContentTest2);
2974
    UtRegisterTest("DetectLongContentTest3", DetectLongContentTest3);
2975
2976
    UtRegisterTest("DetectBadBinContent", DetectBadBinContent);
2977
}
2978
#endif /* UNITTESTS */