Coverage Report

Created: 2025-12-31 06:43

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/suricata7/src/detect-pcre.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
 * Implements the pcre keyword
24
 */
25
26
#include "suricata-common.h"
27
#include "decode.h"
28
#include "detect.h"
29
30
#include "pkt-var.h"
31
#include "flow-var.h"
32
#include "flow-util.h"
33
34
#include "detect-pcre.h"
35
#include "detect-flowvar.h"
36
37
#include "detect-parse.h"
38
#include "detect-content.h"
39
#include "detect-engine.h"
40
#include "detect-engine-sigorder.h"
41
#include "detect-engine-mpm.h"
42
#include "detect-engine-state.h"
43
#include "detect-engine-build.h"
44
45
#include "util-var-name.h"
46
#include "util-unittest-helper.h"
47
#include "util-debug.h"
48
#include "util-unittest.h"
49
#include "util-print.h"
50
#include "util-pool.h"
51
52
#include "conf.h"
53
#include "app-layer.h"
54
#include "app-layer-htp.h"
55
#include "stream.h"
56
#include "stream-tcp.h"
57
#include "stream-tcp-private.h"
58
#include "stream-tcp-reassemble.h"
59
#include "app-layer-protos.h"
60
#include "app-layer-parser.h"
61
#include "util-pages.h"
62
63
/* pcre named substring capture supports only 32byte names, A-z0-9 plus _
64
 * and needs to start with non-numeric. */
65
34
#define PARSE_CAPTURE_REGEX "\\(\\?P\\<([A-z]+)\\_([A-z0-9_]+)\\>"
66
34
#define PARSE_REGEX         "(?<!\\\\)/(.*(?<!(?<!\\\\)\\\\))/([^\"]*)"
67
68
static int pcre_match_limit = 0;
69
static int pcre_match_limit_recursion = 0;
70
71
static DetectParseRegex *parse_regex;
72
static DetectParseRegex *parse_capture_regex;
73
74
#ifdef PCRE2_HAVE_JIT
75
static int pcre2_use_jit = 1;
76
#endif
77
78
// TODOpcre2 pcre2_jit_stack_create ?
79
80
/* \brief Helper function for using pcre2_match with/without JIT
81
 */
82
static inline int DetectPcreExec(DetectEngineThreadCtx *det_ctx, DetectPcreData *pd,
83
        const char *str, const size_t strlen, int start_offset, int options,
84
        pcre2_match_data *match)
85
410k
{
86
410k
    return pcre2_match(pd->parse_regex.regex, (PCRE2_SPTR8)str, strlen, start_offset, options,
87
410k
            match, pd->parse_regex.context);
88
410k
}
89
90
static int DetectPcreSetup (DetectEngineCtx *, Signature *, const char *);
91
static void DetectPcreFree(DetectEngineCtx *, void *);
92
#ifdef UNITTESTS
93
static void DetectPcreRegisterTests(void);
94
#endif
95
96
void DetectPcreRegister (void)
97
34
{
98
34
    sigmatch_table[DETECT_PCRE].name = "pcre";
99
34
    sigmatch_table[DETECT_PCRE].desc = "match on regular expression";
100
34
    sigmatch_table[DETECT_PCRE].url = "/rules/payload-keywords.html#pcre-perl-compatible-regular-expressions";
101
34
    sigmatch_table[DETECT_PCRE].Match = NULL;
102
34
    sigmatch_table[DETECT_PCRE].Setup = DetectPcreSetup;
103
34
    sigmatch_table[DETECT_PCRE].Free  = DetectPcreFree;
104
#ifdef UNITTESTS
105
    sigmatch_table[DETECT_PCRE].RegisterTests  = DetectPcreRegisterTests;
106
#endif
107
34
    sigmatch_table[DETECT_PCRE].flags = (SIGMATCH_QUOTES_OPTIONAL|SIGMATCH_HANDLE_NEGATION);
108
109
34
    intmax_t val = 0;
110
111
34
    if (!ConfGetInt("pcre.match-limit", &val)) {
112
34
        pcre_match_limit = SC_MATCH_LIMIT_DEFAULT;
113
34
        SCLogDebug("Using PCRE match-limit setting of: %i", pcre_match_limit);
114
34
    }
115
0
    else    {
116
0
        pcre_match_limit = val;
117
0
        if (pcre_match_limit != SC_MATCH_LIMIT_DEFAULT) {
118
0
            SCLogInfo("Using PCRE match-limit setting of: %i", pcre_match_limit);
119
0
        } else {
120
0
            SCLogDebug("Using PCRE match-limit setting of: %i", pcre_match_limit);
121
0
        }
122
0
    }
123
124
34
    val = 0;
125
126
34
    if (!ConfGetInt("pcre.match-limit-recursion", &val)) {
127
34
        pcre_match_limit_recursion = SC_MATCH_LIMIT_RECURSION_DEFAULT;
128
34
        SCLogDebug("Using PCRE match-limit-recursion setting of: %i", pcre_match_limit_recursion);
129
34
    }
130
0
    else    {
131
0
        pcre_match_limit_recursion = val;
132
0
        if (pcre_match_limit_recursion != SC_MATCH_LIMIT_RECURSION_DEFAULT) {
133
0
            SCLogInfo("Using PCRE match-limit-recursion setting of: %i", pcre_match_limit_recursion);
134
0
        } else {
135
0
            SCLogDebug("Using PCRE match-limit-recursion setting of: %i", pcre_match_limit_recursion);
136
0
        }
137
0
    }
138
139
34
    parse_regex = DetectSetupPCRE2(PARSE_REGEX, 0);
140
34
    if (parse_regex == NULL) {
141
0
        FatalError("pcre2 compile failed for parse_regex");
142
0
    }
143
144
    /* setup the capture regex, as it needs PCRE2_UNGREEDY we do it manually */
145
    /* pkt_http_ua should be pkt, http_ua, for this reason the UNGREEDY */
146
34
    parse_capture_regex = DetectSetupPCRE2(PARSE_CAPTURE_REGEX, PCRE2_UNGREEDY);
147
34
    if (parse_capture_regex == NULL) {
148
0
        FatalError("pcre2 compile failed for parse_capture_regex");
149
0
    }
150
151
34
#ifdef PCRE2_HAVE_JIT
152
34
    if (PageSupportsRWX() == 0) {
153
0
        SCLogConfig("PCRE2 won't use JIT as OS doesn't allow RWX pages");
154
0
        pcre2_use_jit = 0;
155
0
    }
156
34
#endif
157
158
34
    return;
159
34
}
160
161
/**
162
 * \brief Match a regex on a single payload.
163
 *
164
 * \param det_ctx     Thread detection ctx.
165
 * \param s           Signature.
166
 * \param sm          Sig match to match against.
167
 * \param p           Packet to set PktVars if any.
168
 * \param f           Flow to set FlowVars if any.
169
 * \param payload     Payload to inspect.
170
 * \param payload_len Length of the payload.
171
 *
172
 * \retval  1 Match.
173
 * \retval  0 No match.
174
 */
175
int DetectPcrePayloadMatch(DetectEngineThreadCtx *det_ctx, const Signature *s,
176
                           const SigMatchData *smd, Packet *p, Flow *f,
177
                           const uint8_t *payload, uint32_t payload_len)
178
221k
{
179
221k
    SCEnter();
180
221k
    int ret = 0;
181
221k
    const uint8_t *ptr = NULL;
182
221k
    uint32_t len = 0;
183
221k
    PCRE2_SIZE capture_len = 0;
184
185
221k
    DetectPcreData *pe = (DetectPcreData *)smd->ctx;
186
187
221k
    if (pe->flags & DETECT_PCRE_RELATIVE) {
188
2.77k
        ptr = payload + det_ctx->buffer_offset;
189
2.77k
        len = payload_len - det_ctx->buffer_offset;
190
218k
    } else {
191
218k
        ptr = payload;
192
218k
        len = payload_len;
193
218k
    }
194
195
221k
    int start_offset = 0;
196
221k
    if (det_ctx->pcre_match_start_offset != 0) {
197
2.31k
        start_offset = (payload + det_ctx->pcre_match_start_offset - ptr);
198
2.31k
    }
199
200
    /* run the actual pcre detection */
201
221k
    pcre2_match_data *match =
202
221k
            (pcre2_match_data *)DetectThreadCtxGetKeywordThreadCtx(det_ctx, pe->thread_ctx_id);
203
204
221k
    ret = DetectPcreExec(det_ctx, pe, (char *)ptr, len, start_offset, 0, match);
205
221k
    SCLogDebug("ret %d (negating %s)", ret, (pe->flags & DETECT_PCRE_NEGATE) ? "set" : "not set");
206
207
221k
    if (ret == PCRE2_ERROR_NOMATCH) {
208
182k
        if (pe->flags & DETECT_PCRE_NEGATE) {
209
            /* regex didn't match with negate option means we
210
             * consider it a match */
211
154k
            ret = 1;
212
154k
        } else {
213
28.0k
            ret = 0;
214
28.0k
        }
215
182k
    } else if (ret >= 0) {
216
36.7k
        if (pe->flags & DETECT_PCRE_NEGATE) {
217
            /* regex matched but we're negated, so not
218
             * considering it a match */
219
20.9k
            ret = 0;
220
20.9k
        } else {
221
            /* regex matched and we're not negated,
222
             * considering it a match */
223
224
15.7k
            SCLogDebug("ret %d pe->idx %u", ret, pe->idx);
225
226
            /* see if we need to do substring capturing. */
227
15.7k
            if (ret > 1 && pe->idx != 0) {
228
2
                uint8_t x;
229
4
                for (x = 0; x < pe->idx; x++) {
230
2
                    SCLogDebug("capturing %u", x);
231
2
                    const char *pcre2_str_ptr = NULL;
232
2
                    ret = pcre2_substring_get_bynumber(
233
2
                            match, x + 1, (PCRE2_UCHAR8 **)&pcre2_str_ptr, &capture_len);
234
2
                    if (unlikely(ret != 0)) {
235
0
                        pcre2_substring_free((PCRE2_UCHAR8 *)pcre2_str_ptr);
236
0
                        continue;
237
0
                    }
238
                    /* store max 64k. Errors are ignored */
239
2
                    capture_len = (capture_len < 0xffff) ? (uint16_t)capture_len : 0xffff;
240
2
                    uint8_t *str_ptr = SCMalloc(capture_len);
241
2
                    if (unlikely(str_ptr == NULL)) {
242
0
                        pcre2_substring_free((PCRE2_UCHAR8 *)pcre2_str_ptr);
243
0
                        continue;
244
0
                    }
245
2
                    memcpy(str_ptr, pcre2_str_ptr, capture_len);
246
2
                    pcre2_substring_free((PCRE2_UCHAR8 *)pcre2_str_ptr);
247
248
2
                    SCLogDebug("data %p/%u, type %u id %u p %p",
249
2
                            str_ptr, ret, pe->captypes[x], pe->capids[x], p);
250
251
2
                    if (pe->captypes[x] == VAR_TYPE_PKT_VAR_KV) {
252
                        /* get the value, as first capture is the key */
253
0
                        const char *pcre2_str_ptr2 = NULL;
254
                        /* key length is limited to 256 chars */
255
0
                        uint16_t key_len = (capture_len < 0xff) ? (uint16_t)capture_len : 0xff;
256
0
                        int ret2 = pcre2_substring_get_bynumber(
257
0
                                match, x + 2, (PCRE2_UCHAR8 **)&pcre2_str_ptr2, &capture_len);
258
259
0
                        if (unlikely(ret2 != 0)) {
260
0
                            SCFree(str_ptr);
261
0
                            pcre2_substring_free((PCRE2_UCHAR8 *)pcre2_str_ptr2);
262
0
                            break;
263
0
                        }
264
0
                        capture_len = (capture_len < 0xffff) ? (uint16_t)capture_len : 0xffff;
265
0
                        uint8_t *str_ptr2 = SCMalloc(capture_len);
266
0
                        if (unlikely(str_ptr2 == NULL)) {
267
0
                            SCFree(str_ptr);
268
0
                            pcre2_substring_free((PCRE2_UCHAR8 *)pcre2_str_ptr2);
269
0
                            break;
270
0
                        }
271
0
                        memcpy(str_ptr2, pcre2_str_ptr2, capture_len);
272
0
                        pcre2_substring_free((PCRE2_UCHAR8 *)pcre2_str_ptr2);
273
274
0
                        (void)DetectVarStoreMatchKeyValue(det_ctx, (uint8_t *)str_ptr, key_len,
275
0
                                (uint8_t *)str_ptr2, (uint16_t)capture_len,
276
0
                                DETECT_VAR_TYPE_PKT_POSTMATCH);
277
278
2
                    } else if (pe->captypes[x] == VAR_TYPE_PKT_VAR) {
279
0
                        (void)DetectVarStoreMatch(det_ctx, pe->capids[x], (uint8_t *)str_ptr,
280
0
                                (uint16_t)capture_len, DETECT_VAR_TYPE_PKT_POSTMATCH);
281
282
2
                    } else if (pe->captypes[x] == VAR_TYPE_FLOW_VAR && f != NULL) {
283
2
                        (void)DetectVarStoreMatch(det_ctx, pe->capids[x], (uint8_t *)str_ptr,
284
2
                                (uint16_t)capture_len, DETECT_VAR_TYPE_FLOW_POSTMATCH);
285
2
                    } else {
286
0
                        BUG_ON(1); // Impossible captype
287
0
                        SCFree(str_ptr);
288
0
                    }
289
2
                }
290
2
            }
291
292
15.7k
            PCRE2_SIZE *ov = pcre2_get_ovector_pointer(match);
293
            /* update offset for pcre RELATIVE */
294
15.7k
            det_ctx->buffer_offset = (ptr + ov[1]) - payload;
295
15.7k
            det_ctx->pcre_match_start_offset = (ptr + ov[0] + 1) - payload;
296
297
15.7k
            ret = 1;
298
15.7k
        }
299
300
36.7k
    } else {
301
2.51k
        SCLogDebug("pcre had matching error");
302
2.51k
        ret = 0;
303
2.51k
    }
304
221k
    SCReturnInt(ret);
305
221k
}
306
307
static int DetectPcreSetList(int list, int set)
308
399k
{
309
399k
    if (list != DETECT_SM_LIST_NOTSET) {
310
82.7k
        SCLogError("only one pcre option to specify a buffer type is allowed");
311
82.7k
        return -1;
312
82.7k
    }
313
316k
    return set;
314
399k
}
315
316
static int DetectPcreHasUpperCase(const char *re)
317
2.00k
{
318
2.00k
    size_t len = strlen(re);
319
2.00k
    bool is_meta = false;
320
2.00k
    bool is_meta_hex = false;
321
2.00k
    int meta_hex_cnt = 0;
322
323
36.0k
    for (size_t i = 0; i < len; i++) {
324
34.4k
        if (is_meta_hex) {
325
1.91k
            meta_hex_cnt++;
326
327
1.91k
            if (meta_hex_cnt == 2) {
328
948
                is_meta_hex = false;
329
948
                meta_hex_cnt = 0;
330
948
            }
331
32.5k
        } else if (is_meta) {
332
6.54k
            if (re[i] == 'x') {
333
980
                is_meta_hex = true;
334
5.56k
            } else {
335
5.56k
                is_meta = false;
336
5.56k
            }
337
6.54k
        }
338
26.0k
        else if (re[i] == '\\') {
339
5.61k
            is_meta = true;
340
5.61k
        }
341
20.4k
        else if (isupper((unsigned char)re[i])) {
342
403
            return 1;
343
403
        }
344
34.4k
    }
345
346
1.60k
    return 0;
347
2.00k
}
348
349
static DetectPcreData *DetectPcreParse (DetectEngineCtx *de_ctx,
350
        const char *regexstr, int *sm_list, char *capture_names,
351
        size_t capture_names_size, bool negate, AppProto *alproto)
