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