Add support for flowbits.

remotes/origin/master-1.0.x
Victor Julien 17 years ago
parent 657be002d1
commit ff4b5a5db7

@ -16,6 +16,7 @@ flow-queue.c flow-queue.h \
flow-hash.c flow-hash.h \
flow-util.c flow-util.h \
flow-var.c flow-var.h \
flow-bit.c flow-bit.h \
pkt-var.c pkt-var.h \
host.c host.h \
detect.c detect.h \
@ -31,6 +32,7 @@ detect-engine-iponly.c detect-engine-iponly.h \
detect-parse.c detect-parse.h \
detect-content.c detect-content.h \
detect-uricontent.c detect-uricontent.h \
detect-flowbits.c detect-flowbits.h \
detect-flowvar.c detect-flowvar.h \
detect-pktvar.c detect-pktvar.h \
detect-pcre.c detect-pcre.h \
@ -65,6 +67,8 @@ util-hash.c util-hash.h \
util-hashlist.c util-hashlist.h \
util-bloomfilter.c util-bloomfilter.h \
util-bloomfilter-counting.c util-bloomfilter-counting.h \
util-var.c util-var.h \
util-var-name.c util-var-name.h \
tm-modules.c tm-modules.h \
tm-queues.c tm-queues.h \
tm-queuehandlers.c tm-queuehandlers.h \

@ -13,6 +13,8 @@
#include "util-hash.h"
#include "util-var-name.h"
DetectEngineCtx *DetectEngineCtxInit(void) {
DetectEngineCtx *de_ctx;
@ -30,6 +32,8 @@ DetectEngineCtx *DetectEngineCtxInit(void) {
SigGroupHeadDPortHashInit(de_ctx);
DetectPortSpHashInit(de_ctx);
DetectPortDpHashInit(de_ctx);
VariableNameInitHash(de_ctx);
return de_ctx;
error:
return NULL;

@ -0,0 +1,210 @@
/* Simple pktvar content match part of the detection engine.
*
* Copyright (C) 2008 by Victor Julien <victor@inliniac.net>
*
*
* Option looks like:
*
* flowbits:isset,SoberEhlo;
* - set
* - unset
* - toggle
* - isset
* - isnotset
*
* or
*
* flowbits:noalert;
*
*/
#include <ctype.h>
#include <pcre.h>
#include "decode.h"
#include "detect.h"
#include "threads.h"
#include "flow.h"
#include "flow-bit.h"
#include "detect-flowbits.h"
#include "util-binsearch.h"
#include "util-var-name.h"
#define PARSE_REGEX "([a-z]+)(?:,(.*))?"
static pcre *parse_regex;
static pcre_extra *parse_regex_study;
int DetectFlowbitMatch (ThreadVars *, PatternMatcherThread *, Packet *, Signature *, SigMatch *);
int DetectFlowbitSetup (DetectEngineCtx *, Signature *, SigMatch *, char *);
void DetectFlowbitsRegister (void) {
sigmatch_table[DETECT_FLOWBITS].name = "flowbits";
sigmatch_table[DETECT_FLOWBITS].Match = DetectFlowbitMatch;
sigmatch_table[DETECT_FLOWBITS].Setup = DetectFlowbitSetup;
sigmatch_table[DETECT_FLOWBITS].Free = NULL;
sigmatch_table[DETECT_FLOWBITS].RegisterTests = NULL;
const char *eb;
int eo;
int opts = 0;
parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL);
if(parse_regex == NULL)
{
printf("pcre compile of \"%s\" failed at offset %d: %s\n", PARSE_REGEX, eo, eb);
goto error;
}
parse_regex_study = pcre_study(parse_regex, 0, &eb);
if(eb != NULL)
{
printf("pcre study failed: %s\n", eb);
goto error;
}
return;
error:
return;
}
static int DetectFlowbitMatchToggle (Packet *p, DetectFlowbitsData *fd) {
FlowBitToggle(p->flow,fd->idx);
return 1;
}
static int DetectFlowbitMatchUnset (Packet *p, DetectFlowbitsData *fd) {
FlowBitUnset(p->flow,fd->idx);
return 1;
}
static int DetectFlowbitMatchSet (Packet *p, DetectFlowbitsData *fd) {
FlowBitSet(p->flow,fd->idx);
return 1;
}
static int DetectFlowbitMatchIsset (Packet *p, DetectFlowbitsData *fd) {
return FlowBitIsset(p->flow,fd->idx);
}
static int DetectFlowbitMatchIsnotset (Packet *p, DetectFlowbitsData *fd) {
return FlowBitIsnotset(p->flow,fd->idx);
}
/*
* returns 0: no match
* 1: match
* -1: error
*/
int DetectFlowbitMatch (ThreadVars *t, PatternMatcherThread *pmt, Packet *p, Signature *s, SigMatch *m)
{
DetectFlowbitsData *fd = (DetectFlowbitsData *)m->ctx;
if (fd == NULL)
return 0;
switch (fd->cmd) {
case DETECT_FLOWBITS_CMD_ISSET:
return DetectFlowbitMatchIsset(p,fd);
case DETECT_FLOWBITS_CMD_ISNOTSET:
return DetectFlowbitMatchIsnotset(p,fd);
case DETECT_FLOWBITS_CMD_SET:
return DetectFlowbitMatchSet(p,fd);
case DETECT_FLOWBITS_CMD_UNSET:
return DetectFlowbitMatchUnset(p,fd);
case DETECT_FLOWBITS_CMD_TOGGLE:
return DetectFlowbitMatchToggle(p,fd);
default:
printf("ERROR: DetectFlowbitMatch unknown cmd %u\n", fd->cmd);
return 0;
}
return 0;
}
int DetectFlowbitSetup (DetectEngineCtx *de_ctx, Signature *s, SigMatch *m, char *rawstr)
{
DetectFlowbitsData *cd = NULL;
SigMatch *sm = NULL;
char *str = rawstr;
char dubbed = 0;
char *fb_cmd_str = NULL, *fb_name = NULL;
u_int8_t fb_cmd = 0;
#define MAX_SUBSTRINGS 30
int ret = 0, res = 0;
int ov[MAX_SUBSTRINGS];
ret = pcre_exec(parse_regex, parse_regex_study, rawstr, strlen(rawstr), 0, 0, ov, MAX_SUBSTRINGS);
if (ret > 1) {
const char *str_ptr;
res = pcre_get_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 1, &str_ptr);
if (res < 0) {
printf("DetectPcreSetup: pcre_get_substring failed\n");
return -1;
}
fb_cmd_str = (char *)str_ptr;
if (ret > 2) {
res = pcre_get_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 2, &str_ptr);
if (res < 0) {
printf("DetectPcreSetup: pcre_get_substring failed\n");
return -1;
}
fb_name = (char *)str_ptr;
}
}
if (strcmp(fb_cmd_str,"noalert") == 0) {
fb_cmd = DETECT_FLOWBITS_CMD_NOALERT;
} else if (strcmp(fb_cmd_str,"isset") == 0) {
fb_cmd = DETECT_FLOWBITS_CMD_ISSET;
} else if (strcmp(fb_cmd_str,"isnotset") == 0) {
fb_cmd = DETECT_FLOWBITS_CMD_ISNOTSET;
} else if (strcmp(fb_cmd_str,"set") == 0) {
fb_cmd = DETECT_FLOWBITS_CMD_SET;
} else if (strcmp(fb_cmd_str,"unset") == 0) {
fb_cmd = DETECT_FLOWBITS_CMD_UNSET;
} else if (strcmp(fb_cmd_str,"toggle") == 0) {
fb_cmd = DETECT_FLOWBITS_CMD_TOGGLE;
} else {
printf("ERROR: flowbits action \"%s\" is not supported.\n", fb_cmd_str);
return -1;
}
if (fb_cmd == DETECT_FLOWBITS_CMD_NOALERT) {
s->flags |= SIG_FLAG_NOALERT;
return 0;
}
cd = malloc(sizeof(DetectFlowbitsData));
if (cd == NULL) {
printf("DetectFlowbitsSetup malloc failed\n");
goto error;
}
cd->idx = VariableNameGetIdx(de_ctx,fb_name,fb_cmd,DETECT_FLOWBITS);
cd->cmd = fb_cmd;
//printf("DetectFlowbitSetup: idx %u, cmd %s, name %s\n", cd->idx, fb_cmd_str, fb_name ? fb_name : "(null)");
/* Okay so far so good, lets get this into a SigMatch
* and put it in the Signature. */
sm = SigMatchAlloc();
if (sm == NULL)
goto error;
sm->type = DETECT_FLOWBITS;
sm->ctx = (void *)cd;
SigMatchAppend(s,m,sm);
if (dubbed) free(str);
return 0;
error:
if (dubbed) free(str);
if (sm) free(sm);
return -1;
}

