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