~ubuntu-branches/ubuntu/utopic/suricata/utopic

« back to all changes in this revision

Viewing changes to src/detect-engine-threshold.c

  • Committer: Package Import Robot
  • Author(s): Pierre Chifflier
  • Date: 2012-07-22 22:27:36 UTC
  • mfrom: (1.1.13)
  • Revision ID: package-import@ubuntu.com-20120722222736-s2bcw3ruzenagjam
Tags: 1.3-1
* Imported Upstream version 1.3
* Add build-dependency on libnss3-dev and libnspr4-dev
* Bump Standards Version to 3.9.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
39
39
#include "debug.h"
40
40
#include "detect.h"
41
41
#include "flow.h"
 
42
#include "host.h"
42
43
 
43
44
#include "detect-parse.h"
44
45
#include "detect-engine-sigorder.h"
83
84
        return NULL;
84
85
 
85
86
    if (*psm == NULL) {
86
 
        sm = sig->sm_lists_tail[DETECT_SM_LIST_MATCH];
 
87
        sm = sig->sm_lists_tail[DETECT_SM_LIST_THRESHOLD];
87
88
    } else {
88
89
        /* Iteration in progress, using provided value */
89
90
        sm = *psm;
121
122
}
122
123
 
123
124
/**
124
 
 * \brief Search for a threshold data into threshold hash table
125
 
 *
126
 
 * \param de_ctx Dectection Context
127
 
 * \param tsh_ptr Threshold element
128
 
 * \param p Packet structure
129
 
 *
130
 
 * \retval lookup_tsh Return the threshold element
131
 
 */
132
 
DetectThresholdEntry *ThresholdHashSearch(DetectEngineCtx *de_ctx, DetectThresholdEntry *tsh_ptr, Packet *p)
133
 
{
134
 
    SCEnter();
135
 
 
136
 
    DetectThresholdEntry *lookup_tsh = NULL;
137
 
 
138
 
    SCLogDebug("tsh_ptr->track %u", tsh_ptr->track);
139
 
 
140
 
    if (tsh_ptr->track == TRACK_DST) {
141
 
        if (PKT_IS_IPV4(p)) {
142
 
            SCLogDebug("ipv4 dst");
143
 
            lookup_tsh = HashListTableLookup(de_ctx->ths_ctx.threshold_hash_table_dst, tsh_ptr, sizeof(DetectThresholdEntry));
144
 
        } else if (PKT_IS_IPV6(p)) {
145
 
            lookup_tsh = HashListTableLookup(de_ctx->ths_ctx.threshold_hash_table_dst_ipv6, tsh_ptr, sizeof(DetectThresholdEntry));
146
 
        }
147
 
    } else if (tsh_ptr->track == TRACK_SRC) {
148
 
        if (PKT_IS_IPV4(p)) {
149
 
            SCLogDebug("ipv4 src");
150
 
            lookup_tsh = HashListTableLookup(de_ctx->ths_ctx.threshold_hash_table_src, tsh_ptr, sizeof(DetectThresholdEntry));
151
 
        } else if (PKT_IS_IPV6(p))
152
 
            lookup_tsh = HashListTableLookup(de_ctx->ths_ctx.threshold_hash_table_src_ipv6, tsh_ptr, sizeof(DetectThresholdEntry));
153
 
    } else {
154
 
        SCLogDebug("no track, weird");
155
 
    }
156
 
 
157
 
    SCReturnPtr(lookup_tsh, "DetectThresholdEntry");
158
 
}
159
 
 
160
 
/**
161
125
 * \brief Remove timeout threshold hash elements
162
126
 *
163
127
 * \param de_ctx Dectection Context
164
128
 *
165
129
 */
166
130
 
167
 
/** \todo In some conditions HashListtableRemove returns at dt->array = NULL
168
 
 *  Must need to check it
169
 
 **/
170
 
 
171
 
static inline void ThresholdTimeoutRemove(DetectEngineCtx *de_ctx, struct timeval *tv)
172
 
{
173
 
    HashListTableBucket *next = NULL;
174
 
    HashListTableBucket *buck = HashListTableGetListHead(de_ctx->ths_ctx.threshold_hash_table_src);
175
 
    while (buck != NULL) {
176
 
        /* get the next before we free "buck" */
177
 
        next = HashListTableGetListNext(buck);
178
 
 
179
 
        DetectThresholdEntry *tsh = HashListTableGetListData(buck);
180
 
        if (tsh == NULL)
181
 
            goto next;
182
 
 
183
 
        if ((tv->tv_sec - tsh->tv_sec1) <= tsh->seconds)
184
 
            goto next;
185
 
 
186
 
        switch(tsh->ipv) {
187
 
            case 4:
188
 
                if (tsh->track == TRACK_SRC) {
189
 
                    HashListTableRemove(de_ctx->ths_ctx.threshold_hash_table_src,
190
 
                            tsh, sizeof(DetectThresholdEntry));
191
 
                } else if (tsh->track == TRACK_DST) {
192
 
                    HashListTableRemove(de_ctx->ths_ctx.threshold_hash_table_dst,
193
 
                            tsh, sizeof(DetectThresholdEntry));
194
 
                }
195
 
                break;
196
 
            case 6:
197
 
                if (tsh->track == TRACK_SRC) {
198
 
                    HashListTableRemove(de_ctx->ths_ctx.threshold_hash_table_src_ipv6,
199
 
                            tsh, sizeof(DetectThresholdEntry));
200
 
                } else if (tsh->track == TRACK_DST) {
201
 
                    HashListTableRemove(de_ctx->ths_ctx.threshold_hash_table_dst_ipv6,
202
 
                            tsh, sizeof(DetectThresholdEntry));
203
 
                }
204
 
                break;
205
 
        }
206
 
    next:
207
 
        buck = next;
208
 
    }
209
 
 
210
 
    return;
211
 
}
212
 
 
213
 
