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