From: Victor Julien Date: Sat, 1 Sep 2018 16:54:40 +0000 (+0200) Subject: stream/tcp: support TCP fast open X-Git-Tag: suricata-5.0.0-rc1~143 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=bc2267f131b85e34a7513d7f1a3d708e4c3a8e6e;p=thirdparty%2Fsuricata.git stream/tcp: support TCP fast open --- diff --git a/src/stream-tcp-private.h b/src/stream-tcp-private.h index 2db9e17dcb..b6d2244cd8 100644 --- a/src/stream-tcp-private.h +++ b/src/stream-tcp-private.h @@ -186,6 +186,8 @@ enum #define STREAMTCP_FLAG_APP_LAYER_DISABLED 0x2000 /** Stream can be bypass */ #define STREAMTCP_FLAG_BYPASS 0x4000 +/** SSN uses TCP Fast Open */ +#define STREAMTCP_FLAG_TCP_FAST_OPEN 0x8000 /* * Per STREAM flags diff --git a/src/stream-tcp.c b/src/stream-tcp.c index b1bf2b890d..ddfeb4951a 100644 --- a/src/stream-tcp.c +++ b/src/stream-tcp.c @@ -1058,6 +1058,16 @@ static int StreamTcpPacketStateNone(ThreadVars *tv, Packet *p, SCLogDebug("ssn %p: SACK permited on SYN packet", ssn); } + if (TCP_HAS_TFO(p)) { + ssn->flags |= STREAMTCP_FLAG_TCP_FAST_OPEN; + if (p->payload_len) { + StreamTcpUpdateNextSeq(ssn, &ssn->client, (ssn->client.next_seq + p->payload_len)); + SCLogNotice("ssn: %p (TFO) [len: %d] isn %u base_seq %u next_seq %u payload len %u", + ssn, p->tcpvars.tfo.len, ssn->client.isn, ssn->client.base_seq, ssn->client.next_seq, p->payload_len); + StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p, pq); + } + } + SCLogDebug("ssn %p: ssn->client.isn %" PRIu32 ", " "ssn->client.next_seq %" PRIu32 ", ssn->client.last_ack " "%"PRIu32"", ssn, ssn->client.isn, ssn->client.next_seq, @@ -1504,16 +1514,31 @@ static int StreamTcpPacketStateSynSent(ThreadVars *tv, Packet *p, return -1; } - /* Check if the SYN/ACK packet ack's the earlier - * received SYN packet. */ - if (!(SEQ_EQ(TCP_GET_ACK(p), ssn->client.isn + 1))) { - StreamTcpSetEvent(p, STREAM_3WHS_SYNACK_WITH_WRONG_ACK); - SCLogDebug("ssn %p: ACK mismatch, packet ACK %" PRIu32 " != " + if (!(TCP_HAS_TFO(p) || (ssn->flags & STREAMTCP_FLAG_TCP_FAST_OPEN))) { + /* Check if the SYN/ACK packet ack's the earlier + * received SYN packet. */ + if (!(SEQ_EQ(TCP_GET_ACK(p), ssn->client.isn + 1))) { + StreamTcpSetEvent(p, STREAM_3WHS_SYNACK_WITH_WRONG_ACK); + SCLogDebug("ssn %p: ACK mismatch, packet ACK %" PRIu32 " != " + "%" PRIu32 " from stream", ssn, TCP_GET_ACK(p), + ssn->client.isn + 1); + return -1; + } + } else { + if (!(SEQ_EQ(TCP_GET_ACK(p), ssn->client.next_seq))) { + StreamTcpSetEvent(p, STREAM_3WHS_SYNACK_WITH_WRONG_ACK); + SCLogDebug("ssn %p: (TFO) ACK mismatch, packet ACK %" PRIu32 " != " + "%" PRIu32 " from stream", ssn, TCP_GET_ACK(p), + ssn->client.next_seq); + return -1; + } + SCLogDebug("ssn %p: (TFO) ACK match, packet ACK %" PRIu32 " == " "%" PRIu32 " from stream", ssn, TCP_GET_ACK(p), - ssn->client.isn + 1); - return -1; - } + ssn->client.next_seq); + ssn->flags |= STREAMTCP_FLAG_TCP_FAST_OPEN; + StreamTcpPacketSetState(p, ssn, TCP_ESTABLISHED); + } StreamTcp3whsSynAckUpdate(ssn, p, /* no queue override */NULL); } else if (p->tcph->th_flags & TH_SYN) { @@ -1857,6 +1882,9 @@ static int StreamTcpPacketStateSynRecv(ThreadVars *tv, Packet *p, SCLogDebug("ssn %p: ACK received on midstream SYN/ACK " "pickup session",ssn); /* fall through */ + } else if (ssn->flags & STREAMTCP_FLAG_TCP_FAST_OPEN) { + SCLogDebug("ssn %p: ACK received on TFO session",ssn); + /* fall through */ } else { /* if we missed traffic between the S/SA and the current @@ -2019,11 +2047,16 @@ static int StreamTcpPacketStateSynRecv(ThreadVars *tv, Packet *p, &ssn->client, p, pq); /* toclient packet: after having missed the 3whs's final ACK */ - } else if (ack_indicates_missed_3whs_ack_packet && + } else if ((ack_indicates_missed_3whs_ack_packet || + (ssn->flags & STREAMTCP_FLAG_TCP_FAST_OPEN)) && SEQ_EQ(TCP_GET_ACK(p), ssn->client.last_ack) && SEQ_EQ(TCP_GET_SEQ(p), ssn->server.next_seq)) { - SCLogDebug("ssn %p: packet fits perfectly after a missed 3whs-ACK", ssn); + if (ack_indicates_missed_3whs_ack_packet) { + SCLogDebug("ssn %p: packet fits perfectly after a missed 3whs-ACK", ssn); + } else { + SCLogDebug("ssn %p: (TFO) expected packet fits perfectly after SYN/ACK", ssn); + } StreamTcpUpdateNextSeq(ssn, &ssn->server, (TCP_GET_SEQ(p) + p->payload_len));