352
320k
{
353
320k
    pcre2_match_data *match = NULL;
354
320k
    int en;
355
320k
    PCRE2_SIZE eo2;
356
320k
    int opts = 0;
357
320k
    DetectPcreData *pd = NULL;
358
320k
    char *op = NULL;
359
320k
    int ret = 0, res = 0;
360
320k
    int check_host_header = 0;
361
320k
    char op_str[64] = "";
362
363
320k
    int cut_capture = 0;
364
320k
    char *fcap = strstr(regexstr, "flow:");
365
320k
    char *pcap = strstr(regexstr, "pkt:");
366
    /* take the size of the whole input as buffer size for the regex we will
367
     * extract below. Add 1 to please Coverity's alloc_strlen test. */
368
320k
    size_t slen = strlen(regexstr) + 1;
369
320k
    if (fcap || pcap) {
370
15.6k
        SCLogDebug("regexstr %s", regexstr);
371
372
15.6k
        if (fcap && !pcap)
373
12.3k
            cut_capture = fcap - regexstr;
374
3.27k
        else if (pcap && !fcap)
375
2.19k
            cut_capture = pcap - regexstr;
376
1.08k
        else {
377
1.08k
            BUG_ON(pcap == NULL); // added to assist cppcheck
378
1.08k
            BUG_ON(fcap == NULL);
379
1.08k
            cut_capture = MIN((pcap - regexstr), (fcap - regexstr));
380
1.08k
        }
381
382
15.6k
        SCLogDebug("cut_capture %d", cut_capture);
383
384
15.6k
        if (cut_capture > 1) {
385
14.2k
            int offset = cut_capture - 1;
386
19.0k
            while (offset) {
387
19.0k
                SCLogDebug("regexstr[offset] %c", regexstr[offset]);
388
19.0k
                if (regexstr[offset] == ',' || regexstr[offset] == ' ') {
389
4.80k
                    offset--;
390
4.80k
                }
391
14.2k
                else
392
14.2k
                    break;
393
19.0k
            }
394
395
14.2k
            if (cut_capture == (offset + 1)) {
396
10.0k
                SCLogDebug("missing separators, assume it's part of the regex");
397
10.0k
            } else {
398
4.20k
                slen = offset + 1;
399
4.20k
                strlcpy(capture_names, regexstr+cut_capture, capture_names_size);
400
4.20k
                if (capture_names[strlen(capture_names)-1] == '"')
401
1.12k
                    capture_names[strlen(capture_names)-1] = '\0';
402
4.20k
            }
403
14.2k
        }
404
15.6k
    }
405
406
320k
    char re[slen];
407
408
320k
    match = pcre2_match_data_create_from_pattern(parse_regex->regex, NULL);
409
320k
    if (!match) {
410
0
        goto error;
411
0
    }
412
413
320k
    ret = pcre2_match(parse_regex->regex, (PCRE2_SPTR8)regexstr, slen, 0, 0, match, NULL);
414
320k
    if (ret <= 0) {
415
5.60k
        SCLogError("pcre parse error: %s", regexstr);
416
5.60k
        goto error;
417
5.60k
    }
418
419
314k
    res = pcre2_substring_copy_bynumber(match, 1, (PCRE2_UCHAR8 *)re, &slen);
420
314k
    if (res < 0) {
421
0
        SCLogError("pcre2_substring_copy_bynumber failed");
422
0
        pcre2_match_data_free(match);
423
0
        return NULL;
424
0
    }
425
426
314k
    if (ret > 2) {
427
314k
        size_t copylen = sizeof(op_str);
428
314k
        res = pcre2_substring_copy_bynumber(match, 2, (PCRE2_UCHAR8 *)op_str, &copylen);
429
314k
        if (res < 0) {
430
2.48k
            SCLogError("pcre2_substring_copy_bynumber failed");
431
2.48k
            pcre2_match_data_free(match);
432
2.48k
            return NULL;
433
2.48k
        }
434
312k
        op = op_str;
435
312k
    }
436
    //printf("ret %" PRId32 " re \'%s\', op \'%s\'\n", ret, re, op);
437
438
312k
    pd = SCCalloc(1, sizeof(DetectPcreData));
439
312k
    if (unlikely(pd == NULL))
440
0
        goto error;
441
442
312k
    if (negate)
443
11.2k
        pd->flags |= DETECT_PCRE_NEGATE;
444
445
312k
    if (op != NULL) {
446
890k
        while (*op) {
447
586k
            SCLogDebug("regex option %c", *op);
448
449
586k
            switch (*op) {
450
7.98k
                case 'A':
451
7.98k
                    opts |= PCRE2_ANCHORED;
452
7.98k
                    break;
453
5.63k
                case 'E':
454
5.63k
                    opts |= PCRE2_DOLLAR_ENDONLY;
455
5.63k
                    break;
456
32.6k
                case 'G':
457
32.6k
                    opts |= PCRE2_UNGREEDY;
458
32.6k
                    break;
459
460
172k
                case 'i':
461
172k
                    opts |= PCRE2_CASELESS;
462
172k
                    pd->flags |= DETECT_PCRE_CASELESS;
463
172k
                    break;
464
96.5k
                case 'm':
465
96.5k
                    opts |= PCRE2_MULTILINE;
466
96.5k
                    break;
467
70.9k
                case 's':
468
70.9k
                    opts |= PCRE2_DOTALL;
469
70.9k
                    break;
470
3.54k
                case 'x':
471
3.54k
                    opts |= PCRE2_EXTENDED;
472
3.54k
                    break;
473
474
21.4k
                case 'O':
475
21.4k
                    pd->flags |= DETECT_PCRE_MATCH_LIMIT;
476
21.4k
                    break;
477
478
4.16k
                case 'B': /* snort's option */
479
4.16k
                    if (*sm_list != DETECT_SM_LIST_NOTSET) {
480
153
                        SCLogError("regex modifier 'B' inconsistent with chosen buffer");
481
153
                        goto error;
482
153
                    }
483
4.01k
                    pd->flags |= DETECT_PCRE_RAWBYTES;
484
4.01k
                    break;
485
20.6k
                case 'R': /* snort's option */
486
20.6k
                    pd->flags |= DETECT_PCRE_RELATIVE;
487
20.6k
                    break;
488
489
                /* buffer selection */
490
491
25.9k
                case 'U': { /* snort's option */
492
25.9k
                    if (pd->flags & DETECT_PCRE_RAWBYTES) {
493
60
                        SCLogError("regex modifier 'U' inconsistent with 'B'");
494
60
                        goto error;
495
60
                    }
496
25.9k
                    int list = DetectBufferTypeGetByName("http_uri");
497
25.9k
                    *sm_list = DetectPcreSetList(*sm_list, list);
498
25.9k
                    *alproto = ALPROTO_HTTP1;
499
25.9k
                    break;
500
25.9k
                }
501
562
                case 'V': {
502
562
                    if (pd->flags & DETECT_PCRE_RAWBYTES) {
503
8
                        SCLogError("regex modifier 'V' inconsistent with 'B'");
504
8
                        goto error;
505
8
                    }
506
554
                    int list = DetectBufferTypeGetByName("http_user_agent");
507
554
                    *sm_list = DetectPcreSetList(*sm_list, list);
508
554
                    *alproto = ALPROTO_HTTP1;
509
554
                    break;
510
562
                }
511
14.1k
                case 'W': {
512
14.1k
                    if (pd->flags & DETECT_PCRE_RAWBYTES) {
513
68
                        SCLogError("regex modifier 'W' inconsistent with 'B'");
514
68
                        goto error;
515
68
                    }
516
14.1k
                    int list = DetectBufferTypeGetByName("http_host");
517
14.1k
                    *sm_list = DetectPcreSetList(*sm_list, list);
518
14.1k
                    *alproto = ALPROTO_HTTP1;
519
14.1k
                    check_host_header = 1;
520
14.1k
                    break;
521
14.1k
                }
522
5.93k
                case 'Z': {
523
5.93k
                    if (pd->flags & DETECT_PCRE_RAWBYTES) {
524
2
                        SCLogError("regex modifier 'Z' inconsistent with 'B'");
525
2
                        goto error;
526
2
                    }
527
5.93k
                    int list = DetectBufferTypeGetByName("http_raw_host");
528
5.93k
                    *sm_list = DetectPcreSetList(*sm_list, list);
529
5.93k
                    *alproto = ALPROTO_HTTP1;
530
5.93k
                    break;
531
5.93k
                }
532
1.18k
                case 'H': { /* snort's option */
533
1.18k
                    if (pd->flags & DETECT_PCRE_RAWBYTES) {
534
2
                        SCLogError("regex modifier 'H' inconsistent with 'B'");
535
2
                        goto error;
536
2
                    }
537
1.18k
                    int list = DetectBufferTypeGetByName("http_header");
538
1.18k
                    *sm_list = DetectPcreSetList(*sm_list, list);
539
1.18k
                    *alproto = ALPROTO_HTTP1;
540
1.18k
                    break;
541
3.87k
                } case 'I': { /* snort's option */
542
3.87k
                    if (pd->flags & DETECT_PCRE_RAWBYTES) {
543
13
                        SCLogError("regex modifier 'I' inconsistent with 'B'");
544
13
                        goto error;
545
13
                    }
546
3.86k
                    int list = DetectBufferTypeGetByName("http_raw_uri");
547
3.86k
                    *sm_list = DetectPcreSetList(*sm_list, list);
548
3.86k
                    *alproto = ALPROTO_HTTP1;
549
3.86k
                    break;
550
3.87k
                }
551
3.31k
                case 'D': { /* snort's option */
552
3.31k
                    int list = DetectBufferTypeGetByName("http_raw_header");
553
3.31k
                    *sm_list = DetectPcreSetList(*sm_list, list);
554
3.31k
                    *alproto = ALPROTO_HTTP1;
555
3.31k
                    break;
556
3.87k
                }
557
39.2k
                case 'M': { /* snort's option */
558
39.2k
                    if (pd->flags & DETECT_PCRE_RAWBYTES) {
559
105
                        SCLogError("regex modifier 'M' inconsistent with 'B'");
560
105
                        goto error;
561
105
                    }
562
39.1k
                    int list = DetectBufferTypeGetByName("http_method");
563
39.1k
                    *sm_list = DetectPcreSetList(*sm_list, list);
564
39.1k
                    *alproto = ALPROTO_HTTP1;
565
39.1k
                    break;
566
39.2k
                }
567
2.08k
                case 'C': { /* snort's option */
568
2.08k
                    if (pd->flags & DETECT_PCRE_RAWBYTES) {
569
13
                        SCLogError("regex modifier 'C' inconsistent with 'B'");
570
13
                        goto error;
571
13
                    }
572
2.07k
                    int list = DetectBufferTypeGetByName("http_cookie");
573
2.07k
                    *sm_list = DetectPcreSetList(*sm_list, list);
574
2.07k
                    *alproto = ALPROTO_HTTP1;
575
2.07k
                    break;
576
2.08k
                }
577
12.3k
                case 'P': {
578
                    /* snort's option (http request body inspection) */
579
12.3k
                    int list = DetectBufferTypeGetByName("http_client_body");
580
12.3k
                    *sm_list = DetectPcreSetList(*sm_list, list);
581
12.3k
                    *alproto = ALPROTO_HTTP1;
582
12.3k
                    break;
583
2.08k
                }
584
1.41k
                case 'Q': {
585
1.41k
                    int list = DetectBufferTypeGetByName("file_data");
586
                    /* suricata extension (http response body inspection) */
587
1.41k
                    *sm_list = DetectPcreSetList(*sm_list, list);
588
1.41k
                    *alproto = ALPROTO_HTTP1;
589
1.41k
                    break;
590
2.08k
                }
591
1.03k
                case 'Y': {
592
                    /* snort's option */
593
1.03k
                    int list = DetectBufferTypeGetByName("http_stat_msg");
594
1.03k
                    *sm_list = DetectPcreSetList(*sm_list, list);
595
1.03k
                    *alproto = ALPROTO_HTTP1;
596
1.03k
                    break;
597
2.08k
                }
598
31.6k
                case 'S': {
599
                    /* snort's option */
600
31.6k
                    int list = DetectBufferTypeGetByName("http_stat_code");
601
31.6k
                    *sm_list = DetectPcreSetList(*sm_list, list);
602
31.6k
                    *alproto = ALPROTO_HTTP1;
603
31.6k
                    break;
604
2.08k
                }
605
8.09k
                default:
606
8.09k
                    SCLogError("unknown regex modifier '%c'", *op);
607
8.09k
                    goto error;
608
586k
            }
609
578k
            op++;
610
578k
        }
611
312k
    }
612
303k
    if (*sm_list == -1)
613
1.02k
        goto error;
614
615
302k
    SCLogDebug("DetectPcreParse: \"%s\"", re);
616
617
    /* host header */
618
302k
    if (check_host_header) {
619
11.6k
        if (pd->flags & DETECT_PCRE_CASELESS) {
620
11.1k
            SCLogWarning("http host pcre(\"W\") "
621
11.1k
                         "specified along with \"i(caseless)\" modifier.  "
622
11.1k
                         "Since the hostname buffer we match against "
623
11.1k
                         "is actually lowercase, having a "
624
11.1k
                         "nocase is redundant.");
625
11.1k
        }
626
561
        else if (DetectPcreHasUpperCase(re)) {
627
291
            SCLogError("pcre host(\"W\") "
628
291
                       "specified has an uppercase char.  "
629
291
                       "Since the hostname buffer we match against "
630
291
                       "is actually lowercase, please specify an "
631
291
                       "all lowercase based pcre.");
632
291
            goto error;
633
291
        }
634
11.6k
    }
635
636
    /* Try to compile as if all (...) groups had been meant as (?:...),
637
     * which is the common case in most rules.
638
     * If we fail because a capture group is later referenced (e.g., \1),
639
     * PCRE will let us know.
640
     */
641
302k
    if (capture_names == NULL || strlen(capture_names) == 0)
642
298k
        opts |= PCRE2_NO_AUTO_CAPTURE;
643
644
302k
    pd->parse_regex.regex =
645
302k
            pcre2_compile((PCRE2_SPTR8)re, PCRE2_ZERO_TERMINATED, opts, &en, &eo2, NULL);
646
302k
    if (pd->parse_regex.regex == NULL && en == 115) { // reference to nonexistent subpattern
647
59.2k
        opts &= ~PCRE2_NO_AUTO_CAPTURE;
648
59.2k
        pd->parse_regex.regex =
649
59.2k
                pcre2_compile((PCRE2_SPTR8)re, PCRE2_ZERO_TERMINATED, opts, &en, &eo2, NULL);
650
59.2k
    }
651
302k
    if (pd->parse_regex.regex == NULL)  {
652
35.8k
        PCRE2_UCHAR errbuffer[256];
653
35.8k
        pcre2_get_error_message(en, errbuffer, sizeof(errbuffer));
654
35.8k
        SCLogError("pcre2 compile of \"%s\" failed at "
655
35.8k
                   "offset %d: %s",
656
35.8k
                regexstr, (int)eo2, errbuffer);
657
35.8k
        goto error;
658
35.8k
    }
659
660
266k
#ifdef PCRE2_HAVE_JIT
661
266k
    if (pcre2_use_jit) {
662
266k
        ret = pcre2_jit_compile(pd->parse_regex.regex, PCRE2_JIT_COMPLETE);
663
266k
        if (ret != 0) {
664
            /* warning, so we won't print the sig after this. Adding
665
             * file and line to the message so the admin can figure
666
             * out what sig this is about */
667
266k
            SCLogDebug("PCRE2 JIT compiler does not support: %s. "
668
266k
                       "Falling back to regular PCRE2 handling (%s:%d)",
669
266k
                    regexstr, de_ctx->rule_file, de_ctx->rule_line);
670
266k
        }
671
266k
    }
672
266k
#endif /*PCRE2_HAVE_JIT*/
673
674
266k
    pd->parse_regex.context = pcre2_match_context_create(NULL);
675
266k
    if (pd->parse_regex.context == NULL) {
676
0
        SCLogError("pcre2 could not create match context");
677
0
        goto error;
678
0
    }
679
266k
    pd->parse_regex.match = pcre2_match_data_create_from_pattern(pd->parse_regex.regex, NULL);
680
681
266k
    if (pd->flags & DETECT_PCRE_MATCH_LIMIT) {
682
15.5k
        if (pcre_match_limit >= -1) {
683
15.5k
            pcre2_set_match_limit(pd->parse_regex.context, pcre_match_limit);
684
15.5k
        }
685
15.5k
        if (pcre_match_limit_recursion >= -1) {
686
            // pcre2_set_depth_limit unsupported on ubuntu 16.04
687
15.5k
            pcre2_set_recursion_limit(pd->parse_regex.context, pcre_match_limit_recursion);
688
15.5k
        }
689
250k
    } else {
690
250k
        pcre2_set_match_limit(pd->parse_regex.context, SC_MATCH_LIMIT_DEFAULT);
691
250k
        pcre2_set_recursion_limit(pd->parse_regex.context, SC_MATCH_LIMIT_RECURSION_DEFAULT);
692
250k
    }
693
694
266k
    pcre2_match_data_free(match);
695
266k
    return pd;
696
697
51.2k
error:
698
51.2k
    pcre2_match_data_free(match);
699
51.2k
    DetectPcreFree(de_ctx, pd);
700
51.2k
    return NULL;
701
266k
}
702
703
/** \internal
704
 *  \brief check if we need to extract capture settings and set them up if needed
705
 */
