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