Support newly reported 4WHS TCP setup.

remotes/origin/master-1.0.x
Victor Julien 16 years ago
parent af13665684
commit 2af6ed0c8c

@ -49,18 +49,20 @@ enum
TCP_CLOSED,
};
#define STREAMTCP_FLAG_MIDSTREAM 0x0001 /**< Flag for mid stream session*/
#define STREAMTCP_FLAG_MIDSTREAM_ESTABLISHED 0x0002 /**< Flag for mid stream established session*/
#define STREAMTCP_FLAG_MIDSTREAM 0x0001 /**< Flag for mid stream session*/
#define STREAMTCP_FLAG_MIDSTREAM_ESTABLISHED 0x0002 /**< Flag for mid stream established session*/
#define STREAMTCP_FLAG_MIDSTREAM_SYNACK 0x0004 /**<Flag for mid session when syn/ack is received*/
#define STREAMTCP_FLAG_TIMESTAMP 0x0008 /**< Flag for TCP Timestamp option*/
#define STREAMTCP_FLAG_SERVER_WSCALE 0x0010 /**< Server supports wscale (even though it can be 0) */
#define STREAMTCP_FLAG_ZERO_TIMESTAMP 0x0020 /**< Flag to indicate the zero value of timestamp*/
#define STREAMTCP_FLAG_NOCLIENT_REASSEMBLY 0x0040 /**< Flag to avoid stream reassembly / application layer
#define STREAMTCP_FLAG_TIMESTAMP 0x0008 /**< Flag for TCP Timestamp option*/
#define STREAMTCP_FLAG_SERVER_WSCALE 0x0010 /**< Server supports wscale (even though it can be 0) */
#define STREAMTCP_FLAG_ZERO_TIMESTAMP 0x0020 /**< Flag to indicate the zero value of timestamp*/
#define STREAMTCP_FLAG_NOCLIENT_REASSEMBLY 0x0040 /**< Flag to avoid stream reassembly / application layer
inspection for the client stream.*/
#define STREAMTCP_FLAG_NOSERVER_REASSEMBLY 0x0080 /**< Flag to avoid stream reassembly / application layer
#define STREAMTCP_FLAG_NOSERVER_REASSEMBLY 0x0080 /**< Flag to avoid stream reassembly / application layer
inspection for the server stream.*/
#define STREAMTCP_FLAG_ASYNC 0x0100 /**< Flag to indicate that the session is handling
#define STREAMTCP_FLAG_ASYNC 0x0100 /**< Flag to indicate that the session is handling
asynchronous stream.*/
#define STREAMTCP_FLAG_4WHS 0x0200 /**< Flag to indicate we're dealing with 4WHS:
SYN, SYN, SYN/ACK, ACK (http://www.breakingpointsystems.com/community/blog/tcp-portals-the-three-way-handshake-is-a-lie) */
#define PAWS_24DAYS 2073600 /**< 24 days in seconds */

@ -1,5 +1,13 @@
/* Copyright (c) 2008 Victor Julien <victor@inliniac.net> */
/* 2009 Gurvinder Singh <gurvindersinghdahiya@gmail.com>*/
/* Copyright (c) 2009 OISF */
/** \file
*
* \author Victor Julien <victor@inliniac.net>
* \author Gurvinder Singh <gurvindersinghdahiya@gmail.com>
*
* \todo - 4WHS: what if after the 2nd SYN we turn out to be normal 3WHS anyway?
*/
#include "eidps-common.h"
#include "decode.h"
@ -281,6 +289,7 @@ static inline void StreamTcpPacketSetState(Packet *p, TcpSession *ssn, uint8_t s
* \param p Packet whose flag has to be changed
*/
static inline void StreamTcpPacketSwitchDir(TcpSession *ssn, Packet *p) {
SCLogDebug("ssn %p: switching pkt direction", ssn);
if (PKT_IS_TOSERVER(p)) {
p->flowflags &= ~FLOW_PKT_TOSERVER;
@ -504,11 +513,127 @@ static int StreamTcpPacketStateSynSent(ThreadVars *tv, Packet *p, StreamTcpThrea
if (ssn == NULL)
return -1;
SCLogDebug("ssn %p: pkt received", ssn);
switch (p->tcph->th_flags) {
case TH_SYN:
SCLogDebug("ssn %p: SYN packet on state SYN_SENT... resent", ssn);
if (ssn->flags & STREAMTCP_FLAG_4WHS)
SCLogDebug("ssn %p: SYN packet on state SYN_SENT... resent of 4WHS SYN", ssn);
if (PKT_IS_TOCLIENT(p)) {
/** a SYN only packet in the opposite direction could be:
* http://www.breakingpointsystems.com/community/blog/tcp-portals-the-three-way-handshake-is-a-lie
*
* \todo improve resetting the session */
/* indicate that we're dealing with 4WHS here */
ssn->flags |= STREAMTCP_FLAG_4WHS;
SCLogDebug("ssn %p: STREAMTCP_FLAG_4WHS flag set", ssn);
/* set the sequence numbers and window for server
* We leave the ssn->client.isn in place as we will
* check the SYN/ACK pkt with that.
*/
ssn->server.isn = TCP_GET_SEQ(p);
ssn->server.ra_base_seq = ssn->server.isn;
ssn->server.next_seq = ssn->server.isn + 1;
/* Set the stream timestamp value, if packet has timestamp option enabled. */
if (p->tcpvars.ts != NULL) {
ssn->server.last_ts = TCP_GET_TSVAL(p);
SCLogDebug("ssn %p: p->tcpvars.ts %p, %02x", ssn, p->tcpvars.ts, ssn->server.last_ts);
if (ssn->server.last_ts == 0)
ssn->server.flags |= STREAMTCP_FLAG_ZERO_TIMESTAMP;
ssn->server.last_pkt_ts = p->ts.tv_sec;
ssn->server.flags |= STREAMTCP_FLAG_TIMESTAMP;
}
ssn->server.window = TCP_GET_WINDOW(p);
if (p->tcpvars.ws != NULL) {
ssn->flags |= STREAMTCP_FLAG_SERVER_WSCALE;
ssn->server.wscale = TCP_GET_WSCALE(p);
}
SCLogDebug("ssn %p: 4WHS ssn->server.isn %" PRIu32 ", ssn->server.next_seq %" PRIu32 ", ssn->server.last_ack %"PRIu32"",
ssn, ssn->server.isn, ssn->server.next_seq, ssn->server.last_ack);
SCLogDebug("ssn %p: 4WHS ssn->client.isn %" PRIu32 ", ssn->client.next_seq %" PRIu32 ", ssn->client.last_ack %"PRIu32"",
ssn, ssn->client.isn, ssn->client.next_seq, ssn->client.last_ack);
}
break;
case TH_SYN|TH_ACK:
if (ssn->flags & STREAMTCP_FLAG_4WHS) {
SCLogDebug("ssn %p: SYN/ACK received on 4WHS session", ssn);
/* Check if the SYN/ACK packet ack's the earlier
* received SYN packet. */
if (!(SEQ_EQ(TCP_GET_ACK(p), ssn->server.isn + 1))) {
SCLogDebug("ssn %p: 4WHS ACK mismatch, packet ACK %" PRIu32 " != %" PRIu32 " from stream",
ssn, TCP_GET_ACK(p), ssn->server.isn + 1);
return -1;
}
/* Check if the SYN/ACK packet SEQ's the *FIRST* received SYN packet. */
if (!(SEQ_EQ(TCP_GET_SEQ(p), ssn->client.isn))) {
SCLogDebug("ssn %p: 4WHS SEQ mismatch, packet SEQ %" PRIu32 " != %" PRIu32 " from *first* SYN pkt",
ssn, TCP_GET_SEQ(p), ssn->client.isn);
return -1;
}
/* update state */
StreamTcpPacketSetState(p, ssn, TCP_SYN_RECV);
SCLogDebug("ssn %p: =~ 4WHS ssn state is now TCP_SYN_RECV", ssn);
/* sequence number & window */
ssn->client.isn = TCP_GET_SEQ(p);
ssn->client.ra_base_seq = ssn->client.isn;
ssn->client.next_seq = ssn->client.isn + 1;
ssn->server.window = TCP_GET_WINDOW(p);
SCLogDebug("ssn %p: 4WHS window %" PRIu32 "", ssn, ssn->client.window);
/* Set the timestamp values used to validate the timestamp of received
packets. */
if ((p->tcpvars.ts != NULL) && (ssn->server.flags & STREAMTCP_FLAG_TIMESTAMP)) {
ssn->client.last_ts = TCP_GET_TSVAL(p);
SCLogDebug("ssn %p: 4WHS ssn->client.last_ts %" PRIu32" ssn->server.last_ts %" PRIu32"", ssn, ssn->client.last_ts, ssn->server.last_ts);
ssn->server.flags &= ~STREAMTCP_FLAG_TIMESTAMP;
ssn->flags |= STREAMTCP_FLAG_TIMESTAMP;
ssn->client.last_pkt_ts = p->ts.tv_sec;
if (ssn->client.last_ts == 0)
ssn->client.flags |= STREAMTCP_FLAG_ZERO_TIMESTAMP;
} else {
ssn->server.last_ts = 0;
ssn->client.last_ts = 0;
ssn->server.flags &= ~STREAMTCP_FLAG_TIMESTAMP;
ssn->server.flags &= ~STREAMTCP_FLAG_ZERO_TIMESTAMP;
}
ssn->server.last_ack = TCP_GET_ACK(p);
ssn->client.last_ack = ssn->client.isn + 1;
/** check for the presense of the ws ptr to determine if we
* support wscale at all */
if (ssn->flags & STREAMTCP_FLAG_SERVER_WSCALE && p->tcpvars.ws != NULL) {
ssn->server.wscale = TCP_GET_WSCALE(p);
} else {
ssn->server.wscale = 0;
}
ssn->client.next_win = ssn->client.last_ack + ssn->client.window;
ssn->server.next_win = ssn->server.last_ack + ssn->server.window;
SCLogDebug("ssn %p: 4WHS ssn->client.next_win %" PRIu32 "", ssn, ssn->client.next_win);
SCLogDebug("ssn %p: 4WHS ssn->server.next_win %" PRIu32 "", ssn, ssn->server.next_win);
SCLogDebug("ssn %p: 4WHS ssn->client.isn %" PRIu32 ", ssn->client.next_seq %" PRIu32 ", ssn->client.last_ack %" PRIu32 " (ssn->server.last_ack %" PRIu32 ")",
ssn, ssn->client.isn, ssn->client.next_seq, ssn->client.last_ack, ssn->server.last_ack);
/* done here */
break;
}
if (PKT_IS_TOSERVER(p)) {
SCLogDebug("ssn %p: SYN/ACK received in the wrong direction", ssn);
return -1;
@ -665,28 +790,64 @@ static int StreamTcpPacketStateSynRecv(ThreadVars *tv, Packet *p, StreamTcpThrea
break;
case TH_ACK:
case TH_ACK|TH_PUSH:
/* If the timestamp option is enabled for both the streams, then validate the received packet
timestamp value against the stream->last_ts. If the timestamp is valid then process the packet normally
otherwise the drop the packet (RFC 1323)*/
if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
if (!ValidTimestamp(ssn, p))
return -1;
}
if (ssn->flags & STREAMTCP_FLAG_4WHS) {
SCLogDebug("ssn %p: ACK received on 4WHS session",ssn);
if ((SEQ_EQ(TCP_GET_SEQ(p), ssn->server.next_seq))) {
SCLogDebug("4WHS normal pkt");
ssn->client.last_ack = TCP_GET_ACK(p);
ssn->server.next_seq += p->payload_len;
ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale;
ssn->client.next_win = ssn->client.last_ack + ssn->client.window;
/*If no stream reassembly/application layer protocol inspection, then simple return*/
if (!(ssn->flags & STREAMTCP_FLAG_NOSERVER_REASSEMBLY))
StreamTcpReassembleHandleSegment(stt->ra_ctx, ssn, &ssn->server, p);
} else {
SCLogDebug("ssn %p: 4WHS wrong seq nr on packet", ssn);
return -1;
}
SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ %" PRIu32 ", ACK %" PRIu32 "",
ssn, p->payload_len, TCP_GET_SEQ(p), TCP_GET_ACK(p));
StreamTcpPacketSetState(p, ssn, TCP_ESTABLISHED);
SCLogDebug("ssn %p: =~ ssn state is now TCP_ESTABLISHED", ssn);
SCLogDebug("ssn %p: ssn->client.next_win %" PRIu32 ", ssn->client.last_ack %"PRIu32"",
ssn, ssn->client.next_win, ssn->client.last_ack);
break;
}
/* Check if the ACK received is in right direction. But when we have
* picked up a mid stream session after missing the initial SYN pkt,
* in this case the ACK packet can arrive from either client (normal
* case) or from server itself (asynchronous streams). Therefore
* the check has been avoided in this case */
if (PKT_IS_TOCLIENT(p) &&
!(ssn->flags & STREAMTCP_FLAG_MIDSTREAM_SYNACK))
{
SCLogDebug("ssn %p: ACK received in the wrong direction\n",ssn);
return -1;
}
/* If the timestamp option is enabled for both the streams, then validate the received packet
timestamp value against the stream->last_ts. If the timestamp is valid then process the packet normally
otherwise the drop the packet (RFC 1323)*/
if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
if (!ValidTimestamp(ssn, p))
if (PKT_IS_TOCLIENT(p)) {
/* special case, handle 4WHS, so SYN/ACK in the opposite direction */
if (ssn->flags & STREAMTCP_FLAG_MIDSTREAM_SYNACK) {
SCLogDebug("ssn %p: ACK received on midstream SYN/ACK pickup session",ssn);
/* fall through */
} else {
SCLogDebug("ssn %p: ACK received in the wrong direction",ssn);
return -1;
}
}
if ((SEQ_EQ(TCP_GET_SEQ(p), ssn->client.next_seq))) {
SCLogDebug("normal pkt");
/* process the packet normal, No Async streams :) */
ssn->server.last_ack = TCP_GET_ACK(p);
@ -902,9 +1063,9 @@ static int HandleEstablishedPacketToServer(TcpSession *ssn, Packet *p,
if (!(ssn->flags & STREAMTCP_FLAG_NOCLIENT_REASSEMBLY))
StreamTcpReassembleHandleSegment(stt->ra_ctx, ssn, &ssn->client, p);
} else {
SCLogDebug("ssn %p: server => SEQ out of window, packet SEQ"
SCLogDebug("ssn %p: toserver => SEQ out of window, packet SEQ "
"%" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "),"
"ssn->client.last_ack %" PRIu32 ", ssn->client.next_win"
"ssn->client.last_ack %" PRIu32 ", ssn->client.next_win "
"%" PRIu32 "(%"PRIu32") (ssn->client.ra_base_seq %"PRIu32")",
ssn, TCP_GET_SEQ(p), p->payload_len, TCP_GET_SEQ(p)
+p->payload_len, ssn->client.last_ack, ssn->client.next_win,

Loading…
Cancel
Save