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