]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
tcp reuse: support reuse on syn/ack
authorVictor Julien <victor@inliniac.net>
Mon, 9 Feb 2015 15:44:11 +0000 (16:44 +0100)
committerVictor Julien <victor@inliniac.net>
Wed, 18 Feb 2015 08:18:43 +0000 (09:18 +0100)
Support TCP reuse on SYN/ACK. Only effective if midstream and/or
async-oneside options are enabled.

src/stream-tcp.c

index 46359a4614f752cdcd63b5db6fcdaa526da08d78..97e717e297f42a13407bf7b790902d5d01bfe832 100644 (file)
@@ -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) {