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