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