suricata
detect-content.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  * Simple content match part of the detection engine.
24  */
25 
26 #include "suricata-common.h"
27 #include "decode.h"
28 #include "detect.h"
29 #include "detect-content.h"
30 #include "detect-uricontent.h"
31 #include "detect-engine-mpm.h"
32 #include "detect-engine.h"
33 #include "detect-engine-buffer.h"
34 #include "detect-engine-build.h"
35 #include "detect-engine-state.h"
36 #include "detect-parse.h"
37 #include "detect-pcre.h"
38 #include "util-mpm.h"
39 #include "flow.h"
40 #include "flow-util.h"
41 #include "flow-var.h"
42 #include "detect-flow.h"
43 #include "app-layer.h"
44 #include "util-unittest.h"
45 #include "util-print.h"
46 #include "util-debug.h"
47 #include "util-spm.h"
48 #include "threads.h"
49 #include "util-unittest-helper.h"
50 #include "pkt-var.h"
51 #include "host.h"
52 #include "util-profiling.h"
53 #include "detect-dsize.h"
54 
55 #ifdef UNITTESTS
56 static void DetectContentRegisterTests(void);
57 #endif
58 
60 {
61  sigmatch_table[DETECT_CONTENT].name = "content";
62  sigmatch_table[DETECT_CONTENT].desc = "match on payload content";
63  sigmatch_table[DETECT_CONTENT].url = "/rules/payload-keywords.html#content";
67 #ifdef UNITTESTS
68  sigmatch_table[DETECT_CONTENT].RegisterTests = DetectContentRegisterTests;
69 #endif
72 }
73 
74 /**
75  * \brief Parse a content string, ie "abc|DE|fgh"
76  *
77  * \param content_str null terminated string containing the content
78  * \param result result pointer to pass the fully parsed byte array
79  * \param result_len size of the resulted data
80  * \param flags flags to be set by this parsing function
81  *
82  * \retval -1 error
83  * \retval 0 ok
84  */
85 int DetectContentDataParse(const char *keyword, const char *contentstr,
86  uint8_t **pstr, uint16_t *plen)
87 {
88  char *str = NULL;
89  size_t slen = 0;
90 
91  slen = strlen(contentstr);
92  if (slen == 0) {
93  return -1;
94  }
95  uint8_t buffer[slen + 1];
96  strlcpy((char *)&buffer, contentstr, slen + 1);
97  str = (char *)buffer;
98 
99  SCLogDebug("\"%s\", len %" PRIuMAX, str, (uintmax_t)slen);
100 
101  //SCLogDebug("DetectContentParse: \"%s\", len %" PRIu32 "", str, len);
102  char converted = 0;
103 
104  {
105  size_t i, x;
106  uint8_t bin = 0;
107  uint8_t escape = 0;
108  uint8_t binstr[3] = "";
109  uint8_t binpos = 0;
110  uint16_t bin_count = 0;
111 
112  for (i = 0, x = 0; i < slen; i++) {
113  // SCLogDebug("str[%02u]: %c", i, str[i]);
114  if (str[i] == '|') {
115  bin_count++;
116  if (bin) {
117  if (binpos > 0) {
118  SCLogError("Incomplete hex code in content - %s. Invalidating signature.",
119  contentstr);
120  goto error;
121  }
122  bin = 0;
123  } else {
124  bin = 1;
125  }
126  } else if(!escape && str[i] == '\\') {
127  escape = 1;
128  } else {
129  if (bin) {
130  if (isdigit((unsigned char)str[i]) ||
131  str[i] == 'A' || str[i] == 'a' ||
132  str[i] == 'B' || str[i] == 'b' ||
133  str[i] == 'C' || str[i] == 'c' ||
134  str[i] == 'D' || str[i] == 'd' ||
135  str[i] == 'E' || str[i] == 'e' ||
136  str[i] == 'F' || str[i] == 'f')
137  {
138  // SCLogDebug("part of binary: %c", str[i]);
139 
140  binstr[binpos] = (char)str[i];
141  binpos++;
142 
143  if (binpos == 2) {
144  uint8_t c = strtol((char *)binstr, (char **) NULL, 16) & 0xFF;
145  binpos = 0;
146  str[x] = c;
147  x++;
148  converted = 1;
149  }
150  } else if (str[i] == ' ') {
151  // SCLogDebug("space as part of binary string");
152  }
153  else if (str[i] != ',') {
154  SCLogError("Invalid hex code in "
155  "content - %s, hex %c. Invalidating signature.",
156  contentstr, str[i]);
157  goto error;
158  }
159  } else if (escape) {
160  if (str[i] == ':' ||
161  str[i] == ';' ||
162  str[i] == '\\' ||
163  str[i] == '\"')
164  {
165  str[x] = str[i];
166  x++;
167  } else {
168  SCLogError("'%c' has to be escaped", str[i - 1]);
169  goto error;
170  }
171  escape = 0;
172  converted = 1;
173  } else if (str[i] == '"') {
174  SCLogError("Invalid unescaped double quote within content section.");
175  goto error;
176  } else {
177  str[x] = str[i];
178  x++;
179  }
180  }
181  }
182 
183  if (bin_count % 2 != 0) {
184  SCLogError("Invalid hex code assembly in "
185  "%s - %s. Invalidating signature.",
186  keyword, contentstr);
187  goto error;
188  }
189 
190  if (converted) {
191  slen = x;
192  }
193  }
194 
195  if (slen) {
196  uint8_t *ptr = SCCalloc(1, slen);
197  if (ptr == NULL) {
198  return -1;
199  }
200  memcpy(ptr, str, slen);
201 
202  *plen = (uint16_t)slen;
203  *pstr = ptr;
204  return 0;
205  }
206 error:
207  return -1;
208 }
209 /**
210  * \brief DetectContentParse
211  * \initonly
212  */
214  const char *contentstr)
215 {
216  DetectContentData *cd = NULL;
217  uint8_t *content = NULL;
218  uint16_t len = 0;
219  int ret;
220 
221  ret = DetectContentDataParse("content", contentstr, &content, &len);
222  if (ret == -1) {
223  return NULL;
224  }
225 
226  cd = SCCalloc(1, sizeof(DetectContentData) + len);
227  if (unlikely(cd == NULL)) {
228  SCFree(content);
229  exit(EXIT_FAILURE);
230  }
231 
232  cd->content = (uint8_t *)cd + sizeof(DetectContentData);
233  memcpy(cd->content, content, len);
234  cd->content_len = len;
235 
236  /* Prepare SPM search context. */
237  cd->spm_ctx = SpmInitCtx(cd->content, cd->content_len, 0,
238  spm_global_thread_ctx);
239  if (cd->spm_ctx == NULL) {
240  SCFree(content);
241  SCFree(cd);
242  return NULL;
243  }
244 
245  cd->depth = 0;
246  cd->offset = 0;
247  cd->within = 0;
248  cd->distance = 0;
249 
250  SCFree(content);
251  return cd;
252 
253 }
254 
256  const char *contentstr)
257 {
258  return DetectContentParse(spm_global_thread_ctx, contentstr);
259 }
260 
261 /**
262  * \brief Helper function to print a DetectContentData
263  */
265 {
266  int i = 0;
267  if (cd == NULL) {
268  SCLogDebug("DetectContentData \"cd\" is NULL");
269  return;
270  }
271  char *tmpstr = SCMalloc(sizeof(char) * cd->content_len + 1);
272  if (tmpstr != NULL) {
273  for (i = 0; i < cd->content_len; i++) {
274  if (isprint(cd->content[i]))
275  tmpstr[i] = cd->content[i];
276  else
277  tmpstr[i] = '.';
278  }
279  tmpstr[i] = '\0';
280  SCLogDebug("Content: \"%s\"", tmpstr);
281  SCFree(tmpstr);
282  } else {
283  SCLogDebug("Content: ");
284  for (i = 0; i < cd->content_len; i++)
285  SCLogDebug("%c", cd->content[i]);
286  }
287 
288  SCLogDebug("Content_id: %"PRIu32, cd->id);
289  SCLogDebug("Content_len: %"PRIu16, cd->content_len);
290  SCLogDebug("Depth: %"PRIu16, cd->depth);
291  SCLogDebug("Offset: %"PRIu16, cd->offset);
292  SCLogDebug("Within: %"PRIi32, cd->within);
293  SCLogDebug("Distance: %"PRIi32, cd->distance);
294  SCLogDebug("flags: %u ", cd->flags);
295  SCLogDebug("negated: %s ", cd->flags & DETECT_CONTENT_NEGATED ? "true" : "false");
296  SCLogDebug("relative match next: %s ", cd->flags & DETECT_CONTENT_RELATIVE_NEXT ? "true" : "false");
297 
298  if (cd->replace && cd->replace_len) {
299  char *tmprstr = SCMalloc(sizeof(char) * cd->replace_len + 1);
300 
301  if (tmprstr != NULL) {
302  for (i = 0; i < cd->replace_len; i++) {
303  if (isprint(cd->replace[i]))
304  tmprstr[i] = cd->replace[i];
305  else
306  tmprstr[i] = '.';
307  }
308  tmprstr[i] = '\0';
309  SCLogDebug("Replace: \"%s\"", tmprstr);
310  SCFree(tmprstr);
311  } else {
312  SCLogDebug("Replace: ");
313  for (i = 0; i < cd->replace_len; i++)
314  SCLogDebug("%c", cd->replace[i]);
315  }
316  }
317  SCLogDebug("-----------");
318 }
319 
320 /**
321  * \brief Function to setup a content pattern.
322  *
323  * \param de_ctx pointer to the current detection_engine
324  * \param s pointer to the current Signature
325  * \param m pointer to the last parsed SigMatch
326  * \param contentstr pointer to the current keyword content string
327  * \retval -1 if error
328  * \retval 0 if all was ok
329  */
330 int DetectContentSetup(DetectEngineCtx *de_ctx, Signature *s, const char *contentstr)
331 {
333  if (cd == NULL)
334  goto error;
335  if (s->init_data->negated) {
337  }
338 
339  DetectContentPrint(cd);
340 
341  if (DetectBufferGetActiveList(de_ctx, s) == -1)
342  goto error;
343 
344  int sm_list = s->init_data->list;
345  if (sm_list == DETECT_SM_LIST_NOTSET) {
346  sm_list = DETECT_SM_LIST_PMATCH;
347  } else if (sm_list > DETECT_SM_LIST_MAX &&
348  0 == (cd->flags & DETECT_CONTENT_NEGATED)) {
349  /* Check transform compatibility */
350  const char *tstr;
352  de_ctx, sm_list, cd->content, cd->content_len, &tstr)) {
353  SCLogError("content string \"%s\" incompatible with %s transform", contentstr, tstr);
354  goto error;
355  }
356  }
357 
358  if (SCSigMatchAppendSMToList(de_ctx, s, DETECT_CONTENT, (SigMatchCtx *)cd, sm_list) == NULL) {
359  goto error;
360  }
361 
362  return 0;
363 
364 error:
366  return -1;
367 }
368 
369 /**
370  * \brief this function will SCFree memory associated with DetectContentData
371  *
372  * \param cd pointer to DetectContentData
373  */
375 {
376  SCEnter();
378 
379  if (cd == NULL)
380  SCReturn;
381 
382  SpmDestroyCtx(cd->spm_ctx);
383 
384  SCFree(cd);
385  SCReturn;
386 }
387 
388 /**
389  * \brief Determine the size needed to accommodate the content
390  * elements of a signature
391  * \param s signature to get dsize value from
392  * \param max_size Maximum buffer/data size allowed.
393  * \param list signature match list.
394  * \param len Maximum length required
395  * \param offset Maximum offset encountered
396  *
397  * Note that negated content does not contribute to the maximum
398  * required size value. However, each negated content's values
399  * must not exceed the size value.
400  *
401  * Values from negated content blocks are used to determine if the
402  * negated content block requires a value that exceeds "max_size". The
403  * distance and within values from negated content blocks are added to
404  * the running total of required content size to see if the max_size
405  * would be exceeded.
406  *
407  * - Non-negated content contributes to the required size (content length, distance)
408  * - Negated content values are checked but not accumulated for the required size.
409  */
411  const Signature *s, const uint64_t max_size, const SigMatch *sm, int *len, int *offset)
412 {
413  int max_offset = 0, total_len = 0;
414  bool first = true;
415  // define it first, and override it unless in DETECT_CONTENT_NEGATED edge case
416  *offset = 0;
417  for (; sm != NULL; sm = sm->next) {
418  if (sm->type != DETECT_CONTENT || sm->ctx == NULL) {
419  continue;
420  }
421 
423  SCLogDebug("content_len %d; negated: %s; distance: %d, offset: %d, depth: %d",
424  cd->content_len, cd->flags & DETECT_CONTENT_NEGATED ? "yes" : "no", cd->distance,
425  cd->offset, cd->depth);
426 
427  if (!first) {
428  /* only count content with relative modifiers */
429  if (!((cd->flags & DETECT_CONTENT_DISTANCE) || (cd->flags & DETECT_CONTENT_WITHIN)))
430  continue;
431 
432  if (cd->flags & DETECT_CONTENT_NEGATED) {
433  /* Check if distance/within cause max to be exceeded */
434  int check = total_len + cd->distance + cd->within;
435  if (max_size < (uint64_t)check) {
436  *len = check;
437  return;
438  }
439 
440  continue;
441  }
442  }
443  SCLogDebug("content_len %d; distance: %d, offset: %d, depth: %d", cd->content_len,
444  cd->distance, cd->offset, cd->depth);
445  total_len += cd->content_len + cd->distance;
446  max_offset = MAX(max_offset, cd->offset);
447  first = false;
448  }
449 
450  *len = total_len;
451  *offset = max_offset;
452 }
453 
454 /**
455  * \retval true valid
456  * \retval false invalid
457  */
459 {
460  if (!(s->flags & SIG_FLAG_DSIZE)) {
461  return true;
462  }
463 
464  uint16_t max_right_edge_i;
465  if (SigParseGetMaxDsize(s, &max_right_edge_i) < 0) {
466  return true;
467  }
468  uint32_t max_right_edge = max_right_edge_i;
469 
470  int min_dsize_required = SigParseMaxRequiredDsize(s);
471  if (min_dsize_required >= 0) {
472  SCLogDebug("min_dsize %d; max_right_edge %d", min_dsize_required, max_right_edge);
473  if ((uint32_t)min_dsize_required > max_right_edge) {
474  SCLogError("signature can't match as required content length %d exceeds dsize value %d",
475  min_dsize_required, max_right_edge);
476  return false;
477  }
478  }
479 
480  return true;
481 }
482 
483 /** \brief apply depth/offset and distance/within to content matches
484  *
485  * The idea is that any limitation we can set is a win, as the mpm
486  * can use this to reduce match candidates.
487  *
488  * E.g. if we have 'content:"1"; depth:1; content:"2"; distance:0; within:1;'
489  * we know that we can add 'offset:1; depth:2;' to the 2nd condition. This
490  * will then be used in mpm if the 2nd condition would be selected for mpm.
491  *
492  * Another example: 'content:"1"; depth:1; content:"2"; distance:0;'. Here we
493  * cannot set a depth, but we can set an offset of 'offset:1;'. This will
494  * make the mpm a bit more precise.
495  */
496 static void PropagateLimits(Signature *s, SigMatch *sm_head)
497 {
498 #define VALIDATE(e) \
499  if (!(e)) { \
500  return; \
501  }
502  uint16_t offset = 0;
503  uint16_t offset_plus_pat = 0;
504  uint16_t depth = 0;
505  bool has_active_depth_chain = false;
506 
507  bool has_depth = false;
508  bool has_ends_with = false;
509  uint16_t ends_with_depth = 0;
510 
511  for (SigMatch *sm = sm_head; sm != NULL; sm = sm->next) {
512  switch (sm->type) {
513  case DETECT_CONTENT: {
514  DetectContentData *cd = (DetectContentData *)sm->ctx;
517  offset = depth = 0;
518  offset_plus_pat = cd->content_len;
519  SCLogDebug("reset");
520  has_active_depth_chain = false;
521  continue;
522  }
523  if (sm->prev == NULL) {
524  if (cd->distance >= 0 && cd->distance <= (int32_t)USHRT_MAX &&
525  cd->within >= 0 && cd->within <= (int32_t)USHRT_MAX) {
526  if (cd->flags & DETECT_CONTENT_DISTANCE) {
527  if (cd->distance > 0)
530  cd->offset = (uint16_t)cd->distance;
531  cd->distance = 0;
533  }
534  if (cd->flags & DETECT_CONTENT_WITHIN) {
537  cd->depth = (uint16_t)cd->within + cd->offset;
538  cd->within = 0;
540  }
541  }
542  }
543 
544  if (cd->flags & DETECT_CONTENT_NEGATED) {
545  offset = depth = 0;
546  offset_plus_pat = 0;
547  SCLogDebug("reset because of negation");
548  has_active_depth_chain = false;
549  continue;
550  }
551 
552  if (cd->depth) {
553  has_depth = true;
554  has_active_depth_chain = true;
555  }
556 
557  SCLogDebug("sm %p depth %u offset %u distance %d within %d", sm, cd->depth,
558  cd->offset, cd->distance, cd->within);
559  SCLogDebug("stored: offset %u depth %u offset_plus_pat %u", offset, depth,
560  offset_plus_pat);
561 
562  if ((cd->flags & (DETECT_CONTENT_DEPTH | DETECT_CONTENT_WITHIN)) == 0) {
563  if (depth)
564  SCLogDebug("no within, reset depth");
565  depth = 0;
566  has_active_depth_chain = false;
567  }
568  if ((cd->flags & DETECT_CONTENT_DISTANCE) == 0) {
569  if (offset_plus_pat)
570  SCLogDebug("no distance, reset offset_plus_pat & offset");
571  offset_plus_pat = offset = 0;
572  }
573 
574  SCLogDebug("stored: offset %u depth %u offset_plus_pat %u "
575  "has_active_depth_chain %s",
576  offset, depth, offset_plus_pat, has_active_depth_chain ? "true" : "false");
577  if (cd->flags & DETECT_CONTENT_DISTANCE) {
578  if (cd->distance >= 0) {
579  VALIDATE((uint32_t)offset_plus_pat + cd->distance <= UINT16_MAX);
580  offset = cd->offset = (uint16_t)(offset_plus_pat + cd->distance);
581  SCLogDebug("distance %d: updated content to have offset %u", cd->distance,
582  cd->offset);
583  } else {
584  if (abs(cd->distance) > offset_plus_pat)
585  offset = cd->offset = 0;
586  else
587  offset = cd->offset = (uint16_t)(offset_plus_pat + cd->distance);
588  offset_plus_pat = offset + cd->content_len;
589  SCLogDebug("distance %d: updated content to have offset %u", cd->distance,
590  cd->offset);
591  }
592  }
593  if (has_active_depth_chain) {
594  if (offset_plus_pat && cd->flags & DETECT_CONTENT_WITHIN && cd->within >= 0) {
595  if (depth && depth > offset_plus_pat) {
596  int32_t dist = 0;
597  if (cd->flags & DETECT_CONTENT_DISTANCE && cd->distance > 0) {
598  dist = cd->distance;
599  SCLogDebug(
600  "distance to add: %u. depth + dist %u", dist, depth + dist);
601  }
602  SCLogDebug("depth %u + cd->within %u", depth, cd->within);
603  VALIDATE(depth + cd->within + dist >= 0 &&
604  depth + cd->within + dist <= UINT16_MAX);
605  depth = cd->depth = (uint16_t)(depth + cd->within + dist);
606  } else if ((cd->flags & DETECT_CONTENT_DISTANCE_VAR) == 0) {
607  // we cannot know the depth yet if it comes from a var
608  SCLogDebug("offset %u + cd->within %u", offset, cd->within);
609  VALIDATE(depth + cd->within >= 0 && depth + cd->within <= UINT16_MAX);
610  depth = cd->depth = (uint16_t)(offset + cd->within);
611  }
612  SCLogDebug("updated content to have depth %u", cd->depth);
613  } else {
614  if (cd->depth == 0 && depth != 0) {
615  if (cd->within > 0) {
616  SCLogDebug("within %d distance %d", cd->within, cd->distance);
617  if (cd->flags & DETECT_CONTENT_DISTANCE && cd->distance >= 0) {
618  VALIDATE(offset_plus_pat + cd->distance >= 0 &&
619  offset_plus_pat + cd->distance <= UINT16_MAX);
620  cd->offset = (uint16_t)(offset_plus_pat + cd->distance);
621  SCLogDebug("updated content to have offset %u", cd->offset);
622  }
623 
624  VALIDATE(depth + cd->within >= 0 &&
625  depth + cd->within <= UINT16_MAX);
626  depth = cd->depth = (uint16_t)(cd->within + depth);
627  SCLogDebug("updated content to have depth %u", cd->depth);
628 
629  if (cd->flags & DETECT_CONTENT_ENDS_WITH) {
630  has_ends_with = true;
631  if (ends_with_depth == 0)
632  ends_with_depth = depth;
633  ends_with_depth = MIN(ends_with_depth, depth);
634  }
635  }
636  }
637  }
638  }
639  if (cd->offset == 0) { // && offset != 0) {
640  if (cd->flags & DETECT_CONTENT_DISTANCE && cd->distance >= 0) {
641  cd->offset = offset_plus_pat;
642  SCLogDebug("update content to have offset %u", cd->offset);
643  }
644  }
645 
652  if (cd->distance >= 0) {
653  // only distance
654  VALIDATE((uint32_t)offset_plus_pat + cd->distance <= UINT16_MAX);
655  offset = cd->offset = (uint16_t)(offset_plus_pat + cd->distance);
656  offset_plus_pat = offset + cd->content_len;
657  SCLogDebug("offset %u offset_plus_pat %u", offset, offset_plus_pat);
658  }
659  }
660  if (cd->flags & DETECT_CONTENT_OFFSET) {
661  offset = cd->offset;
662  offset_plus_pat = offset + cd->content_len;
663  SCLogDebug("stored offset %u offset_plus_pat %u", offset, offset_plus_pat);
664  }
665  if (cd->depth) {
666  depth = cd->depth;
667  SCLogDebug("stored depth now %u", depth);
668  offset_plus_pat = offset + cd->content_len;
669  if (cd->flags & DETECT_CONTENT_ENDS_WITH) {
670  has_ends_with = true;
671  if (ends_with_depth == 0)
672  ends_with_depth = depth;
673  ends_with_depth = MIN(ends_with_depth, depth);
674  }
675  }
676  if ((cd->flags & (DETECT_CONTENT_WITHIN | DETECT_CONTENT_DEPTH)) == 0) {
677  has_active_depth_chain = false;
678  depth = 0;
679  }
680  break;
681  }
682  case DETECT_PCRE: {
683  // relative could leave offset_plus_pat set.
684  const DetectPcreData *pd = (const DetectPcreData *)sm->ctx;
685  if (pd->flags & DETECT_PCRE_RELATIVE) {
686  depth = 0;
687  } else {
688  SCLogDebug("non-anchored PCRE not supported, reset offset_plus_pat & offset");
689  offset_plus_pat = offset = depth = 0;
690  }
691  has_active_depth_chain = false;
692  break;
693  }
694  default:
695  SCLogDebug("keyword not supported, reset offset_plus_pat & offset");
696  offset_plus_pat = offset = depth = 0;
697  has_active_depth_chain = false;
698  break;
699  }
700  }
701  /* apply anchored 'ends with' as depth to all patterns */
702  if (has_depth && has_ends_with) {
703  for (SigMatch *sm = sm_head; sm != NULL; sm = sm->next) {
704  switch (sm->type) {
705  case DETECT_CONTENT: {
706  DetectContentData *cd = (DetectContentData *)sm->ctx;
707  if (cd->depth == 0)
708  cd->depth = ends_with_depth;
709  cd->depth = MIN(ends_with_depth, cd->depth);
710  if (cd->depth)
712  break;
713  }
714  }
715  }
716  }
717 #undef VALIDATE
718 }
719 
721 {
722  PropagateLimits(s, s->init_data->smlists[DETECT_SM_LIST_PMATCH]);
723  for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
724  PropagateLimits(s, s->init_data->buffers[x].head);
725  }
726 }
727 
728 static inline bool NeedsAsHex(uint8_t c)
729 {
730  if (!isprint(c))
731  return true;
732 
733  switch (c) {
734  case '/':
735  case ';':
736  case ':':
737  case '\\':
738  case ' ':
739  case '|':
740  case '"':
741  case '`':
742  case '\'':
743  return true;
744  }
745  return false;
746 }
747 
748 void DetectContentPatternPrettyPrint(const DetectContentData *cd, char *str, size_t str_len)
749 {
750  bool hex = false;
751  for (uint16_t i = 0; i < cd->content_len; i++) {
752  if (NeedsAsHex(cd->content[i])) {
753  char hex_str[4];
754  snprintf(hex_str, sizeof(hex_str), "%s%02X", !hex ? "|" : " ", cd->content[i]);
755  strlcat(str, hex_str, str_len);
756  hex = true;
757  } else {
758  char p_str[3];
759  snprintf(p_str, sizeof(p_str), "%s%c", hex ? "|" : "", cd->content[i]);
760  strlcat(str, p_str, str_len);
761  hex = false;
762  }
763  }
764  if (hex) {
765  strlcat(str, "|", str_len);
766  }
767 }
768 
770 {
771  if (cd->flags & DETECT_CONTENT_NOCASE) {
772  SCLogError("can't use multiple nocase modifiers with the same content");
773  return -1;
774  }
775 
776  /* for consistency in later use (e.g. by MPM construction and hashing),
777  * coerce the content string to lower-case. */
778  for (uint8_t *c = cd->content; c < cd->content + cd->content_len; c++) {
779  *c = u8_tolower(*c);
780  }
781 
783  /* Recreate the context with nocase chars */
784  SpmDestroyCtx(cd->spm_ctx);
786  if (cd->spm_ctx == NULL) {
787  return -1;
788  }
789  return 0;
790 }
791 
792 #ifdef UNITTESTS /* UNITTESTS */
793 #include "detect-engine-alert.h"
794 #include "packet.h"
795 
796 static bool TestLastContent(const Signature *s, uint16_t o, uint16_t d)
797 {
799  if (!sm) {
800  SCLogDebug("no sm");
801  return false;
802  }
803  if (!(sm->type == DETECT_CONTENT)) {
804  SCLogDebug("not content");
805  return false;
806  }
807  const DetectContentData *cd = (const DetectContentData *)sm->ctx;
808  if (o != cd->offset) {
809  SCLogDebug("offset mismatch %u != %u", o, cd->offset);
810  return false;
811  }
812  if (d != cd->depth) {
813  SCLogDebug("depth mismatch %u != %u", d, cd->depth);
814  return false;
815  }
816  return true;
817 }
818 
819 #define TEST_RUN(sig, o, d) \
820  { \
821  SCLogDebug("TEST_RUN start: '%s'", (sig)); \
822  DetectEngineCtx *de_ctx = DetectEngineCtxInit(); \
823  FAIL_IF_NULL(de_ctx); \
824  de_ctx->flags |= DE_QUIET; \
825  char rule[2048]; \
826  snprintf(rule, sizeof(rule), "alert tcp any any -> any any (%s sid:1; rev:1;)", (sig)); \
827  Signature *s = DetectEngineAppendSig(de_ctx, rule); \
828  FAIL_IF_NULL(s); \
829  SigPrepareStage1(de_ctx); \
830  bool res = TestLastContent(s, (o), (d)); \
831  FAIL_IF_NOT(res); \
832  DetectEngineCtxFree(de_ctx); \
833  }
834 
835 #define TEST_DONE \
836  PASS
837 
838 /** \test test propagation of depth/offset/distance/within */
839 static int DetectContentDepthTest01(void)
840 {
841  // straight depth/offset
842  TEST_RUN("content:\"abc\"; offset:1; depth:3;", 1, 4);
843  // dsize applied as depth
844  TEST_RUN("dsize:10; content:\"abc\";", 0, 10);
845  TEST_RUN("dsize:<10; content:\"abc\";", 0, 10);
846  TEST_RUN("dsize:5<>10; content:\"abc\";", 0, 10);
847 
848  // relative match, directly following anchored content
849  TEST_RUN("content:\"abc\"; depth:3; content:\"xyz\"; distance:0; within:3; ", 3, 6);
850  // relative match, directly following anchored content
851  TEST_RUN("content:\"abc\"; offset:3; depth:3; content:\"xyz\"; distance:0; within:3; ", 6, 9);
852  TEST_RUN("content:\"abc\"; depth:6; content:\"xyz\"; distance:0; within:3; ", 3, 9);
853 
854  // multiple relative matches after anchored content
855  TEST_RUN("content:\"abc\"; depth:3; content:\"klm\"; distance:0; within:3; content:\"xyz\"; distance:0; within:3; ", 6, 9);
856  // test 'reset' due to unanchored content
857  TEST_RUN("content:\"abc\"; depth:3; content:\"klm\"; content:\"xyz\"; distance:0; within:3; ", 3, 0);
858  // test 'reset' due to unanchored pcre
859  TEST_RUN("content:\"abc\"; depth:3; pcre:/\"klm\"/; content:\"xyz\"; distance:0; within:3; ", 0, 0);
860  // test relative pcre. We can use previous offset+pattern len
861  TEST_RUN("content:\"abc\"; depth:3; pcre:/\"klm\"/R; content:\"xyz\"; distance:0; within:3; ", 3, 0);
862  TEST_RUN("content:\"abc\"; offset:3; depth:3; pcre:/\"klm\"/R; content:\"xyz\"; distance:0; within:3; ", 6, 0);
863 
864  TEST_RUN("content:\"abc\"; depth:3; content:\"klm\"; within:3; content:\"xyz\"; within:3; ", 0, 9);
865 
866  TEST_RUN("content:\"abc\"; depth:3; content:\"klm\"; distance:0; content:\"xyz\"; distance:0; ", 6, 0);
867 
868  // tests to see if anchored 'ends_with' is applied to other content as depth
869  TEST_RUN("content:\"abc\"; depth:6; isdataat:!1,relative; content:\"klm\";", 0, 6);
870  TEST_RUN("content:\"abc\"; depth:3; content:\"klm\"; within:3; content:\"xyz\"; within:3; isdataat:!1,relative; content:\"def\"; ", 0, 9);
871 
872  TEST_RUN("content:\"|03|\"; depth:1; content:\"|e0|\"; distance:4; within:1;", 5, 6);
873  TEST_RUN("content:\"|03|\"; depth:1; content:\"|e0|\"; distance:4; within:1; content:\"Cookie|3a|\"; distance:5; within:7;", 11, 18);
874 
875  TEST_RUN("content:\"this\"; content:\"is\"; within:6; content:\"big\"; within:8; content:\"string\"; within:8;", 0, 0);
876 
877  TEST_RUN("dsize:<80; content:!\"|00 22 02 00|\"; depth: 4; content:\"|00 00 04|\"; distance:8; within:3; content:\"|00 00 00 00 00|\"; distance:6; within:5;", 17, 80);
878  TEST_RUN("content:!\"|00 22 02 00|\"; depth: 4; content:\"|00 00 04|\"; distance:8; within:3; content:\"|00 00 00 00 00|\"; distance:6; within:5;", 17, 0);
879 
880  TEST_RUN("content:\"|0d 0a 0d 0a|\"; content:\"code=\"; distance:0;", 4, 0);
881  TEST_RUN("content:\"|0d 0a 0d 0a|\"; content:\"code=\"; distance:0; content:\"xploit.class\"; distance:2; within:18;", 11, 0);
882 
883  TEST_RUN("content:\"|16 03|\"; depth:2; content:\"|55 04 0a|\"; distance:0;", 2, 0);
884  TEST_RUN("content:\"|16 03|\"; depth:2; content:\"|55 04 0a|\"; distance:0; content:\"|0d|LogMeIn, Inc.\"; distance:1; within:14;", 6, 0);
885  TEST_RUN("content:\"|16 03|\"; depth:2; content:\"|55 04 0a|\"; distance:0; content:\"|0d|LogMeIn, Inc.\"; distance:1; within:14; content:\".app\";", 0, 0);
886 
887  TEST_RUN("content:\"=\"; offset:4; depth:9;", 4, 13);
888  // low end: offset 4 + patlen 1 = 5. So 5 + distance 55 = 60.
889  // hi end: depth '13' (4+9) + distance 55 = 68 + within 2 = 70
890  TEST_RUN("content:\"=\"; offset:4; depth:9; content:\"=&\"; distance:55; within:2;", 60, 70);
891 
892  // distance value is too high so we bail and not set anything on this content
893  TEST_RUN("content:\"0123456789\"; content:\"abcdef\"; distance:1048576;", 0, 0);
894 
895  // Bug #5162.
896  TEST_RUN("content:\"SMB\"; depth:8; content:\"|09 00|\"; distance:8; within:2;", 11, 18);
897  TEST_RUN("content:\"SMB\"; depth:8; content:\"|09 00|\"; distance:8; within:2; content:\"|05 "
898  "00 00|\"; distance:0;",
899  13, 0);
900  TEST_RUN("content:\"SMB\"; depth:8; content:\"|09 00|\"; distance:8; within:2; content:\"|05 "
901  "00 00|\"; distance:0; content:\"|0c 00|\"; distance:19; within:2;",
902  35, 0);
903  TEST_RUN("content:\"SMB\"; depth:8; content:\"|09 00|\"; distance:8; within:2; content:\"|05 "
904  "00 00|\"; distance:0; content:\"|0c 00|\"; distance:19; within:2; content:\"|15 00 "
905  "00 00|\"; distance:20; within:4;",
906  57, 0);
907 
908  TEST_DONE;
909 }
910 
911 /**
912  * \brief Print list of DETECT_CONTENT SigMatch's allocated in a
913  * SigMatch list, from the current sm to the end
914  * \param sm pointer to the current SigMatch to start printing from
915  */
916 static void DetectContentPrintAll(SigMatch *sm)
917 {
918 #ifdef DEBUG
919  if (SCLogDebugEnabled()) {
920  int i = 0;
921 
922  if (sm == NULL)
923  return;
924 
925  SigMatch *first_sm = sm;
926 
927  /* Print all of them */
928  for (; first_sm != NULL; first_sm = first_sm->next) {
929  if (first_sm->type == DETECT_CONTENT) {
930  SCLogDebug("Printing SigMatch DETECT_CONTENT %d", ++i);
932  }
933  }
934  }
935 #endif /* DEBUG */
936 }
937 
938 static int g_file_data_buffer_id = 0;
939 static int g_dce_stub_data_buffer_id = 0;
940 
941 /**
942  * \test DetectContentParseTest01 this is a test to make sure we can deal with escaped colons
943  */
944 static int DetectContentParseTest01 (void)
945 {
946  int result = 1;
947  DetectContentData *cd = NULL;
948  const char *teststring = "abc\\:def";
949  const char *teststringparsed = "abc:def";
950 
951  uint8_t spm_matcher = SinglePatternMatchDefaultMatcher();
952  SpmGlobalThreadCtx *spm_global_thread_ctx = SpmInitGlobalThreadCtx(spm_matcher);
953  FAIL_IF(spm_global_thread_ctx == NULL);
954 
955  cd = DetectContentParse(spm_global_thread_ctx, teststring);
956  if (cd != NULL) {
957  if (memcmp(cd->content, teststringparsed, strlen(teststringparsed)) != 0) {
958  SCLogDebug("expected %s got ", teststringparsed);
959  PrintRawUriFp(stdout,cd->content,cd->content_len);
960  SCLogDebug(": ");
961  result = 0;
962  DetectContentFree(NULL, cd);
963  }
964  } else {
965  SCLogDebug("expected %s got NULL: ", teststringparsed);
966  result = 0;
967  }
968  SpmDestroyGlobalThreadCtx(spm_global_thread_ctx);
969  return result;
970 }
971 
972 /**
973  * \test DetectContentParseTest02 this is a test to make sure we can deal with escaped semi-colons
974  */
975 static int DetectContentParseTest02 (void)
976 {
977  int result = 1;
978  DetectContentData *cd = NULL;
979  const char *teststring = "abc\\;def";
980  const char *teststringparsed = "abc;def";
981 
982  uint8_t spm_matcher = SinglePatternMatchDefaultMatcher();
983  SpmGlobalThreadCtx *spm_global_thread_ctx = SpmInitGlobalThreadCtx(spm_matcher);
984  FAIL_IF(spm_global_thread_ctx == NULL);
985 
986  cd = DetectContentParse(spm_global_thread_ctx, teststring);
987  if (cd != NULL) {
988  if (memcmp(cd->content, teststringparsed, strlen(teststringparsed)) != 0) {
989  SCLogDebug("expected %s got ", teststringparsed);
990  PrintRawUriFp(stdout,cd->content,cd->content_len);
991  SCLogDebug(": ");
992  result = 0;
993  DetectContentFree(NULL, cd);
994  }
995  } else {
996  SCLogDebug("expected %s got NULL: ", teststringparsed);
997  result = 0;
998  }
999  SpmDestroyGlobalThreadCtx(spm_global_thread_ctx);
1000  return result;
1001 }
1002 
1003 /**
1004  * \test DetectContentParseTest03 this is a test to make sure we can deal with escaped double-quotes
1005  */
1006 static int DetectContentParseTest03 (void)
1007 {
1008  int result = 1;
1009  DetectContentData *cd = NULL;
1010  const char *teststring = "abc\\\"def";
1011  const char *teststringparsed = "abc\"def";
1012 
1013  uint8_t spm_matcher = SinglePatternMatchDefaultMatcher();
1014  SpmGlobalThreadCtx *spm_global_thread_ctx = SpmInitGlobalThreadCtx(spm_matcher);
1015  FAIL_IF(spm_global_thread_ctx == NULL);
1016 
1017  cd = DetectContentParse(spm_global_thread_ctx, teststring);
1018  if (cd != NULL) {
1019  if (memcmp(cd->content, teststringparsed, strlen(teststringparsed)) != 0) {
1020  SCLogDebug("expected %s got ", teststringparsed);
1021  PrintRawUriFp(stdout,cd->content,cd->content_len);
1022  SCLogDebug(": ");
1023  result = 0;
1024  DetectContentFree(NULL, cd);
1025  }
1026  } else {
1027  SCLogDebug("expected %s got NULL: ", teststringparsed);
1028  result = 0;
1029  }
1030  SpmDestroyGlobalThreadCtx(spm_global_thread_ctx);
1031  return result;
1032 }
1033 
1034 /**
1035  * \test DetectContentParseTest04 this is a test to make sure we can deal with escaped backslashes
1036  */
1037 static int DetectContentParseTest04 (void)
1038 {
1039  int result = 1;
1040  DetectContentData *cd = NULL;
1041  const char *teststring = "abc\\\\def";
1042  const char *teststringparsed = "abc\\def";
1043 
1044  uint8_t spm_matcher = SinglePatternMatchDefaultMatcher();
1045  SpmGlobalThreadCtx *spm_global_thread_ctx = SpmInitGlobalThreadCtx(spm_matcher);
1046  FAIL_IF(spm_global_thread_ctx == NULL);
1047 
1048  cd = DetectContentParse(spm_global_thread_ctx, teststring);
1049  if (cd != NULL) {
1050  uint16_t len = (cd->content_len > strlen(teststringparsed));
1051  if (memcmp(cd->content, teststringparsed, len) != 0) {
1052  SCLogDebug("expected %s got ", teststringparsed);
1053  PrintRawUriFp(stdout,cd->content,cd->content_len);
1054  SCLogDebug(": ");
1055  result = 0;
1056  DetectContentFree(NULL, cd);
1057  }
1058  } else {
1059  SCLogDebug("expected %s got NULL: ", teststringparsed);
1060  result = 0;
1061  }
1062  SpmDestroyGlobalThreadCtx(spm_global_thread_ctx);
1063  return result;
1064 }
1065 
1066 /**
1067  * \test DetectContentParseTest05 test illegal escape
1068  */
1069 static int DetectContentParseTest05 (void)
1070 {
1071  int result = 1;
1072  DetectContentData *cd = NULL;
1073  const char *teststring = "abc\\def";
1074 
1075  uint8_t spm_matcher = SinglePatternMatchDefaultMatcher();
1076  SpmGlobalThreadCtx *spm_global_thread_ctx = SpmInitGlobalThreadCtx(spm_matcher);
1077  FAIL_IF(spm_global_thread_ctx == NULL);
1078 
1079  cd = DetectContentParse(spm_global_thread_ctx, teststring);
1080  if (cd != NULL) {
1081  SCLogDebug("expected NULL got ");
1082  PrintRawUriFp(stdout,cd->content,cd->content_len);
1083  SCLogDebug(": ");
1084  result = 0;
1085  DetectContentFree(NULL, cd);
1086  }
1087  SpmDestroyGlobalThreadCtx(spm_global_thread_ctx);
1088  return result;
1089 }
1090 
1091 /**
1092  * \test DetectContentParseTest06 test a binary content
1093  */
1094 static int DetectContentParseTest06 (void)
1095 {
1096  int result = 1;
1097  DetectContentData *cd = NULL;
1098  const char *teststring = "a|42|c|44|e|46|";
1099  const char *teststringparsed = "abcdef";
1100 
1101  uint8_t spm_matcher = SinglePatternMatchDefaultMatcher();
1102  SpmGlobalThreadCtx *spm_global_thread_ctx = SpmInitGlobalThreadCtx(spm_matcher);
1103  FAIL_IF(spm_global_thread_ctx == NULL);
1104 
1105  cd = DetectContentParse(spm_global_thread_ctx, teststring);
1106  if (cd != NULL) {
1107  uint16_t len = (cd->content_len > strlen(teststringparsed));
1108  if (memcmp(cd->content, teststringparsed, len) != 0) {
1109  SCLogDebug("expected %s got ", teststringparsed);
1110  PrintRawUriFp(stdout,cd->content,cd->content_len);
1111  SCLogDebug(": ");
1112  result = 0;
1113  DetectContentFree(NULL, cd);
1114  }
1115  } else {
1116  SCLogDebug("expected %s got NULL: ", teststringparsed);
1117  result = 0;
1118  }
1119  SpmDestroyGlobalThreadCtx(spm_global_thread_ctx);
1120  return result;
1121 }
1122 
1123 /**
1124  * \test DetectContentParseTest07 test an empty content
1125  */
1126 static int DetectContentParseTest07 (void)
1127 {
1128  int result = 1;
1129  DetectContentData *cd = NULL;
1130  const char *teststring = "";
1131 
1132  uint8_t spm_matcher = SinglePatternMatchDefaultMatcher();
1133  SpmGlobalThreadCtx *spm_global_thread_ctx = SpmInitGlobalThreadCtx(spm_matcher);
1134  FAIL_IF(spm_global_thread_ctx == NULL);
1135 
1136  cd = DetectContentParse(spm_global_thread_ctx, teststring);
1137  if (cd != NULL) {
1138  SCLogDebug("expected NULL got %p: ", cd);
1139  result = 0;
1140  DetectContentFree(NULL, cd);
1141  }
1142  SpmDestroyGlobalThreadCtx(spm_global_thread_ctx);
1143  return result;
1144 }
1145 
1146 /**
1147  * \test DetectContentParseTest08 test an empty content
1148  */
1149 static int DetectContentParseTest08 (void)
1150 {
1151  int result = 1;
1152  DetectContentData *cd = NULL;
1153  const char *teststring = "";
1154 
1155  uint8_t spm_matcher = SinglePatternMatchDefaultMatcher();
1156  SpmGlobalThreadCtx *spm_global_thread_ctx = SpmInitGlobalThreadCtx(spm_matcher);
1157  FAIL_IF(spm_global_thread_ctx == NULL);
1158 
1159  cd = DetectContentParse(spm_global_thread_ctx, teststring);
1160  if (cd != NULL) {
1161  SCLogDebug("expected NULL got %p: ", cd);
1162  result = 0;
1163  DetectContentFree(NULL, cd);
1164  }
1165  SpmDestroyGlobalThreadCtx(spm_global_thread_ctx);
1166  return result;
1167 }
1168 
1169 /**
1170  * \test Test packet Matches
1171  * \param raw_eth_pkt pointer to the ethernet packet
1172  * \param pktsize size of the packet
1173  * \param sig pointer to the signature to test
1174  * \param sid sid number of the signature
1175  * \retval return 1 if match
1176  * \retval return 0 if not
1177  */
1178 static int DetectContentLongPatternMatchTest(uint8_t *raw_eth_pkt, uint16_t pktsize, const char *sig,
1179  uint32_t sid)
1180 {
1181  Packet *p = PacketGetFromAlloc();
1182  FAIL_IF_NULL(p);
1184 
1185  ThreadVars th_v;
1186  DetectEngineThreadCtx *det_ctx = NULL;
1187  memset(&dtv, 0, sizeof(DecodeThreadVars));
1188  memset(&th_v, 0, sizeof(th_v));
1189 
1191  DecodeEthernet(&th_v, &dtv, p, raw_eth_pkt, pktsize);
1192 
1195  de_ctx->flags |= DE_QUIET;
1196 
1198  FAIL_IF_NULL(s);
1199 
1203  ->ctx;
1205  }
1206 
1207  SCLogDebug("---DetectContentLongPatternMatchTest---");
1208  DetectContentPrintAll(de_ctx->sig_list->init_data->smlists[DETECT_SM_LIST_MATCH]);
1209 
1211  DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
1212 
1213  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1214  int result = PacketAlertCheck(p, sid);
1215 
1216  DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
1218  PacketRecycle(p);
1219  FlowShutdown();
1220  SCFree(p);
1221  return result;
1222 }
1223 
1224 /**
1225  * \brief Wrapper for DetectContentLongPatternMatchTest
1226  */
1227 static int DetectContentLongPatternMatchTestWrp(const char *sig, uint32_t sid)
1228 {
1229  /** Real packet with the following tcp data:
1230  * "Hi, this is a big test to check content matches of splitted"
1231  * "patterns between multiple chunks!"
1232  * (without quotes! :) )
1233  */
1234  uint8_t raw_eth_pkt[] = {
1235  0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,
1236  0x00,0x00,0x00,0x00,0x08,0x00,0x45,0x00,
1237  0x00,0x85,0x00,0x01,0x00,0x00,0x40,0x06,
1238  0x7c,0x70,0x7f,0x00,0x00,0x01,0x7f,0x00,
1239  0x00,0x01,0x00,0x14,0x00,0x50,0x00,0x00,
1240  0x00,0x00,0x00,0x00,0x00,0x00,0x50,0x02,
1241  0x20,0x00,0xc9,0xad,0x00,0x00,0x48,0x69,
1242  0x2c,0x20,0x74,0x68,0x69,0x73,0x20,0x69,
1243  0x73,0x20,0x61,0x20,0x62,0x69,0x67,0x20,
1244  0x74,0x65,0x73,0x74,0x20,0x74,0x6f,0x20,
1245  0x63,0x68,0x65,0x63,0x6b,0x20,0x63,0x6f,
1246  0x6e,0x74,0x65,0x6e,0x74,0x20,0x6d,0x61,
1247  0x74,0x63,0x68,0x65,0x73,0x20,0x6f,0x66,
1248  0x20,0x73,0x70,0x6c,0x69,0x74,0x74,0x65,
1249  0x64,0x20,0x70,0x61,0x74,0x74,0x65,0x72,
1250  0x6e,0x73,0x20,0x62,0x65,0x74,0x77,0x65,
1251  0x65,0x6e,0x20,0x6d,0x75,0x6c,0x74,0x69,
1252  0x70,0x6c,0x65,0x20,0x63,0x68,0x75,0x6e,
1253  0x6b,0x73,0x21 }; /* end raw_eth_pkt */
1254 
1255  return DetectContentLongPatternMatchTest(raw_eth_pkt, (uint16_t)sizeof(raw_eth_pkt),
1256  sig, sid);
1257 }
1258 
1259 /**
1260  * \test Check if we match a normal pattern (not splitted)
1261  */
1262 static int DetectContentLongPatternMatchTest01(void)
1263 {
1264  const char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";"
1265  " content:\"Hi, this is a big test\"; sid:1;)";
1266  return DetectContentLongPatternMatchTestWrp(sig, 1);
1267 }
1268 
1269 /**
1270  * \test Check if we match a splitted pattern
1271  */
1272 static int DetectContentLongPatternMatchTest02(void)
1273 {
1274  const char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";"
1275  " content:\"Hi, this is a big test to check content matches of"
1276  " splitted patterns between multiple chunks!\"; sid:1;)";
1277  return DetectContentLongPatternMatchTestWrp(sig, 1);
1278 }
1279 
1280 /**
1281  * \test Check that we don't match the signature if one of the splitted
1282  * chunks doesn't match the packet
1283  */
1284 static int DetectContentLongPatternMatchTest03(void)
1285 {
1286  /** The last chunk of the content should not match */
1287  const char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";"
1288  " content:\"Hi, this is a big test to check content matches of"
1289  " splitted patterns between multiple splitted chunks!\"; sid:1;)";
1290  return (DetectContentLongPatternMatchTestWrp(sig, 1) == 0) ? 1: 0;
1291 }
1292 
1293 /**
1294  * \test Check if we match multiple content (not splitted)
1295  */
1296 static int DetectContentLongPatternMatchTest04(void)
1297 {
1298  const char *sig = "alert tcp any any -> any any (msg:\"Nothing..\"; "
1299  " content:\"Hi, this is\"; depth:15 ;content:\"a big test\"; "
1300  " within:15; content:\"to check content matches of\"; "
1301  " within:30; content:\"splitted patterns\"; distance:1; "
1302  " within:30; "
1303  " sid:1;)";
1304  return DetectContentLongPatternMatchTestWrp(sig, 1);
1305 }
1306 
1307 /**
1308  * \test Check that we match packets with multiple chunks and not chunks
1309  * Here we should specify only contents that fit in 32 bytes
1310  * Each of them with their modifier values
1311  */
1312 static int DetectContentLongPatternMatchTest05(void)
1313 {
1314  const char *sig = "alert tcp any any -> any any (msg:\"Nothing..\"; "
1315  " content:\"Hi, this is a big\"; depth:17; "
1316  " isdataat:30, relative; "
1317  " content:\"test\"; within: 5; distance:1; "
1318  " isdataat:15, relative; "
1319  " content:\"of splitted\"; within:37; distance:15; "
1320  " isdataat:20,relative; "
1321  " content:\"patterns\"; within:9; distance:1; "
1322  " isdataat:10, relative; "
1323  " sid:1;)";
1324  return DetectContentLongPatternMatchTestWrp(sig, 1);
1325 }
1326 
1327 /**
1328  * \test Check that we match packets with multiple chunks and not chunks
1329  * Here we should specify contents that fit and contents that must be splitted
1330  * Each of them with their modifier values
1331  */
1332 static int DetectContentLongPatternMatchTest06(void)
1333 {
1334  const char *sig = "alert tcp any any -> any any (msg:\"Nothing..\"; "
1335  " content:\"Hi, this is a big test to check cont\"; depth:36;"
1336  " content:\"ent matches\"; within:11; distance:0; "
1337  " content:\"of splitted patterns between multiple\"; "
1338  " within:38; distance:1; "
1339  " content:\"chunks!\"; within: 8; distance:1; "
1340  " sid:1;)";
1341  return DetectContentLongPatternMatchTestWrp(sig, 1);
1342 }
1343 
1344 /**
1345  * \test Check if we match contents that are in the payload
1346  * but not in the same order as specified in the signature
1347  */
1348 static int DetectContentLongPatternMatchTest07(void)
1349 {
1350  const char *sig = "alert tcp any any -> any any (msg:\"Nothing..\"; "
1351  " content:\"chunks!\"; "
1352  " content:\"content matches\"; offset:32; depth:47; "
1353  " content:\"of splitted patterns between multiple\"; "
1354  " content:\"Hi, this is a big\"; offset:0; depth:17; "
1355  " sid:1;)";
1356  return DetectContentLongPatternMatchTestWrp(sig, 1);
1357 }
1358 
1359 /**
1360  * \test Check if we match contents that are in the payload
1361  * but not in the same order as specified in the signature
1362  */
1363 static int DetectContentLongPatternMatchTest08(void)
1364 {
1365  const char *sig = "alert tcp any any -> any any (msg:\"Nothing..\"; "
1366  " content:\"ent matches\"; "
1367  " content:\"of splitted patterns between multiple\"; "
1368  " within:38; distance:1; "
1369  " content:\"chunks!\"; within: 8; distance:1; "
1370  " content:\"Hi, this is a big test to check cont\"; depth:36;"
1371  " sid:1;)";
1372  return DetectContentLongPatternMatchTestWrp(sig, 1);
1373 }
1374 
1375 /**
1376  * \test Check if we match contents that are in the payload
1377  * but not in the same order as specified in the signature
1378  */
1379 static int DetectContentLongPatternMatchTest09(void)
1380 {
1381  const char *sig = "alert tcp any any -> any any (msg:\"Nothing..\"; "
1382  " content:\"ent matches\"; "
1383  " content:\"of splitted patterns between multiple\"; "
1384  " offset:47; depth:85; "
1385  " content:\"chunks!\"; within: 8; distance:1; "
1386  " content:\"Hi, this is a big test to chec\"; depth:36;"
1387  " content:\"k cont\"; distance:0; within:6;"
1388  " sid:1;)";
1389  return DetectContentLongPatternMatchTestWrp(sig, 1);
1390 }
1391 
1392 /**
1393  * \test Check if we match two consecutive simple contents
1394  */
1395 static int DetectContentLongPatternMatchTest10(void)
1396 {
1397  const char *sig = "alert tcp any any -> any any (msg:\"Nothing..\"; "
1398  " content:\"Hi, this is a big test to check \"; "
1399  " content:\"con\"; "
1400  " sid:1;)";
1401  return DetectContentLongPatternMatchTestWrp(sig, 1);
1402 }
1403 
1404 /**
1405  * \test Check if we match two contents of length 1
1406  */
1407 static int DetectContentLongPatternMatchTest11(void)
1408 {
1409  const char *sig = "alert tcp any any -> any any (msg:\"Nothing..\"; "
1410  " content:\"H\"; "
1411  " content:\"i\"; "
1412  " sid:1;)";
1413  return DetectContentLongPatternMatchTestWrp(sig, 1);
1414 }
1415 
1416 static int DetectContentParseTest09(void)
1417 {
1418  DetectContentData *cd = NULL;
1419  const char *teststring = "boo";
1420 
1421  uint8_t spm_matcher = SinglePatternMatchDefaultMatcher();
1422  SpmGlobalThreadCtx *spm_global_thread_ctx = SpmInitGlobalThreadCtx(spm_matcher);
1423  FAIL_IF(spm_global_thread_ctx == NULL);
1424 
1425  cd = DetectContentParse(spm_global_thread_ctx, teststring);
1426  FAIL_IF_NULL(cd);
1427  DetectContentFree(NULL, cd);
1428  SpmDestroyGlobalThreadCtx(spm_global_thread_ctx);
1429  PASS;
1430 }
1431 
1432 /**
1433  * \test Test cases where if within specified is < content length we invalidate
1434  * the sig.
1435  */
1436 static int DetectContentParseTest17(void)
1437 {
1438  int result = 0;
1439  const char *sigstr = "alert tcp any any -> any any (msg:\"Dummy\"; "
1440  "content:\"one\"; content:\"two\"; within:2; sid:1;)";
1441 
1443  if (de_ctx == NULL)
1444  goto end;
1445 
1446  de_ctx->sig_list = SigInit(de_ctx, sigstr);
1447  if (de_ctx->sig_list != NULL)
1448  goto end;
1449 
1450  result = 1;
1451 
1452 end:
1454  if (de_ctx != NULL)
1456  return result;
1457 }
1458 
1459 /**
1460  * \test Test content for dce sig.
1461  */
1462 static int DetectContentParseTest18(void)
1463 {
1466 
1467  Signature *s = SigAlloc();
1468  FAIL_IF_NULL(s);
1470  FAIL_IF_NOT(DetectContentSetup(de_ctx, s, "one") == 0);
1471  FAIL_IF(DetectBufferIsPresent(s, g_dce_stub_data_buffer_id));
1473  SigFree(de_ctx, s);
1474 
1475  s = SigAlloc();
1476  FAIL_IF_NULL(s);
1477  FAIL_IF_NOT(DetectContentSetup(de_ctx, s, "one") == 0);
1478  FAIL_IF(DetectBufferIsPresent(s, g_dce_stub_data_buffer_id));
1480  SigFree(de_ctx, s);
1481 
1483  PASS;
1484 }
1485 
1486 /**
1487  * \test Test content for dce sig.
1488  */
1489 
1490 static int DetectContentParseTest19(void)
1491 {
1492 
1495  de_ctx->flags |= DE_QUIET;
1496 
1497  Signature *s =
1498  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any "
1499  "(msg:\"Testing dce iface, stub_data with content\"; "
1500  "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; "
1501  "dce_stub_data; "
1502  "content:\"one\"; distance:0; sid:1;)");
1503  FAIL_IF_NULL(s);
1504 
1505  SigMatch *sm = DetectBufferGetFirstSigMatch(s, g_dce_stub_data_buffer_id);
1506  FAIL_IF_NULL(sm);
1509 
1510  DetectContentData *data = (DetectContentData *)sm->ctx;
1512 
1514  "alert tcp any any -> any any "
1515  "(msg:\"Testing dce iface, stub_data with contents & distance, within\"; "
1516  "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; "
1517  "dce_stub_data; "
1518  "content:\"one\"; distance:0; content:\"two\"; within:10; sid:2;)");
1519  FAIL_IF_NULL(s);
1520  sm = DetectBufferGetFirstSigMatch(s, g_dce_stub_data_buffer_id);
1521  FAIL_IF_NULL(sm);
1523  FAIL_IF_NULL(sm->next);
1524  sm = sm->next;
1527 
1528  data = (DetectContentData *)sm->ctx;
1530  FAIL_IF_NOT(data->within == 10);
1531 
1533  "alert tcp any any -> any any "
1534  "(msg:\"Testing dce iface, stub with contents, distance, within\"; "
1535  "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; "
1536  "dce_stub_data; "
1537  "content:\"one\"; distance:0; "
1538  "content:\"two\"; within:10; distance:2; sid:3;)");
1539  FAIL_IF_NULL(s);
1540  sm = DetectBufferGetFirstSigMatch(s, g_dce_stub_data_buffer_id);
1541  FAIL_IF_NULL(sm);
1543  FAIL_IF_NULL(sm->next);
1544  sm = sm->next;
1546  data = (DetectContentData *)sm->ctx;
1548  FAIL_IF_NOT(data->within == 10);
1549  FAIL_IF_NOT(data->distance == 2);
1551 
1552  s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any "
1553  "(msg:\"Testing content\"; "
1554  "content:\"one\"; sid:4;)");
1555  FAIL_IF_NULL(s);
1556  FAIL_IF(DetectBufferIsPresent(s, g_dce_stub_data_buffer_id));
1558 
1560  PASS;
1561 }
1562 
1563 /**
1564  * \test Test content for dce sig.
1565  */
1566 static int DetectContentParseTest20(void)
1567 {
1568  DetectEngineCtx *de_ctx = NULL;
1569  int result = 1;
1570 
1572  if (de_ctx == NULL)
1573  goto end;
1574 
1575  de_ctx->flags |= DE_QUIET;
1577  "alert udp any any -> any any "
1578  "(msg:\"test\"; content:\"\"; sid:238012;)");
1579  if (de_ctx->sig_list != NULL) {
1580  result = 0;
1581  goto end;
1582  }
1583 
1584  end:
1588 
1589  return result;
1590 }
1591 
1592 /**
1593  * \test Parsing test
1594  */
1595 static int DetectContentParseTest21(void)
1596 {
1597  DetectEngineCtx *de_ctx = NULL;
1598  int result = 1;
1599 
1601  if (de_ctx == NULL)
1602  goto end;
1603 
1604  de_ctx->flags |= DE_QUIET;
1606  "alert udp any any -> any any "
1607  "(msg:\"test\"; content:\"; sid:238012;)");
1608  if (de_ctx->sig_list != NULL) {
1609  result = 0;
1610  goto end;
1611  }
1612 
1613  end:
1617 
1618  return result;
1619 }
1620 
1621 /**
1622  * \test Parsing test
1623  */
1624 static int DetectContentParseTest22(void)
1625 {
1626  DetectEngineCtx *de_ctx = NULL;
1627  int result = 1;
1628 
1630  if (de_ctx == NULL)
1631  goto end;
1632 
1633  de_ctx->flags |= DE_QUIET;
1635  "alert udp any any -> any any "
1636  "(msg:\"test\"; content:\"boo; sid:238012;)");
1637  if (de_ctx->sig_list != NULL) {
1638  result = 0;
1639  goto end;
1640  }
1641 
1642  end:
1646 
1647  return result;
1648 }
1649 
1650 /**
1651  * \test Parsing test
1652  */
1653 static int DetectContentParseTest23(void)
1654 {
1655  DetectEngineCtx *de_ctx = NULL;
1656  int result = 1;
1657 
1659  if (de_ctx == NULL)
1660  goto end;
1661 
1662  de_ctx->flags |= DE_QUIET;
1664  "alert udp any any -> any any "
1665  "(msg:\"test\"; content:boo\"; sid:238012;)");
1666  if (de_ctx->sig_list != NULL) {
1667  result = 0;
1668  goto end;
1669  }
1670 
1671  end:
1675 
1676  return result;
1677 }
1678 
1679 /**
1680  * \test Parsing test
1681  */
1682 static int DetectContentParseTest24(void)
1683 {
1684  DetectEngineCtx *de_ctx = NULL;
1685  DetectContentData *cd = 0;
1686  Signature *s = NULL;
1687  int result = 1;
1688 
1690  if (de_ctx == NULL)
1691  goto end;
1692 
1693  de_ctx->flags |= DE_QUIET;
1694  s = de_ctx->sig_list = SigInit(de_ctx,
1695  "alert udp any any -> any any "
1696  "(msg:\"test\"; content: !\"boo\"; sid:238012;)");
1697  if (de_ctx->sig_list == NULL) {
1698  printf("de_ctx->sig_list == NULL: ");
1699  result = 0;
1700  goto end;
1701  }
1702 
1703  if (s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH] == NULL ||
1705  printf("de_ctx->pmatch_tail == NULL || de_ctx->pmatch_tail->ctx == NULL: ");
1706  result = 0;
1707  goto end;
1708  }
1709 
1711  result = (strncmp("boo", (char *)cd->content, cd->content_len) == 0);
1712 
1713 end:
1717 
1718  return result;
1719 }
1720 
1721 /**
1722  * \test Parsing test
1723  */
1724 static int DetectContentParseTest25(void)
1725 {
1726  DetectEngineCtx *de_ctx = NULL;
1727  int result = 1;
1728 
1730  if (de_ctx == NULL)
1731  goto end;
1732 
1733  de_ctx->flags |= DE_QUIET;
1735  "alert udp any any -> any any "
1736  "(msg:\"test\"; content:\"|\"; sid:1;)");
1737  if (de_ctx->sig_list != NULL) {
1738  result = 0;
1739  goto end;
1740  }
1741 
1742  end:
1746 
1747  return result;
1748 }
1749 
1750 /**
1751  * \test Parsing test
1752  */
1753 static int DetectContentParseTest26(void)
1754 {
1755  DetectEngineCtx *de_ctx = NULL;
1756  int result = 1;
1757 
1759  if (de_ctx == NULL)
1760  goto end;
1761 
1762  de_ctx->flags |= DE_QUIET;
1764  "alert udp any any -> any any "
1765  "(msg:\"test\"; content:\"|af\"; sid:1;)");
1766  if (de_ctx->sig_list != NULL) {
1767  result = 0;
1768  goto end;
1769  }
1770 
1771  end:
1775 
1776  return result;
1777 }
1778 
1779 /**
1780  * \test Parsing test
1781  */
1782 static int DetectContentParseTest27(void)
1783 {
1784  DetectEngineCtx *de_ctx = NULL;
1785  int result = 1;
1786 
1788  if (de_ctx == NULL)
1789  goto end;
1790 
1791  de_ctx->flags |= DE_QUIET;
1793  "alert udp any any -> any any "
1794  "(msg:\"test\"; content:\"af|\"; sid:1;)");
1795  if (de_ctx->sig_list != NULL) {
1796  result = 0;
1797  goto end;
1798  }
1799 
1800  end:
1804 
1805  return result;
1806 }
1807 
1808 /**
1809  * \test Parsing test
1810  */
1811 static int DetectContentParseTest28(void)
1812 {
1813  DetectEngineCtx *de_ctx = NULL;
1814  int result = 1;
1815 
1817  if (de_ctx == NULL)
1818  goto end;
1819 
1820  de_ctx->flags |= DE_QUIET;
1822  "alert udp any any -> any any "
1823  "(msg:\"test\"; content:\"|af|\"; sid:1;)");
1824  if (de_ctx->sig_list == NULL) {
1825  result = 0;
1826  goto end;
1827  }
1828 
1829  end:
1833 
1834  return result;
1835 }
1836 
1837 /**
1838  * \test Parsing test
1839  */
1840 static int DetectContentParseTest29(void)
1841 {
1842  DetectEngineCtx *de_ctx = NULL;
1843  int result = 1;
1844 
1846  if (de_ctx == NULL)
1847  goto end;
1848 
1849  de_ctx->flags |= DE_QUIET;
1851  "alert udp any any -> any any "
1852  "(msg:\"test\"; content:\"aast|\"; sid:1;)");
1853  if (de_ctx->sig_list != NULL) {
1854  result = 0;
1855  goto end;
1856  }
1857 
1858  end:
1862 
1863  return result;
1864 }
1865 
1866 /**
1867  * \test Parsing test
1868  */
1869 static int DetectContentParseTest30(void)
1870 {
1871  DetectEngineCtx *de_ctx = NULL;
1872  int result = 1;
1873 
1875  if (de_ctx == NULL)
1876  goto end;
1877 
1878  de_ctx->flags |= DE_QUIET;
1880  "alert udp any any -> any any "
1881  "(msg:\"test\"; content:\"aast|af\"; sid:1;)");
1882  if (de_ctx->sig_list != NULL) {
1883  result = 0;
1884  goto end;
1885  }
1886 
1887  end:
1891 
1892  return result;
1893 }
1894 
1895 /**
1896  * \test Parsing test
1897  */
1898 static int DetectContentParseTest31(void)
1899 {
1900  DetectEngineCtx *de_ctx = NULL;
1901  int result = 1;
1902 
1904  if (de_ctx == NULL)
1905  goto end;
1906 
1907  de_ctx->flags |= DE_QUIET;
1909  "alert udp any any -> any any "
1910  "(msg:\"test\"; content:\"aast|af|\"; sid:1;)");
1911  if (de_ctx->sig_list == NULL) {
1912  result = 0;
1913  goto end;
1914  }
1915 
1916  end:
1920 
1921  return result;
1922 }
1923 
1924 /**
1925  * \test Parsing test
1926  */
1927 static int DetectContentParseTest32(void)
1928 {
1929  DetectEngineCtx *de_ctx = NULL;
1930  int result = 1;
1931 
1933  if (de_ctx == NULL)
1934  goto end;
1935 
1936  de_ctx->flags |= DE_QUIET;
1938  "alert udp any any -> any any "
1939  "(msg:\"test\"; content:\"|af|asdf\"; sid:1;)");
1940  if (de_ctx->sig_list == NULL) {
1941  result = 0;
1942  goto end;
1943  }
1944 
1945  end:
1949 
1950  return result;
1951 }
1952 
1953 /**
1954  * \test Parsing test
1955  */
1956 static int DetectContentParseTest33(void)
1957 {
1958  DetectEngineCtx *de_ctx = NULL;
1959  int result = 1;
1960 
1962  if (de_ctx == NULL)
1963  goto end;
1964 
1965  de_ctx->flags |= DE_QUIET;
1967  "alert udp any any -> any any "
1968  "(msg:\"test\"; content:\"|af|af|\"; sid:1;)");
1969  if (de_ctx->sig_list != NULL) {
1970  result = 0;
1971  goto end;
1972  }
1973 
1974  end:
1978 
1979  return result;
1980 }
1981 
1982 /**
1983  * \test Parsing test
1984  */
1985 static int DetectContentParseTest34(void)
1986 {
1987  DetectEngineCtx *de_ctx = NULL;
1988  int result = 1;
1989 
1991  if (de_ctx == NULL)
1992  goto end;
1993 
1994  de_ctx->flags |= DE_QUIET;
1996  "alert udp any any -> any any "
1997  "(msg:\"test\"; content:\"|af|af|af\"; sid:1;)");
1998  if (de_ctx->sig_list != NULL) {
1999  result = 0;
2000  goto end;
2001  }
2002 
2003  end:
2007 
2008  return result;
2009 }
2010 
2011 /**
2012  * \test Parsing test
2013  */
2014 static int DetectContentParseTest35(void)
2015 {
2016  DetectEngineCtx *de_ctx = NULL;
2017  int result = 1;
2018 
2020  if (de_ctx == NULL)
2021  goto end;
2022 
2023  de_ctx->flags |= DE_QUIET;
2025  "alert udp any any -> any any "
2026  "(msg:\"test\"; content:\"|af|af|af|\"; sid:1;)");
2027  if (de_ctx->sig_list == NULL) {
2028  result = 0;
2029  goto end;
2030  }
2031 
2032  end:
2036 
2037  return result;
2038 }
2039 
2040 static int SigTestPositiveTestContent(const char *rule, uint8_t *buf)
2041 {
2042  uint16_t buflen = strlen((char *)buf);
2043  ThreadVars th_v;
2044  DetectEngineThreadCtx *det_ctx = NULL;
2045 
2046  memset(&th_v, 0, sizeof(th_v));
2047  Packet *p = UTHBuildPacket(buf, buflen, IPPROTO_TCP);
2048  FAIL_IF_NULL(p);
2049 
2052  de_ctx->flags |= DE_QUIET;
2053 
2054  de_ctx->sig_list = SigInit(de_ctx, rule);
2056 
2058  DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
2059  FAIL_IF_NULL(det_ctx);
2060 
2061  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
2062 
2063  FAIL_IF(PacketAlertCheck(p, 1) != 1);
2064 
2065  DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
2067 
2068  UTHFreePackets(&p, 1);
2069  PASS;
2070 }
2071 
2072 static int DetectContentParseTest41(void)
2073 {
2074  int result = 1;
2075  DetectContentData *cd = NULL;
2076  int patlen = 255;
2077  char *teststring = SCMalloc(sizeof(char) * (patlen + 1));
2078  if (unlikely(teststring == NULL))
2079  return 0;
2080  int idx = 0;
2081  for (int i = 0; i < patlen; idx++, i++) {
2082  teststring[idx] = 'a';
2083  }
2084  teststring[idx++] = '\0';
2085 
2086  uint8_t spm_matcher = SinglePatternMatchDefaultMatcher();
2087  SpmGlobalThreadCtx *spm_global_thread_ctx = SpmInitGlobalThreadCtx(spm_matcher);
2088  FAIL_IF(spm_global_thread_ctx == NULL);
2089 
2090  cd = DetectContentParse(spm_global_thread_ctx, teststring);
2091  if (cd == NULL) {
2092  SCLogDebug("expected not NULL");
2093  result = 0;
2094  }
2095 
2096  SpmDestroyGlobalThreadCtx(spm_global_thread_ctx);
2097  SCFree(teststring);
2098  DetectContentFree(NULL, cd);
2099  return result;
2100 }
2101 
2102 /**
2103  * Tests that content lengths > 255 are supported.
2104  */
2105 static int DetectContentParseTest42(void)
2106 {
2107  int result = 1;
2108  DetectContentData *cd = NULL;
2109  int patlen = 256;
2110  char *teststring = SCMalloc(sizeof(char) * (patlen + 1));
2111  if (unlikely(teststring == NULL))
2112  return 0;
2113  int idx = 0;
2114  for (int i = 0; i < patlen; idx++, i++) {
2115  teststring[idx] = 'a';
2116  }
2117  teststring[idx++] = '\0';
2118 
2119  uint8_t spm_matcher = SinglePatternMatchDefaultMatcher();
2120  SpmGlobalThreadCtx *spm_global_thread_ctx = SpmInitGlobalThreadCtx(spm_matcher);
2121  FAIL_IF(spm_global_thread_ctx == NULL);
2122 
2123  cd = DetectContentParse(spm_global_thread_ctx, teststring);
2124  if (cd == NULL) {
2125  SCLogDebug("expected not NULL");
2126  result = 0;
2127  }
2128 
2129  SpmDestroyGlobalThreadCtx(spm_global_thread_ctx);
2130  SCFree(teststring);
2131  DetectContentFree(NULL, cd);
2132  return result;
2133 }
2134 
2135 static int DetectContentParseTest43(void)
2136 {
2137  int result = 1;
2138  DetectContentData *cd = NULL;
2139  int patlen = 258;
2140  char *teststring = SCMalloc(sizeof(char) * (patlen + 1));
2141  if (unlikely(teststring == NULL))
2142  return 0;
2143  int idx = 0;
2144  teststring[idx++] = '|';
2145  teststring[idx++] = '4';
2146  teststring[idx++] = '6';
2147  teststring[idx++] = '|';
2148  for (int i = 0; i < (patlen - 4); idx++, i++) {
2149  teststring[idx] = 'a';
2150  }
2151  teststring[idx++] = '\0';
2152 
2153  uint8_t spm_matcher = SinglePatternMatchDefaultMatcher();
2154  SpmGlobalThreadCtx *spm_global_thread_ctx = SpmInitGlobalThreadCtx(spm_matcher);
2155  FAIL_IF(spm_global_thread_ctx == NULL);
2156 
2157  cd = DetectContentParse(spm_global_thread_ctx, teststring);
2158  if (cd == NULL) {
2159  SCLogDebug("expected not NULL");
2160  result = 0;
2161  }
2162 
2163  SpmDestroyGlobalThreadCtx(spm_global_thread_ctx);
2164  SCFree(teststring);
2165  DetectContentFree(NULL, cd);
2166  return result;
2167 }
2168 
2169 /**
2170  * Tests that content lengths > 255 are supported.
2171  */
2172 static int DetectContentParseTest44(void)
2173 {
2174  int result = 1;
2175  DetectContentData *cd = NULL;
2176  int patlen = 259;
2177  char *teststring = SCMalloc(sizeof(char) * (patlen + 1));
2178  if (unlikely(teststring == NULL))
2179  return 0;
2180  int idx = 0;
2181  teststring[idx++] = '|';
2182  teststring[idx++] = '4';
2183  teststring[idx++] = '6';
2184  teststring[idx++] = '|';
2185  for (int i = 0; i < (patlen - 4); idx++, i++) {
2186  teststring[idx] = 'a';
2187  }
2188  teststring[idx++] = '\0';
2189 
2190  uint8_t spm_matcher = SinglePatternMatchDefaultMatcher();
2191  SpmGlobalThreadCtx *spm_global_thread_ctx = SpmInitGlobalThreadCtx(spm_matcher);
2192  FAIL_IF(spm_global_thread_ctx == NULL);
2193 
2194  cd = DetectContentParse(spm_global_thread_ctx, teststring);
2195  if (cd == NULL) {
2196  SCLogDebug("expected not NULL");
2197  result = 0;
2198  }
2199 
2200  SpmDestroyGlobalThreadCtx(spm_global_thread_ctx);
2201  SCFree(teststring);
2202  DetectContentFree(NULL, cd);
2203  return result;
2204 }
2205 
2206 /**
2207  * \test Parsing test to check for unescaped quote within content section
2208  */
2209 static int DetectContentParseTest45(void)
2210 {
2211  DetectEngineCtx *de_ctx = NULL;
2212 
2215 
2216  de_ctx->flags |= DE_QUIET;
2218  "alert tcp any any -> any any "
2219  "(msg:\"test\"; content:\"|ff|\" content:\"TEST\"; sid:1;)");
2221 
2223 
2224  PASS;
2225 }
2226 
2227 static int SigTestNegativeTestContent(const char *rule, uint8_t *buf)
2228 {
2229  uint16_t buflen = strlen((char *)buf);
2230  Packet *p = NULL;
2231  ThreadVars th_v;
2232  DetectEngineThreadCtx *det_ctx = NULL;
2233  int result = 0;
2234  memset(&th_v, 0, sizeof(th_v));
2235 
2236  p = UTHBuildPacket(buf, buflen, IPPROTO_TCP);
2237 
2239  if (de_ctx == NULL)
2240  goto end;
2241 
2242  de_ctx->flags |= DE_QUIET;
2243 
2244  de_ctx->sig_list = SigInit(de_ctx, rule);
2245  if (de_ctx->sig_list == NULL) {
2246  goto end;
2247  }
2248 
2250  DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
2251 
2252  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
2253  if (PacketAlertCheck(p, 1) != 0) {
2254  goto end;
2255  }
2256 
2257  result = 1;
2258 end:
2259  if (det_ctx != NULL) {
2260  DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
2261  }
2262  if (de_ctx != NULL) {
2266  }
2267  UTHFreePackets(&p, 1);
2268  return result;
2269 }
2270 
2271 /**
2272  * \test A positive test that checks that the content string doesn't contain
2273  * the negated content
2274  */
2275 static int SigTest41TestNegatedContent(void)
2276 {
2277  return SigTestPositiveTestContent("alert tcp any any -> any any "
2278  "(msg:\"HTTP URI cap\"; content:!\"GES\"; sid:1;)",
2279 
2280  (uint8_t *)"GET /one/ HTTP/1.1\r\n Host: one.example.org\r\n\r\n\r\n"
2281  "GET /two/ HTTP/1.1\r\nHost: two.example.org\r\n\r\n\r\n");
2282 }
2283 
2284 /**
2285  * \test crash condition: as packet has no direction, it defaults to toclient
2286  * in stream ctx inspection of packet. There a null ptr deref happens
2287  * We don't care about the match/nomatch here.
2288  */
2289 static int SigTest41aTestNegatedContent(void)
2290 {
2291  (void)SigTestPositiveTestContent("alert tcp any any -> any any (msg:\"HTTP URI cap\"; flow:to_server; content:\"GET\"; sid:1;)", (uint8_t *)"GET /one/ HTTP/1.1\r\n Host: one.example.org\r\n\r\n\r\nGET /two/ HTTP/1.1\r\nHost: two.example.org\r\n\r\n\r\n");
2292  return 1;
2293 }
2294 
2295 
2296 /**
2297  * \test A positive test that checks that the content string doesn't contain
2298  * the negated content within the specified depth
2299  */
2300 static int SigTest42TestNegatedContent(void)
2301 {
2302  return SigTestPositiveTestContent(
2303  "alert tcp any any -> any any (content:!\"eeeeeeeeeee\"; depth:22; offset:35; sid:1;)",
2304  (uint8_t *)"aaa bbbb cccc dddddddd eeeeeeeeeee ffffffffff gggggggg hhhhhhhh");
2305 }
2306 
2307 /**
2308  * \test A negative test that checks that the content string doesn't contain
2309  * the negated content within the specified depth, and also after the
2310  * specified offset. Since the content is there, the match fails.
2311  *
2312  * Match is at offset:23, depth:34
2313  */
2314 static int SigTest43TestNegatedContent(void)
2315 {
2316  return SigTestNegativeTestContent(
2317  "alert tcp any any -> any any (content:!\"eeeeeeeeeee\"; depth:34; offset:23; sid:1;)",
2318  (uint8_t *)"aaa bbbb cccc dddddddd eeeeeeeeeee ffffffffff gggggggg hhhhhhhh");
2319 }
2320 
2321 /**
2322  * \test A negative test that checks that the content string doesn't contain
2323  * the negated content after the specified offset and within the specified
2324  * depth.
2325  */
2326 static int SigTest44TestNegatedContent(void)
2327 {
2328  return SigTestPositiveTestContent(
2329  "alert tcp any any -> any any (content:!\"eeeeeeeeeee\"; offset:40; depth:35; sid:1;)",
2330  (uint8_t *)"aaa bbbb cccc dddddddd eeeeeeeeeee ffffffffff gggggggg hhhhhhhh");
2331 }
2332 
2333 /**
2334  * \test A positive test that uses a combination of content string with negated
2335  * content string
2336  */
2337 static int SigTest45TestNegatedContent(void)
2338 {
2339  return SigTestPositiveTestContent("alert tcp any any -> any any (content:\"aaa\"; depth:5; "
2340  "content:!\"eeeeeeeeeee\"; depth:23; sid:1;)",
2341  (uint8_t *)"aaa bbbb cccc dddddddd eeeeeeeeeee ffffffffff gggggggg hhhhhhhh");
2342 }
2343 
2344 /**
2345  * \test A negative test that uses a combination of content string with negated
2346  * content string, with we receiving a failure for 'onee' itself.
2347  */
2348 static int SigTest46TestNegatedContent(void)
2349 {
2350  return SigTestNegativeTestContent("alert tcp any any -> any any (content:\"aaaE\"; "
2351  "content:!\"eeeeeeeeeee\"; depth:23; sid:1;)",
2352  (uint8_t *)"aaa bbbb cccc dddddddd eeeeeeeeeee ffffffffff gggggggg hhhhhhhh");
2353 }
2354 
2355 /**
2356  * \test A negative test that uses a combination of content string with negated
2357  * content string, with we receiving a failure of first content's offset
2358  * condition
2359  */
2360 static int SigTest47TestNegatedContent(void)
2361 {
2362  return SigTestNegativeTestContent("alert tcp any any -> any any (content:\"aaa\"; offset:5; "
2363  "content:!\"eeeeeeeeeee\"; depth:23; sid:1;)",
2364  (uint8_t *)"aaa bbbb cccc dddddddd eeeeeeeeeee ffffffffff gggggggg hhhhhhhh");
2365 }
2366 
2367 /**
2368  * \test A positive test that checks that we don't have a negated content within
2369  * the specified length from the previous content match.
2370  */
2371 static int SigTest48TestNegatedContent(void)
2372 {
2373  return SigTestPositiveTestContent(
2374  "alert tcp any any -> any any (content:\"GET\"; content:!\"GES\"; within:26; sid:1;)",
2375  (uint8_t *)"GET /one/ HTTP/1.1\r\n Host: one.example.org\r\n\r\n\r\nGET /two/ "
2376  "HTTP/1.1\r\nHost: two.example.org\r\n\r\n\r\n");
2377 }
2378 
2379 /**
2380  * \test A negative test that checks the combined use of content and negated
2381  * content with the use of within
2382  */
2383 static int SigTest49TestNegatedContent(void)
2384 {
2385  return SigTestNegativeTestContent(
2386  "alert tcp any any -> any any (content:\"GET\"; content:!\"Host\"; within:26; sid:1;)",
2387  (uint8_t *)"GET /one/ HTTP/1.1\r\n Host: one.example.org\r\n\r\n\r\nGET /two/ "
2388  "HTTP/1.1\r\nHost: two.example.org\r\n\r\n\r\n");
2389 }
2390 
2391 /**
2392  * \test A positive test that checks the combined use of content and negated
2393  * content with the use of distance
2394  */
2395 static int SigTest50TestNegatedContent(void)
2396 {
2397  return SigTestPositiveTestContent(
2398  "alert tcp any any -> any any (content:\"GET\"; content:!\"GES\"; distance:25; sid:1;)",
2399  (uint8_t *)"GET /one/ HTTP/1.1\r\n Host: one.example.org\r\n\r\n\r\nGET /two/ "
2400  "HTTP/1.1\r\nHost: two.example.org\r\n\r\n\r\n");
2401 }
2402 
2403 /**
2404  * \test A negative test that checks the combined use of content and negated
2405  * content with the use of distance
2406  *
2407  * First GET at offset 0
2408  * First Host at offset 21
2409  */
2410 static int SigTest51TestNegatedContent(void)
2411 {
2412  return SigTestNegativeTestContent("alert tcp any any -> any any (content:\"GET\"; content:!\"Host\"; distance:17; sid:1;)", (uint8_t *)"GET /one/ HTTP/1.1\r\nHost: one.example.org\r\n\r\n\r\nGET /two/ HTTP/1.1\r\nHost: two.example.org\r\n\r\n\r\n");
2413 }
2414 
2415 /**
2416  * \test A negative test that checks the combined use of content and negated
2417  * content, with the content not being present
2418  */
2419 static int SigTest52TestNegatedContent(void)
2420 {
2421  return SigTestNegativeTestContent(
2422  "alert tcp any any -> any any (content:\"GES\"; content:!\"BOO\"; sid:1;)",
2423  (uint8_t *)"GET /one/ HTTP/1.1\r\n Host: one.example.org\r\n\r\n\r\nGET /two/ "
2424  "HTTP/1.1\r\nHost: two.example.org\r\n\r\n\r\n");
2425 }
2426 
2427 /**
2428  * \test A negative test that checks the combined use of content and negated
2429  * content, in the presence of within
2430  */
2431 static int SigTest53TestNegatedContent(void)
2432 {
2433  return SigTestNegativeTestContent(
2434  "alert tcp any any -> any any (content:\"aaa\"; content:!\"Ggggg\"; within:56; sid:1;)",
2435  (uint8_t *)"aaa bbbb cccc dddddddd eeeeeeeeeee ffffffffff Ggggggggg hhhhhhhh");
2436 }
2437 
2438 /**
2439  * \test A positive test that checks the combined use of content and negated
2440  * content, in the presence of within
2441  */
2442 static int SigTest54TestNegatedContent(void)
2443 {
2444  return SigTestPositiveTestContent("alert tcp any any -> any any (content:\"aaa\"; "
2445  "content:!\"gggggg\"; within:20; sid:1;)",
2446  (uint8_t *)"aaa bbbb cccc dddddddd eeeeeeeeeee ffffffffff ggggggggg hhhhhhhh");
2447 }
2448 
2449 /**
2450  * \test A negative test that checks the use of negated content along with
2451  * the presence of depth
2452  */
2453 static int SigTest55TestNegatedContent(void)
2454 {
2455  return SigTestNegativeTestContent(
2456  "alert tcp any any -> any any (content:!\"aaa\"; depth:5; sid:1;)",
2457  (uint8_t *)"aaa bbbb cccc dddddddd eeeeeeeeeee ffffffffff gggggggg hhhhhhhh");
2458 }
2459 
2460 /**
2461  * \test A positive test that checks the combined use of 2 contents in the
2462  * presence of within
2463  */
2464 static int SigTest56TestNegatedContent(void)
2465 {
2466  return SigTestPositiveTestContent(
2467  "alert tcp any any -> any any (content:\"aaa\"; content:\"Ggggg\"; within:56; sid:1;)",
2468  (uint8_t *)"aaa bbbb cccc dddddddd eeeeeeeeeee ffffffffff Gggggggg hhhhhhhh");
2469 }
2470 
2471 /**
2472  * \test A negative test that checks the combined use of content and negated
2473  * content, in the presence of within
2474  */
2475 static int SigTest57TestNegatedContent(void)
2476 {
2477  return SigTestNegativeTestContent(
2478  "alert tcp any any -> any any (content:\"aaa\"; content:!\"Ggggg\"; within:56; sid:1;)",
2479  (uint8_t *)"aaa bbbb cccc dddddddd eeeeeeeeeee ffffffffff Ggggggggg hhhhhhhh");
2480 }
2481 
2482 /**
2483  * \test A positive test that checks the combined use of content and negated
2484  * content, in the presence of distance
2485  */
2486 static int SigTest58TestNegatedContent(void)
2487 {
2488  return SigTestPositiveTestContent("alert tcp any any -> any any (content:\"aaa\"; "
2489  "content:!\"Ggggg\"; distance:57; sid:1;)",
2490  (uint8_t *)"aaa bbbb cccc dddddddd eeeeeeeeeee ffffffffff Ggggggggg hhhhhhhh");
2491 }
2492 
2493 /**
2494  * \test A negative test that checks the combined use of content and negated
2495  * content, in the presence of distance
2496  */
2497 static int SigTest59TestNegatedContent(void)
2498 {
2499  return SigTestNegativeTestContent("alert tcp any any -> any any (content:\"aaa\"; "
2500  "content:!\"Gggg\"; distance:30; sid:1;)",
2501  (uint8_t *)"aaa bbbb cccc dddddddd eeeeeeeeeee ffffffffff Ggggggggg hhhhhhhh");
2502 }
2503 
2504 static int SigTest60TestNegatedContent(void)
2505 {
2506  return SigTestNegativeTestContent(
2507  "alert tcp any any -> any any (content:!\"aaa\"; content:\"Ggggg\"; sid:1;)",
2508  (uint8_t *)"aaa bbbb cccc dddddddd eeeeeeeeeee ffffffffff Ggggggggg hhhhhhhh");
2509 }
2510 
2511 static int SigTest61TestNegatedContent(void)
2512 {
2513  return SigTestPositiveTestContent("alert tcp any any -> any any (content:\"aaa\"; depth:10; "
2514  "content:!\"Ggggg\"; within:30; sid:1;)",
2515  (uint8_t *)"aaa bbbb cccc dddddddd eeeeeeeeeee ffffffffff Ggggggggg hhhhhhhh");
2516 }
2517 
2518 /** \test Test negation in combination with within and depth
2519  *
2520  * Match of "aaa" at offset:0, depth:3
2521  * Match of "Gggggg" at offset:46, depth:52
2522  *
2523  * This signature should not match for the test to pass.
2524  */
2525 static int SigTest62TestNegatedContent(void)
2526 {
2527  return SigTestNegativeTestContent("alert tcp any any -> any any (content:\"aaa\"; depth:10; "
2528  "content:!\"Gggggg\"; within:49; sid:1;)",
2529  (uint8_t *)"aaa bbbb cccc dddddddd eeeeeeeeeee ffffffffff Ggggggggg hhhhhhhh");
2530 }
2531 
2532 static int SigTest63TestNegatedContent(void)
2533 {
2534  return SigTestNegativeTestContent("alert tcp any any -> any any (content:\"aaa\"; depth:10; "
2535  "content:!\"Gggggg\"; within:56; sid:1;)",
2536  (uint8_t *)"aaa bbbb cccc dddddddd eeeeeeeeeee ffffffffff Ggggggggg hhhhhhhh");
2537 }
2538 
2539 static int SigTest64TestNegatedContent(void)
2540 {
2541  return SigTestPositiveTestContent("alert tcp any any -> any any (content:\"aaa\"; depth:10; "
2542  "content:!\"Gggggg\"; within:30; sid:1;)",
2543  (uint8_t *)"aaa bbbb cccc dddddddd eeeeeeeeeee ffffffffff Ggggggggg hhhhhhhh");
2544 }
2545 
2546 /** \test Test negation in combination with within and depth
2547  *
2548  * Match of "aaa" at offset:0, depth:3
2549  * Match of "gggggg" at offset:46, depth:52
2550  *
2551  * This signature should not match for the test to pass.
2552  */
2553 static int SigTest65TestNegatedContent(void)
2554 {
2555  return SigTestNegativeTestContent("alert tcp any any -> any any (content:\"aaa\"; depth:10; "
2556  "content:!\"Gggggg\"; distance:0; within:49; sid:1;)",
2557  (uint8_t *)"aaa bbbb cccc dddddddd eeeeeeeeeee ffffffffff Ggggggggg hhhhhhhh");
2558 }
2559 
2560 static int SigTest66TestNegatedContent(void)
2561 {
2562  return SigTestPositiveTestContent("alert tcp any any -> any any (content:\"aaa\"; depth:10; "
2563  "content:!\"Gggggg\"; within:30; sid:1;)",
2564  (uint8_t *)"aaa bbbb cccc dddddddd eeeeeeeeeee ffffffffff Ggggggggg hhhhhhhh");
2565 }
2566 
2567 static int SigTest67TestNegatedContent(void)
2568 {
2569  return SigTestNegativeTestContent("alert tcp any any -> any any (content:\"aaa\"; depth:10; "
2570  "content:!\"XXXX\"; within:56; sid:1;)",
2571  (uint8_t *)"aaa bbbb cccc XXXXdddd eeeeeeeeeee ffffffffff XXXXggggg hhhhhhhh");
2572 }
2573 
2574 static int SigTest68TestNegatedContent(void)
2575 {
2576  return SigTestPositiveTestContent(
2577  "alert tcp any any -> any any (content:\"aaa\"; depth:10; content:\"cccc\"; offset:8; "
2578  "content:!\"Gggggg\"; within:28; content:\"hhhhhhhh\"; sid:1;)",
2579  (uint8_t *)"aaa bbbb cccc dddddddd eeeeeeeeeee ffffffffff Ggggggggg hhhhhhhh");
2580 }
2581 
2582 static int SigTest69TestNegatedContent(void)
2583 {
2584  return SigTestNegativeTestContent(
2585  "alert tcp any any -> any any (content:\"aaa\"; depth:10; content:\"cccc\"; offset:8; "
2586  "content:!\"Gggggg\"; within:48; content:\"hhhhhhhh\"; sid:1;)",
2587  (uint8_t *)"aaa bbbb cccc dddddddd eeeeeeeeeee ffffffffff Ggggggggg hhhhhhhh");
2588 }
2589 
2590 static int SigTest70TestNegatedContent(void)
2591 {
2592  return SigTestNegativeTestContent("alert tcp any any -> any any (content:\"aaa\"; "
2593  "content:!\"Gggggg\"; within:52; sid:1;)",
2594  (uint8_t *)"aaa bbbb cccc dddddddd eeeeeeeeeee ffffffffff Ggggggggg hhhhhhhh");
2595 }
2596 
2597 /** \test within and distance */
2598 static int SigTest71TestNegatedContent(void)
2599 {
2600  return SigTestNegativeTestContent("alert tcp any any -> any any (content:\"aaa\"; "
2601  "content:!\"Gggggg\"; within:40; distance:43; sid:1;)",
2602  (uint8_t *)"aaa bbbb cccc dddddddd eeeeeeeeeee ffffffffff Ggggggggg hhhhhhhh");
2603 }
2604 
2605 static int SigTest72TestNegatedContent(void)
2606 {
2607  return SigTestNegativeTestContent("alert tcp any any -> any any (content:\"aaa\"; "
2608  "content:!\"Gggggg\"; within:49; distance:43; sid:1;)",
2609  (uint8_t *)"aaa bbbb cccc dddddddd eeeeeeeeeee ffffffffff Ggggggggg hhhhhhhh");
2610 }
2611 
2612 static int SigTest73TestNegatedContent(void)
2613 {
2614  return SigTestNegativeTestContent("alert tcp any any -> any any (content:\"aaa\"; depth:5; "
2615  "content:!\"eeeeeeeeeee\"; depth:35; sid:1;)",
2616  (uint8_t *)"aaa bbbb cccc dddddddd eeeeeeeeeee ffffffffff ggggggggg hhhhhhhh");
2617 }
2618 
2619 static int SigTest74TestNegatedContent(void)
2620 {
2621  return SigTestPositiveTestContent("alert tcp any any -> any any (msg:\"HTTP URI cap\"; content:\"USER\"; content:!\"PASS\"; sid:1;)", (uint8_t *)"USER apple");
2622 }
2623 
2624 static int SigTest75TestNegatedContent(void)
2625 {
2626  return SigTestPositiveTestContent("alert tcp any any -> any any (msg:\"HTTP URI cap\"; content:\"USER\"; content:\"!PASS\"; sid:1;)", (uint8_t *)"USER !PASS");
2627 }
2628 
2629 static int SigTest76TestBug134(void)
2630 {
2631  uint8_t *buf = (uint8_t *)"test detect ${IFS} in traffic";
2632  uint16_t buflen = strlen((char *)buf);
2633  Packet *p = UTHBuildPacket( buf, buflen, IPPROTO_TCP);
2634  int result = 0;
2635  Flow f;
2636 
2637  memset(&f, 0, sizeof(Flow));
2638  FLOW_INITIALIZE(&f);
2639 
2640  p->dp = 515;
2643  p->flow = &f;
2644  p->flags |= PKT_HAS_FLOW;
2645 
2646  char sig[] = "alert tcp any any -> any 515 "
2647  "(msg:\"detect IFS\"; flow:to_server,established; content:\"${IFS}\";"
2648  " depth:50; offset:0; sid:900091; rev:1;)";
2649  if (UTHPacketMatchSigMpm(p, sig, MPM_AC) == 0) {
2650  result = 0;
2651  goto end;
2652  }
2653 
2654  result = 1;
2655 end:
2656  if (p != NULL)
2657  UTHFreePacket(p);
2658 
2659  FLOW_DESTROY(&f);
2660  return result;
2661 }
2662 
2663 static int SigTest77TestBug139(void)
2664 {
2665  uint8_t buf[] = {
2666  0x12, 0x23, 0x34, 0x35, 0x52, 0x52, 0x24, 0x42, 0x22, 0x24,
2667  0x52, 0x24, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x34 };
2668  uint16_t buflen = sizeof(buf);
2669  Packet *p = UTHBuildPacket( buf, buflen, IPPROTO_UDP);
2670  int result = 0;
2671 
2672  p->dp = 53;
2673  char sig[] = "alert udp any any -> any 53 (msg:\"dns testing\";"
2674  " content:\"|00 00|\"; depth:5; offset:13; sid:9436601;"
2675  " rev:1;)";
2676  if (UTHPacketMatchSigMpm(p, sig, MPM_AC) == 0) {
2677  result = 0;
2678  goto end;
2679  }
2680 
2681  result = 1;
2682 end:
2683  if (p != NULL)
2684  UTHFreePacket(p);
2685  return result;
2686 }
2687 
2688 static int DetectLongContentTestCommon(const char *sig, uint32_t sid)
2689 {
2690  /* Packet with 512 A's in it for testing long content. */
2691  static uint8_t pkt[739] = {
2692  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2693  0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x45, 0x00,
2694  0x02, 0xd5, 0x4a, 0x18, 0x40, 0x00, 0x40, 0x06,
2695  0xd7, 0xd6, 0x0a, 0x10, 0x01, 0x0b, 0x0a, 0x10,
2696  0x01, 0x0a, 0xdb, 0x36, 0x00, 0x50, 0xca, 0xc5,
2697  0xcc, 0xd1, 0x95, 0x77, 0x0f, 0x7d, 0x80, 0x18,
2698  0x00, 0xe5, 0x77, 0x9d, 0x00, 0x00, 0x01, 0x01,
2699  0x08, 0x0a, 0x1d, 0xe0, 0x86, 0xc6, 0xfc, 0x73,
2700  0x49, 0xf3, 0x50, 0x4f, 0x53, 0x54, 0x20, 0x2f,
2701  0x20, 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e,
2702  0x31, 0x0d, 0x0a, 0x55, 0x73, 0x65, 0x72, 0x2d,
2703  0x41, 0x67, 0x65, 0x6e, 0x74, 0x3a, 0x20, 0x63,
2704  0x75, 0x72, 0x6c, 0x2f, 0x37, 0x2e, 0x33, 0x37,
2705  0x2e, 0x30, 0x0d, 0x0a, 0x48, 0x6f, 0x73, 0x74,
2706  0x3a, 0x20, 0x31, 0x30, 0x2e, 0x31, 0x36, 0x2e,
2707  0x31, 0x2e, 0x31, 0x30, 0x0d, 0x0a, 0x41, 0x63,
2708  0x63, 0x65, 0x70, 0x74, 0x3a, 0x20, 0x2a, 0x2f,
2709  0x2a, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, 0x74, 0x65,
2710  0x6e, 0x74, 0x2d, 0x4c, 0x65, 0x6e, 0x67, 0x74,
2711  0x68, 0x3a, 0x20, 0x35, 0x32, 0x38, 0x0d, 0x0a,
2712  0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d,
2713  0x54, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x61, 0x70,
2714  0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f,
2715  0x6e, 0x2f, 0x78, 0x2d, 0x77, 0x77, 0x77, 0x2d,
2716  0x66, 0x6f, 0x72, 0x6d, 0x2d, 0x75, 0x72, 0x6c,
2717  0x65, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x64, 0x0d,
2718  0x0a, 0x0d, 0x0a, 0x58, 0x58, 0x58, 0x58, 0x58,
2719  0x58, 0x58, 0x58, 0x41, 0x41, 0x41, 0x41, 0x41,
2720  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2721  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2722  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2723  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2724  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2725  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2726  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2727  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2728  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2729  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2730  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2731  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2732  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2733  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2734  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2735  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2736  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2737  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2738  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2739  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2740  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2741  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2742  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2743  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2744  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2745  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2746  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2747  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2748  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2749  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2750  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2751  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2752  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2753  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2754  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2755  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2756  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2757  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2758  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2759  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2760  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2761  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2762  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2763  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2764  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2765  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2766  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2767  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2768  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2769  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2770  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2771  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2772  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2773  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2774  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2775  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2776  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2777  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2778  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2779  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2780  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2781  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2782  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
2783  0x41, 0x41, 0x41, 0x58, 0x58, 0x58, 0x58, 0x58,
2784  0x58, 0x58, 0x58
2785  };
2786 
2787  return DetectContentLongPatternMatchTest(pkt, (uint16_t)sizeof(pkt), sig,
2788  sid);
2789 }
2790 
2791 static int DetectLongContentTest1(void)
2792 {
2793  /* Signature with 256 A's. */
2794  const char *sig = "alert tcp any any -> any any (msg:\"Test Rule\"; content:\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\"; sid:1;)";
2795 
2796  return DetectLongContentTestCommon(sig, 1);
2797 }
2798 
2799 static int DetectLongContentTest2(void)
2800 {
2801  /* Signature with 512 A's. */
2802  const char *sig = "alert tcp any any -> any any (msg:\"Test Rule\"; content:\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\"; sid:1;)";
2803 
2804  return DetectLongContentTestCommon(sig, 1);
2805 }
2806 
2807 static int DetectLongContentTest3(void)
2808 {
2809  /* Signature with 513 A's. */
2810  const char *sig = "alert tcp any any -> any any (msg:\"Test Rule\"; content:\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\"; sid:1;)";
2811 
2812  return !DetectLongContentTestCommon(sig, 1);
2813 }
2814 
2815 static int DetectBadBinContent(void)
2816 {
2817  DetectEngineCtx *de_ctx = NULL;
2820  de_ctx->flags |= DE_QUIET;
2822  de_ctx, "alert tcp any any -> any any (msg:\"test\"; content:\"|a|\"; sid:1;)"));
2824  de_ctx, "alert tcp any any -> any any (msg:\"test\"; content:\"|aa b|\"; sid:1;)"));
2826  de_ctx, "alert tcp any any -> any any (msg:\"test\"; content:\"|aa bz|\"; sid:1;)"));
2827  /* https://redmine.openinfosecfoundation.org/issues/5201 */
2829  de_ctx, "alert tcp any any -> any any (msg:\"test\"; content:\"|22 2 22|\"; sid:1;)"));
2831  PASS;
2832 }
2833 
2834 /**
2835  * \brief this function registers unit tests for DetectContent
2836  */
2837 static void DetectContentRegisterTests(void)
2838 {
2839  g_file_data_buffer_id = DetectBufferTypeGetByName("file_data");
2840  g_dce_stub_data_buffer_id = DetectBufferTypeGetByName("dce_stub_data");
2841 
2842  UtRegisterTest("DetectContentDepthTest01", DetectContentDepthTest01);
2843 
2844  UtRegisterTest("DetectContentParseTest01", DetectContentParseTest01);
2845  UtRegisterTest("DetectContentParseTest02", DetectContentParseTest02);
2846  UtRegisterTest("DetectContentParseTest03", DetectContentParseTest03);
2847  UtRegisterTest("DetectContentParseTest04", DetectContentParseTest04);
2848  UtRegisterTest("DetectContentParseTest05", DetectContentParseTest05);
2849  UtRegisterTest("DetectContentParseTest06", DetectContentParseTest06);
2850  UtRegisterTest("DetectContentParseTest07", DetectContentParseTest07);
2851  UtRegisterTest("DetectContentParseTest08", DetectContentParseTest08);
2852  UtRegisterTest("DetectContentParseTest09", DetectContentParseTest09);
2853  UtRegisterTest("DetectContentParseTest17", DetectContentParseTest17);
2854  UtRegisterTest("DetectContentParseTest18", DetectContentParseTest18);
2855  UtRegisterTest("DetectContentParseTest19", DetectContentParseTest19);
2856  UtRegisterTest("DetectContentParseTest20", DetectContentParseTest20);
2857  UtRegisterTest("DetectContentParseTest21", DetectContentParseTest21);
2858  UtRegisterTest("DetectContentParseTest22", DetectContentParseTest22);
2859  UtRegisterTest("DetectContentParseTest23", DetectContentParseTest23);
2860  UtRegisterTest("DetectContentParseTest24", DetectContentParseTest24);
2861  UtRegisterTest("DetectContentParseTest25", DetectContentParseTest25);
2862  UtRegisterTest("DetectContentParseTest26", DetectContentParseTest26);
2863  UtRegisterTest("DetectContentParseTest27", DetectContentParseTest27);
2864  UtRegisterTest("DetectContentParseTest28", DetectContentParseTest28);
2865  UtRegisterTest("DetectContentParseTest29", DetectContentParseTest29);
2866  UtRegisterTest("DetectContentParseTest30", DetectContentParseTest30);
2867  UtRegisterTest("DetectContentParseTest31", DetectContentParseTest31);
2868  UtRegisterTest("DetectContentParseTest32", DetectContentParseTest32);
2869  UtRegisterTest("DetectContentParseTest33", DetectContentParseTest33);
2870  UtRegisterTest("DetectContentParseTest34", DetectContentParseTest34);
2871  UtRegisterTest("DetectContentParseTest35", DetectContentParseTest35);
2872  UtRegisterTest("DetectContentParseTest41", DetectContentParseTest41);
2873  UtRegisterTest("DetectContentParseTest42", DetectContentParseTest42);
2874  UtRegisterTest("DetectContentParseTest43", DetectContentParseTest43);
2875  UtRegisterTest("DetectContentParseTest44", DetectContentParseTest44);
2876  UtRegisterTest("DetectContentParseTest45", DetectContentParseTest45);
2877 
2878  /* The reals */
2879  UtRegisterTest("DetectContentLongPatternMatchTest01",
2880  DetectContentLongPatternMatchTest01);
2881  UtRegisterTest("DetectContentLongPatternMatchTest02",
2882  DetectContentLongPatternMatchTest02);
2883  UtRegisterTest("DetectContentLongPatternMatchTest03",
2884  DetectContentLongPatternMatchTest03);
2885  UtRegisterTest("DetectContentLongPatternMatchTest04",
2886  DetectContentLongPatternMatchTest04);
2887  UtRegisterTest("DetectContentLongPatternMatchTest05",
2888  DetectContentLongPatternMatchTest05);
2889  UtRegisterTest("DetectContentLongPatternMatchTest06",
2890  DetectContentLongPatternMatchTest06);
2891  UtRegisterTest("DetectContentLongPatternMatchTest07",
2892  DetectContentLongPatternMatchTest07);
2893  UtRegisterTest("DetectContentLongPatternMatchTest08",
2894  DetectContentLongPatternMatchTest08);
2895  UtRegisterTest("DetectContentLongPatternMatchTest09",
2896  DetectContentLongPatternMatchTest09);
2897  UtRegisterTest("DetectContentLongPatternMatchTest10",
2898  DetectContentLongPatternMatchTest10);
2899  UtRegisterTest("DetectContentLongPatternMatchTest11",
2900  DetectContentLongPatternMatchTest11);
2901 
2902  /* Negated content tests */
2903  UtRegisterTest("SigTest41TestNegatedContent", SigTest41TestNegatedContent);
2904  UtRegisterTest("SigTest41aTestNegatedContent",
2905  SigTest41aTestNegatedContent);
2906  UtRegisterTest("SigTest42TestNegatedContent", SigTest42TestNegatedContent);
2907  UtRegisterTest("SigTest43TestNegatedContent", SigTest43TestNegatedContent);
2908  UtRegisterTest("SigTest44TestNegatedContent", SigTest44TestNegatedContent);
2909  UtRegisterTest("SigTest45TestNegatedContent", SigTest45TestNegatedContent);
2910  UtRegisterTest("SigTest46TestNegatedContent", SigTest46TestNegatedContent);
2911  UtRegisterTest("SigTest47TestNegatedContent", SigTest47TestNegatedContent);
2912  UtRegisterTest("SigTest48TestNegatedContent", SigTest48TestNegatedContent);
2913  UtRegisterTest("SigTest49TestNegatedContent", SigTest49TestNegatedContent);
2914  UtRegisterTest("SigTest50TestNegatedContent", SigTest50TestNegatedContent);
2915  UtRegisterTest("SigTest51TestNegatedContent", SigTest51TestNegatedContent);
2916  UtRegisterTest("SigTest52TestNegatedContent", SigTest52TestNegatedContent);
2917  UtRegisterTest("SigTest53TestNegatedContent", SigTest53TestNegatedContent);
2918  UtRegisterTest("SigTest54TestNegatedContent", SigTest54TestNegatedContent);
2919  UtRegisterTest("SigTest55TestNegatedContent", SigTest55TestNegatedContent);
2920  UtRegisterTest("SigTest56TestNegatedContent", SigTest56TestNegatedContent);
2921  UtRegisterTest("SigTest57TestNegatedContent", SigTest57TestNegatedContent);
2922  UtRegisterTest("SigTest58TestNegatedContent", SigTest58TestNegatedContent);
2923  UtRegisterTest("SigTest59TestNegatedContent", SigTest59TestNegatedContent);
2924  UtRegisterTest("SigTest60TestNegatedContent", SigTest60TestNegatedContent);
2925  UtRegisterTest("SigTest61TestNegatedContent", SigTest61TestNegatedContent);
2926  UtRegisterTest("SigTest62TestNegatedContent", SigTest62TestNegatedContent);
2927  UtRegisterTest("SigTest63TestNegatedContent", SigTest63TestNegatedContent);
2928  UtRegisterTest("SigTest64TestNegatedContent", SigTest64TestNegatedContent);
2929  UtRegisterTest("SigTest65TestNegatedContent", SigTest65TestNegatedContent);
2930  UtRegisterTest("SigTest66TestNegatedContent", SigTest66TestNegatedContent);
2931  UtRegisterTest("SigTest67TestNegatedContent", SigTest67TestNegatedContent);
2932  UtRegisterTest("SigTest68TestNegatedContent", SigTest68TestNegatedContent);
2933  UtRegisterTest("SigTest69TestNegatedContent", SigTest69TestNegatedContent);
2934  UtRegisterTest("SigTest70TestNegatedContent", SigTest70TestNegatedContent);
2935  UtRegisterTest("SigTest71TestNegatedContent", SigTest71TestNegatedContent);
2936  UtRegisterTest("SigTest72TestNegatedContent", SigTest72TestNegatedContent);
2937  UtRegisterTest("SigTest73TestNegatedContent", SigTest73TestNegatedContent);
2938  UtRegisterTest("SigTest74TestNegatedContent", SigTest74TestNegatedContent);
2939  UtRegisterTest("SigTest75TestNegatedContent", SigTest75TestNegatedContent);
2940 
2941  UtRegisterTest("SigTest76TestBug134", SigTest76TestBug134);
2942  UtRegisterTest("SigTest77TestBug139", SigTest77TestBug139);
2943 
2944  UtRegisterTest("DetectLongContentTest1", DetectLongContentTest1);
2945  UtRegisterTest("DetectLongContentTest2", DetectLongContentTest2);
2946  UtRegisterTest("DetectLongContentTest3", DetectLongContentTest3);
2947 
2948  UtRegisterTest("DetectBadBinContent", DetectBadBinContent);
2949 }
2950 #endif /* UNITTESTS */
DETECT_CONTENT_NOCASE
#define DETECT_CONTENT_NOCASE
Definition: detect-content.h:29
DetectContentData_::offset
uint16_t offset
Definition: detect-content.h:107
host.h
SigTableElmt_::url
const char * url
Definition: detect.h:1460
DETECT_CONTENT_RELATIVE_NEXT
#define DETECT_CONTENT_RELATIVE_NEXT
Definition: detect-content.h:66
SignatureInitDataBuffer_::head
SigMatch * head
Definition: detect.h:534
detect-content.h
len
uint8_t len
Definition: app-layer-dnp3.h:2
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
detect-dsize.h
sigmatch_table
SigTableElmt * sigmatch_table
Definition: detect-parse.c:79
PKT_HAS_FLOW
#define PKT_HAS_FLOW
Definition: decode.h:1266
offset
uint64_t offset
Definition: util-streaming-buffer.h:0
SinglePatternMatchDefaultMatcher
uint8_t SinglePatternMatchDefaultMatcher(void)
Returns the single pattern matcher algorithm to be used, based on the spm-algo setting in yaml.
Definition: util-spm.c:68
ALPROTO_DCERPC
@ ALPROTO_DCERPC
Definition: app-layer-protos.h:44
SigTableElmt_::Free
void(* Free)(DetectEngineCtx *, void *)
Definition: detect.h:1444
DETECT_CONTENT_DISTANCE_VAR
#define DETECT_CONTENT_DISTANCE_VAR
Definition: detect-content.h:47
flow-util.h
DetectBufferGetFirstSigMatch
SigMatch * DetectBufferGetFirstSigMatch(const Signature *s, const uint32_t buf_id)
Definition: detect-engine-buffer.c:157
SigTableElmt_::name
const char * name
Definition: detect.h:1457
SignatureInitData_::smlists_tail
struct SigMatch_ * smlists_tail[DETECT_SM_LIST_MAX]
Definition: detect.h:644
SigFree
void SigFree(DetectEngineCtx *, Signature *)
Definition: detect-parse.c:2057
unlikely
#define unlikely(expr)
Definition: util-optimize.h:35
DetectContentData_::within
int32_t within
Definition: detect-content.h:109
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
SCLogDebug
#define SCLogDebug(...)
Definition: util-debug.h:275
DETECT_CONTENT_WITHIN2DEPTH
#define DETECT_CONTENT_WITHIN2DEPTH
Definition: detect-content.h:62
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
Packet_::flags
uint32_t flags
Definition: decode.h:544
PacketRecycle
void PacketRecycle(Packet *p)
Definition: packet.c:150
threads.h
Flow_
Flow data structure.
Definition: flow.h:348
SigTableElmt_::flags
uint16_t flags
Definition: detect.h:1448
DetectEngineCtx_
main detection engine ctx
Definition: detect.h:932
UTHPacketMatchSigMpm
int UTHPacketMatchSigMpm(Packet *p, char *sig, uint16_t mpm_type)
Definition: util-unittest-helper.c:756
SigParseGetMaxDsize
int SigParseGetMaxDsize(const Signature *s, uint16_t *dsize)
get max dsize "depth"
Definition: detect-dsize.c:212
DetectEngineCtxFree
void DetectEngineCtxFree(DetectEngineCtx *)
Free a DetectEngineCtx::
Definition: detect-engine.c:2642
DetectContentConvertToNocase
int DetectContentConvertToNocase(DetectEngineCtx *de_ctx, DetectContentData *cd)
Definition: detect-content.c:769
FLOW_PKT_TOSERVER
#define FLOW_PKT_TOSERVER
Definition: flow.h:225
u8_tolower
#define u8_tolower(c)
Definition: suricata-common.h:453
MIN
#define MIN(x, y)
Definition: suricata-common.h:408
DE_QUIET
#define DE_QUIET
Definition: detect.h:330
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
DetectContentData_
Definition: detect-content.h:93
DetectPcreData_::flags
uint16_t flags
Definition: detect-pcre.h:51
SigCleanSignatures
void SigCleanSignatures(DetectEngineCtx *de_ctx)
Definition: detect-engine-build.c:56
SCDetectSignatureSetAppProto
int SCDetectSignatureSetAppProto(Signature *s, AppProto alproto)
Definition: detect-parse.c:2229
SIGMATCH_SUPPORT_FIREWALL
#define SIGMATCH_SUPPORT_FIREWALL
Definition: detect.h:1680
DetectEngineAppendSig
Signature * DetectEngineAppendSig(DetectEngineCtx *, const char *)
Parse and append a Signature into the Detection Engine Context signature list.
Definition: detect-parse.c:3437
Packet_::flowflags
uint8_t flowflags
Definition: decode.h:532
MAX
#define MAX(x, y)
Definition: suricata-common.h:412
DetectBufferIsPresent
bool DetectBufferIsPresent(const Signature *s, const uint32_t buf_id)
Definition: detect-engine.c:1512
SigTableElmt_::Setup
int(* Setup)(DetectEngineCtx *, Signature *, const char *)
Definition: detect.h:1439
detect-pcre.h
DetectContentFree
void DetectContentFree(DetectEngineCtx *de_ctx, void *ptr)
this function will SCFree memory associated with DetectContentData
Definition: detect-content.c:374
DetectContentPMATCHValidateCallback
bool DetectContentPMATCHValidateCallback(const Signature *s)
Definition: detect-content.c:458
util-unittest.h
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
strlcpy
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: util-strlcpyu.c:43
SIGMATCH_QUOTES_MANDATORY
#define SIGMATCH_QUOTES_MANDATORY
Definition: detect.h:1666
FlowInitConfig
void FlowInitConfig(bool quiet)
initialize the configuration
Definition: flow.c:546
FLOW_INITIALIZE
#define FLOW_INITIALIZE(f)
Definition: flow-util.h:38
DetectContentPrint
void DetectContentPrint(DetectContentData *cd)
Helper function to print a DetectContentData.
Definition: detect-content.c:264
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_CONTENT_ENDS_WITH
#define DETECT_CONTENT_ENDS_WITH
Definition: detect-content.h:42
SpmInitGlobalThreadCtx
SpmGlobalThreadCtx * SpmInitGlobalThreadCtx(uint8_t matcher)
Definition: util-spm.c:138
DETECT_CONTENT_DISTANCE
#define DETECT_CONTENT_DISTANCE
Definition: detect-content.h:30
de_ctx
DetectEngineCtx * de_ctx
Definition: fuzz_siginit.c:18
DetectContentSetup
int DetectContentSetup(DetectEngineCtx *de_ctx, Signature *s, const char *contentstr)
Function to setup a content pattern.
Definition: detect-content.c:330
DetectEngineThreadCtx_
Definition: detect.h:1244
strlcat
size_t strlcat(char *, const char *src, size_t siz)
Definition: util-strlcatu.c:45
DetectContentRegister
void DetectContentRegister(void)
Definition: detect-content.c:59
DETECT_CONTENT_DEPTH
#define DETECT_CONTENT_DEPTH
Definition: detect-content.h:33
DETECT_CONTENT_DISTANCE2OFFSET
#define DETECT_CONTENT_DISTANCE2OFFSET
Definition: detect-content.h:63
SignatureInitData_::list
int list
Definition: detect.h:628
util-print.h
SCEnter
#define SCEnter(...)
Definition: util-debug.h:277
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
DetectEngineBufferTypeValidateTransform
bool DetectEngineBufferTypeValidateTransform(DetectEngineCtx *de_ctx, int sm_list, const uint8_t *content, uint16_t content_len, const char **namestr)
Check content byte array compatibility with transforms.
Definition: detect-engine.c:1540
pkt-var.h
DetectEngineThreadCtxInit
TmEcode DetectEngineThreadCtxInit(ThreadVars *tv, void *initdata, void **data)
initialize thread specific detection engine context
Definition: detect-engine.c:3369
SigMatch_::next
struct SigMatch_ * next
Definition: detect.h:360
DETECT_CONTENT_NEGATED
#define DETECT_CONTENT_NEGATED
Definition: detect-content.h:40
DETECT_SM_LIST_MATCH
@ DETECT_SM_LIST_MATCH
Definition: detect.h:117
DetectContentPropagateLimits
void DetectContentPropagateLimits(Signature *s)
Definition: detect-content.c:720
SigInit
Signature * SigInit(DetectEngineCtx *de_ctx, const char *sigstr)
Parses a signature and adds it to the Detection Engine Context.
Definition: detect-parse.c:3095
DetectContentData_::id
PatIntId id
Definition: detect-content.h:105
SigMatch_::ctx
SigMatchCtx * ctx
Definition: detect.h:359
SigGroupCleanup
int SigGroupCleanup(DetectEngineCtx *de_ctx)
Definition: detect-engine-build.c:2256
util-profiling.h
SCReturn
#define SCReturn
Definition: util-debug.h:279
Signature_::flags
uint32_t flags
Definition: detect.h:669
DetectContentData_::depth
uint16_t depth
Definition: detect-content.h:106
Packet_
Definition: decode.h:501
detect-engine-build.h
SigParseRequiredContentSize
void SigParseRequiredContentSize(const Signature *s, const uint64_t max_size, const SigMatch *sm, int *len, int *offset)
Determine the size needed to accommodate the content elements of a signature.
Definition: detect-content.c:410
detect-engine-alert.h
DetectContentData_::flags
uint32_t flags
Definition: detect-content.h:104
DetectContentData_::replace_len
uint16_t replace_len
Definition: detect-content.h:96
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
DetectContentPatternPrettyPrint
void DetectContentPatternPrettyPrint(const DetectContentData *cd, char *str, size_t str_len)
Definition: detect-content.c:748
DetectContentData_::replace
uint8_t * replace
Definition: detect-content.h:113
DETECT_PCRE
@ DETECT_PCRE
Definition: detect-engine-register.h:71
SpmDestroyGlobalThreadCtx
void SpmDestroyGlobalThreadCtx(SpmGlobalThreadCtx *global_thread_ctx)
Definition: util-spm.c:144
VALIDATE
#define VALIDATE(e)
SigGroupBuild
int SigGroupBuild(DetectEngineCtx *de_ctx)
Convert the signature list into the runtime match structure.
Definition: detect-engine-build.c:2185
dtv
DecodeThreadVars * dtv
Definition: fuzz_decodepcapfile.c:33
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
DetectContentDataParse
int DetectContentDataParse(const char *keyword, const char *contentstr, uint8_t **pstr, uint16_t *plen)
Parse a content string, ie "abc|DE|fgh".
Definition: detect-content.c:85
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
util-mpm.h
suricata-common.h
SigMatch_::type
uint16_t type
Definition: detect.h:357
DetectContentData_::distance
int32_t distance
Definition: detect-content.h:108
FlowShutdown
void FlowShutdown(void)
shutdown the flow engine
Definition: flow.c:690
packet.h
DetectEngineThreadCtxDeinit
TmEcode DetectEngineThreadCtxDeinit(ThreadVars *tv, void *data)
Definition: detect-engine.c:3601
util-spm.h
DetectContentData_::content
uint8_t * content
Definition: detect-content.h:94
detect-engine-buffer.h
DetectEngineCtx_::sig_list
Signature * sig_list
Definition: detect.h:941
PrintRawUriFp
void PrintRawUriFp(FILE *fp, const uint8_t *buf, uint32_t buflen)
Definition: util-print.c:69
PacketGetFromAlloc
Packet * PacketGetFromAlloc(void)
Get a malloced packet.
Definition: decode.c:258
SpmGlobalThreadCtx_
Definition: util-spm.h:47
detect-flow.h
SCMalloc
#define SCMalloc(sz)
Definition: util-mem.h:47
DetectContentData_::spm_ctx
SpmCtx * spm_ctx
Definition: detect-content.h:111
SignatureInitData_::buffers
SignatureInitDataBuffer * buffers
Definition: detect.h:647
str
#define str(s)
Definition: suricata-common.h:308
SCLogError
#define SCLogError(...)
Macro used to log ERROR messages.
Definition: util-debug.h:267
SCFree
#define SCFree(p)
Definition: util-mem.h:61
DecodeThreadVars_
Structure to hold thread specific data for all decode modules.
Definition: decode.h:963
UTHFreePacket
void UTHFreePacket(Packet *p)
UTHFreePacket: function to release the allocated data from UTHBuildPacket and the packet itself.
Definition: util-unittest-helper.c:473
DETECT_CONTENT_OFFSET
#define DETECT_CONTENT_OFFSET
Definition: detect-content.h:32
TEST_RUN
#define TEST_RUN(sig, o, d)
Definition: detect-content.c:819
DETECT_CONTENT_MPM
#define DETECT_CONTENT_MPM
Definition: detect-content.h:61
detect-parse.h
Signature_
Signature container.
Definition: detect.h:668
SigMatch_
a single match condition for a signature
Definition: detect.h:356
DETECT_SM_LIST_MAX
@ DETECT_SM_LIST_MAX
Definition: detect.h:135
FLOW_PKT_ESTABLISHED
#define FLOW_PKT_ESTABLISHED
Definition: flow.h:227
DetectEngineCtxInit
DetectEngineCtx * DetectEngineCtxInit(void)
Definition: detect-engine.c:2603
DetectPcreData_
Definition: detect-pcre.h:47
FLOW_QUIET
#define FLOW_QUIET
Definition: flow.h:43
DetectContentData_::content_len
uint16_t content_len
Definition: detect-content.h:95
detect-uricontent.h
DetectEngineCtx_::spm_global_thread_ctx
SpmGlobalThreadCtx * spm_global_thread_ctx
Definition: detect.h:986
DetectContentParse
DetectContentData * DetectContentParse(SpmGlobalThreadCtx *spm_global_thread_ctx, const char *contentstr)
DetectContentParse \initonly.
Definition: detect-content.c:213
DetectEngineCtx_::flags
uint8_t flags
Definition: detect.h:934
DetectContentParseEncloseQuotes
DetectContentData * DetectContentParseEncloseQuotes(SpmGlobalThreadCtx *spm_global_thread_ctx, const char *contentstr)
Definition: detect-content.c:255
DETECT_PCRE_RELATIVE
#define DETECT_PCRE_RELATIVE
Definition: detect-pcre.h:29
SigAlloc
Signature * SigAlloc(void)
Definition: detect-parse.c:1937
flow.h
SpmDestroyCtx
void SpmDestroyCtx(SpmCtx *ctx)
Definition: util-spm.c:183
Packet_::dp
Port dp
Definition: decode.h:516
SCCalloc
#define SCCalloc(nm, sz)
Definition: util-mem.h:53
SigParseMaxRequiredDsize
int SigParseMaxRequiredDsize(const Signature *s)
Determine the required dsize for the signature.
Definition: detect-dsize.c:291
DetectBufferGetActiveList
int DetectBufferGetActiveList(DetectEngineCtx *de_ctx, Signature *s)
Definition: detect-engine-buffer.c:109
SignatureInitData_::buffer_index
uint32_t buffer_index
Definition: detect.h:648
flow-var.h
SpmInitCtx
SpmCtx * SpmInitCtx(const uint8_t *needle, uint16_t needle_len, int nocase, SpmGlobalThreadCtx *global_thread_ctx)
Definition: util-spm.c:173
SCLogDebugEnabled
int SCLogDebugEnabled(void)
Returns whether debug messages are enabled to be logged or not.
Definition: util-debug.c:767
DecodeEthernet
int DecodeEthernet(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint32_t len)
Definition: decode-ethernet.c:42
FLOW_DESTROY
#define FLOW_DESTROY(f)
Definition: flow-util.h:119
DETECT_CONTENT_WITHIN
#define DETECT_CONTENT_WITHIN
Definition: detect-content.h:31
SigTableElmt_::RegisterTests
void(* RegisterTests)(void)
Definition: detect.h:1446
SIG_FLAG_DSIZE
#define SIG_FLAG_DSIZE
Definition: detect.h:248
TEST_DONE
#define TEST_DONE
Definition: detect-content.c:835
app-layer.h
UTHFreePackets
void UTHFreePackets(Packet **p, int numpkts)
UTHFreePackets: function to release the allocated data from UTHBuildPacket and the packet itself.
Definition: util-unittest-helper.c:456
MPM_AC
@ MPM_AC
Definition: util-mpm.h:36