124
* \brief Search for a threshold data into threshold hash table
126
* \param de_ctx Dectection Context
127
* \param tsh_ptr Threshold element
128
* \param p Packet structure
130
* \retval lookup_tsh Return the threshold element
132
DetectThresholdEntry *ThresholdHashSearch(DetectEngineCtx *de_ctx, DetectThresholdEntry *tsh_ptr, Packet *p)
136
DetectThresholdEntry *lookup_tsh = NULL;
138
SCLogDebug("tsh_ptr->track %u", tsh_ptr->track);
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));
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));
154
SCLogDebug("no track, weird");
157
SCReturnPtr(lookup_tsh, "DetectThresholdEntry");
161
125
* \brief Remove timeout threshold hash elements
163
127
* \param de_ctx Dectection Context
167
/** \todo In some conditions HashListtableRemove returns at dt->array = NULL
168
* Must need to check it
171
static inline void ThresholdTimeoutRemove(DetectEngineCtx *de_ctx, struct timeval *tv)
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);
179
DetectThresholdEntry *tsh = HashListTableGetListData(buck);
183
if ((tv->tv_sec - tsh->tv_sec1) <= tsh->seconds)
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));
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));
214
* \brief Add threshold element into hash table
216
* \param de_ctx Dectection Context
217
* \param tsh_ptr Threshold element
218
* \param p Packet structure
221
void ThresholdHashAdd(DetectEngineCtx *de_ctx, DetectThresholdEntry *tsh_ptr, Packet *p)
227
switch(tsh_ptr->ipv) {
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));
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));
248
SCLogError(SC_ERR_THRESHOLD_HASH_ADD,
249
"failed to add element into the hash table");
255
static inline DetectThresholdEntry *DetectThresholdEntryAlloc(DetectThresholdData *td, Packet *p, Signature *s) {
131
int ThresholdTimeoutCheck(Host *host, struct timeval *tv)
133
DetectThresholdEntry *tde = NULL;
134
DetectThresholdEntry *tmp = NULL;
135
DetectThresholdEntry *prev = NULL;
138
if (host->threshold == NULL)
141
tmp = host->threshold;
144
while (tmp != NULL) {
145
if ((tv->tv_sec - tmp->tv_sec1) <= tmp->seconds) {
155
prev->next = tmp->next;
162
host->threshold = tmp->next;
174
static inline DetectThresholdEntry *DetectThresholdEntryAlloc(DetectThresholdData *td, Packet *p, uint32_t sid, uint32_t gid) {
258
177
DetectThresholdEntry *ste = SCMalloc(sizeof(DetectThresholdEntry));
281
189
SCReturnPtr(ste, "DetectThresholdEntry");
285
* \brief Make the threshold logic for signatures
287
* \param de_ctx Dectection Context
288
* \param tsh_ptr Threshold element
289
* \param p Packet structure
290
* \param s Signature structure
292
* \retval 1 alert on this event
293
* \retval 0 do not alert on this event
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)
194
DetectThresholdEntry *e;
196
for (e = h->threshold; e != NULL; e = e->next) {
197
if (e->sid == sid && e->gid == gid)
204
int ThresholdHandlePacketHost(Host *h, Packet *p, DetectThresholdData *td, uint32_t sid, uint32_t gid) {
301
DetectThresholdEntry *lookup_tsh = NULL;
302
DetectThresholdEntry ste;
308
/* setup the Entry we use to search our hash with */
311
else if (PKT_IS_IPV6(p))
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);
326
ste.track = td->track;
327
ste.seconds = td->seconds;
329
SCMutexLock(&de_ctx->ths_ctx.threshold_table_lock);
207
DetectThresholdEntry *lookup_tsh = ThresholdHostLookupEntry(h, sid, gid);
208
SCLogDebug("lookup_tsh %p sid %u gid %u", lookup_tsh, sid, gid);
330
210
switch(td->type) {
333
213
SCLogDebug("limit");
335
lookup_tsh = ThresholdHashSearch(de_ctx, &ste, p);
336
SCLogDebug("lookup_tsh %p", lookup_tsh);
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++;
219
if (lookup_tsh->current_count <= td->count) {
343
lookup_tsh->current_count++;
345
223
lookup_tsh->tv_sec1 = p->ts.tv_sec;
346
224
lookup_tsh->current_count = 1;
403
280
SCLogDebug("both");
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 */
408
286
lookup_tsh->current_count++;
409
287
if (lookup_tsh->current_count == td->count) {
291
/* expired, so reset */
413
292
lookup_tsh->tv_sec1 = p->ts.tv_sec;
414
293
lookup_tsh->current_count = 1;
295
/* if we have a limit of 1, this is a match */
296
if (lookup_tsh->current_count == td->count) {
417
DetectThresholdEntry *e = DetectThresholdEntryAlloc(td, p, s);
301
DetectThresholdEntry *e = DetectThresholdEntryAlloc(td, p, sid, gid);
422
306
e->current_count = 1;
423
307
e->tv_sec1 = p->ts.tv_sec;
426
ThresholdHashAdd(de_ctx, e, p);
309
e->next = h->threshold;
428
312
/* for the first match we return 1 to
429
313
* indicate we should alert */
439
323
SCLogDebug("detection_filter");
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));
329
if (time_diff < td->seconds) {
444
332
lookup_tsh->current_count++;
445
if (lookup_tsh->current_count >= td->count) {
333
if (lookup_tsh->current_count > td->count) {
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;
453
if (td->count == 1) {
457
DetectThresholdEntry *e = DetectThresholdEntryAlloc(td, p, s);
344
DetectThresholdEntry *e = DetectThresholdEntryAlloc(td, p, sid, gid);
462
349
e->current_count = 1;
463
350
e->tv_sec1 = p->ts.tv_sec;
351
e->tv_usec1 = p->ts.tv_usec;
466
ThresholdHashAdd(de_ctx, e, p);
353
e->next = h->threshold;
473
361
SCLogDebug("rate_filter");
475
/* tracking by src/dst or by rule? */
476
if (td->track != TRACK_RULE)
477
lookup_tsh = ThresholdHashSearch(de_ctx, &ste, p);
479
lookup_tsh = (DetectThresholdEntry *)de_ctx->ths_ctx.th_entry[s->num];
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 */
488
/* Already matching */
489
/* Take the action to perform */
490
switch (td->new_action) {
491
case TH_ACTION_ALERT:
497
case TH_ACTION_REJECT:
504
/* Weird, leave the default action */
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
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:
525
case TH_ACTION_REJECT:
532
/* Weird, leave the default action */
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;
373
/* Already matching */
374
/* Take the action to perform */
375
switch (td->new_action) {
376
case TH_ACTION_ALERT:
382
case TH_ACTION_REJECT:
389
/* Weird, leave the default action */
393
} /* else - if ((p->ts.tv_sec - lookup_tsh->tv_timeout) > td->timeout) */
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
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:
411
case TH_ACTION_REJECT:
418
/* Weird, leave the default action */
424
lookup_tsh->tv_sec1 = p->ts.tv_sec;
425
lookup_tsh->current_count = 1;
538
lookup_tsh->tv_sec1 = p->ts.tv_sec;
539
lookup_tsh->current_count = 1;
427
} /* else - if (lookup_tsh->tv_timeout != 0) */
542
429
if (td->count == 1) {
546
DetectThresholdEntry *e = DetectThresholdEntryAlloc(td, p, s);
433
DetectThresholdEntry *e = DetectThresholdEntryAlloc(td, p, sid, gid);
585
468
SCLogError(SC_ERR_INVALID_VALUE, "type %d is not supported", td->type);
588
/* handle timing out entries */
589
ThresholdTimeoutRemove(de_ctx, &p->ts);
591
SCMutexUnlock(&de_ctx->ths_ctx.threshold_table_lock);
474
static int ThresholdHandlePacketRule(DetectEngineCtx *de_ctx, Packet *p, DetectThresholdData *td, Signature *s) {
477
if (td->type != TYPE_RATE)
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 */
488
/* Already matching */
489
/* Take the action to perform */
490
switch (td->new_action) {
491
case TH_ACTION_ALERT:
497
case TH_ACTION_REJECT:
504
/* Weird, leave the default action */
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
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:
525
case TH_ACTION_REJECT:
532
/* Weird, leave the default action */
538
lookup_tsh->tv_sec1 = p->ts.tv_sec;
539
lookup_tsh->current_count = 1;
542
if (td->count == 1) {
546
DetectThresholdEntry *e = DetectThresholdEntryAlloc(td, p, s->id, s->gid);
548
e->current_count = 1;
549
e->tv_sec1 = p->ts.tv_sec;
552
de_ctx->ths_ctx.th_entry[s->num] = e;
560
* \brief Make the threshold logic for signatures
562
* \param de_ctx Dectection Context
563
* \param tsh_ptr Threshold element
564
* \param p Packet structure
565
* \param s Signature structure
567
* \retval 1 alert on this event
568
* \retval 0 do not alert on this event
570
int PacketAlertThreshold(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx,
571
DetectThresholdData *td, Packet *p, Signature *s)
580
if (td->track == TRACK_SRC) {
581
Host *src = HostGetHostFromHash(&p->src);
583
ret = ThresholdHandlePacketHost(src,p,td,s->id,s->gid);
586
} else if (td->track == TRACK_DST) {
587
Host *dst = HostGetHostFromHash(&p->dst);
589
ret = ThresholdHandlePacketHost(dst,p,td,s->id,s->gid);
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);
592
598
SCReturnInt(ret);
595
void ThresholdFreeFunc(void *data)
603
* \brief Compare elements into the hash table
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
610
* \retval 1 Match or 0 No Match
612
char ThresholdCompareFunc(void *data1, uint16_t len1, void *data2,uint16_t len2)
616
DetectThresholdEntry *a = (DetectThresholdEntry *)data1;
617
DetectThresholdEntry *b = (DetectThresholdEntry *)data2;
619
if ((a->sid == b->sid) && (a->gid == b->gid) &&
620
(CMP_ADDR(&a->addr,&b->addr)))
629
* \brief Create the hash for threshold tables
631
* \param ht Hash Table
632
* \param data Data that will be used to create the hash
633
* \param datalen Data length
635
* \retval hash the hash
637
uint32_t ThresholdHashFunc(HashListTable *ht, void *data, uint16_t datalen)
641
DetectThresholdEntry *dt = (DetectThresholdEntry *)data;
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]);
652
SCLogDebug("no dt->ipv");
655
SCReturnInt(hash % THRESHOLD_HASH_SIZE);
659
602
* \brief Init threshold context hash tables
664
607
void ThresholdHashInit(DetectEngineCtx *de_ctx)
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) {
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.");
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.");
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.");
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.");
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.");
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.");