suricata
detect-flags.c
Go to the documentation of this file.
1 /* Copyright (C) 2007-2018 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 Breno Silva <breno.silva@gmail.com>
22  *
23  * Implements the flags keyword
24  */
25 
26 #include "suricata-common.h"
27 #include "suricata.h"
28 #include "decode.h"
29 
30 #include "detect.h"
31 #include "detect-parse.h"
34 
35 #include "flow-var.h"
36 #include "decode-events.h"
37 
38 #include "detect-flags.h"
39 #include "util-unittest.h"
40 
41 #include "util-debug.h"
42 
43 /**
44  * Regex (by Brian Rectanus)
45  * flags: [!+*](SAPRFU120)[,SAPRFU12]
46  */
47 #define PARSE_REGEX "^\\s*(?:([\\+\\*!]))?\\s*([SAPRFU120CE\\+\\*!]+)(?:\\s*,\\s*([SAPRFU12CE]+))?\\s*$"
48 
49 /**
50  * Flags args[0] *(3) +(2) !(1)
51  *
52  */
53 
54 #define MODIFIER_NOT 1
55 #define MODIFIER_PLUS 2
56 #define MODIFIER_ANY 3
57 
58 static pcre *parse_regex;
59 static pcre_extra *parse_regex_study;
60 
61 static int DetectFlagsMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *,
62  const Signature *, const SigMatchCtx *);
63 static int DetectFlagsSetup (DetectEngineCtx *, Signature *, const char *);
64 static void DetectFlagsFree(void *);
65 
66 static _Bool PrefilterTcpFlagsIsPrefilterable(const Signature *s);
67 static int PrefilterSetupTcpFlags(DetectEngineCtx *de_ctx, SigGroupHead *sgh);
68 
69 /**
70  * \brief Registration function for flags: keyword
71  */
72 
74 {
75  sigmatch_table[DETECT_FLAGS].name = "flags";
76  sigmatch_table[DETECT_FLAGS].Match = DetectFlagsMatch;
77  sigmatch_table[DETECT_FLAGS].Setup = DetectFlagsSetup;
78  sigmatch_table[DETECT_FLAGS].Free = DetectFlagsFree;
80 
81  sigmatch_table[DETECT_FLAGS].SupportsPrefilter = PrefilterTcpFlagsIsPrefilterable;
82  sigmatch_table[DETECT_FLAGS].SetupPrefilter = PrefilterSetupTcpFlags;
83 
84  DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study);
85 }
86 
87 static inline int FlagsMatch(const uint8_t pflags, const uint8_t modifier,
88  const uint8_t dflags, const uint8_t iflags)
89 {
90  if (!dflags && pflags) {
91  if(modifier == MODIFIER_NOT) {
92  SCReturnInt(1);
93  }
94 
95  SCReturnInt(0);
96  }
97 
98  const uint8_t flags = pflags & iflags;
99 
100  switch (modifier) {
101  case MODIFIER_ANY:
102  if ((flags & dflags) > 0) {
103  SCReturnInt(1);
104  }
105  SCReturnInt(0);
106 
107  case MODIFIER_PLUS:
108  if (((flags & dflags) == dflags)) {
109  SCReturnInt(1);
110  }
111  SCReturnInt(0);
112 
113  case MODIFIER_NOT:
114  if ((flags & dflags) != dflags) {
115  SCReturnInt(1);
116  }
117  SCReturnInt(0);
118 
119  default:
120  SCLogDebug("flags %"PRIu8" and de->flags %"PRIu8"", flags, dflags);
121  if (flags == dflags) {
122  SCReturnInt(1);
123  }
124  }
125 
126  SCReturnInt(0);
127 }
128 
129 /**
130  * \internal
131  * \brief This function is used to match flags on a packet with those passed via flags:
132  *
133  * \param t pointer to thread vars
134  * \param det_ctx pointer to the pattern matcher thread
135  * \param p pointer to the current packet
136  * \param s pointer to the Signature
137  * \param m pointer to the sigmatch
138  *
139  * \retval 0 no match
140  * \retval 1 match
141  */
142 static int DetectFlagsMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p,
143  const Signature *s, const SigMatchCtx *ctx)
144 {
145  SCEnter();
146 
147  if (!(PKT_IS_TCP(p)) || PKT_IS_PSEUDOPKT(p)) {
148  SCReturnInt(0);
149  }
150 
151  const DetectFlagsData *de = (const DetectFlagsData *)ctx;
152  const uint8_t flags = p->tcph->th_flags;
153 
154  return FlagsMatch(flags, de->modifier, de->flags, de->ignored_flags);
155 }
156 
157 /**
158  * \internal
159  * \brief This function is used to parse flags options passed via flags: keyword
160  *
161  * \param rawstr Pointer to the user provided flags options
162  *
163  * \retval de pointer to DetectFlagsData on success
164  * \retval NULL on failure
165  */
166 static DetectFlagsData *DetectFlagsParse (const char *rawstr)
167 {
168  SCEnter();
169 
170 #define MAX_SUBSTRINGS 30
171  int ret = 0, found = 0, ignore = 0, res = 0;
172  int ov[MAX_SUBSTRINGS];
173  char *ptr;
174 
175  char arg1[16] = "";
176  char arg2[16] = "";
177  char arg3[16] = "";
178 
179  ret = pcre_exec(parse_regex, parse_regex_study, rawstr, strlen(rawstr),
180  0, 0, ov, MAX_SUBSTRINGS);
181  SCLogDebug("input '%s', pcre said %d", rawstr, ret);
182  if (ret < 3) {
183  SCLogError(SC_ERR_PCRE_MATCH, "pcre match failed");
184  SCReturnPtr(NULL, "DetectFlagsData");
185  }
186 
187  res = pcre_copy_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 1, arg1, sizeof(arg1));
188  if (res < 0) {
189  SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed");
190  SCReturnPtr(NULL, "DetectFlagsData");
191  }
192  if (ret >= 2) {
193  res = pcre_copy_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 2, arg2, sizeof(arg2));
194  if (res < 0) {
195  SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed");
196  SCReturnPtr(NULL, "DetectFlagsData");
197  }
198  }
199  if (ret >= 3) {
200  res = pcre_copy_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 3, arg3, sizeof(arg3));
201  if (res < 0) {
202  SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed");
203  SCReturnPtr(NULL, "DetectFlagsData");
204  }
205  }
206  SCLogDebug("args '%s', '%s', '%s'", arg1, arg2, arg3);
207 
208  if (strlen(arg2) == 0) {
209  SCLogDebug("empty argument");
210  SCReturnPtr(NULL, "DetectFlagsData");
211  }
212 
214  if (unlikely(de == NULL))
215  goto error;
216  memset(de, 0, sizeof(DetectFlagsData));
217  de->ignored_flags = 0xff;
218 
219  /** First parse args1 */
220  ptr = arg1;
221  while (*ptr != '\0') {
222  switch (*ptr) {
223  case 'S':
224  case 's':
225  de->flags |= TH_SYN;
226  found++;
227  break;
228  case 'A':
229  case 'a':
230  de->flags |= TH_ACK;
231  found++;
232  break;
233  case 'F':
234  case 'f':
235  de->flags |= TH_FIN;
236  found++;
237  break;
238  case 'R':
239  case 'r':
240  de->flags |= TH_RST;
241  found++;
242  break;
243  case 'P':
244  case 'p':
245  de->flags |= TH_PUSH;
246  found++;
247  break;
248  case 'U':
249  case 'u':
250  de->flags |= TH_URG;
251  found++;
252  break;
253  case '1':
254  de->flags |= TH_CWR;
255  found++;
256  break;
257  case '2':
258  de->flags |= TH_ECN;
259  found++;
260  break;
261  case 'C':
262  case 'c':
263  de->flags |= TH_CWR;
264  found++;
265  break;
266  case 'E':
267  case 'e':
268  de->flags |= TH_ECN;
269  found++;
270  break;
271  case '0':
272  de->flags = 0;
273  found++;
274  break;
275 
276  case '!':
277  de->modifier = MODIFIER_NOT;
278  break;
279  case '+':
280  de->modifier = MODIFIER_PLUS;
281  break;
282  case '*':
283  de->modifier = MODIFIER_ANY;
284  break;
285  }
286  ptr++;
287  }
288 
289  /** Second parse first set of flags */
290  if (strlen(arg2) > 0) {
291  ptr = arg2;
292  while (*ptr != '\0') {
293  switch (*ptr) {
294  case 'S':
295  case 's':
296  de->flags |= TH_SYN;
297  found++;
298  break;
299  case 'A':
300  case 'a':
301  de->flags |= TH_ACK;
302  found++;
303  break;
304  case 'F':
305  case 'f':
306  de->flags |= TH_FIN;
307  found++;
308  break;
309  case 'R':
310  case 'r':
311  de->flags |= TH_RST;
312  found++;
313  break;
314  case 'P':
315  case 'p':
316  de->flags |= TH_PUSH;
317  found++;
318  break;
319  case 'U':
320  case 'u':
321  de->flags |= TH_URG;
322  found++;
323  break;
324  case '1':
325  case 'C':
326  case 'c':
327  de->flags |= TH_CWR;
328  found++;
329  break;
330  case '2':
331  case 'E':
332  case 'e':
333  de->flags |= TH_ECN;
334  found++;
335  break;
336  case '0':
337  de->flags = 0;
338  found++;
339  break;
340 
341  case '!':
342  if (de->modifier != 0) {
343  SCLogError(SC_ERR_FLAGS_MODIFIER, "\"flags\" supports only"
344  " one modifier at a time");
345  goto error;
346  }
347  de->modifier = MODIFIER_NOT;
348  SCLogDebug("NOT modifier is set");
349  break;
350  case '+':
351  if (de->modifier != 0) {
352  SCLogError(SC_ERR_FLAGS_MODIFIER, "\"flags\" supports only"
353  " one modifier at a time");
354  goto error;
355  }
356  de->modifier = MODIFIER_PLUS;
357  SCLogDebug("PLUS modifier is set");
358  break;
359  case '*':
360  if (de->modifier != 0) {
361  SCLogError(SC_ERR_FLAGS_MODIFIER, "\"flags\" supports only"
362  " one modifier at a time");
363  goto error;
364  }
365  de->modifier = MODIFIER_ANY;
366  SCLogDebug("ANY modifier is set");
367  break;
368  default:
369  break;
370  }
371  ptr++;
372  }
373 
374  if (found == 0)
375  goto error;
376  }
377 
378  /** Finally parse ignored flags */
379  if (strlen(arg3) > 0) {
380  ptr = arg3;
381 
382  while (*ptr != '\0') {
383  switch (*ptr) {
384  case 'S':
385  case 's':
386  de->ignored_flags &= ~TH_SYN;
387  ignore++;
388  break;
389  case 'A':
390  case 'a':
391  de->ignored_flags &= ~TH_ACK;
392  ignore++;
393  break;
394  case 'F':
395  case 'f':
396  de->ignored_flags &= ~TH_FIN;
397  ignore++;
398  break;
399  case 'R':
400  case 'r':
401  de->ignored_flags &= ~TH_RST;
402  ignore++;
403  break;
404  case 'P':
405  case 'p':
406  de->ignored_flags &= ~TH_PUSH;
407  ignore++;
408  break;
409  case 'U':
410  case 'u':
411  de->ignored_flags &= ~TH_URG;
412  ignore++;
413  break;
414  case '1':
415  de->ignored_flags &= ~TH_CWR;
416  ignore++;
417  break;
418  case '2':
419  de->ignored_flags &= ~TH_ECN;
420  ignore++;
421  break;
422  case 'C':
423  case 'c':
424  de->ignored_flags &= ~TH_CWR;
425  ignore++;
426  break;
427  case 'E':
428  case 'e':
429  de->ignored_flags &= ~TH_ECN;
430  ignore++;
431  break;
432  case '0':
433  break;
434  default:
435  break;
436  }
437  ptr++;
438  }
439 
440  if (ignore == 0) {
441  SCLogDebug("ignore == 0");
442  goto error;
443  }
444  }
445 
446  SCLogDebug("found %"PRId32" ignore %"PRId32"", found, ignore);
447  SCReturnPtr(de, "DetectFlagsData");
448 
449 error:
450  if (de) {
451  SCFree(de);
452  }
453  SCReturnPtr(NULL, "DetectFlagsData");
454 }
455 
456 /**
457  * \internal
458  * \brief this function is used to add the parsed flags into the current signature
459  *
460  * \param de_ctx pointer to the Detection Engine Context
461  * \param s pointer to the Current Signature
462  * \param m pointer to the Current SigMatch
463  * \param rawstr pointer to the user provided flags options
464  *
465  * \retval 0 on Success
466  * \retval -1 on Failure
467  */
468 static int DetectFlagsSetup (DetectEngineCtx *de_ctx, Signature *s, const char *rawstr)
469 {
470  DetectFlagsData *de = NULL;
471  SigMatch *sm = NULL;
472 
473  de = DetectFlagsParse(rawstr);
474  if (de == NULL)
475  goto error;
476 
477  sm = SigMatchAlloc();
478  if (sm == NULL)
479  goto error;
480 
481  sm->type = DETECT_FLAGS;
482  sm->ctx = (SigMatchCtx *)de;
483 
486 
487  return 0;
488 
489 error:
490  if (de) SCFree(de);
491  if (sm) SCFree(sm);
492  return -1;
493 }
494 
495 /**
496  * \internal
497  * \brief this function will free memory associated with DetectFlagsData
498  *
499  * \param de pointer to DetectFlagsData
500  */
501 static void DetectFlagsFree(void *de_ptr)
502 {
503  DetectFlagsData *de = (DetectFlagsData *)de_ptr;
504  if(de) SCFree(de);
505 }
506 
508 {
509  const SigMatch *sm;
510  for (sm = s->init_data->smlists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) {
511  switch (sm->type) {
512  case DETECT_FLAGS:
513  {
514  const DetectFlagsData *fl = (const DetectFlagsData *)sm->ctx;
515 
516  if (!(fl->modifier == MODIFIER_NOT) && (fl->flags & TH_SYN)) {
517  return 1;
518  }
519  break;
520  }
521  }
522  }
523  return 0;
524 }
525 
527 {
528  const SigMatch *sm;
529  for (sm = s->init_data->smlists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) {
530  switch (sm->type) {
531  case DETECT_FLAGS:
532  {
533  const DetectFlagsData *fl = (const DetectFlagsData *)sm->ctx;
534 
535  if (!(fl->modifier == MODIFIER_NOT) && (fl->flags == TH_SYN)) {
536  return 1;
537  }
538  break;
539  }
540  }
541  }
542  return 0;
543 }
544 
545 static void
546 PrefilterPacketFlagsMatch(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx)
547 {
548  if (!(PKT_IS_TCP(p)) || PKT_IS_PSEUDOPKT(p)) {
549  SCReturn;
550  }
551 
552  const PrefilterPacketHeaderCtx *ctx = pectx;
553  if (PrefilterPacketHeaderExtraMatch(ctx, p) == FALSE)
554  return;
555 
556  const uint8_t flags = p->tcph->th_flags;
557  if (FlagsMatch(flags, ctx->v1.u8[0], ctx->v1.u8[1], ctx->v1.u8[2]))
558  {
559  SCLogDebug("packet matches TCP flags %02x", ctx->v1.u8[1]);
560  PrefilterAddSids(&det_ctx->pmq, ctx->sigs_array, ctx->sigs_cnt);
561  }
562 }
563 
564 static void
565 PrefilterPacketFlagsSet(PrefilterPacketHeaderValue *v, void *smctx)
566 {
567  const DetectFlagsData *a = smctx;
568  v->u8[0] = a->modifier;
569  v->u8[1] = a->flags;
570  v->u8[2] = a->ignored_flags;
571  SCLogDebug("v->u8[0] = %02x", v->u8[0]);
572 }
573 
574 static _Bool
575 PrefilterPacketFlagsCompare(PrefilterPacketHeaderValue v, void *smctx)
576 {
577  const DetectFlagsData *a = smctx;
578  if (v.u8[0] == a->modifier &&
579  v.u8[1] == a->flags &&
580  v.u8[2] == a->ignored_flags)
581  return TRUE;
582  return FALSE;
583 }
584 
585 static int PrefilterSetupTcpFlags(DetectEngineCtx *de_ctx, SigGroupHead *sgh)
586 {
587  return PrefilterSetupPacketHeader(de_ctx, sgh, DETECT_FLAGS,
588  PrefilterPacketFlagsSet,
589  PrefilterPacketFlagsCompare,
590  PrefilterPacketFlagsMatch);
591 
592 }
593 
594 static _Bool PrefilterTcpFlagsIsPrefilterable(const Signature *s)
595 {
596  const SigMatch *sm;
597  for (sm = s->init_data->smlists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) {
598  switch (sm->type) {
599  case DETECT_FLAGS:
600  return TRUE;
601  }
602  }
603  return FALSE;
604 }
605 
606 /*
607  * ONLY TESTS BELOW THIS COMMENT
608  */
609 
610 #ifdef UNITTESTS
611 /**
612  * \test FlagsTestParse01 is a test for a valid flags value
613  *
614  * \retval 1 on succces
615  * \retval 0 on failure
616  */
617 static int FlagsTestParse01 (void)
618 {
619  DetectFlagsData *de = DetectFlagsParse("S");
620  FAIL_IF_NULL(de);
621  FAIL_IF_NOT(de->flags == TH_SYN);
622  DetectFlagsFree(de);
623  PASS;
624 }
625 
626 /**
627  * \test FlagsTestParse02 is a test for an invalid flags value
628  *
629  * \retval 1 on succces
630  * \retval 0 on failure
631  */
632 static int FlagsTestParse02 (void)
633 {
634  DetectFlagsData *de = NULL;
635  de = DetectFlagsParse("G");
636  if (de) {
637  DetectFlagsFree(de);
638  return 0;
639  }
640 
641  return 1;
642 }
643 
644 /**
645  * \test FlagsTestParse03 test if ACK and PUSH are set. Must return success
646  *
647  * \retval 1 on success
648  * \retval 0 on failure
649  */
650 static int FlagsTestParse03 (void)
651 {
653  if (unlikely(p == NULL))
654  return 0;
655  ThreadVars tv;
656  int ret = 0;
657  DetectFlagsData *de = NULL;
658  SigMatch *sm = NULL;
659  IPV4Hdr ipv4h;
660  TCPHdr tcph;
661 
662  memset(&tv, 0, sizeof(ThreadVars));
663  memset(p, 0, SIZE_OF_PACKET);
664  memset(&ipv4h, 0, sizeof(IPV4Hdr));
665  memset(&tcph, 0, sizeof(TCPHdr));
666 
667  p->ip4h = &ipv4h;
668  p->tcph = &tcph;
669  p->tcph->th_flags = TH_ACK|TH_PUSH|TH_SYN|TH_RST;
670 
671  de = DetectFlagsParse("AP+");
672 
673  if (de == NULL || (de->flags != (TH_ACK|TH_PUSH)) )
674  goto error;
675 
676  sm = SigMatchAlloc();
677  if (sm == NULL)
678  goto error;
679 
680  sm->type = DETECT_FLAGS;
681  sm->ctx = (SigMatchCtx *)de;
682 
683  ret = DetectFlagsMatch(&tv, NULL, p, NULL, sm->ctx);
684 
685  if(ret) {
686  if (de) SCFree(de);
687  if (sm) SCFree(sm);
688  SCFree(p);
689  return 1;
690  }
691 
692 error:
693  if (de) SCFree(de);
694  if (sm) SCFree(sm);
695  SCFree(p);
696  return 0;
697 }
698 
699 /**
700  * \test FlagsTestParse04 check if ACK bit is set. Must fails.
701  *
702  * \retval 1 on succces
703  * \retval 0 on failure
704  */
705 static int FlagsTestParse04 (void)
706 {
708  if (unlikely(p == NULL))
709  return 0;
710  ThreadVars tv;
711  int ret = 0;
712  DetectFlagsData *de = NULL;
713  SigMatch *sm = NULL;
714  IPV4Hdr ipv4h;
715  TCPHdr tcph;
716 
717  memset(&tv, 0, sizeof(ThreadVars));
718  memset(p, 0, SIZE_OF_PACKET);
719  memset(&ipv4h, 0, sizeof(IPV4Hdr));
720  memset(&tcph, 0, sizeof(TCPHdr));
721 
722  p->ip4h = &ipv4h;
723  p->tcph = &tcph;
724  p->tcph->th_flags = TH_SYN;
725 
726  de = DetectFlagsParse("A");
727 
728  if (de == NULL || de->flags != TH_ACK)
729  goto error;
730 
731  sm = SigMatchAlloc();
732  if (sm == NULL)
733  goto error;
734 
735  sm->type = DETECT_FLAGS;
736  sm->ctx = (SigMatchCtx *)de;
737 
738  ret = DetectFlagsMatch(&tv, NULL, p, NULL, sm->ctx);
739 
740  if(ret) {
741  if (de) SCFree(de);
742  if (sm) SCFree(sm);
743  SCFree(p);
744  return 0;
745  }
746 
747  /* Error expected. */
748 error:
749  if (de) SCFree(de);
750  if (sm) SCFree(sm);
751  SCFree(p);
752  return 1;
753 }
754 
755 /**
756  * \test FlagsTestParse05 test if ACK+PUSH and more flags are set. Ignore SYN and RST bits.
757  * Must fails.
758  * \retval 1 on success
759  * \retval 0 on failure
760  */
761 static int FlagsTestParse05 (void)
762 {
764  if (unlikely(p == NULL))
765  return 0;
766  ThreadVars tv;
767  int ret = 0;
768  DetectFlagsData *de = NULL;
769  SigMatch *sm = NULL;
770  IPV4Hdr ipv4h;
771  TCPHdr tcph;
772 
773  memset(&tv, 0, sizeof(ThreadVars));
774  memset(p, 0, SIZE_OF_PACKET);
775  memset(&ipv4h, 0, sizeof(IPV4Hdr));
776  memset(&tcph, 0, sizeof(TCPHdr));
777 
778  p->ip4h = &ipv4h;
779  p->tcph = &tcph;
780  p->tcph->th_flags = TH_ACK|TH_PUSH|TH_SYN|TH_RST;
781 
782  de = DetectFlagsParse("+AP,SR");
783 
784  if (de == NULL || (de->modifier != MODIFIER_PLUS) || (de->flags != (TH_ACK|TH_PUSH)) || (de->ignored_flags != (TH_SYN|TH_RST)))
785  goto error;
786 
787  sm = SigMatchAlloc();
788  if (sm == NULL)
789  goto error;
790 
791  sm->type = DETECT_FLAGS;
792  sm->ctx = (SigMatchCtx *)de;
793 
794  ret = DetectFlagsMatch(&tv, NULL, p, NULL, sm->ctx);
795 
796  if(ret) {
797  if (de) SCFree(de);
798  if (sm) SCFree(sm);
799  SCFree(p);
800  return 0;
801  }
802 
803  /* Error expected. */
804 error:
805  if (de) SCFree(de);
806  if (sm) SCFree(sm);
807  SCFree(p);
808  return 1;
809 }
810 
811 /**
812  * \test FlagsTestParse06 test if ACK+PUSH and more flags are set. Ignore URG and RST bits.
813  * Must return success.
814  * \retval 1 on success
815  * \retval 0 on failure
816  */
817 static int FlagsTestParse06 (void)
818 {
820  if (unlikely(p == NULL))
821  return 0;
822  ThreadVars tv;
823  int ret = 0;
824  DetectFlagsData *de = NULL;
825  SigMatch *sm = NULL;
826  IPV4Hdr ipv4h;
827  TCPHdr tcph;
828 
829  memset(&tv, 0, sizeof(ThreadVars));
830  memset(p, 0, SIZE_OF_PACKET);
831  memset(&ipv4h, 0, sizeof(IPV4Hdr));
832  memset(&tcph, 0, sizeof(TCPHdr));
833 
834  p->ip4h = &ipv4h;
835  p->tcph = &tcph;
836  p->tcph->th_flags = TH_ACK|TH_PUSH|TH_SYN|TH_RST;
837 
838  de = DetectFlagsParse("+AP,UR");
839 
840  if (de == NULL || (de->modifier != MODIFIER_PLUS) || (de->flags != (TH_ACK|TH_PUSH)) || ((0xff - de->ignored_flags) != (TH_URG|TH_RST)))
841  goto error;
842 
843  sm = SigMatchAlloc();
844  if (sm == NULL)
845  goto error;
846 
847  sm->type = DETECT_FLAGS;
848  sm->ctx = (SigMatchCtx *)de;
849 
850  ret = DetectFlagsMatch(&tv, NULL, p, NULL, sm->ctx);
851 
852  if(ret) {
853  if (de) SCFree(de);
854  if (sm) SCFree(sm);
855  SCFree(p);
856  return 1;
857  }
858 
859 error:
860  if (de) SCFree(de);
861  if (sm) SCFree(sm);
862  SCFree(p);
863  return 0;
864 }
865 
866 /**
867  * \test FlagsTestParse07 test if SYN or RST are set. Must fails.
868  *
869  * \retval 1 on success
870  * \retval 0 on failure
871  */
872 static int FlagsTestParse07 (void)
873 {
875  if (unlikely(p == NULL))
876  return 0;
877  ThreadVars tv;
878  int ret = 0;
879  DetectFlagsData *de = NULL;
880  SigMatch *sm = NULL;
881  IPV4Hdr ipv4h;
882  TCPHdr tcph;
883 
884  memset(&tv, 0, sizeof(ThreadVars));
885  memset(p, 0, SIZE_OF_PACKET);
886  memset(&ipv4h, 0, sizeof(IPV4Hdr));
887  memset(&tcph, 0, sizeof(TCPHdr));
888 
889  p->ip4h = &ipv4h;
890  p->tcph = &tcph;
891  p->tcph->th_flags = TH_SYN|TH_RST;
892 
893  de = DetectFlagsParse("*AP");
894 
895  if (de == NULL || (de->modifier != MODIFIER_ANY) || (de->flags != (TH_ACK|TH_PUSH)))
896  goto error;
897 
898  sm = SigMatchAlloc();
899  if (sm == NULL)
900  goto error;
901 
902  sm->type = DETECT_FLAGS;
903  sm->ctx = (SigMatchCtx *)de;
904 
905  ret = DetectFlagsMatch(&tv, NULL, p, NULL, sm->ctx);
906 
907  if(ret) {
908  if (de) SCFree(de);
909  if (sm) SCFree(sm);
910  SCFree(p);
911  return 0;
912  }
913 
914  /* Error expected. */
915 error:
916  if (de) SCFree(de);
917  if (sm) SCFree(sm);
918  SCFree(p);
919  return 1;
920 }
921 
922 /**
923  * \test FlagsTestParse08 test if SYN or RST are set. Must return success.
924  *
925  * \retval 1 on success
926  * \retval 0 on failure
927  */
928 static int FlagsTestParse08 (void)
929 {
931  if (unlikely(p == NULL))
932  return 0;
933  ThreadVars tv;
934  int ret = 0;
935  DetectFlagsData *de = NULL;
936  SigMatch *sm = NULL;
937  IPV4Hdr ipv4h;
938  TCPHdr tcph;
939 
940  memset(&tv, 0, sizeof(ThreadVars));
941  memset(p, 0, SIZE_OF_PACKET);
942  memset(&ipv4h, 0, sizeof(IPV4Hdr));
943  memset(&tcph, 0, sizeof(TCPHdr));
944 
945  p->ip4h = &ipv4h;
946  p->tcph = &tcph;
947  p->tcph->th_flags = TH_SYN|TH_RST;
948 
949  de = DetectFlagsParse("*SA");
950 
951  if (de == NULL || (de->modifier != MODIFIER_ANY) || (de->flags != (TH_ACK|TH_SYN)))
952  goto error;
953 
954  sm = SigMatchAlloc();
955  if (sm == NULL)
956  goto error;
957 
958  sm->type = DETECT_FLAGS;
959  sm->ctx = (SigMatchCtx *)de;
960 
961  ret = DetectFlagsMatch(&tv, NULL, p, NULL, sm->ctx);
962 
963  if(ret) {
964  if (de) SCFree(de);
965  if (sm) SCFree(sm);
966  SCFree(p);
967  return 1;
968  }
969 
970 error:
971  if (de) SCFree(de);
972  if (sm) SCFree(sm);
973  SCFree(p);
974  return 0;
975 }
976 
977 /**
978  * \test FlagsTestParse09 test if SYN and RST are not set. Must fails.
979  *
980  * \retval 1 on success
981  * \retval 0 on failure
982  */
983 static int FlagsTestParse09 (void)
984 {
986  if (unlikely(p == NULL))
987  return 0;
988  ThreadVars tv;
989  int ret = 0;
990  DetectFlagsData *de = NULL;
991  SigMatch *sm = NULL;
992  IPV4Hdr ipv4h;
993  TCPHdr tcph;
994 
995  memset(&tv, 0, sizeof(ThreadVars));
996  memset(p, 0, SIZE_OF_PACKET);
997  memset(&ipv4h, 0, sizeof(IPV4Hdr));
998  memset(&tcph, 0, sizeof(TCPHdr));
999 
1000  p->ip4h = &ipv4h;
1001  p->tcph = &tcph;
1002  p->tcph->th_flags = TH_SYN|TH_RST;
1003 
1004  de = DetectFlagsParse("!PA");
1005 
1006  if (de == NULL || (de->modifier != MODIFIER_NOT) || (de->flags != (TH_ACK|TH_PUSH)))
1007  goto error;
1008 
1009  sm = SigMatchAlloc();
1010  if (sm == NULL)
1011  goto error;
1012 
1013  sm->type = DETECT_FLAGS;
1014  sm->ctx = (SigMatchCtx *)de;
1015 
1016  ret = DetectFlagsMatch(&tv, NULL, p, NULL, sm->ctx);
1017 
1018  if(ret) {
1019  if (de) SCFree(de);
1020  if (sm) SCFree(sm);
1021  SCFree(p);
1022  return 1;
1023  }
1024 
1025 error:
1026  if (de) SCFree(de);
1027  if (sm) SCFree(sm);
1028  SCFree(p);
1029  return 0;
1030 }
1031 
1032 /**
1033  * \test FlagsTestParse10 test if ACK and PUSH are not set. Must return success.
1034  *
1035  * \retval 1 on success
1036  * \retval 0 on failure
1037  */
1038 static int FlagsTestParse10 (void)
1039 {
1041  if (unlikely(p == NULL))
1042  return 0;
1043  ThreadVars tv;
1044  int ret = 0;
1045  DetectFlagsData *de = NULL;
1046  SigMatch *sm = NULL;
1047  IPV4Hdr ipv4h;
1048  TCPHdr tcph;
1049 
1050  memset(&tv, 0, sizeof(ThreadVars));
1051  memset(p, 0, SIZE_OF_PACKET);
1052  memset(&ipv4h, 0, sizeof(IPV4Hdr));
1053  memset(&tcph, 0, sizeof(TCPHdr));
1054 
1055  p->ip4h = &ipv4h;
1056  p->tcph = &tcph;
1057  p->tcph->th_flags = TH_SYN|TH_RST;
1058 
1059  de = DetectFlagsParse("!AP");
1060 
1061  if (de == NULL || (de->modifier != MODIFIER_NOT) || (de->flags != (TH_ACK|TH_PUSH)))
1062  goto error;
1063 
1064  sm = SigMatchAlloc();
1065  if (sm == NULL)
1066  goto error;
1067 
1068  sm->type = DETECT_FLAGS;
1069  sm->ctx = (SigMatchCtx *)de;
1070 
1071  ret = DetectFlagsMatch(&tv, NULL, p, NULL, sm->ctx);
1072 
1073  if(ret) {
1074  if (de) SCFree(de);
1075  if (sm) SCFree(sm);
1076  SCFree(p);
1077  return 1;
1078  }
1079 
1080 error:
1081  if (de) SCFree(de);
1082  if (sm) SCFree(sm);
1083  SCFree(p);
1084  return 0;
1085 }
1086 
1087 /**
1088  * \test FlagsTestParse11 test if ACK or PUSH are set. Ignore SYN and RST. Must fails.
1089  *
1090  * \retval 1 on success
1091  * \retval 0 on failure
1092  */
1093 static int FlagsTestParse11 (void)
1094 {
1096  if (unlikely(p == NULL))
1097  return 0;
1098  ThreadVars tv;
1099  int ret = 0;
1100  DetectFlagsData *de = NULL;
1101  SigMatch *sm = NULL;
1102  IPV4Hdr ipv4h;
1103  TCPHdr tcph;
1104 
1105  memset(&tv, 0, sizeof(ThreadVars));
1106  memset(p, 0, SIZE_OF_PACKET);
1107  memset(&ipv4h, 0, sizeof(IPV4Hdr));
1108  memset(&tcph, 0, sizeof(TCPHdr));
1109 
1110  p->ip4h = &ipv4h;
1111  p->tcph = &tcph;
1112  p->tcph->th_flags = TH_SYN|TH_RST|TH_URG;
1113 
1114  de = DetectFlagsParse("*AP,SR");
1115 
1116  if (de == NULL || (de->modifier != MODIFIER_ANY) || (de->flags != (TH_ACK|TH_PUSH)) || ((0xff - de->ignored_flags) != (TH_SYN|TH_RST)))
1117  goto error;
1118 
1119  sm = SigMatchAlloc();
1120  if (sm == NULL)
1121  goto error;
1122 
1123  sm->type = DETECT_FLAGS;
1124  sm->ctx = (SigMatchCtx *)de;
1125 
1126  ret = DetectFlagsMatch(&tv, NULL, p, NULL, sm->ctx);
1127 
1128  if(ret) {
1129  if (de) SCFree(de);
1130  if (sm) SCFree(sm);
1131  SCFree(p);
1132  return 0;
1133  }
1134 
1135  /* Expected. */
1136 error:
1137  if (de) SCFree(de);
1138  if (sm) SCFree(sm);
1139  SCFree(p);
1140  return 1;
1141 }
1142 
1143 /**
1144  * \test FlagsTestParse12 check if no flags are set. Must fails.
1145  *
1146  * \retval 1 on succces
1147  * \retval 0 on failure
1148  */
1149 static int FlagsTestParse12 (void)
1150 {
1152  if (unlikely(p == NULL))
1153  return 0;
1154  ThreadVars tv;
1155  int ret = 0;
1156  DetectFlagsData *de = NULL;
1157  SigMatch *sm = NULL;
1158  IPV4Hdr ipv4h;
1159  TCPHdr tcph;
1160 
1161  memset(&tv, 0, sizeof(ThreadVars));
1162  memset(p, 0, SIZE_OF_PACKET);
1163  memset(&ipv4h, 0, sizeof(IPV4Hdr));
1164  memset(&tcph, 0, sizeof(TCPHdr));
1165 
1166  p->ip4h = &ipv4h;
1167  p->tcph = &tcph;
1168  p->tcph->th_flags = TH_SYN;
1169 
1170  de = DetectFlagsParse("0");
1171 
1172  if (de == NULL || de->flags != 0) {
1173  printf("de setup: ");
1174  goto error;
1175  }
1176 
1177  sm = SigMatchAlloc();
1178  if (sm == NULL)
1179  goto error;
1180 
1181  sm->type = DETECT_FLAGS;
1182  sm->ctx = (SigMatchCtx *)de;
1183 
1184  ret = DetectFlagsMatch(&tv, NULL, p, NULL, sm->ctx);
1185 
1186  if(ret) {
1187  if (de) SCFree(de);
1188  if (sm) SCFree(sm);
1189  SCFree(p);
1190  return 0;
1191  }
1192 
1193  /* Expected. */
1194 error:
1195  if (de) SCFree(de);
1196  if (sm) SCFree(sm);
1197  SCFree(p);
1198  return 1;
1199 }
1200 
1201 /**
1202  * \test test for a valid flags value
1203  *
1204  * \retval 1 on succces
1205  * \retval 0 on failure
1206  */
1207 static int FlagsTestParse13 (void)
1208 {
1209  DetectFlagsData *de = NULL;
1210  de = DetectFlagsParse("+S*");
1211  if (de != NULL) {
1212  DetectFlagsFree(de);
1213  return 0;
1214  }
1215 
1216  return 1;
1217 }
1218 
1219 /**
1220  * \test Parse 'C' and 'E' flags.
1221  *
1222  * \retval 1 on success.
1223  * \retval 0 on failure.
1224  */
1225 static int FlagsTestParse14(void)
1226 {
1227  DetectFlagsData *de = DetectFlagsParse("CE");
1228  if (de != NULL && (de->flags == (TH_CWR | TH_ECN)) ) {
1229  DetectFlagsFree(de);
1230  return 1;
1231  }
1232 
1233  return 0;
1234 }
1235 
1236 static int FlagsTestParse15(void)
1237 {
1239  if (unlikely(p == NULL))
1240  return 0;
1241  ThreadVars tv;
1242  int ret = 0;
1243  DetectFlagsData *de = NULL;
1244  SigMatch *sm = NULL;
1245  IPV4Hdr ipv4h;
1246  TCPHdr tcph;
1247 
1248  memset(&tv, 0, sizeof(ThreadVars));
1249  memset(p, 0, SIZE_OF_PACKET);
1250  memset(&ipv4h, 0, sizeof(IPV4Hdr));
1251  memset(&tcph, 0, sizeof(TCPHdr));
1252 
1253  p->ip4h = &ipv4h;
1254  p->tcph = &tcph;
1255  p->tcph->th_flags = TH_ECN | TH_CWR | TH_SYN | TH_RST;
1256 
1257  de = DetectFlagsParse("EC+");
1258 
1259  if (de == NULL || (de->flags != (TH_ECN | TH_CWR)) )
1260  goto error;
1261 
1262  sm = SigMatchAlloc();
1263  if (sm == NULL)
1264  goto error;
1265 
1266  sm->type = DETECT_FLAGS;
1267  sm->ctx = (SigMatchCtx *)de;
1268 
1269  ret = DetectFlagsMatch(&tv, NULL, p, NULL, sm->ctx);
1270 
1271  if (ret) {
1272  if (de)
1273  SCFree(de);
1274  if (sm)
1275  SCFree(sm);
1276  SCFree(p);
1277  return 1;
1278  }
1279 
1280 error:
1281  if (de)
1282  SCFree(de);
1283  if (sm)
1284  SCFree(sm);
1285  SCFree(p);
1286  return 0;
1287 }
1288 
1289 static int FlagsTestParse16(void)
1290 {
1292  if (unlikely(p == NULL))
1293  return 0;
1294  ThreadVars tv;
1295  int ret = 0;
1296  DetectFlagsData *de = NULL;
1297  SigMatch *sm = NULL;
1298  IPV4Hdr ipv4h;
1299  TCPHdr tcph;
1300 
1301  memset(&tv, 0, sizeof(ThreadVars));
1302  memset(p, 0, SIZE_OF_PACKET);
1303  memset(&ipv4h, 0, sizeof(IPV4Hdr));
1304  memset(&tcph, 0, sizeof(TCPHdr));
1305 
1306  p->ip4h = &ipv4h;
1307  p->tcph = &tcph;
1308  p->tcph->th_flags = TH_ECN | TH_SYN | TH_RST;
1309 
1310  de = DetectFlagsParse("EC*");
1311 
1312  if (de == NULL || (de->flags != (TH_ECN | TH_CWR)) )
1313  goto error;
1314 
1315  sm = SigMatchAlloc();
1316  if (sm == NULL)
1317  goto error;
1318 
1319  sm->type = DETECT_FLAGS;
1320  sm->ctx = (SigMatchCtx *)de;
1321 
1322  ret = DetectFlagsMatch(&tv, NULL, p, NULL, sm->ctx);
1323 
1324  if (ret) {
1325  if (de)
1326  SCFree(de);
1327  if (sm)
1328  SCFree(sm);
1329  SCFree(p);
1330  return 1;
1331  }
1332 
1333 error:
1334  if (de)
1335  SCFree(de);
1336  if (sm)
1337  SCFree(sm);
1338  SCFree(p);
1339  return 0;
1340 }
1341 
1342 /**
1343  * \test Negative test.
1344  */
1345 static int FlagsTestParse17(void)
1346 {
1348  if (unlikely(p == NULL))
1349  return 0;
1350  ThreadVars tv;
1351  int ret = 0;
1352  DetectFlagsData *de = NULL;
1353  SigMatch *sm = NULL;
1354  IPV4Hdr ipv4h;
1355  TCPHdr tcph;
1356 
1357  memset(&tv, 0, sizeof(ThreadVars));
1358  memset(p, 0, SIZE_OF_PACKET);
1359  memset(&ipv4h, 0, sizeof(IPV4Hdr));
1360  memset(&tcph, 0, sizeof(TCPHdr));
1361 
1362  p->ip4h = &ipv4h;
1363  p->tcph = &tcph;
1364  p->tcph->th_flags = TH_ECN | TH_SYN | TH_RST;
1365 
1366  de = DetectFlagsParse("EC+");
1367 
1368  if (de == NULL || (de->flags != (TH_ECN | TH_CWR)) )
1369  goto error;
1370 
1371  sm = SigMatchAlloc();
1372  if (sm == NULL)
1373  goto error;
1374 
1375  sm->type = DETECT_FLAGS;
1376  sm->ctx = (SigMatchCtx *)de;
1377 
1378  ret = DetectFlagsMatch(&tv, NULL, p, NULL, sm->ctx);
1379 
1380  if (ret == 0) {
1381  if (de)
1382  SCFree(de);
1383  if (sm)
1384  SCFree(sm);
1385  SCFree(p);
1386  return 1;
1387  }
1388 
1389 error:
1390  if (de)
1391  SCFree(de);
1392  if (sm)
1393  SCFree(sm);
1394  SCFree(p);
1395  return 0;
1396 }
1397 
1398 #endif /* UNITTESTS */
1399 
1400 /**
1401  * \brief this function registers unit tests for Flags
1402  */
1404 {
1405 #ifdef UNITTESTS
1406  UtRegisterTest("FlagsTestParse01", FlagsTestParse01);
1407  UtRegisterTest("FlagsTestParse02", FlagsTestParse02);
1408  UtRegisterTest("FlagsTestParse03", FlagsTestParse03);
1409  UtRegisterTest("FlagsTestParse04", FlagsTestParse04);
1410  UtRegisterTest("FlagsTestParse05", FlagsTestParse05);
1411  UtRegisterTest("FlagsTestParse06", FlagsTestParse06);
1412  UtRegisterTest("FlagsTestParse07", FlagsTestParse07);
1413  UtRegisterTest("FlagsTestParse08", FlagsTestParse08);
1414  UtRegisterTest("FlagsTestParse09", FlagsTestParse09);
1415  UtRegisterTest("FlagsTestParse10", FlagsTestParse10);
1416  UtRegisterTest("FlagsTestParse11", FlagsTestParse11);
1417  UtRegisterTest("FlagsTestParse12", FlagsTestParse12);
1418  UtRegisterTest("FlagsTestParse13", FlagsTestParse13);
1419  UtRegisterTest("FlagsTestParse14", FlagsTestParse14);
1420  UtRegisterTest("FlagsTestParse15", FlagsTestParse15);
1421  UtRegisterTest("FlagsTestParse16", FlagsTestParse16);
1422  UtRegisterTest("FlagsTestParse17", FlagsTestParse17);
1423 #endif /* UNITTESTS */
1424 }
SigTableElmt sigmatch_table[DETECT_TBLSIZE]
Definition: detect.h:1403
SignatureInitData * init_data
Definition: detect.h:560
uint16_t flags
int(* Setup)(DetectEngineCtx *, Signature *, const char *)
Definition: detect.h:1146
#define SCLogDebug(...)
Definition: util-debug.h:335
int(* SetupPrefilter)(DetectEngineCtx *de_ctx, struct SigGroupHead_ *sgh)
Definition: detect.h:1149
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))
uint32_t flags
Definition: detect.h:493
_Bool(* SupportsPrefilter)(const Signature *s)
Definition: detect.h:1148
#define FALSE
#define PASS
Pass the test.
#define unlikely(expr)
Definition: util-optimize.h:35
void DetectFlagsRegister(void)
Registration function for flags: keyword.
Definition: detect-flags.c:73
#define TH_RST
Definition: decode-tcp.h:37
#define TH_FIN
Definition: decode-tcp.h:35
#define MODIFIER_ANY
Definition: detect-flags.c:56
Container for matching data for a signature group.
Definition: detect.h:1295
#define SIG_FLAG_REQUIRE_PACKET
Definition: detect.h:230
const char * name
Definition: detect.h:1160
TCPHdr * tcph
Definition: decode.h:525
Signature container.
Definition: detect.h:492
#define TRUE
Used to start a pointer to SigMatch context Should never be dereferenced without casting to something...
Definition: detect.h:319
#define PARSE_REGEX
Definition: detect-flags.c:47
struct SigMatch_ * next
Definition: detect.h:328
main detection engine ctx
Definition: detect.h:720
#define SIZE_OF_PACKET
Definition: decode.h:628
int de
void(* Free)(void *)
Definition: detect.h:1151
#define SCLogError(err_code,...)
Macro used to log ERROR messages.
Definition: util-debug.h:294
void UtRegisterTest(const char *name, int(*TestFn)(void))
Register unit test.
void DetectSetupParseRegexes(const char *parse_str, pcre **parse_regex, pcre_extra **parse_regex_study)
#define TH_URG
Definition: decode-tcp.h:40
#define SCEnter(...)
Definition: util-debug.h:337
PrefilterRuleStore pmq
Definition: detect.h:1061
#define TH_ACK
Definition: decode-tcp.h:39
#define TH_PUSH
Definition: decode-tcp.h:38
#define TH_ECN
Definition: decode-tcp.h:42
#define MODIFIER_PLUS
Definition: detect-flags.c:55
uint8_t type
Definition: detect.h:325
#define SCReturnInt(x)
Definition: util-debug.h:341
void SigMatchAppendSMToList(Signature *s, SigMatch *new, int list)
Append a SigMatch to the list type.
Definition: detect-parse.c:282
struct SigMatch_ ** smlists
Definition: detect.h:486
IPV4Hdr * ip4h
Definition: decode.h:503
SigMatchCtx * ctx
Definition: detect.h:327
#define SCMalloc(a)
Definition: util-mem.h:174
#define MODIFIER_NOT
Definition: detect-flags.c:54
#define TH_SYN
Definition: decode-tcp.h:36
#define SCFree(a)
Definition: util-mem.h:236
PoolThreadReserved res
#define PKT_IS_TCP(p)
Definition: decode.h:252
int(* Match)(ThreadVars *, DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *)
Definition: detect.h:1129
#define SCReturnPtr(x, type)
Definition: util-debug.h:353
#define FAIL_IF_NULL(expr)
Fail a test if expression evaluates to NULL.
Definition: util-unittest.h:89
TCPHdr tcph
#define PKT_IS_PSEUDOPKT(p)
return 1 if the packet is a pseudo packet
Definition: decode.h:1140
#define MAX_SUBSTRINGS
SigMatch * SigMatchAlloc(void)
Definition: detect-parse.c:226
#define SCReturn
Definition: util-debug.h:339
Per thread variable structure.
Definition: threadvars.h:57
void FlagsRegisterTests(void)
this function registers unit tests for Flags
int DetectFlagsSignatureNeedsSynOnlyPackets(const Signature *s)
Definition: detect-flags.c:526
#define TH_CWR
Definition: decode-tcp.h:44
int DetectFlagsSignatureNeedsSynPackets(const Signature *s)
Definition: detect-flags.c:507
uint8_t ignored_flags
Definition: detect-flags.h:44
void(* RegisterTests)(void)
Definition: detect.h:1152
a single match condition for a signature
Definition: detect.h:324
#define FAIL_IF_NOT(expr)
Fail a test if expression to true.
Definition: util-unittest.h:82