Coverage Report

Created: 2025-11-16 07:09

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