From 83ddc5813a78adbd0f956361f3fe11f476ec7474 Mon Sep 17 00:00:00 2001 From: Pablo Rincon Date: Mon, 29 Mar 2010 18:56:14 +0200 Subject: [PATCH] Support for ecn/cwr TCP sessions --- src/decode-tcp.h | 4 +- src/detect-flags.c | 12 +- src/stream-tcp.c | 268 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 276 insertions(+), 8 deletions(-) diff --git a/src/decode-tcp.h b/src/decode-tcp.h index 413de1b9e2..d155e013da 100644 --- a/src/decode-tcp.h +++ b/src/decode-tcp.h @@ -18,8 +18,8 @@ #define TH_PUSH 0x08 #define TH_ACK 0x10 #define TH_URG 0x20 -#define TH_RES2 0x40 -#define TH_RES1 0x80 +#define TH_ECN 0x40 +#define TH_CWR 0x80 /* tcp option codes */ #define TCP_OPT_EOL 0x00 diff --git a/src/detect-flags.c b/src/detect-flags.c index a174c28950..e7cf9289bd 100644 --- a/src/detect-flags.c +++ b/src/detect-flags.c @@ -232,11 +232,11 @@ static DetectFlagsData *DetectFlagsParse (char *rawstr) found++; break; case '1': - de->flags |= TH_RES1; + de->flags |= TH_CWR; found++; break; case '2': - de->flags |= TH_RES2; + de->flags |= TH_ECN; found++; break; case '0': @@ -296,11 +296,11 @@ static DetectFlagsData *DetectFlagsParse (char *rawstr) found++; break; case '1': - de->flags |= TH_RES1; + de->flags |= TH_CWR; found++; break; case '2': - de->flags |= TH_RES2; + de->flags |= TH_ECN; found++; break; case '0': @@ -377,11 +377,11 @@ static DetectFlagsData *DetectFlagsParse (char *rawstr) ignore++; break; case '1': - de->ignored_flags &= ~TH_RES1; + de->ignored_flags &= ~TH_CWR; ignore++; break; case '2': - de->ignored_flags &= ~TH_RES2; + de->ignored_flags &= ~TH_ECN; ignore++; break; case '0': diff --git a/src/stream-tcp.c b/src/stream-tcp.c index ca76b50a8e..85795c1f8a 100644 --- a/src/stream-tcp.c +++ b/src/stream-tcp.c @@ -470,6 +470,15 @@ static int StreamTcpPacketStateNone(ThreadVars *tv, Packet *p, StreamTcpThread *stt, TcpSession *ssn) { switch (p->tcph->th_flags) { + /* The following cases will allow us to create the tcp sessions in congestion + * conditions, where the client open a connection with SYN and + * any of the following flags: + * TH_CWR -> Establish a new connection reducing window + * TH_ECN -> Echo Congestion flag + */ + case TH_SYN | TH_CWR | TH_ECN: + case TH_SYN | TH_ECN: + case TH_SYN | TH_CWR: case TH_SYN: { if (ssn == NULL) { @@ -5314,6 +5323,258 @@ end: return result; } +/** + * \test Test the initialization of tcp streams with congestion flags + * + * \retval On success it returns 1 and on failure 0. + */ +static int StreamTcpTest25(void) { + Packet p; + Flow f; + ThreadVars tv; + StreamTcpThread stt; + uint8_t payload[4]; + TCPHdr tcph; + memset (&p, 0, sizeof(Packet)); + memset (&f, 0, sizeof(Flow)); + memset(&tv, 0, sizeof (ThreadVars)); + memset(&stt, 0, sizeof (StreamTcpThread)); + memset(&tcph, 0, sizeof (TCPHdr)); + p.flow = &f; + tcph.th_win = htons(5480); + tcph.th_flags = TH_SYN | TH_CWR; + p.tcph = &tcph; + p.flowflags = FLOW_PKT_TOSERVER; + int ret = 0; + + StreamTcpInitConfig(TRUE); + + if (StreamTcpPacket(&tv, &p, &stt) == -1) + goto end; + + p.tcph->th_ack = htonl(1); + p.tcph->th_flags = TH_SYN | TH_ACK; + p.flowflags = FLOW_PKT_TOCLIENT; + + if (StreamTcpPacket(&tv, &p, &stt) == -1 || (TcpSession *)p.flow->protoctx == NULL) + goto end; + + p.tcph->th_ack = htonl(1); + p.tcph->th_seq = htonl(1); + p.tcph->th_flags = TH_ACK; + p.flowflags = FLOW_PKT_TOSERVER; + + if (StreamTcpPacket(&tv, &p, &stt) == -1 || (TcpSession *)p.flow->protoctx == NULL) + goto end; + + p.tcph->th_ack = htonl(1); + p.tcph->th_seq = htonl(2); + p.tcph->th_flags = TH_PUSH | TH_ACK; + p.flowflags = FLOW_PKT_TOSERVER; + + StreamTcpCreateTestPacket(payload, 0x41, 3, 4); /*AAA*/ + p.payload = payload; + p.payload_len = 3; + + if (StreamTcpPacket(&tv, &p, &stt) == -1 || (TcpSession *)p.flow->protoctx == NULL) + goto end; + + p.flowflags = FLOW_PKT_TOCLIENT; + if (StreamTcpPacket(&tv, &p, &stt) == -1 || (TcpSession *)p.flow->protoctx == NULL) + goto end; + + p.tcph->th_ack = htonl(1); + p.tcph->th_seq = htonl(6); + p.tcph->th_flags = TH_PUSH | TH_ACK; + p.flowflags = FLOW_PKT_TOSERVER; + + StreamTcpCreateTestPacket(payload, 0x42, 3, 4); /*BBB*/ + p.payload = payload; + p.payload_len = 3; + + if (StreamTcpPacket(&tv, &p, &stt) == -1 || (TcpSession *)p.flow->protoctx == NULL) + goto end; + + p.flowflags = FLOW_PKT_TOCLIENT; + if (StreamTcpPacket(&tv, &p, &stt) == -1 || (TcpSession *)p.flow->protoctx == NULL) + goto end; + + StreamTcpSessionClear(p.flow->protoctx); + + ret = 1; +end: + StreamTcpFreeConfig(TRUE); + return ret; +} + +/** + * \test Test the initialization of tcp streams with congestion flags + * + * \retval On success it returns 1 and on failure 0. + */ +static int StreamTcpTest26(void) { + Packet p; + Flow f; + ThreadVars tv; + StreamTcpThread stt; + uint8_t payload[4]; + TCPHdr tcph; + memset (&p, 0, sizeof(Packet)); + memset (&f, 0, sizeof(Flow)); + memset(&tv, 0, sizeof (ThreadVars)); + memset(&stt, 0, sizeof (StreamTcpThread)); + memset(&tcph, 0, sizeof (TCPHdr)); + p.flow = &f; + tcph.th_win = htons(5480); + tcph.th_flags = TH_SYN | TH_ECN; + p.tcph = &tcph; + p.flowflags = FLOW_PKT_TOSERVER; + int ret = 0; + + StreamTcpInitConfig(TRUE); + + if (StreamTcpPacket(&tv, &p, &stt) == -1) + goto end; + + p.tcph->th_ack = htonl(1); + p.tcph->th_flags = TH_SYN | TH_ACK; + p.flowflags = FLOW_PKT_TOCLIENT; + + if (StreamTcpPacket(&tv, &p, &stt) == -1 || (TcpSession *)p.flow->protoctx == NULL) + goto end; + + p.tcph->th_ack = htonl(1); + p.tcph->th_seq = htonl(1); + p.tcph->th_flags = TH_ACK; + p.flowflags = FLOW_PKT_TOSERVER; + + if (StreamTcpPacket(&tv, &p, &stt) == -1 || (TcpSession *)p.flow->protoctx == NULL) + goto end; + + p.tcph->th_ack = htonl(1); + p.tcph->th_seq = htonl(2); + p.tcph->th_flags = TH_PUSH | TH_ACK; + p.flowflags = FLOW_PKT_TOSERVER; + + StreamTcpCreateTestPacket(payload, 0x41, 3, 4); /*AAA*/ + p.payload = payload; + p.payload_len = 3; + + if (StreamTcpPacket(&tv, &p, &stt) == -1 || (TcpSession *)p.flow->protoctx == NULL) + goto end; + + p.flowflags = FLOW_PKT_TOCLIENT; + if (StreamTcpPacket(&tv, &p, &stt) == -1 || (TcpSession *)p.flow->protoctx == NULL) + goto end; + + p.tcph->th_ack = htonl(1); + p.tcph->th_seq = htonl(6); + p.tcph->th_flags = TH_PUSH | TH_ACK; + p.flowflags = FLOW_PKT_TOSERVER; + + StreamTcpCreateTestPacket(payload, 0x42, 3, 4); /*BBB*/ + p.payload = payload; + p.payload_len = 3; + + if (StreamTcpPacket(&tv, &p, &stt) == -1 || (TcpSession *)p.flow->protoctx == NULL) + goto end; + + p.flowflags = FLOW_PKT_TOCLIENT; + if (StreamTcpPacket(&tv, &p, &stt) == -1 || (TcpSession *)p.flow->protoctx == NULL) + goto end; + + StreamTcpSessionClear(p.flow->protoctx); + + ret = 1; +end: + StreamTcpFreeConfig(TRUE); + return ret; +} + +/** + * \test Test the initialization of tcp streams with congestion flags + * + * \retval On success it returns 1 and on failure 0. + */ +static int StreamTcpTest27(void) { + Packet p; + Flow f; + ThreadVars tv; + StreamTcpThread stt; + uint8_t payload[4]; + TCPHdr tcph; + memset (&p, 0, sizeof(Packet)); + memset (&f, 0, sizeof(Flow)); + memset(&tv, 0, sizeof (ThreadVars)); + memset(&stt, 0, sizeof (StreamTcpThread)); + memset(&tcph, 0, sizeof (TCPHdr)); + p.flow = &f; + tcph.th_win = htons(5480); + tcph.th_flags = TH_SYN | TH_CWR | TH_ECN; + p.tcph = &tcph; + p.flowflags = FLOW_PKT_TOSERVER; + int ret = 0; + + StreamTcpInitConfig(TRUE); + + if (StreamTcpPacket(&tv, &p, &stt) == -1) + goto end; + + p.tcph->th_ack = htonl(1); + p.tcph->th_flags = TH_SYN | TH_ACK; + p.flowflags = FLOW_PKT_TOCLIENT; + + if (StreamTcpPacket(&tv, &p, &stt) == -1 || (TcpSession *)p.flow->protoctx == NULL) + goto end; + + p.tcph->th_ack = htonl(1); + p.tcph->th_seq = htonl(1); + p.tcph->th_flags = TH_ACK; + p.flowflags = FLOW_PKT_TOSERVER; + + if (StreamTcpPacket(&tv, &p, &stt) == -1 || (TcpSession *)p.flow->protoctx == NULL) + goto end; + + p.tcph->th_ack = htonl(1); + p.tcph->th_seq = htonl(2); + p.tcph->th_flags = TH_PUSH | TH_ACK; + p.flowflags = FLOW_PKT_TOSERVER; + + StreamTcpCreateTestPacket(payload, 0x41, 3, 4); /*AAA*/ + p.payload = payload; + p.payload_len = 3; + + if (StreamTcpPacket(&tv, &p, &stt) == -1 || (TcpSession *)p.flow->protoctx == NULL) + goto end; + + p.flowflags = FLOW_PKT_TOCLIENT; + if (StreamTcpPacket(&tv, &p, &stt) == -1 || (TcpSession *)p.flow->protoctx == NULL) + goto end; + + p.tcph->th_ack = htonl(1); + p.tcph->th_seq = htonl(6); + p.tcph->th_flags = TH_PUSH | TH_ACK; + p.flowflags = FLOW_PKT_TOSERVER; + + StreamTcpCreateTestPacket(payload, 0x42, 3, 4); /*BBB*/ + p.payload = payload; + p.payload_len = 3; + + if (StreamTcpPacket(&tv, &p, &stt) == -1 || (TcpSession *)p.flow->protoctx == NULL) + goto end; + + p.flowflags = FLOW_PKT_TOCLIENT; + if (StreamTcpPacket(&tv, &p, &stt) == -1 || (TcpSession *)p.flow->protoctx == NULL) + goto end; + + StreamTcpSessionClear(p.flow->protoctx); + + ret = 1; +end: + StreamTcpFreeConfig(TRUE); + return ret; +} + #endif /* UNITTESTS */ void StreamTcpRegisterTests (void) { @@ -5358,6 +5619,13 @@ void StreamTcpRegisterTests (void) { UtRegisterTest("StreamTcpTest22 -- setup OS policy", StreamTcpTest22, 1); UtRegisterTest("StreamTcpTest23 -- stream memory leaks", StreamTcpTest23, 1); UtRegisterTest("StreamTcpTest24 -- stream memory leaks", StreamTcpTest24, 1); + UtRegisterTest("StreamTcpTest25 -- test ecn/cwr sessions", + StreamTcpTest25, 1); + UtRegisterTest("StreamTcpTest26 -- test ecn/cwr sessions", + StreamTcpTest26, 1); + UtRegisterTest("StreamTcpTest27 -- test ecn/cwr sessions", + StreamTcpTest27, 1); + /* set up the reassembly tests as well */ StreamTcpReassembleRegisterTests(); #endif /* UNITTESTS */