706
static int DetectPcreParseCapture(const char *regexstr, DetectEngineCtx *de_ctx, DetectPcreData *pd,
707
    char *capture_names)
708
266k
{
709
266k
    int ret = 0, res = 0;
710
266k
    char type_str[16] = "";
711
266k
    const char *orig_right_edge = regexstr + strlen(regexstr);
712
266k
    char *name_array[DETECT_PCRE_CAPTURE_MAX] = { NULL };
713
266k
    int name_idx = 0;
714
266k
    int capture_cnt = 0;
715
266k
    int key = 0;
716
266k
    size_t copylen;
717
266k
    pcre2_match_data *match = NULL;
718
719
266k
    SCLogDebug("regexstr %s, pd %p", regexstr, pd);
720
721
266k
    ret = pcre2_pattern_info(pd->parse_regex.regex, PCRE2_INFO_CAPTURECOUNT, &capture_cnt);
722
266k
    SCLogDebug("ret %d capture_cnt %d", ret, capture_cnt);
723
266k
    if (ret == 0 && capture_cnt && strlen(capture_names) > 0)
724
2.52k
    {
725
2.52k
        char *ptr = NULL;
726
7.09k
        while ((name_array[name_idx] = strtok_r(name_idx == 0 ? capture_names : NULL, " ,", &ptr))){
727
5.46k
            if (name_idx > (capture_cnt - 1)) {
728
314
                SCLogError("more pkt/flow "
729
314
                           "var capture names than capturing substrings");
730
314
                return -1;
731
314
            }
732
5.14k
            SCLogDebug("name '%s'", name_array[name_idx]);
733
734
5.14k
            if (strcmp(name_array[name_idx], "pkt:key") == 0) {
735
300
                key = 1;
736
300
                SCLogDebug("key-value/key");
737
738
300
                pd->captypes[pd->idx] = VAR_TYPE_PKT_VAR_KV;
739
300
                SCLogDebug("id %u type %u", pd->capids[pd->idx], pd->captypes[pd->idx]);
740
300
                pd->idx++;
741
742
4.84k
            } else if (key == 1 && strcmp(name_array[name_idx], "pkt:value") == 0) {
743
0
                SCLogDebug("key-value/value");
744
0
                key = 0;
745
746
            /* kv error conditions */
747
4.84k
            } else if (key == 0 && strcmp(name_array[name_idx], "pkt:value") == 0) {
748
2
                return -1;
749
4.84k
            } else if (key == 1) {
750
36
                return -1;
751
752
4.81k
            } else if (strncmp(name_array[name_idx], "flow:", 5) == 0) {
753
2.80k
                pd->capids[pd->idx] =
754
2.80k
                        VarNameStoreRegister(name_array[name_idx] + 5, VAR_TYPE_FLOW_VAR);
755
2.80k
                pd->captypes[pd->idx] = VAR_TYPE_FLOW_VAR;
756
2.80k
                pd->idx++;
757
758
2.80k
            } else if (strncmp(name_array[name_idx], "pkt:", 4) == 0) {
759
1.63k
                pd->capids[pd->idx] =
760
1.63k
                        VarNameStoreRegister(name_array[name_idx] + 4, VAR_TYPE_PKT_VAR);
761
1.63k
                pd->captypes[pd->idx] = VAR_TYPE_PKT_VAR;
762
1.63k
                SCLogDebug("id %u type %u", pd->capids[pd->idx], pd->captypes[pd->idx]);
763
1.63k
                pd->idx++;
764
765
1.63k
            } else {
766
370
                SCLogError(" pkt/flow "
767
370
                           "var capture names must start with 'pkt:' or 'flow:'");
768
370
                return -1;
769
370
            }
770
771
4.74k
            name_idx++;
772
4.74k
            if (name_idx >= DETECT_PCRE_CAPTURE_MAX)
773
172
                break;
774
4.74k
        }
775
2.52k
    }
776
777
    /* take the size of the whole input as buffer size for the string we will
778
     * extract below. Add 1 to please Coverity's alloc_strlen test. */
779
265k
    size_t cap_buffer_len = strlen(regexstr) + 1;
780
265k
    char capture_str[cap_buffer_len];
781
265k
    memset(capture_str, 0x00, cap_buffer_len);
782
783
265k
    if (de_ctx == NULL)
784
0
        goto error;
785
786
267k
    while (1) {
787
267k
        SCLogDebug("\'%s\'", regexstr);
788
789
267k
        ret = DetectParsePcreExec(parse_capture_regex, &match, regexstr, 0, 0);
790
267k
        if (ret < 3) {
791
265k
            pcre2_match_data_free(match);
792
265k
            return 0;
793
265k
        }
794
1.67k
        copylen = sizeof(type_str);
795
1.67k
        res = pcre2_substring_copy_bynumber(match, 1, (PCRE2_UCHAR8 *)type_str, &copylen);
796
1.67k
        if (res != 0) {
797
35
            SCLogError("pcre2_substring_copy_bynumber failed");
798
35
            goto error;
799
35
        }
800
1.64k
        cap_buffer_len = strlen(regexstr) + 1;
801
1.64k
        res = pcre2_substring_copy_bynumber(match, 2, (PCRE2_UCHAR8 *)capture_str, &cap_buffer_len);
802
1.64k
        if (res != 0) {
803
0
            SCLogError("pcre2_substring_copy_bynumber failed");
804
0
            goto error;
805
0
        }
806
1.64k
        if (strlen(capture_str) == 0 || strlen(type_str) == 0) {
807
0
            goto error;
808
0
        }
809
810
1.64k
        SCLogDebug("type \'%s\'", type_str);
811
1.64k
        SCLogDebug("capture \'%s\'", capture_str);
812
813
1.64k
        if (pd->idx >= DETECT_PCRE_CAPTURE_MAX) {
814
1
            SCLogError("rule can have maximally %d pkt/flow "
815
1
                       "var captures",
816
1
                    DETECT_PCRE_CAPTURE_MAX);
817
1
            pcre2_match_data_free(match);
818
1
            return -1;
819
1
        }
820
821
1.64k
        if (strcmp(type_str, "pkt") == 0) {
822
243
            pd->capids[pd->idx] = VarNameStoreRegister((char *)capture_str, VAR_TYPE_PKT_VAR);
823
243
            pd->captypes[pd->idx] = VAR_TYPE_PKT_VAR;
824
243
            SCLogDebug("id %u type %u", pd->capids[pd->idx], pd->captypes[pd->idx]);
825
243
            pd->idx++;
826
1.40k
        } else if (strcmp(type_str, "flow") == 0) {
827
260
            pd->capids[pd->idx] = VarNameStoreRegister((char *)capture_str, VAR_TYPE_FLOW_VAR);
828
260
            pd->captypes[pd->idx] = VAR_TYPE_FLOW_VAR;
829
260
            pd->idx++;
830
260
        }
831
832
        //SCLogNotice("pd->capname %s", pd->capname);
833
1.64k
        PCRE2_SIZE *ov = pcre2_get_ovector_pointer(match);
834
1.64k
        regexstr += ov[1];
835
836
1.64k
        pcre2_match_data_free(match);
837
1.64k
        match = NULL;
838
839
1.64k
        if (regexstr >= orig_right_edge)
840
67
            break;
841
1.64k
    }
842
67
    return 0;
843
844
35
error:
845
35
    pcre2_match_data_free(match);
846
35
    return -1;
847
265k
}
848
849
static void *DetectPcreThreadInit(void *data)
850
73.3k
{
851
73.3k
    DetectPcreData *pd = (DetectPcreData *)data;
852
73.3k
    pcre2_match_data *match = pcre2_match_data_create_from_pattern(pd->parse_regex.regex, NULL);
853
73.3k
    return match;
854
73.3k
}
855
856
static void DetectPcreThreadFree(void *ctx)
857
73.3k
{
858
73.3k
    if (ctx != NULL) {
859
73.3k
        pcre2_match_data *match = (pcre2_match_data *)ctx;
860
73.3k
        pcre2_match_data_free(match);
861
73.3k
    }
862
73.3k
}
863
864
static int DetectPcreSetup (DetectEngineCtx *de_ctx, Signature *s, const char *regexstr)
865
758k
{
866
758k
    SCEnter();
867
758k
    DetectPcreData *pd = NULL;
868
758k
    SigMatch *sm = NULL;
869
758k
    int parsed_sm_list = DETECT_SM_LIST_NOTSET;
870
758k
    char capture_names[1024] = "";
871
758k
    AppProto alproto = ALPROTO_UNKNOWN;
872
873
758k
    pd = DetectPcreParse(de_ctx, regexstr, &parsed_sm_list,
874
758k
            capture_names, sizeof(capture_names), s->init_data->negated,
875
758k
            &alproto);
876
758k
    if (pd == NULL)
877
122k
        goto error;
878
635k
    if (DetectPcreParseCapture(regexstr, de_ctx, pd, capture_names) < 0)
879
2.06k
        goto error;
880
881
633k
    pd->thread_ctx_id = DetectRegisterThreadCtxFuncs(
882
633k
            de_ctx, "pcre", DetectPcreThreadInit, (void *)pd, DetectPcreThreadFree, 0);
883
633k
    if (pd->thread_ctx_id == -1)
884
0
        goto error;
885
886
633k
    int sm_list = -1;
887
633k
    if (s->init_data->list != DETECT_SM_LIST_NOTSET) {
888
62.7k
        if (parsed_sm_list != DETECT_SM_LIST_NOTSET && parsed_sm_list != s->init_data->list) {
889
922
            SCLogError("Expression seen with a sticky buffer still set; either (1) reset sticky "
890
922
                       "buffer with pkt_data or (2) use a sticky buffer providing \"%s\".",
891
922
                    DetectEngineBufferTypeGetDescriptionById(de_ctx, parsed_sm_list));
892
922
            goto error;
893
922
        }
894
61.8k
        if (DetectBufferGetActiveList(de_ctx, s) == -1)
895
6
            goto error;
896
897
61.8k
        sm_list = s->init_data->list;
898
570k
    } else {
899
570k
        switch (parsed_sm_list) {
900
313k
            case DETECT_SM_LIST_NOTSET:
901
313k
                sm_list = DETECT_SM_LIST_PMATCH;
902
313k
                break;
903
256k
            default: {
904
256k
                if (alproto != ALPROTO_UNKNOWN) {
905
                    /* see if the proto doesn't conflict
906
                     * with what we already have. */
907
256k
                    if (s->alproto != ALPROTO_UNKNOWN && !AppProtoEquals(s->alproto, alproto)) {
908
555
                        goto error;
909
555
                    }
910
256k
                    if (DetectSignatureSetAppProto(s, alproto) < 0)
911
510
                        goto error;
912
256k
                }
913
255k
                sm_list = parsed_sm_list;
914
255k
                break;
915
256k
            }
916
570k
        }
917
570k
    }
918
631k
    if (sm_list == -1)
919
0
        goto error;
920
921
631k
    sm = SigMatchAlloc();
922
631k
    if (sm == NULL)
923
1
        goto error;
924
631k
    sm->type = DETECT_PCRE;
925
631k
    sm->ctx = (void *)pd;
926
631k
    SigMatchAppendSMToList(s, sm, sm_list);
927
928
643k
    for (uint8_t x = 0; x < pd->idx; x++) {
929
12.2k
        if (DetectFlowvarPostMatchSetup(de_ctx, s, pd->capids[x]) < 0)
930
0
            goto error_nofree;
931
12.2k
    }
932
933
631k
    if (!(pd->flags & DETECT_PCRE_RELATIVE))
934
605k
        goto okay;
935
936
    /* errors below shouldn't free pd */
937
938
26.0k
    SigMatch *prev_pm = DetectGetLastSMByListPtr(s, sm->prev,
939
26.0k
            DETECT_CONTENT, DETECT_PCRE, -1);
940
26.0k
    if (s->init_data->list == DETECT_SM_LIST_NOTSET && prev_pm == NULL) {
941
949
        SCLogError("pcre with /R (relative) needs "
942
949
                   "preceding match in the same buffer");
943
949
        goto error_nofree;
944
    /* null is allowed when we use a sticky buffer */
945
25.1k
    } else if (prev_pm == NULL) {
946
1.51k
        goto okay;
947
1.51k
    }
948
23.6k
    if (prev_pm->type == DETECT_CONTENT) {
949
13.7k
        DetectContentData *cd = (DetectContentData *)prev_pm->ctx;
950
13.7k
        cd->flags |= DETECT_CONTENT_RELATIVE_NEXT;
951
13.7k
    } else if (prev_pm->type == DETECT_PCRE) {
952
9.89k
        DetectPcreData *tmp = (DetectPcreData *)prev_pm->ctx;
953
9.89k
        tmp->flags |= DETECT_PCRE_RELATIVE_NEXT;
954
9.89k
    }
955
956
630k
 okay:
957
630k
    SCReturnInt(0);
958
127k
 error:
959
127k
    DetectPcreFree(de_ctx, pd);
960
127k
 error_nofree:
961
127k
    SCReturnInt(-1);
962
127k
}
963
964
static void DetectPcreFree(DetectEngineCtx *de_ctx, void *ptr)
965
371k
{
966
371k
    if (ptr == NULL)
967
59.3k
        return;
968
969
312k
    DetectPcreData *pd = (DetectPcreData *)ptr;
970
312k
    DetectParseFreeRegex(&pd->parse_regex);
971
312k
    DetectUnregisterThreadCtxFuncs(de_ctx, pd, "pcre");
972
973
317k
    for (uint8_t i = 0; i < pd->idx; i++) {
974
5.24k
        VarNameStoreUnregister(pd->capids[i], pd->captypes[i]);
975
5.24k
    }
976
312k
    SCFree(pd);
977
978
312k
    return;
979
371k
}
980
981
#ifdef UNITTESTS /* UNITTESTS */
982
#include "detect-engine-alert.h"
983
static int g_file_data_buffer_id = 0;
984
static int g_http_header_buffer_id = 0;
985
static int g_dce_stub_data_buffer_id = 0;
986
987
/**
988
 * \test DetectPcreParseTest01 make sure we don't allow invalid opts 7.
989
 */
