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