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