suricata
detect-threshold.c
Go to the documentation of this file.
1/* Copyright (C) 2007-2021 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 * \ingroup threshold
20 * @{
21 */
22
23/**
24 * \file
25 *
26 * \author Breno Silva <breno.silva@gmail.com>
27 * \author Victor Julien <victor@inliniac.net>
28 *
29 * Implements the threshold keyword.
30 *
31 * The feature depends on what is provided
32 * by detect-engine-threshold.c and util-threshold-config.c
33 */
34
35#include "suricata-common.h"
36#include "suricata.h"
37#include "decode.h"
38
39#include "host.h"
40#include "host-storage.h"
41
42#include "detect.h"
43#include "detect-parse.h"
44
45#include "flow-var.h"
46#include "decode-events.h"
47#include "stream-tcp.h"
48
49#include "detect-threshold.h"
52#include "detect-engine-build.h"
53
54#include "util-unittest.h"
56#include "util-byte.h"
57#include "util-debug.h"
58
59#ifdef UNITTESTS
60#include "util-cpu.h"
61#endif
62
63#define PARSE_REGEX_NAME "(track|type|count|seconds|multiplier)"
64#define PARSE_REGEX_VALUE \
65 "(limit|both|threshold|backoff|by_dst|by_src|by_both|by_rule|by_flow|\\d+)"
66
67#define PARSE_REGEX \
68 "^\\s*" PARSE_REGEX_NAME "\\s+" PARSE_REGEX_VALUE "\\s*,\\s*" PARSE_REGEX_NAME \
69 "\\s+" PARSE_REGEX_VALUE "\\s*,\\s*" PARSE_REGEX_NAME "\\s+" PARSE_REGEX_VALUE \
70 "\\s*,\\s*" PARSE_REGEX_NAME "\\s+" PARSE_REGEX_VALUE "\\s*"
71
72static DetectParseRegex parse_regex;
73
74static int DetectThresholdMatch(
75 DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *);
76static int DetectThresholdSetup(DetectEngineCtx *, Signature *, const char *);
77static void DetectThresholdFree(DetectEngineCtx *, void *);
78#ifdef UNITTESTS
79static void ThresholdRegisterTests(void);
80#endif
81
82/**
83 * \brief Registration function for threshold: keyword
84 */
85
87{
89 sigmatch_table[DETECT_THRESHOLD].desc = "control the rule's alert frequency";
90 sigmatch_table[DETECT_THRESHOLD].url = "/rules/thresholding.html#threshold";
91 sigmatch_table[DETECT_THRESHOLD].Match = DetectThresholdMatch;
92 sigmatch_table[DETECT_THRESHOLD].Setup = DetectThresholdSetup;
93 sigmatch_table[DETECT_THRESHOLD].Free = DetectThresholdFree;
94#ifdef UNITTESTS
95 sigmatch_table[DETECT_THRESHOLD].RegisterTests = ThresholdRegisterTests;
96#endif
97 /* this is compatible to ip-only signatures */
99
101}
102
103static int DetectThresholdMatch(
104 DetectEngineThreadCtx *det_ctx, Packet *p, const Signature *s, const SigMatchCtx *ctx)
105{
106 return 1;
107}
108
109/**
110 * \internal
111 * \brief This function is used to parse threshold options passed via threshold: keyword
112 *
113 * \param rawstr Pointer to the user provided threshold options
114 *
115 * \retval de pointer to DetectThresholdData on success
116 * \retval NULL on failure
117 */
118static DetectThresholdData *DetectThresholdParse(const char *rawstr)
119{
120 DetectThresholdData *de = NULL;
121 int ret = 0, res = 0;
122 size_t pcre2_len;
123 const char *str_ptr = NULL;
124 char *args[9] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
125 char *copy_str = NULL, *threshold_opt = NULL;
126 int second_found = 0, count_found = 0;
127 int type_found = 0, track_found = 0;
128 int multiplier_found = 0;
129 int second_pos = 0, count_pos = 0, multiplier_pos = 0;
130 size_t pos = 0;
131 int i = 0;
132 pcre2_match_data *match = NULL;
133
134 copy_str = SCStrdup(rawstr);
135 if (unlikely(copy_str == NULL)) {
136 goto error;
137 }
138
139 char *saveptr = NULL;
140 for (pos = 0, threshold_opt = strtok_r(copy_str, ",", &saveptr);
141 pos < strlen(copy_str) && threshold_opt != NULL;
142 pos++, threshold_opt = strtok_r(NULL, ",", &saveptr)) {
143 if (strstr(threshold_opt, "count"))
144 count_found++;
145 if (strstr(threshold_opt, "second"))
146 second_found++;
147 if (strstr(threshold_opt, "type"))
148 type_found++;
149 if (strstr(threshold_opt, "track"))
150 track_found++;
151 if (strstr(threshold_opt, "multiplier"))
152 multiplier_found++;
153 }
154 SCFree(copy_str);
155 copy_str = NULL;
156
157 if (!(count_found == 1 && (second_found == 1 || multiplier_found == 1) && track_found == 1 &&
158 type_found == 1)) {
159 goto error;
160 }
161
162 ret = DetectParsePcreExec(&parse_regex, &match, rawstr, 0, 0);
163 if (ret < 5 || ret > 9) {
164 SCLogError("pcre_exec parse error, ret %" PRId32 ", string %s", ret, rawstr);
165 goto error;
166 }
167
168 de = SCCalloc(1, sizeof(DetectThresholdData));
169 if (unlikely(de == NULL))
170 goto error;
171
172 for (i = 0; i < (ret - 1); i++) {
173
174 res = pcre2_substring_get_bynumber(match, i + 1, (PCRE2_UCHAR8 **)&str_ptr, &pcre2_len);
175
176 if (res < 0) {
177 SCLogError("pcre2_substring_get_bynumber failed");
178 goto error;
179 }
180
181 args[i] = (char *)str_ptr;
182
183 if (strncasecmp(args[i], "limit", strlen("limit")) == 0)
184 de->type = TYPE_LIMIT;
185 if (strncasecmp(args[i], "both", strlen("both")) == 0)
186 de->type = TYPE_BOTH;
187 if (strncasecmp(args[i], "threshold", strlen("threshold")) == 0)
188 de->type = TYPE_THRESHOLD;
189 if (strcasecmp(args[i], "backoff") == 0)
190 de->type = TYPE_BACKOFF;
191 if (strncasecmp(args[i], "by_dst", strlen("by_dst")) == 0)
192 de->track = TRACK_DST;
193 if (strncasecmp(args[i], "by_src", strlen("by_src")) == 0)
194 de->track = TRACK_SRC;
195 if (strncasecmp(args[i], "by_both", strlen("by_both")) == 0)
196 de->track = TRACK_BOTH;
197 if (strncasecmp(args[i], "by_rule", strlen("by_rule")) == 0)
198 de->track = TRACK_RULE;
199 if (strncasecmp(args[i], "by_flow", strlen("by_flow")) == 0)
200 de->track = TRACK_FLOW;
201 if (strncasecmp(args[i], "count", strlen("count")) == 0)
202 count_pos = i + 1;
203 if (strncasecmp(args[i], "seconds", strlen("seconds")) == 0)
204 second_pos = i + 1;
205 if (strcasecmp(args[i], "multiplier") == 0)
206 multiplier_pos = i + 1;
207 }
208
209 if (de->type != TYPE_BACKOFF) {
210 if (args[count_pos] == NULL || args[second_pos] == NULL) {
211 goto error;
212 }
213
214 if (StringParseUint32(&de->count, 10, strlen(args[count_pos]), args[count_pos]) <= 0) {
215 goto error;
216 }
217 if (StringParseUint32(&de->seconds, 10, strlen(args[second_pos]), args[second_pos]) <= 0) {
218 goto error;
219 }
220 } else {
221 if (args[count_pos] == NULL || args[multiplier_pos] == NULL) {
222 goto error;
223 }
224
225 if (second_found) {
226 goto error;
227 }
228
229 if (StringParseUint32(&de->count, 10, strlen(args[count_pos]), args[count_pos]) <= 0) {
230 goto error;
231 }
233 &de->multiplier, 10, strlen(args[multiplier_pos]), args[multiplier_pos]) <= 0) {
234 goto error;
235 }
236
237 /* impose some sanity limits on the count and multiplier values. Upper bounds are a bit
238 * artificial. */
239 if (!(de->count > 0 && de->count < 65536)) {
240 SCLogError("invalid count value '%u': must be in the range 1-65535", de->count);
241 goto error;
242 }
243 if (!(de->multiplier > 1 && de->multiplier < 65536)) {
245 "invalid multiplier value '%u': must be in the range 2-65535", de->multiplier);
246 goto error;
247 }
248
249 if (de->track != TRACK_FLOW) {
250 SCLogError("invalid track value: type backoff only supported for track by_flow");
251 goto error;
252 }
253
254 SCLogDebug("TYPE_BACKOFF count %u multiplier %u", de->count, de->multiplier);
255 }
256
257 for (i = 0; i < (ret - 1); i++) {
258 if (args[i] != NULL)
259 pcre2_substring_free((PCRE2_UCHAR8 *)args[i]);
260 }
261 pcre2_match_data_free(match);
262 return de;
263
264error:
265 if (match) {
266 pcre2_match_data_free(match);
267 }
268 for (i = 0; i < (ret - 1); i++) {
269 if (args[i] != NULL)
270 pcre2_substring_free((PCRE2_UCHAR8 *)args[i]);
271 }
272 if (de != NULL)
273 SCFree(de);
274 return NULL;
275}
276
277/**
278 * \internal
279 * \brief this function is used to add the parsed threshold into the current signature
280 *
281 * \param de_ctx pointer to the Detection Engine Context
282 * \param s pointer to the Current Signature
283 * \param rawstr pointer to the user provided threshold options
284 *
285 * \retval 0 on Success
286 * \retval -1 on Failure
287 */
288static int DetectThresholdSetup(DetectEngineCtx *de_ctx, Signature *s, const char *rawstr)
289{
290 DetectThresholdData *de = NULL;
291 SigMatch *tmpm = NULL;
292
293 /* checks if there is a previous instance of detection_filter */
295 if (tmpm != NULL) {
296 if (tmpm->type == DETECT_DETECTION_FILTER) {
297 SCLogError("\"detection_filter\" and "
298 "\"threshold\" are not allowed in the same rule");
299 } else {
300 SCLogError("multiple \"threshold\" "
301 "options are not allowed in the same rule");
302 }
303 SCReturnInt(-1);
304 }
305
306 de = DetectThresholdParse(rawstr);
307 if (de == NULL)
308 goto error;
309
312 goto error;
313 }
314
315 return 0;
316
317error:
318 if (de)
319 SCFree(de);
320 return -1;
321}
322
323/**
324 * \internal
325 * \brief this function will free memory associated with DetectThresholdData
326 *
327 * \param de pointer to DetectThresholdData
328 */
329static void DetectThresholdFree(DetectEngineCtx *de_ctx, void *de_ptr)
330{
332 if (de) {
334 SCFree(de);
335 }
336}
337
338/**
339 * \brief Make a deep-copy of an extant DetectTHresholdData object.
340 *
341 * \param de pointer to DetectThresholdData
342 */
344{
346 if (unlikely(new_de == NULL))
347 return NULL;
348
349 *new_de = *de;
350 new_de->addrs.ipv4_head = NULL;
351 new_de->addrs.ipv6_head = NULL;
352
353 for (DetectAddress *last = NULL, *tmp_ad = de->addrs.ipv4_head; tmp_ad; tmp_ad = tmp_ad->next) {
354 DetectAddress *n_addr = DetectAddressCopy(tmp_ad);
355 if (n_addr == NULL)
356 goto error;
357 if (last == NULL) {
358 new_de->addrs.ipv4_head = n_addr;
359 } else {
360 last->next = n_addr;
361 n_addr->prev = last;
362 }
363 last = n_addr;
364 }
365 for (DetectAddress *last = NULL, *tmp_ad = de->addrs.ipv6_head; tmp_ad; tmp_ad = tmp_ad->next) {
366 DetectAddress *n_addr = DetectAddressCopy(tmp_ad);
367 if (n_addr == NULL)
368 goto error;
369 if (last == NULL) {
370 new_de->addrs.ipv6_head = n_addr;
371 } else {
372 last->next = n_addr;
373 n_addr->prev = last;
374 }
375 last = n_addr;
376 }
377
378 return new_de;
379
380error:
381 DetectThresholdFree(NULL, new_de);
382 return NULL;
383}
384
385/*
386 * ONLY TESTS BELOW THIS COMMENT
387 */
388#ifdef UNITTESTS
389#include "detect-engine.h"
390#include "detect-engine-mpm.h"
391#include "detect-engine-alert.h"
392#include "util-time.h"
393#include "util-hashlist.h"
394#include "packet.h"
395#include "action-globals.h"
396
397/**
398 * \test ThresholdTestParse01 is a test for a valid threshold options
399 *
400 * \retval 1 on success
401 * \retval 0 on failure
402 */
403static int ThresholdTestParse01(void)
404{
405 DetectThresholdData *de = NULL;
406 de = DetectThresholdParse("type limit,track by_dst,count 10,seconds 60");
407 if (de && (de->type == TYPE_LIMIT) && (de->track == TRACK_DST) && (de->count == 10) &&
408 (de->seconds == 60)) {
409 DetectThresholdFree(NULL, de);
410 return 1;
411 }
412
413 return 0;
414}
415
416static int ThresholdTestParseByFlow01(void)
417{
418 DetectThresholdData *de = DetectThresholdParse("type limit,track by_flow,count 1,seconds 60");
419 FAIL_IF_NULL(de);
422 FAIL_IF_NOT(de->count == 1);
423 FAIL_IF_NOT(de->seconds == 60);
424 DetectThresholdFree(NULL, de);
425 PASS;
426}
427
428/**
429 * \test ThresholdTestParse02 is a test for a invalid threshold options
430 *
431 * \retval 1 on success
432 * \retval 0 on failure
433 */
434static int ThresholdTestParse02(void)
435{
436 DetectThresholdData *de = NULL;
437 de = DetectThresholdParse("type any,track by_dst,count 10,seconds 60");
438 if (de && (de->type == TYPE_LIMIT) && (de->track == TRACK_DST) && (de->count == 10) &&
439 (de->seconds == 60)) {
440 DetectThresholdFree(NULL, de);
441 return 0;
442 }
443
444 return 1;
445}
446
447/**
448 * \test ThresholdTestParse03 is a test for a valid threshold options in any order
449 *
450 * \retval 1 on success
451 * \retval 0 on failure
452 */
453static int ThresholdTestParse03(void)
454{
455 DetectThresholdData *de = NULL;
456 de = DetectThresholdParse("track by_dst, type limit, seconds 60, count 10");
457 if (de && (de->type == TYPE_LIMIT) && (de->track == TRACK_DST) && (de->count == 10) &&
458 (de->seconds == 60)) {
459 DetectThresholdFree(NULL, de);
460 return 1;
461 }
462
463 return 0;
464}
465
466/**
467 * \test ThresholdTestParse04 is a test for an invalid threshold options in any order
468 *
469 * \retval 1 on success
470 * \retval 0 on failure
471 */
472static int ThresholdTestParse04(void)
473{
474 DetectThresholdData *de = NULL;
475 de = DetectThresholdParse("count 10, track by_dst, seconds 60, type both, count 10");
476 if (de && (de->type == TYPE_BOTH) && (de->track == TRACK_DST) && (de->count == 10) &&
477 (de->seconds == 60)) {
478 DetectThresholdFree(NULL, de);
479 return 0;
480 }
481
482 return 1;
483}
484
485/**
486 * \test ThresholdTestParse05 is a test for a valid threshold options in any order
487 *
488 * \retval 1 on success
489 * \retval 0 on failure
490 */
491static int ThresholdTestParse05(void)
492{
493 DetectThresholdData *de = NULL;
494 de = DetectThresholdParse("count 10, track by_dst, seconds 60, type both");
495 if (de && (de->type == TYPE_BOTH) && (de->track == TRACK_DST) && (de->count == 10) &&
496 (de->seconds == 60)) {
497 DetectThresholdFree(NULL, de);
498 return 1;
499 }
500
501 return 0;
502}
503
504/**
505 * \test ThresholdTestParse06 is a test for thresholding by_both
506 *
507 * \retval 1 on success
508 * \retval 0 on failure
509 */
510static int ThresholdTestParse06(void)
511{
512 DetectThresholdData *de = NULL;
513 de = DetectThresholdParse("count 10, track by_both, seconds 60, type limit");
514 FAIL_IF_NULL(de);
517 FAIL_IF_NOT(de->count == 10);
518 FAIL_IF_NOT(de->seconds == 60);
519 DetectThresholdFree(NULL, de);
520 PASS;
521}
522
523/**
524 * \test ThresholdTestParse07 is a test for thresholding by_rule
525 *
526 * \retval 1 on success
527 * \retval 0 on failure
528 */
529static int ThresholdTestParse07(void)
530{
531 DetectThresholdData *de = NULL;
532 de = DetectThresholdParse("count 10, track by_rule, seconds 60, type limit");
533 FAIL_IF_NULL(de);
536 FAIL_IF_NOT(de->count == 10);
537 FAIL_IF_NOT(de->seconds == 60);
538 DetectThresholdFree(NULL, de);
539 PASS;
540}
541
542/** \test backoff by_flow */
543static int ThresholdTestParse08(void)
544{
546 DetectThresholdParse("count 10, track by_flow, multiplier 2, type backoff");
547 FAIL_IF_NULL(de);
550 FAIL_IF_NOT(de->count == 10);
551 FAIL_IF_NOT(de->multiplier == 2);
552 DetectThresholdFree(NULL, de);
553 PASS;
554}
555
556/**
557 * \test DetectThresholdTestSig1 is a test for checking the working of limit keyword
558 * by setting up the signature and later testing its working by matching
559 * the received packet against the sig.
560 *
561 * \retval 1 on success
562 * \retval 0 on failure
563 */
564
565static int DetectThresholdTestSig1(void)
566{
567 Packet *p = NULL;
568 Signature *s = NULL;
569 ThreadVars th_v;
570 DetectEngineThreadCtx *det_ctx;
571 int result = 0;
572 int alerts = 0;
573
575
576 memset(&th_v, 0, sizeof(th_v));
577
578 p = UTHBuildPacketReal((uint8_t *)"A", 1, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80);
579
581 if (de_ctx == NULL) {
582 goto end;
583 }
584
586
587 s = de_ctx->sig_list =
588 SigInit(de_ctx, "alert tcp any any -> any 80 (msg:\"Threshold limit\"; content:\"A\"; "
589 "threshold: type limit, track by_dst, count 5, seconds 60; sid:1;)");
590 if (s == NULL) {
591 goto end;
592 }
593
595
597
598 DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
599
600 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
601 alerts = PacketAlertCheck(p, 1);
602 if (alerts != 1) {
603 printf("alerts %" PRIi32 ", expected 1: ", alerts);
604 }
605 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
606 alerts += PacketAlertCheck(p, 1);
607 if (alerts != 2) {
608 printf("alerts %" PRIi32 ", expected 2: ", alerts);
609 }
610 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
611 alerts += PacketAlertCheck(p, 1);
612 if (alerts != 3) {
613 printf("alerts %" PRIi32 ", expected 3: ", alerts);
614 }
615 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
616 alerts += PacketAlertCheck(p, 1);
617 if (alerts != 4) {
618 printf("alerts %" PRIi32 ", expected 4: ", alerts);
619 }
620 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
621 alerts += PacketAlertCheck(p, 1);
622 if (alerts != 5) {
623 printf("alerts %" PRIi32 ", expected 5: ", alerts);
624 }
625 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
626 alerts += PacketAlertCheck(p, 1);
627 if (alerts != 5) {
628 printf("alerts %" PRIi32 ", expected 5: ", alerts);
629 }
630 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
631 alerts += PacketAlertCheck(p, 1);
632 if (alerts != 5) {
633 printf("alerts %" PRIi32 ", expected 5: ", alerts);
634 }
635 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
636 alerts += PacketAlertCheck(p, 1);
637 if (alerts != 5) {
638 printf("alerts %" PRIi32 ", expected 5: ", alerts);
639 }
640
641 if (alerts == 5)
642 result = 1;
643 else
644 printf("alerts %" PRIi32 ", expected 5: ", alerts);
645
648
649 DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
651
652 UTHFreePackets(&p, 1);
653
654end:
656 return result;
657}
658
659/**
660 * \test DetectThresholdTestSig2 is a test for checking the working of threshold keyword
661 * by setting up the signature and later testing its working by matching
662 * the received packet against the sig.
663 *
664 * \retval 1 on success
665 * \retval 0 on failure
666 */
667
668static int DetectThresholdTestSig2(void)
669{
670 Packet *p = NULL;
671 Signature *s = NULL;
672 ThreadVars th_v;
673 DetectEngineThreadCtx *det_ctx;
674 int result = 0;
675 int alerts = 0;
676
678
679 memset(&th_v, 0, sizeof(th_v));
680
681 p = UTHBuildPacketReal((uint8_t *)"A", 1, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80);
682
684 if (de_ctx == NULL) {
685 goto end;
686 }
687
689
690 s = de_ctx->sig_list =
691 SigInit(de_ctx, "alert tcp any any -> any 80 (msg:\"Threshold\"; threshold: type "
692 "threshold, track by_dst, count 5, seconds 60; sid:1;)");
693 if (s == NULL) {
694 goto end;
695 }
696
698 DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
699
700 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
701 alerts = PacketAlertCheck(p, 1);
702 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
703 alerts += PacketAlertCheck(p, 1);
704 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
705 alerts += PacketAlertCheck(p, 1);
706 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
707 alerts += PacketAlertCheck(p, 1);
708 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
709 alerts += PacketAlertCheck(p, 1);
710 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
711 alerts += PacketAlertCheck(p, 1);
712 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
713 alerts += PacketAlertCheck(p, 1);
714 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
715 alerts += PacketAlertCheck(p, 1);
716 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
717 alerts += PacketAlertCheck(p, 1);
718 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
719 alerts += PacketAlertCheck(p, 1);
720
721 if (alerts == 2)
722 result = 1;
723 else
724 goto cleanup;
725
726cleanup:
727 DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
729
730end:
731 UTHFreePackets(&p, 1);
733 return result;
734}
735
736/**
737 * \test DetectThresholdTestSig3 is a test for checking the working of limit keyword
738 * by setting up the signature and later testing its working by matching
739 * the received packet against the sig.
740 *
741 * \retval 1 on success
742 * \retval 0 on failure
743 */
744
745static int DetectThresholdTestSig3(void)
746{
747 ThreadVars th_v;
748 memset(&th_v, 0, sizeof(th_v));
749
751 Packet *p = UTHBuildPacketReal((uint8_t *)"A", 1, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80);
752
756
758 "alert tcp any any -> any 80 (msg:\"Threshold limit\"; threshold: type limit, "
759 "track by_dst, count 5, seconds 60; sid:10;)");
760 FAIL_IF_NULL(s);
761
763 DetectEngineThreadCtx *det_ctx;
764 DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
765
766 p->ts = TimeGet();
767
768 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
769 FAIL_IF_NOT(PacketAlertCheck(p, 10) == 1);
770 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
771 FAIL_IF_NOT(PacketAlertCheck(p, 10) == 1);
772 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
773 FAIL_IF_NOT(PacketAlertCheck(p, 10) == 1);
774
776 p->ts = TimeGet();
777
778 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
779 FAIL_IF_NOT(PacketAlertCheck(p, 10) == 1);
780 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
781 FAIL_IF_NOT(PacketAlertCheck(p, 10) == 1);
782 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
783 FAIL_IF_NOT(PacketAlertCheck(p, 10) == 1);
784
785 DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
787 UTHFreePackets(&p, 1);
789 PASS;
790}
791
792/**
793 * \test DetectThresholdTestSig4 is a test for checking the working of both keyword
794 * by setting up the signature and later testing its working by matching
795 * the received packet against the sig.
796 *
797 * \retval 1 on success
798 * \retval 0 on failure
799 */
800
801static int DetectThresholdTestSig4(void)
802{
803 Packet *p = NULL;
804 Signature *s = NULL;
805 ThreadVars th_v;
806 DetectEngineThreadCtx *det_ctx;
807 int result = 0;
808 int alerts = 0;
809
811
812 memset(&th_v, 0, sizeof(th_v));
813
814 p = UTHBuildPacketReal((uint8_t *)"A", 1, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80);
815
817 if (de_ctx == NULL) {
818 goto end;
819 }
820
822
823 s = de_ctx->sig_list =
824 SigInit(de_ctx, "alert tcp any any -> any 80 (msg:\"Threshold both\"; threshold: type "
825 "both, track by_dst, count 2, seconds 60; sid:10;)");
826 if (s == NULL) {
827 goto end;
828 }
829
831 DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
832
833 p->ts = TimeGet();
834 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
835 alerts = PacketAlertCheck(p, 10);
836 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
837 alerts += PacketAlertCheck(p, 10);
838 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
839 alerts += PacketAlertCheck(p, 10);
840
842 p->ts = TimeGet();
843
844 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
845 alerts += PacketAlertCheck(p, 10);
846 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
847 alerts += PacketAlertCheck(p, 10);
848 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
849 alerts += PacketAlertCheck(p, 10);
850
851 if (alerts == 2)
852 result = 1;
853 else
854 goto cleanup;
855
856cleanup:
857 DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
859end:
860 UTHFreePackets(&p, 1);
862 return result;
863}
864
865/**
866 * \test DetectThresholdTestSig5 is a test for checking the working of limit keyword
867 * by setting up the signature and later testing its working by matching
868 * the received packet against the sig.
869 *
870 * \retval 1 on success
871 * \retval 0 on failure
872 */
873
874static int DetectThresholdTestSig5(void)
875{
876 Packet *p = NULL;
877 Signature *s = NULL;
878 ThreadVars th_v;
879 DetectEngineThreadCtx *det_ctx;
880 int result = 0;
881 int alerts = 0;
882
884
885 memset(&th_v, 0, sizeof(th_v));
886 p = UTHBuildPacketReal((uint8_t *)"A", 1, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80);
887
889 if (de_ctx == NULL) {
890 goto end;
891 }
892
894
895 s = de_ctx->sig_list =
896 SigInit(de_ctx, "alert tcp any any -> any 80 (msg:\"Threshold limit sid 1\"; "
897 "threshold: type limit, track by_dst, count 5, seconds 60; sid:1;)");
898 if (s == NULL) {
899 goto end;
900 }
901
902 s = s->next =
903 SigInit(de_ctx, "alert tcp any any -> any 80 (msg:\"Threshold limit sid 1000\"; "
904 "threshold: type limit, track by_dst, count 5, seconds 60; sid:1000;)");
905 if (s == NULL) {
906 goto end;
907 }
908
910 DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
911
912 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
913 alerts = PacketAlertCheck(p, 1);
914 alerts += PacketAlertCheck(p, 1000);
915 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
916 alerts += PacketAlertCheck(p, 1);
917 alerts += PacketAlertCheck(p, 1000);
918 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
919 alerts += PacketAlertCheck(p, 1);
920 alerts += PacketAlertCheck(p, 1000);
921 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
922 alerts += PacketAlertCheck(p, 1);
923 alerts += PacketAlertCheck(p, 1000);
924 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
925 alerts += PacketAlertCheck(p, 1);
926 alerts += PacketAlertCheck(p, 1000);
927 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
928 alerts += PacketAlertCheck(p, 1);
929 alerts += PacketAlertCheck(p, 1000);
930 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
931 alerts += PacketAlertCheck(p, 1);
932 alerts += PacketAlertCheck(p, 1000);
933 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
934 alerts += PacketAlertCheck(p, 1);
935 alerts += PacketAlertCheck(p, 1000);
936
937 if (alerts == 10)
938 result = 1;
939 else {
940 printf("alerts %d != 10: ", alerts);
941 goto cleanup;
942 }
943
944cleanup:
945 DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
947
948end:
949 UTHFreePackets(&p, 1);
951 return result;
952}
953
954static int DetectThresholdTestSig6Ticks(void)
955{
956 Packet *p = NULL;
957 Signature *s = NULL;
958 ThreadVars th_v;
959 DetectEngineThreadCtx *det_ctx;
960 int result = 0;
961 int alerts = 0;
962
964
965 memset(&th_v, 0, sizeof(th_v));
966 p = UTHBuildPacketReal((uint8_t *)"A", 1, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80);
967
969 if (de_ctx == NULL) {
970 goto end;
971 }
972
974
975 s = de_ctx->sig_list =
976 SigInit(de_ctx, "alert tcp any any -> any 80 (msg:\"Threshold limit sid 1\"; "
977 "threshold: type limit, track by_dst, count 5, seconds 60; sid:1;)");
978 if (s == NULL) {
979 goto end;
980 }
981
982 s = s->next =
983 SigInit(de_ctx, "alert tcp any any -> any 80 (msg:\"Threshold limit sid 1000\"; "
984 "threshold: type limit, track by_dst, count 5, seconds 60; sid:1000;)");
985 if (s == NULL) {
986 goto end;
987 }
988
990 DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
991
992 uint64_t ticks_start = 0;
993 uint64_t ticks_end = 0;
994
995 ticks_start = UtilCpuGetTicks();
996 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
997 alerts = PacketAlertCheck(p, 1);
998 alerts += PacketAlertCheck(p, 1000);
999 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1000 alerts += PacketAlertCheck(p, 1);
1001 alerts += PacketAlertCheck(p, 1000);
1002 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1003 alerts += PacketAlertCheck(p, 1);
1004 alerts += PacketAlertCheck(p, 1000);
1005 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1006 alerts += PacketAlertCheck(p, 1);
1007 alerts += PacketAlertCheck(p, 1000);
1008 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1009 alerts += PacketAlertCheck(p, 1);
1010 alerts += PacketAlertCheck(p, 1000);
1011 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1012 alerts += PacketAlertCheck(p, 1);
1013 alerts += PacketAlertCheck(p, 1000);
1014 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1015 alerts += PacketAlertCheck(p, 1);
1016 alerts += PacketAlertCheck(p, 1000);
1017 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1018 alerts += PacketAlertCheck(p, 1);
1019 alerts += PacketAlertCheck(p, 1000);
1020 ticks_end = UtilCpuGetTicks();
1021 printf("test run %" PRIu64 "\n", (ticks_end - ticks_start));
1022
1023 if (alerts == 10)
1024 result = 1;
1025 else
1026 goto cleanup;
1027
1028cleanup:
1029 DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
1031
1032end:
1033 UTHFreePackets(&p, 1);
1035 return result;
1036}
1037
1038/**
1039 * \test Test drop action being set even if thresholded
1040 */
1041static int DetectThresholdTestSig7(void)
1042{
1043 Packet *p = NULL;
1044 Signature *s = NULL;
1045 ThreadVars th_v;
1046 DetectEngineThreadCtx *det_ctx;
1047 int result = 0;
1048 int alerts = 0;
1049 int drops = 0;
1050
1051 ThresholdInit();
1052
1053 memset(&th_v, 0, sizeof(th_v));
1054
1055 p = UTHBuildPacketReal((uint8_t *)"A", 1, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80);
1056
1058 if (de_ctx == NULL) {
1059 goto end;
1060 }
1061
1062 de_ctx->flags |= DE_QUIET;
1063
1064 s = de_ctx->sig_list = SigInit(de_ctx, "drop tcp any any -> any 80 (threshold: type limit, "
1065 "track by_src, count 1, seconds 300; sid:10;)");
1066 if (s == NULL) {
1067 goto end;
1068 }
1069
1071 DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
1072
1073 p->ts = TimeGet();
1074 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1075 alerts = PacketAlertCheck(p, 10);
1076 drops += ((PacketTestAction(p, ACTION_DROP)) ? 1 : 0);
1077 p->action = 0;
1078
1079 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1080 alerts += PacketAlertCheck(p, 10);
1081 drops += ((PacketTestAction(p, ACTION_DROP)) ? 1 : 0);
1082 p->action = 0;
1083
1084 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1085 alerts += PacketAlertCheck(p, 10);
1086 drops += ((PacketTestAction(p, ACTION_DROP)) ? 1 : 0);
1087 p->action = 0;
1088
1090 p->ts = TimeGet();
1091
1092 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1093 alerts += PacketAlertCheck(p, 10);
1094 drops += ((PacketTestAction(p, ACTION_DROP)) ? 1 : 0);
1095 p->action = 0;
1096
1097 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1098 alerts += PacketAlertCheck(p, 10);
1099 drops += ((PacketTestAction(p, ACTION_DROP)) ? 1 : 0);
1100 p->action = 0;
1101
1102 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1103 alerts += PacketAlertCheck(p, 10);
1104 drops += ((PacketTestAction(p, ACTION_DROP)) ? 1 : 0);
1105 p->action = 0;
1106
1107 if (alerts == 1 && drops == 6)
1108 result = 1;
1109 else {
1110 if (alerts != 1)
1111 printf("alerts: %d != 1: ", alerts);
1112 if (drops != 6)
1113 printf("drops: %d != 6: ", drops);
1114 goto cleanup;
1115 }
1116
1117cleanup:
1118 DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
1120end:
1121 UTHFreePackets(&p, 1);
1123 return result;
1124}
1125
1126/**
1127 * \test Test drop action being set even if thresholded
1128 */
1129static int DetectThresholdTestSig8(void)
1130{
1131 Packet *p = NULL;
1132 Signature *s = NULL;
1133 ThreadVars th_v;
1134 DetectEngineThreadCtx *det_ctx;
1135 int result = 0;
1136 int alerts = 0;
1137 int drops = 0;
1138
1139 ThresholdInit();
1140
1141 memset(&th_v, 0, sizeof(th_v));
1142
1143 p = UTHBuildPacketReal((uint8_t *)"A", 1, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80);
1144
1146 if (de_ctx == NULL) {
1147 goto end;
1148 }
1149
1150 de_ctx->flags |= DE_QUIET;
1151
1152 s = de_ctx->sig_list = SigInit(de_ctx, "drop tcp any any -> any 80 (threshold: type limit, "
1153 "track by_src, count 2, seconds 300; sid:10;)");
1154 if (s == NULL) {
1155 goto end;
1156 }
1157
1159 DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
1160
1161 p->ts = TimeGet();
1162 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1163 alerts = PacketAlertCheck(p, 10);
1164 drops += ((PacketTestAction(p, ACTION_DROP)) ? 1 : 0);
1165 p->action = 0;
1166
1167 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1168 alerts += PacketAlertCheck(p, 10);
1169 drops += ((PacketTestAction(p, ACTION_DROP)) ? 1 : 0);
1170 p->action = 0;
1171
1172 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1173 alerts += PacketAlertCheck(p, 10);
1174 drops += ((PacketTestAction(p, ACTION_DROP)) ? 1 : 0);
1175 p->action = 0;
1176
1178 p->ts = TimeGet();
1179
1180 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1181 alerts += PacketAlertCheck(p, 10);
1182 drops += ((PacketTestAction(p, ACTION_DROP)) ? 1 : 0);
1183 p->action = 0;
1184
1185 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1186 alerts += PacketAlertCheck(p, 10);
1187 drops += ((PacketTestAction(p, ACTION_DROP)) ? 1 : 0);
1188 p->action = 0;
1189
1190 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1191 alerts += PacketAlertCheck(p, 10);
1192 drops += ((PacketTestAction(p, ACTION_DROP)) ? 1 : 0);
1193 p->action = 0;
1194
1195 if (alerts == 2 && drops == 6)
1196 result = 1;
1197 else {
1198 if (alerts != 1)
1199 printf("alerts: %d != 1: ", alerts);
1200 if (drops != 6)
1201 printf("drops: %d != 6: ", drops);
1202 goto cleanup;
1203 }
1204
1205cleanup:
1206 DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
1208end:
1209 UTHFreePackets(&p, 1);
1211 return result;
1212}
1213
1214/**
1215 * \test Test drop action being set even if thresholded
1216 */
1217static int DetectThresholdTestSig9(void)
1218{
1219 Packet *p = NULL;
1220 Signature *s = NULL;
1221 ThreadVars th_v;
1222 DetectEngineThreadCtx *det_ctx;
1223 int result = 0;
1224 int alerts = 0;
1225 int drops = 0;
1226
1227 ThresholdInit();
1228
1229 memset(&th_v, 0, sizeof(th_v));
1230
1231 p = UTHBuildPacketReal((uint8_t *)"A", 1, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80);
1232
1234 if (de_ctx == NULL) {
1235 goto end;
1236 }
1237
1238 de_ctx->flags |= DE_QUIET;
1239
1240 s = de_ctx->sig_list = SigInit(de_ctx, "drop tcp any any -> any 80 (threshold: type threshold, "
1241 "track by_src, count 3, seconds 100; sid:10;)");
1242 if (s == NULL) {
1243 goto end;
1244 }
1245
1247 DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
1248
1249 p->ts = TimeGet();
1250 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1251 alerts = PacketAlertCheck(p, 10);
1252 drops += ((PacketTestAction(p, ACTION_DROP)) ? 1 : 0);
1253 p->action = 0;
1254
1255 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1256 alerts += PacketAlertCheck(p, 10);
1257 drops += ((PacketTestAction(p, ACTION_DROP)) ? 1 : 0);
1258 p->action = 0;
1259
1260 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1261 alerts += PacketAlertCheck(p, 10);
1262 drops += ((PacketTestAction(p, ACTION_DROP)) ? 1 : 0);
1263 p->action = 0;
1264
1266 p->ts = TimeGet();
1267
1268 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1269 alerts += PacketAlertCheck(p, 10);
1270 drops += ((PacketTestAction(p, ACTION_DROP)) ? 1 : 0);
1271 p->action = 0;
1272
1273 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1274 alerts += PacketAlertCheck(p, 10);
1275 drops += ((PacketTestAction(p, ACTION_DROP)) ? 1 : 0);
1276 p->action = 0;
1277
1278 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1279 alerts += PacketAlertCheck(p, 10);
1280 drops += ((PacketTestAction(p, ACTION_DROP)) ? 1 : 0);
1281 p->action = 0;
1282
1283 if (alerts == 2 && drops == 2)
1284 result = 1;
1285 else {
1286 if (alerts != 2)
1287 printf("alerts: %d != 2: ", alerts);
1288 if (drops != 2)
1289 printf("drops: %d != 2: ", drops);
1290 goto cleanup;
1291 }
1292
1293cleanup:
1294 DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
1296end:
1297 UTHFreePackets(&p, 1);
1299 return result;
1300}
1301
1302/**
1303 * \test Test drop action being set even if thresholded
1304 */
1305static int DetectThresholdTestSig10(void)
1306{
1307 Packet *p = NULL;
1308 Signature *s = NULL;
1309 ThreadVars th_v;
1310 DetectEngineThreadCtx *det_ctx;
1311 int result = 0;
1312 int alerts = 0;
1313 int drops = 0;
1314
1315 ThresholdInit();
1316
1317 memset(&th_v, 0, sizeof(th_v));
1318
1319 p = UTHBuildPacketReal((uint8_t *)"A", 1, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80);
1320
1322 if (de_ctx == NULL) {
1323 goto end;
1324 }
1325
1326 de_ctx->flags |= DE_QUIET;
1327
1328 s = de_ctx->sig_list = SigInit(de_ctx, "drop tcp any any -> any 80 (threshold: type threshold, "
1329 "track by_src, count 5, seconds 300; sid:10;)");
1330 if (s == NULL) {
1331 goto end;
1332 }
1333
1335 DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
1336
1337 p->ts = TimeGet();
1338 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1339 alerts = PacketAlertCheck(p, 10);
1340 drops += ((PacketTestAction(p, ACTION_DROP)) ? 1 : 0);
1341 p->action = 0;
1342
1343 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1344 alerts += PacketAlertCheck(p, 10);
1345 drops += ((PacketTestAction(p, ACTION_DROP)) ? 1 : 0);
1346 p->action = 0;
1347
1348 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1349 alerts += PacketAlertCheck(p, 10);
1350 drops += ((PacketTestAction(p, ACTION_DROP)) ? 1 : 0);
1351 p->action = 0;
1352
1354 p->ts = TimeGet();
1355
1356 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1357 alerts += PacketAlertCheck(p, 10);
1358 drops += ((PacketTestAction(p, ACTION_DROP)) ? 1 : 0);
1359 p->action = 0;
1360
1361 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1362 alerts += PacketAlertCheck(p, 10);
1363 drops += ((PacketTestAction(p, ACTION_DROP)) ? 1 : 0);
1364 p->action = 0;
1365
1366 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1367 alerts += PacketAlertCheck(p, 10);
1368 drops += ((PacketTestAction(p, ACTION_DROP)) ? 1 : 0);
1369 p->action = 0;
1370
1371 if (alerts == 1 && drops == 1)
1372 result = 1;
1373 else {
1374 if (alerts != 1)
1375 printf("alerts: %d != 1: ", alerts);
1376 if (drops != 1)
1377 printf("drops: %d != 1: ", drops);
1378 goto cleanup;
1379 }
1380
1381cleanup:
1382 DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
1384end:
1385 UTHFreePackets(&p, 1);
1387 return result;
1388}
1389
1390/**
1391 * \test Test drop action being set even if thresholded
1392 */
1393static int DetectThresholdTestSig11(void)
1394{
1395 Packet *p = NULL;
1396 Signature *s = NULL;
1397 ThreadVars th_v;
1398 DetectEngineThreadCtx *det_ctx;
1399 int result = 0;
1400 int alerts = 0;
1401 int drops = 0;
1402
1403 ThresholdInit();
1404
1405 memset(&th_v, 0, sizeof(th_v));
1406
1407 p = UTHBuildPacketReal((uint8_t *)"A", 1, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80);
1408
1410 if (de_ctx == NULL) {
1411 goto end;
1412 }
1413
1414 de_ctx->flags |= DE_QUIET;
1415
1416 s = de_ctx->sig_list = SigInit(de_ctx, "drop tcp any any -> any 80 (threshold: type both, "
1417 "track by_src, count 3, seconds 300; sid:10;)");
1418 if (s == NULL) {
1419 goto end;
1420 }
1421
1423 DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
1424
1425 p->ts = TimeGet();
1426 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1427 alerts = PacketAlertCheck(p, 10);
1428 drops += ((PacketTestAction(p, ACTION_DROP)) ? 1 : 0);
1429 p->action = 0;
1430
1431 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1432 alerts += PacketAlertCheck(p, 10);
1433 drops += ((PacketTestAction(p, ACTION_DROP)) ? 1 : 0);
1434 p->action = 0;
1435
1436 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1437 alerts += PacketAlertCheck(p, 10);
1438 drops += ((PacketTestAction(p, ACTION_DROP)) ? 1 : 0);
1439 p->action = 0;
1440
1442 p->ts = TimeGet();
1443
1444 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1445 alerts += PacketAlertCheck(p, 10);
1446 drops += ((PacketTestAction(p, ACTION_DROP)) ? 1 : 0);
1447 p->action = 0;
1448
1449 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1450 alerts += PacketAlertCheck(p, 10);
1451 drops += ((PacketTestAction(p, ACTION_DROP)) ? 1 : 0);
1452 p->action = 0;
1453
1454 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1455 alerts += PacketAlertCheck(p, 10);
1456 drops += ((PacketTestAction(p, ACTION_DROP)) ? 1 : 0);
1457 p->action = 0;
1458
1459 if (alerts == 1 && drops == 4)
1460 result = 1;
1461 else {
1462 if (alerts != 1)
1463 printf("alerts: %d != 1: ", alerts);
1464 if (drops != 4)
1465 printf("drops: %d != 4: ", drops);
1466 goto cleanup;
1467 }
1468
1469cleanup:
1470 DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
1472end:
1473 UTHFreePackets(&p, 1);
1475 return result;
1476}
1477
1478/**
1479 * \test Test drop action being set even if thresholded
1480 */
1481static int DetectThresholdTestSig12(void)
1482{
1483 Packet *p = NULL;
1484 Signature *s = NULL;
1485 ThreadVars th_v;
1486 DetectEngineThreadCtx *det_ctx;
1487 int result = 0;
1488 int alerts = 0;
1489 int drops = 0;
1490
1491 ThresholdInit();
1492
1493 memset(&th_v, 0, sizeof(th_v));
1494
1495 p = UTHBuildPacketReal((uint8_t *)"A", 1, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80);
1496
1498 if (de_ctx == NULL) {
1499 goto end;
1500 }
1501
1502 de_ctx->flags |= DE_QUIET;
1503
1504 s = de_ctx->sig_list = SigInit(de_ctx, "drop tcp any any -> any 80 (threshold: type both, "
1505 "track by_src, count 5, seconds 300; sid:10;)");
1506 if (s == NULL) {
1507 goto end;
1508 }
1509
1511 DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
1512
1513 p->ts = TimeGet();
1514 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1515 alerts = PacketAlertCheck(p, 10);
1516 drops += ((PacketTestAction(p, ACTION_DROP)) ? 1 : 0);
1517 p->action = 0;
1518
1519 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1520 alerts += PacketAlertCheck(p, 10);
1521 drops += ((PacketTestAction(p, ACTION_DROP)) ? 1 : 0);
1522 p->action = 0;
1523
1524 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1525 alerts += PacketAlertCheck(p, 10);
1526 drops += ((PacketTestAction(p, ACTION_DROP)) ? 1 : 0);
1527 p->action = 0;
1528
1530 p->ts = TimeGet();
1531
1532 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1533 alerts += PacketAlertCheck(p, 10);
1534 drops += ((PacketTestAction(p, ACTION_DROP)) ? 1 : 0);
1535 p->action = 0;
1536
1537 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1538 alerts += PacketAlertCheck(p, 10);
1539 drops += ((PacketTestAction(p, ACTION_DROP)) ? 1 : 0);
1540 p->action = 0;
1541
1542 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1543 alerts += PacketAlertCheck(p, 10);
1544 drops += ((PacketTestAction(p, ACTION_DROP)) ? 1 : 0);
1545 p->action = 0;
1546
1547 if (alerts == 1 && drops == 2)
1548 result = 1;
1549 else {
1550 if (alerts != 1)
1551 printf("alerts: %d != 1: ", alerts);
1552 if (drops != 2)
1553 printf("drops: %d != 2: ", drops);
1554 goto cleanup;
1555 }
1556
1557cleanup:
1558 DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
1560end:
1561 UTHFreePackets(&p, 1);
1562 HostShutdown();
1564 return result;
1565}
1566
1567/**
1568 * \test DetectThresholdTestSig13 is a test for checking the working by_rule limits
1569 * by setting up the signature and later testing its working by matching
1570 * received packets against the sig.
1571 *
1572 * \retval 1 on success
1573 * \retval 0 on failure
1574 */
1575
1576static int DetectThresholdTestSig13(void)
1577{
1578 Packet *p = NULL;
1579 Signature *s = NULL;
1580 ThreadVars th_v;
1581 DetectEngineThreadCtx *det_ctx;
1582 int alerts = 0;
1583
1584 ThresholdInit();
1585
1586 memset(&th_v, 0, sizeof(th_v));
1587 p = UTHBuildPacketReal((uint8_t *)"A", 1, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80);
1588 FAIL_IF_NULL(p);
1589
1592
1593 de_ctx->flags |= DE_QUIET;
1594
1595 s = de_ctx->sig_list =
1596 SigInit(de_ctx, "alert tcp any any -> any 80 (msg:\"Threshold limit sid 1\"; "
1597 "threshold: type limit, track by_rule, count 2, seconds 60; sid:1;)");
1598 FAIL_IF_NULL(s);
1599
1601 DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
1602
1603 /* should alert twice */
1604 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1605 alerts += PacketAlertCheck(p, 1);
1606 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1607 alerts += PacketAlertCheck(p, 1);
1608 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1609 alerts += PacketAlertCheck(p, 1);
1610 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1611 alerts += PacketAlertCheck(p, 1);
1612
1613 FAIL_IF(alerts != 2);
1614
1616 p->ts = TimeGet();
1617
1618 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1619 alerts += PacketAlertCheck(p, 1);
1620 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1621 alerts += PacketAlertCheck(p, 1);
1622 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1623 alerts += PacketAlertCheck(p, 1);
1624 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1625 alerts += PacketAlertCheck(p, 1);
1626
1627 FAIL_IF(alerts != 4);
1628
1629 DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
1631 UTHFreePackets(&p, 1);
1633 PASS;
1634}
1635
1636/**
1637 * \test DetectThresholdTestSig14 is a test for checking the working by_both limits
1638 * by setting up the signature and later testing its working by matching
1639 * received packets against the sig.
1640 *
1641 * \retval 1 on success
1642 * \retval 0 on failure
1643 */
1644
1645static int DetectThresholdTestSig14(void)
1646{
1647 Packet *p1 = NULL;
1648 Packet *p2 = NULL;
1649 Signature *s = NULL;
1650 ThreadVars th_v;
1651 DetectEngineThreadCtx *det_ctx;
1652 int alerts1 = 0;
1653 int alerts2 = 0;
1654
1655 ThresholdInit();
1656
1657 memset(&th_v, 0, sizeof(th_v));
1658 p1 = UTHBuildPacketReal((uint8_t *)"A", 1, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80);
1659 p2 = UTHBuildPacketReal((uint8_t *)"A", 1, IPPROTO_TCP, "1.1.1.1", "3.3.3.3", 1024, 80);
1660 FAIL_IF_NULL(p1);
1661 FAIL_IF_NULL(p2);
1662
1665
1666 de_ctx->flags |= DE_QUIET;
1667
1668 s = de_ctx->sig_list =
1669 SigInit(de_ctx, "alert tcp any any -> any 80 (msg:\"Threshold limit sid 1\"; "
1670 "threshold: type limit, track by_both, count 2, seconds 60; sid:1;)");
1671 FAIL_IF_NULL(s);
1672
1674 DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
1675
1676 /* Both p1 and p2 should alert twice */
1677 SigMatchSignatures(&th_v, de_ctx, det_ctx, p1);
1678 alerts1 += PacketAlertCheck(p1, 1);
1679 SigMatchSignatures(&th_v, de_ctx, det_ctx, p1);
1680 alerts1 += PacketAlertCheck(p1, 1);
1681 SigMatchSignatures(&th_v, de_ctx, det_ctx, p1);
1682 alerts1 += PacketAlertCheck(p1, 1);
1683 SigMatchSignatures(&th_v, de_ctx, det_ctx, p1);
1684 alerts1 += PacketAlertCheck(p1, 1);
1685
1686 SigMatchSignatures(&th_v, de_ctx, det_ctx, p2);
1687 alerts2 += PacketAlertCheck(p2, 1);
1688 SigMatchSignatures(&th_v, de_ctx, det_ctx, p2);
1689 alerts2 += PacketAlertCheck(p2, 1);
1690 SigMatchSignatures(&th_v, de_ctx, det_ctx, p2);
1691 alerts2 += PacketAlertCheck(p2, 1);
1692 SigMatchSignatures(&th_v, de_ctx, det_ctx, p2);
1693 alerts2 += PacketAlertCheck(p2, 1);
1694
1695 FAIL_IF(alerts1 != 2);
1696 FAIL_IF(alerts2 != 2);
1697
1699 p1->ts = TimeGet();
1700 p2->ts = TimeGet();
1701
1702 /* Now they should both alert again after previous alerts expire */
1703 SigMatchSignatures(&th_v, de_ctx, det_ctx, p1);
1704 alerts1 += PacketAlertCheck(p1, 1);
1705 SigMatchSignatures(&th_v, de_ctx, det_ctx, p2);
1706 alerts2 += PacketAlertCheck(p2, 1);
1707
1708 FAIL_IF(alerts1 != 3);
1709 FAIL_IF(alerts2 != 3);
1710
1711 DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
1713 UTHFreePackets(&p1, 1);
1714 UTHFreePackets(&p2, 1);
1716 PASS;
1717}
1718
1719static void ThresholdRegisterTests(void)
1720{
1721 UtRegisterTest("ThresholdTestParse01", ThresholdTestParse01);
1722 UtRegisterTest("ThresholdTestParseByFlow01", ThresholdTestParseByFlow01);
1723 UtRegisterTest("ThresholdTestParse02", ThresholdTestParse02);
1724 UtRegisterTest("ThresholdTestParse03", ThresholdTestParse03);
1725 UtRegisterTest("ThresholdTestParse04", ThresholdTestParse04);
1726 UtRegisterTest("ThresholdTestParse05", ThresholdTestParse05);
1727 UtRegisterTest("ThresholdTestParse06", ThresholdTestParse06);
1728 UtRegisterTest("ThresholdTestParse07", ThresholdTestParse07);
1729 UtRegisterTest("ThresholdTestParse08", ThresholdTestParse08);
1730 UtRegisterTest("DetectThresholdTestSig1", DetectThresholdTestSig1);
1731 UtRegisterTest("DetectThresholdTestSig2", DetectThresholdTestSig2);
1732 UtRegisterTest("DetectThresholdTestSig3", DetectThresholdTestSig3);
1733 UtRegisterTest("DetectThresholdTestSig4", DetectThresholdTestSig4);
1734 UtRegisterTest("DetectThresholdTestSig5", DetectThresholdTestSig5);
1735 UtRegisterTest("DetectThresholdTestSig6Ticks", DetectThresholdTestSig6Ticks);
1736 UtRegisterTest("DetectThresholdTestSig7", DetectThresholdTestSig7);
1737 UtRegisterTest("DetectThresholdTestSig8", DetectThresholdTestSig8);
1738 UtRegisterTest("DetectThresholdTestSig9", DetectThresholdTestSig9);
1739 UtRegisterTest("DetectThresholdTestSig10", DetectThresholdTestSig10);
1740 UtRegisterTest("DetectThresholdTestSig11", DetectThresholdTestSig11);
1741 UtRegisterTest("DetectThresholdTestSig12", DetectThresholdTestSig12);
1742 UtRegisterTest("DetectThresholdTestSig13", DetectThresholdTestSig13);
1743 UtRegisterTest("DetectThresholdTestSig14", DetectThresholdTestSig14);
1744}
1745#endif /* UNITTESTS */
1746
1747/**
1748 * @}
1749 */
#define ACTION_DROP
#define TRACK_SRC
#define TRACK_DST
void DetectAddressHeadCleanup(DetectAddressHead *gh)
Cleans a DetectAddressHead. The functions frees the address group heads(ipv4 and ipv6) inside the Det...
DetectAddress * DetectAddressCopy(DetectAddress *orig)
copy a DetectAddress
int PacketAlertCheck(Packet *p, uint32_t sid)
Check if a certain sid alerted, this is used in the test functions.
int SigGroupBuild(DetectEngineCtx *de_ctx)
Convert the signature list into the runtime match structure.
void SigCleanSignatures(DetectEngineCtx *de_ctx)
int SigGroupCleanup(DetectEngineCtx *de_ctx)
@ DETECT_THRESHOLD
@ DETECT_DETECTION_FILTER
DetectEngineCtx * DetectEngineCtxInit(void)
void DetectEngineCtxFree(DetectEngineCtx *)
Free a DetectEngineCtx::
Signature * DetectEngineAppendSig(DetectEngineCtx *, const char *)
Parse and append a Signature into the Detection Engine Context signature list.
TmEcode DetectEngineThreadCtxInit(ThreadVars *tv, void *initdata, void **data)
initialize thread specific detection engine context
TmEcode DetectEngineThreadCtxDeinit(ThreadVars *tv, void *data)
void DetectSetupParseRegexes(const char *parse_str, DetectParseRegex *detect_parse)
int DetectParsePcreExec(DetectParseRegex *parse_regex, pcre2_match_data **match, const char *str, int start_offset, int options)
Signature * SigInit(DetectEngineCtx *de_ctx, const char *sigstr)
Parses a signature and adds it to the Detection Engine Context.
SigMatch * SCSigMatchAppendSMToList(DetectEngineCtx *de_ctx, Signature *s, uint16_t type, SigMatchCtx *ctx, const int list)
Append a SigMatch to the list type.
SigMatch * DetectGetLastSMFromLists(const Signature *s,...)
Returns the sm with the largest index (added latest) from the lists passed to us.
SigTableElmt * sigmatch_table
DetectThresholdData * DetectThresholdDataCopy(DetectThresholdData *de)
Make a deep-copy of an extant DetectTHresholdData object.
void DetectThresholdRegister(void)
Registration function for threshold: keyword.
#define PARSE_REGEX
#define TYPE_BOTH
#define TYPE_LIMIT
#define TRACK_RULE
#define TRACK_FLOW
#define TRACK_BOTH
#define TYPE_BACKOFF
#define TYPE_THRESHOLD
void SigMatchSignatures(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Packet *p)
wrapper for old tests
Definition detect.c:2420
#define SIGMATCH_IPONLY_COMPAT
Definition detect.h:1653
#define DE_QUIET
Definition detect.h:330
@ SIG_TYPE_IPONLY
Definition detect.h:66
@ DETECT_SM_LIST_THRESHOLD
Definition detect.h:133
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.
#define FAIL_IF(expr)
Fail a test if expression evaluates to true.
void ThresholdInit(void)
void ThresholdDestroy(void)
struct Thresholds ctx
void HostShutdown(void)
shutdown the flow engine
Definition host.c:296
DetectAddress * ipv6_head
Definition detect.h:185
DetectAddress * ipv4_head
Definition detect.h:184
address structure for use in the detection engine.
Definition detect.h:168
struct DetectAddress_ * next
Definition detect.h:179
struct DetectAddress_ * prev
Definition detect.h:177
main detection engine ctx
Definition detect.h:932
uint8_t flags
Definition detect.h:934
Signature * sig_list
Definition detect.h:941
DetectAddressHead addrs
SCTime_t ts
Definition decode.h:555
uint8_t action
Definition decode.h:609
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
const char * url
Definition detect.h:1462
int(* Setup)(DetectEngineCtx *, Signature *, const char *)
Definition detect.h:1441
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 * name
Definition detect.h:1459
Signature container.
Definition detect.h:668
enum SignatureType type
Definition detect.h:671
struct Signature_ * next
Definition detect.h:750
Per thread variable structure.
Definition threadvars.h:58
int StringParseUint32(uint32_t *res, int base, size_t len, const char *str)
Definition util-byte.c:313
uint64_t UtilCpuGetTicks(void)
Definition util-cpu.c:161
#define SCLogDebug(...)
Definition util-debug.h:275
#define SCReturnInt(x)
Definition util-debug.h:281
#define SCLogError(...)
Macro used to log ERROR messages.
Definition util-debug.h:267
#define SCFree(p)
Definition util-mem.h:61
#define SCCalloc(nm, sz)
Definition util-mem.h:53
#define SCStrdup(s)
Definition util-mem.h:56
#define unlikely(expr)
SCTime_t TimeGet(void)
Definition util-time.c:152
void TimeSetIncrementTime(uint32_t tv_sec)
increment the time in the engine
Definition util-time.c:180
void UTHFreePackets(Packet **p, int numpkts)
UTHFreePackets: function to release the allocated data from UTHBuildPacket and the packet itself.
Packet * UTHBuildPacketReal(uint8_t *payload, uint16_t payload_len, uint8_t ipproto, const char *src, const char *dst, uint16_t sport, uint16_t dport)
UTHBuildPacketReal is a function that create tcp/udp packets for unittests specifying ip and port sou...