diff --git a/src/stream-tcp.c b/src/stream-tcp.c index 46359a4614..97e717e297 100644 --- a/src/stream-tcp.c +++ b/src/stream-tcp.c @@ -4680,21 +4680,24 @@ static inline int StreamTcpValidateChecksum(Packet *p) * \retval bool true/false */ static int TcpSessionPacketIsStreamStarter(const Packet *p) { - uint8_t flag = TH_SYN; - - //SCLogInfo("Want: %02x, have %02x", flag, p->tcph->th_flags); - - if (p->tcph->th_flags == flag) { + if (p->tcph->th_flags == TH_SYN) { SCLogDebug("packet %"PRIu64" is a stream starter: %02x", p->pcap_cnt, p->tcph->th_flags); return 1; } + + if (stream_config.midstream == TRUE || stream_config.async_oneside == TRUE) { + if (p->tcph->th_flags == (TH_SYN|TH_ACK)) { + SCLogDebug("packet %"PRIu64" is a midstream stream starter: %02x", p->pcap_cnt, p->tcph->th_flags); + return 1; + } + } return 0; } /** \internal * \brief Check if Flow and TCP SSN allow this flow/tuple to be reused * \retval bool true yes reuse, false no keep tracking old ssn */ -int TcpSessionReuseDoneEnough(const Packet *p, const Flow *f, const TcpSession *ssn) +static int TcpSessionReuseDoneEnoughSyn(const Packet *p, const Flow *f, const TcpSession *ssn) { if (FlowGetPacketDirection(f, p) == TOSERVER) { if (ssn == NULL) { @@ -4741,6 +4744,77 @@ int TcpSessionReuseDoneEnough(const Packet *p, const Flow *f, const TcpSession * return 0; } +/** \internal + * \brief check if ssn is done enough for reuse by syn/ack + * \note should only be called if midstream is enabled + */ +static int TcpSessionReuseDoneEnoughSynAck(const Packet *p, const Flow *f, const TcpSession *ssn) +{ + if (FlowGetPacketDirection(f, p) == TOCLIENT) { + if (ssn == NULL) { + SCLogDebug("steam starter packet %"PRIu64", ssn %p null. No reuse.", p->pcap_cnt, ssn); + return 0; + } + if (SEQ_EQ(ssn->server.isn, TCP_GET_SEQ(p))) { + SCLogDebug("steam starter packet %"PRIu64", ssn %p. Packet SEQ == Stream ISN. Retransmission. Don't reuse.", p->pcap_cnt, ssn); + return 0; + } + if (ssn->state >= TCP_LAST_ACK) { + SCLogDebug("steam starter packet %"PRIu64", ssn %p state >= TCP_LAST_ACK (%u). Reuse.", p->pcap_cnt, ssn, ssn->state); + return 1; + } + if (ssn->state == TCP_NONE) { + SCLogDebug("steam starter packet %"PRIu64", ssn %p state == TCP_NONE (%u). Reuse.", p->pcap_cnt, ssn, ssn->state); + return 1; + } + if (ssn->state < TCP_LAST_ACK) { + SCLogDebug("steam starter packet %"PRIu64", ssn %p state < TCP_LAST_ACK (%u). Don't reuse.", p->pcap_cnt, ssn, ssn->state); + return 0; + } + + } else { + if (ssn == NULL) { + SCLogDebug("steam starter packet %"PRIu64", ssn %p null. Reuse.", p->pcap_cnt, ssn); + return 1; + } + if (ssn->state >= TCP_LAST_ACK) { + SCLogDebug("steam starter packet %"PRIu64", ssn %p state >= TCP_LAST_ACK (%u). Reuse.", p->pcap_cnt, ssn, ssn->state); + return 1; + } + if (ssn->state == TCP_NONE) { + SCLogDebug("steam starter packet %"PRIu64", ssn %p state == TCP_NONE (%u). Reuse.", p->pcap_cnt, ssn, ssn->state); + return 1; + } + if (ssn->state < TCP_LAST_ACK) { + SCLogDebug("steam starter packet %"PRIu64", ssn %p state < TCP_LAST_ACK (%u). Don't reuse.", p->pcap_cnt, ssn, ssn->state); + return 0; + } + } + + SCLogDebug("default: how did we get here?"); + return 0; +} + +/** \brief Check if SSN is done enough for reuse + * + * Reuse means a new TCP session reuses the tuple (flow in suri) + * + * \retval bool true if ssn can be reused, false if not */ +int TcpSessionReuseDoneEnough(const Packet *p, const Flow *f, const TcpSession *ssn) +{ + if (p->tcph->th_flags == TH_SYN) { + return TcpSessionReuseDoneEnoughSyn(p, f, ssn); + } + + if (stream_config.midstream == TRUE || stream_config.async_oneside == TRUE) { + if (p->tcph->th_flags == (TH_SYN|TH_ACK)) { + return TcpSessionReuseDoneEnoughSynAck(p, f, ssn); + } + } + + return 0; +} + int TcpSessionPacketSsnReuse(const Packet *p, const Flow *f, const void *tcp_ssn) { if (p->proto == IPPROTO_TCP && p->tcph != NULL) {