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