From: Russ Combs (rucombs) Date: Thu, 12 Jan 2023 13:22:00 +0000 (+0000) Subject: Pull request #3714: Event driven fw X-Git-Tag: 3.1.52.0~7 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=45606de7d720e8da0f15e4d7adfc5b98b5368489;p=thirdparty%2Fsnort3.git Pull request #3714: Event driven fw Merge in SNORT/snort3 from ~RDEMPSTE/snort3:event_driven_fw to master Squashed commit of the following: commit 8c782e76e24166ec8f7fec99f7a532816c238fb3 Author: Ron Dempster (rdempste) Date: Fri Jan 6 15:28:48 2023 -0500 stream: fix iss and irs and mid-stream sent post processing commit e4b5df660ddb2422335e26b9aa8b4dd99574c8ad Author: Ron Dempster (rdempste) Date: Tue Dec 13 19:19:05 2022 -0500 stream: refactor tcp state machine to handle mid-stream flow and more established cases commit 239472e8bf5924932871e9443581ef12eb23f471 Author: Ron Dempster (rdempste) Date: Tue Dec 13 19:17:49 2022 -0500 flow: update flow creation to exclude non-syn packets with no payload --- diff --git a/src/flow/flow.cc b/src/flow/flow.cc index f5e7a070b..1353e7084 100644 --- a/src/flow/flow.cc +++ b/src/flow/flow.cc @@ -408,9 +408,9 @@ void Flow::markup_packet_flags(Packet* p) { p->packet_flags |= PKT_STREAM_UNEST_UNI; } - if ( (ssn_state.session_flags & SSNFLAG_TCP_ONE_SIDED) == SSNFLAG_TCP_ONE_SIDED ) + if ( (ssn_state.session_flags & SSNFLAG_TCP_PSEUDO_EST) == SSNFLAG_TCP_PSEUDO_EST ) { - p->packet_flags |= PKT_TCP_ONE_SIDED; + p->packet_flags |= PKT_TCP_PSEUDO_EST; } } else diff --git a/src/flow/flow.h b/src/flow/flow.h index f1cf13808..eec263120 100644 --- a/src/flow/flow.h +++ b/src/flow/flow.h @@ -66,7 +66,7 @@ #define SSNFLAG_PRUNED 0x00002000 #define SSNFLAG_RESET 0x00004000 -#define SSNFLAG_TCP_ONE_SIDED 0x00008000 +#define SSNFLAG_TCP_PSEUDO_EST 0x00008000 #define SSNFLAG_DROP_CLIENT 0x00010000 #define SSNFLAG_DROP_SERVER 0x00020000 @@ -91,18 +91,15 @@ #define SSNFLAG_BLOCK (SSNFLAG_DROP_CLIENT|SSNFLAG_DROP_SERVER) #define STREAM_STATE_NONE 0x0000 -#define STREAM_STATE_SYN 0x0001 -#define STREAM_STATE_SYN_ACK 0x0002 -#define STREAM_STATE_ACK 0x0004 -#define STREAM_STATE_ESTABLISHED 0x0008 -#define STREAM_STATE_DROP_CLIENT 0x0010 -#define STREAM_STATE_DROP_SERVER 0x0020 -#define STREAM_STATE_MIDSTREAM 0x0040 -#define STREAM_STATE_TIMEDOUT 0x0080 -#define STREAM_STATE_UNREACH 0x0100 -#define STREAM_STATE_CLOSED 0x0200 -#define STREAM_STATE_BLOCK_PENDING 0x0400 -#define STREAM_STATE_RELEASING 0x0800 +#define STREAM_STATE_ESTABLISHED 0x0001 +#define STREAM_STATE_DROP_CLIENT 0x0002 +#define STREAM_STATE_DROP_SERVER 0x0004 +#define STREAM_STATE_MIDSTREAM 0x0008 +#define STREAM_STATE_TIMEDOUT 0x0010 +#define STREAM_STATE_UNREACH 0x0020 +#define STREAM_STATE_CLOSED 0x0040 +#define STREAM_STATE_BLOCK_PENDING 0x0080 +#define STREAM_STATE_RELEASING 0x0100 class Continuation; class BitOp; diff --git a/src/flow/flow_control.cc b/src/flow/flow_control.cc index 294545039..41beb7d0d 100644 --- a/src/flow/flow_control.cc +++ b/src/flow/flow_control.cc @@ -362,13 +362,17 @@ static bool want_flow(PktType type, Packet* p) // guessing direction based on ports is misleading return false; - if ( !p->ptrs.tcph->is_syn_only() or p->context->conf->track_on_syn() ) + if ( p->ptrs.tcph->is_syn_ack() or p->dsize ) return true; - const unsigned DECODE_TCP_HS = DECODE_TCP_MSS | DECODE_TCP_TS | DECODE_TCP_WS; - - if ( (p->ptrs.decode_flags & DECODE_TCP_HS) or p->dsize ) - return true; + if ( p->ptrs.tcph->is_syn_only() ) + { + if ( p->context->conf->track_on_syn() ) + return true; + const unsigned DECODE_TCP_HS = DECODE_TCP_MSS | DECODE_TCP_TS | DECODE_TCP_WS; + if ( p->ptrs.decode_flags & DECODE_TCP_HS ) + return true; + } p->packet_flags |= PKT_FROM_CLIENT; return false; diff --git a/src/network_inspectors/binder/bind_module.cc b/src/network_inspectors/binder/bind_module.cc index af79d5952..3bbe42f57 100644 --- a/src/network_inspectors/binder/bind_module.cc +++ b/src/network_inspectors/binder/bind_module.cc @@ -145,9 +145,6 @@ static const Parameter binder_use_params[] = { "file", Parameter::PT_STRING, nullptr, nullptr, "use configuration in given file" }, - { "network_policy", Parameter::PT_STRING, nullptr, nullptr, - "use network policy from given file" }, - { "inspection_policy", Parameter::PT_STRING, nullptr, nullptr, "use inspection policy from given file" }, diff --git a/src/protocols/packet.h b/src/protocols/packet.h index 134ce4714..d2bf1a2f4 100644 --- a/src/protocols/packet.h +++ b/src/protocols/packet.h @@ -83,7 +83,7 @@ class SFDAQInstance; #define PKT_MORE_TO_FLUSH 0x20000000 // when more data is available to StreamSplitter::scan #define PKT_FAST_PAT_EVAL 0x40000000 // temporary until IpsOption api updated -#define PKT_TCP_ONE_SIDED 0x80000000 // A one-sided TCP session was detected +#define PKT_TCP_PSEUDO_EST 0x80000000 // A one-sided or bidirectional without LWS TCP session was detected #define TS_PKT_OFFLOADED 0x01 diff --git a/src/stream/tcp/CMakeLists.txt b/src/stream/tcp/CMakeLists.txt index 0380349e6..fe7dec693 100644 --- a/src/stream/tcp/CMakeLists.txt +++ b/src/stream/tcp/CMakeLists.txt @@ -52,6 +52,10 @@ add_library( stream_tcp OBJECT tcp_state_listen.h tcp_state_machine.cc tcp_state_machine.h + tcp_state_mid_stream_recv.cc + tcp_state_mid_stream_recv.h + tcp_state_mid_stream_sent.cc + tcp_state_mid_stream_sent.h tcp_state_none.cc tcp_state_none.h tcp_state_syn_recv.cc diff --git a/src/stream/tcp/tcp_event_logger.cc b/src/stream/tcp/tcp_event_logger.cc index 506e842d7..203fdb3d0 100644 --- a/src/stream/tcp/tcp_event_logger.cc +++ b/src/stream/tcp/tcp_event_logger.cc @@ -90,7 +90,8 @@ void TcpEventLogger::log_tcp_events() { DetectionEngine::queue_event(GID_STREAM_TCP, tcp_event_sids[idx].sid); if ( PacketTracer::is_active() ) - PacketTracer::log("Stream: TCP normalization error in %s\n", + PacketTracer::log("Stream: TCP raised %u:%u %s\n", + GID_STREAM_TCP, tcp_event_sids[idx].sid, tcp_event_sids[idx].event_description); tcp_events ^= tcp_event_sids[idx].event_id; tcpStats.events++; diff --git a/src/stream/tcp/tcp_ha.cc b/src/stream/tcp/tcp_ha.cc index 472d8e14b..b6d27fd7b 100644 --- a/src/stream/tcp/tcp_ha.cc +++ b/src/stream/tcp/tcp_ha.cc @@ -53,8 +53,7 @@ void TcpHA::deactivate_session(Flow* flow) ((TcpSession*)(flow->session))->clear_session(true, false, false); } - flow->clear_session_state(STREAM_STATE_SYN | STREAM_STATE_SYN_ACK | - STREAM_STATE_ACK | STREAM_STATE_ESTABLISHED); + flow->clear_session_state(STREAM_STATE_ESTABLISHED); assert( flow->ha_state ); flow->clear_session_flags( SSNFLAG_SEEN_CLIENT | SSNFLAG_SEEN_SERVER ); diff --git a/src/stream/tcp/tcp_session.cc b/src/stream/tcp/tcp_session.cc index 564874526..def8e0458 100644 --- a/src/stream/tcp/tcp_session.cc +++ b/src/stream/tcp/tcp_session.cc @@ -608,7 +608,6 @@ bool TcpSession::handle_syn_on_reset_session(TcpSegmentDescriptor& tsd) else if ( tcph->is_syn_only() ) { flow->ssn_state.direction = FROM_CLIENT; - flow->session_state = STREAM_STATE_SYN; flow->set_ttl(tsd.get_pkt(), true); init_session_on_syn(tsd); tcpStats.resyns++; @@ -620,7 +619,6 @@ bool TcpSession::handle_syn_on_reset_session(TcpSegmentDescriptor& tsd) if ( tcp_config->midstream_allowed(tsd.get_pkt()) ) { flow->ssn_state.direction = FROM_SERVER; - flow->session_state = STREAM_STATE_SYN_ACK; flow->set_ttl(tsd.get_pkt(), false); init_session_on_synack(tsd); tcpStats.resyns++; diff --git a/src/stream/tcp/tcp_state_established.cc b/src/stream/tcp/tcp_state_established.cc index 3e952704a..0158abc5a 100644 --- a/src/stream/tcp/tcp_state_established.cc +++ b/src/stream/tcp/tcp_state_established.cc @@ -28,6 +28,8 @@ #include "tcp_normalizers.h" #include "tcp_session.h" +using namespace snort; + TcpStateEstablished::TcpStateEstablished(TcpStateMachine& tsm) : TcpStateHandler(TcpStreamTracker::TCP_ESTABLISHED, tsm) { } @@ -54,7 +56,13 @@ bool TcpStateEstablished::syn_ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTrack // not be initialized... update_tracker_ack_sent may fix that but needs // more testing //trk.update_tracker_ack_sent( tsd ); - trk.session->update_session_on_syn_ack(); + Flow* flow = tsd.get_flow(); + if ( !(flow->session_state & STREAM_STATE_ESTABLISHED) ) + { + /* SYN-ACK from server */ + if (flow->session_state != STREAM_STATE_NONE) + trk.session->update_perf_base_state(TcpStreamTracker::TCP_ESTABLISHED); + } } if ( trk.is_server_tracker() ) diff --git a/src/stream/tcp/tcp_state_listen.cc b/src/stream/tcp/tcp_state_listen.cc index 49b047c80..53d9e9650 100644 --- a/src/stream/tcp/tcp_state_listen.cc +++ b/src/stream/tcp/tcp_state_listen.cc @@ -38,16 +38,6 @@ TcpStateListen::TcpStateListen(TcpStateMachine& tsm) : { } -bool TcpStateListen::syn_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) -{ - if ( trk.session->tcp_config->require_3whs() || tsd.has_wscale() || tsd.is_data_segment() ) - { - if ( tsd.is_packet_from_server() ) - trk.session->tel.set_tcp_event(EVENT_4WHS); - } - return true; -} - bool TcpStateListen::syn_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) { trk.init_on_syn_recv(tsd); @@ -60,9 +50,6 @@ bool TcpStateListen::syn_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) bool TcpStateListen::syn_ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) { - Flow* flow = tsd.get_flow(); - flow->session_state |= ( STREAM_STATE_SYN | STREAM_STATE_SYN_ACK ); - if ( trk.session->is_midstream_allowed(tsd) ) { trk.init_on_synack_sent(tsd); @@ -77,56 +64,9 @@ bool TcpStateListen::syn_ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& t return true; } -bool TcpStateListen::syn_ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) -{ - if ( !trk.session->tcp_config->require_3whs() or trk.session->is_midstream_allowed(tsd) ) - { - trk.init_on_synack_recv(tsd); - if ( tsd.is_data_segment() ) - trk.session->handle_data_segment(tsd); - } - else if ( trk.session->tcp_config->require_3whs() ) - { - trk.session->generate_no_3whs_event(); - return false; - } - return true; -} - -bool TcpStateListen::ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) -{ - if ( trk.session->tcp_config->midstream_allowed(tsd.get_pkt()) && tsd.has_wscale() ) - { - Flow* flow = tsd.get_flow(); - flow->session_state |= ( STREAM_STATE_ACK | STREAM_STATE_SYN_ACK | - STREAM_STATE_ESTABLISHED ); - - trk.init_on_3whs_ack_sent(tsd); - trk.session->init_new_tcp_session(tsd); - trk.session->update_perf_base_state(TcpStreamTracker::TCP_ESTABLISHED); - } - else if ( trk.session->tcp_config->require_3whs() ) - { - trk.session->generate_no_3whs_event(); - return false; - } - return true; -} - -bool TcpStateListen::ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) +bool TcpStateListen::ack_sent(TcpSegmentDescriptor&, TcpStreamTracker& trk) { - if ( trk.session->is_midstream_allowed(tsd) && tsd.has_wscale() ) - { - Flow* flow = tsd.get_flow(); - - if ( !tsd.get_tcph()->is_rst() && ( flow->session_state & STREAM_STATE_SYN_ACK) ) - { - trk.init_on_3whs_ack_recv(tsd); - trk.normalizer.ecn_tracker( - tsd.get_tcph(), trk.session->tcp_config->require_3whs()); - } - } - else if ( trk.session->tcp_config->require_3whs() ) + if ( trk.session->tcp_config->require_3whs() ) { trk.session->generate_no_3whs_event(); return false; @@ -149,9 +89,6 @@ bool TcpStateListen::data_seg_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk.init_on_data_seg_sent(tsd); trk.session->init_new_tcp_session(tsd); - - if ( flow->session_state & STREAM_STATE_ESTABLISHED ) - trk.session->update_perf_base_state(TcpStreamTracker::TCP_ESTABLISHED); } else if ( trk.session->tcp_config->require_3whs() ) { @@ -166,13 +103,7 @@ bool TcpStateListen::data_seg_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& if ( trk.session->is_midstream_allowed(tsd) ) { Flow* flow = tsd.get_flow(); - flow->session_state |= STREAM_STATE_MIDSTREAM; - if ( !Stream::is_midstream(flow) ) - { - flow->set_session_flags(SSNFLAG_MIDSTREAM); - DataBus::publish(Stream::get_pub_id(), StreamEventIds::TCP_MIDSTREAM, tsd.get_pkt()); - } trk.init_on_data_seg_recv(tsd); trk.normalizer.ecn_tracker(tsd.get_tcph(), trk.session->tcp_config->require_3whs()); trk.session->handle_data_segment(tsd); diff --git a/src/stream/tcp/tcp_state_listen.h b/src/stream/tcp/tcp_state_listen.h index 0575e8ff8..f9883bb26 100644 --- a/src/stream/tcp/tcp_state_listen.h +++ b/src/stream/tcp/tcp_state_listen.h @@ -29,12 +29,9 @@ class TcpStateListen : public TcpStateHandler public: TcpStateListen(TcpStateMachine&); - bool syn_sent(TcpSegmentDescriptor&, TcpStreamTracker&) override; bool syn_recv(TcpSegmentDescriptor&, TcpStreamTracker&) override; bool syn_ack_sent(TcpSegmentDescriptor&, TcpStreamTracker&) override; - bool syn_ack_recv(TcpSegmentDescriptor&, TcpStreamTracker&) override; bool ack_sent(TcpSegmentDescriptor&, TcpStreamTracker&) override; - bool ack_recv(TcpSegmentDescriptor&, TcpStreamTracker&) override; bool data_seg_sent(TcpSegmentDescriptor&, TcpStreamTracker&) override; bool data_seg_recv(TcpSegmentDescriptor&, TcpStreamTracker&) override; bool fin_sent(TcpSegmentDescriptor&, TcpStreamTracker&) override; diff --git a/src/stream/tcp/tcp_state_machine.cc b/src/stream/tcp/tcp_state_machine.cc index a7432e5a6..936a801ac 100644 --- a/src/stream/tcp/tcp_state_machine.cc +++ b/src/stream/tcp/tcp_state_machine.cc @@ -25,11 +25,14 @@ #include "tcp_state_machine.h" +#include "tcp_session.h" #include "tcp_state_none.h" #include "tcp_state_closed.h" #include "tcp_state_listen.h" #include "tcp_state_syn_sent.h" #include "tcp_state_syn_recv.h" +#include "tcp_state_mid_stream_sent.h" +#include "tcp_state_mid_stream_recv.h" #include "tcp_state_established.h" #include "tcp_state_close_wait.h" #include "tcp_state_closing.h" @@ -64,6 +67,8 @@ TcpStateMachine::TcpStateMachine() new TcpStateListen(*this); new TcpStateSynSent(*this); new TcpStateSynRecv(*this); + new TcpStateMidStreamSent(*this); + new TcpStateMidStreamRecv(*this); new TcpStateEstablished(*this); new TcpStateFinWait1(*this); new TcpStateFinWait2(*this); @@ -103,6 +108,8 @@ bool TcpStateMachine::eval(TcpSegmentDescriptor& tsd) tcp_state_handlers[ listener_state ]->do_post_sm_packet_actions(tsd, *listener); return true; } + else + talker->session->check_for_pseudo_established(tsd.get_pkt()); return false; } diff --git a/src/stream/tcp/tcp_state_mid_stream_recv.cc b/src/stream/tcp/tcp_state_mid_stream_recv.cc new file mode 100644 index 000000000..887133804 --- /dev/null +++ b/src/stream/tcp/tcp_state_mid_stream_recv.cc @@ -0,0 +1,140 @@ +//-------------------------------------------------------------------------- +// Copyright (C) 2022-2022 Cisco and/or its affiliates. All rights reserved. +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License Version 2 as published +// by the Free Software Foundation. You may not use, modify or distribute +// this program under any other version of the GNU General Public License. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +//-------------------------------------------------------------------------- + +// tcp_state_mid_stream_recv.cc author Ron Dempster +// Created on: Dec 7, 2022 + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "tcp_state_mid_stream_recv.h" + +#include "tcp_normalizers.h" +#include "tcp_session.h" + +using namespace snort; + +TcpStateMidStreamRecv::TcpStateMidStreamRecv(TcpStateMachine& tsm) : + TcpStateHandler(TcpStreamTracker::TCP_MID_STREAM_RECV, tsm) +{ +} + +bool TcpStateMidStreamRecv::syn_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) +{ + trk.session->check_for_repeated_syn(tsd); + trk.set_tcp_state(TcpStreamTracker::TCP_ESTABLISHED); + return true; +} + +bool TcpStateMidStreamRecv::syn_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) +{ + trk.session->check_for_repeated_syn(tsd); + trk.normalizer.ecn_tracker(tsd.get_tcph(), trk.session->tcp_config->require_3whs()); + return true; +} + +bool TcpStateMidStreamRecv::syn_ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) +{ + trk.session->check_for_repeated_syn(tsd); + trk.set_tcp_state(TcpStreamTracker::TCP_ESTABLISHED); + return true; +} + +bool TcpStateMidStreamRecv::ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) +{ + trk.update_tracker_ack_sent(tsd); + trk.set_tcp_state(TcpStreamTracker::TCP_ESTABLISHED); + return true; +} + +bool TcpStateMidStreamRecv::ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) +{ + trk.update_tracker_ack_recv(tsd); + return true; +} + +bool TcpStateMidStreamRecv::data_seg_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) +{ + trk.update_tracker_ack_sent(tsd); + trk.set_tcp_state(TcpStreamTracker::TCP_ESTABLISHED); + if ( trk.session->no_ack_mode_enabled() ) + trk.update_tracker_no_ack_recv(tsd); + return true; +} + +bool TcpStateMidStreamRecv::data_seg_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) +{ + trk.update_tracker_ack_recv(tsd); + trk.session->handle_data_segment(tsd); + return true; +} + +bool TcpStateMidStreamRecv::fin_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) +{ + trk.update_on_fin_sent(tsd); + trk.session->flow->call_handlers(tsd.get_pkt(), true); + TcpStreamTracker::TcpState listener_state = tsd.get_listener()->get_tcp_state(); + // If one sided has sent a FIN + if ( TcpStreamTracker::TCP_FIN_WAIT1 == listener_state ) + trk.set_tcp_state(TcpStreamTracker::TCP_LAST_ACK); + else + trk.set_tcp_state(TcpStreamTracker::TCP_FIN_WAIT1); + return true; +} + +bool TcpStateMidStreamRecv::fin_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) +{ + trk.set_fin_seq_status_seen(tsd); + trk.update_tracker_ack_recv(tsd); + trk.perform_fin_recv_flush(tsd); + + if ( trk.update_on_fin_recv(tsd) ) + { + trk.session->update_perf_base_state(TcpStreamTracker::TCP_CLOSING); + trk.set_tcp_state(TcpStreamTracker::TCP_CLOSE_WAIT); + } + + return true; +} + +bool TcpStateMidStreamRecv::rst_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) +{ + if ( trk.update_on_rst_recv(tsd) ) + { + trk.session->update_session_on_rst(tsd, false); + trk.session->update_perf_base_state(TcpStreamTracker::TCP_CLOSING); + trk.session->set_pkt_action_flag(ACTION_RST); + } + + // FIXIT-L might be good to create alert specific to RST with data + if ( tsd.is_data_segment() ) + trk.session->tel.set_tcp_event(EVENT_DATA_AFTER_RST_RCVD); + + return true; +} + +bool TcpStateMidStreamRecv::do_post_sm_packet_actions(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) +{ + // Always need to check for one sided + bool one_sided = trk.session->check_for_one_sided_session(tsd.get_pkt()); + if ( one_sided && TcpStreamTracker::TCP_MID_STREAM_RECV == trk.get_tcp_state() ) + trk.set_tcp_state(TcpStreamTracker::TCP_ESTABLISHED); + return true; +} + diff --git a/src/stream/tcp/tcp_state_mid_stream_recv.h b/src/stream/tcp/tcp_state_mid_stream_recv.h new file mode 100644 index 000000000..995f73b0a --- /dev/null +++ b/src/stream/tcp/tcp_state_mid_stream_recv.h @@ -0,0 +1,47 @@ +//-------------------------------------------------------------------------- +// Copyright (C) 2022-2022 Cisco and/or its affiliates. All rights reserved. +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License Version 2 as published +// by the Free Software Foundation. You may not use, modify or distribute +// this program under any other version of the GNU General Public License. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +//-------------------------------------------------------------------------- + +// tcp_state_mid_stream_recv.h author Ron Dempster +// Created on: Dec 7, 2022 + +#ifndef TCP_STATE_MID_STREAM_RECV_H +#define TCP_STATE_MID_STREAM_RECV_H + +#include "tcp_state_handler.h" + +class TcpStateMidStreamRecv : public TcpStateHandler +{ +public: + TcpStateMidStreamRecv(TcpStateMachine&); + + bool syn_sent(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool syn_recv(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool syn_ack_sent(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool ack_sent(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool ack_recv(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool data_seg_sent(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool data_seg_recv(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool fin_sent(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool fin_recv(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool rst_recv(TcpSegmentDescriptor&, TcpStreamTracker&) override; + + bool do_post_sm_packet_actions(TcpSegmentDescriptor&, TcpStreamTracker&) override; +}; + +#endif + diff --git a/src/stream/tcp/tcp_state_mid_stream_sent.cc b/src/stream/tcp/tcp_state_mid_stream_sent.cc new file mode 100644 index 000000000..9e9209ecd --- /dev/null +++ b/src/stream/tcp/tcp_state_mid_stream_sent.cc @@ -0,0 +1,174 @@ +//-------------------------------------------------------------------------- +// Copyright (C) 2022-2022 Cisco and/or its affiliates. All rights reserved. +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License Version 2 as published +// by the Free Software Foundation. You may not use, modify or distribute +// this program under any other version of the GNU General Public License. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +//-------------------------------------------------------------------------- + +// tcp_state_mid_stream_sent.cc author Ron Dempster +// Created on: Dec 7, 2022 + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "tcp_state_mid_stream_sent.h" + +#include "tcp_normalizers.h" +#include "tcp_session.h" + +using namespace snort; + +TcpStateMidStreamSent::TcpStateMidStreamSent(TcpStateMachine& tsm) : + TcpStateHandler(TcpStreamTracker::TCP_MID_STREAM_SENT, tsm) +{ } + +bool TcpStateMidStreamSent::syn_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) +{ + trk.session->check_for_repeated_syn(tsd); + return true; +} + +bool TcpStateMidStreamSent::syn_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) +{ + trk.session->check_for_repeated_syn(tsd); + trk.normalizer.ecn_tracker(tsd.get_tcph(), trk.session->tcp_config->require_3whs()); + trk.set_tcp_state(TcpStreamTracker::TCP_ESTABLISHED); + return true; +} + +bool TcpStateMidStreamSent::syn_ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) +{ + trk.session->check_for_repeated_syn(tsd); + return true; +} + +bool TcpStateMidStreamSent::syn_ack_recv(TcpSegmentDescriptor&, TcpStreamTracker& trk) +{ + trk.set_tcp_state(TcpStreamTracker::TCP_ESTABLISHED); + return true; +} + +bool TcpStateMidStreamSent::ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) +{ + trk.update_tracker_ack_sent(tsd); + return true; +} + +bool TcpStateMidStreamSent::ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) +{ + trk.update_tracker_ack_recv(tsd); + trk.session->set_established(tsd); + trk.set_tcp_state(TcpStreamTracker::TCP_ESTABLISHED); + return true; +} + +bool TcpStateMidStreamSent::data_seg_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) +{ + trk.update_tracker_ack_sent(tsd); + return true; +} + +bool TcpStateMidStreamSent::data_seg_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) +{ + trk.update_tracker_ack_recv(tsd); + trk.session->set_established(tsd); + trk.set_tcp_state(TcpStreamTracker::TCP_ESTABLISHED); + trk.session->handle_data_segment(tsd); + return true; + } + +bool TcpStateMidStreamSent::fin_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) +{ + trk.update_on_fin_sent(tsd); + return true; +} + +bool TcpStateMidStreamSent::fin_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) +{ + TcpStreamTracker::TcpState talker_state = tsd.get_talker()->get_tcp_state(); + if ( TcpStreamTracker::TCP_LAST_ACK == talker_state ) + { + trk.set_fin_seq_status_seen(tsd); + trk.update_tracker_ack_recv(tsd); + bool is_ack_valid = false; + if ( SEQ_GEQ(tsd.get_end_seq(), trk.r_win_base) and check_for_window_slam(tsd, trk, is_ack_valid) ) + { + trk.perform_fin_recv_flush(tsd); + trk.update_on_fin_recv(tsd); + + if ( is_ack_valid ) + trk.set_tcp_state(TcpStreamTracker::TCP_TIME_WAIT); + else + trk.set_tcp_state(TcpStreamTracker::TCP_CLOSING); + } + } + else if ( trk.update_on_fin_recv(tsd) ) + { + trk.set_fin_seq_status_seen(tsd); + trk.update_tracker_ack_recv(tsd); + trk.session->set_established(tsd); + trk.set_tcp_state(TcpStreamTracker::TCP_ESTABLISHED); + trk.perform_fin_recv_flush(tsd); + + trk.session->update_perf_base_state(TcpStreamTracker::TCP_CLOSING); + trk.set_tcp_state(TcpStreamTracker::TCP_CLOSE_WAIT); + } + return true; +} + +bool TcpStateMidStreamSent::rst_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) +{ + if ( trk.update_on_rst_recv(tsd) ) + { + trk.session->update_session_on_rst(tsd, false); + trk.session->update_perf_base_state(TcpStreamTracker::TCP_CLOSING); + trk.session->set_pkt_action_flag(ACTION_RST); + } + + // FIXIT-L might be good to create alert specific to RST with data + if ( tsd.is_data_segment() ) + trk.session->tel.set_tcp_event(EVENT_DATA_AFTER_RST_RCVD); + + return true; +} + +bool TcpStateMidStreamSent::do_post_sm_packet_actions(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) +{ + trk.session->check_for_pseudo_established(tsd.get_pkt()); + trk.session->update_paws_timestamps(tsd); + trk.session->check_for_window_slam(tsd); + return true; +} + +bool TcpStateMidStreamSent::check_for_window_slam(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk, bool& is_ack_valid) +{ + if ( SEQ_EQ(tsd.get_ack(), trk.get_snd_nxt() ) ) + { + if ( (trk.normalizer.get_os_policy() == StreamPolicy::OS_WINDOWS) + && (tsd.get_wnd() == 0)) + { + trk.session->tel.set_tcp_event(EVENT_WINDOW_SLAM); + trk.normalizer.packet_dropper(tsd, NORM_TCP_BLOCK); + trk.session->set_pkt_action_flag(ACTION_BAD_PKT); + return false; + } + + trk.set_tcp_state(TcpStreamTracker::TCP_FIN_WAIT2); + is_ack_valid = true; + } + + return true; +} + diff --git a/src/stream/tcp/tcp_state_mid_stream_sent.h b/src/stream/tcp/tcp_state_mid_stream_sent.h new file mode 100644 index 000000000..46d690c0a --- /dev/null +++ b/src/stream/tcp/tcp_state_mid_stream_sent.h @@ -0,0 +1,51 @@ +//-------------------------------------------------------------------------- +// Copyright (C) 2022-2022 Cisco and/or its affiliates. All rights reserved. +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License Version 2 as published +// by the Free Software Foundation. You may not use, modify or distribute +// this program under any other version of the GNU General Public License. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +//-------------------------------------------------------------------------- + +// tcp_state_mid_stream_sent.h author Ron Dempster +// Created on: Dec 7, 2022 + +#ifndef TCP_STATE_MID_STREAM_SENT_H +#define TCP_STATE_MID_STREAM_SENT_H + +#include "tcp_state_handler.h" + +class TcpStateMidStreamSent : public TcpStateHandler +{ +public: + TcpStateMidStreamSent(TcpStateMachine&); + + bool syn_sent(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool syn_recv(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool syn_ack_sent(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool syn_ack_recv(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool ack_sent(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool ack_recv(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool data_seg_sent(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool data_seg_recv(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool fin_sent(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool fin_recv(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool rst_recv(TcpSegmentDescriptor&, TcpStreamTracker&) override; + + bool do_post_sm_packet_actions(TcpSegmentDescriptor&, TcpStreamTracker&) override; + +private: + bool check_for_window_slam(TcpSegmentDescriptor&, TcpStreamTracker&, bool& is_ack_valid); +}; + +#endif + diff --git a/src/stream/tcp/tcp_state_none.cc b/src/stream/tcp/tcp_state_none.cc index 4cc945f15..55f5ba35c 100644 --- a/src/stream/tcp/tcp_state_none.cc +++ b/src/stream/tcp/tcp_state_none.cc @@ -41,35 +41,16 @@ bool TcpStateNone::syn_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) { Flow* flow = tsd.get_flow(); flow->ssn_state.direction = FROM_CLIENT; - flow->session_state |= STREAM_STATE_SYN; trk.init_on_syn_sent(tsd); trk.session->init_new_tcp_session(tsd); return true; } -bool TcpStateNone::syn_recv(TcpSegmentDescriptor&, TcpStreamTracker&) +bool TcpStateNone::syn_ack_sent(TcpSegmentDescriptor&, TcpStreamTracker& trk) { - return true; -} - -bool TcpStateNone::syn_ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) -{ - Flow* flow = tsd.get_flow(); - - if ( !trk.session->tcp_config->require_3whs() or trk.session->is_midstream_allowed(tsd) ) - { - flow->session_state |= ( STREAM_STATE_SYN | STREAM_STATE_SYN_ACK ); - trk.init_on_synack_sent(tsd); - trk.session->init_new_tcp_session(tsd); - trk.normalizer.ecn_tracker(tsd.get_tcph(), trk.session->tcp_config->require_3whs()); - } - else if ( trk.session->tcp_config->require_3whs() ) - { - trk.session->generate_no_3whs_event(); - return false; - } - return true; + trk.session->generate_no_3whs_event(); + return false; } bool TcpStateNone::syn_ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) @@ -89,40 +70,9 @@ bool TcpStateNone::syn_ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk return true; } -bool TcpStateNone::ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) -{ - if ( trk.session->is_midstream_allowed(tsd) && tsd.has_wscale() ) - { - Flow* flow = tsd.get_flow(); - - flow->session_state |= ( STREAM_STATE_ACK | STREAM_STATE_SYN_ACK | - STREAM_STATE_ESTABLISHED ); - trk.init_on_3whs_ack_sent(tsd); - trk.session->init_new_tcp_session(tsd); - trk.session->update_perf_base_state(TcpStreamTracker::TCP_ESTABLISHED); - } - else if ( trk.session->tcp_config->require_3whs() ) - { - trk.session->generate_no_3whs_event(); - return false; - } - return true; -} - -bool TcpStateNone::ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) +bool TcpStateNone::ack_sent(TcpSegmentDescriptor&, TcpStreamTracker& trk) { - if ( trk.session->is_midstream_allowed(tsd) && tsd.has_wscale() ) - { - Flow* flow = tsd.get_flow(); - - if ( !tsd.get_tcph()->is_rst() && ( flow->session_state & STREAM_STATE_SYN_ACK ) ) - { - trk.init_on_3whs_ack_recv(tsd); - trk.normalizer.ecn_tracker( - tsd.get_tcph(), trk.session->tcp_config->require_3whs()); - } - } - else if ( trk.session->tcp_config->require_3whs() ) + if ( trk.session->tcp_config->require_3whs() ) { trk.session->generate_no_3whs_event(); return false; @@ -135,7 +85,6 @@ bool TcpStateNone::data_seg_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tr if ( trk.session->is_midstream_allowed(tsd) ) { Flow* flow = tsd.get_flow(); - flow->session_state |= STREAM_STATE_MIDSTREAM; if ( !Stream::is_midstream(flow) ) { @@ -145,9 +94,6 @@ bool TcpStateNone::data_seg_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tr trk.init_on_data_seg_sent(tsd); trk.session->init_new_tcp_session(tsd); - - if ( flow->session_state & STREAM_STATE_ESTABLISHED ) - trk.session->update_perf_base_state(TcpStreamTracker::TCP_ESTABLISHED); } else if ( trk.session->tcp_config->require_3whs() ) { @@ -162,14 +108,7 @@ bool TcpStateNone::data_seg_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tr if ( trk.session->is_midstream_allowed(tsd) ) { Flow* flow = tsd.get_flow(); - flow->session_state |= STREAM_STATE_MIDSTREAM; - if ( !Stream::is_midstream(flow) ) - { - flow->set_session_flags(SSNFLAG_MIDSTREAM); - DataBus::publish(Stream::get_pub_id(), StreamEventIds::TCP_MIDSTREAM, tsd.get_pkt()); - } - trk.init_on_data_seg_recv(tsd); trk.normalizer.ecn_tracker(tsd.get_tcph(), trk.session->tcp_config->require_3whs()); trk.session->handle_data_segment(tsd); @@ -231,3 +170,9 @@ bool TcpStateNone::rst_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) return true; } +bool TcpStateNone::do_post_sm_packet_actions(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) +{ + trk.session->check_for_one_sided_session(tsd.get_pkt()); + return true; +} + diff --git a/src/stream/tcp/tcp_state_none.h b/src/stream/tcp/tcp_state_none.h index 92605f3d9..4d4c09102 100644 --- a/src/stream/tcp/tcp_state_none.h +++ b/src/stream/tcp/tcp_state_none.h @@ -30,17 +30,17 @@ public: TcpStateNone(TcpStateMachine&); bool syn_sent(TcpSegmentDescriptor&, TcpStreamTracker&) override; - bool syn_recv(TcpSegmentDescriptor&, TcpStreamTracker&) override; bool syn_ack_sent(TcpSegmentDescriptor&, TcpStreamTracker&) override; bool syn_ack_recv(TcpSegmentDescriptor&, TcpStreamTracker&) override; bool ack_sent(TcpSegmentDescriptor&, TcpStreamTracker&) override; - bool ack_recv(TcpSegmentDescriptor&, TcpStreamTracker&) override; bool data_seg_sent(TcpSegmentDescriptor&, TcpStreamTracker&) override; bool data_seg_recv(TcpSegmentDescriptor&, TcpStreamTracker&) override; bool fin_sent(TcpSegmentDescriptor&, TcpStreamTracker&) override; bool fin_recv(TcpSegmentDescriptor&, TcpStreamTracker&) override; bool rst_sent(TcpSegmentDescriptor&, TcpStreamTracker&) override; bool rst_recv(TcpSegmentDescriptor&, TcpStreamTracker&) override; + + bool do_post_sm_packet_actions(TcpSegmentDescriptor&, TcpStreamTracker&) override; }; #endif diff --git a/src/stream/tcp/tcp_state_syn_recv.cc b/src/stream/tcp/tcp_state_syn_recv.cc index 6b18e98e6..6c7f79695 100644 --- a/src/stream/tcp/tcp_state_syn_recv.cc +++ b/src/stream/tcp/tcp_state_syn_recv.cc @@ -37,11 +37,10 @@ TcpStateSynRecv::TcpStateSynRecv(TcpStateMachine& tsm) : bool TcpStateSynRecv::syn_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) { - Flow* flow = tsd.get_flow(); - trk.finish_server_init(tsd); trk.normalizer.ecn_tracker(tsd.get_tcph(), trk.session->tcp_config->require_3whs()); trk.session->update_timestamp_tracking(tsd); + Flow* flow = tsd.get_flow(); if ( tsd.get_tcph()->are_flags_set(TH_ECE) && ( flow->get_session_flags() & SSNFLAG_ECN_CLIENT_QUERY ) ) flow->set_session_flags(SSNFLAG_ECN_SERVER_REPLY); @@ -65,11 +64,8 @@ bool TcpStateSynRecv::syn_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) bool TcpStateSynRecv::syn_ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) { - Flow* flow = tsd.get_flow(); - trk.finish_server_init(tsd); trk.normalizer.ecn_tracker(tsd.get_tcph(), trk.session->tcp_config->require_3whs()); - flow->session_state |= STREAM_STATE_SYN_ACK; return true; } @@ -78,10 +74,9 @@ bool TcpStateSynRecv::syn_ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& { if ( trk.is_ack_valid(tsd.get_ack()) ) { + trk.irs = tsd.get_seq(); trk.update_tracker_ack_recv(tsd); trk.normalizer.ecn_tracker(tsd.get_tcph(), trk.session->tcp_config->require_3whs()); - trk.session->set_established(tsd.get_pkt(), STREAM_STATE_ACK); - trk.session->update_perf_base_state(TcpStreamTracker::TCP_ESTABLISHED); trk.set_tcp_state(TcpStreamTracker::TCP_ESTABLISHED); if ( tsd.is_data_segment() ) trk.session->handle_data_on_syn(tsd); @@ -92,9 +87,16 @@ bool TcpStateSynRecv::syn_ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& bool TcpStateSynRecv::ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) { - if ( trk.session->tcp_config->midstream_allowed(tsd.get_pkt()) ) - trk.session->update_session_on_ack(); - + if ( trk.session->tcp_config->midstream_allowed(tsd.get_pkt()) && trk.session->flow->two_way_traffic() ) + { + TcpStreamTracker::TcpState listener_state = tsd.get_listener()->get_tcp_state(); + // Does this ACK finish 4-way handshake + if ( TcpStreamTracker::TCP_ESTABLISHED == listener_state ) + { + trk.session->set_established(tsd); + trk.set_tcp_state(TcpStreamTracker::TCP_ESTABLISHED); + } + } return true; } @@ -105,37 +107,41 @@ bool TcpStateSynRecv::ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) trk.update_tracker_ack_recv(tsd); trk.session->set_pkt_action_flag(trk.normalizer.handle_paws(tsd)); tsd.set_packet_flags(PKT_STREAM_TWH); - trk.session->set_established(tsd.get_pkt(), STREAM_STATE_ACK); - trk.session->update_perf_base_state(TcpStreamTracker::TCP_ESTABLISHED); + TcpStreamTracker::TcpState talker_state = tsd.get_talker()->get_tcp_state(); + // Does this ACK finish the 3-way or 4-way handshake + if ( TcpStreamTracker::TCP_ESTABLISHED == talker_state || !trk.session->flow->two_way_traffic() ) + trk.session->set_established(tsd); trk.set_tcp_state(TcpStreamTracker::TCP_ESTABLISHED); trk.session->check_for_window_slam(tsd); } - return true; } bool TcpStateSynRecv::data_seg_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) { - trk.update_tracker_ack_sent(tsd); - if ( trk.session->no_ack_mode_enabled() ) - trk.update_tracker_no_ack_recv(tsd); - + if ( trk.session->tcp_config->midstream_allowed(tsd.get_pkt()) ) + { + trk.update_tracker_ack_sent(tsd); + if ( trk.session->no_ack_mode_enabled() ) + trk.update_tracker_no_ack_recv(tsd); + if ( trk.session->flow->two_way_traffic() ) + { + TcpStreamTracker::TcpState listener_state = tsd.get_listener()->get_tcp_state(); + // Does this ACK finish 4-way handshake + if ( TcpStreamTracker::TCP_ESTABLISHED == listener_state ) + { + trk.session->set_established(tsd); + trk.set_tcp_state(TcpStreamTracker::TCP_ESTABLISHED); + } + } + } return true; } bool TcpStateSynRecv::data_seg_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) { - if ( trk.is_ack_valid(tsd.get_ack()) ) - { - trk.update_tracker_ack_recv(tsd); - tsd.set_packet_flags(PKT_STREAM_TWH); - trk.session->set_pkt_action_flag(trk.normalizer.handle_paws(tsd)); - trk.session->update_perf_base_state(TcpStreamTracker::TCP_ESTABLISHED); - trk.set_tcp_state(TcpStreamTracker::TCP_ESTABLISHED); - } - + ack_recv(tsd, trk); trk.session->handle_data_segment(tsd); - return true; } @@ -143,12 +149,16 @@ bool TcpStateSynRecv::fin_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) { if ( tsd.get_tcph()->is_ack() ) { - Flow* flow = tsd.get_flow(); - trk.set_fin_seq_status_seen(tsd); trk.update_tracker_ack_recv(tsd); trk.session->set_pkt_action_flag(trk.normalizer.handle_paws(tsd)); - flow->session_state |= STREAM_STATE_ACK; + + TcpStreamTracker::TcpState talker_state = tsd.get_talker()->get_tcp_state(); + // Does this ACK finish the 3-way + if ( TcpStreamTracker::TCP_ESTABLISHED == talker_state + || TcpStreamTracker::TCP_FIN_WAIT1 == talker_state ) + trk.session->set_established(tsd); + trk.perform_fin_recv_flush(tsd); if ( trk.update_on_fin_recv(tsd) ) @@ -168,6 +178,8 @@ bool TcpStateSynRecv::rst_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) { Flow* flow = tsd.get_flow(); flow->set_session_flags(SSNFLAG_RESET); + if ( !((SSNFLAG_TCP_PSEUDO_EST | SSNFLAG_ESTABLISHED) & flow->get_session_flags()) ) + trk.session->set_pseudo_established(tsd.get_pkt()); } else { diff --git a/src/stream/tcp/tcp_state_syn_sent.cc b/src/stream/tcp/tcp_state_syn_sent.cc index 7a0ce1d75..497fb59a1 100644 --- a/src/stream/tcp/tcp_state_syn_sent.cc +++ b/src/stream/tcp/tcp_state_syn_sent.cc @@ -36,30 +36,44 @@ TcpStateSynSent::TcpStateSynSent(TcpStateMachine& tsm) : bool TcpStateSynSent::syn_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) { trk.session->check_for_repeated_syn(tsd); - return true; } bool TcpStateSynSent::syn_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) { + trk.irs = tsd.get_seq(); trk.finish_client_init(tsd); if ( tsd.is_data_segment() ) trk.session->handle_data_on_syn(tsd); trk.set_tcp_state(TcpStreamTracker::TCP_SYN_RECV); + return true; +} +bool TcpStateSynSent::syn_ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) +{ + if ( trk.session->flow->two_way_traffic() ) + { + trk.session->check_for_repeated_syn(tsd); + trk.update_tracker_ack_sent(tsd); + trk.iss = tsd.get_seq(); + trk.session->update_timestamp_tracking(tsd); + } return true; } bool TcpStateSynSent::syn_ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) { - if ( trk.update_on_3whs_ack(tsd) ) + if ( trk.session->flow->two_way_traffic() ) { - trk.session->update_timestamp_tracking(tsd); - if ( tsd.is_data_segment() ) - trk.session->handle_data_on_syn(tsd); + if ( trk.update_on_3whs_ack(tsd) ) + { + trk.session->update_timestamp_tracking(tsd); + if ( tsd.is_data_segment() ) + trk.session->handle_data_on_syn(tsd); + } + else + trk.session->set_pkt_action_flag(ACTION_BAD_PKT); } - else - trk.session->set_pkt_action_flag(ACTION_BAD_PKT); return true; } @@ -67,42 +81,89 @@ bool TcpStateSynSent::syn_ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& bool TcpStateSynSent::ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) { trk.update_tracker_ack_sent(tsd); - trk.session->set_established(tsd.get_pkt(), STREAM_STATE_ACK); trk.session->update_timestamp_tracking(tsd); - trk.session->update_perf_base_state(TcpStreamTracker::TCP_ESTABLISHED); - trk.set_tcp_state(TcpStreamTracker::TCP_ESTABLISHED); - + if ( trk.session->flow->two_way_traffic() ) + { + TcpStreamTracker::TcpState listener_state = tsd.get_listener()->get_tcp_state(); + // Weird case with c2s syn, c2s syn seq + 1, s2c syn-ack to 2nd syn, c2s ack + if ( TcpStreamTracker::TCP_SYN_RECV == listener_state ) + { + trk.session->set_established(tsd); + trk.set_tcp_state(TcpStreamTracker::TCP_ESTABLISHED); + } + } return true; } bool TcpStateSynSent::ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) { - trk.update_on_3whs_ack(tsd); + // Finish handshake + if ( trk.session->flow->two_way_traffic() ) + trk.update_on_3whs_ack(tsd); + else + { + trk.update_tracker_ack_recv(tsd); + trk.session->set_established(tsd); + trk.set_tcp_state(TcpStreamTracker::TCP_ESTABLISHED); + } return true; } bool TcpStateSynSent::data_seg_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) { trk.update_tracker_ack_sent(tsd); - trk.session->set_established(tsd.get_pkt(), STREAM_STATE_ACK); trk.session->update_timestamp_tracking(tsd); - trk.session->update_perf_base_state(TcpStreamTracker::TCP_ESTABLISHED); - trk.set_tcp_state(TcpStreamTracker::TCP_ESTABLISHED); - + if ( trk.session->flow->two_way_traffic() ) + { + TcpStreamTracker::TcpState listener_state = tsd.get_listener()->get_tcp_state(); + // Weird case with c2s syn, c2s syn seq + 1, s2c syn-ack to 2nd syn, c2s ack + if ( TcpStreamTracker::TCP_SYN_RECV == listener_state ) + { + trk.session->set_established(tsd); + trk.set_tcp_state(TcpStreamTracker::TCP_ESTABLISHED); + } + } return true; } bool TcpStateSynSent::data_seg_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) { - if ( trk.update_on_3whs_ack(tsd) ) - trk.session->handle_data_segment(tsd); + ack_recv(tsd, trk); + trk.session->handle_data_segment(tsd); + return true; +} +bool TcpStateSynSent::fin_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) +{ + trk.update_on_fin_sent(tsd); + trk.session->flow->call_handlers(tsd.get_pkt(), true); + trk.session->update_timestamp_tracking(tsd); + if ( trk.session->flow->two_way_traffic() ) + { + TcpStreamTracker::TcpState listener_state = tsd.get_listener()->get_tcp_state(); + // Weird case with c2s syn, c2s syn seq + 1, s2c syn-ack to 2nd syn, c2s ack + if ( TcpStreamTracker::TCP_SYN_RECV == listener_state ) + { + trk.session->set_established(tsd); + trk.set_tcp_state(TcpStreamTracker::TCP_ESTABLISHED); + } + trk.set_tcp_state(TcpStreamTracker::TCP_FIN_WAIT1); + } return true; } bool TcpStateSynSent::fin_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) { trk.set_fin_seq_status_seen(tsd); + ack_recv(tsd, trk); + if ( trk.session->flow->two_way_traffic() ) + { + if ( trk.update_on_fin_recv(tsd) ) + { + trk.session->update_perf_base_state(TcpStreamTracker::TCP_CLOSING); + trk.set_tcp_state(TcpStreamTracker::TCP_CLOSE_WAIT); + } + } trk.perform_fin_recv_flush(tsd); return true; } @@ -125,3 +186,10 @@ bool TcpStateSynSent::rst_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) return true; } +bool TcpStateSynSent::do_post_sm_packet_actions(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) +{ + trk.session->check_for_window_slam(tsd); + + return true; +} + diff --git a/src/stream/tcp/tcp_state_syn_sent.h b/src/stream/tcp/tcp_state_syn_sent.h index c5b302c63..16743a33d 100644 --- a/src/stream/tcp/tcp_state_syn_sent.h +++ b/src/stream/tcp/tcp_state_syn_sent.h @@ -31,13 +31,17 @@ public: bool syn_sent(TcpSegmentDescriptor&, TcpStreamTracker&) override; bool syn_recv(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool syn_ack_sent(TcpSegmentDescriptor&, TcpStreamTracker&) override; bool syn_ack_recv(TcpSegmentDescriptor&, TcpStreamTracker&) override; bool ack_sent(TcpSegmentDescriptor&, TcpStreamTracker&) override; bool ack_recv(TcpSegmentDescriptor&, TcpStreamTracker&) override; bool data_seg_sent(TcpSegmentDescriptor&, TcpStreamTracker&) override; bool data_seg_recv(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool fin_sent(TcpSegmentDescriptor&, TcpStreamTracker&) override; bool fin_recv(TcpSegmentDescriptor&, TcpStreamTracker&) override; bool rst_recv(TcpSegmentDescriptor&, TcpStreamTracker&) override; + + bool do_post_sm_packet_actions(TcpSegmentDescriptor&, TcpStreamTracker&) override; }; #endif diff --git a/src/stream/tcp/tcp_stream_session.cc b/src/stream/tcp/tcp_stream_session.cc index b00dbd747..8067a637d 100644 --- a/src/stream/tcp/tcp_stream_session.cc +++ b/src/stream/tcp/tcp_stream_session.cc @@ -26,7 +26,6 @@ #include "tcp_stream_session.h" #include "framework/data_bus.h" -#include "log/messages.h" #include "pub_sub/stream_event_ids.h" #include "stream/stream.h" #include "stream/tcp/tcp_ha.h" @@ -57,55 +56,12 @@ void TcpStreamSession::init_new_tcp_session(TcpSegmentDescriptor& tsd) lws_init = true; } -void TcpStreamSession::update_session_on_syn_ack() -{ - /* If session is already marked as established */ - if ( !(flow->session_state & STREAM_STATE_ESTABLISHED) ) - { - /* SYN-ACK from server */ - if (flow->session_state != STREAM_STATE_NONE) - { - flow->session_state |= STREAM_STATE_SYN_ACK; - update_perf_base_state(TcpStreamTracker::TCP_ESTABLISHED); - } - } -} - -void TcpStreamSession::update_session_on_ack() -{ - /* If session is already marked as established */ - if ( !(flow->session_state & STREAM_STATE_ESTABLISHED) ) - { - if ( flow->session_state & STREAM_STATE_SYN_ACK ) - { - flow->session_state |= STREAM_STATE_ACK | STREAM_STATE_ESTABLISHED; - update_perf_base_state(TcpStreamTracker::TCP_ESTABLISHED); - } - } -} - void TcpStreamSession::update_session_on_server_packet(TcpSegmentDescriptor& tsd) { flow->set_session_flags(SSNFLAG_SEEN_SERVER); tsd.set_talker(server); tsd.set_listener(client); - /* If we picked this guy up midstream, finish the initialization */ - if ( !(flow->session_state & STREAM_STATE_ESTABLISHED) - && (flow->session_state & STREAM_STATE_MIDSTREAM) ) - { - if ( tsd.get_tcph()->are_flags_set(TH_ECE) - && (flow->get_session_flags() & SSNFLAG_ECN_CLIENT_QUERY) ) - flow->set_session_flags(SSNFLAG_ECN_SERVER_REPLY); - - if ( flow->get_session_flags() & SSNFLAG_SEEN_CLIENT ) - { - // should TCP state go to established too? - set_established(tsd.get_pkt()); - update_perf_base_state(TcpStreamTracker::TCP_ESTABLISHED); - } - } - if ( !flow->inner_server_ttl && !tsd.is_meta_ack_packet() ) flow->set_ttl(tsd.get_pkt(), false); } @@ -117,14 +73,6 @@ void TcpStreamSession::update_session_on_client_packet(TcpSegmentDescriptor& tsd tsd.set_talker(client); tsd.set_listener(server); - if ( !( flow->session_state & STREAM_STATE_ESTABLISHED ) - && ( flow->session_state & STREAM_STATE_MIDSTREAM ) ) - { - /* Midstream and seen server. */ - if ( flow->get_session_flags() & SSNFLAG_SEEN_SERVER ) - set_established(tsd.get_pkt()); - } - if ( !flow->inner_client_ttl && !tsd.is_meta_ack_packet() ) flow->set_ttl(tsd.get_pkt(), true); } @@ -392,20 +340,29 @@ StreamSplitter* TcpStreamSession::get_splitter(bool to_server) void TcpStreamSession::start_proxy() { tcp_config->policy = StreamPolicy::OS_PROXY; } -void TcpStreamSession::set_established(Packet* p, uint32_t flags) +void TcpStreamSession::set_established(const TcpSegmentDescriptor& tsd) { - flow->session_state |= STREAM_STATE_ESTABLISHED | flags; + update_perf_base_state(TcpStreamTracker::TCP_ESTABLISHED); + flow->session_state |= STREAM_STATE_ESTABLISHED; if (SSNFLAG_ESTABLISHED != (SSNFLAG_ESTABLISHED & flow->get_session_flags())) { flow->set_session_flags(SSNFLAG_ESTABLISHED); - DataBus::publish(Stream::get_pub_id(), StreamEventIds::TCP_ESTABLISHED, p); + // Only send 1 event + if (SSNFLAG_TCP_PSEUDO_EST != (SSNFLAG_TCP_PSEUDO_EST & flow->get_session_flags())) + DataBus::publish(Stream::get_pub_id(), StreamEventIds::TCP_ESTABLISHED, tsd.get_pkt()); } } -void TcpStreamSession::check_for_one_sided_session(Packet* p) +void TcpStreamSession::set_pseudo_established(Packet* p) +{ + p->flow->ssn_state.session_flags |= SSNFLAG_TCP_PSEUDO_EST; + DataBus::publish(Stream::get_pub_id(), StreamEventIds::TCP_ESTABLISHED, p); +} + +bool TcpStreamSession::check_for_one_sided_session(Packet* p) { Flow& flow = *p->flow; - if ( !( (SSNFLAG_ESTABLISHED | SSNFLAG_TCP_ONE_SIDED) & flow.ssn_state.session_flags ) + if ( 0 == ( (SSNFLAG_ESTABLISHED | SSNFLAG_TCP_PSEUDO_EST) & flow.ssn_state.session_flags ) && p->is_from_client_originally() ) { uint64_t initiator_packets; @@ -430,10 +387,23 @@ void TcpStreamSession::check_for_one_sided_session(Packet* p) initiator_watermark = watermark; else if ( initiator_watermark != watermark ) { - flow.ssn_state.session_flags |= SSNFLAG_TCP_ONE_SIDED; - DataBus::publish(Stream::get_pub_id(), StreamEventIds::TCP_ESTABLISHED, p); + set_pseudo_established(p); + return true; } } } + return false; +} + +void TcpStreamSession::check_for_pseudo_established(Packet* p) +{ + Flow& flow = *p->flow; + if ( 0 == ( (SSNFLAG_ESTABLISHED | SSNFLAG_TCP_PSEUDO_EST) & flow.ssn_state.session_flags ) ) + { + if ( check_for_one_sided_session(p) ) + return; + if ( 0 < flow.flowstats.client_pkts && 0 < flow.flowstats.server_pkts ) + set_pseudo_established(p); + } } diff --git a/src/stream/tcp/tcp_stream_session.h b/src/stream/tcp/tcp_stream_session.h index 8145f7b0d..6e0fa1559 100644 --- a/src/stream/tcp/tcp_stream_session.h +++ b/src/stream/tcp/tcp_stream_session.h @@ -79,8 +79,6 @@ public: virtual void init_new_tcp_session(TcpSegmentDescriptor&); virtual void update_timestamp_tracking(TcpSegmentDescriptor&) = 0; - virtual void update_session_on_syn_ack(); - virtual void update_session_on_ack(); virtual void update_session_on_server_packet(TcpSegmentDescriptor&); virtual void update_session_on_client_packet(TcpSegmentDescriptor&); virtual void update_session_on_rst(TcpSegmentDescriptor&, bool) = 0; @@ -99,8 +97,10 @@ public: void set_pkt_action_flag(uint32_t flag) { pkt_action_mask |= flag; } - void set_established(snort::Packet*, uint32_t flags = 0); - void check_for_one_sided_session(snort::Packet*); + void set_established(const TcpSegmentDescriptor&); + void set_pseudo_established(snort::Packet*); + bool check_for_one_sided_session(snort::Packet*); + void check_for_pseudo_established(snort::Packet*); virtual void update_paws_timestamps(TcpSegmentDescriptor&) = 0; virtual void check_for_repeated_syn(TcpSegmentDescriptor&) = 0; diff --git a/src/stream/tcp/tcp_stream_tracker.cc b/src/stream/tcp/tcp_stream_tracker.cc index 9d8fb205c..9a64fbf77 100644 --- a/src/stream/tcp/tcp_stream_tracker.cc +++ b/src/stream/tcp/tcp_stream_tracker.cc @@ -27,7 +27,6 @@ #include -#include "log/messages.h" #include "main/analyzer.h" #include "main/snort.h" #include "packet_io/active.h" @@ -89,9 +88,27 @@ TcpStreamTracker::TcpEvent TcpStreamTracker::set_tcp_event(const TcpSegmentDescr { // talker events if ( tcph->is_syn_only() ) + { tcp_event = TCP_SYN_SENT_EVENT; + if ( tcp_state == TcpStreamTracker::TCP_STATE_NONE ) + DataBus::publish(Stream::get_pub_id(), StreamEventIds::TCP_SYN, tsd.get_pkt()); + } else if ( tcph->is_syn_ack() ) + { tcp_event = TCP_SYN_ACK_SENT_EVENT; + if ( tcp_state == TcpStreamTracker::TCP_LISTEN ) + DataBus::publish(Stream::get_pub_id(), StreamEventIds::TCP_SYN_ACK, tsd.get_pkt()); + else if ( tcp_state == TcpStreamTracker::TCP_SYN_RECV ) + { + Flow* flow = tsd.get_flow(); + if ( flow->get_session_flags() & SSNFLAG_SEEN_CLIENT ) + { + TcpStreamTracker::TcpState listener_state = tsd.get_listener()->get_tcp_state(); + if ( listener_state == TcpStreamTracker::TCP_SYN_SENT ) + DataBus::publish(Stream::get_pub_id(), StreamEventIds::TCP_SYN_ACK, tsd.get_pkt()); + } + } + } else if ( tcph->is_rst() ) tcp_event = TCP_RST_SENT_EVENT; else if ( tcph->is_fin( ) ) @@ -117,18 +134,11 @@ TcpStreamTracker::TcpEvent TcpStreamTracker::set_tcp_event(const TcpSegmentDescr { tcp_event = TCP_SYN_RECV_EVENT; tcpStats.syns++; - if ( tcp_state == TcpStreamTracker::TCP_LISTEN ) - DataBus::publish(Stream::get_pub_id(), StreamEventIds::TCP_SYN, tsd.get_pkt()); } else if ( tcph->is_syn_ack() ) { tcp_event = TCP_SYN_ACK_RECV_EVENT; tcpStats.syn_acks++; - if ( tcp_state == TcpStreamTracker::TCP_SYN_SENT or - (!Stream::is_midstream(tsd.get_flow()) and - (tcp_state == TcpStreamTracker::TCP_LISTEN or - tcp_state == TcpStreamTracker::TCP_STATE_NONE)) ) - DataBus::publish(Stream::get_pub_id(), StreamEventIds::TCP_SYN_ACK, tsd.get_pkt()); } else if ( tcph->is_rst() ) { @@ -371,49 +381,10 @@ void TcpStreamTracker::init_on_synack_recv(TcpSegmentDescriptor& tsd) reassembler.set_seglist_base_seq(tsd.get_seq() + 1); cache_mac_address(tsd, FROM_SERVER); - tcp_state = TcpStreamTracker::TCP_ESTABLISHED; -} - -void TcpStreamTracker::init_on_3whs_ack_sent(TcpSegmentDescriptor& tsd) -{ - tsd.get_flow()->set_session_flags(SSNFLAG_SEEN_CLIENT); - - if ( tsd.get_tcph()->are_flags_set(TH_CWR | TH_ECE) ) - tsd.get_flow()->set_session_flags(SSNFLAG_ECN_CLIENT_QUERY); - - iss = tsd.get_seq(); - snd_una = tsd.get_seq(); - snd_nxt = snd_una; - snd_wnd = tsd.get_wnd(); - - r_win_base = tsd.get_ack(); - rcv_nxt = tsd.get_ack(); - - ts_last_packet = tsd.get_packet_timestamp(); - tf_flags |= normalizer.get_tcp_timestamp(tsd, false); - ts_last = tsd.get_timestamp(); - if (ts_last == 0) - tf_flags |= TF_TSTAMP_ZERO; - tf_flags |= tsd.init_wscale(&wscale); - - cache_mac_address(tsd, FROM_CLIENT); - tcp_state = TcpStreamTracker::TCP_ESTABLISHED; -} - -void TcpStreamTracker::init_on_3whs_ack_recv(TcpSegmentDescriptor& tsd) -{ - iss = tsd.get_ack() - 1; - irs = tsd.get_seq(); - snd_una = tsd.get_ack(); - snd_nxt = snd_una; - - rcv_nxt = tsd.get_seq(); - r_win_base = tsd.get_seq(); - reassembler.set_seglist_base_seq(tsd.get_seq() + 1); - - cache_mac_address(tsd, FROM_CLIENT); - tcp_state = TcpStreamTracker::TCP_ESTABLISHED; - tcpStats.sessions_on_3way++; + if ( TcpStreamTracker::TCP_SYN_SENT == tcp_state ) + tcp_state = TcpStreamTracker::TCP_ESTABLISHED; + else + tcp_state = TcpStreamTracker::TCP_SYN_SENT; } void TcpStreamTracker::init_on_data_seg_sent(TcpSegmentDescriptor& tsd) @@ -425,8 +396,8 @@ void TcpStreamTracker::init_on_data_seg_sent(TcpSegmentDescriptor& tsd) else flow->set_session_flags(SSNFLAG_SEEN_SERVER); - iss = tsd.get_seq(); - irs = tsd.get_ack(); + iss = tsd.get_seq() - 1; + irs = tsd.get_ack() - 1; snd_una = tsd.get_seq(); snd_nxt = snd_una + tsd.get_len(); snd_wnd = tsd.get_wnd(); @@ -444,13 +415,16 @@ void TcpStreamTracker::init_on_data_seg_sent(TcpSegmentDescriptor& tsd) tf_flags |= tsd.init_wscale(&wscale); cache_mac_address(tsd, tsd.get_direction() ); - tcp_state = TcpStreamTracker::TCP_ESTABLISHED; + if ( TcpStreamTracker::TCP_LISTEN == tcp_state || TcpStreamTracker::TCP_STATE_NONE == tcp_state) + tcp_state = TcpStreamTracker::TCP_MID_STREAM_SENT; + else + tcp_state = TcpStreamTracker::TCP_ESTABLISHED; } void TcpStreamTracker::init_on_data_seg_recv(TcpSegmentDescriptor& tsd) { - iss = tsd.get_ack(); - irs = tsd.get_seq(); + iss = tsd.get_ack() - 1; + irs = tsd.get_seq() - 1; snd_una = tsd.get_ack(); snd_nxt = snd_una; snd_wnd = 0; /* reset later */ @@ -460,7 +434,10 @@ void TcpStreamTracker::init_on_data_seg_recv(TcpSegmentDescriptor& tsd) reassembler.set_seglist_base_seq(tsd.get_seq()); cache_mac_address(tsd, tsd.get_direction() ); - tcp_state = TcpStreamTracker::TCP_ESTABLISHED; + if ( TcpStreamTracker::TCP_LISTEN == tcp_state || TcpStreamTracker::TCP_STATE_NONE == tcp_state ) + tcp_state = TcpStreamTracker::TCP_MID_STREAM_RECV; + else + tcp_state = TcpStreamTracker::TCP_ESTABLISHED; tcpStats.sessions_on_data++; } @@ -553,10 +530,13 @@ bool TcpStreamTracker::update_on_3whs_ack(TcpSegmentDescriptor& tsd) if ( good_ack ) { - irs = tsd.get_seq(); + if (!irs) + irs = tsd.get_seq(); finish_client_init(tsd); update_tracker_ack_recv(tsd); - session->set_established(tsd.get_pkt(), STREAM_STATE_ACK); + TcpStreamTracker::TcpState talker_state = tsd.get_talker()->get_tcp_state(); + if ( TcpStreamTracker::TCP_ESTABLISHED == talker_state ) + session->set_established(tsd); tcp_state = TcpStreamTracker::TCP_ESTABLISHED; } @@ -593,17 +573,22 @@ void TcpStreamTracker::update_on_rst_sent() bool TcpStreamTracker::update_on_fin_recv(TcpSegmentDescriptor& tsd) { - if ( SEQ_LT(tsd.get_end_seq(), r_win_base) ) - return false; + if ( session->flow->two_way_traffic() ) + { + if ( SEQ_LT(tsd.get_end_seq(), r_win_base) ) + return false; - //-------------------------------------------------- - // FIXIT-L don't bump rcv_nxt unless FIN is in seq - // because it causes bogus 129:5 cases - // but doing so causes extra gaps - if ( SEQ_EQ(tsd.get_end_seq(), rcv_nxt) ) - rcv_nxt++; + //-------------------------------------------------- + // FIXIT-L don't bump rcv_nxt unless FIN is in seq + // because it causes bogus 129:5 cases + // but doing so causes extra gaps + if ( SEQ_EQ(tsd.get_end_seq(), rcv_nxt) ) + rcv_nxt++; + else + fin_seq_adjust = 1; + } else - fin_seq_adjust = 1; + rcv_nxt++; return true; } diff --git a/src/stream/tcp/tcp_stream_tracker.h b/src/stream/tcp/tcp_stream_tracker.h index 309fdef2c..08208f319 100644 --- a/src/stream/tcp/tcp_stream_tracker.h +++ b/src/stream/tcp/tcp_stream_tracker.h @@ -54,6 +54,8 @@ public: TCP_SYN_SENT, TCP_SYN_RECV, TCP_ESTABLISHED, + TCP_MID_STREAM_SENT, + TCP_MID_STREAM_RECV, TCP_FIN_WAIT1, TCP_FIN_WAIT2, TCP_CLOSE_WAIT, @@ -276,8 +278,6 @@ public: virtual void init_on_syn_recv(TcpSegmentDescriptor&); virtual void init_on_synack_sent(TcpSegmentDescriptor&); virtual void init_on_synack_recv(TcpSegmentDescriptor&); - virtual void init_on_3whs_ack_sent(TcpSegmentDescriptor&); - virtual void init_on_3whs_ack_recv(TcpSegmentDescriptor&); virtual void init_on_data_seg_sent(TcpSegmentDescriptor&); virtual void init_on_data_seg_recv(TcpSegmentDescriptor&); virtual void finish_server_init(TcpSegmentDescriptor&); diff --git a/src/stream/tcp/tcp_trace.cc b/src/stream/tcp/tcp_trace.cc index e3b882bde..5ef7f4c3a 100644 --- a/src/stream/tcp/tcp_trace.cc +++ b/src/stream/tcp/tcp_trace.cc @@ -40,7 +40,7 @@ void S5TraceTCP(const TcpSegmentDescriptor&, const snort::Packet*) { } static const char* const statext[] = { - "LST", "SYS", "SYR", "EST", "FW1", "FW2", "CLW", + "LST", "SYS", "SYR", "EST", "MDS", "MDR", "FW1", "FW2", "CLW", "CLG", "LAK", "TWT", "CLD", "NON" };