From: Philippe Antoine Date: Mon, 26 Dec 2022 10:56:18 +0000 (+0100) Subject: tcp: pick up a midstream session even with FIN flag X-Git-Tag: suricata-7.0.0-rc2~579 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=3365ef72c3e45616b233cb01e73144971a7d09a7;p=thirdparty%2Fsuricata.git tcp: pick up a midstream session even with FIN flag Ticket: #5437 --- diff --git a/src/stream-tcp.c b/src/stream-tcp.c index e4c61dbd26..5e84ff6d27 100644 --- a/src/stream-tcp.c +++ b/src/stream-tcp.c @@ -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);