@ -0,0 +1,20 @@
#ifndef __DETECT_FLOWBITS_H__
#define __DETECT_FLOWBITS_H__
#define DETECT_FLOWBITS_CMD_ISSET 0
#define DETECT_FLOWBITS_CMD_ISNOTSET 1
#define DETECT_FLOWBITS_CMD_SET 2
#define DETECT_FLOWBITS_CMD_UNSET 3
#define DETECT_FLOWBITS_CMD_TOGGLE 4
#define DETECT_FLOWBITS_CMD_NOALERT 5
typedef struct _DetectFlowbitsData {
u_int16_t idx;
u_int8_t cmd;
} DetectFlowbitsData;
/* prototypes */
void DetectFlowbitsRegister (void);
#endif /* __DETECT_FLOWBITS_H__ */

@ -64,7 +64,7 @@ int DetectFlowvarMatch (ThreadVars *t, PatternMatcherThread *pmt, Packet *p, Sig
/* we need a lock */
mutex_lock(&p->flow->m);
FlowVar *fv = FlowVarGet(p->flow, fd->name);
FlowVar *fv = FlowVarGet(p->flow, fd->idx);
if (fv != NULL) {
u_int8_t *ptr = BinSearch(fv->value, fv->value_len, fd->content, fd->content_len);
if (ptr != NULL)
@ -188,6 +188,7 @@ int DetectFlowvarSetup (DetectEngineCtx *de_ctx, Signature *s, SigMatch *m, char
return -1;
cd->name = strdup(varname);
cd->idx = VariableNameGetIdx(varname,DETECT_FLOWVAR);
memcpy(cd->content, str, len);
cd->content_len = len;
cd->flags = 0;

@ -5,6 +5,7 @@
typedef struct _DetectFlowvarData {
char *name;
u_int16_t idx;
u_int8_t *content;
u_int8_t content_len;
u_int8_t flags;

@ -13,6 +13,8 @@
#include "detect-engine-mpm.h"
#include "util-var-name.h"
#define PARSE_CAPTURE_REGEX "\\(\\?P\\<([A-z]+)\\_([A-z0-9_]+)\\>"
#define PARSE_REGEX "(?<!\\\\)/(.*)(?<!\\\\)/([A-z]*)"
static pcre *parse_regex;
@ -105,7 +107,7 @@ int DetectPcreMatch (ThreadVars *t, PatternMatcherThread *pmt, Packet *p, Signat
ret = pcre_exec(pe->re, pe->sd, (char *)ptr, len, 0, 0, ov, MAX_SUBSTRINGS);
if (ret >= 0) {
if (ret > 1 && pe->capname != NULL) {
if (ret > 1 && pe->capidx != 0) {
const char *str_ptr;
ret = pcre_get_substring((char *)ptr, ov, MAX_SUBSTRINGS, 1, &str_ptr);
if (ret) {
@ -153,7 +155,7 @@ int DetectPcreMatch (ThreadVars *t, PatternMatcherThread *pmt, Packet *p, Signat
if (pe->flags & DETECT_PCRE_CAPTURE_PKT) {
PktVarAdd(p, pe->capname, (u_int8_t *)str_ptr, ret);
} else if (pe->flags & DETECT_PCRE_CAPTURE_FLOW) {
FlowVarAdd(p->flow, pe->capname, (u_int8_t *)str_ptr, ret);
FlowVarAdd(p->flow, pe->capidx, (u_int8_t *)str_ptr, ret);
}
}
}
@ -249,6 +251,12 @@ int DetectPcreSetup (DetectEngineCtx *de_ctx, Signature *s, SigMatch *m, char *r
} else if (strcmp(type_str_ptr,"flow") == 0) {
pd->flags |= DETECT_PCRE_CAPTURE_FLOW;
}
if (capture_str_ptr != NULL) {
if (pd->flags & DETECT_PCRE_CAPTURE_PKT)
pd->capidx = VariableNameGetIdx(de_ctx,(char *)capture_str_ptr,0,DETECT_PKTVAR);
else if (pd->flags & DETECT_PCRE_CAPTURE_FLOW)
pd->capidx = VariableNameGetIdx(de_ctx,(char *)capture_str_ptr,0,DETECT_FLOWVAR);
}
}
//printf("DetectPcreSetup: pd->capname %s\n", pd->capname ? pd->capname : "NULL");

@ -29,6 +29,7 @@ typedef struct _DetectPcreData {
u_int16_t flags;
char *capname;
u_int16_t capidx;
} DetectPcreData;
/* prototypes */

@ -40,6 +40,7 @@
#include "detect-flowvar.h"
#include "detect-pktvar.h"
#include "detect-noalert.h"
#include "detect-flowbits.h"
#include "action-globals.h"
#include "tm-modules.h"
@ -2542,6 +2543,7 @@ void SigTableSetup(void) {
DetectFlowvarRegister();
DetectPktvarRegister();
DetectNoalertRegister();
DetectFlowbitsRegister();
u_int8_t i = 0;
for (i = 0; i < DETECT_TBLSIZE; i++) {
@ -3669,6 +3671,244 @@ end:
return result;
}
int SigTest21 (void) {
ThreadVars th_v;
memset(&th_v, 0, sizeof(th_v));
PatternMatcherThread *pmt;
int result = 0;
Flow f;
memset(&f, 0, sizeof(f));
/* packet 1 */
u_int8_t *buf1 = (u_int8_t *)"GET /one/ HTTP/1.0\r\n"
"\r\n\r\n";
u_int16_t buf1len = strlen((char *)buf1);
Packet p1;
memset(&p1, 0, sizeof(p1));
p1.src.family = AF_INET;
p1.dst.family = AF_INET;
p1.payload = buf1;
p1.payload_len = buf1len;
p1.proto = IPPROTO_TCP;
p1.flow = &f;
/* packet 2 */
u_int8_t *buf2 = (u_int8_t *)"GET /two/ HTTP/1.0\r\n"
"\r\n\r\n";
u_int16_t buf2len = strlen((char *)buf2);
Packet p2;
memset(&p2, 0, sizeof(p2));
p2.src.family = AF_INET;
p2.dst.family = AF_INET;
p2.payload = buf2;
p2.payload_len = buf2len;
p2.proto = IPPROTO_TCP;
p2.flow = &f;
g_de_ctx = DetectEngineCtxInit();
if (g_de_ctx == NULL) {
goto end;
}
g_de_ctx->flags |= DE_QUIET;
g_de_ctx->sig_list = SigInit(g_de_ctx,"alert tcp any any -> any any (msg:\"FLOWBIT SET\"; content:\"/one/\"; flowbits:set,TEST.one; flowbits:noalert; sid:1;)");
if (g_de_ctx->sig_list == NULL) {
result = 0;
goto end;
}
g_de_ctx->sig_list->next = SigInit(g_de_ctx,"alert tcp any any -> any any (msg:\"FLOWBIT TEST\"; content:\"/two/\"; flowbits:isset,TEST.one; sid:2;)");
if (g_de_ctx->sig_list == NULL) {
result = 0;
goto end;
}
SigGroupBuild(g_de_ctx);
PatternMatchPrepare(mpm_ctx);
PatternMatcherThreadInit(&th_v, (void *)g_de_ctx, (void *)&pmt);
SigMatchSignatures(&th_v, pmt, &p1);
if (PacketAlertCheck(&p1, 1)) {
printf("sid 1 alerted, but shouldn't: ");
goto end;
}
SigMatchSignatures(&th_v, pmt, &p2);
if (PacketAlertCheck(&p2, 2))
result = 1;
SigGroupCleanup();
SigCleanSignatures();
PatternMatcherThreadDeinit(&th_v, (void *)pmt);
PatternMatchDestroy(mpm_ctx);
DetectEngineCtxFree(g_de_ctx);
end:
return result;
}
int SigTest22 (void) {
ThreadVars th_v;
memset(&th_v, 0, sizeof(th_v));
PatternMatcherThread *pmt;
int result = 0;
Flow f;
memset(&f, 0, sizeof(f));
/* packet 1 */
u_int8_t *buf1 = (u_int8_t *)"GET /one/ HTTP/1.0\r\n"
"\r\n\r\n";
u_int16_t buf1len = strlen((char *)buf1);
Packet p1;
memset(&p1, 0, sizeof(p1));
p1.src.family = AF_INET;
p1.dst.family = AF_INET;
p1.payload = buf1;
p1.payload_len = buf1len;
p1.proto = IPPROTO_TCP;
p1.flow = &f;
/* packet 2 */
u_int8_t *buf2 = (u_int8_t *)"GET /two/ HTTP/1.0\r\n"
"\r\n\r\n";
u_int16_t buf2len = strlen((char *)buf2);
Packet p2;
memset(&p2, 0, sizeof(p2));
p2.src.family = AF_INET;
p2.dst.family = AF_INET;
p2.payload = buf2;
p2.payload_len = buf2len;
p2.proto = IPPROTO_TCP;
p2.flow = &f;
g_de_ctx = DetectEngineCtxInit();
if (g_de_ctx == NULL) {
goto end;
}
g_de_ctx->flags |= DE_QUIET;
g_de_ctx->sig_list = SigInit(g_de_ctx,"alert tcp any any -> any any (msg:\"FLOWBIT SET\"; content:\"/one/\"; flowbits:set,TEST.one; flowbits:noalert; sid:1;)");
if (g_de_ctx->sig_list == NULL) {
result = 0;
goto end;
}
g_de_ctx->sig_list->next = SigInit(g_de_ctx,"alert tcp any any -> any any (msg:\"FLOWBIT TEST\"; content:\"/two/\"; flowbits:isset,TEST.abc; sid:2;)");
if (g_de_ctx->sig_list == NULL) {
result = 0;
goto end;
}
SigGroupBuild(g_de_ctx);
PatternMatchPrepare(mpm_ctx);
PatternMatcherThreadInit(&th_v, (void *)g_de_ctx, (void *)&pmt);
SigMatchSignatures(&th_v, pmt, &p1);
if (PacketAlertCheck(&p1, 1)) {
printf("sid 1 alerted, but shouldn't: ");
goto end;
}
SigMatchSignatures(&th_v, pmt, &p2);
if (!(PacketAlertCheck(&p2, 2)))
result = 1;
else
printf("sid 2 alerted, but shouldn't: ");
SigGroupCleanup();
SigCleanSignatures();
PatternMatcherThreadDeinit(&th_v, (void *)pmt);
PatternMatchDestroy(mpm_ctx);
DetectEngineCtxFree(g_de_ctx);
end:
return result;
}
int SigTest23 (void) {
ThreadVars th_v;
memset(&th_v, 0, sizeof(th_v));
PatternMatcherThread *pmt;
int result = 0;
Flow f;
memset(&f, 0, sizeof(f));
/* packet 1 */
u_int8_t *buf1 = (u_int8_t *)"GET /one/ HTTP/1.0\r\n"
"\r\n\r\n";
u_int16_t buf1len = strlen((char *)buf1);
Packet p1;
memset(&p1, 0, sizeof(p1));
p1.src.family = AF_INET;
p1.dst.family = AF_INET;
p1.payload = buf1;
p1.payload_len = buf1len;
p1.proto = IPPROTO_TCP;
p1.flow = &f;
/* packet 2 */
u_int8_t *buf2 = (u_int8_t *)"GET /two/ HTTP/1.0\r\n"
"\r\n\r\n";
u_int16_t buf2len = strlen((char *)buf2);
Packet p2;
memset(&p2, 0, sizeof(p2));
p2.src.family = AF_INET;
p2.dst.family = AF_INET;
p2.payload = buf2;
p2.payload_len = buf2len;
p2.proto = IPPROTO_TCP;
p2.flow = &f;
g_de_ctx = DetectEngineCtxInit();
if (g_de_ctx == NULL) {
goto end;
}
g_de_ctx->flags |= DE_QUIET;
g_de_ctx->sig_list = SigInit(g_de_ctx,"alert tcp any any -> any any (msg:\"FLOWBIT SET\"; content:\"/one/\"; flowbits:toggle,TEST.one; flowbits:noalert; sid:1;)");
if (g_de_ctx->sig_list == NULL) {
result = 0;
goto end;
}
g_de_ctx->sig_list->next = SigInit(g_de_ctx,"alert tcp any any -> any any (msg:\"FLOWBIT TEST\"; content:\"/two/\"; flowbits:isset,TEST.one; sid:2;)");
if (g_de_ctx->sig_list == NULL) {
result = 0;
goto end;
}
SigGroupBuild(g_de_ctx);
PatternMatchPrepare(mpm_ctx);
PatternMatcherThreadInit(&th_v, (void *)g_de_ctx, (void *)&pmt);
SigMatchSignatures(&th_v, pmt, &p1);
if (PacketAlertCheck(&p1, 1)) {
printf("sid 1 alerted, but shouldn't: ");
goto end;
}
SigMatchSignatures(&th_v, pmt, &p2);
if (PacketAlertCheck(&p2, 2))
result = 1;
else
printf("sid 2 didn't alert, but should have: ");
SigGroupCleanup();
SigCleanSignatures();
PatternMatcherThreadDeinit(&th_v, (void *)pmt);
PatternMatchDestroy(mpm_ctx);
DetectEngineCtxFree(g_de_ctx);
end:
return result;
}
void SigRegisterTests(void) {
SigParseRegisterTests();
UtRegisterTest("SigTest01 -- HTTP URI cap", SigTest01, 1);
@ -3691,5 +3931,8 @@ void SigRegisterTests(void) {
UtRegisterTest("SigTest18 -- Ftp negation sig test", SigTest18, 1);
UtRegisterTest("SigTest19 -- IP-ONLY test (1)", SigTest19, 1);
UtRegisterTest("SigTest20 -- IP-ONLY test (2)", SigTest20, 1);
UtRegisterTest("SigTest21 -- FLOWBIT test (1)", SigTest21, 1);
UtRegisterTest("SigTest22 -- FLOWBIT test (2)", SigTest22, 1);
UtRegisterTest("SigTest23 -- FLOWBIT test (3)", SigTest23, 1);
}

@ -274,6 +274,9 @@ typedef struct DetectEngineCtx_ {
HashListTable *sport_hash_table;
HashListTable *dport_hash_table;
HashListTable *variable_names;
u_int16_t variable_names_idx;
/* memory counters */
u_int32_t mpm_memory_size;
@ -372,6 +375,7 @@ enum {
DETECT_FLOWVAR,
DETECT_PKTVAR,
DETECT_NOALERT,
DETECT_FLOWBITS,
DETECT_ADDRESS,
DETECT_PROTO,

@ -0,0 +1,426 @@
/* implement per flow bits
*
* actually, not a bit, but called that way because of Snort's
* flowbits. It's a binary storage. */
/* TODO
* - move away from a linked list implementation
* - use different datatypes, such as string, int, etc.
* - have more than one instance of the same var, and be able to match on a
* specific one, or one all at a time. So if a certain capture matches
* multiple times, we can operate on all of them.
*/
#include <ctype.h>
#include "threads.h"
#include "flow-bit.h"
#include "flow.h"
#include "flow-util.h"
#include "flow-private.h"
#include "detect.h"
#include "util-var.h"
#include "util-unittest.h"
/* get the flowbit with name 'name' from the flow
*
* name is a normal string*/
static FlowBit *FlowBitGet(Flow *f, u_int16_t idx) {
GenericVar *gv = f->flowvar;
for ( ; gv != NULL; gv = gv->next) {
if (gv->type == DETECT_FLOWBITS && gv->idx == idx) {
return (FlowBit *)gv;
}
}
return NULL;
}
/* add a flowbit to the flow */
static void FlowBitAdd(Flow *f, u_int16_t idx) {
FlowBit *fb = FlowBitGet(f, idx);
if (fb == NULL) {
fb = malloc(sizeof(FlowBit));
if (fb == NULL)
return;
fb->type = DETECT_FLOWBITS;
fb->idx = idx;
fb->next = NULL;
GenericVarAppend(&f->flowvar, (GenericVar *)fb);
//printf("FlowBitAdd: adding flowbit with idx %u\n", idx);
#ifdef FLOWBITS_STATS
mutex_lock(&flowbits_mutex);
flowbits_added++;
flowbits_memuse += sizeof(FlowBit);
if (flowbits_memuse > flowbits_memuse_max)
flowbits_memuse_max = flowbits_memuse;
mutex_unlock(&flowbits_mutex);
#endif /* FLOWBITS_STATS */
}
}
static void FlowBitRemove(Flow *f, u_int16_t idx) {
FlowBit *fb = FlowBitGet(f, idx);
if (fb == NULL)
return;
GenericVarRemove(&f->flowvar, (GenericVar *)fb);
//printf("FlowBitRemove: remove flowbit with idx %u\n", idx);
#ifdef FLOWBITS_STATS
mutex_lock(&flowbits_mutex);
flowbits_removed++;
if (flowbits_memuse >= sizeof(FlowBit))
flowbits_memuse -= sizeof(FlowBit);
else {
printf("ERROR: flowbits memory usage going below 0!\n");
flowbits_memuse = 0;
}
mutex_unlock(&flowbits_mutex);
#endif /* FLOWBITS_STATS */
}
void FlowBitSet(Flow *f, u_int16_t idx) {
mutex_lock(&f->m);
FlowBit *fb = FlowBitGet(f, idx);
if (fb == NULL) {
FlowBitAdd(f, idx);
}
mutex_unlock(&f->m);
}
void FlowBitUnset(Flow *f, u_int16_t idx) {
mutex_lock(&f->m);
FlowBit *fb = FlowBitGet(f, idx);
if (fb != NULL) {
FlowBitRemove(f, idx);
}
mutex_unlock(&f->m);
}
void FlowBitToggle(Flow *f, u_int16_t idx) {
mutex_lock(&f->m);
FlowBit *fb = FlowBitGet(f, idx);
if (fb != NULL) {
FlowBitRemove(f, idx);
} else {
FlowBitAdd(f, idx);
}
mutex_unlock(&f->m);
}
int FlowBitIsset(Flow *f, u_int16_t idx) {
int r = 0;
mutex_lock(&f->m);
FlowBit *fb = FlowBitGet(f, idx);
if (fb != NULL) {
r = 1;
}
mutex_unlock(&f->m);
return r;
}
int FlowBitIsnotset(Flow *f, u_int16_t idx) {
int r = 0;
mutex_lock(&f->m);
FlowBit *fb = FlowBitGet(f, idx);
if (fb == NULL) {
r = 1;
}
mutex_unlock(&f->m);
return r;
}
void FlowBitFree(FlowBit *fb) {
if (fb == NULL)
return;
free(fb);
#ifdef FLOWBITS_STATS
mutex_lock(&flowbits_mutex);
flowbits_added++;
flowbits_memuse += sizeof(FlowBit);
if (flowbits_memuse > flowbits_memuse_max)
flowbits_memuse_max = flowbits_memuse;
mutex_unlock(&flowbits_mutex);
#endif /* FLOWBITS_STATS */
}
/* TESTS */
static int FlowBitTest01 (void) {
int ret = 0;
Flow f;
memset(&f, 0, sizeof(Flow));
FlowBitAdd(&f, 0);
FlowBit *fb = FlowBitGet(&f,0);
if (fb != NULL)
ret = 1;
GenericVarFree(f.flowvar);
return ret;
}
static int FlowBitTest02 (void) {
int ret = 0;
Flow f;
memset(&f, 0, sizeof(Flow));
FlowBit *fb = FlowBitGet(&f,0);
if (fb == NULL)
ret = 1;
GenericVarFree(f.flowvar);
return ret;
}
static int FlowBitTest03 (void) {
int ret = 0;
Flow f;
memset(&f, 0, sizeof(Flow));
FlowBitAdd(&f, 0);
FlowBit *fb = FlowBitGet(&f,0);
if (fb == NULL) {
printf("fb == NULL although it was just added: ");
goto end;
}
FlowBitRemove(&f, 0);
fb = FlowBitGet(&f,0);
if (fb != NULL) {
printf("fb != NULL although it was just removed: ");
goto end;
} else {
ret = 1;
}
end:
GenericVarFree(f.flowvar);
return ret;
}
static int FlowBitTest04 (void) {
int ret = 0;
Flow f;
memset(&f, 0, sizeof(Flow));
FlowBitAdd(&f, 0);
FlowBitAdd(&f, 1);
FlowBitAdd(&f, 2);
FlowBitAdd(&f, 3);
FlowBit *fb = FlowBitGet(&f,0);
if (fb != NULL)
ret = 1;
GenericVarFree(f.flowvar);
return ret;
}
static int FlowBitTest05 (void) {
int ret = 0;
Flow f;
memset(&f, 0, sizeof(Flow));
FlowBitAdd(&f, 0);
FlowBitAdd(&f, 1);
FlowBitAdd(&f, 2);
FlowBitAdd(&f, 3);
FlowBit *fb = FlowBitGet(&f,1);
if (fb != NULL)
ret = 1;
GenericVarFree(f.flowvar);
return ret;
}
static int FlowBitTest06 (void) {
int ret = 0;
Flow f;
memset(&f, 0, sizeof(Flow));
FlowBitAdd(&f, 0);
FlowBitAdd(&f, 1);
FlowBitAdd(&f, 2);
FlowBitAdd(&f, 3);
FlowBit *fb = FlowBitGet(&f,2);
if (fb != NULL)
ret = 1;
GenericVarFree(f.flowvar);
return ret;
}
static int FlowBitTest07 (void) {
int ret = 0;
Flow f;
memset(&f, 0, sizeof(Flow));
FlowBitAdd(&f, 0);
FlowBitAdd(&f, 1);
FlowBitAdd(&f, 2);
FlowBitAdd(&f, 3);
FlowBit *fb = FlowBitGet(&f,3);
if (fb != NULL)
ret = 1;
GenericVarFree(f.flowvar);
return ret;
}
static int FlowBitTest08 (void) {
int ret = 0;
Flow f;
memset(&f, 0, sizeof(Flow));
FlowBitAdd(&f, 0);
FlowBitAdd(&f, 1);
FlowBitAdd(&f, 2);
FlowBitAdd(&f, 3);
FlowBit *fb = FlowBitGet(&f,0);
if (fb == NULL)
goto end;
FlowBitRemove(&f,0);
fb = FlowBitGet(&f,0);
if (fb != NULL) {
printf("fb != NULL even though it was removed: ");
goto end;
}
ret = 1;
end:
GenericVarFree(f.flowvar);
return ret;
}
static int FlowBitTest09 (void) {
int ret = 0;
Flow f;
memset(&f, 0, sizeof(Flow));
FlowBitAdd(&f, 0);
FlowBitAdd(&f, 1);
FlowBitAdd(&f, 2);
FlowBitAdd(&f, 3);
FlowBit *fb = FlowBitGet(&f,1);
if (fb == NULL)
goto end;
FlowBitRemove(&f,1);
fb = FlowBitGet(&f,1);
if (fb != NULL) {
printf("fb != NULL even though it was removed: ");
goto end;
}
ret = 1;
end:
GenericVarFree(f.flowvar);
return ret;
}
static int FlowBitTest10 (void) {
int ret = 0;
Flow f;
memset(&f, 0, sizeof(Flow));
FlowBitAdd(&f, 0);
FlowBitAdd(&f, 1);
FlowBitAdd(&f, 2);
FlowBitAdd(&f, 3);
FlowBit *fb = FlowBitGet(&f,2);
if (fb == NULL)
goto end;
FlowBitRemove(&f,2);
fb = FlowBitGet(&f,2);
if (fb != NULL) {
printf("fb != NULL even though it was removed: ");
goto end;
}
ret = 1;
end:
GenericVarFree(f.flowvar);
return ret;
}
static int FlowBitTest11 (void) {
int ret = 0;
Flow f;
memset(&f, 0, sizeof(Flow));
FlowBitAdd(&f, 0);
FlowBitAdd(&f, 1);
FlowBitAdd(&f, 2);
FlowBitAdd(&f, 3);
FlowBit *fb = FlowBitGet(&f,3);
if (fb == NULL)
goto end;
FlowBitRemove(&f,3);
fb = FlowBitGet(&f,3);
if (fb != NULL) {
printf("fb != NULL even though it was removed: ");
goto end;
}
ret = 1;
end:
GenericVarFree(f.flowvar);
return ret;
}
void FlowBitRegisterTests(void) {
UtRegisterTest("FlowBitTest01", FlowBitTest01, 1);
UtRegisterTest("FlowBitTest02", FlowBitTest02, 1);
UtRegisterTest("FlowBitTest03", FlowBitTest03, 1);
UtRegisterTest("FlowBitTest04", FlowBitTest04, 1);
UtRegisterTest("FlowBitTest05", FlowBitTest05, 1);
UtRegisterTest("FlowBitTest06", FlowBitTest06, 1);
UtRegisterTest("FlowBitTest07", FlowBitTest07, 1);
UtRegisterTest("FlowBitTest08", FlowBitTest08, 1);
UtRegisterTest("FlowBitTest09", FlowBitTest09, 1);
UtRegisterTest("FlowBitTest10", FlowBitTest10, 1);
UtRegisterTest("FlowBitTest11", FlowBitTest11, 1);
}

@ -0,0 +1,25 @@
/* Copyright (c) 2009 Victor Julien <victor@inliniac.net> */
#ifndef __FLOW_BIT_H__
#define __FLOW_BIT_H__
#include "flow.h"
#include "util-var.h"
typedef struct _FlowBit {
u_int8_t type; /* type, DETECT_FLOWBITS in this case */
u_int16_t idx; /* name idx */
GenericVar *next; /* right now just implement this as a list,
* in the long run we have think of something
* faster. */
} FlowBit;
void FlowBitFree(FlowBit *);
void FlowBitRegisterTests(void);
void FlowBitSet(Flow *, u_int16_t);
void FlowBitUnset(Flow *, u_int16_t);
void FlowBitToggle(Flow *, u_int16_t);
int FlowBitIsset(Flow *, u_int16_t);
int FlowBitIsnotset(Flow *, u_int16_t);
#endif /* __FLOW_BIT_H__ */

@ -35,5 +35,14 @@ u_int8_t flow_flags;
u_int32_t flow_memuse;
pthread_mutex_t flow_memuse_mutex;
#define FLOWBITS_STATS
#ifdef FLOWBITS_STATS
u_int32_t flowbits_memuse;
u_int32_t flowbits_memuse_max;
u_int32_t flowbits_added;
u_int32_t flowbits_removed;
pthread_mutex_t flowbits_mutex;
#endif /* FLOWBITS_STATS */
#endif /* __FLOW_PRIVATE_H__ */

@ -7,6 +7,8 @@
#include "flow-util.h"
#include "flow-var.h"
#include "util-var.h"
/* Allocate a flow */
Flow *FlowAlloc(void)
{
@ -31,8 +33,6 @@ Flow *FlowAlloc(void)
f->hnext = NULL;
f->hprev = NULL;
/* we need this here so even unitialized are freed
* properly */
f->flowvar = NULL;
return f;
@ -44,7 +44,7 @@ void FlowFree(Flow *f)
flow_memuse -= sizeof(Flow);
mutex_unlock(&flow_memuse_mutex);
FlowVarFree(f->flowvar);
GenericVarFree(f->flowvar);
free(f);
}

@ -14,6 +14,7 @@
(f)->bytecnt = 0; \
(f)->lastts.tv_sec = 0; \
(f)->lastts.tv_usec = 0; \
GenericVarFree((f)->flowvar); \
(f)->flowvar = NULL; \
}

@ -12,6 +12,7 @@
#include "threads.h"
#include "flow-var.h"
#include "flow.h"
#include "detect.h"
/* puts a new value into a flowvar */
void FlowVarUpdate(FlowVar *fv, u_int8_t *value, u_int16_t size) {
@ -23,46 +24,36 @@ void FlowVarUpdate(FlowVar *fv, u_int8_t *value, u_int16_t size) {
/* get the flowvar with name 'name' from the flow
*
* name is a normal string*/
FlowVar *FlowVarGet(Flow *f, char *name) {
FlowVar *fv = f->flowvar;
FlowVar *FlowVarGet(Flow *f, u_int8_t idx) {
GenericVar *gv = f->flowvar;
for (;fv != NULL; fv = fv->next) {
if (fv->name && strcmp(fv->name, name) == 0)
return fv;
for ( ; gv != NULL; gv = gv->next) {
if (gv->type == DETECT_FLOWVAR && gv->idx == idx)
return (FlowVar *)gv;
}
return NULL;
}
/* add a flowvar to the flow, or update it */
void FlowVarAdd(Flow *f, char *name, u_int8_t *value, u_int16_t size) {
void FlowVarAdd(Flow *f, u_int8_t idx, u_int8_t *value, u_int16_t size) {
//printf("Adding flow var \"%s\" with value(%d) \"%s\"\n", name, size, value);
mutex_lock(&f->m);
FlowVar *fv = FlowVarGet(f, name);
FlowVar *fv = FlowVarGet(f, idx);
if (fv == NULL) {
fv = malloc(sizeof(FlowVar));
if (fv == NULL)
goto out;
fv->name = name;
fv->type = DETECT_FLOWVAR;
fv->idx = idx;
fv->value = value;
fv->value_len = size;
fv->next = NULL;
FlowVar *tfv = f->flowvar;
if (f->flowvar == NULL) f->flowvar = fv;
else {
while(tfv) {
if (tfv->next == NULL) {
tfv->next = fv;
goto out;
}
tfv = tfv->next;
}
}
GenericVarAppend(&f->flowvar, (GenericVar *)fv);
} else {
FlowVarUpdate(fv, value, size);
}
@ -75,25 +66,28 @@ void FlowVarFree(FlowVar *fv) {
if (fv == NULL)
return;
fv->name = NULL;
if (fv->value) free(fv->value);
if (fv->value != NULL)
free(fv->value);
if (fv->next) FlowVarFree(fv->next);
free(fv);
}
void FlowVarPrint(FlowVar *fv) {
void FlowVarPrint(GenericVar *gv) {
u_int16_t i;
if (fv == NULL)
if (gv == NULL)
return;
printf("Name \"%s\", Value \"", fv->name);
for (i = 0; i < fv->value_len; i++) {
if (isprint(fv->value[i])) printf("%c", fv->value[i]);
else printf("\\%02X", fv->value[i]);
}
printf("\", Len \"%u\"\n", fv->value_len);
if (gv->type == DETECT_FLOWVAR) {
FlowVar *fv = (FlowVar *)gv;
FlowVarPrint(fv->next);
printf("Name idx \"%u\", Value \"", fv->idx);
for (i = 0; i < fv->value_len; i++) {
if (isprint(fv->value[i])) printf("%c", fv->value[i]);
else printf("\\%02X", fv->value[i]);
}
printf("\", Len \"%u\"\n", fv->value_len);
}
FlowVarPrint(gv->next);
}

@ -3,20 +3,22 @@
#define __FLOW_VAR_H__
#include "flow.h"
#include "util-var.h"
typedef struct _FlowVar {
char *name;
u_int8_t type; /* type, DETECT_FLOWVAR in this case */
u_int16_t idx; /* name idx */
GenericVar *next; /* right now just implement this as a list,
* in the long run we have think of something
* faster. */
u_int8_t *value;
u_int16_t value_len;
struct _FlowVar *next; /* right now just implement this as a list,
* in the long run we have thing of something
* faster. */
} FlowVar;
void FlowVarAdd(Flow *, char *, u_int8_t *, u_int16_t);
FlowVar *FlowVarGet(Flow *, char *);
void FlowVarAdd(Flow *, u_int8_t, u_int8_t *, u_int16_t);
FlowVar *FlowVarGet(Flow *, u_int8_t);
void FlowVarFree(FlowVar *);
void FlowVarPrint(FlowVar *);
void FlowVarPrint(GenericVar *);
#endif /* __FLOW_VAR_H__ */

@ -330,6 +330,11 @@ void FlowPrintFlows (void)
#ifdef DBG_PERF
printf(" flow_est_q.dbg_maxlen %u\n", flow_est_q.dbg_maxlen);
#endif
#ifdef FLOWBITS_STATS
printf("Flowbits added: %u, removed: %u\n", flowbits_added, flowbits_removed);
printf("Max memory usage: %u\n", flowbits_memuse_max);
#endif /* FLOWBITS_STATS */
}
/* Not thread safe */

@ -4,6 +4,7 @@
#define __FLOW_H__
#include "decode.h"
#include "util-var.h"
/* pkt flow flags */
#define FLOW_PKT_TOSERVER 0x01
@ -53,7 +54,8 @@ typedef struct _Flow
struct timeval startts;
struct timeval lastts;
struct _FlowVar *flowvar;
/* pointer to the var list */
GenericVar *flowvar;
u_int32_t todstpktcnt;
u_int32_t tosrcpktcnt;

@ -0,0 +1,88 @@
#include "vips.h"
#include "detect.h"
#include "util-hashlist.h"
typedef struct _VariableName {
char *name;
u_int8_t type; /* flowbit, pktvar, etc */
u_int16_t idx;
u_int8_t flags;
} VariableName;
static u_int32_t VariableNameHash(HashListTable *ht, void *buf, u_int16_t buflen) {
VariableName *fn = (VariableName *)buf;
u_int32_t hash = strlen(fn->name) + fn->type;
u_int16_t u;
for (u = 0; u < buflen; u++) {
hash += fn->name[u];
}
return hash;
}
static char VariableNameCompare(void *buf1, u_int16_t len1, void *buf2, u_int16_t len2) {
VariableName *fn1 = (VariableName *)buf1;
VariableName *fn2 = (VariableName *)buf2;
if (fn1->type != fn2->type)
return 0;
if (strcmp(fn1->name,fn2->name) == 0)
return 1;
return 0;
}
static void VariableNameFree(void *data) {
VariableName *fn = (VariableName *)data;
if (fn == NULL)
return;
if (fn->name != NULL) {
free(fn->name);
fn->name = NULL;
}
free(fn);
}
int VariableNameInitHash(DetectEngineCtx *de_ctx) {
de_ctx->variable_names = HashListTableInit(4096, VariableNameHash, VariableNameCompare, VariableNameFree);
if (de_ctx->variable_names == NULL)
return -1;
return 0;
}
u_int16_t VariableNameGetIdx(DetectEngineCtx *de_ctx, char *name, u_int8_t cmd, u_int8_t type) {
u_int16_t idx = 0;
VariableName *fn = malloc(sizeof(VariableName));
if (fn == NULL)
goto error;
memset(fn, 0, sizeof(VariableName));
fn->type = type;
fn->name = strdup(name);
if (fn->name == NULL)
goto error;
VariableName *lookup_fn = (VariableName *)HashListTableLookup(de_ctx->variable_names, (void *)fn, 0);
if (lookup_fn == NULL) {
de_ctx->variable_names_idx++;
idx = fn->idx = de_ctx->variable_names_idx;
HashListTableAdd(de_ctx->variable_names, (void *)fn, 0);
} else {
idx = lookup_fn->idx;
}
return idx;
error:
VariableNameFree(fn);
return 0;
}

@ -0,0 +1,8 @@
#ifndef __UTIL_VAR_NAME_H__
#define __UTIL_VAR_NAME_H__
int VariableNameInitHash(DetectEngineCtx *de_ctx);
u_int16_t VariableNameGetIdx(DetectEngineCtx *, char *, u_int8_t, u_int8_t);
#endif

@ -0,0 +1,84 @@
#include "vips.h"
#include "detect.h"
#include "util-var.h"
#include "flow-var.h"
#include "flow-bit.h"
#include "pkt-var.h"
void GenericVarFree(GenericVar *gv) {
if (gv == NULL)
return;
//printf("GenericVarFree: gv %p, gv->type %u\n", gv, gv->type);
GenericVar *next_gv = gv->next;
switch (gv->type) {
case DETECT_FLOWBITS:
{
FlowBit *fb = (FlowBit *)gv;
//printf("GenericVarFree: fb %p, removing\n", fb);
FlowBitFree(fb);
break;
}
case DETECT_FLOWVAR:
{
FlowVar *fv = (FlowVar *)gv;
FlowVarFree(fv);
break;
}
case DETECT_PKTVAR:
{
PktVar *pv = (PktVar *)gv;
PktVarFree(pv);
break;
}
default:
{
printf("ERROR: GenericVarFree unknown type %u\n", gv->type);
break;
}
}
GenericVarFree(next_gv);
}
void GenericVarAppend(GenericVar **list, GenericVar *gv) {
gv->next = NULL;
if (*list == NULL) {
*list = gv;
} else {
GenericVar *tgv = *list;
while(tgv) {
if (tgv->next == NULL) {
tgv->next = gv;
return;
}
tgv = tgv->next;
}
}
}
void GenericVarRemove(GenericVar **list, GenericVar *gv) {
if (*list == NULL)
return;
GenericVar *listgv = *list, *prevgv = NULL;
while (listgv != NULL) {
if (listgv == gv) {
if (prevgv == NULL)
*list = gv->next;
else
prevgv->next = gv->next;
return;
}
prevgv = listgv;
listgv = listgv->next;
}
}

@ -0,0 +1,15 @@
#ifndef __UTIL_VAR_H__
#define __UTIL_VAR_H__
typedef struct _GenericVar {
u_int8_t type;
u_int16_t idx;
struct _GenericVar *next;
} GenericVar;
void GenericVarFree(GenericVar *);
void GenericVarAppend(GenericVar **, GenericVar *);
void GenericVarRemove(GenericVar **, GenericVar *);
#endif /* __UTIL_VAR_H__ */

@ -51,6 +51,7 @@
#include "flow.h"
#include "flow-var.h"
#include "flow-bit.h"
#include "pkt-var.h"
#include "util-cidr.h"
@ -223,6 +224,7 @@ int main(int argc, char **argv)
BloomFilterRegisterTests();
BloomFilterCountingRegisterTests();
MpmRegisterTests();
FlowBitRegisterTests();
SigRegisterTests();
//UtRunTests();
UtCleanup();
@ -933,8 +935,8 @@ int main(int argc, char **argv)
sleep(1);
}
FlowPrintFlows();
FlowShutdown();
FlowPrintFlows();
SigGroupCleanup();
SigCleanSignatures();

Loading…
Cancel
Save