Adding tag keyword support

remotes/origin/master-1.0.x
Pablo Rincon 15 years ago committed by Victor Julien
parent 9222386377
commit eed0ef6e69

@ -50,6 +50,7 @@ detect-window.c detect-window.h \
detect-ftpbounce.c detect-ftpbounce.h \
detect-engine-address.c detect-engine-address.h \
detect-engine-threshold.c detect-engine-threshold.h \
detect-engine-tag.c detect-engine-tag.h \
detect-engine-address-ipv4.c detect-engine-address-ipv4.h \
detect-engine-address-ipv6.c detect-engine-address-ipv6.h \
detect-engine-proto.c detect-engine-proto.h \

@ -671,6 +671,7 @@ void AddressDebugPrint(Address *);
#define PKT_NOPACKET_INSPECTION 0x01 /**< Flag to indicate that packet header or contents should not be inspected*/
#define PKT_NOPAYLOAD_INSPECTION 0x02 /**< Flag to indicate that packet contents should not be inspected*/
#define PKT_ALLOC 0x04 /**< Packet was alloc'd this run, needs to be freed */
#define PKT_HAS_TAG 0x08 /**< Packet has matched a tag */
#endif /* __DECODE_H__ */

@ -20,12 +20,47 @@
#include "detect.h"
#include "detect-engine-alert.h"
#include "detect-engine-threshold.h"
#include "detect-engine-tag.h"
#include "decode.h"
#include "flow.h"
#include "flow-private.h"
/**
* \brief Handle a packet and check if needs a threshold logic
*
* \param de_ctx Detection Context
* \param sig Signature pointer
* \param p Packet structure
*
*/
int PacketAlertHandle(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx,
Signature *s, Packet *p, uint16_t pos)
{
SCEnter();
int ret = 0;
/* retrieve the sig match data */
DetectThresholdData *td = SigGetThresholdType(s,p);
SCLogDebug("td %p", td);
/* if have none just alert, otherwise handle thresholding */
if (td == NULL) {
/* Already inserted so get out */
ret = 1;
} else {
ret = PacketAlertThreshold(de_ctx, det_ctx, td, p, s);
if (ret == 0) {
/* It doesn't match threshold, remove it */
PacketAlertRemove(p, pos);
}
}
SCReturnInt(ret);
}
/**
* \brief Check if a certain sid alerted, this is used in the test functions
@ -132,6 +167,54 @@ int PacketAlertAppend(DetectEngineThreadCtx *det_ctx, Signature *s, Packet *p)
return 0;
}
int PacketAlertAppendTag(DetectEngineThreadCtx *det_ctx, Packet *p)
{
int i = 0;
if (p->alerts.cnt == PACKET_ALERT_MAX)
return 0;
/* It should be usually the last, so check it before iterating */
if (p->alerts.cnt == 0) {
p->alerts.alerts[p->alerts.cnt].sid = TAG_SIG_ID;
p->alerts.alerts[p->alerts.cnt].gid = TAG_SIG_GEN;
p->alerts.alerts[p->alerts.cnt].num = TAG_SIG_ID;
p->alerts.alerts[p->alerts.cnt].order_id = 1000;
p->alerts.alerts[p->alerts.cnt].action = ACTION_ALERT;
p->alerts.alerts[p->alerts.cnt].rev = 1;
p->alerts.alerts[p->alerts.cnt].prio = 2;
p->alerts.alerts[p->alerts.cnt].msg = NULL;
p->alerts.alerts[p->alerts.cnt].class = 0;
p->alerts.alerts[p->alerts.cnt].class_msg = NULL;
p->alerts.alerts[p->alerts.cnt].references = NULL;
} else {
/* We need to make room for this s->num
(a bit ugly with mamcpy but we are planning changes here)*/
for (i = p->alerts.cnt - 1; i >= 0; i--) {
memcpy(&p->alerts.alerts[i + 1], &p->alerts.alerts[i], sizeof(PacketAlert));
}
i++; /* The right place to store the alert */
p->alerts.alerts[p->alerts.cnt].sid = TAG_SIG_ID;
p->alerts.alerts[p->alerts.cnt].gid = TAG_SIG_GEN;
p->alerts.alerts[p->alerts.cnt].num = TAG_SIG_ID;
p->alerts.alerts[p->alerts.cnt].order_id = 1000;
p->alerts.alerts[p->alerts.cnt].action = ACTION_ALERT;
p->alerts.alerts[p->alerts.cnt].rev = 1;
p->alerts.alerts[p->alerts.cnt].prio = 2;
p->alerts.alerts[p->alerts.cnt].msg = NULL;
p->alerts.alerts[p->alerts.cnt].class = 0;
p->alerts.alerts[p->alerts.cnt].class_msg = NULL;
p->alerts.alerts[p->alerts.cnt].references = NULL;
}
p->alerts.cnt++;
return 0;
}
/**
* \brief Check the threshold of the sigs that match, set actions, break on pass action
* This function iterate the packet alerts array, removing those that didn't match
@ -146,6 +229,7 @@ void PacketAlertFinalize(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx
int i = 0;
Signature *s = NULL;
SigMatch *sm = NULL;
for (i = 0; i < p->alerts.cnt; i++) {
SCLogDebug("Sig->num: %"PRIu16, p->alerts.alerts[i].num);
@ -156,6 +240,15 @@ void PacketAlertFinalize(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx
if (res == 0) {
i--;
} else {
/* Now, if we have an alert, we have to check if we want
* to tag this session or src/dst host */
sm = s->tmatch;
while (sm) {
/* tags are set only for alerts */
sigmatch_table[sm->type].Match(NULL, det_ctx, p, s, sm);
sm = sm->next;
}
if (s->flags & SIG_FLAG_IPONLY) {
if ((p->flowflags & FLOW_PKT_TOSERVER && !(p->flowflags & FLOW_PKT_TOSERVER_IPONLY_SET)) ||
(p->flowflags & FLOW_PKT_TOCLIENT && !(p->flowflags & FLOW_PKT_TOCLIENT_IPONLY_SET))) {
@ -194,5 +287,10 @@ void PacketAlertFinalize(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx
* have compacted the array and decreased cnt by one, so
* process again the same position (with different alert now) */
}
/* At this point, we should have all the new alerts. Now check the tag
* keyword context for sessions and hosts */
TagHandlePacket(de_ctx, det_ctx, p);
}

@ -29,6 +29,7 @@
void PacketAlertFinalize(DetectEngineCtx *, DetectEngineThreadCtx *, Packet *);
int PacketAlertAppend(DetectEngineThreadCtx *, Signature *, Packet *);
int PacketAlertAppendTag(DetectEngineThreadCtx *, Packet *);
int PacketAlertCheck(Packet *, uint32_t);
int PacketAlertRemove(Packet *, uint16_t);

@ -0,0 +1,755 @@
/* Copyright (C) 2007-2010 Open Information Security Foundation
*
* You can copy, redistribute or modify this Program under the terms of
* the GNU General Public License version 2 as published by the Free
* Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* version 2 along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
/**
* \file detect-engine-tag.c
*
* \author Pablo Rincon Crespo <pablo.rincon.crespo@gmail.com>
*
* Implements a global context to store data related to hosts flagged
* tag keyword
*/
#include "suricata-common.h"
#include "util-hash.h"
#include "util-time.h"
#include "util-hashlist.h"
#include "detect-engine-tag.h"
#include "detect-tag.h"
static void TagTimeoutRemove(DetectTagHostCtx *tag_ctx, struct timeval *tv);
/* Global Ctx for tagging hosts */
DetectTagHostCtx *tag_ctx = NULL;
void TagFreeFunc(void *data)
{
DetectTagDataListFree(data);
return;
}
/**
* \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 TagCompareFunc(void *data1, uint16_t len1, void *data2,uint16_t len2)
{
SCEnter();
DetectTagDataEntryList *a = (DetectTagDataEntryList *)data1;
DetectTagDataEntryList *b = (DetectTagDataEntryList *)data2;
if (CMP_ADDR(&a->addr,&b->addr)) {
SCReturnInt(1);
}
SCReturnInt(0);
}
/**
* \brief Create the hash for tag tables
*
* \param ht Hash Table
* \param data DataEntry that will be used to create the hash
* \param datalen DataEntry length
*
* \retval hash the hash
*/
uint32_t TagHashFunc(HashListTable *ht, void *data, uint16_t datalen)
{
SCEnter();
if (data == NULL) return 0;
DetectTagDataEntryList *dt = (DetectTagDataEntryList *)data;
uint32_t hash = 0;
if (dt->ipv == 4)
hash = (dt->addr.addr_data32[0]);
else if (dt->ipv == 6)
hash = (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");
}
SCReturnInt(hash % TAG_HASH_SIZE);
}
void TagInitCtx(void) {
tag_ctx = SCMalloc(sizeof(DetectTagHostCtx));
if (tag_ctx == NULL) {
SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory for the tagging context");
exit(EXIT_FAILURE);
}
TimeGet(&tag_ctx->last_ts);
if (SCMutexInit(&tag_ctx->lock, NULL) != 0) {
SCLogError(SC_ERR_MEM_ALLOC,
"Tag: Failed to initialize hash table mutex.");
exit(EXIT_FAILURE);
}
TagHashInit(tag_ctx);
}
/** \brief Reset the tagging engine context
*/
void TagRestartCtx() {
TagDestroyCtx();
TagInitCtx();
}
/**
* \brief Init tag context hash tables
*
* \param det_ctx Dectection Thread Context
*
*/
void TagHashInit(DetectTagHostCtx *tag_ctx)
{
if (tag_ctx->tag_hash_table_ipv4 == NULL ||
tag_ctx->tag_hash_table_ipv6 == NULL) {
tag_ctx->tag_hash_table_ipv4 = HashListTableInit(TAG_HASH_SIZE, TagHashFunc, TagCompareFunc, TagFreeFunc);
if(tag_ctx->tag_hash_table_ipv4 == NULL) {
SCLogError(SC_ERR_MEM_ALLOC,
"Tag: Failed to initialize ipv4 dst hash table.");
exit(EXIT_FAILURE);
}
tag_ctx->tag_hash_table_ipv6 = HashListTableInit(TAG_HASH_SIZE, TagHashFunc, TagCompareFunc, TagFreeFunc);
if(tag_ctx->tag_hash_table_ipv6 == NULL) {
SCLogError(SC_ERR_MEM_ALLOC,
"Tag: Failed to initialize ipv4 src hash table.");
exit(EXIT_FAILURE);
}
}
}
/**
* \brief Search for a tag data into tag hash table
*
* \param de_ctx Dectection Context
* \param dtde Tag element
* \param p Packet structure
*
* \retval lookup_tde Return the tag element
*/
DetectTagDataEntryList *TagHashSearch(DetectTagHostCtx *tag_ctx, DetectTagDataEntryList *dtde,
Packet *p)
{
SCEnter();
DetectTagDataEntryList *lookup_tde = NULL;
if (PKT_IS_IPV4(p)) {
SCLogDebug("ipv4 search");
lookup_tde = HashListTableLookup(tag_ctx->tag_hash_table_ipv4, dtde, sizeof(DetectTagDataEntryList));
} else if (PKT_IS_IPV6(p)) {
SCLogDebug("ipv6 search");
lookup_tde = HashListTableLookup(tag_ctx->tag_hash_table_ipv6, dtde, sizeof(DetectTagDataEntryList));
}
SCReturnPtr(lookup_tde, "DetectTagDataEntryList");
}
/**
* \brief Add tag element into hash table
*
* \param de_ctx Dectection Context
* \param dtde Tag element
* \param p Packet structure
*
*/
void TagHashAdd(DetectTagHostCtx *tag_ctx, DetectTagDataEntryList *dtde, Packet *p)
{
SCEnter();
int ret = 0;
if (PKT_IS_IPV4(p)) {
dtde->ipv = 4;
ret = HashListTableAdd(tag_ctx->tag_hash_table_ipv4,
dtde, sizeof(DetectTagDataEntry));
} else if (PKT_IS_IPV6(p)) {
dtde->ipv = 6;
ret = HashListTableAdd(tag_ctx->tag_hash_table_ipv6,
dtde, sizeof(DetectTagDataEntry));
}
SCReturn;
}
/**
* \brief Add a tag entry for a host. If it already exist, update it.
*
* \param tag_ctx Tag context for hosts
* \param tde Tag data
* \param p packet
*
* \retval 0 if it was added, 1 if it was updated
*/
int TagHashAddTag(DetectTagHostCtx *tag_ctx, DetectTagDataEntry *tde, Packet *p)
{
uint8_t updated = 0;
uint16_t num_tags = 0;
/* local, just for searching */
DetectTagDataEntryList tdl;
tdl.header_entry = NULL;
tdl.header_entry = tde;
SCEnter();
SCMutexLock(&tag_ctx->lock);
/* first search if we already have an entry of this host */
DetectTagDataEntryList *entry = NULL;
if (PKT_IS_IPV4(p)) {
tdl.ipv = 4;
if (tde->td->direction == DETECT_TAG_DIR_SRC) {
SET_IPV4_SRC_ADDR(p, &tdl.addr);
} else if (tde->td->direction == DETECT_TAG_DIR_DST) {
SET_IPV4_DST_ADDR(p, &tdl.addr);
}
} else if (PKT_IS_IPV6(p)) {
tdl.ipv = 6;
if (tde->td->direction == DETECT_TAG_DIR_SRC) {
SET_IPV6_SRC_ADDR(p, &tdl.addr);
} else if (tde->td->direction == DETECT_TAG_DIR_DST) {
SET_IPV6_DST_ADDR(p, &tdl.addr);
}
}
entry = TagHashSearch(tag_ctx, &tdl, p);
if (entry == NULL) {
DetectTagDataEntryList *new = SCMalloc(sizeof(DetectTagDataEntryList));
if (new == NULL) {
SCLogError(SC_ERR_MEM_ALLOC, "Failed to allocate a new session");
}
memcpy(new, &tdl, sizeof(DetectTagDataEntryList));
TagHashAdd(tag_ctx, new, p);
} else {
/* Append the tag to the list of this host */
/* First iterate installed entries searching a duplicated sid/gid */
DetectTagDataEntry *iter = NULL;
for (iter = entry->header_entry; iter != NULL; iter = iter->next) {
num_tags++;
if (iter->sid == tde->sid && iter->gid == tde->gid) {
iter->cnt_match++;
/* If so, update data, unless the maximum MATCH limit is
* reached. This prevents possible DOS attacks */
if (iter->cnt_match < DETECT_TAG_MATCH_LIMIT) {
/* Reset time and counters */
iter->first_ts.tv_sec = iter->last_ts.tv_sec = tde->first_ts.tv_sec;
iter->packets = 0;
iter->bytes = 0;
}
updated = 1;
break;
}
}
/* If there was no entry of this rule, append the new tde */
if (updated == 0 && num_tags < DETECT_TAG_MAX_TAGS) {
tde->next = entry->header_entry;
entry->header_entry = tde;
} else if (num_tags == DETECT_TAG_MAX_TAGS) {
SCLogDebug("Max tags for sessions reached (%"PRIu16")", num_tags);
}
}
SCMutexUnlock(&tag_ctx->lock);
SCReturnInt(updated);
}
/**
* \brief Destroy tag context hash tables
*
* \param tag_ctx Tag Context
*
*/
void TagDestroyCtx(void)
{
HashListTableFree(tag_ctx->tag_hash_table_ipv4);
tag_ctx->tag_hash_table_ipv4 = NULL;
HashListTableFree(tag_ctx->tag_hash_table_ipv6);
tag_ctx->tag_hash_table_ipv6 = NULL;
SCMutexDestroy(&tag_ctx->lock);
SCFree(tag_ctx);
tag_ctx = NULL;
}
/**
* \brief Search tags for src and dst. Update entries of the tag, remove if necessary
*
* \param de_ctx Detect context
* \param det_ctx Detect thread context
* \param p packet
*
*/
void TagHandlePacket(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx,
Packet *p) {
DetectTagDataEntry *tde = NULL;
DetectTagDataEntry *prev = NULL;
DetectTagDataEntry *iter = NULL;
DetectTagDataEntryList tdl;
struct timeval ts;
TimeGet(&ts);
uint8_t flag_added = 0;
/* Check for timeout tags if we reached the interval for checking it */
if (ts.tv_sec - tag_ctx->last_ts.tv_sec > TAG_TIMEOUT_CHECK_INTERVAL) {
TagTimeoutRemove(tag_ctx, &ts);
tag_ctx->last_ts.tv_sec = ts.tv_sec;
}
/* First update and get session tags */
if (p->flow != NULL) {
SCMutexLock(&p->flow->m);
if (p->flow->tag_list != NULL) {
iter = p->flow->tag_list->header_entry;
prev = NULL;
while (iter != NULL) {
/* update counters */
iter->last_ts.tv_sec = ts.tv_sec;
iter->packets++;
iter->bytes += p->pktlen;
/* If this packet triggered the rule with tag, we dont need
* to log it (the alert will log it) */
if (iter->first_time++ > 0) {
/* Update metrics; remove if tag expired; and set alerts */
switch (iter->td->metric) {
case DETECT_TAG_METRIC_PACKET:
if (iter->packets > iter->td->count) {
/* tag expired */
if (prev != NULL) {
tde = iter;
prev->next = iter->next;
iter = iter->next;
SCFree(tde);
continue;
} else {
p->flow->tag_list->header_entry = iter->next;
tde = iter;
iter = iter->next;
SCFree(tde);
continue;
}
} else if (flag_added == 0) {
/* It's matching the tag. Add it to be logged and
* update "flag_added" to add the packet once. */
PacketAlertAppendTag(det_ctx, p);
p->flags |= PKT_HAS_TAG;
flag_added++;
}
break;
case DETECT_TAG_METRIC_BYTES:
if (iter->bytes > iter->td->count) {
/* tag expired */
if (prev != NULL) {
tde = iter;
prev->next = iter->next;
iter = iter->next;
SCFree(tde);
continue;
} else {
p->flow->tag_list->header_entry = iter->next;
tde = iter;
iter = iter->next;
SCFree(tde);
continue;
}
} else if (flag_added == 0) {
/* It's matching the tag. Add it to be logged and
* update "flag_added" to add the packet once. */
PacketAlertAppendTag(det_ctx, p);
p->flags |= PKT_HAS_TAG;
flag_added++;
}
break;
case DETECT_TAG_METRIC_SECONDS:
/* last_ts handles this metric, but also a generic time based
* expiration to prevent dead sessions/hosts */
if (iter->last_ts.tv_sec - iter->first_ts.tv_sec > iter->td->count) {
/* tag expired */
if (prev != NULL) {
tde = iter;
prev->next = iter->next;
iter = iter->next;
SCFree(tde);
continue;
} else {
p->flow->tag_list->header_entry = iter->next;
tde = iter;
iter = iter->next;
SCFree(tde);
continue;
}
} else if (flag_added == 0) {
/* It's matching the tag. Add it to be logged and
* update "flag_added" to add the packet once. */
PacketAlertAppendTag(det_ctx, p);
p->flags |= PKT_HAS_TAG;
flag_added++;
}
break;
}
}
prev = iter;
iter = iter->next;
}
}
SCMutexUnlock(&p->flow->m);
}
/* Then search the src and dst hosts at the ctx */
SCMutexLock(&tag_ctx->lock);
DetectTagDataEntryList *tde_src = NULL;
DetectTagDataEntryList *tde_dst = NULL;
if (PKT_IS_IPV4(p)) {
tdl.ipv = 4;
/* search tags for source */
SET_IPV4_SRC_ADDR(p, &tdl.addr);
tde_src = TagHashSearch(tag_ctx, &tdl, p);
/* search tags for dest */
SET_IPV4_DST_ADDR(p, &tdl.addr);
tde_dst = TagHashSearch(tag_ctx, &tdl, p);
} else if (PKT_IS_IPV6(p)) {
tdl.ipv = 6;
/* search tags for source */
SET_IPV6_SRC_ADDR(p, &tdl.addr);
tde_src = TagHashSearch(tag_ctx, &tdl, p);
/* search tags for dest */
SET_IPV6_DST_ADDR(p, &tdl.addr);
tde_dst = TagHashSearch(tag_ctx, &tdl, p);
}
if (tde_src != NULL)
iter = tde_src->header_entry;
prev = NULL;
while (iter != NULL) {
/* update counters */
iter->last_ts.tv_sec = ts.tv_sec;
iter->packets++;
iter->bytes += p->pktlen;
/* If this packet triggered the rule with tag, we dont need
* to log it (the alert will log it) */
if (iter->first_time++ > 0 && iter->td != NULL) {
/* Update metrics; remove if tag expired; and set alerts */
switch (iter->td->metric) {
case DETECT_TAG_METRIC_PACKET:
if (iter->packets > iter->td->count) {
/* tag expired */
if (prev != NULL) {
tde = iter;
prev->next = iter->next;
iter = iter->next;
DetectTagDataEntryFree(tde);
continue;
} else {
tde = iter;
iter = iter->next;
SCFree(tde);
tde_src->header_entry = NULL;
continue;
}
} else if (flag_added == 0) {
/* It's matching the tag. Add it to be logged and
* update "flag_added" to add the packet once. */
PacketAlertAppendTag(det_ctx, p);
p->flags |= PKT_HAS_TAG;
flag_added++;
}
break;
case DETECT_TAG_METRIC_BYTES:
if (iter->bytes > iter->td->count) {
/* tag expired */
if (prev != NULL) {
tde = iter;
prev->next = iter->next;
iter = iter->next;
DetectTagDataEntryFree(tde);
continue;
} else {
tde = iter;
iter = iter->next;
SCFree(tde);
tde_src->header_entry = NULL;
continue;
}
} else if (flag_added == 0) {
/* It's matching the tag. Add it to be logged and
* update "flag_added" to add the packet once. */
PacketAlertAppendTag(det_ctx, p);
p->flags |= PKT_HAS_TAG;
flag_added++;
}
break;
case DETECT_TAG_METRIC_SECONDS:
/* last_ts handles this metric, but also a generic time based
* expiration to prevent dead sessions/hosts */
if (iter->last_ts.tv_sec - iter->first_ts.tv_sec > iter->td->count) {
/* tag expired */
if (prev != NULL) {
tde = iter;
prev->next = iter->next;
iter = iter->next;
DetectTagDataEntryFree(tde);
continue;
} else {
tde = iter;
iter = iter->next;
SCFree(tde);
tde_src->header_entry = NULL;
continue;
}
} else if (flag_added == 0) {
/* It's matching the tag. Add it to be logged and
* update "flag_added" to add the packet once. */
PacketAlertAppendTag(det_ctx, p);
p->flags |= PKT_HAS_TAG;
flag_added++;
}
break;
}
}
prev = iter;
iter = iter->next;
}
if (tde_dst != NULL)
iter = tde_dst->header_entry;
prev = NULL;
while (iter != NULL) {
/* update counters */
iter->last_ts.tv_sec = ts.tv_sec;
iter->packets++;
iter->bytes += p->pktlen;
/* If this packet triggered the rule with tag, we dont need
* to log it (the alert will log it) */
if (iter->first_time++ > 0 && iter->td != NULL) {
/* Update metrics; remove if tag expired; and set alerts */
switch (iter->td->metric) {
case DETECT_TAG_METRIC_PACKET:
if (iter->packets > iter->td->count) {
/* tag expired */
if (prev != NULL) {
tde = iter;
prev->next = iter->next;
iter = iter->next;
DetectTagDataEntryFree(tde);
continue;
} else {
tde = iter;
iter = iter->next;
SCFree(tde);
tde_dst->header_entry = NULL;
continue;
}
} else if (flag_added == 0) {
/* It's matching the tag. Add it to be logged and
* update "flag_added" to add the packet once. */
PacketAlertAppendTag(det_ctx, p);
p->flags |= PKT_HAS_TAG;
flag_added++;
}
break;
case DETECT_TAG_METRIC_BYTES:
if (iter->bytes > iter->td->count) {
/* tag expired */
if (prev != NULL) {
tde = iter;
prev->next = iter->next;
iter = iter->next;
DetectTagDataEntryFree(tde);
continue;
} else {
tde = iter;
iter = iter->next;
SCFree(tde);
tde_dst->header_entry = NULL;
continue;
}
} else if (flag_added == 0) {
/* It's matching the tag. Add it to be logged and
* update "flag_added" to add the packet once. */
PacketAlertAppendTag(det_ctx, p);
p->flags |= PKT_HAS_TAG;
flag_added++;
}
break;
case DETECT_TAG_METRIC_SECONDS:
/* last_ts handles this metric, but also a generic time based
* expiration to prevent dead sessions/hosts */
if (iter->last_ts.tv_sec - iter->first_ts.tv_sec > iter->td->count) {
/* tag expired */
if (prev != NULL) {
tde = iter;
prev->next = iter->next;
iter = iter->next;
DetectTagDataEntryFree(tde);
continue;
} else {
tde = iter;
iter = iter->next;
SCFree(tde);
tde_dst->header_entry = NULL;
continue;
}
} else if (flag_added == 0) {
/* It's matching the tag. Add it to be logged and
* update "flag_added" to add the packet once. */
PacketAlertAppendTag(det_ctx, p);
p->flags |= PKT_HAS_TAG;
flag_added++;
}
break;
}
}
prev = iter;
iter = iter->next;
}
SCMutexUnlock(&tag_ctx->lock);
}
/**
* \brief Removes the entries exceding the max timeout value
*
* \param tag_ctx Tag context
* \param ts the current time
*
*/
static void TagTimeoutRemove(DetectTagHostCtx *tag_ctx, struct timeval *tv)
{
HashListTableBucket *next = NULL;
HashListTableBucket *buck = NULL;
DetectTagDataEntry *tde= NULL;
DetectTagDataEntry *tmp = NULL;
DetectTagDataEntry *prev= NULL;
DetectTagDataEntryList *tdl = NULL;
buck = HashListTableGetListHead(tag_ctx->tag_hash_table_ipv4);
while (buck != NULL) {
/* get the next before we free "buck" */
next = HashListTableGetListNext(buck);
tdl = HashListTableGetListData(buck);
if (tdl != NULL && tdl->header_entry != NULL) {
tmp = tdl->header_entry;
prev = NULL;
while (tmp != NULL) {
if ((tv->tv_sec - tmp->last_ts.tv_sec) <= TAG_MAX_LAST_TIME_SEEN) {
tmp = tmp->next;
continue;
}
if (prev != NULL) {
prev->next = tmp->next;
tde = tmp;
tmp = tmp->next;
SCFree(tde);
} else {
tdl->header_entry = tmp->next;
tde = tmp;
tmp = tmp->next;
SCFree(tde);
}
}
}
buck = next;
}
buck = HashListTableGetListHead(tag_ctx->tag_hash_table_ipv6);
while (buck != NULL) {
/* get the next before we free "buck" */
next = HashListTableGetListNext(buck);
tdl = HashListTableGetListData(buck);
if (tdl != NULL && tdl->header_entry != NULL) {
tmp = tdl->header_entry;
prev = NULL;
while (tmp != NULL) {
if ((tv->tv_sec - tmp->last_ts.tv_sec) <= TAG_MAX_LAST_TIME_SEEN) {
tmp = tmp->next;
continue;
}
if (prev != NULL) {
prev->next = tmp->next;
tde = tmp;
tmp = tmp->next;
SCFree(tde);
} else {
tdl->header_entry = tmp->next;
tde = tmp;
tmp = tmp->next;
SCFree(tde);
}
}
}
buck = next;
}
return;
}

@ -0,0 +1,58 @@
/* Copyright (C) 2007-2010 Open Information Security Foundation
*
* You can copy, redistribute or modify this Program under the terms of
* the GNU General Public License version 2 as published by the Free
* Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* version 2 along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
/**
* \file detect-engine-tag.h
*
* \author Pablo Rincon Crespo <pablo.rincon.crespo@gmail.com>
*
* Implements a global context to store data related to hosts flagged
* tag keyword
*/
#ifndef __DETECT_ENGINE_TAG_H__
#define __DETECT_ENGINE_TAG_H__
#include "detect.h"
#define TAG_HASH_SIZE 0xffff
/* This limit should be overwriten/predefined at the config file
* to limit the options to prevent possible DOS situations. We should also
* create a limit for bytes and a limit for number of packets */
#define TAG_MAX_LAST_TIME_SEEN 600
#define TAG_TIMEOUT_CHECK_INTERVAL 60
/* Used for tagged data (sid and gid of the packets that
* follow the one that triggered the rule with tag option) */
#define TAG_SIG_GEN 2
#define TAG_SIG_ID 1
void TagHashInit(DetectTagHostCtx *);
int TagHashAddTag(DetectTagHostCtx *, DetectTagDataEntry *, Packet *);
void TagContextDestroy(DetectTagHostCtx *);
void TagHandlePacket(DetectEngineCtx *, DetectEngineThreadCtx *,
Packet *);
void TagInitCtx(void);
void TagDestroyCtx(void);
void TagRestartCtx(void);
#endif /* __DETECT_ENGINE_TAG_H__ */

@ -52,40 +52,6 @@
#include "util-var-name.h"
#include "tm-modules.h"
/**
* \brief Handle a packet and check if needs a threshold logic
*
* \param de_ctx Detection Context
* \param sig Signature pointer
* \param p Packet structure
*
*/
int PacketAlertHandle(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx,
Signature *s, Packet *p, uint16_t pos)
{
SCEnter();
int ret = 0;
/* retrieve the sig match data */
DetectThresholdData *td = SigGetThresholdType(s,p);
SCLogDebug("td %p", td);
/* if have none just alert, otherwise handle thresholding */
if (td == NULL) {
/* Already inserted so get out */
ret = 1;
} else {
ret = PacketAlertThreshold(de_ctx, det_ctx, td, p, s);
if (ret == 0) {
/* It doesn't match threshold, remove it */
PacketAlertRemove(p, pos);
}
}
SCReturnInt(ret);
}
/**
* \brief Check if a certain signature has threshold option
*

@ -35,6 +35,7 @@
#include "detect-engine-port.h"
#include "detect-engine-mpm.h"
#include "detect-engine-iponly.h"
#include "detect-engine-tag.h"
#include "detect-engine.h"

@ -216,6 +216,33 @@ void SigMatchAppendDcePayload(Signature *s, SigMatch *new) {
return;
}
/** \brief Append a sig match to the signatures tag match list
* This is done on other list because the tag keyword
* should be always the last inspected (never ordered)
*
* \param s signature
* \param new sigmatch to append
*/
void SigMatchAppendTag(Signature *s, SigMatch *new) {
if (s->tmatch == NULL) {
s->tmatch = new;
s->tmatch_tail = new;
new->next = NULL;
new->prev = NULL;
} else {
SigMatch *cur = s->tmatch_tail;
cur->next = new;
new->prev = cur;
new->next = NULL;
s->tmatch_tail = new;
}
new->idx = s->sm_cnt;
s->sm_cnt++;
return;
}
/** \brief Append a sig match to the signatures non-payload match list
*
* \param s signature

@ -60,6 +60,7 @@ void SigMatchAppendDcePayload(Signature *, SigMatch *);
void SigMatchAppendPacket(Signature *, SigMatch *);
void SigMatchAppendUricontent(Signature *, SigMatch *);
void SigMatchAppendAppLayer(Signature *, SigMatch *);
void SigMatchAppendTag(Signature *, SigMatch *);
#endif /* __DETECT_PARSE_H__ */

@ -16,30 +16,875 @@
*/
/**
* \file
* \file detect-tag.c
*
* \author Pablo Rincon <pablo.rincon.crespo@gmail.com>
* \author Victor Julien <victor@inliniac.net>
*
* Implements the tag keyword
*
* \todo Actually implement support
*/
#include "suricata-common.h"
#include "detect.h"
#include "detect-parse.h"
#include "detect-tag.h"
#include "detect-engine-tag.h"
#include "detect-engine.h"
static int DetectTagSetup(DetectEngineCtx *, Signature *, char *);
#include "debug.h"
#include "decode.h"
#include "flow.h"
#include "flow-var.h"
#include "stream-tcp-private.h"
#include "util-time.h"
#include "util-byte.h"
#include "util-unittest.h"
#include "util-unittest-helper.h"
#include "util-debug.h"
extern DetectTagHostCtx *tag_ctx;
/* format: tag: <type>, <count>, <metric>, [direction]; */
#define PARSE_REGEX "^\\s*(host|session)\\s*(,\\s*(\\d+)\\s*,\\s*(packets|bytes|seconds)\\s*(,\\s*(src|dst))?\\s*)?$"
static pcre *parse_regex;
static pcre_extra *parse_regex_study;
int DetectTagMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *);
static int DetectTagSetup (DetectEngineCtx *, Signature *, char *);
void DetectTagRegisterTests(void);
void DetectTagDataFree(void *);
/**
* \brief Registration function for keyword tag
*/
void DetectTagRegister (void) {
sigmatch_table[DETECT_TAG].name = "tag";
sigmatch_table[DETECT_TAG].Match = NULL;
sigmatch_table[DETECT_TAG].Match = DetectTagMatch;
sigmatch_table[DETECT_TAG].Setup = DetectTagSetup;
sigmatch_table[DETECT_TAG].Free = NULL;
sigmatch_table[DETECT_TAG].RegisterTests = NULL;
sigmatch_table[DETECT_TAG].Free = DetectTagDataFree;
sigmatch_table[DETECT_TAG].RegisterTests = DetectTagRegisterTests;
const char *eb;
int eo;
int opts = 0;
parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL);
if(parse_regex == NULL)
{
SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at offset %" PRId32 ": %s", PARSE_REGEX, eo, eb);
goto error;
}
parse_regex_study = pcre_study(parse_regex, 0, &eb);
if(eb != NULL)
{
SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb);
goto error;
}
return;
error:
/* XXX */
return;
}
/**
* \brief This function is used to add a tag to a session (type session)
* or update it if it's already installed. The number of times to
* allow an update is limited by DETECT_TAG_MATCH_LIMIT. This way
* repetitive matches to the same rule are limited of setting tags,
* to avoid DOS attacks
*
* \param p pointer to the current packet
* \param tde pointer to the new DetectTagDataEntry
*
* \retval 0 if the tde was added succesfuly
* \retval 1 if an entry of this sid/gid already exist and was updated
*/
int DetectTagFlowAdd(Packet *p, DetectTagDataEntry *tde) {
uint8_t updated = 0;
uint16_t num_tags = 0;
DetectTagDataEntry *iter = NULL;
SCMutexLock(&p->flow->m);
if (p->flow->tag_list == NULL) {
p->flow->tag_list = SCMalloc(sizeof(DetectTagDataEntryList));
memset(p->flow->tag_list, 0, sizeof(DetectTagDataEntryList));
} else {
iter = p->flow->tag_list->header_entry;
}
/* First iterate installed entries searching a duplicated sid/gid */
for (; iter != NULL; iter = iter->next) {
num_tags++;
if (iter->sid == tde->sid && iter->gid == tde->gid) {
iter->cnt_match++;
/* If so, update data, unless the maximum MATCH limit is
* reached. This prevents possible DOS attacks */
if (iter->cnt_match < DETECT_TAG_MATCH_LIMIT) {
/* Reset time and counters */
iter->first_ts.tv_sec = iter->last_ts.tv_sec = tde->first_ts.tv_sec;
iter->packets = 0;
iter->bytes = 0;
}
updated = 1;
break;
}
}
/* If there was no entry of this rule, prepend the new tde */
if (updated == 0 && num_tags < DETECT_TAG_MAX_TAGS) {
tde->next = p->flow->tag_list->header_entry;
p->flow->tag_list->header_entry = tde;
} else if (num_tags == DETECT_TAG_MAX_TAGS) {
SCLogDebug("Max tags for sessions reached (%"PRIu16")", num_tags);
}
SCMutexUnlock(&p->flow->m);
return updated;
}
/**
* \brief This function is used to setup a tag for session/host
*
* \param t pointer to thread vars
* \param det_ctx pointer to the pattern matcher thread
* \param p pointer to the current packet
* \param m pointer to the sigmatch that we will cast into DetectTagData
*
* \retval 0 no match
* \retval 1 match
*/
int DetectTagMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *m)
{
DetectTagData *td = (DetectTagData *) m->ctx;
DetectTagDataEntry *tde = NULL;
tde = SCMalloc(sizeof(DetectTagDataEntry));
if (tde == NULL) {
SCLogError(SC_ERR_MEM_ALLOC, "Allocation failed for tag entry. The rule will alert, but no session/host will be taged");
return 1;
}
memset(tde, 0, sizeof(DetectTagDataEntry));
tde->sid = s->id;
tde->gid = s->gid;
tde->td = td;
TimeGet(&tde->first_ts);
tde->last_ts.tv_sec = tde->first_ts.tv_sec;
switch (td->type) {
case DETECT_TAG_TYPE_HOST:
if (td->direction == DETECT_TAG_DIR_SRC || td->direction == DETECT_TAG_DIR_DST) {
SCLogDebug("Tagging Host with sid %"PRIu32":%"PRIu32"", s->id, s->gid);
if (TagHashAddTag(tag_ctx, tde, p) == 1)
DetectTagDataEntryFree(tde);
} else {
SCLogError(SC_ERR_INVALID_VALUE, "Error on direction of a tag keyword (not src nor dst)");
}
break;
case DETECT_TAG_TYPE_SESSION:
if (p->flow != NULL) {
/* If it already exists it will be updated */
if (DetectTagFlowAdd(p, tde) == 1)
DetectTagDataEntryFree(tde);
} else {
SCLogDebug("No flow to append the session tag");
}
break;
default:
SCLogError(SC_ERR_INVALID_VALUE, "Error on type of a tag keyword (not session nor host)");
break;
}
return 1;
}
/**
* \brief This function is used to parse tag options passed to tag keyword
*
* \param tagstr Pointer to the user provided tag options
*
* \retval td pointer to DetectTagData on success
* \retval NULL on failure
*/
DetectTagData *DetectTagParse (char *tagstr)
{
DetectTagData td;
#define MAX_SUBSTRINGS 30
int ret = 0, res = 0;
int ov[MAX_SUBSTRINGS];
ret = pcre_exec(parse_regex, parse_regex_study, tagstr, strlen(tagstr), 0, 0, ov, MAX_SUBSTRINGS);
if (ret < 1) {
SCLogError(SC_ERR_PCRE_MATCH, "parse error, ret %" PRId32 ", string %s", ret, tagstr);
goto error;
}
const char *str_ptr;
res = pcre_get_substring((char *)tagstr, ov, MAX_SUBSTRINGS, 1, &str_ptr);
if (res < 0) {
SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed");
goto error;
}
/* Type */
if (strcasecmp("session", str_ptr) == 0) {
td.type = DETECT_TAG_TYPE_SESSION;
} else if (strcasecmp("host", str_ptr) == 0) {
td.type = DETECT_TAG_TYPE_HOST;
} else {
SCLogError(SC_ERR_INVALID_VALUE, "Invalid argument type. Must be session or host (%s)", tagstr);
goto error;
}
/* default tag is 256 packets from session or dst host */
td.count = DETECT_TAG_MAX_PKTS;
td.metric = DETECT_TAG_METRIC_PACKET;
td.direction = DETECT_TAG_DIR_DST;
if (ret > 4) {
res = pcre_get_substring((char *)tagstr, ov, MAX_SUBSTRINGS, 3, &str_ptr);
if (res < 0) {
SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed");
goto error;
}
/* count */
if (ByteExtractStringUint32(&td.count, 10, strlen(str_ptr),
str_ptr) <= 0) {
SCLogError(SC_ERR_INVALID_VALUE, "Invalid argument for count. Must be a value in the range of 0 to %"PRIu32" (%s)", UINT32_MAX, tagstr);
goto error;
}
res = pcre_get_substring((char *)tagstr, ov, MAX_SUBSTRINGS, 4, &str_ptr);
if (res < 0) {
SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed");
goto error;
}
/* metric */
if (strcasecmp("packets", str_ptr) == 0) {
td.metric = DETECT_TAG_METRIC_PACKET;
if (DETECT_TAG_MAX_PKTS > 0 && td.count > DETECT_TAG_MAX_PKTS)
td.count = DETECT_TAG_MAX_PKTS;
/* TODO: load DETECT_TAG_MAX_PKTS from config */
} else if (strcasecmp("seconds", str_ptr) == 0) {
td.metric = DETECT_TAG_METRIC_SECONDS;
} else if (strcasecmp("bytes", str_ptr) == 0) {
td.metric = DETECT_TAG_METRIC_BYTES;
} else {
SCLogError(SC_ERR_INVALID_VALUE, "Invalid argument metric. Must be one of \"seconds\", \"packets\" or \"bytes\" (%s)", tagstr);
goto error;
}
/* if specified, overwrite it */
if (ret == 7) {
res = pcre_get_substring((char *)tagstr, ov, MAX_SUBSTRINGS, 6, &str_ptr);
if (res < 0) {
SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed");
goto error;
}
/* metric */
if (strcasecmp("src", str_ptr) == 0) {
td.direction = DETECT_TAG_DIR_SRC;
} else if (strcasecmp("dst", str_ptr) == 0) {
td.direction = DETECT_TAG_DIR_DST;
} else {
SCLogError(SC_ERR_INVALID_VALUE, "Invalid argument direction. Must be one of \"src\" or \"dst\" (only valid for tag host type, not sessions) (%s)", tagstr);
goto error;
}
if (td.type != DETECT_TAG_TYPE_HOST) {
SCLogWarning(SC_ERR_INVALID_VALUE, "Argument direction doesn't make sense for type \"session\" (%s [%"PRIu8"])", tagstr, td.type);
}
}
}
DetectTagData *real_td = SCMalloc(sizeof(DetectTagData));
if (real_td == NULL) {
SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory");
goto error;
}
memcpy(real_td, &td, sizeof(DetectTagData));
return real_td;
error:
return NULL;
}
static int DetectTagSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawstr)
/**
* \brief this function is used to add the parsed tag data into the current signature
*
* \param de_ctx pointer to the Detection Engine Context
* \param s pointer to the Current Signature
* \param tagstr pointer to the user provided tag options
*
* \retval 0 on Success
* \retval -1 on Failure
*/
int DetectTagSetup (DetectEngineCtx *de_ctx, Signature *s, char *tagstr)
{
DetectTagData *td = NULL;
SigMatch *sm = NULL;
td = DetectTagParse(tagstr);
if (td == NULL) goto error;
sm = SigMatchAlloc();
if (sm == NULL)
goto error;
sm->type = DETECT_TAG;
sm->ctx = (void *)td;
/* Append it to the list of tags */
SigMatchAppendTag(s, sm);
return 0;
error:
if (td != NULL) DetectTagDataFree(td);
if (sm != NULL) SCFree(sm);
return -1;
}
/**
* \brief this function will free all the entries of a list
* DetectTagDataEntry
*
* \param td pointer to DetectTagDataEntryList
*/
void DetectTagDataListFree(void *ptr) {
if (ptr != NULL) {
DetectTagDataEntryList *list = (DetectTagDataEntryList *)ptr;
DetectTagDataEntryFree(list->header_entry);
SCFree(ptr);
}
}
/**
* \brief this function will free memory associated with
* DetectTagDataEntry
*
* \param td pointer to DetectTagDataEntry
*/
void DetectTagDataEntryFree(void *ptr) {
if (ptr != NULL) {
DetectTagDataEntry *dte = (DetectTagDataEntry *)ptr;
if (dte->next != NULL)
DetectTagDataEntryFree(dte->next);
SCFree(ptr);
}
}
/**
* \brief this function will free memory associated with DetectTagData
*
* \param td pointer to DetectTagData
*/
void DetectTagDataFree(void *ptr) {
DetectTagData *td = (DetectTagData *)ptr;
SCFree(td);
}
#ifdef UNITTESTS
/**
* \test DetectTagTestParse01 is a test to make sure that we return "something"
* when given valid tag opt
*/
int DetectTagTestParse01 (void) {
int result = 0;
DetectTagData *td = NULL;
td = DetectTagParse("session, 123, packets");
if (td != NULL && td->type == DETECT_TAG_TYPE_SESSION
&& td->count == 123
&& td->metric == DETECT_TAG_METRIC_PACKET) {
DetectTagDataFree(td);
result = 1;
}
return result;
}
/**
* \test DetectTagTestParse02 is a test to check that we parse tag correctly
*/
int DetectTagTestParse02 (void) {
int result = 0;
DetectTagData *td = NULL;
td = DetectTagParse("host, 200, bytes, src");
if (td != NULL && td->type == DETECT_TAG_TYPE_HOST
&& td->count == 200
&& td->metric == DETECT_TAG_METRIC_BYTES
&& td->direction == DETECT_TAG_DIR_SRC) {
result = 1;
DetectTagDataFree(td);
}
return result;
}
/**
* \test DetectTagTestParse03 is a test for setting the stateless tag opt
*/
int DetectTagTestParse03 (void) {
int result = 0;
DetectTagData *td = NULL;
td = DetectTagParse("host, 200, bytes, dst");
if (td != NULL && td->type == DETECT_TAG_TYPE_HOST
&& td->count == 200
&& td->metric == DETECT_TAG_METRIC_BYTES
&& td->direction == DETECT_TAG_DIR_DST) {
result = 1;
DetectTagDataFree(td);
}
return result;
}
/**
* \test DetectTagTestParse04 is a test for default opts
*/
int DetectTagTestParse04 (void) {
int result = 0;
DetectTagData *td = NULL;
td = DetectTagParse("session");
if (td != NULL && td->type == DETECT_TAG_TYPE_SESSION
&& td->count == DETECT_TAG_MAX_PKTS
&& td->metric == DETECT_TAG_METRIC_PACKET) {
result = 1;
DetectTagDataFree(td);
}
return result;
}
/**
* \test DetectTagTestParse05 is a test for default opts
*/
int DetectTagTestParse05 (void) {
int result = 0;
DetectTagData *td = NULL;
td = DetectTagParse("host");
if (td != NULL && td->type == DETECT_TAG_TYPE_HOST
&& td->count == DETECT_TAG_MAX_PKTS
&& td->metric == DETECT_TAG_METRIC_PACKET
&& td->direction == DETECT_TAG_DIR_DST) {
result = 1;
DetectTagDataFree(td);
}
return result;
}
/**
* \test DetectTagTestPacket01 is a test to check tagged hosts
*/
int DetectTagTestPacket01 (void) {
int result = 0;
uint8_t *buf = (uint8_t *)"Hi all!";
uint8_t *buf2 = (uint8_t *)"lalala!";
uint16_t buf_len = strlen((char *)buf);
uint16_t buf_len2 = strlen((char *)buf2);
Packet *p[7];
p[0] = UTHBuildPacketReal(buf, buf_len, IPPROTO_TCP,
"192.168.1.5", "192.168.1.1",
41424, 80);
p[1] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP,
"192.168.1.5", "192.168.1.1",
41424, 80);
p[2] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP,
"192.168.1.5", "192.168.1.9",
41424, 80);
p[3] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP,
"192.168.1.5", "192.168.1.9",
41424, 80);
p[4] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP,
"192.168.1.1", "192.168.1.9",
41424, 80);
p[5] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP,
"192.168.1.1", "192.168.1.11",
41424, 80);
p[6] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP,
"192.168.1.5", "192.168.1.11",
41424, 80);
char *sigs[5];
sigs[0]= "alert tcp any any -> any any (msg:\"Testing tag 1\"; content:\"Hi all\"; tag:host, 3, packets, src; sid:4;)";
sigs[1]= "alert tcp any any -> any any (msg:\"Testing tag 2\"; content:\"Hi all\"; tag:host, 4, packets, dst; sid:5;)";
sigs[2]= "alert tcp any any -> any any (msg:\"Testing tag 2\"; content:\"no match\"; sid:3;)";
sigs[3]= "alert tcp any any -> any any (msg:\"Testing tag 2\"; content:\"no match\"; sid:6;)";
sigs[4]= "alert tcp any any -> any any (msg:\"Testing tag 2\"; content:\"no match\"; sid:2;)";
/* Please, Notice that tagged data goes with sig_id = 1 and tag sig generator = 2 */
uint32_t sid[5] = {1,2,3,4,5};
int32_t results[7][5] = {
{0, 0, 0, 1, 1},
{1, 0, 0, 0, 0},
{1, 0, 0, 0, 0},
{0, 0, 0, 0, 0},
{1, 0, 0, 0, 0},
{1, 0, 0, 0, 0},
{0, 0, 0, 0, 0}
};
result = UTHGenericTest(p, 7, sigs, sid, (uint32_t *) results, 5);
UTHFreePackets(p, 7);
TagRestartCtx();
return result;
}
/**
* \test DetectTagTestPacket02 is a test to check tagged hosts
*/
int DetectTagTestPacket02 (void) {
int result = 0;
uint8_t *buf = (uint8_t *)"Hi all!";
uint8_t *buf2 = (uint8_t *)"lalala!";
uint16_t buf_len = strlen((char *)buf);
uint16_t buf_len2 = strlen((char *)buf2);
DecodeThreadVars dtv;
ThreadVars th_v;
DetectEngineThreadCtx *det_ctx = NULL;
memset(&dtv, 0, sizeof(DecodeThreadVars));
memset(&th_v, 0, sizeof(th_v));
DetectEngineCtx *de_ctx = DetectEngineCtxInit();
if (de_ctx == NULL) {
goto end;
}
de_ctx->flags |= DE_QUIET;
Packet *p[7];
p[0] = UTHBuildPacketReal(buf, buf_len, IPPROTO_TCP,
"192.168.1.5", "192.168.1.1",
41424, 80);
p[1] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP,
"192.168.1.5", "192.168.1.1",
41424, 80);
p[2] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP,
"192.168.1.5", "192.168.1.9",
41424, 80);
p[3] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP,
"192.168.1.5", "192.168.1.9",
41424, 80);
p[4] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP,
"192.168.1.1", "192.168.1.9",
41424, 80);
p[5] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP,
"192.168.1.1", "192.168.1.11",
41424, 80);
p[6] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP,
"192.168.1.5", "192.168.1.11",
41424, 80);
char *sigs[5];
sigs[0]= "alert tcp any any -> any any (msg:\"Testing tag 1\"; content:\"Hi all\"; tag:host, 3, seconds, src; sid:4;)";
sigs[1]= "alert tcp any any -> any any (msg:\"Testing tag 2\"; content:\"Hi all\"; tag:host, 4, seconds, dst; sid:5;)";
sigs[2]= "alert tcp any any -> any any (msg:\"Testing tag 2\"; content:\"no match\"; sid:3;)";
sigs[3]= "alert tcp any any -> any any (msg:\"Testing tag 2\"; content:\"no match\"; sid:6;)";
sigs[4]= "alert tcp any any -> any any (msg:\"Testing tag 2\"; content:\"no match\"; sid:2;)";
/* Please, Notice that tagged data goes with sig_id = 1 and tag sig generator = 2 */
uint32_t sid[5] = {1,2,3,4,5};
int numsigs = 5;
if (UTHAppendSigs(de_ctx, sigs, numsigs) == 0)
goto cleanup;
//de_ctx->flags |= DE_QUIET;
int32_t results[7][5] = {
{0, 0, 0, 1, 1},
{1, 0, 0, 0, 0},
{1, 0, 0, 0, 0},
{1, 0, 0, 0, 0},
{0, 0, 0, 0, 0},
{0, 0, 0, 0, 0},
{0, 0, 0, 0, 0}
};
int num_packets = 7;
SigGroupBuild(de_ctx);
DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
int i = 0;
for (; i < num_packets; i++) {
SigMatchSignatures(&th_v, de_ctx, det_ctx, p[i]);
if (UTHCheckPacketMatchResults(p[i], sid, (uint32_t *)&results[i][0], numsigs) == 0)
goto cleanup;
if (i == 3)
TimeSetIncrementTime(10);
}
result = 1;
cleanup:
UTHFreePackets(p, 7);
if (det_ctx != NULL)
DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
if (de_ctx != NULL) {
SigGroupCleanup(de_ctx);
SigCleanSignatures(de_ctx);
DetectEngineCtxFree(de_ctx);
}
end:
TagRestartCtx();
return result;
}
/**
* \test DetectTagTestPacket03 is a test to check tagged hosts
*/
int DetectTagTestPacket03 (void) {
int result = 0;
uint8_t *buf = (uint8_t *)"Hi all!";
uint8_t *buf2 = (uint8_t *)"lalala!";
uint16_t buf_len = strlen((char *)buf);
uint16_t buf_len2 = strlen((char *)buf2);
DecodeThreadVars dtv;
ThreadVars th_v;
DetectEngineThreadCtx *det_ctx = NULL;
memset(&dtv, 0, sizeof(DecodeThreadVars));
memset(&th_v, 0, sizeof(th_v));
DetectEngineCtx *de_ctx = DetectEngineCtxInit();
if (de_ctx == NULL) {
goto end;
}
de_ctx->flags |= DE_QUIET;
Packet *p[7];
p[0] = UTHBuildPacketReal(buf, buf_len, IPPROTO_TCP,
"192.168.1.5", "192.168.1.1",
41424, 80);
p[1] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP,
"192.168.1.5", "192.168.1.1",
41424, 80);
p[2] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP,
"192.168.1.5", "192.168.1.9",
41424, 80);
p[3] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP,
"192.168.1.5", "192.168.1.9",
41424, 80);
p[4] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP,
"192.168.1.1", "192.168.1.9",
41424, 80);
p[5] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP,
"192.168.1.1", "192.168.1.11",
41424, 80);
p[6] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP,
"192.168.1.5", "192.168.1.11",
41424, 80);
char *sigs[5];
sigs[0]= "alert tcp any any -> any any (msg:\"Testing tag 1\"; content:\"Hi all\"; tag:host, 150, bytes, src; sid:4;)";
sigs[1]= "alert tcp any any -> any any (msg:\"Testing tag 2\"; content:\"Hi all\"; tag:host, 150, bytes, dst; sid:5;)";
sigs[2]= "alert tcp any any -> any any (msg:\"Testing tag 2\"; content:\"no match\"; sid:3;)";
sigs[3]= "alert tcp any any -> any any (msg:\"Testing tag 2\"; content:\"no match\"; sid:6;)";
sigs[4]= "alert tcp any any -> any any (msg:\"Testing tag 2\"; content:\"no match\"; sid:2;)";
/* Please, Notice that tagged data goes with sig_id = 1 and tag sig generator = 2 */
uint32_t sid[5] = {1,2,3,4,5};
int numsigs = 5;
if (UTHAppendSigs(de_ctx, sigs, numsigs) == 0)
goto cleanup;
//de_ctx->flags |= DE_QUIET;
int32_t results[7][5] = {
{0, 0, 0, 1, 1},
{1, 0, 0, 0, 0},
{1, 0, 0, 0, 0},
{0, 0, 0, 0, 0},
{1, 0, 0, 0, 0},
{0, 0, 0, 0, 0},
{0, 0, 0, 0, 0}
};
int num_packets = 7;
SigGroupBuild(de_ctx);
DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
uint32_t sum = 0;
int i = 0;
for (; i < num_packets; i++) {
SigMatchSignatures(&th_v, de_ctx, det_ctx, p[i]);
sum += p[i]->pktlen;
//printf("Sum %"PRIu32"\n", sum);
if (UTHCheckPacketMatchResults(p[i], sid, (uint32_t *)&results[i][0], numsigs) == 0)
goto cleanup;
}
result = 1;
cleanup:
UTHFreePackets(p, 7);
if (det_ctx != NULL)
DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
if (de_ctx != NULL) {
SigGroupCleanup(de_ctx);
SigCleanSignatures(de_ctx);
DetectEngineCtxFree(de_ctx);
}
end:
TagRestartCtx();
return result;
}
/**
* \test DetectTagTestPacket04 is a test to check tagged hosts
*/
int DetectTagTestPacket04 (void) {
int result = 0;
uint8_t *buf = (uint8_t *)"Hi all!";
uint8_t *buf2 = (uint8_t *)"lalala!";
uint16_t buf_len = strlen((char *)buf);
uint16_t buf_len2 = strlen((char *)buf2);
Flow f;
TcpSession ssn;
memset(&f, 0, sizeof(f));
memset(&ssn, 0, sizeof(ssn));
f.protoctx = (void *)&ssn;
f.dst.family = AF_INET;
inet_pton(f.src.family, "192.168.1.5", f.src.addr_data32);
inet_pton(f.dst.family, "192.168.1.1", f.dst.addr_data32);
DecodeThreadVars dtv;
ThreadVars th_v;
DetectEngineThreadCtx *det_ctx = NULL;
memset(&dtv, 0, sizeof(DecodeThreadVars));
memset(&th_v, 0, sizeof(th_v));
DetectEngineCtx *de_ctx = DetectEngineCtxInit();
if (de_ctx == NULL) {
goto end;
}
de_ctx->flags |= DE_QUIET;
Packet *p[7];
p[0] = UTHBuildPacketReal(buf, buf_len, IPPROTO_TCP,
"192.168.1.5", "192.168.1.1",
41424, 80);
p[1] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP,
"192.168.1.5", "192.168.1.1",
41424, 80);
p[2] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP,
"192.168.1.5", "192.168.1.1",
41424, 80);
p[3] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP,
"192.168.1.5", "192.168.1.1",
41424, 80);
p[4] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP,
"192.168.1.1", "192.168.1.5",
80, 41424);
p[5] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP,
"192.168.1.1", "192.168.1.5",
80, 41424);
p[6] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP,
"192.168.1.5", "192.168.1.1",
80, 41424);
char *sigs[5];
sigs[0]= "alert tcp any any -> any any (msg:\"Testing tag 1\"; content:\"Hi all\"; tag:session, 5, packets; sid:4;)";
sigs[1]= "alert tcp any any -> any any (msg:\"Testing tag 2\"; content:\"blahblah\"; sid:5;)";
sigs[2]= "alert tcp any any -> any any (msg:\"Testing tag 2\"; content:\"no match\"; sid:3;)";
sigs[3]= "alert tcp any any -> any any (msg:\"Testing tag 2\"; content:\"no match\"; sid:6;)";
sigs[4]= "alert tcp any any -> any any (msg:\"Testing tag 2\"; content:\"no match\"; sid:2;)";
/* Please, Notice that tagged data goes with sig_id = 1 and tag sig generator = 2 */
uint32_t sid[5] = {1,2,3,4,5};
int numsigs = 5;
if (UTHAppendSigs(de_ctx, sigs, numsigs) == 0)
goto cleanup;
//de_ctx->flags |= DE_QUIET;
int32_t results[7][5] = {
{0, 0, 0, 1, 0},
{1, 0, 0, 0, 0},
{1, 0, 0, 0, 0},
{1, 0, 0, 0, 0},
{1, 0, 0, 0, 0},
{0, 0, 0, 0, 0},
{0, 0, 0, 0, 0}
};
int num_packets = 7;
SigGroupBuild(de_ctx);
DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
uint32_t sum = 0;
int i = 0;
for (; i < num_packets; i++) {
p[i]->flow = &f;
p[i]->flow->protoctx = &ssn;
SigMatchSignatures(&th_v, de_ctx, det_ctx, p[i]);
sum += p[i]->pktlen;
//printf("Sum %"PRIu32"\n", sum);
if (UTHCheckPacketMatchResults(p[i], sid, (uint32_t *)&results[i][0], numsigs) == 0)
goto cleanup;
}
result = 1;
cleanup:
UTHFreePackets(p, 7);
if (det_ctx != NULL)
DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
if (de_ctx != NULL) {
SigGroupCleanup(de_ctx);
SigCleanSignatures(de_ctx);
DetectEngineCtxFree(de_ctx);
}
end:
TagRestartCtx();
return result;
}
#endif /* UNITTESTS */
/**
* \brief this function registers unit tests for DetectTag
*/
void DetectTagRegisterTests(void) {
#ifdef UNITTESTS
UtRegisterTest("DetectTagTestParse01", DetectTagTestParse01, 1);
UtRegisterTest("DetectTagTestParse02", DetectTagTestParse02, 1);
UtRegisterTest("DetectTagTestParse03", DetectTagTestParse03, 1);
UtRegisterTest("DetectTagTestParse04", DetectTagTestParse04, 1);
UtRegisterTest("DetectTagTestParse05", DetectTagTestParse05, 1);
UtRegisterTest("DetectTagTestPacket01", DetectTagTestPacket01, 1);
UtRegisterTest("DetectTagTestPacket02", DetectTagTestPacket02, 1);
UtRegisterTest("DetectTagTestPacket03", DetectTagTestPacket03, 1);
UtRegisterTest("DetectTagTestPacket04", DetectTagTestPacket04, 1);
#endif /* UNITTESTS */
}

