]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
tcp: pick up a midstream session even with FIN flag
authorPhilippe Antoine <pantoine@oisf.net>
Mon, 26 Dec 2022 10:56:18 +0000 (11:56 +0100)
committerVictor Julien <vjulien@oisf.net>
Fri, 10 Feb 2023 17:04:20 +0000 (18:04 +0100)
Ticket: #5437

src/stream-tcp.c

index e4c61dbd26254f7533f70594334ab0b0417f3198..5e84ff6d27f2fe11f597372442db17bc4c70f039 100644 (file)
@@ -935,11 +935,102 @@ static int StreamTcpPacketStateNone(ThreadVars *tv, Packet *p,
         return -1;
 
     } else if (p->tcph->th_flags & TH_FIN) {
-        StreamTcpSetEvent(p, STREAM_FIN_BUT_NO_SESSION);
-        SCLogDebug("FIN packet received, no session setup");
-        return -1;
+        /* Drop reason will only be used if midstream policy is set to fail closed */
+        ExceptionPolicyApply(p, stream_config.midstream_policy, PKT_DROP_REASON_STREAM_MIDSTREAM);
 
-    /* SYN/ACK */
+        if (!stream_config.midstream || p->payload_len == 0) {
+            StreamTcpSetEvent(p, STREAM_FIN_BUT_NO_SESSION);
+            SCLogDebug("FIN packet received, no session setup");
+            return -1;
+        }
+        if (!(stream_config.midstream_policy == EXCEPTION_POLICY_NOT_SET ||
+                    stream_config.midstream_policy == EXCEPTION_POLICY_PASS_FLOW ||
+                    stream_config.midstream_policy == EXCEPTION_POLICY_PASS_PACKET)) {
+            StreamTcpSetEvent(p, STREAM_FIN_BUT_NO_SESSION);
+            SCLogDebug("FIN packet received, no session setup");
+            return -1;
+        }
+        SCLogDebug("midstream picked up");
+
+        if (ssn == NULL) {
+            ssn = StreamTcpNewSession(tv, stt, p, stt->ssn_pool_id);
+            if (ssn == NULL) {
+                StatsIncr(tv, stt->counter_tcp_ssn_memcap);
+                return -1;
+            }
+            StatsIncr(tv, stt->counter_tcp_sessions);
+            StatsIncr(tv, stt->counter_tcp_active_sessions);
+            StatsIncr(tv, stt->counter_tcp_midstream_pickups);
+        }
+        /* set the state */
+        StreamTcpPacketSetState(p, ssn, TCP_FIN_WAIT1);
+        SCLogDebug("ssn %p: =~ midstream picked ssn state is now "
+                   "TCP_FIN_WAIT1",
+                ssn);
+
+        ssn->flags = STREAMTCP_FLAG_MIDSTREAM;
+        ssn->flags |= STREAMTCP_FLAG_MIDSTREAM_ESTABLISHED;
+        if (stream_config.async_oneside) {
+            SCLogDebug("ssn %p: =~ ASYNC", ssn);
+            ssn->flags |= STREAMTCP_FLAG_ASYNC;
+        }
+
+        /** window scaling for midstream pickups, we can't do much other
+         *  than assume that it's set to the max value: 14 */
+        ssn->client.wscale = TCP_WSCALE_MAX;
+        ssn->server.wscale = TCP_WSCALE_MAX;
+
+        /* set the sequence numbers and window */
+        ssn->client.isn = TCP_GET_SEQ(p) - 1;
+        STREAMTCP_SET_RA_BASE_SEQ(&ssn->client, ssn->client.isn);
+        ssn->client.next_seq = TCP_GET_SEQ(p) + p->payload_len;
+        ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale;
+        ssn->client.last_ack = TCP_GET_SEQ(p);
+        ssn->client.next_win = ssn->client.last_ack + ssn->client.window;
+        SCLogDebug("ssn %p: ssn->client.isn %u, ssn->client.next_seq %u", ssn, ssn->client.isn,
+                ssn->client.next_seq);
+
+        ssn->server.isn = TCP_GET_ACK(p) - 1;
+        STREAMTCP_SET_RA_BASE_SEQ(&ssn->server, ssn->server.isn);
+        ssn->server.next_seq = ssn->server.isn + 1;
+        ssn->server.last_ack = TCP_GET_ACK(p);
+        ssn->server.next_win = ssn->server.last_ack;
+
+        SCLogDebug("ssn %p: ssn->client.next_win %" PRIu32 ", "
+                   "ssn->server.next_win %" PRIu32 "",
+                ssn, ssn->client.next_win, ssn->server.next_win);
+        SCLogDebug("ssn %p: ssn->client.last_ack %" PRIu32 ", "
+                   "ssn->server.last_ack %" PRIu32 "",
+                ssn, ssn->client.last_ack, ssn->server.last_ack);
+
+        /* Set the timestamp value for both streams, if packet has timestamp
+         * option enabled.*/
+        if (TCP_HAS_TS(p)) {
+            ssn->client.last_ts = TCP_GET_TSVAL(p);
+            ssn->server.last_ts = TCP_GET_TSECR(p);
+            SCLogDebug("ssn %p: ssn->server.last_ts %" PRIu32 " "
+                       "ssn->client.last_ts %" PRIu32 "",
+                    ssn, ssn->server.last_ts, ssn->client.last_ts);
+
+            ssn->flags |= STREAMTCP_FLAG_TIMESTAMP;
+
+            ssn->client.last_pkt_ts = SCTIME_SECS(p->ts);
+            if (ssn->server.last_ts == 0)
+                ssn->server.flags |= STREAMTCP_STREAM_FLAG_ZERO_TIMESTAMP;
+            if (ssn->client.last_ts == 0)
+                ssn->client.flags |= STREAMTCP_STREAM_FLAG_ZERO_TIMESTAMP;
+
+        } else {
+            ssn->server.last_ts = 0;
+            ssn->client.last_ts = 0;
+        }
+
+        StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p, pq);
+
+        ssn->flags |= STREAMTCP_FLAG_SACKOK;
+        SCLogDebug("ssn %p: assuming SACK permitted for both sides", ssn);
+
+        /* SYN/ACK */
     } else if ((p->tcph->th_flags & (TH_SYN | TH_ACK)) == (TH_SYN | TH_ACK)) {
         /* Drop reason will only be used if midstream policy is set to fail closed */
         ExceptionPolicyApply(p, stream_config.midstream_policy, PKT_DROP_REASON_STREAM_MIDSTREAM);