From ac53ca5b279653d6f9e13bdef958b5e6b973e7a5 Mon Sep 17 00:00:00 2001 From: Gurvinder Singh Date: Mon, 7 Sep 2009 22:46:03 +0300 Subject: [PATCH] Stream Size rule option --- src/Makefile.am | 1 + src/detect-stream_size.c | 260 +++++++++++++++++++++++++++++++++++++++ src/detect-stream_size.h | 27 ++++ src/detect.c | 2 + src/detect.h | 1 + 5 files changed, 291 insertions(+) create mode 100644 src/detect-stream_size.c create mode 100644 src/detect-stream_size.h diff --git a/src/Makefile.am b/src/Makefile.am index 8b1522fde4..1f89ef7906 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -59,6 +59,7 @@ detect-metadata.c detect-metadata.h \ detect-msg.c detect-msg.h \ detect-flow.c detect-flow.h \ detect-dsize.c detect-dsize.h \ +detect-stream_size.c detect-stream_size.h \ detect-decode-event.c detect-decode-event.h \ detect-noalert.c detect-noalert.h \ detect-csum.c detect-csum.h \ diff --git a/src/detect-stream_size.c b/src/detect-stream_size.c new file mode 100644 index 0000000000..467a3403a8 --- /dev/null +++ b/src/detect-stream_size.c @@ -0,0 +1,260 @@ +/**Copyright (c) 2009 Open Information Security Foundation + * + * \author Gurvinder Singh + * + * Stream size for the engine. + */ + +#include +#include + +#include "eidps.h" +#include "stream-tcp.h" +#include "util-unittest.h" +#include "detect.h" +#include "flow.h" +#include "detect-stream_size.h" + +/** XXX GS define it properly!! + * \brief Regex for parsing our flow options + */ +#define PARSE_REGEX "^\\s*([A-z_]+)\\s*(?:,\\s*([A-z_]+))?\\s*(?:,\\s*([0-9]+))?\\s*$" + +static pcre *parse_regex; +static pcre_extra *parse_regex_study; + +int DetectStreamSizeMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); +int DetectStreamSizeSetup (DetectEngineCtx *, Signature *, SigMatch *, char *); +void DetectStreamSizeFree(void *); +void DetectStreamSizeRegisterTests(void); + +void DetectStreamSizeRegister(void) { + sigmatch_table[DETECT_STREAM_SIZE].name = "stream_size"; + sigmatch_table[DETECT_STREAM_SIZE].Match = DetectStreamSizeMatch; + sigmatch_table[DETECT_STREAM_SIZE].Setup = DetectStreamSizeSetup; + sigmatch_table[DETECT_STREAM_SIZE].Free = DetectStreamSizeFree; + sigmatch_table[DETECT_STREAM_SIZE].RegisterTests = DetectStreamSizeRegisterTests; + + 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 %" PRId32 ": %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: + if (parse_regex != NULL) free(parse_regex); + if (parse_regex_study != NULL) free(parse_regex_study); + return; +} + +/** + * \brief This function is used to match Stream size rule option on a packet with those passed via stream_size: + * + * \param t pointer to thread vars + * \param det_ctx pointer to the pattern matcher thread + * \param p pointer to the current packet + * \param m pointer to the sigmatch that we will cast into DetectStreamSizeData + * + * \retval 0 no match + * \retval 1 match + */ +int DetectStreamSizeMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *m) { + + int ret = 0; + DetectStreamSizeData *sd = (DetectStreamSizeData *) m->ctx; + + if (p->ip4h == NULL) + return ret; + + if (sd->flags & FLOW_PKT_TOCLIENT && p->flowflags & FLOW_PKT_TOCLIENT) { + ret = 1; + } else if (sd->flags & FLOW_PKT_TOSERVER && p->flowflags & FLOW_PKT_TOSERVER) { + ret = 1; + } + + return ret; +} + +DetectStreamSizeData *DetectStreamSizeParse (char *streamstr) { + + DetectStreamSizeData *sd = NULL; + char *arg = NULL; + char *value = NULL; + char *mode = NULL; +#define MAX_SUBSTRINGS 30 + int ret = 0, res = 0; + int ov[MAX_SUBSTRINGS]; + + ret = pcre_exec(parse_regex, parse_regex_study, streamstr, strlen(streamstr), 0, 0, ov, MAX_SUBSTRINGS); + if (ret != 3) { + printf("DetectStreamSizeSetup: parse error, ret %" PRId32 "\n", ret); + goto error; + } + + const char *str_ptr; + + res = pcre_get_substring((char *)streamstr, ov, MAX_SUBSTRINGS, 1, &str_ptr); + if (res < 0) { + printf("DetectStreamSizeSetup: pcre_get_substring failed\n"); + goto error; + } + arg = (char *)str_ptr; + + res = pcre_get_substring((char *)streamstr, ov, MAX_SUBSTRINGS, 2, &str_ptr); + if (res < 0) { + printf("DetectDsizeSetup: pcre_get_substring failed\n"); + goto error; + } + mode = (char *)str_ptr; + + res = pcre_get_substring((char *)streamstr, ov, MAX_SUBSTRINGS, 3, &str_ptr); + if (res < 0) { + printf("DetectDsizeSetup: pcre_get_substring failed\n"); + goto error; + } + value = (char *)str_ptr; + + sd = malloc(sizeof(DetectStreamSizeData)); + if (sd == NULL) { + printf("DetectStreamSizeSetup malloc failed\n"); + goto error; + } + sd->ssize = 0; + sd->flags = 0; + + if(mode[0] == '<') sd->mode = DETECTSSIZE_LT; + else if(strcmp("<=", mode) == 0) sd->mode = DETECTSSIZE_LEQ; + else if (mode[0] == '>') sd->mode = DETECTSSIZE_GT; + else if(strcmp(">=", mode)) sd->mode = DETECTSSIZE_GEQ; + else if(strcmp("!=", mode)) sd->mode = DETECTSSIZE_NEQ; + else sd->mode = DETECTSSIZE_EQ; + + /* set the value */ + sd->ssize = (uint16_t)atoi(value); + + if (strcmp(arg, "server") == 0) { + if (sd->flags & FLOW_PKT_TOCLIENT) { + printf("DetectFlowParse error FLOW_PKT_TOCLIENT flag is already set \n"); + goto error; + } + sd->flags |= FLOW_PKT_TOCLIENT; + + } else if (strcmp(arg, "client") == 0) { + + if (sd->flags & FLOW_PKT_TOSERVER) { + printf("DetectFlowParse error FLOW_PKT_SERVER flag is already set \n"); + goto error; + } + sd->flags |= FLOW_PKT_TOSERVER; + + } else if ((strcmp(arg, "both") == 0) || (strcmp(arg, "either") == 0)) { + + if (sd->flags & FLOW_PKT_TOCLIENT || sd->flags & FLOW_PKT_TOSERVER) { + printf("DetectFlowParse error FLOW_PKT_TOCLIENT or FLOW_PKT_TOSERVER flag is already set \n"); + goto error; + } + sd->flags |= FLOW_PKT_TOCLIENT|FLOW_PKT_TOSERVER; + } + + if (mode != NULL) free(mode); + if (arg != NULL) free(arg); + if (value != NULL) free(value); + if (sd != NULL) printf("hello in parse\n"); + return sd; + +error: + if (mode != NULL) free(mode); + if (arg != NULL) free(arg); + if (value != NULL) free(value); + if (sd != NULL) DetectStreamSizeFree(sd); + + return NULL; +} + +/** + * \brief this function is used to add the parsed stream size data into the current signature + * + * \param de_ctx pointer to the Detection Engine Context + * \param s pointer to the Current Signature + * \param m pointer to the Current SigMatch + * \param streamstr pointer to the user provided stream size options + * + * \retval 0 on Success + * \retval -1 on Failure + */ +int DetectStreamSizeSetup (DetectEngineCtx *de_ctx, Signature *s, SigMatch *m, char *streamstr) { + + DetectStreamSizeData *sd = NULL; + SigMatch *sm = NULL; + + sd = DetectStreamSizeParse(streamstr); + if (sd == NULL) + goto error; + + sm = SigMatchAlloc(); + if (sm == NULL) + goto error; + + sm->type = DETECT_STREAM_SIZE; + sm->ctx = (void *)sd; + + SigMatchAppend(s,m,sm); + + return 0; + +error: + if (sd != NULL) DetectStreamSizeFree(sd); + if (sm != NULL) free(sm); + return -1; +} + +/** + * \brief this function will free memory associated with DetectStreamSizeData + * + * \param ptr pointer to DetectStreamSizeData + */ +void DetectStreamSizeFree(void *ptr) { + DetectStreamSizeData *sd = (DetectStreamSizeData *)ptr; + free(sd); +} + +static int DetectStreamSizeParseTest01 (void) { + int result = 0; + DetectStreamSizeData *sd = NULL; + sd = DetectStreamSizeParse("server,<,6"); + if (sd != NULL) { + if (sd->flags & FLOW_PKT_TOCLIENT && sd->mode == DETECTSSIZE_LT && sd->ssize == 6) + result = 1; + DetectStreamSizeFree(sd); + } + + return result; +} + +static int DetectStreamSizeParseTest02 (void) { + int result = 1; + DetectStreamSizeData *sd = NULL; + sd = DetectStreamSizeParse("invalidoption,<,6"); + if (sd != NULL) { + printf("expected: NULL got 0x%02X %" PRId16 ": ",sd->flags, sd->ssize); + result = 0; + DetectStreamSizeFree(sd); + } + + return result; +} +void DetectStreamSizeRegisterTests(void) { + + UtRegisterTest("DetectStreamSizeParseTest01", DetectStreamSizeParseTest01, 1); +} \ No newline at end of file diff --git a/src/detect-stream_size.h b/src/detect-stream_size.h new file mode 100644 index 0000000000..ee0b8c23f5 --- /dev/null +++ b/src/detect-stream_size.h @@ -0,0 +1,27 @@ +/* + * File: detect-stream_size.h + * \author Gurvinder Singh + * + * Created on September 7, 2009, 7:54 AM + */ + +#ifndef _DETECT_STREAM_SIZE_H +#define _DETECT_STREAM_SIZE_H + +#define DETECTSSIZE_LT 0 +#define DETECTSSIZE_LEQ 1 +#define DETECTSSIZE_EQ 2 +#define DETECTSSIZE_NEQ 3 +#define DETECTSSIZE_GT 4 +#define DETECTSSIZE_GEQ 5 + +typedef struct DetectStreamSizeData_ { + uint8_t flags; + uint8_t mode; + uint32_t ssize; +}DetectStreamSizeData; + +void DetectStreamSizeRegister(void); + +#endif /* _DETECT_STREAM_SIZE_H */ + diff --git a/src/detect.c b/src/detect.c index 006c033168..824d4fb5b6 100644 --- a/src/detect.c +++ b/src/detect.c @@ -44,6 +44,7 @@ #include "detect-noalert.h" #include "detect-flowbits.h" #include "detect-csum.h" +#include "detect-stream_size.h" #include "action-globals.h" #include "tm-modules.h" @@ -2503,6 +2504,7 @@ void SigTableSetup(void) { DetectFlowbitsRegister(); DetectDecodeEventRegister(); DetectCsumRegister(); + DetectStreamSizeRegister(); uint8_t i = 0; for (i = 0; i < DETECT_TBLSIZE; i++) { diff --git a/src/detect.h b/src/detect.h index b5863c0759..e1abb93046 100644 --- a/src/detect.h +++ b/src/detect.h @@ -406,6 +406,7 @@ enum { DETECT_UDPV6_CSUM, DETECT_ICMPV4_CSUM, DETECT_ICMPV6_CSUM, + DETECT_STREAM_SIZE, DETECT_ADDRESS, DETECT_PROTO,