@ -18,14 +18,85 @@
/**
* \file
*
* \author Pablo Rincon <pablo.rincon.crespo@gmail.com>
* \author Victor Julien <victor@inliniac.net>
*/
#ifndef __DETECT_TAG_H__
#define __DETECT_TAG_H__
#include "suricata-common.h"
#include "suricata.h"
#include "util-time.h"
/* Limit the number of times a session can be tagged by the
* same rule without finishing older tags */
#define DETECT_TAG_MATCH_LIMIT 10
/* Limit the number of tags that a session can have */
#define DETECT_TAG_MAX_TAGS 50
/* Limit the number of pkts to capture. Change this to
* zero to make it unlimited
* TODO: load it from config (var tagged_packet_limit) */
#define DETECT_TAG_MAX_PKTS 256
/* Type of tag: session or host */
enum {
DETECT_TAG_TYPE_SESSION,
DETECT_TAG_TYPE_HOST,
DETECT_TAG_TYPE_MAX
};
enum {
DETECT_TAG_DIR_SRC,
DETECT_TAG_DIR_DST,
DETECT_TAG_DIR_MAX
};
enum {
DETECT_TAG_METRIC_PACKET,
DETECT_TAG_METRIC_SECONDS,
DETECT_TAG_METRIC_BYTES,
DETECT_TAG_METRIC_MAX
};
/** This will be the rule options/parameters */
typedef struct DetectTagData_ {
uint8_t type; /**< tag type */
uint32_t count; /**< count */
uint32_t metric; /**< metric */
uint8_t direction; /**< host direction */
} DetectTagData;
/** This is the installed data at the session/global or host table */
typedef struct DetectTagDataEntry_ {
DetectTagData *td; /**< Pointer referencing the tag parameters */
uint32_t sid; /**< sid originating the tag */
uint32_t gid; /**< gid originating the tag */
uint32_t packets; /**< number of packets */
uint32_t bytes; /**< number of bytes */
struct timeval first_ts; /**< First time seen (for metric = seconds) */
struct timeval last_ts; /**< Last time seen (to prune old sessions) */
struct DetectTagDataEntry_ *next; /**< Pointer to the next tag of this
* session/src_host/dst_host (if any from other rule) */
uint16_t cnt_match; /**< number of times this tag was reset/updated */
uint8_t first_time; /**< Used at unified output. The first packet write the
header with the data of the sig. The next packets use
gid/sid/rev of the tagging engine */
} DetectTagDataEntry;
typedef struct DetectTagDataEntryList_ {
DetectTagDataEntry *header_entry;
Address addr; /**< Var used to store dst or src addr */
uint8_t ipv; /**< IP Version */
}DetectTagDataEntryList;
/* prototypes */
void DetectTagRegister (void);
void DetectTagDataFree(void *ptr);
void DetectTagDataEntryFree(void *ptr);
void DetectTagDataListFree(void *ptr);
#endif /* __DETECT_TAG_H__ */

