diff --git a/src/detect-detection-filter.c b/src/detect-detection-filter.c index 0bc2e6df54..6dd47bd535 100644 --- a/src/detect-detection-filter.c +++ b/src/detect-detection-filter.c @@ -29,6 +29,8 @@ #include "decode.h" #include "detect.h" +#include "host.h" + #include "detect-detection-filter.h" #include "detect-threshold.h" #include "detect-parse.h" @@ -404,6 +406,8 @@ static int DetectDetectionFilterTestSig1(void) { int result = 0; int alerts = 0; + HostInitConfig(HOST_QUIET); + memset(&th_v, 0, sizeof(th_v)); p = UTHBuildPacketReal(NULL, 0, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80); @@ -451,6 +455,7 @@ static int DetectDetectionFilterTestSig1(void) { end: UTHFreePackets(&p, 1); + HostShutdown(); return result; } @@ -472,6 +477,8 @@ static int DetectDetectionFilterTestSig2(void) { int alerts = 0; struct timeval ts; + HostInitConfig(HOST_QUIET); + memset (&ts, 0, sizeof(struct timeval)); TimeGet(&ts); @@ -525,6 +532,7 @@ static int DetectDetectionFilterTestSig2(void) { DetectEngineCtxFree(de_ctx); end: UTHFreePackets(&p, 1); + HostShutdown(); return result; } diff --git a/src/detect-engine-threshold.c b/src/detect-engine-threshold.c index f6e4ddbaa5..bcab9a722e 100644 --- a/src/detect-engine-threshold.c +++ b/src/detect-engine-threshold.c @@ -39,6 +39,7 @@ #include "debug.h" #include "detect.h" #include "flow.h" +#include "host.h" #include "detect-parse.h" #include "detect-engine-sigorder.h" @@ -120,43 +121,6 @@ DetectThresholdData *SigGetThresholdType(Signature *sig, Packet *p) return SigGetThresholdTypeIter(sig, p, &psm); } -/** - * \brief Search for a threshold data into threshold hash table - * - * \param de_ctx Dectection Context - * \param tsh_ptr Threshold element - * \param p Packet structure - * - * \retval lookup_tsh Return the threshold element - */ -DetectThresholdEntry *ThresholdHashSearch(DetectEngineCtx *de_ctx, DetectThresholdEntry *tsh_ptr, Packet *p) -{ - SCEnter(); - - DetectThresholdEntry *lookup_tsh = NULL; - - SCLogDebug("tsh_ptr->track %u", tsh_ptr->track); - - if (tsh_ptr->track == TRACK_DST) { - if (PKT_IS_IPV4(p)) { - SCLogDebug("ipv4 dst"); - lookup_tsh = HashListTableLookup(de_ctx->ths_ctx.threshold_hash_table_dst, tsh_ptr, sizeof(DetectThresholdEntry)); - } else if (PKT_IS_IPV6(p)) { - lookup_tsh = HashListTableLookup(de_ctx->ths_ctx.threshold_hash_table_dst_ipv6, tsh_ptr, sizeof(DetectThresholdEntry)); - } - } else if (tsh_ptr->track == TRACK_SRC) { - if (PKT_IS_IPV4(p)) { - SCLogDebug("ipv4 src"); - lookup_tsh = HashListTableLookup(de_ctx->ths_ctx.threshold_hash_table_src, tsh_ptr, sizeof(DetectThresholdEntry)); - } else if (PKT_IS_IPV6(p)) - lookup_tsh = HashListTableLookup(de_ctx->ths_ctx.threshold_hash_table_src_ipv6, tsh_ptr, sizeof(DetectThresholdEntry)); - } else { - SCLogDebug("no track, weird"); - } - - SCReturnPtr(lookup_tsh, "DetectThresholdEntry"); -} - /** * \brief Remove timeout threshold hash elements * @@ -164,95 +128,50 @@ DetectThresholdEntry *ThresholdHashSearch(DetectEngineCtx *de_ctx, DetectThresho * */ -/** \todo In some conditions HashListtableRemove returns at dt->array = NULL - * Must need to check it - **/ - -static inline void ThresholdTimeoutRemove(DetectEngineCtx *de_ctx, struct timeval *tv) +int ThresholdTimeoutCheck(Host *host, struct timeval *tv) { - HashListTableBucket *next = NULL; - HashListTableBucket *buck = HashListTableGetListHead(de_ctx->ths_ctx.threshold_hash_table_src); - while (buck != NULL) { - /* get the next before we free "buck" */ - next = HashListTableGetListNext(buck); - - DetectThresholdEntry *tsh = HashListTableGetListData(buck); - if (tsh == NULL) - goto next; - - if ((tv->tv_sec - tsh->tv_sec1) <= tsh->seconds) - goto next; - - switch(tsh->ipv) { - case 4: - if (tsh->track == TRACK_SRC) { - HashListTableRemove(de_ctx->ths_ctx.threshold_hash_table_src, - tsh, sizeof(DetectThresholdEntry)); - } else if (tsh->track == TRACK_DST) { - HashListTableRemove(de_ctx->ths_ctx.threshold_hash_table_dst, - tsh, sizeof(DetectThresholdEntry)); - } - break; - case 6: - if (tsh->track == TRACK_SRC) { - HashListTableRemove(de_ctx->ths_ctx.threshold_hash_table_src_ipv6, - tsh, sizeof(DetectThresholdEntry)); - } else if (tsh->track == TRACK_DST) { - HashListTableRemove(de_ctx->ths_ctx.threshold_hash_table_dst_ipv6, - tsh, sizeof(DetectThresholdEntry)); - } - break; + DetectThresholdEntry *tde = NULL; + DetectThresholdEntry *tmp = NULL; + DetectThresholdEntry *prev = NULL; + int retval = 1; + + if (host->threshold == NULL) + return 1; + + tmp = host->threshold; + + prev = NULL; + while (tmp != NULL) { + if ((tv->tv_sec - tmp->tv_sec1) <= tmp->seconds) { + prev = tmp; + tmp = tmp->next; + retval = 0; + continue; } - next: - buck = next; - } - return; -} + /* timed out */ -/** - * \brief Add threshold element into hash table - * - * \param de_ctx Dectection Context - * \param tsh_ptr Threshold element - * \param p Packet structure - * - */ -void ThresholdHashAdd(DetectEngineCtx *de_ctx, DetectThresholdEntry *tsh_ptr, Packet *p) -{ - SCEnter(); + if (prev != NULL) { + prev->next = tmp->next; - int ret = 0; + tde = tmp; + tmp = tde->next; - switch(tsh_ptr->ipv) { - case 4: - if (tsh_ptr->track == TRACK_DST) { - ret = HashListTableAdd(de_ctx->ths_ctx.threshold_hash_table_dst, - tsh_ptr, sizeof(DetectThresholdEntry)); - } else if (tsh_ptr->track == TRACK_SRC) { - ret = HashListTableAdd(de_ctx->ths_ctx.threshold_hash_table_src, - tsh_ptr, sizeof(DetectThresholdEntry)); - } - break; - case 6: - if (tsh_ptr->track == TRACK_DST) - ret = HashListTableAdd(de_ctx->ths_ctx.threshold_hash_table_dst_ipv6, - tsh_ptr, sizeof(DetectThresholdEntry)); - else if (tsh_ptr->track == TRACK_SRC) - ret = HashListTableAdd(de_ctx->ths_ctx.threshold_hash_table_src_ipv6, - tsh_ptr, sizeof(DetectThresholdEntry)); - break; - } + SCFree(tde); + } else { + host->threshold = tmp->next; + + tde = tmp; + tmp = tde->next; - if(ret == -1) { - SCLogError(SC_ERR_THRESHOLD_HASH_ADD, - "failed to add element into the hash table"); + SCFree(tde); + } } - SCReturn; + return retval; } -static inline DetectThresholdEntry *DetectThresholdEntryAlloc(DetectThresholdData *td, Packet *p, Signature *s) { +static inline DetectThresholdEntry *DetectThresholdEntryAlloc(DetectThresholdData *td, Packet *p, uint32_t sid, uint32_t gid) { SCEnter(); DetectThresholdEntry *ste = SCMalloc(sizeof(DetectThresholdEntry)); @@ -260,19 +179,8 @@ static inline DetectThresholdEntry *DetectThresholdEntryAlloc(DetectThresholdDat SCReturnPtr(NULL, "DetectThresholdEntry"); } - if (PKT_IS_IPV4(p)) - ste->ipv = 4; - else if (PKT_IS_IPV6(p)) - ste->ipv = 6; - - ste->sid = s->id; - ste->gid = s->gid; - - if (td->track == TRACK_DST) { - COPY_ADDRESS(&p->dst, &ste->addr); - } else if (td->track == TRACK_SRC) { - COPY_ADDRESS(&p->src, &ste->addr); - } + ste->sid = sid; + ste->gid = gid; ste->track = td->track; ste->seconds = td->seconds; @@ -281,66 +189,36 @@ static inline DetectThresholdEntry *DetectThresholdEntryAlloc(DetectThresholdDat SCReturnPtr(ste, "DetectThresholdEntry"); } -/** - * \brief Make the threshold logic for signatures - * - * \param de_ctx Dectection Context - * \param tsh_ptr Threshold element - * \param p Packet structure - * \param s Signature structure - * - * \retval 1 alert on this event - * \retval 0 do not alert on this event - */ -int PacketAlertThreshold(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - DetectThresholdData *td, Packet *p, Signature *s) +static DetectThresholdEntry *ThresholdHostLookupEntry(Host *h, uint32_t sid, uint32_t gid) { - SCEnter(); + DetectThresholdEntry *e = h->threshold; - int ret = 0; - DetectThresholdEntry *lookup_tsh = NULL; - DetectThresholdEntry ste; - - if (td == NULL) { - SCReturnInt(0); - } - - /* setup the Entry we use to search our hash with */ - if (PKT_IS_IPV4(p)) - ste.ipv = 4; - else if (PKT_IS_IPV6(p)) - ste.ipv = 6; - else { - SCReturnInt(0); + for (e = h->threshold; e != NULL; e = e->next) { + if (e->sid == sid && e->gid == gid) + break; } - ste.sid = s->id; - ste.gid = s->gid; + return e; +} - if (td->track == TRACK_DST) { - COPY_ADDRESS(&p->dst, &ste.addr); - } else if (td->track == TRACK_SRC) { - COPY_ADDRESS(&p->src, &ste.addr); - } +int ThresholdHandlePacketHost(Host *h, Packet *p, DetectThresholdData *td, uint32_t sid, uint32_t gid) { + int ret = 0; - ste.track = td->track; - ste.seconds = td->seconds; + DetectThresholdEntry *lookup_tsh = ThresholdHostLookupEntry(h, sid, gid); + SCLogDebug("lookup_tsh %p sid %u gid %u", lookup_tsh, sid, gid); - SCMutexLock(&de_ctx->ths_ctx.threshold_table_lock); switch(td->type) { case TYPE_LIMIT: { SCLogDebug("limit"); - lookup_tsh = ThresholdHashSearch(de_ctx, &ste, p); - SCLogDebug("lookup_tsh %p", lookup_tsh); - if (lookup_tsh != NULL) { if ((p->ts.tv_sec - lookup_tsh->tv_sec1) < td->seconds) { - if (lookup_tsh->current_count < td->count) { + lookup_tsh->current_count++; + + if (lookup_tsh->current_count <= td->count) { ret = 1; } - lookup_tsh->current_count++; } else { lookup_tsh->tv_sec1 = p->ts.tv_sec; lookup_tsh->current_count = 1; @@ -348,18 +226,18 @@ int PacketAlertThreshold(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx ret = 1; } } else { - DetectThresholdEntry *e = DetectThresholdEntryAlloc(td, p, s); + DetectThresholdEntry *e = DetectThresholdEntryAlloc(td, p, sid, gid); if (e == NULL) { break; } e->tv_sec1 = p->ts.tv_sec; e->current_count = 1; - e->ipv = ste.ipv; ret = 1; - ThresholdHashAdd(de_ctx, e, p); + e->next = h->threshold; + h->threshold = e; } break; } @@ -367,7 +245,6 @@ int PacketAlertThreshold(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx { SCLogDebug("threshold"); - lookup_tsh = ThresholdHashSearch(de_ctx, &ste, p); if (lookup_tsh != NULL) { if ((p->ts.tv_sec - lookup_tsh->tv_sec1) < td->seconds) { lookup_tsh->current_count++; @@ -384,16 +261,16 @@ int PacketAlertThreshold(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx if (td->count == 1) { ret = 1; } else { - DetectThresholdEntry *e = DetectThresholdEntryAlloc(td, p, s); + DetectThresholdEntry *e = DetectThresholdEntryAlloc(td, p, sid, gid); if (e == NULL) { break; } e->current_count = 1; e->tv_sec1 = p->ts.tv_sec; - e->ipv = ste.ipv; - ThresholdHashAdd(de_ctx, e, p); + e->next = h->threshold; + h->threshold = e; } } break; @@ -402,28 +279,35 @@ int PacketAlertThreshold(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx { SCLogDebug("both"); - lookup_tsh = ThresholdHashSearch(de_ctx, &ste, p); if (lookup_tsh != NULL) { if ((p->ts.tv_sec - lookup_tsh->tv_sec1) < td->seconds) { + /* within time limit */ + lookup_tsh->current_count++; if (lookup_tsh->current_count == td->count) { ret = 1; } - } else { + } else { + /* expired, so reset */ lookup_tsh->tv_sec1 = p->ts.tv_sec; lookup_tsh->current_count = 1; + + /* if we have a limit of 1, this is a match */ + if (lookup_tsh->current_count == td->count) { + ret = 1; + } } } else { - DetectThresholdEntry *e = DetectThresholdEntryAlloc(td, p, s); + DetectThresholdEntry *e = DetectThresholdEntryAlloc(td, p, sid, gid); if (e == NULL) { break; } e->current_count = 1; e->tv_sec1 = p->ts.tv_sec; - e->ipv = ste.ipv; - ThresholdHashAdd(de_ctx, e, p); + e->next = h->threshold; + h->threshold = e; /* for the first match we return 1 to * indicate we should alert */ @@ -438,32 +322,39 @@ int PacketAlertThreshold(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx { SCLogDebug("detection_filter"); - lookup_tsh = ThresholdHashSearch(de_ctx, &ste, p); if (lookup_tsh != NULL) { if ((p->ts.tv_sec - lookup_tsh->tv_sec1) < td->seconds) { + /* within timeout */ + lookup_tsh->current_count++; if (lookup_tsh->current_count >= td->count) { ret = 1; } } else { + /* expired, reset */ + lookup_tsh->tv_sec1 = p->ts.tv_sec; lookup_tsh->current_count = 1; + + if (td->count == 1) { + ret = 1; + } } } else { if (td->count == 1) { ret = 1; } - DetectThresholdEntry *e = DetectThresholdEntryAlloc(td, p, s); + DetectThresholdEntry *e = DetectThresholdEntryAlloc(td, p, sid, gid); if (e == NULL) { break; } e->current_count = 1; e->tv_sec1 = p->ts.tv_sec; - e->ipv = ste.ipv; - ThresholdHashAdd(de_ctx, e, p); + e->next = h->threshold; + h->threshold = e; } break; } @@ -472,12 +363,6 @@ int PacketAlertThreshold(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx { SCLogDebug("rate_filter"); - /* tracking by src/dst or by rule? */ - if (td->track != TRACK_RULE) - lookup_tsh = ThresholdHashSearch(de_ctx, &ste, p); - else - lookup_tsh = (DetectThresholdEntry *)de_ctx->ths_ctx.th_entry[s->num]; - if (lookup_tsh != NULL) { /* Check if we have a timeout enabled, if so, * we still matching (and enabling the new_action) */ @@ -543,7 +428,7 @@ int PacketAlertThreshold(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx ret = 1; } - DetectThresholdEntry *e = DetectThresholdEntryAlloc(td, p, s); + DetectThresholdEntry *e = DetectThresholdEntryAlloc(td, p, sid, gid); if (e == NULL) { break; } @@ -551,13 +436,9 @@ int PacketAlertThreshold(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx e->current_count = 1; e->tv_sec1 = p->ts.tv_sec; e->tv_timeout = 0; - e->ipv = ste.ipv; - /** The track is by src/dst or by rule? */ - if (td->track != TRACK_RULE) - ThresholdHashAdd(de_ctx, e, p); - else - de_ctx->ths_ctx.th_entry[s->num] = e; + e->next = h->threshold; + h->threshold = e; } break; } @@ -585,74 +466,134 @@ int PacketAlertThreshold(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx SCLogError(SC_ERR_INVALID_VALUE, "type %d is not supported", td->type); } - /* handle timing out entries */ - ThresholdTimeoutRemove(de_ctx, &p->ts); - - SCMutexUnlock(&de_ctx->ths_ctx.threshold_table_lock); - SCReturnInt(ret); + return ret; } -void ThresholdFreeFunc(void *data) -{ - if (data != NULL) - SCFree(data); - return; -} +static int ThresholdHandlePacketRule(DetectEngineCtx *de_ctx, Packet *p, DetectThresholdData *td, Signature *s) { + int ret = 0; -/** - * \brief Compare elements into the hash table - * - * \param data1 First element to compare - * \param len1 length of first element - * \param data2 Second element to compare - * \param len2 length of second element - * - * \retval 1 Match or 0 No Match - */ -char ThresholdCompareFunc(void *data1, uint16_t len1, void *data2,uint16_t len2) -{ - SCEnter(); + if (td->type != TYPE_RATE) + return 1; + + DetectThresholdEntry* lookup_tsh = (DetectThresholdEntry *)de_ctx->ths_ctx.th_entry[s->num]; + if (lookup_tsh != NULL) { + /* Check if we have a timeout enabled, if so, + * we still matching (and enabling the new_action) */ + if ( (p->ts.tv_sec - lookup_tsh->tv_timeout) > td->timeout) { + /* Ok, we are done, timeout reached */ + td->timeout = 0; + } else { + /* Already matching */ + /* Take the action to perform */ + switch (td->new_action) { + case TH_ACTION_ALERT: + ALERT_PACKET(p); + break; + case TH_ACTION_DROP: + DROP_PACKET(p); + break; + case TH_ACTION_REJECT: + REJECT_PACKET(p); + break; + case TH_ACTION_PASS: + PASS_PACKET(p); + break; + default: + /* Weird, leave the default action */ + break; + } + ret = 1; + } + + /* Update the matching state with the timeout interval */ + if ( (p->ts.tv_sec - lookup_tsh->tv_sec1) < td->seconds) { + lookup_tsh->current_count++; + if (lookup_tsh->current_count >= td->count) { + /* Then we must enable the new action by setting a + * timeout */ + lookup_tsh->tv_timeout = p->ts.tv_sec; + /* Take the action to perform */ + switch (td->new_action) { + case TH_ACTION_ALERT: + ALERT_PACKET(p); + break; + case TH_ACTION_DROP: + DROP_PACKET(p); + break; + case TH_ACTION_REJECT: + REJECT_PACKET(p); + break; + case TH_ACTION_PASS: + PASS_PACKET(p); + break; + default: + /* Weird, leave the default action */ + break; + } + ret = 1; + } + } else { + lookup_tsh->tv_sec1 = p->ts.tv_sec; + lookup_tsh->current_count = 1; + } + } else { + if (td->count == 1) { + ret = 1; + } - DetectThresholdEntry *a = (DetectThresholdEntry *)data1; - DetectThresholdEntry *b = (DetectThresholdEntry *)data2; + DetectThresholdEntry *e = DetectThresholdEntryAlloc(td, p, s->id, s->gid); + if (e != NULL) { + e->current_count = 1; + e->tv_sec1 = p->ts.tv_sec; + e->tv_timeout = 0; - if ((a->sid == b->sid) && (a->gid == b->gid) && - (CMP_ADDR(&a->addr,&b->addr))) - { - SCReturnInt(1); + de_ctx->ths_ctx.th_entry[s->num] = e; + } } - SCReturnInt(0); + return ret; } /** - * \brief Create the hash for threshold tables + * \brief Make the threshold logic for signatures * - * \param ht Hash Table - * \param data Data that will be used to create the hash - * \param datalen Data length + * \param de_ctx Dectection Context + * \param tsh_ptr Threshold element + * \param p Packet structure + * \param s Signature structure * - * \retval hash the hash + * \retval 1 alert on this event + * \retval 0 do not alert on this event */ -uint32_t ThresholdHashFunc(HashListTable *ht, void *data, uint16_t datalen) +int PacketAlertThreshold(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + DetectThresholdData *td, Packet *p, Signature *s) { SCEnter(); - DetectThresholdEntry *dt = (DetectThresholdEntry *)data; - uint32_t hash = 0; - - if (dt->ipv == 4) - hash = (dt->sid + dt->gid + dt->addr.addr_data32[0]); - else if (dt->ipv == 6) - hash = (dt->sid + dt->gid + dt->addr.addr_data32[0] + - dt->addr.addr_data32[1] + - dt->addr.addr_data32[2] + - dt->addr.addr_data32[3]); - else { - SCLogDebug("no dt->ipv"); + int ret = 0; + if (td == NULL) { + SCReturnInt(0); } - SCReturnInt(hash % THRESHOLD_HASH_SIZE); + if (td->track == TRACK_SRC) { + Host *src = HostGetHostFromHash(&p->src); + if (src) { + ret = ThresholdHandlePacketHost(src,p,td,s->id,s->gid); + HostRelease(src); + } + } else if (td->track == TRACK_DST) { + Host *dst = HostGetHostFromHash(&p->dst); + if (dst) { + ret = ThresholdHandlePacketHost(dst,p,td,s->id,s->gid); + HostRelease(dst); + } + } else if (td->track == TRACK_RULE) { + SCMutexLock(&de_ctx->ths_ctx.threshold_table_lock); + ret = ThresholdHandlePacketRule(de_ctx,p,td,s); + SCMutexUnlock(&de_ctx->ths_ctx.threshold_table_lock); + } + + SCReturnInt(ret); } /** @@ -663,44 +604,10 @@ uint32_t ThresholdHashFunc(HashListTable *ht, void *data, uint16_t datalen) */ void ThresholdHashInit(DetectEngineCtx *de_ctx) { - if (de_ctx->ths_ctx.threshold_hash_table_dst == NULL || - de_ctx->ths_ctx.threshold_hash_table_src == NULL || - de_ctx->ths_ctx.threshold_hash_table_src_ipv6 == NULL || - de_ctx->ths_ctx.threshold_hash_table_dst_ipv6 == NULL) { - - de_ctx->ths_ctx.threshold_hash_table_dst = HashListTableInit(THRESHOLD_HASH_SIZE, ThresholdHashFunc, ThresholdCompareFunc, ThresholdFreeFunc); - if(de_ctx->ths_ctx.threshold_hash_table_dst == NULL) { - SCLogError(SC_ERR_MEM_ALLOC, - "Threshold: Failed to initialize ipv4 dst hash table."); - exit(EXIT_FAILURE); - } - - de_ctx->ths_ctx.threshold_hash_table_src = HashListTableInit(THRESHOLD_HASH_SIZE, ThresholdHashFunc, ThresholdCompareFunc, ThresholdFreeFunc); - if(de_ctx->ths_ctx.threshold_hash_table_dst == NULL) { - SCLogError(SC_ERR_MEM_ALLOC, - "Threshold: Failed to initialize ipv4 src hash table."); - exit(EXIT_FAILURE); - } - - de_ctx->ths_ctx.threshold_hash_table_src_ipv6 = HashListTableInit(THRESHOLD_HASH_SIZE, ThresholdHashFunc, ThresholdCompareFunc, ThresholdFreeFunc); - if(de_ctx->ths_ctx.threshold_hash_table_dst == NULL) { - SCLogError(SC_ERR_MEM_ALLOC, - "Threshold: Failed to initialize ipv6 src hash table."); - exit(EXIT_FAILURE); - } - - de_ctx->ths_ctx.threshold_hash_table_dst_ipv6 = HashListTableInit(THRESHOLD_HASH_SIZE, ThresholdHashFunc, ThresholdCompareFunc, ThresholdFreeFunc); - if(de_ctx->ths_ctx.threshold_hash_table_dst == NULL) { - SCLogError(SC_ERR_MEM_ALLOC, - "Threshold: Failed to initialize ipv6 dst hash table."); - exit(EXIT_FAILURE); - } - - if (SCMutexInit(&de_ctx->ths_ctx.threshold_table_lock, NULL) != 0) { - SCLogError(SC_ERR_MEM_ALLOC, - "Threshold: Failed to initialize hash table mutex."); - exit(EXIT_FAILURE); - } + if (SCMutexInit(&de_ctx->ths_ctx.threshold_table_lock, NULL) != 0) { + SCLogError(SC_ERR_MEM_ALLOC, + "Threshold: Failed to initialize hash table mutex."); + exit(EXIT_FAILURE); } } @@ -712,12 +619,27 @@ void ThresholdHashInit(DetectEngineCtx *de_ctx) */ void ThresholdContextDestroy(DetectEngineCtx *de_ctx) { - HashListTableFree(de_ctx->ths_ctx.threshold_hash_table_dst); - HashListTableFree(de_ctx->ths_ctx.threshold_hash_table_src); - HashListTableFree(de_ctx->ths_ctx.threshold_hash_table_dst_ipv6); - HashListTableFree(de_ctx->ths_ctx.threshold_hash_table_src_ipv6); if (de_ctx->ths_ctx.th_entry != NULL) SCFree(de_ctx->ths_ctx.th_entry); + SCMutexDestroy(&de_ctx->ths_ctx.threshold_table_lock); +} + +/** + * \brief this function will free all the entries of a list + * DetectTagDataEntry + * + * \param td pointer to DetectTagDataEntryList + */ +void ThresholdListFree(void *ptr) { + if (ptr != NULL) { + DetectThresholdEntry *entry = ptr; + + while (entry != NULL) { + DetectThresholdEntry *next_entry = entry->next; + SCFree(entry); + entry = next_entry; + } + } } /** diff --git a/src/detect-engine-threshold.h b/src/detect-engine-threshold.h index b547a636cc..cc3df56792 100644 --- a/src/detect-engine-threshold.h +++ b/src/detect-engine-threshold.h @@ -26,17 +26,17 @@ #define __DETECT_ENGINE_THRESHOLD_H__ #include "detect.h" - -#define THRESHOLD_HASH_SIZE 0xffff +#include "host.h" DetectThresholdData *SigGetThresholdType(Signature *, Packet *); -DetectThresholdData *SigGetThresholdTypeIter(Signature *sig, Packet *p, SigMatch **psm); +DetectThresholdData *SigGetThresholdTypeIter(Signature *, Packet *, SigMatch **); int PacketAlertThreshold(DetectEngineCtx *, DetectEngineThreadCtx *, DetectThresholdData *, Packet *, Signature *); -void ThresholdFreeFunc(void *data); -char ThresholdCompareFunc(void *data1, uint16_t len1, void *data2,uint16_t len2); -uint32_t ThresholdHashFunc(HashListTable *ht, void *data, uint16_t datalen); -void ThresholdHashInit(DetectEngineCtx *de_ctx); -void ThresholdContextDestroy(DetectEngineCtx *de_ctx); + +void ThresholdHashInit(DetectEngineCtx *); +void ThresholdContextDestroy(DetectEngineCtx *); + +int ThresholdTimeoutCheck(Host *, struct timeval *); +void ThresholdListFree(void *ptr); #endif /* __DETECT_ENGINE_THRESHOLD_H__ */ diff --git a/src/detect-threshold.c b/src/detect-threshold.c index d1c181ca39..035ee71a57 100644 --- a/src/detect-threshold.c +++ b/src/detect-threshold.c @@ -35,6 +35,8 @@ #include "suricata.h" #include "decode.h" +#include "host.h" + #include "detect.h" #include "detect-parse.h" @@ -401,6 +403,8 @@ static int DetectThresholdTestSig1(void) { int result = 0; int alerts = 0; + HostInitConfig(HOST_QUIET); + memset(&th_v, 0, sizeof(th_v)); p = UTHBuildPacketReal((uint8_t *)"A",1,IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80); @@ -428,20 +432,44 @@ static int DetectThresholdTestSig1(void) { SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts = PacketAlertCheck(p, 1); + if (alerts != 1) { + printf("alerts %"PRIi32", expected 1: ", alerts); + } SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 1); + if (alerts != 2) { + printf("alerts %"PRIi32", expected 2: ", alerts); + } SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 1); + if (alerts != 3) { + printf("alerts %"PRIi32", expected 3: ", alerts); + } SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 1); + if (alerts != 4) { + printf("alerts %"PRIi32", expected 4: ", alerts); + } SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 1); + if (alerts != 5) { + printf("alerts %"PRIi32", expected 5: ", alerts); + } SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 1); + if (alerts != 5) { + printf("alerts %"PRIi32", expected 5: ", alerts); + } SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 1); + if (alerts != 5) { + printf("alerts %"PRIi32", expected 5: ", alerts); + } SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 1); + if (alerts != 5) { + printf("alerts %"PRIi32", expected 5: ", alerts); + } if(alerts == 5) result = 1; @@ -455,6 +483,8 @@ static int DetectThresholdTestSig1(void) { DetectEngineCtxFree(de_ctx); UTHFreePackets(&p, 1); + + HostShutdown(); end: return result; } @@ -476,6 +506,8 @@ static int DetectThresholdTestSig2(void) { int result = 0; int alerts = 0; + HostInitConfig(HOST_QUIET); + memset(&th_v, 0, sizeof(th_v)); p = UTHBuildPacketReal((uint8_t *)"A",1,IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80); @@ -530,6 +562,7 @@ cleanup: end: UTHFreePackets(&p, 1); + HostShutdown(); return result; } @@ -550,9 +583,9 @@ static int DetectThresholdTestSig3(void) { int result = 0; int alerts = 0; struct timeval ts; - DetectThresholdData *td = NULL; DetectThresholdEntry *lookup_tsh = NULL; - DetectThresholdEntry *ste = NULL; + + HostInitConfig(HOST_QUIET); memset (&ts, 0, sizeof(struct timeval)); TimeGet(&ts); @@ -576,41 +609,25 @@ static int DetectThresholdTestSig3(void) { SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - td = SigGetThresholdType(s,p); - - /* setup the Entry we use to search our hash with */ - ste = SCMalloc(sizeof(DetectThresholdEntry)); - if (ste == NULL) - goto end; - memset(ste, 0x00, sizeof(*ste)); - - if (PKT_IS_IPV4(p)) - ste->ipv = 4; - else if (PKT_IS_IPV6(p)) - ste->ipv = 6; - - ste->sid = s->id; - ste->gid = s->gid; - - if (td->track == TRACK_DST) { - COPY_ADDRESS(&p->dst, &ste->addr); - } else if (td->track == TRACK_SRC) { - COPY_ADDRESS(&p->src, &ste->addr); - } - - ste->track = td->track; - TimeGet(&p->ts); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - lookup_tsh = (DetectThresholdEntry *)HashListTableLookup(de_ctx->ths_ctx.threshold_hash_table_dst, ste, sizeof(DetectThresholdEntry)); + Host *host = HostLookupHostFromHash(&p->dst); + if (host == NULL) { + printf("host not found: "); + goto cleanup; + } + + lookup_tsh = (DetectThresholdEntry *)host->threshold; if (lookup_tsh == NULL) { + HostRelease(host); printf("lookup_tsh is NULL: "); goto cleanup; } + HostRelease(host); TimeSetIncrementTime(200); TimeGet(&p->ts); @@ -619,8 +636,21 @@ static int DetectThresholdTestSig3(void) { SigMatchSignatures(&th_v, de_ctx, det_ctx, p); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (lookup_tsh) - alerts = lookup_tsh->current_count; + host = HostLookupHostFromHash(&p->dst); + if (host == NULL) { + printf("host not found: "); + goto cleanup; + } + HostRelease(host); + + lookup_tsh = (DetectThresholdEntry *)host->threshold; + if (lookup_tsh == NULL) { + HostRelease(host); + printf("lookup_tsh is NULL: "); + goto cleanup; + } + + alerts = lookup_tsh->current_count; if (alerts == 3) result = 1; @@ -637,6 +667,7 @@ cleanup: DetectEngineCtxFree(de_ctx); end: UTHFreePackets(&p, 1); + HostShutdown(); return result; } @@ -658,6 +689,8 @@ static int DetectThresholdTestSig4(void) { int alerts = 0; struct timeval ts; + HostInitConfig(HOST_QUIET); + memset (&ts, 0, sizeof(struct timeval)); TimeGet(&ts); @@ -711,6 +744,7 @@ cleanup: DetectEngineCtxFree(de_ctx); end: UTHFreePackets(&p, 1); + HostShutdown(); return result; } @@ -731,6 +765,8 @@ static int DetectThresholdTestSig5(void) { int result = 0; int alerts = 0; + HostInitConfig(HOST_QUIET); + memset(&th_v, 0, sizeof(th_v)); p = UTHBuildPacketReal((uint8_t *)"A",1,IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80); @@ -793,6 +829,7 @@ cleanup: end: UTHFreePackets(&p, 1); + HostShutdown(); return result; } @@ -804,6 +841,8 @@ static int DetectThresholdTestSig6Ticks(void) { int result = 0; int alerts = 0; + HostInitConfig(HOST_QUIET); + memset(&th_v, 0, sizeof(th_v)); p = UTHBuildPacketReal((uint8_t *)"A",1,IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80); @@ -872,6 +911,7 @@ cleanup: end: UTHFreePackets(&p, 1); + HostShutdown(); return result; } #endif /* UNITTESTS */ diff --git a/src/detect-threshold.h b/src/detect-threshold.h index 68f485e69f..e71bcb9afc 100644 --- a/src/detect-threshold.h +++ b/src/detect-threshold.h @@ -55,8 +55,6 @@ typedef struct DetectThresholdData_ { uint32_t count; /**< Event count */ uint32_t seconds; /**< Event seconds */ - uint32_t sid; /**< Signature id */ - uint8_t gid; /**< Signature group id */ uint8_t type; /**< Threshold type : limit , threshold, both, detection_filter */ uint8_t track; /**< Track type: by_src, by_dst */ uint8_t new_action; /**< new_action alert|drop|pass|log|sdrop|reject */ @@ -66,16 +64,17 @@ typedef struct DetectThresholdData_ { } DetectThresholdData; typedef struct DetectThresholdEntry_ { + uint32_t sid; /**< Signature id */ + uint32_t gid; /**< Signature group id */ + uint32_t tv_timeout; /**< Timeout for new_action (for rate_filter) its not "seconds", that define the time interval */ uint32_t seconds; /**< Event seconds */ - uint32_t sid; /**< Signature id */ uint32_t tv_sec1; /**< Var for time control */ uint32_t current_count; /**< Var for count control */ - Address addr; /**< Var used to store dst or src addr */ - uint8_t gid; /**< Signature group id */ - uint8_t ipv; /**< Packet ip version */ - uint8_t track; /**< Track type: by_src, by_src */ + int track; /**< Track type: by_src, by_src */ + + struct DetectThresholdEntry_ *next; } DetectThresholdEntry; diff --git a/src/detect.h b/src/detect.h index 62f34aad2d..d2a609e160 100644 --- a/src/detect.h +++ b/src/detect.h @@ -514,10 +514,6 @@ typedef struct MpmPatternIdStore_ { /** \brief threshold ctx */ typedef struct ThresholdCtx_ { - HashListTable *threshold_hash_table_dst; /**< Ipv4 dst hash table */ - HashListTable *threshold_hash_table_src; /**< Ipv4 src hash table */ - HashListTable *threshold_hash_table_dst_ipv6; /**< Ipv6 dst hash table */ - HashListTable *threshold_hash_table_src_ipv6; /**< Ipv6 src hash table */ SCMutex threshold_table_lock; /**< Mutex for hash table */ /** to support rate_filter "by_rule" option */ diff --git a/src/host-timeout.c b/src/host-timeout.c index 991d90f004..21b33c1683 100644 --- a/src/host-timeout.c +++ b/src/host-timeout.c @@ -23,7 +23,9 @@ #include "suricata-common.h" #include "host.h" + #include "detect-engine-tag.h" +#include "detect-engine-threshold.h" uint32_t HostGetSpareCount(void) { return HostSpareQueueGetSize(); @@ -55,8 +57,8 @@ static int HostHostTimedOut(Host *h, struct timeval *ts) { if (h->tag && TagTimeoutCheck(h, ts) == 0) { tags = 1; } - if (h->threshold) { - // run threshold cleanup + if (h->threshold && ThresholdTimeoutCheck(h, ts) == 0) { + thresholds = 1; } if (tags || thresholds) diff --git a/src/host.c b/src/host.c index 007619b679..7fbf08d303 100644 --- a/src/host.c +++ b/src/host.c @@ -36,6 +36,7 @@ #include "host-queue.h" #include "detect-tag.h" +#include "detect-engine-threshold.h" static Host *HostGetUsedHost(void); @@ -62,6 +63,8 @@ Host *HostAlloc(void) { if (h == NULL) goto error; + memset(h, 0x00, sizeof(Host)); + SCMutexInit(&h->m, NULL); return h; @@ -98,6 +101,10 @@ void HostClearMemory(Host *h) { DetectTagDataListFree(h->tag); h->tag = NULL; } + if (h->threshold != NULL) { + ThresholdListFree(h->threshold); + h->threshold = NULL; + } } #define HOST_DEFAULT_HASHSIZE 4096 diff --git a/src/util-threshold-config.c b/src/util-threshold-config.c index 63e5c000ad..5df793e554 100644 --- a/src/util-threshold-config.c +++ b/src/util-threshold-config.c @@ -31,6 +31,9 @@ */ #include "suricata-common.h" + +#include "host.h" + #include "detect.h" #include "detect-engine.h" #include "detect-engine-address.h" @@ -1507,6 +1510,8 @@ int SCThresholdConfTest09(void) int result = 0; FILE *fd = NULL; + HostInitConfig(HOST_QUIET); + Packet *p = UTHBuildPacket((uint8_t*)"lalala", 6, IPPROTO_TCP); ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; @@ -1583,6 +1588,7 @@ end: DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); + HostShutdown(); return result; } @@ -1598,6 +1604,8 @@ int SCThresholdConfTest10(void) int result = 0; FILE *fd = NULL; + HostInitConfig(HOST_QUIET); + Packet *p = UTHBuildPacket((uint8_t*)"lalala", 6, IPPROTO_TCP); Packet *p2 = UTHBuildPacketSrcDst((uint8_t*)"lalala", 6, IPPROTO_TCP, "172.26.0.1", "172.26.0.10"); @@ -1680,6 +1688,7 @@ end: DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); + HostShutdown(); return result; } @@ -1695,6 +1704,8 @@ int SCThresholdConfTest11(void) int result = 0; FILE *fd = NULL; + HostInitConfig(HOST_QUIET); + Packet *p = UTHBuildPacket((uint8_t*)"lalala", 6, IPPROTO_TCP); ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; @@ -1796,6 +1807,7 @@ end: DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); + HostShutdown(); return result; } @@ -1811,6 +1823,8 @@ int SCThresholdConfTest12(void) int result = 0; FILE *fd = NULL; + HostInitConfig(HOST_QUIET); + Packet *p = UTHBuildPacket((uint8_t*)"lalala", 6, IPPROTO_TCP); ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; @@ -1913,6 +1927,7 @@ end: DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); + HostShutdown(); return result; } @@ -1931,6 +1946,8 @@ int SCThresholdConfTest13(void) int result = 0; FILE *fd = NULL; + HostInitConfig(HOST_QUIET); + if (de_ctx == NULL) return result; @@ -1958,6 +1975,7 @@ end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); + HostShutdown(); return result; } @@ -1973,6 +1991,8 @@ int SCThresholdConfTest14(void) int result = 0; FILE *fd = NULL; + HostInitConfig(HOST_QUIET); + Packet *p = UTHBuildPacketReal((uint8_t*)"lalala", 6, IPPROTO_TCP, "192.168.0.10", "192.168.0.100", 1234, 24); Packet *p1 = UTHBuildPacketReal((uint8_t*)"lalala", 6, IPPROTO_TCP, "192.168.1.1", @@ -2020,6 +2040,7 @@ end: DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); + HostShutdown(); return result; }