diff --git a/src/Makefile.am b/src/Makefile.am index 2d9cb14ec3..11d3268799 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -137,6 +137,7 @@ detect-fragoffset.c detect-fragoffset.h \ detect-ftpbounce.c detect-ftpbounce.h \ detect-geoip.c detect-geoip.h \ detect-gid.c detect-gid.h \ +detect-hostbits.c detect-hostbits.h \ detect-http-client-body.c detect-http-client-body.h \ detect-http-cookie.c detect-http-cookie.h \ detect-http-header.c detect-http-header.h \ @@ -207,6 +208,7 @@ flow-timeout.c flow-timeout.h \ flow-util.c flow-util.h \ flow-var.c flow-var.h \ host.c host.h \ +host-bit.c host-bit.h \ host-queue.c host-queue.h \ host-storage.c host-storage.h \ host-timeout.c host-timeout.h \ diff --git a/src/detect-hostbits.c b/src/detect-hostbits.c new file mode 100644 index 0000000000..f52f089bef --- /dev/null +++ b/src/detect-hostbits.c @@ -0,0 +1,1091 @@ +/* Copyright (C) 2007-2010 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + * + * Implements the hostbits keyword + */ + +#include "suricata-common.h" +#include "decode.h" +#include "detect.h" +#include "threads.h" +#include "flow.h" +#include "flow-util.h" +#include "detect-hostbits.h" +#include "util-spm.h" + +#include "app-layer-parser.h" + +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-state.h" + +#include "flow-bit.h" +#include "host-bit.h" +#include "util-var-name.h" +#include "util-unittest.h" +#include "util-debug.h" + +#define PARSE_REGEX "([a-z]+)(?:,(.*))?" +static pcre *parse_regex; +static pcre_extra *parse_regex_study; + +int DetectHostbitMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, const SigMatchCtx *); +static int DetectHostbitSetup (DetectEngineCtx *, Signature *, char *); +void DetectHostbitFree (void *); +void HostBitsRegisterTests(void); + +void DetectHostbitsRegister (void) +{ + sigmatch_table[DETECT_HOSTBITS].name = "hostbits"; + sigmatch_table[DETECT_HOSTBITS].desc = "operate on flow flag"; +// sigmatch_table[DETECT_HOSTBITS].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Flow-keywords#Flowbits"; + sigmatch_table[DETECT_HOSTBITS].Match = DetectHostbitMatch; + sigmatch_table[DETECT_HOSTBITS].Setup = DetectHostbitSetup; + sigmatch_table[DETECT_HOSTBITS].Free = DetectHostbitFree; + sigmatch_table[DETECT_HOSTBITS].RegisterTests = HostBitsRegisterTests; + /* this is compatible to ip-only signatures */ + sigmatch_table[DETECT_HOSTBITS].flags |= SIGMATCH_IPONLY_COMPAT; + + const char *eb; + int eo; + int opts = 0; + + parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); + if(parse_regex == NULL) + { + SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); + goto error; + } + + parse_regex_study = pcre_study(parse_regex, 0, &eb); + if(eb != NULL) + { + SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); + goto error; + } + + return; + +error: + return; +} + + +static int DetectHostbitMatchToggle (Packet *p, const DetectHostbitsData *fd) +{ + if (p->host_src == NULL) { + p->host_src = HostGetHostFromHash(&p->src); + if (p->host_src == NULL) + return 0; + } + else + HostLock(p->host_src); + + HostBitToggle(p->host_src,fd->idx); + HostUnlock(p->host_src); + return 1; +} + +/* return true even if bit not found */ +static int DetectHostbitMatchUnset (Packet *p, const DetectHostbitsData *fd) +{ + if (p->host_src == NULL) + return 1; + + HostLock(p->host_src); + HostBitUnset(p->host_src,fd->idx); + HostUnlock(p->host_src); + return 1; +} + +static int DetectHostbitMatchSet (Packet *p, const DetectHostbitsData *fd) +{ + if (p->host_src == NULL) { + p->host_src = HostGetHostFromHash(&p->src); + if (p->host_src == NULL) + return 0; + //SCLogInfo("host added"); + } else + HostLock(p->host_src); + + HostBitSet(p->host_src,fd->idx); + HostUnlock(p->host_src); + return 1; +} + +static int DetectHostbitMatchIsset (Packet *p, const DetectHostbitsData *fd) +{ + if (p->host_src == NULL) + return 0; + + HostLock(p->host_src); + int r = 0; + r = HostBitIsset(p->host_src,fd->idx); + HostUnlock(p->host_src); + return r; +} + +static int DetectHostbitMatchIsnotset (Packet *p, const DetectHostbitsData *fd) +{ + if (p->host_src == NULL) + return 1; + + HostLock(p->host_src); + int r = 0; + r = HostBitIsnotset(p->host_src,fd->idx); + HostUnlock(p->host_src); + return r; +} + +/* + * returns 0: no match + * 1: match + * -1: error + */ + +int DetectHostbitMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, const SigMatchCtx *ctx) +{ + const DetectHostbitsData *fd = (const DetectHostbitsData *)ctx; + if (fd == NULL) + return 0; + + switch (fd->cmd) { + case DETECT_HOSTBITS_CMD_ISSET: + return DetectHostbitMatchIsset(p,fd); + case DETECT_HOSTBITS_CMD_ISNOTSET: + return DetectHostbitMatchIsnotset(p,fd); + case DETECT_HOSTBITS_CMD_SET: + return DetectHostbitMatchSet(p,fd); + case DETECT_HOSTBITS_CMD_UNSET: + return DetectHostbitMatchUnset(p,fd); + case DETECT_HOSTBITS_CMD_TOGGLE: + return DetectHostbitMatchToggle(p,fd); + default: + SCLogError(SC_ERR_UNKNOWN_VALUE, "unknown cmd %" PRIu32 "", fd->cmd); + return 0; + } + + return 0; +} + +int DetectHostbitSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawstr) +{ + DetectHostbitsData *cd = NULL; + SigMatch *sm = NULL; + uint8_t fb_cmd = 0; +#define MAX_SUBSTRINGS 30 + int ret = 0, res = 0; + int ov[MAX_SUBSTRINGS]; + char fb_cmd_str[16] = "", fb_name[256] = ""; + + ret = pcre_exec(parse_regex, parse_regex_study, rawstr, strlen(rawstr), 0, 0, ov, MAX_SUBSTRINGS); + if (ret != 2 && ret != 3) { + SCLogError(SC_ERR_PCRE_MATCH, "\"%s\" is not a valid setting for flowbits.", rawstr); + return -1; + } + + res = pcre_copy_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 1, fb_cmd_str, sizeof(fb_cmd_str)); + if (res < 0) { + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed"); + return -1; + } + + if (ret == 3) { + res = pcre_copy_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 2, fb_name, sizeof(fb_name)); + if (res < 0) { + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed"); + goto error; + } + } + + if (strcmp(fb_cmd_str,"noalert") == 0) { + fb_cmd = DETECT_HOSTBITS_CMD_NOALERT; + } else if (strcmp(fb_cmd_str,"isset") == 0) { + fb_cmd = DETECT_HOSTBITS_CMD_ISSET; + } else if (strcmp(fb_cmd_str,"isnotset") == 0) { + fb_cmd = DETECT_HOSTBITS_CMD_ISNOTSET; + } else if (strcmp(fb_cmd_str,"set") == 0) { + fb_cmd = DETECT_HOSTBITS_CMD_SET; + } else if (strcmp(fb_cmd_str,"unset") == 0) { + fb_cmd = DETECT_HOSTBITS_CMD_UNSET; + } else if (strcmp(fb_cmd_str,"toggle") == 0) { + fb_cmd = DETECT_HOSTBITS_CMD_TOGGLE; + } else { + SCLogError(SC_ERR_UNKNOWN_VALUE, "ERROR: flowbits action \"%s\" is not supported.", fb_cmd_str); + goto error; + } + + switch (fb_cmd) { + case DETECT_HOSTBITS_CMD_NOALERT: + if (strlen(fb_name) != 0) + goto error; + s->flags |= SIG_FLAG_NOALERT; + return 0; + case DETECT_HOSTBITS_CMD_ISNOTSET: + case DETECT_HOSTBITS_CMD_ISSET: + case DETECT_HOSTBITS_CMD_SET: + case DETECT_HOSTBITS_CMD_UNSET: + case DETECT_HOSTBITS_CMD_TOGGLE: + default: + if (strlen(fb_name) == 0) + goto error; + break; + } + + cd = SCMalloc(sizeof(DetectHostbitsData)); + if (unlikely(cd == NULL)) + goto error; + + cd->idx = VariableNameGetIdx(de_ctx, fb_name, DETECT_HOSTBITS); + cd->cmd = fb_cmd; + + SCLogDebug("idx %" PRIu32 ", cmd %s, name %s", + cd->idx, fb_cmd_str, strlen(fb_name) ? fb_name : "(none)"); + + /* 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_HOSTBITS; + sm->ctx = (void *)cd; + + switch (fb_cmd) { + case DETECT_HOSTBITS_CMD_NOALERT: + /* nothing to do */ + break; + + case DETECT_HOSTBITS_CMD_ISNOTSET: + case DETECT_HOSTBITS_CMD_ISSET: + /* checks, so packet list */ + SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); + break; + + case DETECT_HOSTBITS_CMD_SET: + case DETECT_HOSTBITS_CMD_UNSET: + case DETECT_HOSTBITS_CMD_TOGGLE: + /* modifiers, only run when entire sig has matched */ + SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_POSTMATCH); + break; + } + + return 0; + +error: + if (cd != NULL) + SCFree(cd); + if (sm != NULL) + SCFree(sm); + return -1; +} + +void DetectHostbitFree (void *ptr) +{ + DetectHostbitsData *fd = (DetectHostbitsData *)ptr; + + if (fd == NULL) + return; + + SCFree(fd); +} + +#ifdef UNITTESTS +/** + * \test HostBitsTestSig01 is a test for a valid noalert flowbits option + * + * \retval 1 on succces + * \retval 0 on failure + */ + +static int HostBitsTestSig01(void) +{ + uint8_t *buf = (uint8_t *) + "GET /one/ HTTP/1.1\r\n" + "Host: one.example.org\r\n" + "\r\n"; + uint16_t buflen = strlen((char *)buf); + Packet *p = SCMalloc(SIZE_OF_PACKET); + if (unlikely(p == NULL)) + return 0; + Signature *s = NULL; + ThreadVars th_v; + DetectEngineThreadCtx *det_ctx = NULL; + DetectEngineCtx *de_ctx = NULL; + int result = 0; + + HostInitConfig(TRUE); + + memset(&th_v, 0, sizeof(th_v)); + memset(p, 0, SIZE_OF_PACKET); + p->src.family = AF_INET; + p->dst.family = AF_INET; + p->payload = buf; + p->payload_len = buflen; + p->proto = IPPROTO_TCP; + + de_ctx = DetectEngineCtxInit(); + + if (de_ctx == NULL) { + printf("bad de_ctx: "); + goto end; + } + + de_ctx->flags |= DE_QUIET; + + s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (hostbits:set,abc; content:\"GET \"; sid:1;)"); + + if (s == NULL) { + printf("bad sig: "); + goto end; + } + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + + result = 1; + +end: + if (de_ctx != NULL) { + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + } + + if (det_ctx != NULL) { + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + } + + if (de_ctx != NULL) { + DetectEngineCtxFree(de_ctx); + } + + HostCleanup(); + + SCFree(p); + return result; +} + +#if 0 +/** + * \test HostBitsTestSig02 is a test for a valid isset,set,isnotset,unset,toggle flowbits options + * + * \retval 1 on succces + * \retval 0 on failure + */ + +static int HostBitsTestSig02(void) +{ + uint8_t *buf = (uint8_t *) + "GET /one/ HTTP/1.1\r\n" + "Host: one.example.org\r\n" + "\r\n"; + uint16_t buflen = strlen((char *)buf); + Packet *p = SCMalloc(SIZE_OF_PACKET); + if (unlikely(p == NULL)) + return 0; + Signature *s = NULL; + ThreadVars th_v; + DetectEngineThreadCtx *det_ctx = NULL; + DetectEngineCtx *de_ctx = NULL; + int result = 0; + int error_count = 0; + + memset(&th_v, 0, sizeof(th_v)); + memset(p, 0, SIZE_OF_PACKET); + p->src.family = AF_INET; + p->dst.family = AF_INET; + p->payload = buf; + p->payload_len = buflen; + p->proto = IPPROTO_TCP; + + de_ctx = DetectEngineCtxInit(); + + if (de_ctx == NULL) { + goto end; + } + + de_ctx->flags |= DE_QUIET; + + s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"isset rule need an option\"; flowbits:isset; content:\"GET \"; sid:1;)"); + + if (s == NULL) { + error_count++; + } + + s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"isnotset rule need an option\"; flowbits:isnotset; content:\"GET \"; sid:2;)"); + + if (s == NULL) { + error_count++; + } + + s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"set rule need an option\"; flowbits:set; content:\"GET \"; sid:3;)"); + + if (s == NULL) { + error_count++; + } + + s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"unset rule need an option\"; flowbits:unset; content:\"GET \"; sid:4;)"); + + if (s == NULL) { + error_count++; + } + + s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"toggle rule need an option\"; flowbits:toggle; content:\"GET \"; sid:5;)"); + + if (s == NULL) { + error_count++; + } + + if(error_count == 5) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + + if (PacketAlertCheck(p, 1)) { + goto cleanup; + } + if (PacketAlertCheck(p, 2)) { + goto cleanup; + } + if (PacketAlertCheck(p, 3)) { + goto cleanup; + } + if (PacketAlertCheck(p, 4)) { + goto cleanup; + } + if (PacketAlertCheck(p, 5)) { + goto cleanup; + } + + result = 1; + +cleanup: + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + +end: + + if (de_ctx != NULL) { + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + } + + if (det_ctx != NULL) { + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + } + + if (de_ctx != NULL) { + DetectEngineCtxFree(de_ctx); + } + + SCFree(p); + return result; +} + +/** + * \test HostBitsTestSig03 is a test for a invalid flowbits option + * + * \retval 1 on succces + * \retval 0 on failure + */ + +static int HostBitsTestSig03(void) +{ + uint8_t *buf = (uint8_t *) + "GET /one/ HTTP/1.1\r\n" + "Host: one.example.org\r\n" + "\r\n"; + uint16_t buflen = strlen((char *)buf); + Packet *p = SCMalloc(SIZE_OF_PACKET); + if (unlikely(p == NULL)) + return 0; + Signature *s = NULL; + ThreadVars th_v; + DetectEngineThreadCtx *det_ctx = NULL; + DetectEngineCtx *de_ctx = NULL; + int result = 0; + + memset(&th_v, 0, sizeof(th_v)); + memset(p, 0, SIZE_OF_PACKET); + p->src.family = AF_INET; + p->dst.family = AF_INET; + p->payload = buf; + p->payload_len = buflen; + p->proto = IPPROTO_TCP; + + de_ctx = DetectEngineCtxInit(); + + if (de_ctx == NULL) { + goto end; + } + + de_ctx->flags |= DE_QUIET; + + s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Unknown cmd\"; flowbits:wrongcmd; content:\"GET \"; sid:1;)"); + + if (s == NULL) { + goto end; + } + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + + result = 1; + + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + +end: + + if (de_ctx != NULL) { + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + } + + if (det_ctx != NULL) { + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + } + + if (de_ctx != NULL) { + DetectEngineCtxFree(de_ctx); + } + + + SCFree(p); + return result; +} +#endif + +/** + * \test HostBitsTestSig04 is a test check idx value + * + * \retval 1 on succces + * \retval 0 on failure + */ + +static int HostBitsTestSig04(void) +{ + uint8_t *buf = (uint8_t *) + "GET /one/ HTTP/1.1\r\n" + "Host: one.example.org\r\n" + "\r\n"; + uint16_t buflen = strlen((char *)buf); + Packet *p = SCMalloc(SIZE_OF_PACKET); + if (unlikely(p == NULL)) + return 0; + Signature *s = NULL; + ThreadVars th_v; + DetectEngineThreadCtx *det_ctx = NULL; + DetectEngineCtx *de_ctx = NULL; + int result = 0; + int idx = 0; + + memset(&th_v, 0, sizeof(th_v)); + memset(p, 0, SIZE_OF_PACKET); + p->src.family = AF_INET; + p->dst.family = AF_INET; + p->payload = buf; + p->payload_len = buflen; + p->proto = IPPROTO_TCP; + + de_ctx = DetectEngineCtxInit(); + + if (de_ctx == NULL) { + goto end; + } + + de_ctx->flags |= DE_QUIET; + + s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"isset option\"; hostbits:isset,fbt; content:\"GET \"; sid:1;)"); + + idx = VariableNameGetIdx(de_ctx, "fbt", DETECT_HOSTBITS); + + if (s == NULL || idx != 1) { + goto end; + } + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + + result = 1; + + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + SCFree(p); + return result; + +end: + + if (de_ctx != NULL) { + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + } + + if (det_ctx != NULL) { + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + } + + if (de_ctx != NULL) { + DetectEngineCtxFree(de_ctx); + } + + SCFree(p); + return result; +} + +#if 0 +/** + * \test HostBitsTestSig05 is a test check noalert flag + * + * \retval 1 on succces + * \retval 0 on failure + */ + +static int HostBitsTestSig05(void) +{ + uint8_t *buf = (uint8_t *) + "GET /one/ HTTP/1.1\r\n" + "Host: one.example.org\r\n" + "\r\n"; + uint16_t buflen = strlen((char *)buf); + Packet *p = SCMalloc(SIZE_OF_PACKET); + if (unlikely(p == NULL)) + return 0; + Signature *s = NULL; + ThreadVars th_v; + DetectEngineThreadCtx *det_ctx = NULL; + DetectEngineCtx *de_ctx = NULL; + int result = 0; + + memset(&th_v, 0, sizeof(th_v)); + memset(p, 0, SIZE_OF_PACKET); + p->src.family = AF_INET; + p->dst.family = AF_INET; + p->payload = buf; + p->payload_len = buflen; + p->proto = IPPROTO_TCP; + + de_ctx = DetectEngineCtxInit(); + + if (de_ctx == NULL) { + goto end; + } + + de_ctx->flags |= DE_QUIET; + + s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Noalert\"; flowbits:noalert; content:\"GET \"; sid:1;)"); + + if (s == NULL || ((s->flags & SIG_FLAG_NOALERT) != SIG_FLAG_NOALERT)) { + goto end; + } + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + + result = 1; + + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + + SCFree(p); + return result; +end: + + if (de_ctx != NULL) { + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + } + + if (det_ctx != NULL) { + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + } + + if (de_ctx != NULL) { + DetectEngineCtxFree(de_ctx); + } + + SCFree(p); + return result; +} + +/** + * \test HostBitsTestSig06 is a test set flowbits option + * + * \retval 1 on succces + * \retval 0 on failure + */ + +static int HostBitsTestSig06(void) +{ + uint8_t *buf = (uint8_t *) + "GET /one/ HTTP/1.1\r\n" + "Host: one.example.org\r\n" + "\r\n"; + uint16_t buflen = strlen((char *)buf); + Packet *p = SCMalloc(SIZE_OF_PACKET); + if (unlikely(p == NULL)) + return 0; + Signature *s = NULL; + ThreadVars th_v; + DetectEngineThreadCtx *det_ctx = NULL; + DetectEngineCtx *de_ctx = NULL; + Flow f; + GenericVar flowvar, *gv = NULL; + int result = 0; + int idx = 0; + + memset(p, 0, SIZE_OF_PACKET); + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(Flow)); + memset(&flowvar, 0, sizeof(GenericVar)); + + FLOW_INITIALIZE(&f); + p->flow = &f; + p->flow->flowvar = &flowvar; + + p->src.family = AF_INET; + p->dst.family = AF_INET; + p->payload = buf; + p->payload_len = buflen; + p->proto = IPPROTO_TCP; + p->flags |= PKT_HAS_FLOW; + p->flowflags |= FLOW_PKT_TOSERVER; + + de_ctx = DetectEngineCtxInit(); + + if (de_ctx == NULL) { + goto end; + } + + de_ctx->flags |= DE_QUIET; + + s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit set\"; flowbits:set,myflow; sid:10;)"); + + if (s == NULL) { + goto end; + } + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + + idx = VariableNameGetIdx(de_ctx, "myflow", DETECT_HOSTBITS); + + gv = p->flow->flowvar; + + for ( ; gv != NULL; gv = gv->next) { + if (gv->type == DETECT_HOSTBITS && gv->idx == idx) { + result = 1; + } + } + + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + + if(gv) GenericVarFree(gv); + FLOW_DESTROY(&f); + + SCFree(p); + return result; +end: + + if (de_ctx != NULL) { + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + } + + if (det_ctx != NULL) { + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + } + + if (de_ctx != NULL) { + DetectEngineCtxFree(de_ctx); + } + + if(gv) GenericVarFree(gv); + FLOW_DESTROY(&f); + SCFree(p); + return result; +} + +/** + * \test HostBitsTestSig07 is a test unset flowbits option + * + * \retval 1 on succces + * \retval 0 on failure + */ + +static int HostBitsTestSig07(void) +{ + uint8_t *buf = (uint8_t *) + "GET /one/ HTTP/1.1\r\n" + "Host: one.example.org\r\n" + "\r\n"; + uint16_t buflen = strlen((char *)buf); + Packet *p = SCMalloc(SIZE_OF_PACKET); + if (unlikely(p == NULL)) + return 0; + Signature *s = NULL; + ThreadVars th_v; + DetectEngineThreadCtx *det_ctx = NULL; + DetectEngineCtx *de_ctx = NULL; + Flow f; + GenericVar flowvar, *gv = NULL; + int result = 0; + int idx = 0; + + memset(p, 0, SIZE_OF_PACKET); + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(Flow)); + memset(&flowvar, 0, sizeof(GenericVar)); + + FLOW_INITIALIZE(&f); + p->flow = &f; + p->flow->flowvar = &flowvar; + + p->src.family = AF_INET; + p->dst.family = AF_INET; + p->payload = buf; + p->payload_len = buflen; + p->proto = IPPROTO_TCP; + + de_ctx = DetectEngineCtxInit(); + + if (de_ctx == NULL) { + goto end; + } + + de_ctx->flags |= DE_QUIET; + + s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit set\"; flowbits:set,myflow2; sid:10;)"); + if (s == NULL) { + goto end; + } + + s = s->next = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit unset\"; flowbits:unset,myflow2; sid:11;)"); + if (s == NULL) { + goto end; + } + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + + idx = VariableNameGetIdx(de_ctx, "myflow", DETECT_HOSTBITS); + + gv = p->flow->flowvar; + + for ( ; gv != NULL; gv = gv->next) { + if (gv->type == DETECT_HOSTBITS && gv->idx == idx) { + result = 1; + } + } + + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + + if(gv) GenericVarFree(gv); + FLOW_DESTROY(&f); + + SCFree(p); + return result; +end: + + if (de_ctx != NULL) { + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + } + + if (det_ctx != NULL) { + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + } + + if (de_ctx != NULL) { + DetectEngineCtxFree(de_ctx); + } + + if(gv) GenericVarFree(gv); + FLOW_DESTROY(&f); + + SCFree(p); + return result; +} +#endif + +/** + * \test HostBitsTestSig08 is a test toogle flowbits option + * + * \retval 1 on succces + * \retval 0 on failure + */ + +static int HostBitsTestSig08(void) +{ + uint8_t *buf = (uint8_t *) + "GET /one/ HTTP/1.1\r\n" + "Host: one.example.org\r\n" + "\r\n"; + uint16_t buflen = strlen((char *)buf); + Packet *p = SCMalloc(SIZE_OF_PACKET); + if (unlikely(p == NULL)) + return 0; + Signature *s = NULL; + ThreadVars th_v; + DetectEngineThreadCtx *det_ctx = NULL; + DetectEngineCtx *de_ctx = NULL; + Flow f; + int result = 0; + + memset(p, 0, SIZE_OF_PACKET); + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(Flow)); + + HostInitConfig(TRUE); + + FLOW_INITIALIZE(&f); + p->flow = &f; + + p->src.family = AF_INET; + p->dst.family = AF_INET; + p->payload = buf; + p->payload_len = buflen; + p->proto = IPPROTO_TCP; + + de_ctx = DetectEngineCtxInit(); + + if (de_ctx == NULL) { + goto end; + } + + de_ctx->flags |= DE_QUIET; + + s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit set\"; hostbits:set,myflow2; sid:10;)"); + + if (s == NULL) { + goto end; + } + + s = s->next = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit toggle\"; hostbits:isset,myflow2; sid:11;)"); + + if (s == NULL) { + goto end; + } + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + + SCLogInfo("p->host_src %p", p->host_src); + + if (HostHasHostBits(p->host_src) == 1) { + if (PacketAlertCheck(p, 11)) { + result = 1; + } + } + + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + + FLOW_DESTROY(&f); + + HostCleanup(); + + SCFree(p); + return result; +end: + + if (de_ctx != NULL) { + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + } + + if (det_ctx != NULL) { + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + } + + if (de_ctx != NULL) { + DetectEngineCtxFree(de_ctx); + } + + FLOW_DESTROY(&f); + + SCFree(p); + return result; +} +#endif /* UNITTESTS */ + +/** + * \brief this function registers unit tests for HostBits + */ +void HostBitsRegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("HostBitsTestSig01", HostBitsTestSig01, 1); +#if 0 + UtRegisterTest("HostBitsTestSig02", HostBitsTestSig02, 0); + UtRegisterTest("HostBitsTestSig03", HostBitsTestSig03, 0); +#endif + UtRegisterTest("HostBitsTestSig04", HostBitsTestSig04, 1); +#if 0 + UtRegisterTest("HostBitsTestSig05", HostBitsTestSig05, 1); + UtRegisterTest("HostBitsTestSig06", HostBitsTestSig06, 1); + UtRegisterTest("HostBitsTestSig07", HostBitsTestSig07, 0); +#endif + UtRegisterTest("HostBitsTestSig08", HostBitsTestSig08, 1); +#endif /* UNITTESTS */ +} diff --git a/src/detect-hostbits.h b/src/detect-hostbits.h new file mode 100644 index 0000000000..82f5c1fa29 --- /dev/null +++ b/src/detect-hostbits.h @@ -0,0 +1,43 @@ +/* Copyright (C) 2007-2014 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + */ + +#ifndef __DETECT_HOSTBITS_H__ +#define __DETECT_HOSTBITS_H__ + +#define DETECT_HOSTBITS_CMD_SET 0 +#define DETECT_HOSTBITS_CMD_TOGGLE 1 +#define DETECT_HOSTBITS_CMD_UNSET 2 +#define DETECT_HOSTBITS_CMD_ISNOTSET 3 +#define DETECT_HOSTBITS_CMD_ISSET 4 +#define DETECT_HOSTBITS_CMD_NOALERT 5 +#define DETECT_HOSTBITS_CMD_MAX 6 + +typedef struct DetectHostbitsData_ { + uint16_t idx; + uint8_t cmd; +} DetectHostbitsData; + +/* prototypes */ +void DetectHostbitsRegister (void); + +#endif /* __DETECT_HOSTBITS_H__ */ diff --git a/src/detect.c b/src/detect.c index ed4d132b4b..0082969a06 100644 --- a/src/detect.c +++ b/src/detect.c @@ -108,6 +108,7 @@ #include "detect-pktvar.h" #include "detect-noalert.h" #include "detect-flowbits.h" +#include "detect-hostbits.h" #include "detect-csum.h" #include "detect-stream_size.h" #include "detect-engine-sigorder.h" @@ -5002,6 +5003,7 @@ void SigTableSetup(void) DetectPktvarRegister(); DetectNoalertRegister(); DetectFlowbitsRegister(); + DetectHostbitsRegister(); DetectEngineEventRegister(); DetectIpOptsRegister(); DetectFlagsRegister(); diff --git a/src/detect.h b/src/detect.h index 80d6d6a97d..775fe2eeaa 100644 --- a/src/detect.h +++ b/src/detect.h @@ -1106,6 +1106,7 @@ enum { DETECT_PKTVAR, DETECT_NOALERT, DETECT_FLOWBITS, + DETECT_HOSTBITS, DETECT_IPV4_CSUM, DETECT_TCPV4_CSUM, DETECT_TCPV6_CSUM, diff --git a/src/host-bit.c b/src/host-bit.c new file mode 100644 index 0000000000..a70d15bf6e --- /dev/null +++ b/src/host-bit.c @@ -0,0 +1,489 @@ +/* Copyright (C) 2014 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + * + * Implements per host 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 + * \todo use different datatypes, such as string, int, etc. + */ + +#include "suricata-common.h" +#include "threads.h" +#include "host-bit.h" +#include "host.h" +#include "detect.h" +#include "util-var.h" +#include "util-debug.h" +#include "util-unittest.h" +#include "host-storage.h" + +static int host_bit_id = -1; /**< Host storage id for bits */ + +void HostBitFreeAll(void *store) { + GenericVar *gv = store; + GenericVarFree(gv); +} + +void HostBitInitCtx(void) +{ + host_bit_id = HostStorageRegister("bit", sizeof(void *), NULL, HostBitFreeAll); + if (host_bit_id == -1) { + SCLogError(SC_ERR_HOST_INIT, "Can't initiate host storage for bits"); + exit(EXIT_FAILURE); + } +} + +/* lock before using this */ +int HostHasHostBits(Host *host) +{ + if (host == NULL) + return 0; + return HostGetStorageById(host, host_bit_id) ? 1 : 0; +} + +/* get the bit with idx from the host */ +static HostBit *HostBitGet(Host *h, uint16_t idx) +{ + GenericVar *gv = HostGetStorageById(h, host_bit_id); + for ( ; gv != NULL; gv = gv->next) { + if (gv->type == DETECT_HOSTBITS && gv->idx == idx) { + return (HostBit *)gv; + } + } + + return NULL; +} + +/* add a flowbit to the flow */ +static void HostBitAdd(Host *h, uint16_t idx) +{ + HostBit *fb = HostBitGet(h, idx); + if (fb == NULL) { + fb = SCMalloc(sizeof(HostBit)); + if (unlikely(fb == NULL)) + return; + + fb->type = DETECT_HOSTBITS; + fb->idx = idx; + fb->next = NULL; + + GenericVar *gv = HostGetStorageById(h, host_bit_id); + GenericVarAppend(&gv, (GenericVar *)fb); + HostSetStorageById(h, host_bit_id, gv); + } +} + +static void HostBitRemove(Host *h, uint16_t idx) +{ + HostBit *fb = HostBitGet(h, idx); + if (fb == NULL) + return; + + GenericVar *gv = HostGetStorageById(h, host_bit_id); + if (gv) { + GenericVarRemove(&gv, (GenericVar *)fb); + HostSetStorageById(h, host_bit_id, gv); + } +} + +void HostBitSet(Host *h, uint16_t idx) +{ + HostBit *fb = HostBitGet(h, idx); + if (fb == NULL) { + HostBitAdd(h, idx); + } +} + +void HostBitUnset(Host *h, uint16_t idx) +{ + HostBit *fb = HostBitGet(h, idx); + if (fb != NULL) { + HostBitRemove(h, idx); + } +} + +void HostBitToggle(Host *h, uint16_t idx) +{ + HostBit *fb = HostBitGet(h, idx); + if (fb != NULL) { + HostBitRemove(h, idx); + } else { + HostBitAdd(h, idx); + } +} + +int HostBitIsset(Host *h, uint16_t idx) +{ + int r = 0; + + HostBit *fb = HostBitGet(h, idx); + if (fb != NULL) { + r = 1; + } + return r; +} + +int HostBitIsnotset(Host *h, uint16_t idx) +{ + int r = 0; + + HostBit *fb = HostBitGet(h, idx); + if (fb == NULL) { + r = 1; + } + + return r; +} + +void HostBitFree(HostBit *fb) +{ + if (fb == NULL) + return; + + SCFree(fb); +} + + +/* TESTS */ +#ifdef UNITTESTS +static int HostBitTest01 (void) +{ + int ret = 0; + + HostInitConfig(TRUE); + Host *h = HostAlloc(); + if (h == NULL) + goto end; + + HostBitAdd(h, 0); + + HostBit *fb = HostBitGet(h,0); + if (fb != NULL) + ret = 1; + + HostFree(h); +end: + HostCleanup(); + return ret; +} + +static int HostBitTest02 (void) +{ + int ret = 0; + + HostInitConfig(TRUE); + Host *h = HostAlloc(); + if (h == NULL) + goto end; + + HostBit *fb = HostBitGet(h,0); + if (fb == NULL) + ret = 1; + + HostFree(h); +end: + HostCleanup(); + return ret; +} + +static int HostBitTest03 (void) +{ + int ret = 0; + + HostInitConfig(TRUE); + Host *h = HostAlloc(); + if (h == NULL) + goto end; + + HostBitAdd(h, 0); + + HostBit *fb = HostBitGet(h,0); + if (fb == NULL) { + printf("fb == NULL although it was just added: "); + goto end; + } + + HostBitRemove(h, 0); + + fb = HostBitGet(h,0); + if (fb != NULL) { + printf("fb != NULL although it was just removed: "); + goto end; + } else { + ret = 1; + } + + HostFree(h); +end: + HostCleanup(); + return ret; +} + +static int HostBitTest04 (void) +{ + int ret = 0; + + HostInitConfig(TRUE); + Host *h = HostAlloc(); + if (h == NULL) + goto end; + + HostBitAdd(h, 0); + HostBitAdd(h, 1); + HostBitAdd(h, 2); + HostBitAdd(h, 3); + + HostBit *fb = HostBitGet(h,0); + if (fb != NULL) + ret = 1; + + HostFree(h); +end: + HostCleanup(); + return ret; +} + +static int HostBitTest05 (void) +{ + int ret = 0; + + HostInitConfig(TRUE); + Host *h = HostAlloc(); + if (h == NULL) + goto end; + + HostBitAdd(h, 0); + HostBitAdd(h, 1); + HostBitAdd(h, 2); + HostBitAdd(h, 3); + + HostBit *fb = HostBitGet(h,1); + if (fb != NULL) + ret = 1; + + HostFree(h); +end: + HostCleanup(); + return ret; +} + +static int HostBitTest06 (void) +{ + int ret = 0; + + HostInitConfig(TRUE); + Host *h = HostAlloc(); + if (h == NULL) + goto end; + + HostBitAdd(h, 0); + HostBitAdd(h, 1); + HostBitAdd(h, 2); + HostBitAdd(h, 3); + + HostBit *fb = HostBitGet(h,2); + if (fb != NULL) + ret = 1; + + HostFree(h); +end: + HostCleanup(); + return ret; +} + +static int HostBitTest07 (void) +{ + int ret = 0; + + HostInitConfig(TRUE); + Host *h = HostAlloc(); + if (h == NULL) + goto end; + + HostBitAdd(h, 0); + HostBitAdd(h, 1); + HostBitAdd(h, 2); + HostBitAdd(h, 3); + + HostBit *fb = HostBitGet(h,3); + if (fb != NULL) + ret = 1; + + HostFree(h); +end: + HostCleanup(); + return ret; +} + +static int HostBitTest08 (void) +{ + int ret = 0; + + HostInitConfig(TRUE); + Host *h = HostAlloc(); + if (h == NULL) + goto end; + + HostBitAdd(h, 0); + HostBitAdd(h, 1); + HostBitAdd(h, 2); + HostBitAdd(h, 3); + + HostBit *fb = HostBitGet(h,0); + if (fb == NULL) + goto end; + + HostBitRemove(h,0); + + fb = HostBitGet(h,0); + if (fb != NULL) { + printf("fb != NULL even though it was removed: "); + goto end; + } + + ret = 1; + HostFree(h); +end: + HostCleanup(); + return ret; +} + +static int HostBitTest09 (void) +{ + int ret = 0; + + HostInitConfig(TRUE); + Host *h = HostAlloc(); + if (h == NULL) + goto end; + + HostBitAdd(h, 0); + HostBitAdd(h, 1); + HostBitAdd(h, 2); + HostBitAdd(h, 3); + + HostBit *fb = HostBitGet(h,1); + if (fb == NULL) + goto end; + + HostBitRemove(h,1); + + fb = HostBitGet(h,1); + if (fb != NULL) { + printf("fb != NULL even though it was removed: "); + goto end; + } + + ret = 1; + HostFree(h); +end: + HostCleanup(); + return ret; +} + +static int HostBitTest10 (void) +{ + int ret = 0; + + HostInitConfig(TRUE); + Host *h = HostAlloc(); + if (h == NULL) + goto end; + + HostBitAdd(h, 0); + HostBitAdd(h, 1); + HostBitAdd(h, 2); + HostBitAdd(h, 3); + + HostBit *fb = HostBitGet(h,2); + if (fb == NULL) + goto end; + + HostBitRemove(h,2); + + fb = HostBitGet(h,2); + if (fb != NULL) { + printf("fb != NULL even though it was removed: "); + goto end; + } + + ret = 1; + HostFree(h); +end: + HostCleanup(); + return ret; +} + +static int HostBitTest11 (void) +{ + int ret = 0; + + HostInitConfig(TRUE); + Host *h = HostAlloc(); + if (h == NULL) + goto end; + + HostBitAdd(h, 0); + HostBitAdd(h, 1); + HostBitAdd(h, 2); + HostBitAdd(h, 3); + + HostBit *fb = HostBitGet(h,3); + if (fb == NULL) + goto end; + + HostBitRemove(h,3); + + fb = HostBitGet(h,3); + if (fb != NULL) { + printf("fb != NULL even though it was removed: "); + goto end; + } + + ret = 1; + HostFree(h); +end: + HostCleanup(); + ret = 1; + return ret; +} + +#endif /* UNITTESTS */ + +void HostBitRegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("HostBitTest01", HostBitTest01, 1); + UtRegisterTest("HostBitTest02", HostBitTest02, 1); + UtRegisterTest("HostBitTest03", HostBitTest03, 1); + UtRegisterTest("HostBitTest04", HostBitTest04, 1); + UtRegisterTest("HostBitTest05", HostBitTest05, 1); + UtRegisterTest("HostBitTest06", HostBitTest06, 1); + UtRegisterTest("HostBitTest07", HostBitTest07, 1); + UtRegisterTest("HostBitTest08", HostBitTest08, 1); + UtRegisterTest("HostBitTest09", HostBitTest09, 1); + UtRegisterTest("HostBitTest10", HostBitTest10, 1); + UtRegisterTest("HostBitTest11", HostBitTest11, 1); +#endif /* UNITTESTS */ +} diff --git a/src/host-bit.h b/src/host-bit.h new file mode 100644 index 0000000000..c10a4fecf0 --- /dev/null +++ b/src/host-bit.h @@ -0,0 +1,49 @@ +/* Copyright (C) 2007-2010 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + */ + +#ifndef __HOST_BIT_H__ +#define __HOST_BIT_H__ + +#include "host.h" +#include "util-var.h" + +typedef struct HostBit_ { + uint8_t type; /* type, DETECT_HOSTBITS in this case */ + uint16_t idx; /* name idx */ + GenericVar *next; /* right now just implement this as a list, + * in the long run we have think of something + * faster. */ +} HostBit; + +void HostBitInitCtx(void); +void HostBitFree(HostBit *); +void HostBitRegisterTests(void); + +int HostHasHostBits(Host *host); + +void HostBitSet(Host *, uint16_t); +void HostBitUnset(Host *, uint16_t); +void HostBitToggle(Host *, uint16_t); +int HostBitIsset(Host *, uint16_t); +int HostBitIsnotset(Host *, uint16_t); +#endif /* __FLOW_BIT_H__ */ diff --git a/src/host.c b/src/host.c index c3831c757e..7c3c584172 100644 --- a/src/host.c +++ b/src/host.c @@ -29,6 +29,7 @@ #include "util-debug.h" #include "host.h" #include "host-storage.h" +#include "host-bit.h" #include "util-random.h" #include "util-misc.h" @@ -439,6 +440,12 @@ void HostLock(Host *h) SCMutexLock(&h->m); } +void HostUnlock(Host *h) +{ + SCMutexUnlock(&h->m); +} + + /* HostGetHostFromHash * * Hash retrieval function for hosts. Looks up the hash bucket containing the diff --git a/src/host.h b/src/host.h index 56a16dc472..e3dd167a2e 100644 --- a/src/host.h +++ b/src/host.h @@ -148,5 +148,10 @@ void HostPrintStats (void); void HostRegisterUnittests(void); +Host *HostAlloc(); +void HostFree(); + +void HostUnlock(Host *h); + #endif /* __HOST_H__ */ diff --git a/src/runmode-unittests.c b/src/runmode-unittests.c index d4c55f391e..1252dd9752 100644 --- a/src/runmode-unittests.c +++ b/src/runmode-unittests.c @@ -60,6 +60,7 @@ #include "pkt-var.h" #include "host.h" +#include "host-bit.h" #include "ippair.h" #include "unix-manager.h" @@ -171,6 +172,8 @@ void RunUnittests(int list_unittests, char *regex_arg) DetectEngineRegisterAppInspectionEngines(); + HostBitInitCtx(); + StorageFinalize(); /* test and initialize the unittesting subsystem */ if(regex_arg == NULL){ @@ -194,6 +197,7 @@ void RunUnittests(int list_unittests, char *regex_arg) ByteRegisterTests(); MpmRegisterTests(); FlowBitRegisterTests(); + HostBitRegisterTests(); SCPerfRegisterTests(); DecodePPPRegisterTests(); DecodeVLANRegisterTests(); diff --git a/src/suricata.c b/src/suricata.c index b766ff54e5..a6e022b5ce 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -130,6 +130,7 @@ #include "flow-var.h" #include "flow-bit.h" #include "pkt-var.h" +#include "host-bit.h" #include "ippair.h" #include "host.h" @@ -2097,6 +2098,7 @@ static int PostConfLoadedSetup(SCInstance *suri) TagInitCtx(); ThresholdInit(); + HostBitInitCtx(); if (DetectAddressTestConfVars() < 0) { SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY, diff --git a/src/util-var.c b/src/util-var.c index 832a2d31f1..b84f191187 100644 --- a/src/util-var.c +++ b/src/util-var.c @@ -31,6 +31,7 @@ #include "flow-var.h" #include "flow-bit.h" #include "pkt-var.h" +#include "host-bit.h" #include "util-debug.h" @@ -50,6 +51,13 @@ void GenericVarFree(GenericVar *gv) FlowBitFree(fb); break; } + case DETECT_HOSTBITS: + { + HostBit *fb = (HostBit *)gv; + //printf("GenericVarFree: fb %p, removing\n", fb); + HostBitFree(fb); + break; + } case DETECT_FLOWVAR: { FlowVar *fv = (FlowVar *)gv;