detect/threshold: Refactor threshold calculation to handle by_rule and by_both.

The only difference between threshold calculations for by_src/by_dst,
by_rule or by_both is which table stores the DetectThresholdEntry.
Refactor the ThresholdHandlePacket* functions to do table lookup and
storage individually, but calculate thresholds in a common function.
pull/4785/head
Todd Mortimer 5 years ago committed by Victor Julien
parent 9fafc1031c
commit 82dc61f4c3

@ -174,7 +174,7 @@ static DetectThresholdEntry* ThresholdTimeoutCheck(DetectThresholdEntry *head, s
/* check if the 'check' timestamp is not before the creation ts.
* This can happen due to the async nature of the host timeout
* code that also calls this code from a management thread. */
if (((uint32_t)tv->tv_sec < tmp->tv_sec1) || (tv->tv_sec - tmp->tv_sec1) <= tmp->seconds) {
if (TIMEVAL_EARLIER(*tv, tmp->tv1) || TIMEVAL_DIFF_SEC(*tv, tmp->tv1) <= tmp->seconds) {
prev = tmp;
tmp = tmp->next;
continue;
@ -333,14 +333,14 @@ static inline void RateFilterSetAction(Packet *p, PacketAlert *pa, uint8_t new_a
* \retval int 1 if threshold reached for this entry
*
*/
static int IsThresholdReached(DetectThresholdEntry* lookup_tsh, const DetectThresholdData *td, uint32_t packet_time)
static int IsThresholdReached(DetectThresholdEntry* lookup_tsh, const DetectThresholdData *td, struct timeval packet_time)
{
int ret = 0;
/* Check if we have a timeout enabled, if so,
* we still matching (and enabling the new_action) */
if (lookup_tsh->tv_timeout != 0) {
if ((packet_time - lookup_tsh->tv_timeout) > td->timeout) {
if ((packet_time.tv_sec - lookup_tsh->tv_timeout) > td->timeout) {
/* Ok, we are done, timeout reached */
lookup_tsh->tv_timeout = 0;
}
@ -352,17 +352,17 @@ static int IsThresholdReached(DetectThresholdEntry* lookup_tsh, const DetectThre
}
else {
/* Update the matching state with the timeout interval */
if ((packet_time - lookup_tsh->tv_sec1) < td->seconds) {
if (TIMEVAL_DIFF_SEC(packet_time, lookup_tsh->tv1) < 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 = packet_time;
lookup_tsh->tv_timeout = packet_time.tv_sec;
ret = 1;
}
}
else {
lookup_tsh->tv_sec1 = packet_time;
lookup_tsh->tv1 = packet_time;
lookup_tsh->current_count = 1;
}
} /* else - if (lookup_tsh->tv_timeout != 0) */
@ -370,79 +370,49 @@ static int IsThresholdReached(DetectThresholdEntry* lookup_tsh, const DetectThre
return ret;
}
static void AddEntryToHostStorage(Host *h, DetectThresholdEntry *e, uint32_t packet_time)
static void AddEntryToHostStorage(Host *h, DetectThresholdEntry *e, struct timeval packet_time)
{
if (h && e) {
e->current_count = 1;
e->tv_sec1 = packet_time;
e->tv1 = packet_time;
e->tv_timeout = 0;
e->next = HostGetStorageById(h, host_threshold_id);
HostSetStorageById(h, host_threshold_id, e);
}
}
static void AddEntryToIPPairStorage(IPPair *pair, DetectThresholdEntry *e, uint32_t packet_time)
static void AddEntryToIPPairStorage(IPPair *pair, DetectThresholdEntry *e, struct timeval packet_time)
{
if (pair && e) {
e->current_count = 1;
e->tv_sec1 = packet_time;
e->tv1 = packet_time;
e->tv_timeout = 0;
e->next = IPPairGetStorageById(pair, ippair_threshold_id);
IPPairSetStorageById(pair, ippair_threshold_id, e);
}
}
static int ThresholdHandlePacketIPPair(IPPair *pair, Packet *p, const DetectThresholdData *td,
uint32_t sid, uint32_t gid, PacketAlert *pa)
{
int ret = 0;
DetectThresholdEntry *lookup_tsh = ThresholdIPPairLookupEntry(pair, sid, gid);
SCLogDebug("ippair lookup_tsh %p sid %u gid %u", lookup_tsh, sid, gid);
switch (td->type) {
case TYPE_RATE:
{
SCLogDebug("rate_filter");
ret = 1;
if (lookup_tsh && IsThresholdReached(lookup_tsh, td, p->ts.tv_sec)) {
RateFilterSetAction(p, pa, td->new_action);
} else if (!lookup_tsh) {
DetectThresholdEntry *e = DetectThresholdEntryAlloc(td, p, sid, gid);
AddEntryToIPPairStorage(pair, e, p->ts.tv_sec);
}
break;
}
default:
{
SCLogError(SC_ERR_INVALID_VALUE, "type %d is not supported", td->type);
break;
}
}
return ret;
}
/**
* \retval 2 silent match (no alert but apply actions)
* \retval 1 normal match
* \retval 0 no match
*
* If a new DetectThresholdEntry is generated to track the threshold
* for this rule, then it will be returned in new_tsh.
*/
static int ThresholdHandlePacketHost(Host *h, Packet *p, const DetectThresholdData *td,
static int ThresholdHandlePacket(Packet *p, DetectThresholdEntry *lookup_tsh,
DetectThresholdEntry **new_tsh, const DetectThresholdData *td,
uint32_t sid, uint32_t gid, PacketAlert *pa)
{
int ret = 0;
DetectThresholdEntry *lookup_tsh = ThresholdHostLookupEntry(h, sid, gid);
SCLogDebug("lookup_tsh %p sid %u gid %u", lookup_tsh, sid, gid);
switch(td->type) {
case TYPE_LIMIT:
{
SCLogDebug("limit");
if (lookup_tsh != NULL) {
if ((p->ts.tv_sec - lookup_tsh->tv_sec1) < td->seconds) {
if (TIMEVAL_DIFF_SEC(p->ts, lookup_tsh->tv1) < td->seconds) {
lookup_tsh->current_count++;
if (lookup_tsh->current_count <= td->count) {
@ -451,24 +421,15 @@ static int ThresholdHandlePacketHost(Host *h, Packet *p, const DetectThresholdDa
ret = 2;
}
} else {
lookup_tsh->tv_sec1 = p->ts.tv_sec;
lookup_tsh->tv1 = p->ts;
lookup_tsh->current_count = 1;
ret = 1;
}
} else {
DetectThresholdEntry *e = DetectThresholdEntryAlloc(td, p, sid, gid);
if (e == NULL) {
break;
}
e->tv_sec1 = p->ts.tv_sec;
e->current_count = 1;
*new_tsh = DetectThresholdEntryAlloc(td, p, sid, gid);
ret = 1;
e->next = HostGetStorageById(h, host_threshold_id);
HostSetStorageById(h, host_threshold_id, e);
}
break;
}
@ -477,7 +438,7 @@ static int ThresholdHandlePacketHost(Host *h, Packet *p, const DetectThresholdDa
SCLogDebug("threshold");
if (lookup_tsh != NULL) {
if ((p->ts.tv_sec - lookup_tsh->tv_sec1) < td->seconds) {
if (TIMEVAL_DIFF_SEC(p->ts, lookup_tsh->tv1) < td->seconds) {
lookup_tsh->current_count++;
if (lookup_tsh->current_count >= td->count) {
@ -485,23 +446,14 @@ static int ThresholdHandlePacketHost(Host *h, Packet *p, const DetectThresholdDa
lookup_tsh->current_count = 0;
}
} else {
lookup_tsh->tv_sec1 = p->ts.tv_sec;
lookup_tsh->tv1 = p->ts;
lookup_tsh->current_count = 1;
}
} else {
if (td->count == 1) {
ret = 1;
} else {
DetectThresholdEntry *e = DetectThresholdEntryAlloc(td, p, sid, gid);
if (e == NULL) {
break;
}
e->current_count = 1;
e->tv_sec1 = p->ts.tv_sec;
e->next = HostGetStorageById(h, host_threshold_id);
HostSetStorageById(h, host_threshold_id, e);
*new_tsh = DetectThresholdEntryAlloc(td, p, sid, gid);
}
}
break;
@ -511,7 +463,7 @@ static int ThresholdHandlePacketHost(Host *h, Packet *p, const DetectThresholdDa
SCLogDebug("both");
if (lookup_tsh != NULL) {
if ((p->ts.tv_sec - lookup_tsh->tv_sec1) < td->seconds) {
if (TIMEVAL_DIFF_SEC(p->ts, lookup_tsh->tv1) < td->seconds) {
/* within time limit */
lookup_tsh->current_count++;
@ -523,7 +475,7 @@ static int ThresholdHandlePacketHost(Host *h, Packet *p, const DetectThresholdDa
}
} else {
/* expired, so reset */
lookup_tsh->tv_sec1 = p->ts.tv_sec;
lookup_tsh->tv1 = p->ts;
lookup_tsh->current_count = 1;
/* if we have a limit of 1, this is a match */
@ -532,16 +484,7 @@ static int ThresholdHandlePacketHost(Host *h, Packet *p, const DetectThresholdDa
}
}
} else {
DetectThresholdEntry *e = DetectThresholdEntryAlloc(td, p, sid, gid);
if (e == NULL) {
break;
}
e->current_count = 1;
e->tv_sec1 = p->ts.tv_sec;
e->next = HostGetStorageById(h, host_threshold_id);
HostSetStorageById(h, host_threshold_id, e);
*new_tsh = DetectThresholdEntryAlloc(td, p, sid, gid);
/* for the first match we return 1 to
* indicate we should alert */
@ -557,35 +500,19 @@ static int ThresholdHandlePacketHost(Host *h, Packet *p, const DetectThresholdDa
SCLogDebug("detection_filter");
if (lookup_tsh != NULL) {
long double time_diff = ((p->ts.tv_sec + p->ts.tv_usec/1000000.0) -
(lookup_tsh->tv_sec1 + lookup_tsh->tv_usec1/1000000.0));
if (time_diff < td->seconds) {
if (TIMEVAL_DIFF_SEC(p->ts, lookup_tsh->tv1) < 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->tv_usec1 = p->ts.tv_usec;
lookup_tsh->tv1 = p->ts;
lookup_tsh->current_count = 1;
}
} else {
DetectThresholdEntry *e = DetectThresholdEntryAlloc(td, p, sid, gid);
if (e == NULL) {
break;
}
e->current_count = 1;
e->tv_sec1 = p->ts.tv_sec;
e->tv_usec1 = p->ts.tv_usec;
e->next = HostGetStorageById(h, host_threshold_id);
HostSetStorageById(h, host_threshold_id, e);
*new_tsh = DetectThresholdEntryAlloc(td, p, sid, gid);
}
break;
}
@ -594,11 +521,10 @@ static int ThresholdHandlePacketHost(Host *h, Packet *p, const DetectThresholdDa
{
SCLogDebug("rate_filter");
ret = 1;
if (lookup_tsh && IsThresholdReached(lookup_tsh, td, p->ts.tv_sec)) {
if (lookup_tsh && IsThresholdReached(lookup_tsh, td, p->ts)) {
RateFilterSetAction(p, pa, td->new_action);
} else if (!lookup_tsh) {
DetectThresholdEntry *e = DetectThresholdEntryAlloc(td, p, sid, gid);
AddEntryToHostStorage(h, e, p->ts.tv_sec);
*new_tsh = DetectThresholdEntryAlloc(td, p, sid, gid);
}
break;
}
@ -606,7 +532,43 @@ static int ThresholdHandlePacketHost(Host *h, Packet *p, const DetectThresholdDa
default:
SCLogError(SC_ERR_INVALID_VALUE, "type %d is not supported", td->type);
}
return ret;
}
static int ThresholdHandlePacketIPPair(IPPair *pair, Packet *p, const DetectThresholdData *td,
uint32_t sid, uint32_t gid, PacketAlert *pa)
{
int ret = 0;
DetectThresholdEntry *lookup_tsh = ThresholdIPPairLookupEntry(pair, sid, gid);
SCLogDebug("ippair lookup_tsh %p sid %u gid %u", lookup_tsh, sid, gid);
DetectThresholdEntry *new_tsh = NULL;
ret = ThresholdHandlePacket(p, lookup_tsh, &new_tsh, td, sid, gid, pa);
if (new_tsh != NULL) {
AddEntryToIPPairStorage(pair, new_tsh, p->ts);
}
return ret;
}
/**
* \retval 2 silent match (no alert but apply actions)
* \retval 1 normal match
* \retval 0 no match
*/
static int ThresholdHandlePacketHost(Host *h, Packet *p, const DetectThresholdData *td,
uint32_t sid, uint32_t gid, PacketAlert *pa)
{
int ret = 0;
DetectThresholdEntry *lookup_tsh = ThresholdHostLookupEntry(h, sid, gid);
SCLogDebug("lookup_tsh %p sid %u gid %u", lookup_tsh, sid, gid);
DetectThresholdEntry *new_tsh = NULL;
ret = ThresholdHandlePacket(p, lookup_tsh, &new_tsh, td, sid, gid, pa);
if (new_tsh != NULL) {
AddEntryToHostStorage(h, new_tsh, p->ts);
}
return ret;
}
@ -618,30 +580,13 @@ static int ThresholdHandlePacketRule(DetectEngineCtx *de_ctx, Packet *p,
DetectThresholdEntry* lookup_tsh = (DetectThresholdEntry *)de_ctx->ths_ctx.th_entry[s->num];
SCLogDebug("by_rule lookup_tsh %p num %u", lookup_tsh, s->num);
switch (td->type) {
case TYPE_RATE:
{
ret = 1;
if (lookup_tsh && IsThresholdReached(lookup_tsh, td, p->ts.tv_sec)) {
RateFilterSetAction(p, pa, td->new_action);
}
else if (!lookup_tsh) {
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;
de_ctx->ths_ctx.th_entry[s->num] = e;
}
}
break;
}
default:
{
SCLogError(SC_ERR_INVALID_VALUE, "type %d is not supported", td->type);
break;
}
DetectThresholdEntry *new_tsh = NULL;
ret = ThresholdHandlePacket(p, lookup_tsh, &new_tsh, td, s->id, s->gid, pa);
if (new_tsh != NULL) {
new_tsh->tv1 = p->ts;
new_tsh->current_count = 1;
new_tsh->tv_timeout = 0;
de_ctx->ths_ctx.th_entry[s->num] = new_tsh;
}
return ret;

@ -72,11 +72,10 @@ typedef struct DetectThresholdEntry_ {
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 tv_sec1; /**< Var for time control */
uint32_t tv_usec1; /**< Var for time control */
uint32_t current_count; /**< Var for count control */
int track; /**< Track type: by_src, by_src */
struct timeval tv1; /**< Var for time control */
struct DetectThresholdEntry_ *next;
} DetectThresholdEntry;

Loading…
Cancel
Save