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