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