@ -659,11 +659,13 @@ static int DetectTlsVersionTestDetect03(void) {
result = 1;
end:
if (de_ctx) {
SigGroupCleanup(de_ctx);
SigCleanSignatures(de_ctx);
DetectEngineCtxFree(de_ctx);
}
DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
DetectEngineCtxFree(de_ctx);
FlowL7DataPtrFree(&f);
StreamTcpFreeConfig(TRUE);

@ -1235,6 +1235,7 @@ end:
* match
*/
static int DetectUriSigTest05(void) {
DetectEngineCtx *de_ctx = NULL;
int result = 0;
Flow f;
HtpState *http_state = NULL;
@ -1283,7 +1284,7 @@ static int DetectUriSigTest05(void) {
ssn.toserver_smsg_head = stream_msg;
ssn.toserver_smsg_tail = stream_msg;
DetectEngineCtx *de_ctx = DetectEngineCtxInit();
de_ctx = DetectEngineCtxInit();
if (de_ctx == NULL) {
goto end;
}
@ -1361,6 +1362,7 @@ end:
* match
*/
static int DetectUriSigTest06(void) {
DetectEngineCtx *de_ctx = NULL;
int result = 0;
Flow f;
HtpState *http_state = NULL;
@ -1409,7 +1411,7 @@ static int DetectUriSigTest06(void) {
ssn.toserver_smsg_head = stream_msg;
ssn.toserver_smsg_tail = stream_msg;
DetectEngineCtx *de_ctx = DetectEngineCtxInit();
de_ctx = DetectEngineCtxInit();
if (de_ctx == NULL) {
goto end;
}

@ -931,6 +931,7 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh
end:
/* so now let's iterate the alerts and remove the ones after a pass rule
* matched (if any). This is done inside PacketAlertFinalize() */
/* PR: installed "tag" keywords are handled after the threshold inspection */
PacketAlertFinalize(de_ctx, det_ctx, p);
if (p->alerts.cnt > 0) {
SCPerfCounterAddUI64(det_ctx->counter_alerts, det_ctx->tv->sc_perf_pca, (uint64_t)p->alerts.cnt);

@ -40,6 +40,7 @@
#include "util-radix-tree.h"
#include "detect-threshold.h"
//#include "detect-engine-tag.h"
#define COUNTER_DETECT_ALERTS 1
@ -272,6 +273,8 @@ typedef struct Signature_ {
struct SigMatch_ *amatch_tail; /* general app layer matches, tail of the list */
struct SigMatch_ *dmatch; /* dce app layer matches */
struct SigMatch_ *dmatch_tail; /* dce app layer matches, tail of the list */
struct SigMatch_ *tmatch; /* list of tags matches */
struct SigMatch_ *tmatch_tail; /* tag matches, tail of the list */
/** ptr to the next sig in the list */
struct Signature_ *next;
@ -381,6 +384,15 @@ typedef struct ThresholdCtx_ {
uint32_t th_size;
} ThresholdCtx;
/** \brief tag ctx */
typedef struct DetectTagHostCtx_ {
HashListTable *tag_hash_table_ipv4; /**< Ipv4 hash table */
HashListTable *tag_hash_table_ipv6; /**< Ipv6 hash table */
SCMutex lock; /**< Mutex for the ctx */
struct timeval last_ts; /**< Last time the ctx was pruned */
} DetectTagHostCtx;
/** \brief main detection engine ctx */
typedef struct DetectEngineCtx_ {
uint8_t flags;

@ -49,6 +49,7 @@
(f)->aldata = NULL; \
(f)->alflags = 0; \
(f)->alproto = 0; \
(f)->tag_list = NULL; \
} while (0)
#define FLOW_RECYCLE(f) do { \
@ -78,6 +79,7 @@
(f)->aldata = NULL; \
(f)->alflags = 0; \
(f)->alproto = 0; \
DetectTagDataListFree((f)->tag_list); \
} while(0)
#define FLOW_DESTROY(f) do { \
@ -94,6 +96,7 @@
(f)->aldata = NULL; \
(f)->alflags = 0; \
(f)->alproto = 0; \
DetectTagDataListFree((f)->tag_list); \
} while(0)
Flow *FlowAlloc(void);

@ -27,6 +27,7 @@
#include "decode.h"
#include "util-var.h"
#include "util-atomic.h"
#include "detect-tag.h"
#define FLOW_QUIET TRUE
#define FLOW_VERBOSE FALSE
@ -183,6 +184,9 @@ typedef struct Flow_
SCMutex m;
/** List of tags of this flow (from "tag" keyword of type "session") */
DetectTagDataEntryList *tag_list;
/* list flow ptrs
* NOTE!!! These are NOT protected by the
* above mutex, but by the FlowQ's */

@ -52,6 +52,7 @@
#include "detect-engine-payload.h"
#include "detect-engine-dcepayload.h"
#include "detect-engine-state.h"
#include "detect-engine-tag.h"
#include "tm-queuehandlers.h"
#include "tm-queues.h"
@ -759,6 +760,8 @@ int main(int argc, char **argv)
#endif /* PROFILING */
SCReputationInitCtx();
TagInitCtx();
TmModuleReceiveNFQRegister();
TmModuleVerdictNFQRegister();
TmModuleDecodeNFQRegister();
@ -1168,10 +1171,13 @@ int main(int argc, char **argv)
}
}
#endif
SigCleanSignatures(de_ctx);
DetectEngineCtxFree(de_ctx);
AlpProtoDestroy();
TagDestroyCtx();
RunModeShutDown();
OutputDeregisterAll();
TimeDeinit();

@ -97,6 +97,8 @@ Packet *UTHBuildPacketIPV6Real(uint8_t *payload, uint16_t payload_len,
memset(p->tcph, 0, sizeof(TCPHdr));
p->tcph->th_sport = sport;
p->tcph->th_dport = dport;
p->pktlen = sizeof(IPV6Hdr) + sizeof(TCPHdr) + payload_len;
return p;
}
@ -159,6 +161,7 @@ Packet *UTHBuildPacketReal(uint8_t *payload, uint16_t payload_len,
memset(p->udph, 0, sizeof(UDPHdr));
p->udph->uh_sport = sport;
p->udph->uh_dport = dport;
p->pktlen = sizeof(IPV4Hdr) + sizeof(UDPHdr) + payload_len;
break;
case IPPROTO_TCP:
p->tcph = SCMalloc(sizeof(TCPHdr));
@ -167,6 +170,7 @@ Packet *UTHBuildPacketReal(uint8_t *payload, uint16_t payload_len,
memset(p->tcph, 0, sizeof(TCPHdr));
p->tcph->th_sport = sport;
p->tcph->th_dport = dport;
p->pktlen = sizeof(IPV4Hdr) + sizeof(TCPHdr) + payload_len;
break;
case IPPROTO_ICMP:
default:

Loading…
Cancel
Save