/**
214
 
 * \brief Add threshold element into hash table
215
 
 *
216
 
 * \param de_ctx Dectection Context
217
 
 * \param tsh_ptr Threshold element
218
 
 * \param p Packet structure
219
 
 *
220
 
 */
221
 
void ThresholdHashAdd(DetectEngineCtx *de_ctx, DetectThresholdEntry *tsh_ptr, Packet *p)
222
 
{
223
 
    SCEnter();
224
 
 
225
 
    int ret = 0;
226
 
 
227
 
    switch(tsh_ptr->ipv) {
228
 
        case 4:
229
 
            if (tsh_ptr->track == TRACK_DST) {
230
 
                ret = HashListTableAdd(de_ctx->ths_ctx.threshold_hash_table_dst,
231
 
                        tsh_ptr, sizeof(DetectThresholdEntry));
232
 
            } else if (tsh_ptr->track == TRACK_SRC) {
233
 
                ret = HashListTableAdd(de_ctx->ths_ctx.threshold_hash_table_src,
234
 
                        tsh_ptr, sizeof(DetectThresholdEntry));
235
 
            }
236
 
            break;
237
 
        case 6:
238
 
            if (tsh_ptr->track == TRACK_DST)
239
 
                ret = HashListTableAdd(de_ctx->ths_ctx.threshold_hash_table_dst_ipv6,
240
 
                        tsh_ptr, sizeof(DetectThresholdEntry));
241
 
            else if (tsh_ptr->track == TRACK_SRC)
242
 
                ret =  HashListTableAdd(de_ctx->ths_ctx.threshold_hash_table_src_ipv6,
243
 
                        tsh_ptr, sizeof(DetectThresholdEntry));
244
 
            break;
245
 
    }
246
 
 
247
 
    if(ret == -1)   {
248
 
        SCLogError(SC_ERR_THRESHOLD_HASH_ADD,
249
 
                "failed to add element into the hash table");
250
 
    }
251
 
 
252
 
    SCReturn;
253
 
}
254
 
 
255
 
static inline DetectThresholdEntry *DetectThresholdEntryAlloc(DetectThresholdData *td, Packet *p, Signature *s) {
 
131
int ThresholdTimeoutCheck(Host *host, struct timeval *tv)
 
132
{
 
133
    DetectThresholdEntry *tde = NULL;
 
134
    DetectThresholdEntry *tmp = NULL;
 
135
    DetectThresholdEntry *prev = NULL;
 
136
    int retval = 1;
 
137
 
 
138
    if (host->threshold == NULL)
 
139
        return 1;
 
140
 
 
141
    tmp = host->threshold;
 
142
 
 
143
    prev = NULL;
 
144
    while (tmp != NULL) {
 
145
        if ((tv->tv_sec - tmp->tv_sec1) <= tmp->seconds) {
 
146
            prev = tmp;
 
147
            tmp = tmp->next;
 
148
            retval = 0;
 
149
            continue;
 
150
        }
 
151
 
 
152
        /* timed out */
 
153
 
 
154
        if (prev != NULL) {
 
155
            prev->next = tmp->next;
 
156
 
 
157
            tde = tmp;
 
158
            tmp = tde->next;
 
159
 
 
160
            SCFree(tde);
 
161
        } else {
 
162
            host->threshold = tmp->next;
 
163
 
 
164
            tde = tmp;
 
165
            tmp = tde->next;
 
166
 
 
167
            SCFree(tde);
 
168
        }
 
169
    }
 
170
 
 
171
    return retval;
 
172
}
 
173
 
 
174
static inline DetectThresholdEntry *DetectThresholdEntryAlloc(DetectThresholdData *td, Packet *p, uint32_t sid, uint32_t gid) {
256
175
    SCEnter();
257
176
 
258
177
    DetectThresholdEntry *ste = SCMalloc(sizeof(DetectThresholdEntry));
260
179
        SCReturnPtr(NULL, "DetectThresholdEntry");
261
180
    }
262
181
 
263
 
    if (PKT_IS_IPV4(p))
264
 
        ste->ipv = 4;
265
 
    else if (PKT_IS_IPV6(p))
266
 
        ste->ipv = 6;
267
 
 
268
 
    ste->sid = s->id;
269
 
    ste->gid = s->gid;
270
 
 
271
 
    if (td->track == TRACK_DST) {
272
 
        COPY_ADDRESS(&p->dst, &ste->addr);
273
 
    } else if (td->track == TRACK_SRC) {
274
 
        COPY_ADDRESS(&p->src, &ste->addr);
275
 
    }
 
182
    ste->sid = sid;
 
183
    ste->gid = gid;
276
184
 
277
185
    ste->track = td->track;
278
186
    ste->seconds = td->seconds;
281
189
    SCReturnPtr(ste, "DetectThresholdEntry");
282
190
}
283
191
 
