suricata
detect-dsize.c
Go to the documentation of this file.
1 /* Copyright (C) 2007-2010 Open Information Security Foundation
2  *
3  * You can copy, redistribute or modify this Program under the terms of
4  * the GNU General Public License version 2 as published by the Free
5  * Software Foundation.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * version 2 along with this program; if not, write to the Free Software
14  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15  * 02110-1301, USA.
16  */
17 
18 /**
19  * \file
20  *
21  * \author Victor Julien <victor@inliniac.net>
22  *
23  * Implements the dsize keyword
24  */
25 
26 #include "suricata-common.h"
27 #include "decode.h"
28 
29 #include "detect.h"
30 #include "detect-parse.h"
32 
33 #include "flow-var.h"
34 
35 #include "detect-content.h"
36 #include "detect-dsize.h"
37 
38 #include "util-unittest.h"
39 #include "util-debug.h"
40 #include "util-byte.h"
41 
42 #include "pkt-var.h"
43 #include "host.h"
44 #include "util-profiling.h"
45 
46 /**
47  * dsize:[<>]<0-65535>[<><0-65535>];
48  */
49 #define PARSE_REGEX "^\\s*(<|>)?\\s*([0-9]{1,5})\\s*(?:(<>)\\s*([0-9]{1,5}))?\\s*$"
50 static pcre *parse_regex;
51 static pcre_extra *parse_regex_study;
52 
53 static int DetectDsizeMatch (DetectEngineThreadCtx *, Packet *,
54  const Signature *, const SigMatchCtx *);
55 static int DetectDsizeSetup (DetectEngineCtx *, Signature *s, const char *str);
56 static void DsizeRegisterTests(void);
57 static void DetectDsizeFree(void *);
58 
59 static int PrefilterSetupDsize(DetectEngineCtx *de_ctx, SigGroupHead *sgh);
60 static _Bool PrefilterDsizeIsPrefilterable(const Signature *s);
61 
62 /**
63  * \brief Registration function for dsize: keyword
64  */
66 {
67  sigmatch_table[DETECT_DSIZE].name = "dsize";
68  sigmatch_table[DETECT_DSIZE].desc = "match on the size of the packet payload";
69  sigmatch_table[DETECT_DSIZE].url = DOC_URL DOC_VERSION "/rules/payload-keywords.html#dsize";
70  sigmatch_table[DETECT_DSIZE].Match = DetectDsizeMatch;
71  sigmatch_table[DETECT_DSIZE].Setup = DetectDsizeSetup;
72  sigmatch_table[DETECT_DSIZE].Free = DetectDsizeFree;
73  sigmatch_table[DETECT_DSIZE].RegisterTests = DsizeRegisterTests;
74 
75  sigmatch_table[DETECT_DSIZE].SupportsPrefilter = PrefilterDsizeIsPrefilterable;
76  sigmatch_table[DETECT_DSIZE].SetupPrefilter = PrefilterSetupDsize;
77 
78  DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study);
79 }
80 
81 static inline int
82 DsizeMatch(const uint16_t psize, const uint8_t mode,
83  const uint16_t dsize, const uint16_t dsize2)
84 {
85  if (mode == DETECTDSIZE_EQ && dsize == psize)
86  return 1;
87  else if (mode == DETECTDSIZE_LT && psize < dsize)
88  return 1;
89  else if (mode == DETECTDSIZE_GT && psize > dsize)
90  return 1;
91  else if (mode == DETECTDSIZE_RA && psize > dsize && psize < dsize2)
92  return 1;
93 
94  return 0;
95 }
96 
97 /**
98  * \internal
99  * \brief This function is used to match flags on a packet with those passed via dsize:
100  *
101  * \param t pointer to thread vars
102  * \param det_ctx pointer to the pattern matcher thread
103  * \param p pointer to the current packet
104  * \param s pointer to the Signature
105  * \param m pointer to the sigmatch
106  *
107  * \retval 0 no match
108  * \retval 1 match
109  */
110 static int DetectDsizeMatch (DetectEngineThreadCtx *det_ctx, Packet *p,
111  const Signature *s, const SigMatchCtx *ctx)
112 {
113  SCEnter();
114  int ret = 0;
115 
116  if (PKT_IS_PSEUDOPKT(p)) {
117  SCReturnInt(0);
118  }
119 
120  const DetectDsizeData *dd = (const DetectDsizeData *)ctx;
121 
122  SCLogDebug("p->payload_len %"PRIu16"", p->payload_len);
123 
124  ret = DsizeMatch(p->payload_len, dd->mode, dd->dsize, dd->dsize2);
125 
126  SCReturnInt(ret);
127 }
128 
129 /**
130  * \internal
131  * \brief This function is used to parse dsize options passed via dsize: keyword
132  *
133  * \param rawstr Pointer to the user provided dsize options
134  *
135  * \retval dd pointer to DetectDsizeData on success
136  * \retval NULL on failure
137  */
138 static DetectDsizeData *DetectDsizeParse (const char *rawstr)
139 {
140  DetectDsizeData *dd = NULL;
141 #define MAX_SUBSTRINGS 30
142  int ret = 0, res = 0;
143  int ov[MAX_SUBSTRINGS];
144  char mode[2] = "";
145  char value1[6] = "";
146  char value2[6] = "";
147  char range[3] = "";
148 
149  ret = pcre_exec(parse_regex, parse_regex_study, rawstr, strlen(rawstr), 0, 0, ov, MAX_SUBSTRINGS);
150  if (ret < 3 || ret > 5) {
151  SCLogError(SC_ERR_PCRE_MATCH,"Parse error %s", rawstr);
152  goto error;
153  }
154 
155  res = pcre_copy_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 1, mode, sizeof(mode));
156  if (res < 0) {
157  SCLogError(SC_ERR_PCRE_GET_SUBSTRING,"pcre_copy_substring failed");
158  goto error;
159  }
160  SCLogDebug("mode \"%s\"", mode);
161 
162  res = pcre_copy_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 2, value1, sizeof(value1));
163  if (res < 0) {
164  SCLogError(SC_ERR_PCRE_GET_SUBSTRING,"pcre_copy_substring failed");
165  goto error;
166  }
167  SCLogDebug("value1 \"%s\"", value1);
168 
169  if (ret > 3) {
170  res = pcre_copy_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 3, range, sizeof(range));
171  if (res < 0) {
172  SCLogError(SC_ERR_PCRE_GET_SUBSTRING,"pcre_copy_substring failed");
173  goto error;
174  }
175  SCLogDebug("range \"%s\"", range);
176 
177  if (ret > 4) {
178  res = pcre_copy_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 4, value2, sizeof(value2));
179  if (res < 0) {
180  SCLogError(SC_ERR_PCRE_GET_SUBSTRING,"pcre_copy_substring failed");
181  goto error;
182  }
183  SCLogDebug("value2 \"%s\"", value2);
184  }
185  }
186 
187  dd = SCMalloc(sizeof(DetectDsizeData));
188  if (unlikely(dd == NULL))
189  goto error;
190  dd->dsize = 0;
191  dd->dsize2 = 0;
192  dd->mode = DETECTDSIZE_EQ; // default
193 
194  if (strlen(mode) > 0) {
195  if (mode[0] == '<')
196  dd->mode = DETECTDSIZE_LT;
197  else if (mode[0] == '>')
198  dd->mode = DETECTDSIZE_GT;
199  else
200  dd->mode = DETECTDSIZE_EQ;
201  }
202 
203  if (strcmp("<>", range) == 0) {
204  if (strlen(mode) != 0) {
205  SCLogError(SC_ERR_INVALID_ARGUMENT,"Range specified but mode also set");
206  goto error;
207  }
208  dd->mode = DETECTDSIZE_RA;
209  }
210 
211  /** set the first dsize value */
212  if (ByteExtractStringUint16(&dd->dsize,10,strlen(value1),value1) <= 0) {
213  SCLogError(SC_ERR_INVALID_ARGUMENT, "Invalid size value1:\"%s\"", value1);
214  goto error;
215  }
216 
217  /** set the second dsize value if specified */
218  if (strlen(value2) > 0) {
219  if (dd->mode != DETECTDSIZE_RA) {
220  SCLogError(SC_ERR_INVALID_ARGUMENT,"Multiple dsize values specified but mode is not range");
221  goto error;
222  }
223 
224  if (ByteExtractStringUint16(&dd->dsize2,10,strlen(value2),value2) <= 0) {
225  SCLogError(SC_ERR_INVALID_ARGUMENT,"Invalid size value2:\"%s\"",value2);
226  goto error;
227  }
228 
229  if (dd->dsize2 <= dd->dsize) {
230  SCLogError(SC_ERR_INVALID_ARGUMENT,"dsize2:%"PRIu16" <= dsize:%"PRIu16"",dd->dsize2,dd->dsize);
231  goto error;
232  }
233  }
234 
235  SCLogDebug("dsize parsed successfully dsize: %"PRIu16" dsize2: %"PRIu16"",dd->dsize,dd->dsize2);
236  return dd;
237 
238 error:
239  if (dd)
240  SCFree(dd);
241  return NULL;
242 }
243 
244 /**
245  * \internal
246  * \brief this function is used to add the parsed dsize into the current signature
247  *
248  * \param de_ctx pointer to the Detection Engine Context
249  * \param s pointer to the Current Signature
250  * \param rawstr pointer to the user provided flags options
251  *
252  * \retval 0 on Success
253  * \retval -1 on Failure
254  */
255 static int DetectDsizeSetup (DetectEngineCtx *de_ctx, Signature *s, const char *rawstr)
256 {
257  DetectDsizeData *dd = NULL;
258  SigMatch *sm = NULL;
259 
261  SCLogError(SC_ERR_INVALID_SIGNATURE, "Can't use 2 or more dsizes in "
262  "the same sig. Invalidating signature.");
263  goto error;
264  }
265 
266  SCLogDebug("\'%s\'", rawstr);
267 
268  dd = DetectDsizeParse(rawstr);
269  if (dd == NULL) {
270  SCLogError(SC_ERR_INVALID_ARGUMENT,"Parsing \'%s\' failed", rawstr);
271  goto error;
272  }
273 
274  /* Okay so far so good, lets get this into a SigMatch
275  * and put it in the Signature. */
276  sm = SigMatchAlloc();
277  if (sm == NULL){
278  SCLogError(SC_ERR_MEM_ALLOC, "Failed to allocate memory for SigMatch");
279  SCFree(dd);
280  goto error;
281  }
282 
283  sm->type = DETECT_DSIZE;
284  sm->ctx = (SigMatchCtx *)dd;
285 
287 
288  SCLogDebug("dd->dsize %"PRIu16", dd->dsize2 %"PRIu16", dd->mode %"PRIu8"",
289  dd->dsize, dd->dsize2, dd->mode);
290  /* tell the sig it has a dsize to speed up engine init */
292  s->flags |= SIG_FLAG_DSIZE;
293 
294  if (s->init_data->dsize_sm == NULL) {
295  s->init_data->dsize_sm = sm;
296  }
297 
298  return 0;
299 
300 error:
301  return -1;
302 }
303 
304 /**
305  * \internal
306  * \brief this function will free memory associated with DetectDsizeData
307  *
308  * \param de pointer to DetectDsizeData
309  */
310 void DetectDsizeFree(void *de_ptr)
311 {
312  DetectDsizeData *dd = (DetectDsizeData *)de_ptr;
313  if(dd) SCFree(dd);
314 }
315 
316 /* prefilter code */
317 
318 static void
319 PrefilterPacketDsizeMatch(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx)
320 {
321  if (PKT_IS_PSEUDOPKT(p)) {
322  SCReturn;
323  }
324 
325  const PrefilterPacketHeaderCtx *ctx = pectx;
326  if (PrefilterPacketHeaderExtraMatch(ctx, p) == FALSE)
327  return;
328 
329  const uint16_t dsize = p->payload_len;
330  if (DsizeMatch(dsize, ctx->v1.u8[0], ctx->v1.u16[1], ctx->v1.u16[2]))
331  {
332  SCLogDebug("packet matches dsize %u", dsize);
333  PrefilterAddSids(&det_ctx->pmq, ctx->sigs_array, ctx->sigs_cnt);
334  }
335 }
336 
337 static void
338 PrefilterPacketDsizeSet(PrefilterPacketHeaderValue *v, void *smctx)
339 {
340  const DetectDsizeData *a = smctx;
341  v->u8[0] = a->mode;
342  v->u16[1] = a->dsize;
343  v->u16[2] = a->dsize2;
344 }
345 
346 static _Bool
347 PrefilterPacketDsizeCompare(PrefilterPacketHeaderValue v, void *smctx)
348 {
349  const DetectDsizeData *a = smctx;
350  if (v.u8[0] == a->mode &&
351  v.u16[1] == a->dsize &&
352  v.u16[2] == a->dsize2)
353  return TRUE;
354  return FALSE;
355 }
356 
357 static int PrefilterSetupDsize(DetectEngineCtx *de_ctx, SigGroupHead *sgh)
358 {
359  return PrefilterSetupPacketHeader(de_ctx, sgh, DETECT_DSIZE,
360  PrefilterPacketDsizeSet,
361  PrefilterPacketDsizeCompare,
362  PrefilterPacketDsizeMatch);
363 }
364 
365 static _Bool PrefilterDsizeIsPrefilterable(const Signature *s)
366 {
367  const SigMatch *sm;
368  for (sm = s->init_data->smlists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) {
369  switch (sm->type) {
370  case DETECT_DSIZE:
371  return TRUE;
372  }
373  }
374  return FALSE;
375 }
376 
377 /** \brief get max dsize "depth"
378  * \param s signature to get dsize value from
379  * \retval depth or negative value
380  */
382 {
383  if (s->flags & SIG_FLAG_DSIZE && s->init_data->dsize_sm != NULL) {
384  const DetectDsizeData *dd = (const DetectDsizeData *)s->init_data->dsize_sm->ctx;
385 
386  switch (dd->mode) {
387  case DETECTDSIZE_LT:
388  case DETECTDSIZE_EQ:
389  return dd->dsize;
390  case DETECTDSIZE_RA:
391  return dd->dsize2;
392  case DETECTDSIZE_GT:
393  default:
394  SCReturnInt(-2);
395  }
396  }
397  SCReturnInt(-1);
398 }
399 
400 /** \brief set prefilter dsize pair
401  * \param s signature to get dsize value from
402  */
404 {
405  if (s->flags & SIG_FLAG_DSIZE && s->init_data->dsize_sm != NULL) {
407 
408  uint16_t low = 0;
409  uint16_t high = 65535;
410 
411  switch (dd->mode) {
412  case DETECTDSIZE_LT:
413  low = 0;
414  high = dd->dsize;
415  break;
416  case DETECTDSIZE_EQ:
417  low = dd->dsize;
418  high = dd->dsize;
419  break;
420  case DETECTDSIZE_RA:
421  low = dd->dsize;
422  high = dd->dsize2;
423  break;
424  case DETECTDSIZE_GT:
425  low = dd->dsize;
426  high = 65535;
427  break;
428  }
429  s->dsize_low = low;
430  s->dsize_high = high;
431 
432  SCLogDebug("low %u, high %u", low, high);
433  }
434 }
435 
436 /**
437  * \brief Apply dsize as depth to content matches in the rule
438  * \param s signature to get dsize value from
439  */
441 {
442  SCEnter();
443 
444  if (s->flags & SIG_FLAG_DSIZE) {
446 
447  int dsize = SigParseGetMaxDsize(s);
448  if (dsize < 0) {
449  /* nothing to do */
450  return;
451  }
452 
454  for ( ; sm != NULL; sm = sm->next) {
455  if (sm->type != DETECT_CONTENT) {
456  continue;
457  }
458 
460  if (cd == NULL) {
461  continue;
462  }
463 
464  if (cd->depth == 0 || cd->depth >= dsize) {
465  cd->depth = (uint16_t)dsize;
466  SCLogDebug("updated %u, content %u to have depth %u "
467  "because of dsize.", s->id, cd->id, cd->depth);
468  }
469  }
470  }
471 }
472 
473 /*
474  * ONLY TESTS BELOW THIS COMMENT
475  */
476 
477 #ifdef UNITTESTS
478 #include "detect-engine.h"
479 
480 /**
481  * \test this is a test for a valid dsize value 1
482  *
483  * \retval 1 on succces
484  * \retval 0 on failure
485  */
486 static int DsizeTestParse01 (void)
487 {
488  DetectDsizeData *dd = NULL;
489  dd = DetectDsizeParse("1");
490  if (dd) {
491  DetectDsizeFree(dd);
492  return 1;
493  }
494 
495  return 0;
496 }
497 
498 /**
499  * \test this is a test for a valid dsize value >10
500  *
501  * \retval 1 on succces
502  * \retval 0 on failure
503  */
504 static int DsizeTestParse02 (void)
505 {
506  DetectDsizeData *dd = NULL;
507  dd = DetectDsizeParse(">10");
508  if (dd) {
509  DetectDsizeFree(dd);
510  return 1;
511  }
512 
513  return 0;
514 }
515 
516 /**
517  * \test this is a test for a valid dsize value <100
518  *
519  * \retval 1 on succces
520  * \retval 0 on failure
521  */
522 static int DsizeTestParse03 (void)
523 {
524  DetectDsizeData *dd = NULL;
525  dd = DetectDsizeParse("<100");
526  if (dd) {
527  DetectDsizeFree(dd);
528  return 1;
529  }
530 
531  return 0;
532 }
533 
534 /**
535  * \test this is a test for a valid dsize value 1<>2
536  *
537  * \retval 1 on succces
538  * \retval 0 on failure
539  */
540 static int DsizeTestParse04 (void)
541 {
542  DetectDsizeData *dd = NULL;
543  dd = DetectDsizeParse("1<>2");
544  if (dd) {
545  DetectDsizeFree(dd);
546  return 1;
547  }
548 
549  return 0;
550 }
551 
552 /**
553  * \test this is a test for a valid dsize value 1
554  *
555  * \retval 1 on succces
556  * \retval 0 on failure
557  */
558 static int DsizeTestParse05 (void)
559 {
560  int result = 0;
561  DetectDsizeData *dd = NULL;
562  dd = DetectDsizeParse("1");
563  if (dd) {
564  if (dd->dsize == 1)
565  result = 1;
566 
567  DetectDsizeFree(dd);
568  }
569 
570  return result;
571 }
572 
573 /**
574  * \test this is a test for a valid dsize value >10
575  *
576  * \retval 1 on succces
577  * \retval 0 on failure
578  */
579 static int DsizeTestParse06 (void)
580 {
581  int result = 0;
582  DetectDsizeData *dd = NULL;
583  dd = DetectDsizeParse(">10");
584  if (dd) {
585  if (dd->dsize == 10 && dd->mode == DETECTDSIZE_GT)
586  result = 1;
587 
588  DetectDsizeFree(dd);
589  }
590 
591  return result;
592 }
593 
594 /**
595  * \test this is a test for a valid dsize value <100
596  *
597  * \retval 1 on succces
598  * \retval 0 on failure
599  */
600 static int DsizeTestParse07 (void)
601 {
602  int result = 0;
603  DetectDsizeData *dd = NULL;
604  dd = DetectDsizeParse("<100");
605  if (dd) {
606  if (dd->dsize == 100 && dd->mode == DETECTDSIZE_LT)
607  result = 1;
608 
609  DetectDsizeFree(dd);
610  }
611 
612  return result;
613 }
614 
615 /**
616  * \test this is a test for a valid dsize value 1<>2
617  *
618  * \retval 1 on succces
619  * \retval 0 on failure
620  */
621 static int DsizeTestParse08 (void)
622 {
623  int result = 0;
624  DetectDsizeData *dd = NULL;
625  dd = DetectDsizeParse("1<>2");
626  if (dd) {
627  if (dd->dsize == 1 && dd->dsize2 == 2 && dd->mode == DETECTDSIZE_RA)
628  result = 1;
629 
630  DetectDsizeFree(dd);
631  }
632 
633  return result;
634 }
635 
636 /**
637  * \test this is a test for a invalid dsize value A
638  *
639  * \retval 1 on succces
640  * \retval 0 on failure
641  */
642 static int DsizeTestParse09 (void)
643 {
644  DetectDsizeData *dd = NULL;
645  dd = DetectDsizeParse("A");
646  if (dd) {
647  DetectDsizeFree(dd);
648  return 0;
649  }
650 
651  return 1;
652 }
653 
654 /**
655  * \test this is a test for a invalid dsize value >10<>10
656  *
657  * \retval 1 on succces
658  * \retval 0 on failure
659  */
660 static int DsizeTestParse10 (void)
661 {
662  DetectDsizeData *dd = NULL;
663  dd = DetectDsizeParse(">10<>10");
664  if (dd) {
665  DetectDsizeFree(dd);
666  return 0;
667  }
668 
669  return 1;
670 }
671 
672 /**
673  * \test this is a test for a invalid dsize value <>10
674  *
675  * \retval 1 on succces
676  * \retval 0 on failure
677  */
678 static int DsizeTestParse11 (void)
679 {
680  DetectDsizeData *dd = NULL;
681  dd = DetectDsizeParse("<>10");
682  if (dd) {
683  DetectDsizeFree(dd);
684  return 0;
685  }
686 
687  return 1;
688 }
689 
690 /**
691  * \test this is a test for a invalid dsize value 1<>
692  *
693  * \retval 1 on succces
694  * \retval 0 on failure
695  */
696 static int DsizeTestParse12 (void)
697 {
698  DetectDsizeData *dd = NULL;
699  dd = DetectDsizeParse("1<>");
700  if (dd) {
701  DetectDsizeFree(dd);
702  return 0;
703  }
704 
705  return 1;
706 }
707 
708 /**
709  * \test this is a test for a valid dsize value 1
710  *
711  * \retval 1 on succces
712  * \retval 0 on failure
713  */
714 static int DsizeTestParse13 (void)
715 {
716  int result = 0;
717  DetectDsizeData *dd = NULL;
718  dd = DetectDsizeParse("1");
719  if (dd) {
720  if (dd->dsize2 == 0)
721  result = 1;
722 
723  DetectDsizeFree(dd);
724  }
725 
726  return result;
727 }
728 
729 /**
730  * \test this is a test for a invalid dsize value ""
731  *
732  * \retval 1 on succces
733  * \retval 0 on failure
734  */
735 static int DsizeTestParse14 (void)
736 {
737  DetectDsizeData *dd = NULL;
738  dd = DetectDsizeParse("");
739  if (dd) {
740  DetectDsizeFree(dd);
741  return 0;
742  }
743 
744  return 1;
745 }
746 
747 /**
748  * \test this is a test for a invalid dsize value " "
749  *
750  * \retval 1 on succces
751  * \retval 0 on failure
752  */
753 static int DsizeTestParse15 (void)
754 {
755  DetectDsizeData *dd = NULL;
756  dd = DetectDsizeParse(" ");
757  if (dd) {
758  DetectDsizeFree(dd);
759  return 0;
760  }
761 
762  return 1;
763 }
764 
765 /**
766  * \test this is a test for a invalid dsize value 2<>1
767  *
768  * \retval 1 on succces
769  * \retval 0 on failure
770  */
771 static int DsizeTestParse16 (void)
772 {
773  DetectDsizeData *dd = NULL;
774  dd = DetectDsizeParse("2<>1");
775  if (dd) {
776  DetectDsizeFree(dd);
777  return 0;
778  }
779 
780  return 1;
781 }
782 
783 /**
784  * \test this is a test for a valid dsize value 1 <> 2
785  *
786  * \retval 1 on succces
787  * \retval 0 on failure
788  */
789 static int DsizeTestParse17 (void)
790 {
791  int result = 0;
792  DetectDsizeData *dd = NULL;
793  dd = DetectDsizeParse(" 1 <> 2 ");
794  if (dd) {
795  if (dd->dsize == 1 && dd->dsize2 == 2 && dd->mode == DETECTDSIZE_RA)
796  result = 1;
797 
798  DetectDsizeFree(dd);
799  }
800 
801  return result;
802 }
803 
804 /**
805  * \test this is test for a valid dsize value > 2
806  *
807  * \retval 1 on succces
808  * \retval 0 on failure
809  */
810 static int DsizeTestParse18 (void)
811 {
812  int result = 0;
813  DetectDsizeData *dd = NULL;
814  dd = DetectDsizeParse("> 2 ");
815  if (dd) {
816  if (dd->dsize == 2 && dd->mode == DETECTDSIZE_GT)
817  result = 1;
818 
819  DetectDsizeFree(dd);
820  }
821 
822  return result;
823 }
824 
825 /**
826  * \test test for a valid dsize value < 12
827  *
828  * \retval 1 on succces
829  * \retval 0 on failure
830  */
831 static int DsizeTestParse19 (void)
832 {
833  int result = 0;
834  DetectDsizeData *dd = NULL;
835  dd = DetectDsizeParse("< 12 ");
836  if (dd) {
837  if (dd->dsize == 12 && dd->mode == DETECTDSIZE_LT)
838  result = 1;
839 
840  DetectDsizeFree(dd);
841  }
842 
843  return result;
844 }
845 
846 /**
847  * \test test for a valid dsize value 12
848  *
849  * \retval 1 on succces
850  * \retval 0 on failure
851  */
852 static int DsizeTestParse20 (void)
853 {
854  int result = 0;
855  DetectDsizeData *dd = NULL;
856  dd = DetectDsizeParse(" 12 ");
857  if (dd) {
858  if (dd->dsize == 12 && dd->mode == DETECTDSIZE_EQ)
859  result = 1;
860 
861  DetectDsizeFree(dd);
862  }
863 
864  return result;
865 }
866 
867 /**
868  * \test DetectDsizeIcmpv6Test01 is a test for checking the working of
869  * dsize keyword by creating 2 rules and matching a crafted packet
870  * against them. Only the first one shall trigger.
871  */
872 static int DetectDsizeIcmpv6Test01 (void)
873 {
874  int result = 0;
875 
876  static uint8_t raw_icmpv6[] = {
877  0x60, 0x00, 0x00, 0x00, 0x00, 0x30, 0x3a, 0xff,
878  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
879  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
880  0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
881  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
882  0x01, 0x00, 0x7b, 0x85, 0x00, 0x00, 0x00, 0x00,
883  0x60, 0x4b, 0xe8, 0xbd, 0x00, 0x00, 0x3b, 0xff,
884  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
885  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
886  0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
887  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 };
888 
890  if (unlikely(p == NULL))
891  return 0;
892  IPV6Hdr ip6h;
893  ThreadVars tv;
894  DecodeThreadVars dtv;
895  Signature *s = NULL;
896  ThreadVars th_v;
897  DetectEngineThreadCtx *det_ctx = NULL;
898 
899  memset(&tv, 0, sizeof(ThreadVars));
900  memset(p, 0, SIZE_OF_PACKET);
901  memset(&dtv, 0, sizeof(DecodeThreadVars));
902  memset(&ip6h, 0, sizeof(IPV6Hdr));
903  memset(&th_v, 0, sizeof(ThreadVars));
904 
906  p->src.family = AF_INET6;
907  p->dst.family = AF_INET6;
908  p->ip6h = &ip6h;
909 
910  DecodeIPV6(&tv, &dtv, p, raw_icmpv6, sizeof(raw_icmpv6), NULL);
911 
913  if (de_ctx == NULL) {
914  goto end;
915  }
916 
917  de_ctx->flags |= DE_QUIET;
918 
919  s = de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any "
920  "(msg:\"ICMP Large ICMP Packet\"; dsize:>8; sid:1; rev:4;)");
921  if (s == NULL) {
922  goto end;
923  }
924 
925  s = s->next = SigInit(de_ctx, "alert icmp any any -> any any "
926  "(msg:\"ICMP Large ICMP Packet\"; dsize:>800; sid:2; rev:4;)");
927  if (s == NULL) {
928  goto end;
929  }
930 
931  SigGroupBuild(de_ctx);
932  DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
933 
934  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
935  if (PacketAlertCheck(p, 1) == 0) {
936  printf("sid 1 did not alert, but should have: ");
937  goto cleanup;
938  } else if (PacketAlertCheck(p, 2)) {
939  printf("sid 2 alerted, but should not have: ");
940  goto cleanup;
941  }
942 
943  result = 1;
944 
945 cleanup:
946  SigGroupCleanup(de_ctx);
947  SigCleanSignatures(de_ctx);
948 
949  DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
950  DetectEngineCtxFree(de_ctx);
951 
952  PACKET_RECYCLE(p);
953  FlowShutdown();
954 end:
955  SCFree(p);
956  return result;
957 
958 }
959 #endif /* UNITTESTS */
960 
961 /**
962  * \brief this function registers unit tests for dsize
963  */
964 static void DsizeRegisterTests(void)
965 {
966 #ifdef UNITTESTS
967  UtRegisterTest("DsizeTestParse01", DsizeTestParse01);
968  UtRegisterTest("DsizeTestParse02", DsizeTestParse02);
969  UtRegisterTest("DsizeTestParse03", DsizeTestParse03);
970  UtRegisterTest("DsizeTestParse04", DsizeTestParse04);
971  UtRegisterTest("DsizeTestParse05", DsizeTestParse05);
972  UtRegisterTest("DsizeTestParse06", DsizeTestParse06);
973  UtRegisterTest("DsizeTestParse07", DsizeTestParse07);
974  UtRegisterTest("DsizeTestParse08", DsizeTestParse08);
975  UtRegisterTest("DsizeTestParse09", DsizeTestParse09);
976  UtRegisterTest("DsizeTestParse10", DsizeTestParse10);
977  UtRegisterTest("DsizeTestParse11", DsizeTestParse11);
978  UtRegisterTest("DsizeTestParse12", DsizeTestParse12);
979  UtRegisterTest("DsizeTestParse13", DsizeTestParse13);
980  UtRegisterTest("DsizeTestParse14", DsizeTestParse14);
981  UtRegisterTest("DsizeTestParse15", DsizeTestParse15);
982  UtRegisterTest("DsizeTestParse16", DsizeTestParse16);
983  UtRegisterTest("DsizeTestParse17", DsizeTestParse17);
984  UtRegisterTest("DsizeTestParse18", DsizeTestParse18);
985  UtRegisterTest("DsizeTestParse19", DsizeTestParse19);
986  UtRegisterTest("DsizeTestParse20", DsizeTestParse20);
987 
988  UtRegisterTest("DetectDsizeIcmpv6Test01", DetectDsizeIcmpv6Test01);
989 #endif /* UNITTESTS */
990 }
991 
SigTableElmt sigmatch_table[DETECT_TBLSIZE]
Definition: detect.h:1448
#define DETECTDSIZE_LT
Definition: detect-dsize.h:27
SignatureInitData * init_data
Definition: detect.h:591
int(* Setup)(DetectEngineCtx *, Signature *, const char *)
Definition: detect.h:1186
#define SCLogDebug(...)
Definition: util-debug.h:335
SigMatch * dsize_sm
Definition: detect.h:490
#define DETECTDSIZE_GT
Definition: detect-dsize.h:29
int(* SetupPrefilter)(DetectEngineCtx *de_ctx, struct SigGroupHead_ *sgh)
Definition: detect.h:1189
int PrefilterSetupPacketHeader(DetectEngineCtx *de_ctx, SigGroupHead *sgh, int sm_type, void(*Set)(PrefilterPacketHeaderValue *v, void *), _Bool(*Compare)(PrefilterPacketHeaderValue v, void *), void(*Match)(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx))
int PacketAlertCheck(Packet *p, uint32_t sid)
Check if a certain sid alerted, this is used in the test functions.
uint16_t dsize_high
Definition: detect.h:529
uint32_t flags
Definition: detect.h:523
_Bool(* SupportsPrefilter)(const Signature *s)
Definition: detect.h:1188
uint32_t id
Definition: detect.h:555
#define FALSE
#define DETECTDSIZE_RA
Definition: detect-dsize.h:30
#define unlikely(expr)
Definition: util-optimize.h:35
Signature * SigInit(DetectEngineCtx *, const char *)
Parses a signature and adds it to the Detection Engine Context.
#define MAX_SUBSTRINGS
Signature * sig_list
Definition: detect.h:767
#define FLOW_QUIET
Definition: flow.h:38
Address dst
Definition: decode.h:413
void SigCleanSignatures(DetectEngineCtx *de_ctx)
#define PACKET_RECYCLE(p)
Definition: decode.h:814
Container for matching data for a signature group.
Definition: detect.h:1336
#define SIG_FLAG_REQUIRE_PACKET
Definition: detect.h:223
TmEcode DetectEngineThreadCtxInit(ThreadVars *, void *, void **)
initialize thread specific detection engine context
const char * name
Definition: detect.h:1200
Signature container.
Definition: detect.h:522
#define TRUE
Used to start a pointer to SigMatch context Should never be dereferenced without casting to something...
Definition: detect.h:313
struct SigMatch_ * next
Definition: detect.h:322
main detection engine ctx
Definition: detect.h:761
int ByteExtractStringUint16(uint16_t *res, int base, uint16_t len, const char *str)
Definition: util-byte.c:264
TmEcode DetectEngineThreadCtxDeinit(ThreadVars *, void *)
#define DE_QUIET
Definition: detect.h:292
#define SIZE_OF_PACKET
Definition: decode.h:618
#define str(s)
void DetectDsizeRegister(void)
Registration function for dsize: keyword.
Definition: detect-dsize.c:65
IPV6Hdr * ip6h
Definition: decode.h:502
char family
Definition: decode.h:111
uint8_t flags
Definition: detect.h:762
void(* Free)(void *)
Definition: detect.h:1191
#define SCLogError(err_code,...)
Macro used to log ERROR messages.
Definition: util-debug.h:294
int SigGroupBuild(DetectEngineCtx *de_ctx)
Convert the signature list into the runtime match structure.
void UtRegisterTest(const char *name, int(*TestFn)(void))
Register unit test.
Structure to hold thread specific data for all decode modules.
Definition: decode.h:632
void SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Packet *p)
wrapper for old tests
Definition: detect.c:1669
void DetectSetupParseRegexes(const char *parse_str, pcre **parse_regex, pcre_extra **parse_regex_study)
int SigParseGetMaxDsize(const Signature *s)
get max dsize "depth"
Definition: detect-dsize.c:381
#define SCEnter(...)
Definition: util-debug.h:337
PrefilterRuleStore pmq
Definition: detect.h:1102
void SigParseApplyDsizeToContent(Signature *s)
Apply dsize as depth to content matches in the rule.
Definition: detect-dsize.c:440
#define DETECTDSIZE_EQ
Definition: detect-dsize.h:28
int(* Match)(DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *)
Definition: detect.h:1170
int SigGroupCleanup(DetectEngineCtx *de_ctx)
struct Signature_ * next
Definition: detect.h:594
uint8_t type
Definition: detect.h:319
#define SCReturnInt(x)
Definition: util-debug.h:341
const char * desc
Definition: detect.h:1202
void SigMatchAppendSMToList(Signature *s, SigMatch *new, int list)
Append a SigMatch to the list type.
Definition: detect-parse.c:346
struct SigMatch_ ** smlists
Definition: detect.h:516
#define PARSE_REGEX
Definition: detect-dsize.c:49
SigMatchCtx * ctx
Definition: detect.h:321
#define SCMalloc(a)
Definition: util-mem.h:222
int DecodeIPV6(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint16_t len, PacketQueue *pq)
Definition: decode-ipv6.c:585
#define SCFree(a)
Definition: util-mem.h:322
PoolThreadReserved res
#define SIG_FLAG_DSIZE
Definition: detect.h:217
void FlowShutdown(void)
shutdown the flow engine
Definition: flow.c:670
SigMatch * DetectGetLastSMFromLists(const Signature *s,...)
Returns the sm with the largest index (added latest) from the lists passed to us. ...
Definition: detect-parse.c:465
const char * url
Definition: detect.h:1203
#define DOC_URL
Definition: suricata.h:86
#define PKT_IS_PSEUDOPKT(p)
return 1 if the packet is a pseudo packet
Definition: decode.h:1132
SigMatch * SigMatchAlloc(void)
Definition: detect-parse.c:232
#define SCReturn
Definition: util-debug.h:339
void SigParseSetDsizePair(Signature *s)
set prefilter dsize pair
Definition: detect-dsize.c:403
Per thread variable structure.
Definition: threadvars.h:57
uint16_t payload_len
Definition: decode.h:541
#define DOC_VERSION
Definition: suricata.h:91
uint16_t dsize_low
Definition: detect.h:528
void DetectEngineCtxFree(DetectEngineCtx *)
Free a DetectEngineCtx::
void(* RegisterTests)(void)
Definition: detect.h:1192
a single match condition for a signature
Definition: detect.h:318
Address src
Definition: decode.h:412
DetectEngineCtx * DetectEngineCtxInit(void)
void FlowInitConfig(char quiet)
initialize the configuration
Definition: flow.c:515