diff --git a/src/Makefile.am b/src/Makefile.am index 9aea3dd330..6ce30157fa 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -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 \ diff --git a/src/detect-engine.c b/src/detect-engine.c index 18a6acec19..a461110000 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -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; diff --git a/src/detect-flowbits.c b/src/detect-flowbits.c new file mode 100644 index 0000000000..53480f9aac --- /dev/null +++ b/src/detect-flowbits.c @@ -0,0 +1,210 @@ +/* Simple pktvar content match part of the detection engine. + * + * Copyright (C) 2008 by Victor Julien + * + * + * Option looks like: + * + * flowbits:isset,SoberEhlo; + * - set + * - unset + * - toggle + * - isset + * - isnotset + * + * or + * + * flowbits:noalert; + * + */ + +#include +#include +#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; +} + + diff --git a/src/detect-flowbits.h b/src/detect-flowbits.h new file mode 100644 index 0000000000..f1d211e604 --- /dev/null +++ b/src/detect-flowbits.h @@ -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__ */ + diff --git a/src/detect-flowvar.c b/src/detect-flowvar.c index 08312fabda..1f161304ec 100644 --- a/src/detect-flowvar.c +++ b/src/detect-flowvar.c @@ -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; diff --git a/src/detect-flowvar.h b/src/detect-flowvar.h index 944504949d..5ff008bc2d 100644 --- a/src/detect-flowvar.h +++ b/src/detect-flowvar.h @@ -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; diff --git a/src/detect-pcre.c b/src/detect-pcre.c index 70c98a2df3..380d92f9a8 100644 --- a/src/detect-pcre.c +++ b/src/detect-pcre.c @@ -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 "(?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"); diff --git a/src/detect-pcre.h b/src/detect-pcre.h index 3598373dd9..276806241b 100644 --- a/src/detect-pcre.h +++ b/src/detect-pcre.h @@ -29,6 +29,7 @@ typedef struct _DetectPcreData { u_int16_t flags; char *capname; + u_int16_t capidx; } DetectPcreData; /* prototypes */ diff --git a/src/detect.c b/src/detect.c index dde3d67ac0..2ef2befa5a 100644 --- a/src/detect.c +++ b/src/detect.c @@ -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); } diff --git a/src/detect.h b/src/detect.h index 4c111e2f91..13ef5dcdb9 100644 --- a/src/detect.h +++ b/src/detect.h @@ -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, diff --git a/src/flow-bit.c b/src/flow-bit.c new file mode 100644 index 0000000000..e99202a30c --- /dev/null +++ b/src/flow-bit.c @@ -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 +#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); +} + diff --git a/src/flow-bit.h b/src/flow-bit.h new file mode 100644 index 0000000000..6f9bb71711 --- /dev/null +++ b/src/flow-bit.h @@ -0,0 +1,25 @@ +/* Copyright (c) 2009 Victor Julien */ +#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__ */ + diff --git a/src/flow-private.h b/src/flow-private.h index e2ea32a76b..e7096f933f 100644 --- a/src/flow-private.h +++ b/src/flow-private.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__ */ diff --git a/src/flow-util.c b/src/flow-util.c index db4a854981..7b9e0cb3c3 100644 --- a/src/flow-util.c +++ b/src/flow-util.c @@ -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); } diff --git a/src/flow-util.h b/src/flow-util.h index d448c3d897..aba7a5cd04 100644 --- a/src/flow-util.h +++ b/src/flow-util.h @@ -14,6 +14,7 @@ (f)->bytecnt = 0; \ (f)->lastts.tv_sec = 0; \ (f)->lastts.tv_usec = 0; \ + GenericVarFree((f)->flowvar); \ (f)->flowvar = NULL; \ } diff --git a/src/flow-var.c b/src/flow-var.c index 068e456319..5cccf4df01 100644 --- a/src/flow-var.c +++ b/src/flow-var.c @@ -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); } diff --git a/src/flow-var.h b/src/flow-var.h index 8d1116c6e4..c404aea7cf 100644 --- a/src/flow-var.h +++ b/src/flow-var.h @@ -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__ */ diff --git a/src/flow.c b/src/flow.c index 2e3ea960b1..c55fcd0e65 100644 --- a/src/flow.c +++ b/src/flow.c @@ -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 */ diff --git a/src/flow.h b/src/flow.h index 585965f470..eda8fc45d6 100644 --- a/src/flow.h +++ b/src/flow.h @@ -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; diff --git a/src/util-var-name.c b/src/util-var-name.c new file mode 100644 index 0000000000..6157f92f48 --- /dev/null +++ b/src/util-var-name.c @@ -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; +} + diff --git a/src/util-var-name.h b/src/util-var-name.h new file mode 100644 index 0000000000..0ab2d53f44 --- /dev/null +++ b/src/util-var-name.h @@ -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 + diff --git a/src/util-var.c b/src/util-var.c new file mode 100644 index 0000000000..ab799447d4 --- /dev/null +++ b/src/util-var.c @@ -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; + } +} + diff --git a/src/util-var.h b/src/util-var.h new file mode 100644 index 0000000000..e9e3821af6 --- /dev/null +++ b/src/util-var.h @@ -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__ */ + diff --git a/src/vips.c b/src/vips.c index 5f00c64670..8ad969250d 100644 --- a/src/vips.c +++ b/src/vips.c @@ -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();