284
 
/**
285
 
 * \brief Make the threshold logic for signatures
286
 
 *
287
 
 * \param de_ctx Dectection Context
288
 
 * \param tsh_ptr Threshold element
289
 
 * \param p Packet structure
290
 
 * \param s Signature structure
291
 
 *
292
 
 * \retval 1 alert on this event
293
 
 * \retval 0 do not alert on this event
294
 
 */
295
 
int PacketAlertThreshold(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx,
296
 
        DetectThresholdData *td, Packet *p, Signature *s)
 
192
static DetectThresholdEntry *ThresholdHostLookupEntry(Host *h, uint32_t sid, uint32_t gid)
297
193
{
298
 
    SCEnter();
299
 
 
 
194
    DetectThresholdEntry *e;
 
195
 
 
196
    for (e = h->threshold; e != NULL; e = e->next) {
 
197
        if (e->sid == sid && e->gid == gid)
 
198
            break;
 
199
    }
 
200
 
 
201
    return e;
 
202
}
 
203
 
 
204
int ThresholdHandlePacketHost(Host *h, Packet *p, DetectThresholdData *td, uint32_t sid, uint32_t gid) {
300
205
    int ret = 0;
301
 
    DetectThresholdEntry *lookup_tsh = NULL;
302
 
    DetectThresholdEntry ste;
303
 
 
304
 
    if (td == NULL) {
305
 
        SCReturnInt(0);
306
 
    }
307
 
 
308
 
    /* setup the Entry we use to search our hash with */
309
 
    if (PKT_IS_IPV4(p))
310
 
        ste.ipv = 4;
311
 
    else if (PKT_IS_IPV6(p))
312
 
        ste.ipv = 6;
313
 
    else {
314
 
        SCReturnInt(0);
315
 
    }
316
 
 
317
 
    ste.sid = s->id;
318
 
    ste.gid = s->gid;
319
 
 
320
 
    if (td->track == TRACK_DST) {
321
 
        COPY_ADDRESS(&p->dst, &ste.addr);
322
 
    } else if (td->track == TRACK_SRC) {
323
 
        COPY_ADDRESS(&p->src, &ste.addr);
324
 
    }
325
 
 
326
 
    ste.track = td->track;
327
 
    ste.seconds = td->seconds;
328
 
 
329
 
    SCMutexLock(&de_ctx->ths_ctx.threshold_table_lock);
 
206
 
 
207
    DetectThresholdEntry *lookup_tsh = ThresholdHostLookupEntry(h, sid, gid);
 
208
    SCLogDebug("lookup_tsh %p sid %u gid %u", lookup_tsh, sid, gid);
 
209
 
330
210
    switch(td->type)   {
331
211
        case TYPE_LIMIT:
332
212
        {
333
213
            SCLogDebug("limit");
334
214
 
335
 
            lookup_tsh = ThresholdHashSearch(de_ctx, &ste, p);
336
 
            SCLogDebug("lookup_tsh %p", lookup_tsh);
337
 
 
338
215
            if (lookup_tsh != NULL)  {
339
216
                if ((p->ts.tv_sec - lookup_tsh->tv_sec1) < td->seconds) {
340
 
                    if (lookup_tsh->current_count < td->count) {
 
217
                    lookup_tsh->current_count++;
 
218
 
 
219
                    if (lookup_tsh->current_count <= td->count) {
341
220
                        ret = 1;
342
221
                    }
343
 
                    lookup_tsh->current_count++;
344
222
                } else    {
345
223
                    lookup_tsh->tv_sec1 = p->ts.tv_sec;
346
224
                    lookup_tsh->current_count = 1;
348
226
                    ret = 1;
349
227
                }
350
228
            } else {
351
 
                DetectThresholdEntry *e = DetectThresholdEntryAlloc(td, p, s);
 
229
                DetectThresholdEntry *e = DetectThresholdEntryAlloc(td, p, sid, gid);
352
230
                if (e == NULL) {
353
231
                    break;
354
232
                }
355
233
 
356
234
                e->tv_sec1 = p->ts.tv_sec;
357
235
                e->current_count = 1;
358
 
                e->ipv = ste.ipv;
359
236
 
360
237
                ret = 1;
361
238
 
362
 
                ThresholdHashAdd(de_ctx, e, p);
 
239
                e->next = h->threshold;
 
240
                h->threshold = e;
363
241
            }
364
242
            break;
365
243
        }
367
245
        {
368
246
            SCLogDebug("threshold");
369
247
 
370
 
            lookup_tsh = ThresholdHashSearch(de_ctx, &ste, p);
371
248
            if (lookup_tsh != NULL)  {
372
249
                if ((p->ts.tv_sec - lookup_tsh->tv_sec1) < td->seconds) {
373
250
                    lookup_tsh->current_count++;
384
261
                if (td->count == 1)  {
385
262
                    ret = 1;
386
263
                } else {
387
 
                    DetectThresholdEntry *e = DetectThresholdEntryAlloc(td, p, s);
 
264
                    DetectThresholdEntry *e = DetectThresholdEntryAlloc(td, p, sid, gid);
388
265
                    if (e == NULL) {
389
266
                        break;
390
267
                    }
391
268
 
392
269
                    e->current_count = 1;
393
270
                    e->tv_sec1 = p->ts.tv_sec;
394
 
                    e->ipv = ste.ipv;
395
271
 
396
 
                    ThresholdHashAdd(de_ctx, e, p);
 
272
                    e->next = h->threshold;
 
273
                    h->threshold = e;
397
274
                }
398
275
            }
399
276
            break;
402
279
        {
403
280
            SCLogDebug("both");
404
281
 
405
 
            lookup_tsh = ThresholdHashSearch(de_ctx, &ste, p);
406
282
            if (lookup_tsh != NULL) {
407
283
                if ((p->ts.tv_sec - lookup_tsh->tv_sec1) < td->seconds) {
 
284
                    /* within time limit */
 
285
 
408
286
                    lookup_tsh->current_count++;
409
287
                    if (lookup_tsh->current_count == td->count) {
410
288
                        ret = 1;
411
289
                    }
412
 
                } else    {
 
290
                } else {
 
291
                    /* expired, so reset */
413
292
                    lookup_tsh->tv_sec1 = p->ts.tv_sec;
414
293
                    lookup_tsh->current_count = 1;
 
294
 
 
295
                    /* if we have a limit of 1, this is a match */
 
296
                    if (lookup_tsh->current_count == td->count) {
 
297
                        ret = 1;
 
298
                    }
415
299
                }
416
300
            } else {
417
 
                DetectThresholdEntry *e = DetectThresholdEntryAlloc(td, p, s);
 
301
                DetectThresholdEntry *e = DetectThresholdEntryAlloc(td, p, sid, gid);
418
302
                if (e == NULL) {
419
303
                    break;
420
304
                }
421
305
 
422
306
                e->current_count = 1;
423
307
                e->tv_sec1 = p->ts.tv_sec;
424
 
                e->ipv = ste.ipv;
425
308
 
426
 
                ThresholdHashAdd(de_ctx, e, p);
 
309
                e->next = h->threshold;
 
310
                h->threshold = e;
427
311
 
428
312
                /* for the first match we return 1 to
429
313
                 * indicate we should alert */
438
322
        {
439
323
            SCLogDebug("detection_filter");
440
324
 
441
 
            lookup_tsh = ThresholdHashSearch(de_ctx, &ste, p);
442
325
            if (lookup_tsh != NULL) {
443
 
                if ((p->ts.tv_sec - lookup_tsh->tv_sec1) < td->seconds) {
 
326
                long double time_diff = ((p->ts.tv_sec + p->ts.tv_usec/1000000.0) -
 
327
                                         (lookup_tsh->tv_sec1 + lookup_tsh->tv_usec1/1000000.0));
 
328
 
 
329
                if (time_diff < td->seconds) {
 
330
                    /* within timeout */
 
331
 
444
332
                    lookup_tsh->current_count++;
445
 
                    if (lookup_tsh->current_count >= td->count) {
 
333
                    if (lookup_tsh->current_count > td->count) {
446
334
                        ret = 1;
447
335
                    }
448
336
                } else {
 
337
                    /* expired, reset */
 
338
 
449
339
                    lookup_tsh->tv_sec1 = p->ts.tv_sec;
 
340
                    lookup_tsh->tv_usec1 = p->ts.tv_usec;
450
341
                    lookup_tsh->current_count = 1;
451
342
                }
452
343
            } else {
453
 
                if (td->count == 1) {
454
 
                    ret = 1;
455
 
                }
456
 
 
457
 
                DetectThresholdEntry *e = DetectThresholdEntryAlloc(td, p, s);
 
344
                DetectThresholdEntry *e = DetectThresholdEntryAlloc(td, p, sid, gid);
458
345
                if (e == NULL) {
459
346
                    break;
460
347
                }
461
348
 
462
349
                e->current_count = 1;
463
350
                e->tv_sec1 = p->ts.tv_sec;
464
 
                e->ipv = ste.ipv;
 
351
                e->tv_usec1 = p->ts.tv_usec;
465
352
 
466
 
                ThresholdHashAdd(de_ctx, e, p);
 
353
                e->next = h->threshold;
 
354
                h->threshold = e;
467
355
            }
468
356
            break;
469
357
        }
472
360
        {
473
361
            SCLogDebug("rate_filter");
474
362
 
475
 
            /* tracking by src/dst or by rule? */
476
 
            if (td->track != TRACK_RULE)
477
 
                lookup_tsh = ThresholdHashSearch(de_ctx, &ste, p);
478
 
            else
479
 
                lookup_tsh = (DetectThresholdEntry *)de_ctx->ths_ctx.th_entry[s->num];
 
363
            ret = 1;
480
364
 
481
365
            if (lookup_tsh != NULL) {
482
366
                /* Check if we have a timeout enabled, if so,
483
367
                 * we still matching (and enabling the new_action) */
484
 
                if ( (p->ts.tv_sec - lookup_tsh->tv_timeout) > td->timeout) {
485
 
                    /* Ok, we are done, timeout reached */
486
 
                    td->timeout = 0;
487
 
                } else {
488
 
                    /* Already matching */
489
 
                    /* Take the action to perform */
490
 
                    switch (td->new_action) {
491
 
                        case TH_ACTION_ALERT:
492
 
                            ALERT_PACKET(p);
493
 
                            break;
494
 
                        case TH_ACTION_DROP:
495
 
                            DROP_PACKET(p);
496
 
                            break;
497
 
                        case TH_ACTION_REJECT:
498
 
                            REJECT_PACKET(p);
499
 
                            break;
500
 
                        case TH_ACTION_PASS:
501
 
                            PASS_PACKET(p);
502
 
                            break;
503
 
                        default:
504
 
                            /* Weird, leave the default action */
505
 
                            break;
506
 
                    }
507
 
                    ret = 1;
508
 
                }
509
 
 
510
 
                /* Update the matching state with the timeout interval */
511
 
                if ( (p->ts.tv_sec - lookup_tsh->tv_sec1) < td->seconds) {
512
 
                    lookup_tsh->current_count++;
513
 
                    if (lookup_tsh->current_count >= td->count) {
514
 
                        /* Then we must enable the new action by setting a
515
 
                         * timeout */
516
 
                        lookup_tsh->tv_timeout = p->ts.tv_sec;
517
 
                    /* Take the action to perform */
518
 
                    switch (td->new_action) {
519
 
                        case TH_ACTION_ALERT:
520
 
                            ALERT_PACKET(p);
521
 
                            break;
522
 
                        case TH_ACTION_DROP:
523
 
                            DROP_PACKET(p);
524
 
                            break;
525
 
                        case TH_ACTION_REJECT:
526
 
                            REJECT_PACKET(p);
527
 
                            break;
528
 
                        case TH_ACTION_PASS:
529
 
                            PASS_PACKET(p);
530
 
                            break;
531
 
                        default:
532
 
                            /* Weird, leave the default action */
533
 
                            break;
534
 
                    }
 
368
                if (lookup_tsh->tv_timeout != 0) {
 
369
                    if ((p->ts.tv_sec - lookup_tsh->tv_timeout) > td->timeout) {
 
370
                        /* Ok, we are done, timeout reached */
 
371
                        lookup_tsh->tv_timeout = 0;
 
372
                    } else {
 
373
                        /* Already matching */
 
374
                        /* Take the action to perform */
 
375
                        switch (td->new_action) {
 
376
                            case TH_ACTION_ALERT:
 
377
                                ALERT_PACKET(p);
 
378
                                break;
 
379
                            case TH_ACTION_DROP:
 
380
                                DROP_PACKET(p);
 
381
                                break;
 
382
                            case TH_ACTION_REJECT:
 
383
                                REJECT_PACKET(p);
 
384
                                break;
 
385
                            case TH_ACTION_PASS:
 
386
                                PASS_PACKET(p);
 
387
                                break;
 
388
                            default:
 
389
                                /* Weird, leave the default action */
 
390
                                break;
 
391
                        }
535
392
                        ret = 1;
 
393
                    } /* else - if ((p->ts.tv_sec - lookup_tsh->tv_timeout) > td->timeout) */
 
394
 
 
395
                } else {
 
396
                    /* Update the matching state with the timeout interval */
 
397
                    if ( (p->ts.tv_sec - lookup_tsh->tv_sec1) < td->seconds) {
 
398
                        lookup_tsh->current_count++;
 
399
                        if (lookup_tsh->current_count > td->count) {
 
400
                            /* Then we must enable the new action by setting a
 
401
                             * timeout */
 
402
                            lookup_tsh->tv_timeout = p->ts.tv_sec;
 
403
                            /* Take the action to perform */
 
404
                            switch (td->new_action) {
 
405
                                case TH_ACTION_ALERT:
 
406
                                    ALERT_PACKET(p);
 
407
                                    break;
 
408
                                case TH_ACTION_DROP:
 
409
                                    DROP_PACKET(p);
 
410
                                    break;
 
411
                                case TH_ACTION_REJECT:
 
412
                                    REJECT_PACKET(p);
 
413
                                    break;
 
414
                                case TH_ACTION_PASS:
 
415
                                    PASS_PACKET(p);
 
416
                                    break;
 
417
                                default:
 
418
                                    /* Weird, leave the default action */
 
419
                                    break;
 
420
                            }
 
421
                            ret = 1;
 
422
                        }
 
423
                    } else {
 
424
                        lookup_tsh->tv_sec1 = p->ts.tv_sec;
 
425
                        lookup_tsh->current_count = 1;
536
426
                    }
537
 
                } else {
538
 
                    lookup_tsh->tv_sec1 = p->ts.tv_sec;
539
 
                    lookup_tsh->current_count = 1;
540
 
                }
 
427
                } /* else - if (lookup_tsh->tv_timeout != 0) */
541
428
            } else {
542
429
                if (td->count == 1) {
543
430
                    ret = 1;
544
431
                }
545
432
 
546
 
                DetectThresholdEntry *e = DetectThresholdEntryAlloc(td, p, s);
 
433
                DetectThresholdEntry *e = DetectThresholdEntryAlloc(td, p, sid, gid);
547
434
                if (e == NULL) {
548
435
                    break;
549
436
                }
551
438
                e->current_count = 1;
552
439
                e->tv_sec1 = p->ts.tv_sec;
553
440
                e->tv_timeout = 0;
554
 
                e->ipv = ste.ipv;
555
441
 
556
 
                /** The track is by src/dst or by rule? */
557
 
                if (td->track != TRACK_RULE)
558
 
                    ThresholdHashAdd(de_ctx, e, p);
559
 
                else
560
 
                    de_ctx->ths_ctx.th_entry[s->num] = e;
 
442
                e->next = h->threshold;
 
443
                h->threshold = e;
561
444
            }
562
445
            break;
563
446
        }
585
468
            SCLogError(SC_ERR_INVALID_VALUE, "type %d is not supported", td->type);
586
469
    }
587
470
 
588
 
    /* handle timing out entries */
589
 
    ThresholdTimeoutRemove(de_ctx, &p->ts);
590
 
 
591
 
    SCMutexUnlock(&de_ctx->ths_ctx.threshold_table_lock);
 
471
    return ret;
 
472
}
 
473
 
 
474
static int ThresholdHandlePacketRule(DetectEngineCtx *de_ctx, Packet *p, DetectThresholdData *td, Signature *s) {
 
475
    int ret = 0;
 
476
 
 
477
    if (td->type != TYPE_RATE)
 
478
        return 1;
 
479
 
 
480
    DetectThresholdEntry* lookup_tsh = (DetectThresholdEntry *)de_ctx->ths_ctx.th_entry[s->num];
 
481
    if (lookup_tsh != NULL) {
 
482
        /* Check if we have a timeout enabled, if so,
 
483
         * we still matching (and enabling the new_action) */
 
484
        if ( (p->ts.tv_sec - lookup_tsh->tv_timeout) > td->timeout) {
 
485
            /* Ok, we are done, timeout reached */
 
486
            td->timeout = 0;
 
487
        } else {
 
488
            /* Already matching */
 
489
            /* Take the action to perform */
 
490
            switch (td->new_action) {
 
491
                case TH_ACTION_ALERT:
 
492
                    ALERT_PACKET(p);
 
493
                    break;
 
494
                case TH_ACTION_DROP:
 
495
                    DROP_PACKET(p);
 
496
                    break;
 
497
                case TH_ACTION_REJECT:
 
498
                    REJECT_PACKET(p);
 
499
                    break;
 
500
                case TH_ACTION_PASS:
 
501
                    PASS_PACKET(p);
 
502
                    break;
 
503
                default:
 
504
                    /* Weird, leave the default action */
 
505
                    break;
 
506
            }
 
507
            ret = 1;
 
508
        }
 
509
 
 
510
        /* Update the matching state with the timeout interval */
 
511
        if ( (p->ts.tv_sec - lookup_tsh->tv_sec1) < td->seconds) {
 
512
            lookup_tsh->current_count++;
 
513
            if (lookup_tsh->current_count >= td->count) {
 
514
                /* Then we must enable the new action by setting a
 
515
                 * timeout */
 
516
                lookup_tsh->tv_timeout = p->ts.tv_sec;
 
517
                /* Take the action to perform */
 
518
                switch (td->new_action) {
 
519
                    case TH_ACTION_ALERT:
 
520
                        ALERT_PACKET(p);
 
521
                        break;
 
522
                    case TH_ACTION_DROP:
 
523
                        DROP_PACKET(p);
 
524
                        break;
 
525
                    case TH_ACTION_REJECT:
 
526
                        REJECT_PACKET(p);
 
527
                        break;
 
528
                    case TH_ACTION_PASS:
 
529
                        PASS_PACKET(p);
 
530
                        break;
 
531
                    default:
 
532
                        /* Weird, leave the default action */
 
533
                        break;
 
534
                }
 
535
                ret = 1;
 
536
            }
 
537
        } else {
 
538
            lookup_tsh->tv_sec1 = p->ts.tv_sec;
 
539
            lookup_tsh->current_count = 1;
 
540
        }
 
541
    } else {
 
542
        if (td->count == 1) {
 
543
            ret = 1;
 
544
        }
 
545
 
 
546
        DetectThresholdEntry *e = DetectThresholdEntryAlloc(td, p, s->id, s->gid);
 
547
        if (e != NULL) {
 
548
            e->current_count = 1;
 
549
            e->tv_sec1 = p->ts.tv_sec;
 
550
            e->tv_timeout = 0;
 
551
 
 
552
            de_ctx->ths_ctx.th_entry[s->num] = e;
 
553
        }
 
554
    }
 
555
 
 
556
    return ret;
 
557
}
 
558
 
 
559
/**
 
560
 * \brief Make the threshold logic for signatures
 
561
 *
 
562
 * \param de_ctx Dectection Context
 
563
 * \param tsh_ptr Threshold element
 
564
 * \param p Packet structure
 
565
 * \param s Signature structure
 
566
 *
 
567
 * \retval 1 alert on this event
 
568
 * \retval 0 do not alert on this event
 
569
 */
 
570
int PacketAlertThreshold(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx,
 
571
        DetectThresholdData *td, Packet *p, Signature *s)
 
572
{
 
573
    SCEnter();
 
574
 
 
575
    int ret = 0;
 
576
    if (td == NULL) {
 
577
        SCReturnInt(0);
 
578
    }
 
579
 
 
580
    if (td->track == TRACK_SRC) {
 
581
        Host *src = HostGetHostFromHash(&p->src);
 
582
        if (src) {
 
583
            ret = ThresholdHandlePacketHost(src,p,td,s->id,s->gid);
 
584
            HostRelease(src);
 
585
        }
 
586
    } else if (td->track == TRACK_DST) {
 
587
        Host *dst = HostGetHostFromHash(&p->dst);
 
588
        if (dst) {
 
589
            ret = ThresholdHandlePacketHost(dst,p,td,s->id,s->gid);
 
590
            HostRelease(dst);
 
591
        }
 
592
    } else if (td->track == TRACK_RULE) {
 
593
        SCMutexLock(&de_ctx->ths_ctx.threshold_table_lock);
 
594
        ret = ThresholdHandlePacketRule(de_ctx,p,td,s);
 
595
        SCMutexUnlock(&de_ctx->ths_ctx.threshold_table_lock);
 
596
    }
 
597
 
592
598
    SCReturnInt(ret);
593
599
}
594
600
 
595
 
void ThresholdFreeFunc(void *data)
596
 
{
597
 
    if (data != NULL)
598
 
        SCFree(data);
599
 
    return;
600
 
}
601
 
 
602
 
/**
603
 
 * \brief Compare elements into the hash table
604
 
 *
605
 
 * \param data1 First element to compare
606
 
 * \param len1 length of first element
607
 
 * \param data2 Second element to compare
608
 
 * \param len2 length of second element
609
 
 *
610
 
 * \retval 1 Match or 0 No Match
611
 
 */
612
 
char ThresholdCompareFunc(void *data1, uint16_t len1, void *data2,uint16_t len2)
613
 
{
614
 
    SCEnter();
615
 
 
616
 
    DetectThresholdEntry *a = (DetectThresholdEntry *)data1;
617
 
    DetectThresholdEntry *b = (DetectThresholdEntry *)data2;
618
 
 
619
 
    if ((a->sid == b->sid) && (a->gid == b->gid) &&
620
 
            (CMP_ADDR(&a->addr,&b->addr)))
621
 
    {
622
 
        SCReturnInt(1);
623
 
    }
624
 
 
625
 
    SCReturnInt(0);
626
 
}
627
 
 
628
 
/**
629
 
 * \brief Create the hash for threshold tables
630
 
 *
631
 
 * \param ht Hash Table
632
 
 * \param data Data that will be used to create the hash
633
 
 * \param datalen Data length
634
 
 *
635
 
 * \retval hash the hash
636
 
 */
637
 
uint32_t ThresholdHashFunc(HashListTable *ht, void *data, uint16_t datalen)
638
 
{
639
 
    SCEnter();
640
 
 
641
 
    DetectThresholdEntry *dt = (DetectThresholdEntry *)data;
642
 
    uint32_t hash = 0;
643
 
 
644
 
    if (dt->ipv == 4)
645
 
        hash = (dt->sid + dt->gid + dt->addr.addr_data32[0]);
646
 
    else if (dt->ipv == 6)
647
 
        hash = (dt->sid + dt->gid + dt->addr.addr_data32[0] +
648
 
                dt->addr.addr_data32[1] +
649
 
                dt->addr.addr_data32[2] +
650
 
                dt->addr.addr_data32[3]);
651
 
    else {
652
 
        SCLogDebug("no dt->ipv");
653
 
    }
654
 
 
655
 
    SCReturnInt(hash % THRESHOLD_HASH_SIZE);
656
 
}
657
 
 
658
601
/**
659
602
 * \brief Init threshold context hash tables
660
603
 *
663
606
 */
664
607
void ThresholdHashInit(DetectEngineCtx *de_ctx)
665
608
{
666
 
    if (de_ctx->ths_ctx.threshold_hash_table_dst == NULL ||
667
 
        de_ctx->ths_ctx.threshold_hash_table_src == NULL ||
668
 
        de_ctx->ths_ctx.threshold_hash_table_src_ipv6 == NULL ||
669
 
        de_ctx->ths_ctx.threshold_hash_table_dst_ipv6 == NULL) {
670
 
 
671
 
        de_ctx->ths_ctx.threshold_hash_table_dst = HashListTableInit(THRESHOLD_HASH_SIZE, ThresholdHashFunc, ThresholdCompareFunc, ThresholdFreeFunc);
672
 
        if(de_ctx->ths_ctx.threshold_hash_table_dst == NULL)    {
673
 
            SCLogError(SC_ERR_MEM_ALLOC,
674
 
                    "Threshold: Failed to initialize ipv4 dst hash table.");
675
 
            exit(EXIT_FAILURE);
676
 
        }
677
 
 
678
 
        de_ctx->ths_ctx.threshold_hash_table_src = HashListTableInit(THRESHOLD_HASH_SIZE, ThresholdHashFunc, ThresholdCompareFunc, ThresholdFreeFunc);
679
 
        if(de_ctx->ths_ctx.threshold_hash_table_dst == NULL)    {
680
 
            SCLogError(SC_ERR_MEM_ALLOC,
681
 
                    "Threshold: Failed to initialize ipv4 src hash table.");
682
 
            exit(EXIT_FAILURE);
683
 
        }
684
 
 
685
 
        de_ctx->ths_ctx.threshold_hash_table_src_ipv6 = HashListTableInit(THRESHOLD_HASH_SIZE, ThresholdHashFunc, ThresholdCompareFunc, ThresholdFreeFunc);
686
 
        if(de_ctx->ths_ctx.threshold_hash_table_dst == NULL)    {
687
 
            SCLogError(SC_ERR_MEM_ALLOC,
688
 
                    "Threshold: Failed to initialize ipv6 src hash table.");
689
 
            exit(EXIT_FAILURE);
690
 
        }
691
 
 
692
 
        de_ctx->ths_ctx.threshold_hash_table_dst_ipv6 = HashListTableInit(THRESHOLD_HASH_SIZE, ThresholdHashFunc, ThresholdCompareFunc, ThresholdFreeFunc);
693
 
        if(de_ctx->ths_ctx.threshold_hash_table_dst == NULL)    {
694
 
            SCLogError(SC_ERR_MEM_ALLOC,
695
 
                    "Threshold: Failed to initialize ipv6 dst hash table.");
696
 
            exit(EXIT_FAILURE);
697
 
        }
698
 
 
699
 
        if (SCMutexInit(&de_ctx->ths_ctx.threshold_table_lock, NULL) != 0) {
700
 
            SCLogError(SC_ERR_MEM_ALLOC,
701
 
                    "Threshold: Failed to initialize hash table mutex.");
702
 
            exit(EXIT_FAILURE);
703
 
        }
 
609
    if (SCMutexInit(&de_ctx->ths_ctx.threshold_table_lock, NULL) != 0) {
 
610
        SCLogError(SC_ERR_MEM_ALLOC,
 
611
                "Threshold: Failed to initialize hash table mutex.");
 
612
        exit(EXIT_FAILURE);
704
613
    }
705
614
}
706
615
 
712
621
 */
713
622
void ThresholdContextDestroy(DetectEngineCtx *de_ctx)
714
623
{
715
 
    HashListTableFree(de_ctx->ths_ctx.threshold_hash_table_dst);
716
 
    HashListTableFree(de_ctx->ths_ctx.threshold_hash_table_src);
717
 
    HashListTableFree(de_ctx->ths_ctx.threshold_hash_table_dst_ipv6);
718
 
    HashListTableFree(de_ctx->ths_ctx.threshold_hash_table_src_ipv6);
719
624
    if (de_ctx->ths_ctx.th_entry != NULL)
720
625
        SCFree(de_ctx->ths_ctx.th_entry);
 
626
    SCMutexDestroy(&de_ctx->ths_ctx.threshold_table_lock);
 
627
}
 
628
 
 
629
/**
 
630
 * \brief this function will free all the entries of a list
 
631
 *        DetectTagDataEntry
 
632
 *
 
633
 * \param td pointer to DetectTagDataEntryList
 
634
 */
 
635
void ThresholdListFree(void *ptr) {
 
636
    if (ptr != NULL) {
 
637
        DetectThresholdEntry *entry = ptr;
 
638
 
 
639
        while (entry != NULL) {
 
640
            DetectThresholdEntry *next_entry = entry->next;
 
641
            SCFree(entry);
 
642
            entry = next_entry;
 
643
        }
 
644
    }
721
645
}
722
646
 
723
647
/**