990
static int DetectPcreParseTest01 (void)
991
{
992
    int result = 1;
993
    DetectPcreData *pd = NULL;
994
    const char *teststring = "/blah/7";
995
    int list = DETECT_SM_LIST_NOTSET;
996
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
997
    FAIL_IF_NULL(de_ctx);
998
    AppProto alproto = ALPROTO_UNKNOWN;
999
1000
    pd = DetectPcreParse(de_ctx, teststring, &list, NULL, 0, false, &alproto);
1001
    FAIL_IF_NOT_NULL(pd);
1002
1003
    DetectEngineCtxFree(de_ctx);
1004
    return result;
1005
}
1006
1007
/**
1008
 * \test DetectPcreParseTest02 make sure we don't allow invalid opts Ui$.
1009
 */
1010
static int DetectPcreParseTest02 (void)
1011
{
1012
    int result = 1;
1013
    DetectPcreData *pd = NULL;
1014
    const char *teststring = "/blah/Ui$";
1015
    int list = DETECT_SM_LIST_NOTSET;
1016
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1017
    FAIL_IF_NULL(de_ctx);
1018
    AppProto alproto = ALPROTO_UNKNOWN;
1019
1020
    pd = DetectPcreParse(de_ctx, teststring, &list, NULL, 0, false, &alproto);
1021
    FAIL_IF_NOT_NULL(pd);
1022
    FAIL_IF_NOT(alproto == ALPROTO_HTTP1);
1023
1024
    DetectEngineCtxFree(de_ctx);
1025
    return result;
1026
}
1027
1028
/**
1029
 * \test DetectPcreParseTest03 make sure we don't allow invalid opts UZi.
1030
 */
