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