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