1031
static int DetectPcreParseTest03 (void)
1032
{
1033
    int result = 1;
1034
    DetectPcreData *pd = NULL;
1035
    const char *teststring = "/blah/UNi";
1036
    int list = DETECT_SM_LIST_NOTSET;
1037
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1038
    FAIL_IF_NULL(de_ctx);
1039
    AppProto alproto = ALPROTO_UNKNOWN;
1040
1041
    pd = DetectPcreParse(de_ctx, teststring, &list, NULL, 0, false, &alproto);
1042
    FAIL_IF_NOT_NULL(pd);
1043
1044
    DetectEngineCtxFree(de_ctx);
1045
    return result;
1046
}
1047
1048
/**
1049
 * \test DetectPcreParseTest04 make sure we allow escaped "
1050
 */
1051
static int DetectPcreParseTest04 (void)
1052
{
1053
    int result = 1;
1054
    DetectPcreData *pd = NULL;
1055
    const char *teststring = "/b\\\"lah/i";
1056
    int list = DETECT_SM_LIST_NOTSET;
1057
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1058
    FAIL_IF_NULL(de_ctx);
1059
    AppProto alproto = ALPROTO_UNKNOWN;
1060
1061
    pd = DetectPcreParse(de_ctx, teststring, &list, NULL, 0, false, &alproto);
1062
    FAIL_IF_NULL(pd);
1063
    FAIL_IF_NOT(alproto == ALPROTO_UNKNOWN);
1064
1065
    DetectPcreFree(de_ctx, pd);
1066
    DetectEngineCtxFree(de_ctx);
1067
    return result;
1068
}
1069
1070
/**
1071
 * \test DetectPcreParseTest05 make sure we parse pcre with no opts
1072
 */
1073
static int DetectPcreParseTest05 (void)
1074
{
1075
    int result = 1;
1076
    DetectPcreData *pd = NULL;
1077
    const char *teststring = "/b(l|a)h/";
1078
    int list = DETECT_SM_LIST_NOTSET;
1079
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1080
    FAIL_IF_NULL(de_ctx);
1081
    AppProto alproto = ALPROTO_UNKNOWN;
1082
1083
    pd = DetectPcreParse(de_ctx, teststring, &list, NULL, 0, false, &alproto);
1084
    FAIL_IF_NULL(pd);
1085
    FAIL_IF_NOT(alproto == ALPROTO_UNKNOWN);
1086
1087
    DetectPcreFree(de_ctx, pd);
1088
    DetectEngineCtxFree(de_ctx);
1089
    return result;
1090
}
1091
1092
/**
1093
 * \test DetectPcreParseTest06 make sure we parse pcre with smi opts
1094
 */
1095
static int DetectPcreParseTest06 (void)
1096
{
1097
    int result = 1;
1098
    DetectPcreData *pd = NULL;
1099
    const char *teststring = "/b(l|a)h/smi";
1100
    int list = DETECT_SM_LIST_NOTSET;
1101
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1102
    FAIL_IF_NULL(de_ctx);
1103
    AppProto alproto = ALPROTO_UNKNOWN;
1104
1105
    pd = DetectPcreParse(de_ctx, teststring, &list, NULL, 0, false, &alproto);
1106
    FAIL_IF_NULL(pd);
1107
    FAIL_IF_NOT(alproto == ALPROTO_UNKNOWN);
1108
1109
    DetectPcreFree(de_ctx, pd);
1110
    DetectEngineCtxFree(de_ctx);
1111
    return result;
1112
}
1113
1114
/**
1115
 * \test DetectPcreParseTest07 make sure we parse pcre with /Ui opts
1116
 */
1117
static int DetectPcreParseTest07 (void)
1118
{
1119
    int result = 1;
1120
    DetectPcreData *pd = NULL;
1121
    const char *teststring = "/blah/Ui";
1122
    int list = DETECT_SM_LIST_NOTSET;
1123
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1124
    FAIL_IF_NULL(de_ctx);
1125
    AppProto alproto = ALPROTO_UNKNOWN;
1126
1127
    pd = DetectPcreParse(de_ctx, teststring, &list, NULL, 0, false, &alproto);
1128
    FAIL_IF_NULL(pd);
1129
    FAIL_IF_NOT(alproto == ALPROTO_HTTP1);
1130
1131
    DetectPcreFree(de_ctx, pd);
1132
    DetectEngineCtxFree(de_ctx);
1133
    return result;
1134
}
1135
1136
/**
1137
 * \test DetectPcreParseTest08 make sure we parse pcre with O opts
1138
 */
1139
static int DetectPcreParseTest08 (void)
1140
{
1141
    int result = 1;
1142
    DetectPcreData *pd = NULL;
1143
    const char *teststring = "/b(l|a)h/O";
1144
    int list = DETECT_SM_LIST_NOTSET;
1145
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1146
    FAIL_IF_NULL(de_ctx);
1147
    AppProto alproto = ALPROTO_UNKNOWN;
1148
1149
    pd = DetectPcreParse(de_ctx, teststring, &list, NULL, 0, false, &alproto);
1150
    FAIL_IF_NULL(pd);
1151
    FAIL_IF_NOT(alproto == ALPROTO_UNKNOWN);
1152
1153
    DetectPcreFree(de_ctx, pd);
1154
    DetectEngineCtxFree(de_ctx);
1155
    return result;
1156
}
1157
1158
/**
1159
 * \test DetectPcreParseTest09 make sure we parse pcre with a content
1160
 *       that has slashes
1161
 */
1162
static int DetectPcreParseTest09 (void)
1163
{
1164
    DetectPcreData *pd = NULL;
1165
    const char *teststring = "/lala\\\\/";
1166
    int list = DETECT_SM_LIST_NOTSET;
1167
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1168
    FAIL_IF_NULL(de_ctx);
1169
    AppProto alproto = ALPROTO_UNKNOWN;
1170
1171
    pd = DetectPcreParse(de_ctx, teststring, &list, NULL, 0, false, &alproto);
1172
    FAIL_IF_NULL(pd);
1173
1174
    DetectPcreFree(de_ctx, pd);
1175
    DetectEngineCtxFree(de_ctx);
1176
    PASS;
1177
}
1178
1179
/**
1180
 * \test Test pcre option for dce sig(yeah I'm bored of writing test titles).
1181
 */
