mirror of https://github.com/OISF/suricata
Add support for flowbits.
parent
657be002d1
commit
ff4b5a5db7
@ -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__ */
|
||||
|
||||
@ -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__ */
|
||||
|
||||
@ -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__ */
|
||||
|
||||
Loading…
Reference in New Issue