diff --git a/src/stream-tcp-private.h b/src/stream-tcp-private.h index adbfdff719..23c2ef83fe 100644 --- a/src/stream-tcp-private.h +++ b/src/stream-tcp-private.h @@ -18,7 +18,9 @@ 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*/ + uint32_t last_ts; /**< Time stamp of last seen packet*/ + uint32_t last_pkt_ts; /**< Time of last seen packet for this stream (needed for PAWS update)*/ + /* 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 */ @@ -44,8 +46,11 @@ enum #define STREAMTCP_FLAG_MIDSTREAM 0x01 /*Flag for mid stream session*/ #define STREAMTCP_FLAG_MIDSTREAM_ESTABLISHED 0x02 /*Flag for mid stream established session*/ +#define STREAMTCP_TIMESTAMP 0x04 /*Flag for TCP Timestamp option*/ #define STREAMTCP_FLAG_SERVER_WSCALE 0x08 /**< Server supports wscale (even though it can be 0) */ +#define PAWS_24DAYS 2073600 /* 24 days in seconds */ + /* Macro's for comparing Sequence numbers * Page 810 from TCP/IP Illustrated, Volume 2. */ #define SEQ_EQ(a,b) ((int)((a) - (b)) == 0) @@ -54,6 +59,8 @@ enum #define SEQ_GT(a,b) ((int)((a) - (b)) > 0) #define SEQ_GEQ(a,b) ((int)((a) - (b)) >= 0) +#define GET_TIMESTAMP(p) ((u_int32_t) ntohl (*(u_int32_t *)(p))) + typedef struct TcpSession_ { uint8_t state; uint8_t flags; diff --git a/src/stream-tcp.c b/src/stream-tcp.c index 162553c9fa..7f082cd805 100644 --- a/src/stream-tcp.c +++ b/src/stream-tcp.c @@ -36,6 +36,7 @@ void StreamTcpReturnStreamSegments (TcpStream *); void StreamTcpInitConfig(char); extern void StreamTcpSegmentReturntoPool(TcpSegment *); int StreamTcpGetFlowState(void *); +static int ValidTimestamp(TcpSession * , Packet *); #define STREAMTCP_DEFAULT_SESSIONS 262144 #define STREAMTCP_DEFAULT_PREALLOC 32768 @@ -292,8 +293,15 @@ 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; + + if (p->tcpvars.ts != NULL) { + ssn->client.last_ts = GET_TIMESTAMP(p->tcpvars.ts->data); +#ifdef DEBUG + printf("StreamTcpPacketStateNone (%p): p->tcpvars.ts %p, %02x\n", ssn, p->tcpvars.ts, ssn->client.last_ts); +#endif + ssn->client.last_pkt_ts = p->ts.tv_sec; + } + ssn->server.window = TCP_GET_WINDOW(p); if (p->tcpvars.ws != NULL) { @@ -351,6 +359,19 @@ static int StreamTcpPacketStateNone(ThreadVars *tv, Packet *p, StreamTcpThread * printf("StreamTcpPacketStateNone (%p): ssn->server.isn %"PRIu32", ssn->server.next_seq %"PRIu32", ssn->server.last_ack %"PRIu32"\n", ssn, ssn->server.isn, ssn->server.next_seq, ssn->server.last_ack); #endif + if (p->tcpvars.ts != NULL) { + ssn->server.last_ts = GET_TIMESTAMP(p->tcpvars.ts->data); + ssn->client.last_ts = GET_TIMESTAMP((p->tcpvars.ts->data) + 4); +#ifdef DEBUG + printf("StreamTcpPacketStateNone (%p): ssn->server.last_ts %" PRIu32" ssn->client.last_ts %" PRIu32"\n", ssn, ssn->server.last_ts, ssn->client.last_ts); +#endif + ssn->flags |= STREAMTCP_TIMESTAMP; + ssn->server.last_pkt_ts = p->ts.tv_sec; + } else { + ssn->server.last_ts = 0; + ssn->client.last_ts = 0; + } + break; /* Handle SYN/ACK and 3WHS shake missed together as it is almost similar. */ case TH_ACK: @@ -400,6 +421,19 @@ static int StreamTcpPacketStateNone(ThreadVars *tv, Packet *p, StreamTcpThread * ssn->client.wscale = TCP_WSCALE_MAX; ssn->server.wscale = TCP_WSCALE_MAX; + if (p->tcpvars.ts != NULL) { + ssn->server.last_ts = GET_TIMESTAMP (p->tcpvars.ts->data); + ssn->client.last_ts = GET_TIMESTAMP ((p->tcpvars.ts->data) + 4); +#ifdef DEBUG + printf("StreamTcpPacketStateNone (%p): ssn->server.last_ts %" PRIu32" ssn->client.last_ts %" PRIu32"\n", ssn, ssn->server.last_ts, ssn->client.last_ts); +#endif + ssn->flags |= STREAMTCP_TIMESTAMP; + ssn->client.last_pkt_ts = p->ts.tv_sec; + } else { + ssn->server.last_ts = 0; + ssn->client.last_ts = 0; + } + StreamTcpReassembleHandleSegment(ssn, &ssn->client, p); break; case TH_RST: @@ -477,8 +511,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; + if (p->tcpvars.ts != NULL && ssn->client.last_ts != 0) { + ssn->server.last_ts = GET_TIMESTAMP (p->tcpvars.ts->data); +#ifdef DEBUG + printf("StreamTcpPacketStateSynSent (%p): ssn->server.last_ts %" PRIu32" ssn->client.last_ts %" PRIu32"\n", ssn, ssn->server.last_ts, ssn->client.last_ts); +#endif + ssn->flags |= STREAMTCP_TIMESTAMP; + ssn->server.last_pkt_ts = p->ts.tv_sec; } else { ssn->client.last_ts = 0; ssn->server.last_ts = 0; @@ -584,6 +623,9 @@ static int StreamTcpPacketStateSynRecv(ThreadVars *tv, Packet *p, StreamTcpThrea ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale; ssn->server.next_win = ssn->server.last_ack + ssn->server.window; + + if (ssn->flags & STREAMTCP_TIMESTAMP) + ssn->client.last_pkt_ts = p->ts.tv_sec; #ifdef DEBUG printf("StreamTcpPacketStateSynRecv (%p): ssn->server.next_win %" PRIu32 ", ssn->server.last_ack %"PRIu32"\n", ssn, ssn->server.next_win, ssn->server.last_ack); #endif @@ -638,6 +680,10 @@ static int StreamTcpPacketStateEstablished(ThreadVars *tv, Packet *p, StreamTcpT break; case TH_ACK: case TH_ACK|TH_PUSH: + + if (!ValidTimestamp(ssn, p)) + return -1; + if (PKT_IS_TOSERVER(p)) { #ifdef DEBUG printf("StreamTcpPacketStateEstablished (%p): =+ pkt (%" PRIu32 ") is to server: SEQ %" PRIu32 ", ACK %" PRIu32 ", WIN %"PRIu16"\n", @@ -648,6 +694,8 @@ static int StreamTcpPacketStateEstablished(ThreadVars *tv, Packet *p, StreamTcpT #ifdef DEBUG printf("StreamTcpPacketStateEstablished (%p): ssn->client.next_seq %" PRIu32 "\n", ssn, ssn->client.next_seq); #endif + if (ssn->flags & STREAMTCP_TIMESTAMP) + ssn->client.last_ts = GET_TIMESTAMP(p->tcpvars.ts->data); } if (SEQ_GEQ(TCP_GET_SEQ(p), ssn->client.last_ack)) { @@ -671,6 +719,8 @@ static int StreamTcpPacketStateEstablished(ThreadVars *tv, Packet *p, StreamTcpT printf("StreamTcpPacketStateEstablished (%p): seq %"PRIu32", updated ssn->server.next_win %" PRIu32 " (win %"PRIu32")\n", ssn, TCP_GET_SEQ(p), ssn->server.next_win, ssn->server.window); #endif } + if (ssn->flags & STREAMTCP_TIMESTAMP) + ssn->client.last_pkt_ts = p->ts.tv_sec; StreamTcpReassembleHandleSegment(ssn, &ssn->client, p); } else { @@ -712,6 +762,8 @@ static int StreamTcpPacketStateEstablished(ThreadVars *tv, Packet *p, StreamTcpT #ifdef DEBUG printf("StreamTcpPacketStateEstablished (%p): ssn->server.next_seq %" PRIu32 "\n", ssn, ssn->server.next_seq); #endif + if (ssn->flags & STREAMTCP_TIMESTAMP) + ssn->server.last_ts = GET_TIMESTAMP(p->tcpvars.ts->data); } if (SEQ_GEQ(TCP_GET_SEQ(p), ssn->server.last_ack)) { @@ -738,6 +790,8 @@ static int StreamTcpPacketStateEstablished(ThreadVars *tv, Packet *p, StreamTcpT printf("StreamTcpPacketStateEstablished (%p): seq %"PRIu32", keeping ssn->client.next_win %" PRIu32 " the same (win %"PRIu32")\n", ssn, TCP_GET_SEQ(p), ssn->client.next_win, ssn->client.window); #endif } + if (ssn->flags & STREAMTCP_TIMESTAMP) + ssn->server.last_pkt_ts = p->ts.tv_sec; StreamTcpReassembleHandleSegment(ssn, &ssn->server, p); } else { @@ -1736,6 +1790,15 @@ int StreamTcpGetFlowState(void *s) { return FLOW_STATE_CLOSED; } +static int ValidTimestamp (TcpSession *ssn, Packet *p) { + /*XXX GS its WIP*/ + if (!(ssn->flags & STREAMTCP_TIMESTAMP)) { + return 1; + } else { + + } + return 1; +} #ifdef UNITTESTS