1182
static int DetectPcreParseTest10(void)
1183
{
1184
    Signature *s = SigAlloc();
1185
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1186
    FAIL_IF_NULL(de_ctx);
1187
1188
    FAIL_IF(DetectSignatureSetAppProto(s, ALPROTO_DCERPC) < 0);
1189
1190
    FAIL_IF_NOT(DetectPcreSetup(de_ctx, s, "/bamboo/") == 0);
1191
    FAIL_IF_NOT(DetectBufferGetFirstSigMatch(s, g_dce_stub_data_buffer_id) == NULL);
1192
    FAIL_IF_NOT(s->init_data->smlists[DETECT_SM_LIST_PMATCH] != NULL);
1193
1194
    SigFree(de_ctx, s);
1195
1196
    s = SigAlloc();
1197
    FAIL_IF_NULL(s);
1198
1199
    /* failure since we have no preceding content/pcre/bytejump */
1200
    FAIL_IF_NOT(DetectPcreSetup(de_ctx, s, "/bamboo/") == 0);
1201
    FAIL_IF_NOT(DetectBufferGetFirstSigMatch(s, g_dce_stub_data_buffer_id) == NULL);
1202
    FAIL_IF_NOT(s->init_data->smlists[DETECT_SM_LIST_PMATCH] != NULL);
1203
1204
    SigFree(de_ctx, s);
1205
    DetectEngineCtxFree(de_ctx);
1206
1207
    PASS;
1208
}
1209
1210
/** \test Check a signature with pcre relative method */
1211
static int DetectPcreParseTest15(void)
1212
{
1213
    DetectEngineCtx *de_ctx = NULL;
1214
1215
    FAIL_IF( (de_ctx = DetectEngineCtxInit()) == NULL);
1216
1217
    de_ctx->flags |= DE_QUIET;
1218
    de_ctx->sig_list = SigInit(de_ctx,
1219
                               "alert tcp any any -> any any "
1220
                               "(msg:\"Testing pcre relative http_method\"; "
1221
                               "content:\"GET\"; "
1222
                               "http_method; pcre:\"/abc/RM\"; sid:1;)");
1223
    FAIL_IF_NULL(de_ctx->sig_list);
1224
1225
    if (de_ctx != NULL)
1226
        SigCleanSignatures(de_ctx);
1227
    if (de_ctx != NULL)
1228
        DetectEngineCtxFree(de_ctx);
1229
    PASS;
1230
}
1231
1232
1233
/** \test Check a signature with pcre relative cookie */
1234
static int DetectPcreParseTest16(void)
1235
{
1236
    DetectEngineCtx *de_ctx = NULL;
1237
1238
    FAIL_IF( (de_ctx = DetectEngineCtxInit()) == NULL);
1239
1240
    de_ctx->flags |= DE_QUIET;
1241
    de_ctx->sig_list = SigInit(de_ctx,
1242
                               "alert tcp any any -> any any "
1243
                               "(msg:\"Testing pcre relative http_cookie\"; "
1244
                               "content:\"test\"; "
1245
                               "http_cookie; pcre:\"/abc/RC\"; sid:1;)");
1246
    FAIL_IF_NULL(de_ctx->sig_list);
1247
1248
    if (de_ctx != NULL)
1249
        SigCleanSignatures(de_ctx);
1250
    if (de_ctx != NULL)
1251
        DetectEngineCtxFree(de_ctx);
1252
    PASS;
1253
}
1254
1255
/** \test Check a signature with pcre relative raw header */
1256
static int DetectPcreParseTest17(void)
1257
{
1258
    DetectEngineCtx *de_ctx = NULL;
1259
1260
    FAIL_IF( (de_ctx = DetectEngineCtxInit()) == NULL);
1261
1262
    de_ctx->flags |= DE_QUIET;
1263
    de_ctx->sig_list = SigInit(de_ctx,
1264
                               "alert tcp any any -> any any "
1265
                               "(msg:\"Testing pcre relative http_raw_header\"; "
1266
                               "flow:to_server; content:\"test\"; "
1267
                               "http_raw_header; pcre:\"/abc/RD\"; sid:1;)");
1268
    FAIL_IF_NULL(de_ctx->sig_list);
1269
1270
    if (de_ctx != NULL)
1271
        SigCleanSignatures(de_ctx);
1272
    if (de_ctx != NULL)
1273
        DetectEngineCtxFree(de_ctx);
1274
    PASS;
1275
}
1276
1277
/** \test Check a signature with pcre relative header */
1278
static int DetectPcreParseTest18(void)
1279
{
1280
    DetectEngineCtx *de_ctx = NULL;
1281
1282
    FAIL_IF( (de_ctx = DetectEngineCtxInit()) == NULL);
1283
1284
    de_ctx->flags |= DE_QUIET;
1285
    de_ctx->sig_list = SigInit(de_ctx,
1286
                               "alert tcp any any -> any any "
1287
                               "(msg:\"Testing pcre relative http_header\"; "
1288
                               "content:\"test\"; "
1289
                               "http_header; pcre:\"/abc/RH\"; sid:1;)");
1290
    FAIL_IF_NULL(de_ctx->sig_list);
1291
1292
    if (de_ctx != NULL)
1293
        SigCleanSignatures(de_ctx);
1294
    if (de_ctx != NULL)
1295
        DetectEngineCtxFree(de_ctx);
1296
    PASS;
1297
}
1298
1299
/** \test Check a signature with pcre relative client-body */
1300
static int DetectPcreParseTest19(void)
1301
{
1302
    DetectEngineCtx *de_ctx = NULL;
1303
1304
    FAIL_IF( (de_ctx = DetectEngineCtxInit()) == NULL);
1305
1306
    de_ctx->flags |= DE_QUIET;
1307
    de_ctx->sig_list = SigInit(de_ctx,
1308
                               "alert tcp any any -> any any "
1309
                               "(msg:\"Testing pcre relative http_client_body\"; "
1310
                               "content:\"test\"; "
1311
                               "http_client_body; pcre:\"/abc/RP\"; sid:1;)");
1312
    FAIL_IF_NULL(de_ctx->sig_list);
1313
1314
    if (de_ctx != NULL)
1315
        SigCleanSignatures(de_ctx);
1316
    if (de_ctx != NULL)
1317
        DetectEngineCtxFree(de_ctx);
1318
    PASS;
1319
}
1320
1321
/** \test Check a signature with pcre relative raw uri */
1322
static int DetectPcreParseTest20(void)
1323
{
1324
    DetectEngineCtx *de_ctx = NULL;
1325
1326
    FAIL_IF( (de_ctx = DetectEngineCtxInit()) == NULL);
1327
1328
    de_ctx->flags |= DE_QUIET;
1329
    de_ctx->sig_list = SigInit(de_ctx,
1330
                               "alert tcp any any -> any any "
1331
                               "(msg:\"Testing http_raw_uri\"; "
1332
                               "content:\"test\"; "
1333
                               "http_raw_uri; pcre:\"/abc/RI\"; sid:1;)");
1334
    FAIL_IF_NULL(de_ctx->sig_list);
1335
1336
    if (de_ctx != NULL)
1337
        SigCleanSignatures(de_ctx);
1338
    if (de_ctx != NULL)
1339
        DetectEngineCtxFree(de_ctx);
1340
    PASS;
1341
}
1342
1343
/** \test Check a signature with pcre relative uricontent */
1344
static int DetectPcreParseTest21(void)
1345
{
1346
    DetectEngineCtx *de_ctx = NULL;
1347
1348
    FAIL_IF( (de_ctx = DetectEngineCtxInit()) == NULL);
1349
1350
    de_ctx->flags |= DE_QUIET;
1351
    de_ctx->sig_list = SigInit(de_ctx,
1352
                               "alert tcp any any -> any any "
1353
                               "(msg:\"Testing pcre relative uricontent\"; "
1354
                               "uricontent:\"test\"; "
1355
                               "pcre:\"/abc/RU\"; sid:1;)");
1356
    FAIL_IF_NULL(de_ctx->sig_list);
1357
1358
    if (de_ctx != NULL)
1359
        SigCleanSignatures(de_ctx);
1360
    if (de_ctx != NULL)
1361
        DetectEngineCtxFree(de_ctx);
1362
    PASS;
1363
}
1364
1365
/** \test Check a signature with pcre relative http_uri */
1366
static int DetectPcreParseTest22(void)
1367
{
1368
    DetectEngineCtx *de_ctx = NULL;
1369
1370
    FAIL_IF( (de_ctx = DetectEngineCtxInit()) == NULL);
1371
1372
    de_ctx->flags |= DE_QUIET;
1373
    de_ctx->sig_list = SigInit(de_ctx,
1374
                               "alert tcp any any -> any any "
1375
                               "(msg:\"Testing pcre relative http_uri\"; "
1376
                               "content:\"test\"; "
1377
                               "http_uri; pcre:\"/abc/RU\"; sid:1;)");
1378
    FAIL_IF_NULL(de_ctx->sig_list);
1379
1380
    if (de_ctx != NULL)
1381
        SigCleanSignatures(de_ctx);
1382
    if (de_ctx != NULL)
1383
        DetectEngineCtxFree(de_ctx);
1384
    PASS;
1385
}
1386
1387
/** \test Check a signature with inconsistent pcre relative  */
1388
static int DetectPcreParseTest23(void)
1389
{
1390
    DetectEngineCtx *de_ctx = NULL;
1391
1392
    FAIL_IF( (de_ctx = DetectEngineCtxInit()) == NULL);
1393
1394
    de_ctx->flags |= DE_QUIET;
1395
    de_ctx->sig_list = SigInit(de_ctx,
1396
                               "alert tcp any any -> any any "
1397
                               "(msg:\"Testing inconsistent pcre relative\"; "
1398
                               "content:\"GET\"; "
1399
                               "http_cookie; pcre:\"/abc/RM\"; sid:1;)");
1400
    FAIL_IF_NOT_NULL(de_ctx->sig_list);
1401
1402
    if (de_ctx != NULL)
1403
        SigCleanSignatures(de_ctx);
1404
    if (de_ctx != NULL)
1405
        DetectEngineCtxFree(de_ctx);
1406
    PASS;
1407
}
1408
1409
/** \test Check a signature with inconsistent pcre modifiers  */
1410
static int DetectPcreParseTest24(void)
1411
{
1412
    DetectEngineCtx *de_ctx = NULL;
1413
1414
    FAIL_IF( (de_ctx = DetectEngineCtxInit()) == NULL);
1415
1416
    de_ctx->flags |= DE_QUIET;
1417
    de_ctx->sig_list = SigInit(de_ctx,
1418
                               "alert tcp any any -> any any "
1419
                               "(msg:\"Testing inconsistent pcre modifiers\"; "
1420
                               "pcre:\"/abc/UI\"; sid:1;)");
1421
    FAIL_IF_NOT_NULL(de_ctx->sig_list);
1422
1423
    if (de_ctx != NULL)
1424
        SigCleanSignatures(de_ctx);
1425
    if (de_ctx != NULL)
1426
        DetectEngineCtxFree(de_ctx);
1427
    PASS;
1428
}
1429
1430
/** \test Check a signature with inconsistent pcre modifiers  */
1431
static int DetectPcreParseTest25(void)
1432
{
1433
    DetectEngineCtx *de_ctx = NULL;
1434
1435
    FAIL_IF( (de_ctx = DetectEngineCtxInit()) == NULL);
1436
1437
    de_ctx->flags |= DE_QUIET;
1438
    de_ctx->sig_list = SigInit(de_ctx,
1439
                               "alert tcp any any -> any any "
1440
                               "(msg:\"Testing inconsistent pcre modifiers\"; "
1441
                               "pcre:\"/abc/DH\"; sid:1;)");
1442
    FAIL_IF_NOT_NULL(de_ctx->sig_list);
1443
1444
    if (de_ctx != NULL)
1445
        SigCleanSignatures(de_ctx);
1446
    if (de_ctx != NULL)
1447
        DetectEngineCtxFree(de_ctx);
1448
    PASS;
1449
}
1450
1451
/** \test Check a signature with inconsistent pcre modifiers  */
1452
static int DetectPcreParseTest26(void)
1453
{
1454
    DetectEngineCtx *de_ctx = NULL;
1455
1456
    FAIL_IF( (de_ctx = DetectEngineCtxInit()) == NULL);
1457
1458
    de_ctx->flags |= DE_QUIET;
1459
    de_ctx->sig_list = SigInit(de_ctx,
1460
                               "alert http any any -> any any "
1461
                               "(msg:\"Testing inconsistent pcre modifiers\"; "
1462
                               "pcre:\"/abc/F\"; sid:1;)");
1463
    FAIL_IF_NOT_NULL(de_ctx->sig_list);
1464
1465
    if (de_ctx != NULL)
1466
        SigCleanSignatures(de_ctx);
1467
    if (de_ctx != NULL)
1468
        DetectEngineCtxFree(de_ctx);
1469
    PASS;
1470
}
1471
1472
/** \test Bug 1098 */
1473
static int DetectPcreParseTest27(void)
1474
{
1475
    DetectEngineCtx *de_ctx = NULL;
1476
1477
    FAIL_IF( (de_ctx = DetectEngineCtxInit()) == NULL);
1478
1479
    de_ctx->flags |= DE_QUIET;
1480
    de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any 80 "
1481
            "(content:\"baduricontent\"; http_raw_uri; "
1482
            "pcre:\"/^[a-z]{5}\\.html/R\"; sid:2; rev:2;)");
1483
    FAIL_IF_NOT(de_ctx->sig_list == NULL);
1484
1485
    if (de_ctx != NULL)
1486
        SigCleanSignatures(de_ctx);
1487
    if (de_ctx != NULL)
1488
        DetectEngineCtxFree(de_ctx);
1489
    PASS;
1490
}
1491
1492
/** \test Bug 1957 */
1493
static int DetectPcreParseTest28(void)
1494
{
1495
    DetectEngineCtx *de_ctx = NULL;
1496
1497
    FAIL_IF( (de_ctx = DetectEngineCtxInit()) == NULL);
1498
1499
    de_ctx->flags |= DE_QUIET;
1500
    de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any 80 "
1501
            "(content:\"|2E|suricata\"; http_host; pcre:\"/\\x2Esuricata$/W\"; "
1502
            "sid:2; rev:2;)");
1503
    FAIL_IF_NULL(de_ctx->sig_list);
1504
1505
    DetectEngineCtxFree(de_ctx);
1506
    PASS;
1507
}
1508
1509
static int DetectPcreTestSig01(void)
1510
{
1511
    uint8_t *buf = (uint8_t *)"lalala lalala\\ lala\n";
1512
    uint16_t buflen = strlen((char *)buf);
1513
    Packet *p = UTHBuildPacket(buf, buflen, IPPROTO_TCP);
1514
    int result = 0;
1515
1516
    char sig[] = "alert tcp any any -> any any (msg:\"pcre with an ending slash\"; pcre:\"/ "
1517
                 "lalala\\\\/\"; sid:1;)";
1518
    if (UTHPacketMatchSig(p, sig) == 0) {
1519
        result = 0;
1520
        goto end;
1521
    }
1522
    result = 1;
1523
end:
1524
    if (p != NULL)
1525
        UTHFreePacket(p);
1526
    return result;
1527
}
1528
1529
/** \test anchored pcre */
1530
static int DetectPcreTestSig02(void)
1531
{
1532
    uint8_t *buf = (uint8_t *)"lalala\n";
1533
    uint16_t buflen = strlen((char *)buf);
1534
    Packet *p = UTHBuildPacket(buf, buflen, IPPROTO_TCP);
1535
1536
    char sig[] = "alert tcp any any -> any any (msg:\"pcre with an ending slash\"; "
1537
                 "pcre:\"/^(la)+$/\"; sid:1;)";
1538
    FAIL_IF(UTHPacketMatchSig(p, sig) == 0);
1539
1540
    if (p != NULL)
1541
        UTHFreePacket(p);
1542
    PASS;
1543
}
1544
1545
/** \test anchored pcre */
1546
static int DetectPcreTestSig03(void)
1547
{
1548
    /* test it also without ending in a newline "\n" */
1549
    uint8_t *buf = (uint8_t *)"lalala";
1550
    uint16_t buflen = strlen((char *)buf);
1551
    Packet *p = UTHBuildPacket(buf, buflen, IPPROTO_TCP);
1552
1553
    char sig[] = "alert tcp any any -> any any (msg:\"pcre with an ending slash\"; "
1554
                 "pcre:\"/^(la)+$/\"; sid:1;)";
1555
    FAIL_IF(UTHPacketMatchSig(p, sig) == 0);
1556
1557
    if (p != NULL)
1558
        UTHFreePacket(p);
1559
    PASS;
1560
}
1561
1562
/** \test Test tracking of body chunks per transactions (on requests)
1563
 */
