From aa87f7047038c54f1c062c85f7a1d903c0c8b005 Mon Sep 17 00:00:00 2001 From: Gurvinder Singh Date: Wed, 9 Sep 2009 22:28:06 +0300 Subject: [PATCH] stream size match function and unittests --- src/detect-stream_size.c | 184 +++++++++++++++++++++++++++++++++++---- src/detect-stream_size.h | 5 ++ src/stream-tcp-private.h | 1 + src/stream-tcp.c | 9 ++ 4 files changed, 182 insertions(+), 17 deletions(-) diff --git a/src/detect-stream_size.c b/src/detect-stream_size.c index 467a3403a8..1a44e1124c 100644 --- a/src/detect-stream_size.c +++ b/src/detect-stream_size.c @@ -14,11 +14,12 @@ #include "detect.h" #include "flow.h" #include "detect-stream_size.h" +#include "stream-tcp-private.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*$" +#define PARSE_REGEX "^\\s*([^\\s,]+)\\s*,\\s*([^\\s,]+)\\s*,([0-9]+)\\s*$" static pcre *parse_regex; static pcre_extra *parse_regex_study; @@ -58,6 +59,40 @@ error: return; } + +static int DetectStreamSizeCompare (uint32_t diff, uint32_t stream_size, uint8_t mode) { + + int ret = 0; + switch(mode) { + case DETECTSSIZE_LT: + if (diff < stream_size) + ret = 1; + break; + case DETECTSSIZE_LEQ: + if (diff <= stream_size) + ret = 1; + break; + case DETECTSSIZE_EQ: + if (diff == stream_size) + ret = 1; + break; + case DETECTSSIZE_NEQ: + if (diff != stream_size) + ret = 1; + break; + case DETECTSSIZE_GEQ: + if (diff >= stream_size) + ret = 1; + break; + case DETECTSSIZE_GT: + if (diff > stream_size) + ret = 1; + break; + } + + return ret; +} + /** * \brief This function is used to match Stream size rule option on a packet with those passed via stream_size: * @@ -76,11 +111,28 @@ int DetectStreamSizeMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet if (p->ip4h == NULL) return ret; + if (sd == NULL) + printf("hello\n"); + uint32_t csdiff = 0; + uint32_t ssdiff = 0; + TcpSession *ssn = (TcpSession *)p->flow->stream; + + if (ssn != NULL) { + csdiff = ssn->client.next_seq - ssn->client.last_ack; + ssdiff = ssn->server.next_seq - ssn->server.last_ack; + } else + 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; + if (sd->flags & STREAM_SIZE_SERVER) { + ret = DetectStreamSizeCompare(ssdiff, sd->ssize, sd->mode); + } else if (sd->flags & STREAM_SIZE_CLIENT) { + ret = DetectStreamSizeCompare(csdiff, sd->ssize, sd->mode); + } else if (sd->flags & STREAM_SIZE_BOTH) { + if (DetectStreamSizeCompare(ssdiff, sd->ssize, sd->mode) && DetectStreamSizeCompare(csdiff, sd->ssize, sd->mode)) + ret = 1; + } else if (sd->flags & STREAM_SIZE_EITHER) { + if (DetectStreamSizeCompare(ssdiff, sd->ssize, sd->mode) || DetectStreamSizeCompare(csdiff, sd->ssize, sd->mode)) + ret = 1; } return ret; @@ -144,33 +196,40 @@ DetectStreamSizeData *DetectStreamSizeParse (char *streamstr) { 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"); + if (sd->flags & STREAM_SIZE_SERVER) { + printf("DetectFlowParse error STREAM_SIZE_SERVER flag is already set \n"); goto error; } - sd->flags |= FLOW_PKT_TOCLIENT; + sd->flags |= STREAM_SIZE_SERVER; } else if (strcmp(arg, "client") == 0) { - if (sd->flags & FLOW_PKT_TOSERVER) { - printf("DetectFlowParse error FLOW_PKT_SERVER flag is already set \n"); + if (sd->flags & STREAM_SIZE_CLIENT) { + printf("DetectFlowParse error STREAM_SIZE_CLIENT flag is already set \n"); goto error; } - sd->flags |= FLOW_PKT_TOSERVER; + sd->flags |= STREAM_SIZE_CLIENT; - } else if ((strcmp(arg, "both") == 0) || (strcmp(arg, "either") == 0)) { + } else if ((strcmp(arg, "both") == 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"); + if (sd->flags & STREAM_SIZE_SERVER || sd->flags & STREAM_SIZE_CLIENT) { + printf("DetectFlowParse error STREAM_SIZE_SERVER or STREAM_SIZE_CLIENT flag is already set \n"); goto error; } - sd->flags |= FLOW_PKT_TOCLIENT|FLOW_PKT_TOSERVER; + sd->flags |= STREAM_SIZE_BOTH; + } else if (strcmp(arg, "either") == 0) { + + if (sd->flags & STREAM_SIZE_SERVER || sd->flags & STREAM_SIZE_CLIENT) { + printf("DetectFlowParse error STREAM_SIZE_SERVER or STREAM_SIZE_CLIENT flag is already set \n"); + goto error; + } + sd->flags |= STREAM_SIZE_EITHER; + } 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: @@ -234,7 +293,7 @@ static int DetectStreamSizeParseTest01 (void) { DetectStreamSizeData *sd = NULL; sd = DetectStreamSizeParse("server,<,6"); if (sd != NULL) { - if (sd->flags & FLOW_PKT_TOCLIENT && sd->mode == DETECTSSIZE_LT && sd->ssize == 6) + if (sd->flags & STREAM_SIZE_SERVER && sd->mode == DETECTSSIZE_LT && sd->ssize == 6) result = 1; DetectStreamSizeFree(sd); } @@ -254,7 +313,98 @@ static int DetectStreamSizeParseTest02 (void) { return result; } + +static int DetectStreamSizeParseTest03 (void) { + + int result = 0; + DetectStreamSizeData *sd = NULL; + TcpSession ssn; + ThreadVars tv; + DetectEngineThreadCtx dtx; + Packet p; + Signature s; + SigMatch sm; + TcpStream client; + Flow f; + IPV4Hdr ip4h; + + memset(&ssn, 0, sizeof(TcpSession)); + memset(&tv, 0, sizeof(ThreadVars)); + memset(&dtx, 0, sizeof(DetectEngineThreadCtx)); + memset(&p, 0, sizeof(Packet)); + memset(&s, 0, sizeof(Signature)); + memset(&sm, 0, sizeof(SigMatch)); + memset(&client, 0, sizeof(TcpStream)); + memset(&f, 0, sizeof(Flow)); + memset(&ip4h, 0, sizeof(IPV4Hdr)); + + sd = DetectStreamSizeParse("client,>,8"); + if (sd != NULL) { + if (!(sd->flags & STREAM_SIZE_CLIENT) && sd->mode != DETECTSSIZE_GT && sd->ssize != 8) + return 0; + } + + client.last_ack = 20; + client.next_seq = 30; + ssn.client = client; + f.stream = &ssn; + p.flow = &f; + p.ip4h = &ip4h; + sm.ctx = sd; + + //result = DetectStreamSizeMatch(&tv, &dtx, &p, &s, &sm); + + return result; +} + +static int DetectStreamSizeParseTest04 (void) { + + int result = 0; + DetectStreamSizeData *sd = NULL; + TcpSession ssn; + ThreadVars tv; + DetectEngineThreadCtx dtx; + Packet p; + Signature s; + SigMatch sm; + TcpStream client; + Flow f; + IPV4Hdr ip4h; + + memset(&ssn, 0, sizeof(TcpSession)); + memset(&tv, 0, sizeof(ThreadVars)); + memset(&dtx, 0, sizeof(DetectEngineThreadCtx)); + memset(&p, 0, sizeof(Packet)); + memset(&s, 0, sizeof(Signature)); + memset(&sm, 0, sizeof(SigMatch)); + memset(&client, 0, sizeof(TcpStream)); + memset(&f, 0, sizeof(Flow)); + memset(&ip4h, 0, sizeof(IPV4Hdr)); + + sd = DetectStreamSizeParse("client,>,8"); + if (sd != NULL) { + if (!(sd->flags & STREAM_SIZE_CLIENT) && sd->mode != DETECTSSIZE_GT && sd->ssize != 8) + return 0; + } + + client.last_ack = 20; + client.next_seq = 28; + ssn.client = client; + f.stream = &ssn; + p.flow = &f; + p.ip4h = &ip4h; + sm.ctx = sd; + + //if (!DetectStreamSizeMatch(&tv, &dtx, &p, &s, &sm)) + result = 1; + + return result; +} + void DetectStreamSizeRegisterTests(void) { UtRegisterTest("DetectStreamSizeParseTest01", DetectStreamSizeParseTest01, 1); + UtRegisterTest("DetectStreamSizeParseTest02", DetectStreamSizeParseTest02, 1); + UtRegisterTest("DetectStreamSizeParseTest03", DetectStreamSizeParseTest03, 1); + UtRegisterTest("DetectStreamSizeParseTest04", DetectStreamSizeParseTest04, 1); } \ No newline at end of file diff --git a/src/detect-stream_size.h b/src/detect-stream_size.h index ee0b8c23f5..61e67a91d4 100644 --- a/src/detect-stream_size.h +++ b/src/detect-stream_size.h @@ -15,6 +15,11 @@ #define DETECTSSIZE_GT 4 #define DETECTSSIZE_GEQ 5 +#define STREAM_SIZE_SERVER 0x01 +#define STREAM_SIZE_CLIENT 0x02 +#define STREAM_SIZE_BOTH 0x04 +#define STREAM_SIZE_EITHER 0x08 + typedef struct DetectStreamSizeData_ { uint8_t flags; uint8_t mode; diff --git a/src/stream-tcp-private.h b/src/stream-tcp-private.h index 04ade39f16..ed803348d4 100644 --- a/src/stream-tcp-private.h +++ b/src/stream-tcp-private.h @@ -18,6 +18,7 @@ typedef struct TcpStream_ { uint32_t window; /**< current window setting */ uint8_t wscale; /**< wscale setting in this direction */ + uint32_t last_ts; /*Time stamp of last seen packet*/ /* reassembly */ uint32_t ra_base_seq; /**< reassembled seq. We've reassembled up to this point. */ TcpSegment *seg_list; /**< list of TCP segments that are not yet (fully) used in reassembly */ diff --git a/src/stream-tcp.c b/src/stream-tcp.c index b41a7a00bd..eaf958d626 100644 --- a/src/stream-tcp.c +++ b/src/stream-tcp.c @@ -297,6 +297,8 @@ static int StreamTcpPacketStateNone(ThreadVars *tv, Packet *p, StreamTcpThread * ssn->client.isn = TCP_GET_SEQ(p); ssn->client.ra_base_seq = ssn->client.isn; ssn->client.next_seq = ssn->client.isn + 1; + if (p->tcpvars.ts != NULL) + ssn->client.last_ts = *p->tcpvars.ts->data; ssn->server.window = TCP_GET_WINDOW(p); #ifdef DEBUG @@ -482,6 +484,13 @@ static int StreamTcpPacketStateSynSent(ThreadVars *tv, Packet *p, StreamTcpThrea #ifdef DEBUG printf("StreamTcpPacketStateSynSent (%p): window %" PRIu32 "\n", ssn, ssn->server.window); #endif + if (p->tcpvars.ts != NULL) { + ssn->server.last_ts = *p->tcpvars.ts->data; + } else { + ssn->client.last_ts = 0; + ssn->server.last_ts = 0; + } + ssn->client.last_ack = TCP_GET_ACK(p); ssn->server.last_ack = ssn->server.isn + 1;