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