1564
static int DetectPcreTxBodyChunksTest01(void)
1565
{
1566
    Flow f;
1567
    TcpSession ssn;
1568
    Packet *p = NULL;
1569
    uint8_t httpbuf1[] = "GET / HTTP/1.1\r\n";
1570
    uint8_t httpbuf2[] = "User-Agent: Mozilla/1.0\r\nContent-Length: 10\r\n";
1571
    uint8_t httpbuf3[] = "Cookie: dummy\r\n\r\n";
1572
    uint8_t httpbuf4[] = "Body one!!";
1573
    uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
1574
    uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
1575
    uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
1576
    uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */
1577
    uint8_t httpbuf5[] = "GET /?var=val HTTP/1.1\r\n";
1578
    uint8_t httpbuf6[] = "User-Agent: Firefox/1.0\r\n";
1579
    uint8_t httpbuf7[] = "Cookie: dummy2\r\nContent-Length: 10\r\n\r\nBody two!!";
1580
    uint32_t httplen5 = sizeof(httpbuf5) - 1; /* minus the \0 */
1581
    uint32_t httplen6 = sizeof(httpbuf6) - 1; /* minus the \0 */
1582
    uint32_t httplen7 = sizeof(httpbuf7) - 1; /* minus the \0 */
1583
    AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
1584
1585
    memset(&f, 0, sizeof(f));
1586
    memset(&ssn, 0, sizeof(ssn));
1587
1588
    p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
1589
1590
    FLOW_INITIALIZE(&f);
1591
    f.protoctx = (void *)&ssn;
1592
    f.proto = IPPROTO_TCP;
1593
    f.flags |= FLOW_IPV4;
1594
1595
    p->flow = &f;
1596
    p->flowflags |= FLOW_PKT_TOSERVER;
1597
    p->flowflags |= FLOW_PKT_ESTABLISHED;
1598
    p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST;
1599
    f.alproto = ALPROTO_HTTP1;
1600
1601
    StreamTcpInitConfig(true);
1602
1603
    AppLayerHtpEnableRequestBodyCallback();
1604
1605
    int r = AppLayerParserParse(
1606
            NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1);
1607
    FAIL_IF(r != 0);
1608
1609
    r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf2, httplen2);
1610
    FAIL_IF(r != 0);
1611
1612
    r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf3, httplen3);
1613
    FAIL_IF(r != 0);
1614
1615
    r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf4, httplen4);
1616
    FAIL_IF(r != 0);
1617
1618
    r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf5, httplen5);
1619
    FAIL_IF(r != 0);
1620
1621
    r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf6, httplen6);
1622
    FAIL_IF(r != 0);
1623
1624
    r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf7, httplen7);
1625
    FAIL_IF(r != 0);
1626
1627
    /* Now we should have 2 transactions, each with it's own list
1628
     * of request body chunks (let's test it) */
1629
1630
    HtpState *htp_state = f.alstate;
1631
    FAIL_IF(htp_state == NULL);
1632
1633
    /* hardcoded check of the transactions and it's client body chunks */
1634
    FAIL_IF(AppLayerParserGetTxCnt(&f, htp_state) != 2);
1635
1636
    htp_tx_t *t1 = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, htp_state, 0);
1637
    htp_tx_t *t2 = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, htp_state, 1);
1638
1639
    HtpTxUserData *htud = (HtpTxUserData *) htp_tx_get_user_data(t1);
1640
    FAIL_IF(htud == NULL);
1641
1642
    HtpBodyChunk *cur = htud->request_body.first;
1643
    FAIL_IF(htud->request_body.first == NULL);
1644
1645
    FAIL_IF(StreamingBufferSegmentCompareRawData(htud->request_body.sb, &cur->sbseg, (uint8_t *)"Body one!!", 10) != 1);
1646
1647
    htud = (HtpTxUserData *) htp_tx_get_user_data(t2);
1648
1649
    cur = htud->request_body.first;
1650
    FAIL_IF(htud->request_body.first == NULL);
1651
1652
    FAIL_IF(StreamingBufferSegmentCompareRawData(htud->request_body.sb, &cur->sbseg, (uint8_t *)"Body two!!", 10) != 1);
1653
1654
    if (alp_tctx != NULL)
1655
        AppLayerParserThreadCtxFree(alp_tctx);
1656
    StreamTcpFreeConfig(true);
1657
    FLOW_DESTROY(&f);
1658
    UTHFreePacket(p);
1659
    PASS;
1660
}
1661
1662
/** \test test pcre P modifier with multiple pipelined http transactions */
1663
static int DetectPcreTxBodyChunksTest02(void)
1664
{
1665
    Signature *s = NULL;
1666
    DetectEngineThreadCtx *det_ctx = NULL;
1667
    ThreadVars th_v;
1668
    Flow f;
1669
    TcpSession ssn;
1670
    Packet *p = NULL;
1671
    uint8_t httpbuf1[] = "POST / HTTP/1.1\r\n";
1672
    uint8_t httpbuf2[] = "User-Agent: Mozilla/1.0\r\nContent-Length: 10\r\n";
1673
    uint8_t httpbuf3[] = "Cookie: dummy\r\n\r\n";
1674
    uint8_t httpbuf4[] = "Body one!!";
1675
    uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
1676
    uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
1677
    uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
1678
    uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */
1679
    uint8_t httpbuf5[] = "GET /?var=val HTTP/1.1\r\n";
1680
    uint8_t httpbuf6[] = "User-Agent: Firefox/1.0\r\n";
1681
    uint8_t httpbuf7[] = "Cookie: dummy2\r\nContent-Length: 10\r\n\r\nBody two!!";
1682
    uint32_t httplen5 = sizeof(httpbuf5) - 1; /* minus the \0 */
1683
    uint32_t httplen6 = sizeof(httpbuf6) - 1; /* minus the \0 */
1684
    uint32_t httplen7 = sizeof(httpbuf7) - 1; /* minus the \0 */
1685
    AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
1686
1687
    memset(&th_v, 0, sizeof(th_v));
1688
    memset(&f, 0, sizeof(f));
1689
    memset(&ssn, 0, sizeof(ssn));
1690
1691
    p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
1692
1693
    FLOW_INITIALIZE(&f);
1694
    f.protoctx = (void *)&ssn;
1695
    f.proto = IPPROTO_TCP;
1696
    f.flags |= FLOW_IPV4;
1697
1698
    p->flow = &f;
1699
    p->flowflags |= FLOW_PKT_TOSERVER;
1700
    p->flowflags |= FLOW_PKT_ESTABLISHED;
1701
    p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST;
1702
    f.alproto = ALPROTO_HTTP1;
1703
1704
    StreamTcpInitConfig(true);
1705
1706
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1707
    FAIL_IF(de_ctx == NULL);
1708
1709
    de_ctx->flags |= DE_QUIET;
1710
1711
    s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"POST\"; http_method; content:\"Mozilla\"; http_header; content:\"dummy\"; http_cookie; pcre:\"/one/P\"; sid:1; rev:1;)");
1712
    FAIL_IF(s == NULL);
1713
    s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"GET\"; http_method; content:\"Firefox\"; http_header; content:\"dummy2\"; http_cookie; pcre:\"/two/P\"; sid:2; rev:1;)");
1714
    FAIL_IF(s == NULL);
1715
1716
    SigGroupBuild(de_ctx);
1717
    DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
1718
1719
    int r = AppLayerParserParse(
1720
            NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf1, httplen1);
1721
    FAIL_IF(r != 0);
1722
1723
    /* do detect */
1724
    SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1725
    FAIL_IF(PacketAlertCheck(p, 1));
1726
    p->alerts.cnt = 0;
1727
1728
    r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf2, httplen2);
1729
    FAIL_IF(r != 0);
1730
1731
    /* do detect */
1732
    SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1733
    FAIL_IF(PacketAlertCheck(p, 1));
1734
    p->alerts.cnt = 0;
1735
1736
    r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf3, httplen3);
1737
    FAIL_IF(r != 0);
1738
1739
    /* do detect */
1740
    SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1741
    FAIL_IF(PacketAlertCheck(p, 1));
1742
    p->alerts.cnt = 0;
1743
1744
    r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf4, httplen4);
1745
    FAIL_IF(r != 0);
1746
1747
    /* do detect */
1748
    SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1749
    FAIL_IF(!(PacketAlertCheck(p, 1)));
1750
    p->alerts.cnt = 0;
1751
1752
    r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf5, httplen5);
1753
    FAIL_IF(r != 0);
1754
1755
    /* do detect */
1756
    SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1757
    FAIL_IF(PacketAlertCheck(p, 1));
1758
    p->alerts.cnt = 0;
1759
1760
    r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf6, httplen6);
1761
    FAIL_IF(r != 0);
1762
1763
    /* do detect */
1764
    SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1765
    FAIL_IF((PacketAlertCheck(p, 1)) || (PacketAlertCheck(p, 2)));
1766
    p->alerts.cnt = 0;
1767
1768
    SCLogDebug("sending data chunk 7");
1769
1770
    r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf7, httplen7);
1771
    FAIL_IF(r != 0);
1772
1773
    /* do detect */
1774
    SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1775
    FAIL_IF(!(PacketAlertCheck(p, 2)));
1776
    p->alerts.cnt = 0;
1777
1778
    HtpState *htp_state = f.alstate;
1779
    FAIL_IF(htp_state == NULL);
1780
1781
    /* hardcoded check of the transactions and it's client body chunks */
1782
    FAIL_IF(AppLayerParserGetTxCnt(&f, htp_state) != 2);
1783
1784
    htp_tx_t *t1 = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, htp_state, 0);
1785
    htp_tx_t *t2 = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, htp_state, 1);
1786
1787
    HtpTxUserData *htud = (HtpTxUserData *) htp_tx_get_user_data(t1);
1788
1789
    HtpBodyChunk *cur = htud->request_body.first;
1790
    FAIL_IF(htud->request_body.first == NULL);
1791
1792
    FAIL_IF(StreamingBufferSegmentCompareRawData(htud->request_body.sb, &cur->sbseg, (uint8_t *)"Body one!!", 10) != 1);
1793
1794
    htud = (HtpTxUserData *) htp_tx_get_user_data(t2);
1795
1796
    cur = htud->request_body.first;
1797
    FAIL_IF(htud->request_body.first == NULL);
1798
1799
    FAIL_IF(StreamingBufferSegmentCompareRawData(htud->request_body.sb, &cur->sbseg, (uint8_t *)"Body two!!", 10) != 1);
1800
1801
    if (alp_tctx != NULL)
1802
        AppLayerParserThreadCtxFree(alp_tctx);
1803
    if (det_ctx != NULL) {
1804
        DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
1805
    }
1806
    if (de_ctx != NULL) {
1807
        SigGroupCleanup(de_ctx);
1808
        DetectEngineCtxFree(de_ctx);
1809
    }
1810
1811
    StreamTcpFreeConfig(true);
1812
    FLOW_DESTROY(&f);
1813
    UTHFreePacket(p);
1814
    PASS;
