suricata
util-threshold-config.c
Go to the documentation of this file.
1/* Copyright (C) 2007-2023 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 Pinto <breno.silva@gmail.com>
27 *
28 * Implements Threshold support
29 */
30
31#include "suricata-common.h"
32
33#include "action-globals.h"
34#include "host.h"
35#include "ippair.h"
36
37#include "detect.h"
38#include "detect-engine.h"
41#include "detect-threshold.h"
42#include "detect-parse.h"
43#include "detect-engine-build.h"
44
45#include "conf.h"
47#include "util-unittest.h"
49#include "util-byte.h"
50#include "util-time.h"
51#include "util-debug.h"
52#include "util-fmemopen.h"
53
60
61#ifdef UNITTESTS
62/* File descriptor for unittests */
63static FILE *g_ut_threshold_fp = NULL;
64#endif
65
66/* common base for all options */
67#define DETECT_BASE_REGEX "^\\s*(event_filter|threshold|rate_filter|suppress)\\s*gen_id\\s*(\\d+)\\s*,\\s*sig_id\\s*(\\d+)\\s*(.*)\\s*$"
68
69#define DETECT_THRESHOLD_REGEX \
70 "^,\\s*type\\s*(limit|both|threshold)\\s*,\\s*track\\s*(by_dst|by_src|by_both|by_rule|by_" \
71 "flow)\\s*," \
72 "\\s*count\\s*(\\d+)\\s*,\\s*seconds\\s*(\\d+)\\s*$"
73
74/* TODO: "apply_to" */
75#define DETECT_RATE_REGEX \
76 "^,\\s*track\\s*(by_dst|by_src|by_both|by_rule|by_flow)\\s*,\\s*count\\s*(\\d+)\\s*,\\s*" \
77 "seconds\\s*(\\d+)\\s*,\\s*new_action\\s*(alert|drop|pass|log|sdrop|reject)\\s*,\\s*" \
78 "timeout\\s*(\\d+)\\s*$"
79
80/*
81 * suppress has two form:
82 * suppress gen_id 0, sig_id 0, track by_dst, ip 10.88.0.14
83 * suppress gen_id 1, sig_id 2000328
84 * suppress gen_id 1, sig_id 2000328, track by_src, ip fe80::/10
85*/
86#define DETECT_SUPPRESS_REGEX "^,\\s*track\\s*(by_dst|by_src|by_either)\\s*,\\s*ip\\s*([\\[\\],\\$\\s\\da-zA-Z.:/_]+)*\\s*$"
87
88/* Default path for the threshold.config file */
89#if defined OS_WIN32 || defined __CYGWIN__
90#define THRESHOLD_CONF_DEF_CONF_FILEPATH CONFIG_DIR "\\\\threshold.config"
91#else
92#define THRESHOLD_CONF_DEF_CONF_FILEPATH CONFIG_DIR "/threshold.config"
93#endif
94
95static DetectParseRegex *regex_base = NULL;
96static DetectParseRegex *regex_threshold = NULL;
97static DetectParseRegex *regex_rate = NULL;
98static DetectParseRegex *regex_suppress = NULL;
99
100static void SCThresholdConfDeInitContext(DetectEngineCtx *de_ctx, FILE *fd);
101
103{
104 regex_base = DetectSetupPCRE2(DETECT_BASE_REGEX, 0);
105 if (regex_base == NULL) {
106 FatalError("classification base regex setup failed");
107 }
108 regex_threshold = DetectSetupPCRE2(DETECT_THRESHOLD_REGEX, 0);
109 if (regex_threshold == NULL) {
110 FatalError("classification threshold regex setup failed");
111 }
112 regex_rate = DetectSetupPCRE2(DETECT_RATE_REGEX, 0);
113 if (regex_rate == NULL) {
114 FatalError("classification rate_filter regex setup failed");
115 }
116 regex_suppress = DetectSetupPCRE2(DETECT_SUPPRESS_REGEX, 0);
117 if (regex_suppress == NULL) {
118 FatalError("classification suppress regex setup failed");
119 }
120}
121
122/**
123 * \brief Returns the path for the Threshold Config file. We check if we
124 * can retrieve the path from the yaml conf file. If it is not present,
125 * return the default path for the threshold file which is
126 * "./threshold.config".
127 *
128 * \retval log_filename Pointer to a string containing the path for the
129 * Threshold Config file.
130 */
131static const char *SCThresholdConfGetConfFilename(const DetectEngineCtx *de_ctx)
132{
133 const char *log_filename = NULL;
134
135 if (de_ctx != NULL && strlen(de_ctx->config_prefix) > 0) {
136 char config_value[256];
137 snprintf(config_value, sizeof(config_value),
138 "%s.threshold-file", de_ctx->config_prefix);
139
140 /* try loading prefix setting, fall back to global if that
141 * fails. */
142 if (SCConfGet(config_value, &log_filename) != 1) {
143 if (SCConfGet("threshold-file", &log_filename) != 1) {
144 log_filename = (char *)THRESHOLD_CONF_DEF_CONF_FILEPATH;
145 }
146 }
147 } else {
148 if (SCConfGet("threshold-file", &log_filename) != 1) {
149 log_filename = (char *)THRESHOLD_CONF_DEF_CONF_FILEPATH;
150 }
151 }
152 return log_filename;
153}
154
155/**
156 * \brief Inits the context to be used by the Threshold Config parsing API.
157 *
158 * This function initializes the hash table to be used by the Detection
159 * Engine Context to hold the data from the threshold.config file,
160 * obtains the file desc to parse the threshold.config file, and
161 * inits the regex used to parse the lines from threshold.config
162 * file.
163 *
164 * \param de_ctx Pointer to the Detection Engine Context.
165 *
166 * \retval 0 On success.
167 * \retval -1 On failure.
168 */
170{
171 const char *filename = NULL;
172 int ret = 0;
173#ifndef UNITTESTS
174 FILE *fd = NULL;
175#else
176 FILE *fd = g_ut_threshold_fp;
177 if (fd == NULL) {
178#endif
179 filename = SCThresholdConfGetConfFilename(de_ctx);
180 if ( (fd = fopen(filename, "r")) == NULL) {
181 SCLogWarning("Error opening file: \"%s\": %s", filename, strerror(errno));
182 SCThresholdConfDeInitContext(de_ctx, fd);
183 return 0;
184 }
185#ifdef UNITTESTS
186 }
187#endif
188
189 if (SCThresholdConfParseFile(de_ctx, fd) < 0) {
190 SCLogWarning("Error loading threshold configuration from %s", filename);
191 SCThresholdConfDeInitContext(de_ctx, fd);
192 /* maintain legacy behavior so no errors unless config testing */
194 ret = -1;
195 }
196 return ret;
197 }
198 SCThresholdConfDeInitContext(de_ctx, fd);
199
200#ifdef UNITTESTS
201 g_ut_threshold_fp = NULL;
202#endif
203 SCLogDebug("Global thresholding options defined");
204 return 0;
205}
206
207/**
208 * \brief Releases resources used by the Threshold Config API.
209 *
210 * \param de_ctx Pointer to the Detection Engine Context.
211 * \param fd Pointer to file descriptor.
212 */
213static void SCThresholdConfDeInitContext(DetectEngineCtx *de_ctx, FILE *fd)
214{
215 if (fd != NULL)
216 fclose(fd);
217}
218
219/** \internal
220 * \brief setup suppress rules
221 * \retval 0 ok
222 * \retval -1 error
223 */
224static int SetupSuppressRule(DetectEngineCtx *de_ctx, uint32_t id, uint32_t gid,
225 uint8_t parsed_type, uint8_t parsed_track, uint32_t parsed_count,
226 uint32_t parsed_seconds, uint32_t parsed_timeout, uint8_t parsed_new_action,
227 const char *th_ip)
228{
229 Signature *s = NULL;
230 DetectThresholdData *de = NULL;
231
232 BUG_ON(parsed_type != TYPE_SUPPRESS);
233
234 DetectThresholdData *orig_de = NULL;
235 if (parsed_track != TRACK_RULE) {
236 orig_de = SCCalloc(1, sizeof(DetectThresholdData));
237 if (unlikely(orig_de == NULL))
238 goto error;
239
240 orig_de->type = TYPE_SUPPRESS;
241 orig_de->track = parsed_track;
242 orig_de->count = parsed_count;
243 orig_de->seconds = parsed_seconds;
244 orig_de->new_action = parsed_new_action;
245 orig_de->timeout = parsed_timeout;
246 if (DetectAddressParse((const DetectEngineCtx *)de_ctx, &orig_de->addrs, (char *)th_ip) <
247 0) {
248 SCLogError("failed to parse %s", th_ip);
249 goto error;
250 }
251 }
252
253 /* Install it */
254 if (id == 0 && gid == 0) {
255 if (parsed_track == TRACK_RULE) {
256 SCLogWarning("suppressing all rules");
257 }
258
259 /* update each sig with our suppress info */
260 for (s = de_ctx->sig_list; s != NULL; s = s->next) {
261 /* tag the rule as noalert */
262 if (parsed_track == TRACK_RULE) {
263 s->action &= ~ACTION_ALERT;
264 continue;
265 }
266
267 de = DetectThresholdDataCopy(orig_de);
268 if (unlikely(de == NULL))
269 goto error;
270
272 DETECT_SM_LIST_SUPPRESS) == NULL) {
273 goto error;
274 }
275 }
276 } else if (id == 0 && gid > 0) {
277 if (parsed_track == TRACK_RULE) {
278 SCLogWarning("suppressing all rules with gid %" PRIu32, gid);
279 }
280 /* set up suppression for each signature with a matching gid */
281 for (s = de_ctx->sig_list; s != NULL; s = s->next) {
282 if (s->gid != gid)
283 continue;
284
285 /* tag the rule as noalert */
286 if (parsed_track == TRACK_RULE) {
287 s->action &= ~ACTION_ALERT;
288 continue;
289 }
290
291 de = DetectThresholdDataCopy(orig_de);
292 if (unlikely(de == NULL))
293 goto error;
294
296 DETECT_SM_LIST_SUPPRESS) == NULL) {
297 goto error;
298 }
299 }
300 } else if (id > 0 && gid == 0) {
301 SCLogError("Can't use a event config that has "
302 "sid > 0 and gid == 0. Please fix this "
303 "in your threshold.config file");
304 goto error;
305 } else {
306 s = SigFindSignatureBySidGid(de_ctx, id, gid);
307 if (s == NULL) {
308 SCLogWarning("can't suppress sid "
309 "%" PRIu32 ", gid %" PRIu32 ": unknown rule",
310 id, gid);
311 } else {
312 if (parsed_track == TRACK_RULE) {
313 s->action &= ~ACTION_ALERT;
314 goto end;
315 }
316
317 de = DetectThresholdDataCopy(orig_de);
318 if (unlikely(de == NULL))
319 goto error;
320
322 DETECT_SM_LIST_SUPPRESS) == NULL) {
323 goto error;
324 }
325 }
326 }
327
328end:
329 if (orig_de != NULL) {
331 SCFree(orig_de);
332 }
333 return 0;
334error:
335 if (orig_de != NULL) {
337 SCFree(orig_de);
338 }
339 if (de != NULL) {
341 SCFree(de);
342 }
343 return -1;
344}
345
346/** \internal
347 * \brief setup suppress rules
348 * \retval 0 ok
349 * \retval -1 error
350 */
351static int SetupThresholdRule(DetectEngineCtx *de_ctx, uint32_t id, uint32_t gid,
352 uint8_t parsed_type, uint8_t parsed_track, uint32_t parsed_count, uint32_t parsed_seconds,
353 uint32_t parsed_timeout, uint8_t parsed_new_action)
354{
355 Signature *s = NULL;
356 SigMatch *sm = NULL;
357 DetectThresholdData *de = NULL;
358
359 BUG_ON(parsed_type == TYPE_SUPPRESS);
360
361 /* Install it */
362 if (id == 0 && gid == 0) {
363 for (s = de_ctx->sig_list; s != NULL; s = s->next) {
365 if (sm != NULL) {
366 SCLogWarning("signature sid:%" PRIu32 " has "
367 "an event var set. The signature event var is "
368 "given precedence over the threshold.conf one. "
369 "We'll change this in the future though.",
370 s->id);
371 continue;
372 }
373
376 if (sm != NULL) {
377 SCLogWarning("signature sid:%" PRIu32 " has "
378 "an event var set. The signature event var is "
379 "given precedence over the threshold.conf one. "
380 "We'll change this in the future though.",
381 s->id);
382 continue;
383 }
384
385 de = SCCalloc(1, sizeof(DetectThresholdData));
386 if (unlikely(de == NULL))
387 goto error;
388
389 de->type = parsed_type;
390 de->track = parsed_track;
391 de->count = parsed_count;
392 de->seconds = parsed_seconds;
393 de->new_action = parsed_new_action;
394 de->timeout = parsed_timeout;
395
396 uint16_t smtype = DETECT_THRESHOLD;
397 if (parsed_type == TYPE_RATE)
399
401 de_ctx, s, smtype, (SigMatchCtx *)de, DETECT_SM_LIST_THRESHOLD) == NULL) {
402 goto error;
403 }
404 }
405
406 } else if (id == 0 && gid > 0) {
407 for (s = de_ctx->sig_list; s != NULL; s = s->next) {
408 if (s->gid == gid) {
411 if (sm != NULL) {
412 SCLogWarning("signature sid:%" PRIu32 " has "
413 "an event var set. The signature event var is "
414 "given precedence over the threshold.conf one. "
415 "We'll change this in the future though.",
416 id);
417 continue;
418 }
419
420 de = SCCalloc(1, sizeof(DetectThresholdData));
421 if (unlikely(de == NULL))
422 goto error;
423
424 de->type = parsed_type;
425 de->track = parsed_track;
426 de->count = parsed_count;
427 de->seconds = parsed_seconds;
428 de->new_action = parsed_new_action;
429 de->timeout = parsed_timeout;
430
431 uint16_t smtype = DETECT_THRESHOLD;
432 if (parsed_type == TYPE_RATE)
434
435 if (SCSigMatchAppendSMToList(de_ctx, s, smtype, (SigMatchCtx *)de,
436 DETECT_SM_LIST_THRESHOLD) == NULL) {
437 goto error;
438 }
439 }
440 }
441 } else if (id > 0 && gid == 0) {
442 SCLogError("Can't use a event config that has "
443 "sid > 0 and gid == 0. Please fix this "
444 "in your threshold.conf file");
445 } else {
446 s = SigFindSignatureBySidGid(de_ctx, id, gid);
447 if (s == NULL) {
448 SCLogWarning("can't suppress sid "
449 "%" PRIu32 ", gid %" PRIu32 ": unknown rule",
450 id, gid);
451 } else {
452 if (parsed_type != TYPE_SUPPRESS && parsed_type != TYPE_THRESHOLD &&
453 parsed_type != TYPE_BOTH && parsed_type != TYPE_LIMIT)
454 {
457 if (sm != NULL) {
458 SCLogWarning("signature sid:%" PRIu32 " has "
459 "a threshold set. The signature event var is "
460 "given precedence over the threshold.conf one. "
461 "Bug #425.",
462 s->id);
463 goto end;
464 }
465
468 if (sm != NULL) {
469 SCLogWarning("signature sid:%" PRIu32 " has "
470 "a detection_filter set. The signature event var is "
471 "given precedence over the threshold.conf one. "
472 "Bug #425.",
473 s->id);
474 goto end;
475 }
476
477 /* replace threshold on sig if we have a global override for it */
478 } else if (parsed_type == TYPE_THRESHOLD || parsed_type == TYPE_BOTH || parsed_type == TYPE_LIMIT) {
481 if (sm != NULL) {
483 SigMatchFree(de_ctx, sm);
484 }
485 }
486
487 de = SCCalloc(1, sizeof(DetectThresholdData));
488 if (unlikely(de == NULL))
489 goto error;
490
491 de->type = parsed_type;
492 de->track = parsed_track;
493 de->count = parsed_count;
494 de->seconds = parsed_seconds;
495 de->new_action = parsed_new_action;
496 de->timeout = parsed_timeout;
497
498 uint16_t smtype = DETECT_THRESHOLD;
499 if (parsed_type == TYPE_RATE)
501
503 de_ctx, s, smtype, (SigMatchCtx *)de, DETECT_SM_LIST_THRESHOLD) == NULL) {
504 goto error;
505 }
506 }
507 }
508end:
509 return 0;
510error:
511 if (de != NULL) {
513 SCFree(de);
514 }
515 return -1;
516}
517
518static int ParseThresholdRule(const DetectEngineCtx *de_ctx, char *rawstr, uint32_t *ret_id,
519 uint32_t *ret_gid, uint8_t *ret_parsed_type, uint8_t *ret_parsed_track,
520 uint32_t *ret_parsed_count, uint32_t *ret_parsed_seconds, uint32_t *ret_parsed_timeout,
521 uint8_t *ret_parsed_new_action, char **ret_th_ip)
522{
523 char th_rule_type[32];
524 char th_gid[16];
525 char th_sid[16];
526 const char *rule_extend = NULL;
527 char th_type[16] = "";
528 char th_track[16] = "";
529 char th_count[16] = "";
530 char th_seconds[16] = "";
531 char th_new_action[16] = "";
532 char th_timeout[16] = "";
533 const char *th_ip = NULL;
534
535 uint8_t parsed_type = 0;
536 uint8_t parsed_track = 0;
537 uint8_t parsed_new_action = 0;
538 uint32_t parsed_count = 0;
539 uint32_t parsed_seconds = 0;
540 uint32_t parsed_timeout = 0;
541
542 int ret = 0;
543 uint32_t id = 0, gid = 0;
544 ThresholdRuleType rule_type;
545
546 if (de_ctx == NULL)
547 return -1;
548
549 pcre2_match_data *regex_base_match = NULL;
550 ret = DetectParsePcreExec(regex_base, &regex_base_match, rawstr, 0, 0);
551 if (ret < 4) {
552 SCLogError("pcre2_match parse error, ret %" PRId32 ", string %s", ret, rawstr);
553 pcre2_match_data_free(regex_base_match);
554 goto error;
555 }
556
557 /* retrieve the classtype name */
558 size_t copylen = sizeof(th_rule_type);
559 ret = pcre2_substring_copy_bynumber(
560 regex_base_match, 1, (PCRE2_UCHAR8 *)th_rule_type, &copylen);
561 if (ret < 0) {
562 SCLogError("pcre2_substring_copy_bynumber failed");
563 pcre2_match_data_free(regex_base_match);
564 goto error;
565 }
566
567 /* retrieve the classtype name */
568 copylen = sizeof(th_gid);
569 ret = pcre2_substring_copy_bynumber(regex_base_match, 2, (PCRE2_UCHAR8 *)th_gid, &copylen);
570 if (ret < 0) {
571 SCLogError("pcre2_substring_copy_bynumber failed");
572 pcre2_match_data_free(regex_base_match);
573 goto error;
574 }
575
576 copylen = sizeof(th_sid);
577 ret = pcre2_substring_copy_bynumber(regex_base_match, 3, (PCRE2_UCHAR8 *)th_sid, &copylen);
578 if (ret < 0) {
579 SCLogError("pcre2_substring_copy_bynumber failed");
580 pcre2_match_data_free(regex_base_match);
581 goto error;
582 }
583
584 /* Use "get" for heap allocation */
585 ret = pcre2_substring_get_bynumber(
586 regex_base_match, 4, (PCRE2_UCHAR8 **)&rule_extend, &copylen);
587 if (ret < 0) {
588 SCLogError("pcre2_substring_get_bynumber failed");
589 pcre2_match_data_free(regex_base_match);
590 goto error;
591 }
592 pcre2_match_data_free(regex_base_match);
593 regex_base_match = NULL;
594
595 /* get type of rule */
596 if (strcasecmp(th_rule_type,"event_filter") == 0) {
597 rule_type = THRESHOLD_TYPE_EVENT_FILTER;
598 } else if (strcasecmp(th_rule_type,"threshold") == 0) {
599 rule_type = THRESHOLD_TYPE_THRESHOLD;
600 } else if (strcasecmp(th_rule_type,"rate_filter") == 0) {
601 rule_type = THRESHOLD_TYPE_RATE;
602 } else if (strcasecmp(th_rule_type,"suppress") == 0) {
603 rule_type = THRESHOLD_TYPE_SUPPRESS;
604 } else {
605 SCLogError("rule type %s is unknown", th_rule_type);
606 goto error;
607 }
608
609 /* get end of rule */
610 switch(rule_type) {
613 if (strlen(rule_extend) > 0) {
614 pcre2_match_data *match = NULL;
615
616 ret = DetectParsePcreExec(regex_threshold, &match, rule_extend, 0, 0);
617 if (ret < 4) {
618 SCLogError("pcre2_match parse error, ret %" PRId32 ", string %s", ret,
619 rule_extend);
620 pcre2_match_data_free(match);
621 goto error;
622 }
623
624 copylen = sizeof(th_type);
625 ret = pcre2_substring_copy_bynumber(match, 1, (PCRE2_UCHAR8 *)th_type, &copylen);
626 if (ret < 0) {
627 SCLogError("pcre2_substring_copy_bynumber failed");
628 pcre2_match_data_free(match);
629 goto error;
630 }
631
632 copylen = sizeof(th_track);
633 ret = pcre2_substring_copy_bynumber(match, 2, (PCRE2_UCHAR8 *)th_track, &copylen);
634 if (ret < 0) {
635 SCLogError("pcre2_substring_copy_bynumber failed");
636 pcre2_match_data_free(match);
637 goto error;
638 }
639
640 copylen = sizeof(th_count);
641 ret = pcre2_substring_copy_bynumber(match, 3, (PCRE2_UCHAR8 *)th_count, &copylen);
642 if (ret < 0) {
643 SCLogError("pcre2_substring_copy_bynumber failed");
644 pcre2_match_data_free(match);
645 goto error;
646 }
647
648 copylen = sizeof(th_seconds);
649 ret = pcre2_substring_copy_bynumber(match, 4, (PCRE2_UCHAR8 *)th_seconds, &copylen);
650 if (ret < 0) {
651 SCLogError("pcre2_substring_copy_bynumber failed");
652 pcre2_match_data_free(match);
653 goto error;
654 }
655 pcre2_match_data_free(match);
656
657 if (strcasecmp(th_type,"limit") == 0)
658 parsed_type = TYPE_LIMIT;
659 else if (strcasecmp(th_type,"both") == 0)
660 parsed_type = TYPE_BOTH;
661 else if (strcasecmp(th_type,"threshold") == 0)
662 parsed_type = TYPE_THRESHOLD;
663 else {
664 SCLogError("limit type not supported: %s", th_type);
665 goto error;
666 }
667 } else {
668 SCLogError("rule invalid: %s", rawstr);
669 goto error;
670 }
671 break;
673 if (strlen(rule_extend) > 0) {
674 pcre2_match_data *match = NULL;
675 ret = DetectParsePcreExec(regex_suppress, &match, rule_extend, 0, 0);
676 if (ret < 2) {
677 SCLogError("pcre2_match parse error, ret %" PRId32 ", string %s", ret,
678 rule_extend);
679 pcre2_match_data_free(match);
680 goto error;
681 }
682 /* retrieve the track mode */
683 copylen = sizeof(th_seconds);
684 ret = pcre2_substring_copy_bynumber(match, 1, (PCRE2_UCHAR8 *)th_track, &copylen);
685 if (ret < 0) {
686 SCLogError("pcre2_substring_copy_bynumber failed");
687 pcre2_match_data_free(match);
688 goto error;
689 }
690 /* retrieve the IP; use "get" for heap allocation */
691 ret = pcre2_substring_get_bynumber(match, 2, (PCRE2_UCHAR8 **)&th_ip, &copylen);
692 if (ret < 0) {
693 SCLogError("pcre2_substring_get_bynumber failed");
694 pcre2_match_data_free(match);
695 goto error;
696 }
697 pcre2_match_data_free(match);
698 } else {
699 parsed_track = TRACK_RULE;
700 }
701 parsed_type = TYPE_SUPPRESS;
702 break;
704 if (strlen(rule_extend) > 0) {
705 pcre2_match_data *match = NULL;
706 ret = DetectParsePcreExec(regex_rate, &match, rule_extend, 0, 0);
707 if (ret < 5) {
708 SCLogError("pcre2_match parse error, ret %" PRId32 ", string %s", ret,
709 rule_extend);
710 pcre2_match_data_free(match);
711 goto error;
712 }
713
714 copylen = sizeof(th_track);
715 ret = pcre2_substring_copy_bynumber(match, 1, (PCRE2_UCHAR8 *)th_track, &copylen);
716 if (ret < 0) {
717 SCLogError("pcre2_substring_copy_bynumber failed");
718 pcre2_match_data_free(match);
719 goto error;
720 }
721
722 copylen = sizeof(th_count);
723 ret = pcre2_substring_copy_bynumber(match, 2, (PCRE2_UCHAR8 *)th_count, &copylen);
724 if (ret < 0) {
725 SCLogError("pcre2_substring_copy_bynumber failed");
726 pcre2_match_data_free(match);
727 goto error;
728 }
729
730 copylen = sizeof(th_seconds);
731 ret = pcre2_substring_copy_bynumber(match, 3, (PCRE2_UCHAR8 *)th_seconds, &copylen);
732 if (ret < 0) {
733 SCLogError("pcre2_substring_copy_bynumber failed");
734 pcre2_match_data_free(match);
735 goto error;
736 }
737
738 copylen = sizeof(th_new_action);
739 ret = pcre2_substring_copy_bynumber(
740 match, 4, (PCRE2_UCHAR8 *)th_new_action, &copylen);
741 if (ret < 0) {
742 SCLogError("pcre2_substring_copy_bynumber failed");
743 pcre2_match_data_free(match);
744 goto error;
745 }
746
747 copylen = sizeof(th_timeout);
748 ret = pcre2_substring_copy_bynumber(match, 5, (PCRE2_UCHAR8 *)th_timeout, &copylen);
749 if (ret < 0) {
750 SCLogError("pcre2_substring_copy_bynumber failed");
751 pcre2_match_data_free(match);
752 goto error;
753 }
754 pcre2_match_data_free(match);
755
756 /* TODO: implement option "apply_to" */
757
758 if (StringParseUint32(&parsed_timeout, 10, sizeof(th_timeout), th_timeout) <= 0) {
759 goto error;
760 }
761
762 /* Get the new action to take */
763 if (strcasecmp(th_new_action, "alert") == 0)
764 parsed_new_action = TH_ACTION_ALERT;
765 if (strcasecmp(th_new_action, "drop") == 0)
766 parsed_new_action = TH_ACTION_DROP;
767 if (strcasecmp(th_new_action, "pass") == 0)
768 parsed_new_action = TH_ACTION_PASS;
769 if (strcasecmp(th_new_action, "reject") == 0)
770 parsed_new_action = TH_ACTION_REJECT;
771 if (strcasecmp(th_new_action, "log") == 0) {
772 SCLogInfo("log action for rate_filter not supported yet");
773 parsed_new_action = TH_ACTION_LOG;
774 }
775 if (strcasecmp(th_new_action, "sdrop") == 0) {
776 SCLogInfo("sdrop action for rate_filter not supported yet");
777 parsed_new_action = TH_ACTION_SDROP;
778 }
779 parsed_type = TYPE_RATE;
780 } else {
781 SCLogError("rule invalid: %s", rawstr);
782 goto error;
783 }
784 break;
785 }
786
787 switch (rule_type) {
788 /* This part is common to threshold/event_filter/rate_filter */
792 if (strcasecmp(th_track,"by_dst") == 0)
793 parsed_track = TRACK_DST;
794 else if (strcasecmp(th_track,"by_src") == 0)
795 parsed_track = TRACK_SRC;
796 else if (strcasecmp(th_track, "by_both") == 0) {
797 parsed_track = TRACK_BOTH;
798 }
799 else if (strcasecmp(th_track,"by_rule") == 0)
800 parsed_track = TRACK_RULE;
801 else if (strcasecmp(th_track, "by_flow") == 0)
802 parsed_track = TRACK_FLOW;
803 else {
804 SCLogError("Invalid track parameter %s in %s", th_track, rawstr);
805 goto error;
806 }
807
808 if (StringParseUint32(&parsed_count, 10, sizeof(th_count), th_count) <= 0) {
809 goto error;
810 }
811 if (parsed_count == 0) {
812 SCLogError("rate filter count should be > 0");
813 goto error;
814 }
815
816 if (StringParseUint32(&parsed_seconds, 10, sizeof(th_seconds), th_seconds) <= 0) {
817 goto error;
818 }
819
820 break;
822 /* need to get IP if extension is provided */
823 if (strcmp("", th_track) != 0) {
824 if (strcasecmp(th_track,"by_dst") == 0)
825 parsed_track = TRACK_DST;
826 else if (strcasecmp(th_track,"by_src") == 0)
827 parsed_track = TRACK_SRC;
828 else if (strcasecmp(th_track,"by_either") == 0) {
829 parsed_track = TRACK_EITHER;
830 }
831 else {
832 SCLogError("Invalid track parameter %s in %s", th_track, rule_extend);
833 goto error;
834 }
835 }
836 break;
837 }
838
839 if (StringParseUint32(&id, 10, sizeof(th_sid), th_sid) <= 0) {
840 goto error;
841 }
842
843 if (StringParseUint32(&gid, 10, sizeof(th_gid), th_gid) <= 0) {
844 goto error;
845 }
846
847 *ret_id = id;
848 *ret_gid = gid;
849 *ret_parsed_type = parsed_type;
850 *ret_parsed_track = parsed_track;
851 *ret_parsed_new_action = parsed_new_action;
852 *ret_parsed_count = parsed_count;
853 *ret_parsed_seconds = parsed_seconds;
854 *ret_parsed_timeout = parsed_timeout;
855 *ret_th_ip = NULL;
856 if (th_ip != NULL) {
857 *ret_th_ip = (char *)th_ip;
858 }
859 pcre2_substring_free((PCRE2_UCHAR8 *)rule_extend);
860 return 0;
861
862error:
863 if (rule_extend != NULL) {
864 pcre2_substring_free((PCRE2_UCHAR8 *)rule_extend);
865 }
866 if (th_ip != NULL) {
867 pcre2_substring_free((PCRE2_UCHAR8 *)th_ip);
868 }
869 return -1;
870}
871
872/**
873 * \brief Parses a line from the threshold file and applies it to the
874 * detection engine
875 *
876 * \param rawstr Pointer to the string to be parsed.
877 * \param de_ctx Pointer to the Detection Engine Context.
878 *
879 * \retval 0 On success.
880 * \retval -1 On failure.
881 */
882static int SCThresholdConfAddThresholdtype(char *rawstr, DetectEngineCtx *de_ctx)
883{
884 uint8_t parsed_type = 0;
885 uint8_t parsed_track = 0;
886 uint8_t parsed_new_action = 0;
887 uint32_t parsed_count = 0;
888 uint32_t parsed_seconds = 0;
889 uint32_t parsed_timeout = 0;
890 char *th_ip = NULL;
891 uint32_t id = 0, gid = 0;
892
893 int r = ParseThresholdRule(de_ctx, rawstr, &id, &gid, &parsed_type, &parsed_track,
894 &parsed_count, &parsed_seconds, &parsed_timeout, &parsed_new_action, &th_ip);
895 if (r < 0)
896 goto error;
897
898 if (parsed_type == TYPE_SUPPRESS) {
899 r = SetupSuppressRule(de_ctx, id, gid, parsed_type, parsed_track,
900 parsed_count, parsed_seconds, parsed_timeout, parsed_new_action,
901 th_ip);
902 } else {
903 r = SetupThresholdRule(de_ctx, id, gid, parsed_type, parsed_track, parsed_count,
904 parsed_seconds, parsed_timeout, parsed_new_action);
905 }
906 if (r < 0) {
907 goto error;
908 }
909
910 pcre2_substring_free((PCRE2_UCHAR8 *)th_ip);
911 return 0;
912error:
913 if (th_ip != NULL)
914 pcre2_substring_free((PCRE2_UCHAR8 *)th_ip);
915 return -1;
916}
917
918/**
919 * \brief Checks if a string is a comment or a blank line.
920 *
921 * Comments lines are lines of the following format -
922 * "# This is a comment string" or
923 * " # This is a comment string".
924 *
925 * \param line String that has to be checked
926 *
927 * \retval 1 On the argument string being a comment or blank line
928 * \retval 0 Otherwise
929 */
930static int SCThresholdConfIsLineBlankOrComment(char *line)
931{
932 while (*line != '\0') {
933 /* we have a comment */
934 if (*line == '#')
935 return 1;
936
937 /* this line is neither a comment line, nor a blank line */
938 if (!isspace((unsigned char)*line))
939 return 0;
940
941 line++;
942 }
943
944 /* we have a blank line */
945 return 1;
946}
947
948/**
949 * \brief Checks if the rule is multiline, by searching an ending slash
950 *
951 * \param line String that has to be checked
952 *
953 * \retval the position of the slash making it multiline
954 * \retval 0 Otherwise
955 */
956static int SCThresholdConfLineIsMultiline(char *line)
957{
958 int flag = 0;
959 char *rline = line;
960 size_t len = strlen(line);
961
962 while (line < rline + len && *line != '\n') {
963 /* we have a comment */
964 if (*line == '\\')
965 flag = (int)(line - rline);
966 else
967 if (!isspace((unsigned char)*line))
968 flag = 0;
969
970 line++;
971 }
972
973 /* we have a blank line */
974 return flag;
975}
976
977/**
978 * \brief Parses the Threshold Config file
979 *
980 * \param de_ctx Pointer to the Detection Engine Context.
981 * \param fd Pointer to file descriptor.
982 */
984{
985 char line[8192] = "";
986 int rule_num = 0;
987
988 /* position of "\", on multiline rules */
989 int esc_pos = 0;
990
991 if (fp == NULL)
992 return -1;
993
994 while (fgets(line + esc_pos, (int)sizeof(line) - esc_pos, fp) != NULL) {
995 if (SCThresholdConfIsLineBlankOrComment(line)) {
996 continue;
997 }
998
999 esc_pos = SCThresholdConfLineIsMultiline(line);
1000 if (esc_pos == 0) {
1001 if (SCThresholdConfAddThresholdtype(line, de_ctx) < 0) {
1003 return -1;
1004 } else {
1005 SCLogDebug("Adding threshold.config rule num %" PRIu32 "( %s )", rule_num, line);
1006 rule_num++;
1007 }
1008 }
1009 }
1010
1011 if (de_ctx != NULL && strlen(de_ctx->config_prefix) > 0)
1012 SCLogInfo("tenant id %d: Threshold config parsed: %d rule(s) found", de_ctx->tenant_id,
1013 rule_num);
1014 else
1015 SCLogInfo("Threshold config parsed: %d rule(s) found", rule_num);
1016 return 0;
1017}
1018
1019#ifdef UNITTESTS
1020#include "detect-engine-alert.h"
1021#include "packet.h"
1022#include "action-globals.h"
1023
1024/**
1025 * \brief Creates a dummy threshold file, with all valid options, for testing purposes.
1026 *
1027 * \retval fd Pointer to file descriptor.
1028 */
1029static FILE *SCThresholdConfGenerateValidDummyFD01(void)
1030{
1031 FILE *fd = NULL;
1032 const char *buffer =
1033 "event_filter gen_id 1, sig_id 10, type limit, track by_src, count 1, seconds 60\n"
1034 "threshold gen_id 1, sig_id 100, type both, track by_dst, count 10, seconds 60\n"
1035 "event_filter gen_id 1, sig_id 1000, type threshold, track by_src, count 100, seconds 60\n";
1036
1037 fd = SCFmemopen((void *)buffer, strlen(buffer), "r");
1038 if (fd == NULL)
1039 SCLogDebug("Error with SCFmemopen() called by Threshold Config test code");
1040
1041 return fd;
1042}
1043
1044/**
1045 * \brief Creates a dummy threshold file, with some valid options and a couple of invalid options.
1046 * For testing purposes.
1047 *
1048 * \retval fd Pointer to file descriptor.
1049 */
1050static FILE *SCThresholdConfGenerateInvalidDummyFD02(void)
1051{
1052 FILE *fd;
1053 const char *buffer =
1054 "event_filter gen_id 1, sig_id 1000, type invalid, track by_src, count 100, seconds 60\n";
1055
1056 fd = SCFmemopen((void *)buffer, strlen(buffer), "r");
1057 if (fd == NULL)
1058 SCLogDebug("Error with SCFmemopen() called by Threshold Config test code");
1059
1060 return fd;
1061}
1062
1063/**
1064 * \brief Creates a dummy threshold file, with all valid options, for testing purposes.
1065 *
1066 * \retval fd Pointer to file descriptor.
1067 */
1068static FILE *SCThresholdConfGenerateValidDummyFD03(void)
1069{
1070 FILE *fd;
1071 const char *buffer =
1072 "event_filter gen_id 0, sig_id 0, type threshold, track by_src, count 100, seconds 60\n";
1073
1074 fd = SCFmemopen((void *)buffer, strlen(buffer), "r");
1075 if (fd == NULL)
1076 SCLogDebug("Error with SCFmemopen() called by Threshold Config test code");
1077
1078 return fd;
1079}
1080
1081/**
1082 * \brief Creates a dummy threshold file, with all valid options, but
1083 * with split rules (multiline), for testing purposes.
1084 *
1085 * \retval fd Pointer to file descriptor.
1086 */
1087static FILE *SCThresholdConfGenerateValidDummyFD04(void)
1088{
1089 FILE *fd = NULL;
1090 const char *buffer =
1091 "event_filter gen_id 1 \\\n, sig_id 10, type limit, track by_src, \\\ncount 1, seconds 60\n"
1092 "threshold gen_id 1, \\\nsig_id 100, type both\\\n, track by_dst, count 10, \\\n seconds 60\n"
1093 "event_filter gen_id 1, sig_id 1000, \\\ntype threshold, track \\\nby_src, count 100, seconds 60\n";
1094
1095 fd = SCFmemopen((void *)buffer, strlen(buffer), "r");
1096 if (fd == NULL)
1097 SCLogDebug("Error with SCFmemopen() called by Threshold Config test code");
1098
1099 return fd;
1100}
1101
1102/**
1103 * \brief Creates a dummy threshold file, with all valid options, for testing purposes.
1104 *
1105 * \retval fd Pointer to file descriptor.
1106 */
1107static FILE *SCThresholdConfGenerateValidDummyFD05(void)
1108{
1109 FILE *fd = NULL;
1110 const char *buffer =
1111 "rate_filter gen_id 1, sig_id 10, track by_src, count 1, seconds 60, new_action drop, timeout 10\n"
1112 "rate_filter gen_id 1, sig_id 100, track by_dst, count 10, seconds 60, new_action pass, timeout 5\n"
1113 "rate_filter gen_id 1, sig_id 1000, track by_rule, count 100, seconds 60, new_action alert, timeout 30\n"
1114 "rate_filter gen_id 1, sig_id 10000, track by_both, count 1000, seconds 60, new_action reject, timeout 21\n";
1115
1116 fd = SCFmemopen((void *)buffer, strlen(buffer), "r");
1117 if (fd == NULL)
1118 SCLogDebug("Error with SCFmemopen() called by Threshold Config test code");
1119
1120 return fd;
1121}
1122
1123/**
1124 * \brief Creates a dummy threshold file, with all valid options, but
1125 * with split rules (multiline), for testing purposes.
1126 *
1127 * \retval fd Pointer to file descriptor.
1128 */
1129static FILE *SCThresholdConfGenerateValidDummyFD06(void)
1130{
1131 FILE *fd = NULL;
1132 const char *buffer =
1133 "rate_filter \\\ngen_id 1, sig_id 10, track by_src, count 1, seconds 60\\\n, new_action drop, timeout 10\n"
1134 "rate_filter gen_id 1, \\\nsig_id 100, track by_dst, \\\ncount 10, seconds 60, new_action pass, timeout 5\n"
1135 "rate_filter gen_id 1, sig_id 1000, \\\ntrack by_rule, count 100, seconds 60, new_action alert, timeout 30\n"
1136 "rate_filter gen_id 1, sig_id 10000, track by_both, count 1000, \\\nseconds 60, new_action reject, timeout 21\n";
1137
1138 fd = SCFmemopen((void *)buffer, strlen(buffer), "r");
1139 if (fd == NULL)
1140 SCLogDebug("Error with SCFmemopen() called by Threshold Config test code");
1141
1142 return fd;
1143}
1144
1145/**
1146 * \brief Creates a dummy threshold file, with all valid options, but
1147 * with split rules (multiline), for testing purposes.
1148 *
1149 * \retval fd Pointer to file descriptor.
1150 */
1151static FILE *SCThresholdConfGenerateValidDummyFD07(void)
1152{
1153 FILE *fd = NULL;
1154 const char *buffer =
1155 "rate_filter gen_id 1, sig_id 10, track by_src, count 3, seconds 3, new_action drop, timeout 10\n"
1156 "rate_filter gen_id 1, sig_id 11, track by_src, count 3, seconds 1, new_action drop, timeout 5\n";
1157
1158 fd = SCFmemopen((void *)buffer, strlen(buffer), "r");
1159 if (fd == NULL)
1160 SCLogDebug("Error with SCFmemopen() called by Threshold Config test code");
1161
1162 return fd;
1163}
1164
1165/**
1166 * \brief Creates a dummy threshold file, for testing rate_filter, track by_rule
1167 *
1168 * \retval fd Pointer to file descriptor.
1169 */
1170static FILE *SCThresholdConfGenerateValidDummyFD08(void)
1171{
1172 FILE *fd = NULL;
1173 const char *buffer =
1174 "rate_filter gen_id 1, sig_id 10, track by_rule, count 3, seconds 3, new_action drop, timeout 10\n";
1175
1176 fd = SCFmemopen((void *)buffer, strlen(buffer), "r");
1177 if (fd == NULL)
1178 SCLogDebug("Error with SCFmemopen() called by Threshold Config test code");
1179
1180 return fd;
1181}
1182
1183/**
1184 * \brief Creates a dummy threshold file, with all valid options, but
1185 * with split rules (multiline), for testing purposes.
1186 *
1187 * \retval fd Pointer to file descriptor.
1188 */
1189static FILE *SCThresholdConfGenerateValidDummyFD09(void)
1190{
1191 FILE *fd = NULL;
1192 const char *buffer =
1193 "event_filter gen_id 1 \\\n, sig_id 10, type limit, track by_src, \\\ncount 2, seconds 60\n"
1194 "threshold gen_id 1, \\\nsig_id 11, type threshold\\\n, track by_dst, count 3, \\\n seconds 60\n"
1195 "event_filter gen_id 1, sig_id 12, \\\ntype both, track \\\nby_src, count 2, seconds 60\n";
1196
1197 fd = SCFmemopen((void *)buffer, strlen(buffer), "r");
1198 if (fd == NULL)
1199 SCLogDebug("Error with SCFmemopen() called by Threshold Config test code");
1200
1201 return fd;
1202}
1203
1204/**
1205 * \brief Creates a dummy threshold file, with all valid options, but
1206 * with split rules (multiline), for testing purposes.
1207 *
1208 * \retval fd Pointer to file descriptor.
1209 */
1210static FILE *SCThresholdConfGenerateValidDummyFD10(void)
1211{
1212 FILE *fd = NULL;
1213 const char *buffer =
1214 "event_filter gen_id 1 \\\n, sig_id 10, type limit, track by_src, \\\ncount 5, seconds 2\n"
1215 "threshold gen_id 1, \\\nsig_id 11, type threshold\\\n, track by_dst, count 5, \\\n seconds 2\n"
1216 "event_filter gen_id 1, sig_id 12, \\\ntype both, track \\\nby_src, count 5, seconds 2\n";
1217
1218 fd = SCFmemopen((void *)buffer, strlen(buffer), "r");
1219 if (fd == NULL)
1220 SCLogDebug("Error with SCFmemopen() called by Threshold Config test code");
1221
1222 return fd;
1223}
1224
1225/**
1226 * \brief Creates a dummy threshold file, with all valid options, for testing purposes.
1227 *
1228 * \retval fd Pointer to file descriptor.
1229 */
1230static FILE *SCThresholdConfGenerateValidDummyFD11(void)
1231{
1232 FILE *fd = NULL;
1233 const char *buffer =
1234 "suppress gen_id 1, sig_id 10000\n"
1235 "suppress gen_id 1, sig_id 1000, track by_src, ip 192.168.1.1\n";
1236
1237 fd = SCFmemopen((void *)buffer, strlen(buffer), "r");
1238 if (fd == NULL)
1239 SCLogDebug("Error with SCFmemopen() called by Threshold Config test code");
1240
1241 return fd;
1242}
1243
1244/**
1245 * \test Check if the threshold file is loaded and well parsed
1246 *
1247 * \retval 1 on success
1248 * \retval 0 on failure
1249 */
1250static int SCThresholdConfTest01(void)
1251{
1254 de_ctx->flags |= DE_QUIET;
1255
1257 "alert tcp any any -> any any (msg:\"Threshold limit\"; gid:1; sid:10;)");
1258 FAIL_IF_NULL(sig);
1259
1260 FAIL_IF_NOT_NULL(g_ut_threshold_fp);
1261 g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD01();
1262 FAIL_IF_NULL(g_ut_threshold_fp);
1264
1266 DETECT_THRESHOLD, -1);
1267 FAIL_IF_NULL(m);
1268
1270 FAIL_IF_NULL(de);
1271
1272 FAIL_IF_NOT(de->type == TYPE_LIMIT && de->track == TRACK_SRC && de->count == 1 && de->seconds == 60);
1274 PASS;
1275}
1276
1277/**
1278 * \test Check if the threshold file is loaded and well parsed
1279 *
1280 * \retval 1 on success
1281 * \retval 0 on failure
1282 */
1283static int SCThresholdConfTest02(void)
1284{
1287 de_ctx->flags |= DE_QUIET;
1288
1290 "alert tcp any any -> any any (msg:\"Threshold limit\"; gid:1; sid:100;)");
1291 FAIL_IF_NULL(sig);
1292
1293 FAIL_IF_NOT_NULL(g_ut_threshold_fp);
1294 g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD01();
1295 FAIL_IF_NULL(g_ut_threshold_fp);
1297
1299 DETECT_THRESHOLD, -1);
1300 FAIL_IF_NULL(m);
1301
1303 FAIL_IF_NULL(de);
1304
1305 FAIL_IF_NOT(de->type == TYPE_BOTH && de->track == TRACK_DST && de->count == 10 && de->seconds == 60);
1307 PASS;
1308}
1309
1310/**
1311 * \test Check if the threshold file is loaded and well parsed
1312 *
1313 * \retval 1 on success
1314 * \retval 0 on failure
1315 */
1316static int SCThresholdConfTest03(void)
1317{
1320 de_ctx->flags |= DE_QUIET;
1321
1323 "alert tcp any any -> any any (msg:\"Threshold limit\"; gid:1; sid:1000;)");
1324 FAIL_IF_NULL(sig);
1325
1326 FAIL_IF_NOT_NULL(g_ut_threshold_fp);
1327 g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD01();
1328 FAIL_IF_NULL(g_ut_threshold_fp);
1330
1332 DETECT_THRESHOLD, -1);
1333 FAIL_IF_NULL(m);
1334
1336 FAIL_IF_NULL(de);
1337
1338 FAIL_IF_NOT(de->type == TYPE_THRESHOLD && de->track == TRACK_SRC && de->count == 100 && de->seconds == 60);
1340 PASS;
1341}
1342
1343/**
1344 * \test Check if the threshold file is loaded and well parsed
1345 *
1346 * \retval 1 on success
1347 * \retval 0 on failure
1348 */
1349static int SCThresholdConfTest04(void)
1350{
1353 de_ctx->flags |= DE_QUIET;
1354
1356 "alert tcp any any -> any any (msg:\"Threshold limit\"; gid:1; sid:1000;)");
1357 FAIL_IF_NULL(sig);
1358
1359 FAIL_IF_NOT_NULL(g_ut_threshold_fp);
1360 g_ut_threshold_fp = SCThresholdConfGenerateInvalidDummyFD02();
1361 FAIL_IF_NULL(g_ut_threshold_fp);
1363
1365 DETECT_THRESHOLD, -1);
1367
1369 PASS;
1370}
1371
1372/**
1373 * \test Check if the threshold file is loaded and well parsed
1374 *
1375 * \retval 1 on success
1376 * \retval 0 on failure
1377 */
1378static int SCThresholdConfTest05(void)
1379{
1382 de_ctx->flags |= DE_QUIET;
1383
1385 "alert tcp any any -> any any (msg:\"Threshold limit\"; gid:1; sid:1;)");
1386 FAIL_IF_NULL(sig);
1388 "alert tcp any any -> any 80 (msg:\"Threshold limit\"; gid:1; sid:10;)");
1389 FAIL_IF_NULL(sig);
1390
1392 "alert tcp any any -> any 80 (msg:\"Threshold limit\"; gid:1; sid:100;)");
1393 FAIL_IF_NULL(sig);
1394
1395 FAIL_IF_NOT_NULL(g_ut_threshold_fp);
1396 g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD03();
1397 FAIL_IF_NULL(g_ut_threshold_fp);
1399
1402 DETECT_THRESHOLD, -1);
1403 FAIL_IF_NULL(m);
1404 FAIL_IF_NULL(m->ctx);
1406 FAIL_IF_NOT(de->type == TYPE_THRESHOLD && de->track == TRACK_SRC && de->count == 100 && de->seconds == 60);
1407
1408 s = de_ctx->sig_list->next;
1410 DETECT_THRESHOLD, -1);
1411 FAIL_IF_NULL(m);
1412 FAIL_IF_NULL(m->ctx);
1413 de = (DetectThresholdData *)m->ctx;
1414 FAIL_IF_NOT(de->type == TYPE_THRESHOLD && de->track == TRACK_SRC && de->count == 100 && de->seconds == 60);
1415
1416 s = de_ctx->sig_list->next->next;
1418 DETECT_THRESHOLD, -1);
1419 FAIL_IF_NULL(m);
1420 FAIL_IF_NULL(m->ctx);
1421 de = (DetectThresholdData *)m->ctx;
1422 FAIL_IF_NOT(de->type == TYPE_THRESHOLD && de->track == TRACK_SRC && de->count == 100 && de->seconds == 60);
1423
1424 PASS;
1425}
1426
1427/**
1428 * \test Check if the threshold file is loaded and well parsed
1429 *
1430 * \retval 1 on success
1431 * \retval 0 on failure
1432 */
1433static int SCThresholdConfTest06(void)
1434{
1437 de_ctx->flags |= DE_QUIET;
1438
1440 "alert tcp any any -> any any (msg:\"Threshold limit\"; gid:1; sid:10;)");
1441 FAIL_IF_NULL(sig);
1442
1443 FAIL_IF_NOT_NULL(g_ut_threshold_fp);
1444 g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD04();
1445 FAIL_IF_NULL(g_ut_threshold_fp);
1447
1449 DETECT_THRESHOLD, -1);
1450 FAIL_IF_NULL(m);
1451
1453 FAIL_IF_NULL(de);
1454 FAIL_IF_NOT(de->type == TYPE_LIMIT && de->track == TRACK_SRC && de->count == 1 && de->seconds == 60);
1455
1457 PASS;
1458}
1459
1460/**
1461 * \test Check if the rate_filter rules are loaded and well parsed
1462 *
1463 * \retval 1 on success
1464 * \retval 0 on failure
1465 */
1466static int SCThresholdConfTest07(void)
1467{
1470 de_ctx->flags |= DE_QUIET;
1471
1473 "alert tcp any any -> any any (msg:\"Threshold limit\"; gid:1; sid:10;)");
1474 FAIL_IF_NULL(sig);
1475
1476 FAIL_IF_NOT_NULL(g_ut_threshold_fp);
1477 g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD05();
1478 FAIL_IF_NULL(g_ut_threshold_fp);
1480
1483 FAIL_IF_NULL(m);
1484
1486 FAIL_IF_NULL(de);
1487 FAIL_IF_NOT(de->type == TYPE_RATE && de->track == TRACK_SRC && de->count == 1 && de->seconds == 60);
1488
1490 PASS;
1491}
1492
1493/**
1494 * \test Check if the rate_filter rules are loaded and well parsed
1495 * with multilines
1496 *
1497 * \retval 1 on success
1498 * \retval 0 on failure
1499 */
1500static int SCThresholdConfTest08(void)
1501{
1504 de_ctx->flags |= DE_QUIET;
1505
1507 "alert tcp any any -> any any (msg:\"Threshold limit\"; gid:1; sid:10;)");
1508 FAIL_IF_NULL(sig);
1509
1510 FAIL_IF_NOT_NULL(g_ut_threshold_fp);
1511 g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD06();
1512 FAIL_IF_NULL(g_ut_threshold_fp);
1514
1517 FAIL_IF_NULL(m);
1518
1520 FAIL_IF_NULL(de);
1521 FAIL_IF_NOT(de->type == TYPE_RATE && de->track == TRACK_SRC && de->count == 1 && de->seconds == 60);
1522
1524 PASS;
1525}
1526
1527/**
1528 * \test Check if the rate_filter rules work
1529 *
1530 * \retval 1 on success
1531 * \retval 0 on failure
1532 */
1533static int SCThresholdConfTest09(void)
1534{
1535 ThreadVars th_v;
1536 memset(&th_v, 0, sizeof(th_v));
1537
1538 ThresholdInit();
1539
1540 Packet *p = UTHBuildPacket((uint8_t*)"lalala", 6, IPPROTO_TCP);
1541 FAIL_IF_NULL(p);
1542
1543 DetectEngineThreadCtx *det_ctx = NULL;
1544
1547 de_ctx->flags |= DE_QUIET;
1548
1550 "alert tcp any any -> any any (msg:\"ratefilter test\"; gid:1; sid:10;)");
1551 FAIL_IF_NULL(s);
1552
1553 FAIL_IF_NOT_NULL(g_ut_threshold_fp);
1554 g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD07();
1555 FAIL_IF_NULL(g_ut_threshold_fp);
1557
1559 DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
1560
1561 p->ts = TimeGet();
1562 p->alerts.cnt = 0;
1563 p->action = 0;
1564 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1565 FAIL_IF(p->alerts.cnt != 1 || PacketTestAction(p, ACTION_DROP));
1566 p->alerts.cnt = 0;
1567 p->action = 0;
1568 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1569 FAIL_IF(p->alerts.cnt != 1 || PacketTestAction(p, ACTION_DROP));
1570 p->alerts.cnt = 0;
1571 p->action = 0;
1572 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1573 FAIL_IF(p->alerts.cnt != 1 || PacketTestAction(p, ACTION_DROP));
1574
1576 p->ts = TimeGet();
1577
1578 p->alerts.cnt = 0;
1579 p->action = 0;
1580 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1581 FAIL_IF(p->alerts.cnt != 1 || !(PacketTestAction(p, ACTION_DROP)));
1582
1584 p->ts = TimeGet();
1585
1586 p->alerts.cnt = 0;
1587 p->action = 0;
1588 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1589 FAIL_IF(p->alerts.cnt != 1 || !(PacketTestAction(p, ACTION_DROP)));
1590
1592 p->ts = TimeGet();
1593
1594 p->alerts.cnt = 0;
1595 p->action = 0;
1596 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1597 FAIL_IF(p->alerts.cnt != 1 || PacketTestAction(p, ACTION_DROP));
1598
1599 p->alerts.cnt = 0;
1600 p->action = 0;
1601 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1602 FAIL_IF(p->alerts.cnt != 1 || PacketTestAction(p, ACTION_DROP));
1603
1604 UTHFreePacket(p);
1605 DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
1608 PASS;
1609}
1610
1611/**
1612 * \test Check if the rate_filter rules work with track by_rule
1613 *
1614 * \retval 1 on success
1615 * \retval 0 on failure
1616 */
1617static int SCThresholdConfTest10(void)
1618{
1619 ThresholdInit();
1620
1621 /* Create two different packets falling to the same rule, and
1622 * because count:3, we should drop on match #4.
1623 */
1624 Packet *p1 = UTHBuildPacketSrcDst((uint8_t*)"lalala", 6, IPPROTO_TCP,
1625 "172.26.0.2", "172.26.0.11");
1626 FAIL_IF_NULL(p1);
1627 Packet *p2 = UTHBuildPacketSrcDst((uint8_t*)"lalala", 6, IPPROTO_TCP,
1628 "172.26.0.1", "172.26.0.10");
1629 FAIL_IF_NULL(p2);
1630
1631 ThreadVars th_v;
1632 memset(&th_v, 0, sizeof(th_v));
1633
1636 de_ctx->flags |= DE_QUIET;
1637 DetectEngineThreadCtx *det_ctx = NULL;
1638
1640 "alert tcp any any -> any any (msg:\"ratefilter test\"; gid:1; sid:10;)");
1641 FAIL_IF_NULL(s);
1642
1643 FAIL_IF_NOT_NULL(g_ut_threshold_fp);
1644 g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD08();
1645 FAIL_IF_NULL(g_ut_threshold_fp);
1647
1649 DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
1650 p1->ts = TimeGet();
1651 p2->ts = p1->ts;
1652
1653 /* All should be alerted, none dropped */
1654 SigMatchSignatures(&th_v, de_ctx, det_ctx, p1);
1655 FAIL_IF(PacketTestAction(p1, ACTION_DROP));
1656 FAIL_IF(PacketAlertCheck(p1, 10) != 1);
1657 p1->action = 0;
1658 SigMatchSignatures(&th_v, de_ctx, det_ctx, p2);
1659 FAIL_IF(PacketTestAction(p2, ACTION_DROP));
1660 FAIL_IF(PacketAlertCheck(p2, 10) != 1);
1661 p2->action = 0;
1662 SigMatchSignatures(&th_v, de_ctx, det_ctx, p1);
1663 FAIL_IF(PacketTestAction(p1, ACTION_DROP));
1664 FAIL_IF(PacketAlertCheck(p1, 10) != 1);
1665 p1->action = 0;
1666
1667 /* Match #4 should be dropped*/
1668 SigMatchSignatures(&th_v, de_ctx, det_ctx, p2);
1669 FAIL_IF_NOT(PacketTestAction(p2, ACTION_DROP));
1670 FAIL_IF(PacketAlertCheck(p2, 10) != 1);
1671 p2->action = 0;
1672
1674 p1->ts = TimeGet();
1675
1676 /* Still dropped because timeout not expired */
1677 SigMatchSignatures(&th_v, de_ctx, det_ctx, p1);
1678 FAIL_IF_NOT(PacketTestAction(p1, ACTION_DROP));
1679 FAIL_IF(PacketAlertCheck(p1, 10) != 1);
1680 p1->action = 0;
1681
1683 p1->ts = TimeGet();
1684
1685 /* Not dropped because timeout expired */
1686 SigMatchSignatures(&th_v, de_ctx, det_ctx, p1);
1687 FAIL_IF(PacketTestAction(p1, ACTION_DROP));
1688 FAIL_IF(PacketAlertCheck(p1, 10) != 1);
1689#if 0
1690 /* Ensure that a Threshold entry was installed at the sig */
1691 FAIL_IF_NULL(de_ctx->ths_ctx.th_entry[s->iid]);
1692#endif
1693 UTHFreePacket(p1);
1694 UTHFreePacket(p2);
1695 DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
1698 PASS;
1699}
1700
1701/**
1702 * \test Check if the rate_filter rules work
1703 *
1704 * \retval 1 on success
1705 * \retval 0 on failure
1706 */
1707static int SCThresholdConfTest11(void)
1708{
1709 ThresholdInit();
1710
1711 Packet *p = UTHBuildPacket((uint8_t*)"lalala", 6, IPPROTO_TCP);
1712 FAIL_IF_NULL(p);
1713
1714 ThreadVars th_v;
1715 memset(&th_v, 0, sizeof(th_v));
1716
1719 de_ctx->flags |= DE_QUIET;
1720 DetectEngineThreadCtx *det_ctx = NULL;
1721
1723 "alert tcp any any -> any any (msg:\"event_filter test limit\"; gid:1; sid:10;)");
1724 FAIL_IF_NULL(s);
1726 "alert tcp any any -> any any (msg:\"event_filter test threshold\"; gid:1; sid:11;)");
1727 FAIL_IF_NULL(s);
1729 "alert tcp any any -> any any (msg:\"event_filter test both\"; gid:1; sid:12;)");
1730 FAIL_IF_NULL(s);
1731
1732 FAIL_IF_NOT_NULL(g_ut_threshold_fp);
1733 g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD09();
1734 FAIL_IF_NULL(g_ut_threshold_fp);
1736
1738 DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
1739
1740 p->ts = TimeGet();
1741
1742 int alerts10 = 0;
1743 int alerts11 = 0;
1744 int alerts12 = 0;
1745
1746 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1747 alerts10 += PacketAlertCheck(p, 10);
1748 alerts11 += PacketAlertCheck(p, 11);
1749 alerts12 += PacketAlertCheck(p, 12);
1750 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1751 alerts10 += PacketAlertCheck(p, 10);
1752 alerts11 += PacketAlertCheck(p, 11);
1753 alerts12 += PacketAlertCheck(p, 12);
1754 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1755 alerts10 += PacketAlertCheck(p, 10);
1756 alerts11 += PacketAlertCheck(p, 11);
1757 alerts12 += PacketAlertCheck(p, 12);
1758 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1759 alerts10 += PacketAlertCheck(p, 10);
1760 alerts11 += PacketAlertCheck(p, 11);
1761 alerts12 += PacketAlertCheck(p, 12);
1762 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1763 alerts10 += PacketAlertCheck(p, 10);
1764 alerts11 += PacketAlertCheck(p, 11);
1765 alerts12 += PacketAlertCheck(p, 12);
1766
1768 p->ts = TimeGet();
1769
1770 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1771 alerts10 += PacketAlertCheck(p, 10);
1772 alerts11 += PacketAlertCheck(p, 11);
1773
1775 p->ts = TimeGet();
1776
1777 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1778 alerts10 += PacketAlertCheck(p, 10);
1779 alerts11 += PacketAlertCheck(p, 11);
1780 alerts12 += PacketAlertCheck(p, 12);
1781 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1782 alerts10 += PacketAlertCheck(p, 10);
1783 alerts11 += PacketAlertCheck(p, 11);
1784 alerts12 += PacketAlertCheck(p, 12);
1785 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1786 alerts10 += PacketAlertCheck(p, 10);
1787 alerts11 += PacketAlertCheck(p, 11);
1788 alerts12 += PacketAlertCheck(p, 12);
1789 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1790 alerts10 += PacketAlertCheck(p, 10);
1791 alerts11 += PacketAlertCheck(p, 11);
1792 alerts12 += PacketAlertCheck(p, 12);
1793
1794 FAIL_IF_NOT(alerts10 == 4);
1795 /* One on the first interval, another on the second */
1796 FAIL_IF_NOT(alerts11 == 2);
1797 FAIL_IF_NOT(alerts12 == 2);
1798
1799 UTHFreePacket(p);
1800 DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
1803 PASS;
1804}
1805
1806/**
1807 * \test Check if the rate_filter rules work
1808 *
1809 * \retval 1 on success
1810 * \retval 0 on failure
1811 */
1812static int SCThresholdConfTest12(void)
1813{
1814 ThresholdInit();
1815
1816 Packet *p = UTHBuildPacket((uint8_t*)"lalala", 6, IPPROTO_TCP);
1817 FAIL_IF_NULL(p);
1818
1819 ThreadVars th_v;
1820 memset(&th_v, 0, sizeof(th_v));
1821
1824 de_ctx->flags |= DE_QUIET;
1825 DetectEngineThreadCtx *det_ctx = NULL;
1826
1828 "alert tcp any any -> any any (msg:\"event_filter test limit\"; gid:1; sid:10;)");
1829 FAIL_IF_NULL(s);
1831 "alert tcp any any -> any any (msg:\"event_filter test threshold\"; gid:1; sid:11;)");
1832 FAIL_IF_NULL(s);
1834 "alert tcp any any -> any any (msg:\"event_filter test both\"; gid:1; sid:12;)");
1835 FAIL_IF_NULL(s);
1836
1837 FAIL_IF_NOT_NULL(g_ut_threshold_fp);
1838 g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD10();
1839 FAIL_IF_NULL(g_ut_threshold_fp);
1841
1843 DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
1844
1845 p->ts = TimeGet();
1846
1847 int alerts10 = 0;
1848 int alerts11 = 0;
1849 int alerts12 = 0;
1850
1851 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1852 alerts10 += PacketAlertCheck(p, 10);
1853 alerts11 += PacketAlertCheck(p, 11);
1854 alerts12 += PacketAlertCheck(p, 12);
1855 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1856 alerts10 += PacketAlertCheck(p, 10);
1857 alerts11 += PacketAlertCheck(p, 11);
1858 alerts12 += PacketAlertCheck(p, 12);
1859 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1860 alerts10 += PacketAlertCheck(p, 10);
1861 alerts11 += PacketAlertCheck(p, 11);
1862 alerts12 += PacketAlertCheck(p, 12);
1863 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1864 alerts10 += PacketAlertCheck(p, 10);
1865 alerts11 += PacketAlertCheck(p, 11);
1866 alerts12 += PacketAlertCheck(p, 12);
1867 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1868 alerts10 += PacketAlertCheck(p, 10);
1869 alerts11 += PacketAlertCheck(p, 11);
1870 alerts12 += PacketAlertCheck(p, 12);
1871
1873 p->ts = TimeGet();
1874
1875 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1876 alerts10 += PacketAlertCheck(p, 10);
1877 alerts11 += PacketAlertCheck(p, 11);
1878
1880 p->ts = TimeGet();
1881
1882 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1883 alerts10 += PacketAlertCheck(p, 10);
1884 alerts11 += PacketAlertCheck(p, 11);
1885 alerts12 += PacketAlertCheck(p, 12);
1886 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1887 alerts10 += PacketAlertCheck(p, 10);
1888 alerts11 += PacketAlertCheck(p, 11);
1889 alerts12 += PacketAlertCheck(p, 12);
1890 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1891 alerts10 += PacketAlertCheck(p, 10);
1892 alerts11 += PacketAlertCheck(p, 11);
1893 alerts12 += PacketAlertCheck(p, 12);
1894 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1895 alerts10 += PacketAlertCheck(p, 10);
1896 alerts11 += PacketAlertCheck(p, 11);
1897 alerts12 += PacketAlertCheck(p, 12);
1898
1899 FAIL_IF_NOT(alerts10 == 10);
1900 /* One on the first interval, another on the second */
1901 FAIL_IF_NOT(alerts11 == 1);
1902 FAIL_IF_NOT(alerts12 == 1);
1903
1904 UTHFreePacket(p);
1905 DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
1908 PASS;
1909}
1910
1911/**
1912 * \test Check if the threshold file is loaded and well parsed
1913 *
1914 * \retval 1 on success
1915 * \retval 0 on failure
1916 */
1917static int SCThresholdConfTest13(void)
1918{
1921 de_ctx->flags |= DE_QUIET;
1922
1924 "alert tcp any any -> any any (msg:\"Threshold limit\"; gid:1; sid:1000;)");
1925 FAIL_IF_NULL(sig);
1926
1927 FAIL_IF_NOT_NULL(g_ut_threshold_fp);
1928 g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD11();
1929 FAIL_IF_NULL(g_ut_threshold_fp);
1931
1934 FAIL_IF_NULL(m);
1935
1937 FAIL_IF_NULL(de);
1938 FAIL_IF_NOT(de->type == TYPE_SUPPRESS && de->track == TRACK_SRC);
1939
1941 PASS;
1942}
1943
1944/**
1945 * \test Check if the suppress rules work
1946 *
1947 * \retval 1 on success
1948 * \retval 0 on failure
1949 */
1950static int SCThresholdConfTest14(void)
1951{
1952 ThresholdInit();
1953
1954 Packet *p1 = UTHBuildPacketReal((uint8_t*)"lalala", 6, IPPROTO_TCP, "192.168.0.10",
1955 "192.168.0.100", 1234, 24);
1956 FAIL_IF_NULL(p1);
1957 Packet *p2 = UTHBuildPacketReal((uint8_t*)"lalala", 6, IPPROTO_TCP, "192.168.1.1",
1958 "192.168.0.100", 1234, 24);
1959 FAIL_IF_NULL(p2);
1960
1961 DetectEngineThreadCtx *det_ctx = NULL;
1964 de_ctx->flags |= DE_QUIET;
1965
1967 "alert tcp any any -> any any (msg:\"suppress test\"; gid:1; sid:10000;)");
1968 FAIL_IF_NULL(sig);
1970 "alert tcp any any -> any any (msg:\"suppress test 2\"; gid:1; sid:10;)");
1971 FAIL_IF_NULL(sig);
1973 "alert tcp any any -> any any (msg:\"suppress test 3\"; gid:1; sid:1000;)");
1974 FAIL_IF_NULL(sig);
1975
1976 ThreadVars th_v;
1977 memset(&th_v, 0, sizeof(th_v));
1978
1979 FAIL_IF_NOT_NULL(g_ut_threshold_fp);
1980 g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD11();
1981 FAIL_IF_NULL(g_ut_threshold_fp);
1983
1985 DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
1986
1987 SigMatchSignatures(&th_v, de_ctx, det_ctx, p1);
1988 SigMatchSignatures(&th_v, de_ctx, det_ctx, p2);
1989
1990 FAIL_IF_NOT(PacketAlertCheck(p1, 10000) == 0);
1991 FAIL_IF_NOT(PacketAlertCheck(p1, 10) == 1);
1992 FAIL_IF_NOT(PacketAlertCheck(p1, 1000) == 1);
1993 FAIL_IF_NOT(PacketAlertCheck(p2, 1000) == 0);
1994
1995 UTHFreePacket(p1);
1996 UTHFreePacket(p2);
1997
1998 DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
2000
2002 PASS;
2003}
2004
2005/**
2006 * \test Check if the suppress rules work
2007 *
2008 * \retval 1 on success
2009 * \retval 0 on failure
2010 */
2011static int SCThresholdConfTest15(void)
2012{
2013 ThresholdInit();
2014
2015 Packet *p = UTHBuildPacketReal((uint8_t*)"lalala", 6, IPPROTO_TCP, "192.168.0.10",
2016 "192.168.0.100", 1234, 24);
2017 FAIL_IF_NULL(p);
2018
2019 ThreadVars th_v;
2020 memset(&th_v, 0, sizeof(th_v));
2021
2022 DetectEngineThreadCtx *det_ctx = NULL;
2025 de_ctx->flags |= DE_QUIET;
2026
2028 "drop tcp any any -> any any (msg:\"suppress test\"; content:\"lalala\"; gid:1; sid:10000;)");
2029 FAIL_IF_NULL(sig);
2030
2031 FAIL_IF_NOT_NULL(g_ut_threshold_fp);
2032 g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD11();
2033 FAIL_IF_NULL(g_ut_threshold_fp);
2035
2037 DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
2038
2039 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
2040
2041 /* 10000 shouldn't match */
2042 FAIL_IF(PacketAlertCheck(p, 10000) != 0);
2043 /* however, it should have set the drop flag */
2044 FAIL_IF(!(PacketTestAction(p, ACTION_DROP)));
2045
2046 UTHFreePacket(p);
2047 DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
2050 PASS;
2051}
2052
2053/**
2054 * \test Check if the suppress rules work
2055 *
2056 * \retval 1 on success
2057 * \retval 0 on failure
2058 */
2059static int SCThresholdConfTest16(void)
2060{
2061 ThresholdInit();
2062
2063 Packet *p = UTHBuildPacketReal((uint8_t*)"lalala", 6, IPPROTO_TCP, "192.168.1.1",
2064 "192.168.0.100", 1234, 24);
2065 FAIL_IF_NULL(p);
2066
2067 ThreadVars th_v;
2068 memset(&th_v, 0, sizeof(th_v));
2069
2070 DetectEngineThreadCtx *det_ctx = NULL;
2073 de_ctx->flags |= DE_QUIET;
2074
2076 "drop tcp any any -> any any (msg:\"suppress test\"; gid:1; sid:1000;)");
2077 FAIL_IF_NULL(sig);
2078
2079 FAIL_IF_NOT_NULL(g_ut_threshold_fp);
2080 g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD11();
2081 FAIL_IF_NULL(g_ut_threshold_fp);
2083
2085 DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
2086
2087 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
2088
2089 FAIL_IF(PacketAlertCheck(p, 1000) != 0);
2090 /* however, it should have set the drop flag */
2091 FAIL_IF(!(PacketTestAction(p, ACTION_DROP)));
2092
2093 UTHFreePacket(p);
2094 DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
2097 PASS;
2098}
2099
2100/**
2101 * \test Check if the suppress rules work - ip only rule
2102 *
2103 * \retval 1 on success
2104 * \retval 0 on failure
2105 */
2106static int SCThresholdConfTest17(void)
2107{
2108 ThresholdInit();
2109
2110 Packet *p = UTHBuildPacketReal((uint8_t*)"lalala", 6, IPPROTO_TCP, "192.168.0.10",
2111 "192.168.0.100", 1234, 24);
2112 FAIL_IF_NULL(p);
2113
2114 ThreadVars th_v;
2115 memset(&th_v, 0, sizeof(th_v));
2116
2117 DetectEngineThreadCtx *det_ctx = NULL;
2120 de_ctx->flags |= DE_QUIET;
2121
2123 "drop tcp 192.168.0.10 any -> 192.168.0.100 any (msg:\"suppress test\"; gid:1; sid:10000;)");
2124 FAIL_IF_NULL(sig);
2125
2126 FAIL_IF_NOT_NULL(g_ut_threshold_fp);
2127 g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD11();
2128 FAIL_IF_NULL(g_ut_threshold_fp);
2130
2132 DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
2133
2134 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
2135
2136 /* 10000 shouldn't match */
2137 FAIL_IF(PacketAlertCheck(p, 10000) != 0);
2138 /* however, it should have set the drop flag */
2139 FAIL_IF(!(PacketTestAction(p, ACTION_DROP)));
2140
2141 UTHFreePacket(p);
2142 DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
2145 PASS;
2146}
2147
2148/**
2149 * \brief Creates a dummy threshold file, with all valid options, for testing purposes.
2150 *
2151 * \retval fd Pointer to file descriptor.
2152 */
2153static FILE *SCThresholdConfGenerateInvalidDummyFD12(void)
2154{
2155 FILE *fd = NULL;
2156 const char *buffer =
2157 "suppress gen_id 1, sig_id 2200029, track by_dst, ip fe80::/16\n"
2158 "suppress gen_id 1, sig_id 2200029, track by_stc, ip fe80::/16\n";
2159
2160 fd = SCFmemopen((void *)buffer, strlen(buffer), "r");
2161 if (fd == NULL)
2162 SCLogDebug("Error with SCFmemopen() called by Threshold Config test code");
2163
2164 return fd;
2165}
2166
2167/**
2168 * \test Check if the suppress rule parsing handles errors correctly
2169 *
2170 * \retval 1 on success
2171 * \retval 0 on failure
2172 */
2173static int SCThresholdConfTest18(void)
2174{
2175 ThresholdInit();
2178 de_ctx->flags |= DE_QUIET;
2179
2181 "alert tcp 192.168.0.10 any -> 192.168.0.100 any (msg:\"suppress test\"; gid:1; sid:2200029;)");
2182 FAIL_IF_NULL(s);
2183 FAIL_IF_NOT_NULL(g_ut_threshold_fp);
2184 g_ut_threshold_fp = SCThresholdConfGenerateInvalidDummyFD12();
2185 FAIL_IF_NULL(g_ut_threshold_fp);
2188
2192 FAIL_IF_NULL(de);
2193 FAIL_IF_NOT(de->type == TYPE_SUPPRESS && de->track == TRACK_DST);
2194
2197 PASS;
2198}
2199
2200/**
2201 * \brief Creates a dummy threshold file, with all valid options, for testing purposes.
2202 *
2203 * \retval fd Pointer to file descriptor.
2204 */
2205static FILE *SCThresholdConfGenerateInvalidDummyFD13(void)
2206{
2207 FILE *fd = NULL;
2208 const char *buffer =
2209 "suppress gen_id 1, sig_id 2200029, track by_stc, ip fe80::/16\n"
2210 "suppress gen_id 1, sig_id 2200029, track by_dst, ip fe80::/16\n";
2211
2212 fd = SCFmemopen((void *)buffer, strlen(buffer), "r");
2213 if (fd == NULL)
2214 SCLogDebug("Error with SCFmemopen() called by Threshold Config test code");
2215
2216 return fd;
2217}
2218
2219/**
2220 * \test Check if the suppress rule parsing handles errors correctly
2221 *
2222 * \retval 1 on success
2223 * \retval 0 on failure
2224 */
2225static int SCThresholdConfTest19(void)
2226{
2227 ThresholdInit();
2230 de_ctx->flags |= DE_QUIET;
2232 "alert tcp 192.168.0.10 any -> 192.168.0.100 any (msg:\"suppress test\"; gid:1; sid:2200029;)");
2233 FAIL_IF_NULL(s);
2234 FAIL_IF_NOT_NULL(g_ut_threshold_fp);
2235 g_ut_threshold_fp = SCThresholdConfGenerateInvalidDummyFD13();
2236 FAIL_IF_NULL(g_ut_threshold_fp);
2242 FAIL_IF_NULL(de);
2243 FAIL_IF_NOT(de->type == TYPE_SUPPRESS && de->track == TRACK_DST);
2246 PASS;
2247}
2248
2249/**
2250 * \brief Creates a dummy threshold file, with all valid options, for testing purposes.
2251 *
2252 * \retval fd Pointer to file descriptor.
2253 */
2254static FILE *SCThresholdConfGenerateValidDummyFD20(void)
2255{
2256 FILE *fd = NULL;
2257 const char *buffer =
2258 "suppress gen_id 1, sig_id 1000, track by_src, ip 2.2.3.4\n"
2259 "suppress gen_id 1, sig_id 1000, track by_src, ip 1.2.3.4\n"
2260 "suppress gen_id 1, sig_id 1000, track by_src, ip 192.168.1.1\n";
2261
2262 fd = SCFmemopen((void *)buffer, strlen(buffer), "r");
2263 if (fd == NULL)
2264 SCLogDebug("Error with SCFmemopen() called by Threshold Config test code");
2265
2266 return fd;
2267}
2268
2269/**
2270 * \test Check if the threshold file is loaded and well parsed
2271 *
2272 * \retval 1 on success
2273 * \retval 0 on failure
2274 */
2275static int SCThresholdConfTest20(void)
2276{
2277 ThresholdInit();
2280 de_ctx->flags |= DE_QUIET;
2282 "alert tcp any any -> any any (msg:\"Threshold limit\"; content:\"abc\"; sid:1000;)");
2283 FAIL_IF_NULL(s);
2284 FAIL_IF_NOT_NULL(g_ut_threshold_fp);
2285 g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD20();
2286 FAIL_IF_NULL(g_ut_threshold_fp);
2290
2293 FAIL_IF_NULL(de);
2294 FAIL_IF_NOT(de->type == TYPE_SUPPRESS && de->track == TRACK_SRC);
2295 FAIL_IF(smd->is_last);
2296
2297 smd++;
2298 de = (DetectThresholdData *)smd->ctx;
2299 FAIL_IF_NULL(de);
2300 FAIL_IF_NOT(de->type == TYPE_SUPPRESS && de->track == TRACK_SRC);
2301 FAIL_IF(smd->is_last);
2302
2303 smd++;
2304 de = (DetectThresholdData *)smd->ctx;
2305 FAIL_IF_NULL(de);
2306 FAIL_IF_NOT(de->type == TYPE_SUPPRESS && de->track == TRACK_SRC);
2307 FAIL_IF_NOT(smd->is_last);
2308
2311 PASS;
2312}
2313
2314/**
2315 * \test Check if the threshold file is loaded and well parsed, and applied
2316 * correctly to a rule with thresholding
2317 *
2318 * \retval 1 on success
2319 * \retval 0 on failure
2320 */
2321static int SCThresholdConfTest21(void)
2322{
2323 ThresholdInit();
2326 de_ctx->flags |= DE_QUIET;
2328 "alert tcp any any -> any any (msg:\"Threshold limit\"; content:\"abc\"; threshold: type limit, track by_dst, count 5, seconds 60; sid:1000;)");
2329 FAIL_IF_NULL(s);
2330 g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD20();
2331 FAIL_IF_NULL(g_ut_threshold_fp);
2335
2338 FAIL_IF_NULL(de);
2339 FAIL_IF_NOT(de->type == TYPE_SUPPRESS && de->track == TRACK_SRC);
2340 FAIL_IF(smd->is_last);
2341
2342 smd++;
2343 de = (DetectThresholdData *)smd->ctx;
2344 FAIL_IF_NULL(de);
2345 FAIL_IF_NOT(de->type == TYPE_SUPPRESS && de->track == TRACK_SRC);
2346 FAIL_IF(smd->is_last);
2347
2348 smd++;
2349 de = (DetectThresholdData *)smd->ctx;
2350 FAIL_IF_NULL(de);
2351 FAIL_IF_NOT(de->type == TYPE_SUPPRESS && de->track == TRACK_SRC);
2352 FAIL_IF_NOT(smd->is_last);
2353
2356 PASS;
2357}
2358
2359/**
2360* \brief Creates a dummy rate_filter file, for testing rate filtering by_both source and destination
2361*
2362* \retval fd Pointer to file descriptor.
2363*/
2364static FILE *SCThresholdConfGenerateValidDummyFD22(void)
2365{
2366 FILE *fd = NULL;
2367 const char *buffer =
2368 "rate_filter gen_id 1, sig_id 10, track by_both, count 2, seconds 5, new_action drop, timeout 6\n";
2369
2370 fd = SCFmemopen((void *)buffer, strlen(buffer), "r");
2371 if (fd == NULL)
2372 SCLogDebug("Error with SCFmemopen() called by Threshold Config test code");
2373
2374 return fd;
2375}
2376
2377/**
2378 * \test Check if the rate_filter rules work with track by_both
2379 *
2380 * \retval 1 on success
2381 * \retval 0 on failure
2382 */
2383static int SCThresholdConfTest22(void)
2384{
2385 ThreadVars th_v;
2386 memset(&th_v, 0, sizeof(th_v));
2387
2388 ThresholdInit();
2389
2390 /* This packet will cause rate_filter */
2391 Packet *p1 = UTHBuildPacketSrcDst((uint8_t*)"lalala", 6, IPPROTO_TCP, "172.26.0.1", "172.26.0.10");
2392 FAIL_IF_NULL(p1);
2393
2394 /* Should not be filtered for different destination */
2395 Packet *p2 = UTHBuildPacketSrcDst((uint8_t*)"lalala", 6, IPPROTO_TCP, "172.26.0.1", "172.26.0.2");
2396 FAIL_IF_NULL(p2);
2397
2398 /* Should not be filtered when both src and dst the same */
2399 Packet *p3 = UTHBuildPacketSrcDst((uint8_t*)"lalala", 6, IPPROTO_TCP, "172.26.0.1", "172.26.0.1");
2400 FAIL_IF_NULL(p3);
2401
2402 DetectEngineThreadCtx *det_ctx = NULL;
2403
2406 de_ctx->flags |= DE_QUIET;
2407
2409 "alert tcp any any -> any any (msg:\"ratefilter by_both test\"; gid:1; sid:10;)");
2410 FAIL_IF_NULL(sig);
2411
2412 FAIL_IF_NOT_NULL(g_ut_threshold_fp);
2413 g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD22();
2414 FAIL_IF_NULL(g_ut_threshold_fp);
2416
2418 DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
2419
2420 p1->ts = TimeGet();
2421 p2->ts = p3->ts = p1->ts;
2422
2423 /* All should be alerted, none dropped */
2424 SigMatchSignatures(&th_v, de_ctx, det_ctx, p1);
2425 FAIL_IF(PacketTestAction(p1, ACTION_DROP));
2426 FAIL_IF(PacketAlertCheck(p1, 10) != 1);
2427
2428 SigMatchSignatures(&th_v, de_ctx, det_ctx, p2);
2429 FAIL_IF(PacketTestAction(p2, ACTION_DROP));
2430 FAIL_IF(PacketAlertCheck(p2, 10) != 1);
2431
2432 SigMatchSignatures(&th_v, de_ctx, det_ctx, p3);
2433 FAIL_IF(PacketTestAction(p3, ACTION_DROP));
2434 FAIL_IF(PacketAlertCheck(p3, 10) != 1);
2435
2436 p1->action = p2->action = p3->action = 0;
2437
2439 p1->ts = TimeGet();
2440 p2->ts = p3->ts = p1->ts;
2441
2442 /* p1 still shouldn't be dropped after 2nd alert */
2443 SigMatchSignatures(&th_v, de_ctx, det_ctx, p1);
2444 FAIL_IF(PacketTestAction(p1, ACTION_DROP));
2445 FAIL_IF(PacketAlertCheck(p1, 10) != 1);
2446
2447 p1->action = 0;
2448
2450 p1->ts = TimeGet();
2451 p2->ts = p3->ts = p1->ts;
2452
2453 /* All should be alerted, only p1 must be dropped due to rate_filter*/
2454 SigMatchSignatures(&th_v, de_ctx, det_ctx, p1);
2455 FAIL_IF_NOT(PacketTestAction(p1, ACTION_DROP));
2456 FAIL_IF(PacketAlertCheck(p1, 10) != 1);
2457
2458 SigMatchSignatures(&th_v, de_ctx, det_ctx, p2);
2459 FAIL_IF(PacketTestAction(p2, ACTION_DROP));
2460 FAIL_IF(PacketAlertCheck(p2, 10) != 1);
2461
2462 SigMatchSignatures(&th_v, de_ctx, det_ctx, p3);
2463 FAIL_IF(PacketTestAction(p3, ACTION_DROP));
2464 FAIL_IF(PacketAlertCheck(p3, 10) != 1);
2465
2466 p1->action = p2->action = p3->action = 0;
2467
2469 p1->ts = TimeGet();
2470 p2->ts = p3->ts = p1->ts;
2471
2472 /* All should be alerted, none dropped (because timeout expired) */
2473 SigMatchSignatures(&th_v, de_ctx, det_ctx, p1);
2474 FAIL_IF(PacketTestAction(p1, ACTION_DROP));
2475 FAIL_IF(PacketAlertCheck(p1, 10) != 1);
2476
2477 SigMatchSignatures(&th_v, de_ctx, det_ctx, p2);
2478 FAIL_IF(PacketTestAction(p2, ACTION_DROP));
2479 FAIL_IF(PacketAlertCheck(p2, 10) != 1);
2480
2481 SigMatchSignatures(&th_v, de_ctx, det_ctx, p3);
2482 FAIL_IF(PacketTestAction(p3, ACTION_DROP));
2483 FAIL_IF(PacketAlertCheck(p3, 10) != 1);
2484
2485 UTHFreePacket(p3);
2486 UTHFreePacket(p2);
2487 UTHFreePacket(p1);
2488
2489 DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
2492 PASS;
2493}
2494
2495/**
2496* \brief Creates a dummy rate_filter file, for testing rate filtering by_both source and destination
2497*
2498* \retval fd Pointer to file descriptor.
2499*/
2500static FILE *SCThresholdConfGenerateValidDummyFD23(void)
2501{
2502 FILE *fd = NULL;
2503 const char *buffer =
2504 "rate_filter gen_id 1, sig_id 10, track by_both, count 1, seconds 5, new_action drop, timeout 6\n";
2505
2506 fd = SCFmemopen((void *)buffer, strlen(buffer), "r");
2507 if (fd == NULL)
2508 SCLogDebug("Error with SCFmemopen() called by Threshold Config test code");
2509
2510 return fd;
2511}
2512
2513/**
2514 * \test Check if the rate_filter by_both work when similar packets
2515 * going in opposite direction
2516 *
2517 * \retval 1 on success
2518 * \retval 0 on failure
2519 */
2520static int SCThresholdConfTest23(void)
2521{
2522 ThreadVars th_v;
2523 memset(&th_v, 0, sizeof(th_v));
2524
2525 ThresholdInit();
2526
2527 /* Create two packets between same addresses in opposite direction */
2528 Packet *p1 = UTHBuildPacketSrcDst((uint8_t*)"lalala", 6, IPPROTO_TCP, "172.26.0.1", "172.26.0.10");
2529 FAIL_IF_NULL(p1);
2530
2531 Packet *p2 = UTHBuildPacketSrcDst((uint8_t*)"lalala", 6, IPPROTO_TCP, "172.26.0.10", "172.26.0.1");
2532 FAIL_IF_NULL(p2);
2533
2534 DetectEngineThreadCtx *det_ctx = NULL;
2535
2538 de_ctx->flags |= DE_QUIET;
2539
2541 "alert tcp any any -> any any (msg:\"ratefilter by_both test\"; gid:1; sid:10;)");
2542 FAIL_IF_NULL(sig);
2543
2544 FAIL_IF_NOT_NULL(g_ut_threshold_fp);
2545 g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD23();
2546 FAIL_IF_NULL(g_ut_threshold_fp);
2548
2550 DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
2551
2552 p1->ts = TimeGet();
2553 SigMatchSignatures(&th_v, de_ctx, det_ctx, p1);
2554 /* First packet should be alerted, not dropped */
2555 FAIL_IF(PacketTestAction(p1, ACTION_DROP));
2556 FAIL_IF(PacketAlertCheck(p1, 10) != 1);
2557
2559 p2->ts = TimeGet();
2560 SigMatchSignatures(&th_v, de_ctx, det_ctx, p2);
2561
2562 /* Second packet should be dropped because it considered as "the same pair"
2563 and rate_filter count reached*/
2564 FAIL_IF_NOT(PacketTestAction(p2, ACTION_DROP));
2565 FAIL_IF(PacketAlertCheck(p2, 10) != 1);
2566
2567 UTHFreePacket(p2);
2568 UTHFreePacket(p1);
2569
2570 DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
2573 PASS;
2574}
2575#endif /* UNITTESTS */
2576
2577/**
2578 * \brief This function registers unit tests for Classification Config API.
2579 */
2581{
2582#ifdef UNITTESTS
2583 UtRegisterTest("SCThresholdConfTest01", SCThresholdConfTest01);
2584 UtRegisterTest("SCThresholdConfTest02", SCThresholdConfTest02);
2585 UtRegisterTest("SCThresholdConfTest03", SCThresholdConfTest03);
2586 UtRegisterTest("SCThresholdConfTest04", SCThresholdConfTest04);
2587 UtRegisterTest("SCThresholdConfTest05", SCThresholdConfTest05);
2588 UtRegisterTest("SCThresholdConfTest06", SCThresholdConfTest06);
2589 UtRegisterTest("SCThresholdConfTest07", SCThresholdConfTest07);
2590 UtRegisterTest("SCThresholdConfTest08", SCThresholdConfTest08);
2591 UtRegisterTest("SCThresholdConfTest09 - rate_filter",
2592 SCThresholdConfTest09);
2593 UtRegisterTest("SCThresholdConfTest10 - rate_filter",
2594 SCThresholdConfTest10);
2595 UtRegisterTest("SCThresholdConfTest11 - event_filter",
2596 SCThresholdConfTest11);
2597 UtRegisterTest("SCThresholdConfTest12 - event_filter",
2598 SCThresholdConfTest12);
2599 UtRegisterTest("SCThresholdConfTest13", SCThresholdConfTest13);
2600 UtRegisterTest("SCThresholdConfTest14 - suppress", SCThresholdConfTest14);
2601 UtRegisterTest("SCThresholdConfTest15 - suppress drop",
2602 SCThresholdConfTest15);
2603 UtRegisterTest("SCThresholdConfTest16 - suppress drop",
2604 SCThresholdConfTest16);
2605 UtRegisterTest("SCThresholdConfTest17 - suppress drop",
2606 SCThresholdConfTest17);
2607
2608 UtRegisterTest("SCThresholdConfTest18 - suppress parsing",
2609 SCThresholdConfTest18);
2610 UtRegisterTest("SCThresholdConfTest19 - suppress parsing",
2611 SCThresholdConfTest19);
2612 UtRegisterTest("SCThresholdConfTest20 - suppress parsing",
2613 SCThresholdConfTest20);
2614 UtRegisterTest("SCThresholdConfTest21 - suppress parsing",
2615 SCThresholdConfTest21);
2616 UtRegisterTest("SCThresholdConfTest22 - rate_filter by_both",
2617 SCThresholdConfTest22);
2618 UtRegisterTest("SCThresholdConfTest23 - rate_filter by_both opposite",
2619 SCThresholdConfTest23);
2620
2621#endif /* UNITTESTS */
2622}
2623
2624/**
2625 * @}
2626 */
#define ACTION_DROP
uint8_t len
int SCConfGet(const char *name, const char **vptr)
Retrieve the value of a configuration node.
Definition conf.c:350
#define TRACK_SRC
#define TRACK_DST
int DetectAddressParse(const DetectEngineCtx *de_ctx, DetectAddressHead *gh, const char *str)
Parses an address group sent as a character string and updates the DetectAddressHead sent as the argu...
void DetectAddressHeadCleanup(DetectAddressHead *gh)
Cleans a DetectAddressHead. The functions frees the address group heads(ipv4 and ipv6) inside the Det...
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.
Signature * SigFindSignatureBySidGid(DetectEngineCtx *de_ctx, uint32_t sid, uint32_t gid)
Find a specific signature by sid and gid.
@ 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)
uint32_t id
SigMatch * DetectGetLastSMByListId(const Signature *s, int list_id,...)
Returns the sm with the largest index (added last) from the list passed to us as an id.
DetectParseRegex * DetectSetupPCRE2(const char *parse_str, int opts)
int DetectParsePcreExec(DetectParseRegex *parse_regex, pcre2_match_data **match, const char *str, int start_offset, int options)
SigMatch * SCSigMatchAppendSMToList(DetectEngineCtx *de_ctx, Signature *s, uint16_t type, SigMatchCtx *ctx, const int list)
Append a SigMatch to the list type.
void SigMatchRemoveSMFromList(Signature *s, SigMatch *sm, int sm_list)
void SigMatchFree(DetectEngineCtx *de_ctx, SigMatch *sm)
free a SigMatch
DetectThresholdData * DetectThresholdDataCopy(DetectThresholdData *de)
Make a deep-copy of an extant DetectTHresholdData object.
#define TH_ACTION_SDROP
#define TYPE_SUPPRESS
#define TH_ACTION_REJECT
#define TYPE_BOTH
#define TYPE_LIMIT
#define TH_ACTION_PASS
#define TH_ACTION_ALERT
#define TRACK_RULE
#define TYPE_RATE
#define TRACK_FLOW
#define TRACK_BOTH
#define TH_ACTION_DROP
#define TYPE_THRESHOLD
#define TH_ACTION_LOG
#define TRACK_EITHER
void SigMatchSignatures(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Packet *p)
wrapper for old tests
Definition detect.c:2420
#define DE_QUIET
Definition detect.h:330
@ DETECT_SM_LIST_THRESHOLD
Definition detect.h:133
@ DETECT_SM_LIST_SUPPRESS
Definition detect.h:132
SCMutex m
Definition flow-hash.h:6
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.
#define FAIL_IF_NOT_NULL(expr)
Fail a test if expression evaluates to non-NULL.
void ThresholdInit(void)
void ThresholdDestroy(void)
@ RUNMODE_CONF_TEST
Definition runmodes.h:54
main detection engine ctx
Definition detect.h:932
uint32_t tenant_id
Definition detect.h:939
uint8_t flags
Definition detect.h:934
Signature * sig_list
Definition detect.h:941
char config_prefix[64]
Definition detect.h:1051
DetectAddressHead addrs
uint16_t cnt
Definition decode.h:287
SCTime_t ts
Definition decode.h:555
uint8_t action
Definition decode.h:609
PacketAlerts alerts
Definition decode.h:620
Used to start a pointer to SigMatch context Should never be dereferenced without casting to something...
Definition detect.h:351
Data needed for Match()
Definition detect.h:365
SigMatchCtx * ctx
Definition detect.h:368
a single match condition for a signature
Definition detect.h:356
Signature container.
Definition detect.h:668
uint8_t action
Definition detect.h:683
SigIntId iid
Definition detect.h:680
uint32_t id
Definition detect.h:713
struct Signature_ * next
Definition detect.h:750
SigMatchData * sm_arrays[DETECT_SM_LIST_MAX]
Definition detect.h:731
uint32_t gid
Definition detect.h:714
Per thread variable structure.
Definition threadvars.h:58
#define BUG_ON(x)
SCRunMode SCRunmodeGet(void)
Get the current run mode.
Definition suricata.c:279
int StringParseUint32(uint32_t *res, int base, size_t len, const char *str)
Definition util-byte.c:313
#define FatalError(...)
Definition util-debug.h:510
#define SCLogDebug(...)
Definition util-debug.h:275
#define SCLogWarning(...)
Macro used to log WARNING messages.
Definition util-debug.h:255
#define SCLogInfo(...)
Macro used to log INFORMATIONAL messages.
Definition util-debug.h:225
#define SCLogError(...)
Macro used to log ERROR messages.
Definition util-debug.h:267
#define SCFmemopen
#define SCFree(p)
Definition util-mem.h:61
#define SCCalloc(nm, sz)
Definition util-mem.h:53
#define unlikely(expr)
#define DETECT_SUPPRESS_REGEX
#define THRESHOLD_CONF_DEF_CONF_FILEPATH
int SCThresholdConfParseFile(DetectEngineCtx *de_ctx, FILE *fp)
Parses the Threshold Config file.
#define DETECT_RATE_REGEX
#define DETECT_THRESHOLD_REGEX
int SCThresholdConfInitContext(DetectEngineCtx *de_ctx)
Inits the context to be used by the Threshold Config parsing API.
#define DETECT_BASE_REGEX
void SCThresholdConfGlobalInit(void)
void SCThresholdConfRegisterTests(void)
This function registers unit tests for Classification Config API.
@ THRESHOLD_TYPE_EVENT_FILTER
@ THRESHOLD_TYPE_THRESHOLD
@ THRESHOLD_TYPE_RATE
@ THRESHOLD_TYPE_SUPPRESS
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
Packet * UTHBuildPacket(uint8_t *payload, uint16_t payload_len, uint8_t ipproto)
UTHBuildPacket is a wrapper that build packets with default ip and port fields.
Packet * UTHBuildPacketSrcDst(uint8_t *payload, uint16_t payload_len, uint8_t ipproto, const char *src, const char *dst)
UTHBuildPacketSrcDst is a wrapper that build packets specifying IPs and defaulting ports.
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...
void UTHFreePacket(Packet *p)
UTHFreePacket: function to release the allocated data from UTHBuildPacket and the packet itself.