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