1815
}
1816
1817
/** \test multiple http transactions and body chunks of request handling */
1818
static int DetectPcreTxBodyChunksTest03(void)
1819
{
1820
    Signature *s = NULL;
1821
    DetectEngineThreadCtx *det_ctx = NULL;
1822
    ThreadVars th_v;
1823
    Flow f;
1824
    TcpSession ssn;
1825
    Packet *p = NULL;
1826
    uint8_t httpbuf1[] = "POST / HTTP/1.1\r\n";
1827
    uint8_t httpbuf2[] = "User-Agent: Mozilla/1.0\r\nContent-Length: 10\r\n";
1828
    uint8_t httpbuf3[] = "Cookie: dummy\r\n\r\n";
1829
    uint8_t httpbuf4[] = "Body one!!";
1830
    uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
1831
    uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
1832
    uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
1833
    uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */
1834
    uint8_t httpbuf5[] = "GET /?var=val HTTP/1.1\r\n";
1835
    uint8_t httpbuf6[] = "User-Agent: Firefox/1.0\r\n";
1836
    uint8_t httpbuf7[] = "Cookie: dummy2\r\nContent-Length: 10\r\n\r\nBody two!!";
1837
    uint32_t httplen5 = sizeof(httpbuf5) - 1; /* minus the \0 */
1838
    uint32_t httplen6 = sizeof(httpbuf6) - 1; /* minus the \0 */
1839
    uint32_t httplen7 = sizeof(httpbuf7) - 1; /* minus the \0 */
1840
    AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
1841
1842
    memset(&th_v, 0, sizeof(th_v));
1843
    memset(&f, 0, sizeof(f));
1844
    memset(&ssn, 0, sizeof(ssn));
1845
1846
    p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
1847
1848
    FLOW_INITIALIZE(&f);
1849
    f.protoctx = (void *)&ssn;
1850
    f.proto = IPPROTO_TCP;
1851
    f.flags |= FLOW_IPV4;
1852
1853
    p->flow = &f;
1854
    p->flowflags |= FLOW_PKT_TOSERVER;
1855
    p->flowflags |= FLOW_PKT_ESTABLISHED;
1856
    p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST;
1857
    f.alproto = ALPROTO_HTTP1;
1858
1859
    StreamTcpInitConfig(true);
1860
1861
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1862
    FAIL_IF(de_ctx == NULL);
1863
1864
    de_ctx->flags |= DE_QUIET;
1865
1866
    s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"POST\"; http_method; content:\"Mozilla\"; http_header; content:\"dummy\"; http_cookie; pcre:\"/one/P\"; sid:1; rev:1;)");
1867
    FAIL_IF(s == NULL);
1868
    s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"GET\"; http_method; content:\"Firefox\"; http_header; content:\"dummy2\"; http_cookie; pcre:\"/two/P\"; sid:2; rev:1;)");
1869
    FAIL_IF(s == NULL);
1870
1871
    SigGroupBuild(de_ctx);
1872
    DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
1873
1874
    int r = AppLayerParserParse(
1875
            NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf1, httplen1);
1876
    FAIL_IF(r != 0);
1877
1878
    /* do detect */
1879
    SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1880
    FAIL_IF(PacketAlertCheck(p, 1));
1881
    p->alerts.cnt = 0;
1882
1883
    r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf2, httplen2);
1884
    FAIL_IF(r != 0);
1885
1886
    /* do detect */
1887
    SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1888
    FAIL_IF(PacketAlertCheck(p, 1));
1889
    p->alerts.cnt = 0;
1890
1891
    r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf3, httplen3);
1892
    FAIL_IF(r != 0);
1893
1894
    /* do detect */
1895
    SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1896
    FAIL_IF(PacketAlertCheck(p, 1));
1897
    p->alerts.cnt = 0;
1898
1899
    r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf4, httplen4);
1900
    FAIL_IF(r != 0);
1901
1902
    /* do detect */
1903
    SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1904
    FAIL_IF(!(PacketAlertCheck(p, 1)));
1905
    p->alerts.cnt = 0;
1906
1907
    r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf5, httplen5);
1908
    FAIL_IF(r != 0);
1909
1910
    /* do detect */
1911
    SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1912
    FAIL_IF(PacketAlertCheck(p, 1));
1913
    p->alerts.cnt = 0;
1914
1915
    r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf6, httplen6);
1916
    FAIL_IF(r != 0);
1917
1918
    /* do detect */
1919
    SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1920
    FAIL_IF((PacketAlertCheck(p, 1)) || (PacketAlertCheck(p, 2)));
1921
    p->alerts.cnt = 0;
1922
1923
    SCLogDebug("sending data chunk 7");
1924
1925
    r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf7, httplen7);
1926
    FAIL_IF(r != 0);
1927
1928
    /* do detect */
1929
    SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1930
    FAIL_IF(!(PacketAlertCheck(p, 2)));
1931
    p->alerts.cnt = 0;
1932
1933
    HtpState *htp_state = f.alstate;
1934
    FAIL_IF(htp_state == NULL);
1935
1936
    FAIL_IF(AppLayerParserGetTxCnt(&f, htp_state) != 2);
1937
1938
    if (alp_tctx != NULL)
1939
        AppLayerParserThreadCtxFree(alp_tctx);
1940
    if (det_ctx != NULL) {
1941
        DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
1942
    }
1943
    if (de_ctx != NULL) {
1944
        SigGroupCleanup(de_ctx);
1945
        DetectEngineCtxFree(de_ctx);
1946
    }
1947
1948
    StreamTcpFreeConfig(true);
1949
    FLOW_DESTROY(&f);
1950
    UTHFreePacket(p);
1951
    PASS;
1952
}
1953
1954
/**
1955
 * \brief Test parsing of pcre's with the W modifier set.
1956
 */
1957
static int DetectPcreParseHttpHost(void)
1958
{
1959
    AppProto alproto = ALPROTO_UNKNOWN;
1960
    int list = DETECT_SM_LIST_NOTSET;
1961
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1962
1963
    FAIL_IF(de_ctx == NULL);
1964
1965
    DetectPcreData *pd = DetectPcreParse(de_ctx, "/domain\\.com/W", &list, NULL, 0, false, &alproto);
1966
    FAIL_IF(pd == NULL);
1967
    DetectPcreFree(de_ctx, pd);
1968
1969
    list = DETECT_SM_LIST_NOTSET;
1970
    pd = DetectPcreParse(de_ctx, "/dOmain\\.com/W", &list, NULL, 0, false, &alproto);
1971
    FAIL_IF(pd != NULL);
1972
1973
    /* Uppercase meta characters are valid. */
1974
    list = DETECT_SM_LIST_NOTSET;
1975
    pd = DetectPcreParse(de_ctx, "/domain\\D+\\.com/W", &list, NULL, 0, false, &alproto);
1976
    FAIL_IF(pd == NULL);
1977
    DetectPcreFree(de_ctx, pd);
1978
1979
    /* This should not parse as the first \ escapes the second \, then
1980
     * we have a D. */
1981
    list = DETECT_SM_LIST_NOTSET;
1982
    pd = DetectPcreParse(de_ctx, "/\\\\Ddomain\\.com/W", &list, NULL, 0, false, &alproto);
1983
    FAIL_IF(pd != NULL);
1984
1985
    DetectEngineCtxFree(de_ctx);
1986
    PASS;
1987
}
1988
1989
/**
1990
 * \brief Test parsing of capture extension
1991
 */
1992
static int DetectPcreParseCaptureTest(void)
1993
{
1994
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1995
    FAIL_IF(de_ctx == NULL);
1996
1997
    Signature *s = DetectEngineAppendSig(de_ctx, "alert http any any -> any any "
1998
            "(content:\"Server: \"; http_header; pcre:\"/(.*)\\r\\n/HR, flow:somecapture\"; content:\"xyz\"; http_header; sid:1;)");
1999
    FAIL_IF(s == NULL);
2000
    s = DetectEngineAppendSig(de_ctx, "alert http any any -> any any "
2001
            "(content:\"Server: \"; http_header; pcre:\"/(flow:.*)\\r\\n/HR\"; content:\"xyz\"; http_header; sid:2;)");
2002
    FAIL_IF(s == NULL);
2003
    s = DetectEngineAppendSig(de_ctx, "alert http any any -> any any "
2004
            "(content:\"Server: \"; http_header; pcre:\"/([a-z]+)([0-9]+)\\r\\n/HR, flow:somecapture, pkt:anothercap\"; content:\"xyz\"; http_header; sid:3;)");
2005
    FAIL_IF(s == NULL);
2006
    s = DetectEngineAppendSig(de_ctx,
2007
            "alert http any any -> any any "
2008
            "(content:\"Server: \"; http_header; pcre:\"/([a-z]+)\\r\\n/HR, flow:somecapture, "
2009
            "pkt:anothercap\"; content:\"xyz\"; http_header; sid:3;)");
2010
    FAIL_IF_NOT_NULL(s);
2011
2012
    SigGroupBuild(de_ctx);
2013
2014
    uint32_t capid1 = VarNameStoreLookupByName("somecapture", VAR_TYPE_FLOW_VAR);
2015
    FAIL_IF(capid1 == 0);
2016
    uint32_t capid2 = VarNameStoreLookupByName("anothercap", VAR_TYPE_PKT_VAR);
2017
    FAIL_IF(capid2 == 0);
2018
    FAIL_IF(capid1 == capid2);
2019
2020
    DetectEngineCtxFree(de_ctx);
2021
    PASS;
2022
}
2023
2024
/**
2025
 * \brief this function registers unit tests for DetectPcre
2026
 */
2027
static void DetectPcreRegisterTests(void)
2028
{
2029
    g_file_data_buffer_id = DetectBufferTypeGetByName("file_data");
2030
    g_http_header_buffer_id = DetectBufferTypeGetByName("http_header");
2031
    g_dce_stub_data_buffer_id = DetectBufferTypeGetByName("dce_stub_data");
2032
2033
    UtRegisterTest("DetectPcreParseTest01", DetectPcreParseTest01);
2034
    UtRegisterTest("DetectPcreParseTest02", DetectPcreParseTest02);
2035
    UtRegisterTest("DetectPcreParseTest03", DetectPcreParseTest03);
2036
    UtRegisterTest("DetectPcreParseTest04", DetectPcreParseTest04);
2037
    UtRegisterTest("DetectPcreParseTest05", DetectPcreParseTest05);
2038
    UtRegisterTest("DetectPcreParseTest06", DetectPcreParseTest06);
2039
    UtRegisterTest("DetectPcreParseTest07", DetectPcreParseTest07);
2040
    UtRegisterTest("DetectPcreParseTest08", DetectPcreParseTest08);
2041
    UtRegisterTest("DetectPcreParseTest09", DetectPcreParseTest09);
2042
    UtRegisterTest("DetectPcreParseTest10", DetectPcreParseTest10);
2043
    UtRegisterTest("DetectPcreParseTest15", DetectPcreParseTest15);
2044
    UtRegisterTest("DetectPcreParseTest16", DetectPcreParseTest16);
2045
    UtRegisterTest("DetectPcreParseTest17", DetectPcreParseTest17);
2046
    UtRegisterTest("DetectPcreParseTest18", DetectPcreParseTest18);
2047
    UtRegisterTest("DetectPcreParseTest19", DetectPcreParseTest19);
2048
    UtRegisterTest("DetectPcreParseTest20", DetectPcreParseTest20);
2049
    UtRegisterTest("DetectPcreParseTest21", DetectPcreParseTest21);
2050
    UtRegisterTest("DetectPcreParseTest22", DetectPcreParseTest22);
2051
    UtRegisterTest("DetectPcreParseTest23", DetectPcreParseTest23);
2052
    UtRegisterTest("DetectPcreParseTest24", DetectPcreParseTest24);
2053
    UtRegisterTest("DetectPcreParseTest25", DetectPcreParseTest25);
2054
    UtRegisterTest("DetectPcreParseTest26", DetectPcreParseTest26);
2055
    UtRegisterTest("DetectPcreParseTest27", DetectPcreParseTest27);
2056
    UtRegisterTest("DetectPcreParseTest28", DetectPcreParseTest28);
2057
2058
    UtRegisterTest("DetectPcreTestSig01", DetectPcreTestSig01);
2059
    UtRegisterTest("DetectPcreTestSig02 -- anchored pcre", DetectPcreTestSig02);
2060
    UtRegisterTest("DetectPcreTestSig03 -- anchored pcre", DetectPcreTestSig03);
2061
2062
    UtRegisterTest("DetectPcreTxBodyChunksTest01",
2063
                   DetectPcreTxBodyChunksTest01);
2064
    UtRegisterTest("DetectPcreTxBodyChunksTest02 -- modifier P, body chunks per tx",
2065
                   DetectPcreTxBodyChunksTest02);
2066
    UtRegisterTest("DetectPcreTxBodyChunksTest03 -- modifier P, body chunks per tx",
2067
                   DetectPcreTxBodyChunksTest03);
2068
2069
    UtRegisterTest("DetectPcreParseHttpHost", DetectPcreParseHttpHost);
2070
    UtRegisterTest("DetectPcreParseCaptureTest", DetectPcreParseCaptureTest);
2071
2072
}
2073
#endif /* UNITTESTS */