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