From: Davis McPherson -X (davmcphe - XORIANT CORPORATION at Cisco) Date: Sat, 18 Oct 2025 00:23:46 +0000 (+0000) Subject: Pull request #4923: stream_tcp: enhance rst validation to follow RFC 5961 recommendations X-Git-Tag: 3.9.7.0~19 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=17aa4dcd7ea51c6c8ec725de951bbbf762a277c6;p=thirdparty%2Fsnort3.git Pull request #4923: stream_tcp: enhance rst validation to follow RFC 5961 recommendations Merge in SNORT/snort3 from ~DAVMCPHE/snort3:stream_tcp_rst_handling to master Squashed commit of the following: commit f355fb9799470aae71c2f6b13cea98d981e0ba68 Author: davis mcpherson Date: Tue Sep 9 11:58:15 2025 -0400 stream_tcp: enhance rst validation to follow RFC 5961 recommendations, default all modern OSes to use this validation algorithm add PegCounts to track all outcomes when validating RST packets clean up code that was redundantly setting flags/state --- diff --git a/src/stream/tcp/tcp_module.cc b/src/stream/tcp/tcp_module.cc index 63e83fc70..913208ddf 100644 --- a/src/stream/tcp/tcp_module.cc +++ b/src/stream/tcp/tcp_module.cc @@ -99,7 +99,13 @@ const PegInfo tcp_pegs[] = { CountType::NOW, "closing", "number of sessions currently closing" }, { CountType::SUM, "syns", "number of syn packets" }, { CountType::SUM, "syn_acks", "number of syn-ack packets" }, - { CountType::SUM, "resets", "number of reset packets" }, + { CountType::SUM, "rsts", "number of rst packets" }, + { CountType::SUM, "rsts_ok_rfc793", "number of valid rst packets per RFC 793" }, + { CountType::SUM, "rsts_ok_rfc5961", "number of valid rst packets per RFC 5961" }, + { CountType::SUM, "rsts_in_window", "number of rst packets in window per RFC 5961" }, + { CountType::SUM, "rsts_bad_seq", "number of invalid rst packets, seq out of window" }, + { CountType::SUM, "rsts_ack_ok", "number of valid rst packets good ack (RST in syn sent)" }, + { CountType::SUM, "rsts_ack_bad", "number of invalid rst packets bad ack (RST in syn sent)" }, { CountType::SUM, "fins", "number of fin packets" }, { CountType::SUM, "meta_acks", "number of meta acks processed" }, { CountType::SUM, "packets_held", "number of packets held" }, @@ -417,7 +423,7 @@ const PegInfo* StreamTcpModule::get_pegs() const { return tcp_pegs; } PegCount* StreamTcpModule::get_counts() const -{ return (PegCount*)&tcpStats; } +{ return reinterpret_cast(&tcpStats); } void StreamTcpModule::reset_stats() { diff --git a/src/stream/tcp/tcp_module.h b/src/stream/tcp/tcp_module.h index 5d7b3814d..50d5d9b52 100644 --- a/src/stream/tcp/tcp_module.h +++ b/src/stream/tcp/tcp_module.h @@ -97,7 +97,13 @@ struct TcpStats PegCount sessions_closing; PegCount syns; PegCount syn_acks; - PegCount resets; + PegCount rsts; + PegCount rsts_ok_rfc793; + PegCount rsts_ok_rfc5961; + PegCount rsts_in_window; + PegCount rsts_bad_seq; + PegCount rsts_ack_ok; + PegCount rsts_ack_bad; PegCount fins; PegCount meta_acks; PegCount total_packets_held; diff --git a/src/stream/tcp/tcp_normalizer.cc b/src/stream/tcp/tcp_normalizer.cc index c6acc6f89..f01526e5e 100644 --- a/src/stream/tcp/tcp_normalizer.cc +++ b/src/stream/tcp/tcp_normalizer.cc @@ -63,8 +63,8 @@ TcpNormalizer::NormStatus TcpNormalizer::apply_normalizations( break; } if (PacketTracer::is_active()) - PacketTracer::log("Current TCP window : [ %u - %u ]\n" - , tns.tracker->r_win_base, tns.tracker->r_win_base + tns.tracker->get_snd_wnd()); + PacketTracer::log("Current TCP window : [ %u - %u ]\n", + tns.tracker->r_win_base, tns.tracker->r_win_base + tns.tracker->get_snd_wnd()); tns.tracker->seglist.print_stream_state(tsd.get_talker()); trim_win_payload(tns, tsd, 0, inline_mode); return NORM_BAD_SEQ; @@ -354,52 +354,123 @@ uint32_t TcpNormalizer::get_tcp_timestamp( return TF_NONE; } -bool TcpNormalizer::validate_rst_seq_geq( +TcpNormalizer::RstStatus TcpNormalizer::validate_rst_seq_os_hpux11( TcpNormalizerState& tns, TcpSegmentDescriptor& tsd) { // FIXIT-M check for rcv_nxt == 0 is hack for uninitialized rcv_nxt if ( ( tns.tracker->rcv_nxt == 0 ) || SEQ_GEQ(tsd.get_seq(), tns.tracker->rcv_nxt) ) - return true; + { + if ( PacketTracer::is_active() ) + PacketTracer::log("stream_tcp: RST is valid for OS HPUX 11, seq %u >= rcv_nxt %u.\n", + tsd.get_seq(), tns.tracker->rcv_nxt); - return false; + tcpStats.rsts_ok_rfc793++; + return RST_OK; + } + + if ( PacketTracer::is_active() ) + PacketTracer::log("stream_tcp: RST is NOT valid for OS HPUX 11, seq %u rcv_nxt); + + tcpStats.rsts_bad_seq++; + return RST_BAD_SEQ; } -bool TcpNormalizer::validate_rst_end_seq_geq( +TcpNormalizer::RstStatus TcpNormalizer::is_rst_seq_valid_rfc793( TcpNormalizerState& tns, TcpSegmentDescriptor& tsd) { - // FIXIT-M check for r_win_base == 0 is hack for uninitialized r_win_base - if ( tns.tracker->r_win_base == 0 ) - return true; + uint32_t rst_seq = tsd.get_seq(); + uint32_t window = get_stream_window(tns, tsd); - if ( SEQ_GEQ(tsd.get_end_seq(), tns.tracker->r_win_base)) + if ( SEQ_GEQ(rst_seq, tns.tracker->r_win_base) ) { - // reset must be admitted when window closed - if (SEQ_LEQ(tsd.get_seq(), tns.tracker->r_win_base + get_stream_window(tns, tsd))) - return true; + if ( SEQ_LEQ(rst_seq, tns.tracker->r_win_base + window) ) + { + if ( PacketTracer::is_active() ) + PacketTracer::log("stream_tcp: RST is valid, seq %u is in window. Current TCP window : [ %u - %u ]\n", + rst_seq, tns.tracker->r_win_base, + tns.tracker->r_win_base + tns.tracker->get_snd_wnd()); + + tcpStats.rsts_ok_rfc793++; + return RST_OK; + } + else if ( window == 0 ) + { + if ( PacketTracer::is_active() ) + PacketTracer::log("stream_tcp: RST is valid, the window is closed, seq %u is >= base of window: %u\n", + rst_seq, tns.tracker->r_win_base); + + tcpStats.rsts_ok_rfc793++; + return RST_OK; + } } + + if ( PacketTracer::is_active() ) + PacketTracer::log("stream_tcp: RST is invalid, seq %u not in window. Current TCP window : [ %u - %u ]\n", + rst_seq, tns.tracker->r_win_base, + tns.tracker->r_win_base + tns.tracker->get_snd_wnd()); + + tcpStats.rsts_bad_seq++; + return RST_BAD_SEQ; - return false; } -bool TcpNormalizer::validate_rst_seq_eq( +TcpNormalizer::RstStatus TcpNormalizer::is_rst_seq_valid_rfc5961( TcpNormalizerState& tns, TcpSegmentDescriptor& tsd) { - uint32_t expected_seq = tns.tracker->r_win_base + tns.tracker->get_fin_seq_adjust(); + uint32_t rst_seq = tsd.get_seq(); + uint32_t window = get_stream_window(tns, tsd); + uint32_t my_rcv_nxt = tns.tracker->rcv_nxt + tns.tracker->get_fin_seq_adjust(); - if ( SEQ_EQ(tsd.get_seq(), expected_seq) ) - return true; + if ( SEQ_EQ(rst_seq, my_rcv_nxt) ) + { + if ( PacketTracer::is_active() ) + PacketTracer::log("stream_tcp: RST is valid, seq %u matches rcv_nxt %u.\n", + rst_seq, my_rcv_nxt); - return false; + tcpStats.rsts_ok_rfc5961++; + return RST_OK; + } + else if ( SEQ_GEQ(rst_seq, tns.tracker->r_win_base) ) + { + if ( SEQ_LEQ(rst_seq, tns.tracker->r_win_base + window) ) + { + if ( PacketTracer::is_active() ) + PacketTracer::log("stream_tcp: RST is valid, seq %u is in window. Current TCP window : [ %u - %u ]\n", + rst_seq, tns.tracker->r_win_base, + tns.tracker->r_win_base + tns.tracker->get_snd_wnd()); + + tcpStats.rsts_in_window++; + return RST_IN_WINDOW; + } + else if ( window == 0 ) + { + if ( PacketTracer::is_active() ) + PacketTracer::log("stream_tcp: RST is valid, the window is closed, seq %u is >= base of window: %u\n", + rst_seq, tns.tracker->r_win_base); + + tcpStats.rsts_ok_rfc5961++; + return RST_OK; + } + } + + if ( PacketTracer::is_active() ) + PacketTracer::log("stream_tcp: RST is invalid, seq %u is left of window base. Current TCP window : [ %u - %u ]\n", + rst_seq, tns.tracker->r_win_base, + tns.tracker->r_win_base + tns.tracker->get_snd_wnd()); + + tcpStats.rsts_bad_seq++; + return RST_BAD_SEQ; } -// per rfc 793 a rst is valid if the seq number is in window -// for all states but syn-sent (handled above). however, we -// validate here based on how various implementations actually -// handle a rst. -bool TcpNormalizer::validate_rst( +// The default validation is to check if the rst seq is in the window as +// specified in RFC 9293 and RFC 5961. The default method is used for +// all the modern OSes and for IPS mode (FIRST) when no specific OS policy +// is specified. +TcpNormalizer::RstStatus TcpNormalizer::validate_rst( TcpNormalizerState& tns, TcpSegmentDescriptor& tsd) { - return validate_rst_seq_eq(tns, tsd); + return is_rst_seq_valid_rfc5961(tns, tsd); } int TcpNormalizer::validate_paws_timestamp( diff --git a/src/stream/tcp/tcp_normalizer.h b/src/stream/tcp/tcp_normalizer.h index 0f1b0ae61..474bfc99b 100644 --- a/src/stream/tcp/tcp_normalizer.h +++ b/src/stream/tcp/tcp_normalizer.h @@ -65,6 +65,8 @@ class TcpNormalizer public: using State = TcpNormalizerState; enum NormStatus { NORM_BAD_SEQ = -1, NORM_TRIMMED = 0, NORM_OK = 1 }; + enum RstStatus { RST_BAD_ACK = -2, RST_BAD_SEQ = -1, + RST_OK = 1, RST_IN_WINDOW = 2 }; virtual ~TcpNormalizer() = default; @@ -86,7 +88,7 @@ public: virtual uint32_t data_inside_window(State&, TcpSegmentDescriptor&); virtual uint32_t get_tcp_timestamp(State&, TcpSegmentDescriptor&, bool strip); virtual int handle_paws(State&, TcpSegmentDescriptor&); - virtual bool validate_rst(State&, TcpSegmentDescriptor&); + virtual RstStatus validate_rst(State&, TcpSegmentDescriptor&); virtual int handle_repeated_syn(State&, TcpSegmentDescriptor&) = 0; virtual uint16_t set_urg_offset(State&, const snort::tcp::TCPHdr* tcph, uint16_t dsize); virtual void set_zwp_seq(State&, uint32_t seq); @@ -102,13 +104,13 @@ public: protected: TcpNormalizer() = default; - virtual bool trim_payload(State&, TcpSegmentDescriptor&, uint32_t, NormMode, PegCounts, - bool force = false); - virtual bool strip_tcp_timestamp( - State&, TcpSegmentDescriptor&, const snort::tcp::TcpOption*, NormMode); - virtual bool validate_rst_seq_geq(State&, TcpSegmentDescriptor&); - virtual bool validate_rst_end_seq_geq(State&, TcpSegmentDescriptor&); - virtual bool validate_rst_seq_eq(State&, TcpSegmentDescriptor&); + virtual bool trim_payload(State&, TcpSegmentDescriptor&, uint32_t, NormMode, + PegCounts, bool force = false); + virtual bool strip_tcp_timestamp(State&, TcpSegmentDescriptor&, + const snort::tcp::TcpOption*, NormMode); + virtual RstStatus validate_rst_seq_os_hpux11(State&, TcpSegmentDescriptor&); + virtual RstStatus is_rst_seq_valid_rfc793(State&, TcpSegmentDescriptor&); + virtual RstStatus is_rst_seq_valid_rfc5961(State&, TcpSegmentDescriptor&); virtual int validate_paws_timestamp(State&, TcpSegmentDescriptor&); virtual bool is_paws_ts_checked_required(State&, TcpSegmentDescriptor&); diff --git a/src/stream/tcp/tcp_normalizers.cc b/src/stream/tcp/tcp_normalizers.cc index 1c052c9b4..20d7e7a92 100644 --- a/src/stream/tcp/tcp_normalizers.cc +++ b/src/stream/tcp/tcp_normalizers.cc @@ -40,7 +40,6 @@ public: TcpNormalizerFirst() { my_name = "First"; } - int handle_repeated_syn(TcpNormalizerState&, TcpSegmentDescriptor&) override; }; @@ -50,7 +49,6 @@ public: TcpNormalizerLast() { my_name = "Last"; } - int handle_repeated_syn(TcpNormalizerState&, TcpSegmentDescriptor&) override; }; @@ -60,14 +58,12 @@ public: TcpNormalizerLinux() { my_name = "OS_Linux"; } - void init(TcpNormalizerState& tns) override { // Linux 2.6 accepts timestamp values that are off by one. so set fudge factor */ tns.paws_ts_fudge = 1; } - bool validate_rst(TcpNormalizerState&, TcpSegmentDescriptor&) override; bool is_paws_ts_checked_required(TcpNormalizerState&, TcpSegmentDescriptor&) override; int handle_repeated_syn(TcpNormalizerState&, TcpSegmentDescriptor&) override; }; @@ -78,11 +74,14 @@ public: TcpNormalizerOldLinux() { my_name = "OS_OldLinux"; } - void init(TcpNormalizerState& tns) override { tns.paws_drop_zero_ts = false; } - bool validate_rst(TcpNormalizerState&, TcpSegmentDescriptor&) override; + RstStatus validate_rst(TcpNormalizerState& tns, TcpSegmentDescriptor& tsd) override + { + return is_rst_seq_valid_rfc793(tns, tsd); + } + bool is_paws_ts_checked_required(TcpNormalizerState&, TcpSegmentDescriptor&) override; int handle_repeated_syn(TcpNormalizerState&, TcpSegmentDescriptor&) override; }; @@ -93,8 +92,6 @@ public: TcpNormalizerBSD() { my_name = "OS_BSD"; } - - bool validate_rst(TcpNormalizerState&, TcpSegmentDescriptor&) override; int handle_repeated_syn(TcpNormalizerState&, TcpSegmentDescriptor&) override; }; @@ -104,7 +101,6 @@ public: TcpNormalizerMacOS() { my_name = "OS_MacOS"; } - int handle_repeated_syn(TcpNormalizerState&, TcpSegmentDescriptor&) override; }; @@ -114,11 +110,14 @@ public: TcpNormalizerSolaris() { my_name = "OS_Solaris"; } - void init(TcpNormalizerState& tns) override { tns.paws_drop_zero_ts = false; } - bool validate_rst(TcpNormalizerState&, TcpSegmentDescriptor&) override; + RstStatus validate_rst(TcpNormalizerState& tns, TcpSegmentDescriptor& tsd) override + { + return is_rst_seq_valid_rfc793(tns, tsd); + } + int handle_repeated_syn(TcpNormalizerState&, TcpSegmentDescriptor&) override; }; @@ -128,6 +127,10 @@ public: TcpNormalizerIrix() { my_name = "OS_Irix"; } + RstStatus validate_rst(TcpNormalizerState& tns, TcpSegmentDescriptor& tsd) override + { + return is_rst_seq_valid_rfc793(tns, tsd); + } int handle_repeated_syn(TcpNormalizerState&, TcpSegmentDescriptor&) override; }; @@ -138,8 +141,7 @@ public: TcpNormalizerHpux11() { my_name = "OS_Hpux11"; } - - bool validate_rst(TcpNormalizerState&, TcpSegmentDescriptor&) override; + TcpNormalizer::RstStatus validate_rst(TcpNormalizerState&, TcpSegmentDescriptor&) override; bool is_paws_ts_checked_required(TcpNormalizerState&, TcpSegmentDescriptor&) override; int handle_repeated_syn(TcpNormalizerState&, TcpSegmentDescriptor&) override; }; @@ -150,6 +152,10 @@ public: TcpNormalizerHpux10() { my_name = "OS_Hpux10"; } + RstStatus validate_rst(TcpNormalizerState& tns, TcpSegmentDescriptor& tsd) override + { + return is_rst_seq_valid_rfc793(tns, tsd); + } int handle_repeated_syn(TcpNormalizerState&, TcpSegmentDescriptor&) override; }; @@ -160,7 +166,6 @@ public: TcpNormalizerWindows() { my_name = "OS_Windows"; } - void init(TcpNormalizerState& tns) override { tns.paws_drop_zero_ts = false; } @@ -174,10 +179,14 @@ public: TcpNormalizerWindows2K3() { my_name = "OS_Windows2K3"; } - void init(TcpNormalizerState& tns) override { tns.paws_drop_zero_ts = false; } + RstStatus validate_rst(TcpNormalizerState& tns, TcpSegmentDescriptor& tsd) override + { + return is_rst_seq_valid_rfc793(tns, tsd); + } + bool is_paws_ts_checked_required(TcpNormalizerState&, TcpSegmentDescriptor&) override; int handle_repeated_syn(TcpNormalizerState&, TcpSegmentDescriptor&) override; }; @@ -188,10 +197,14 @@ public: TcpNormalizerVista() { my_name = "OS_Vista"; } - void init(TcpNormalizerState& tns) override { tns.paws_drop_zero_ts = false; } + RstStatus validate_rst(TcpNormalizerState& tns, TcpSegmentDescriptor& tsd) override + { + return is_rst_seq_valid_rfc793(tns, tsd); + } + bool is_paws_ts_checked_required(TcpNormalizerState&, TcpSegmentDescriptor&) override; int handle_repeated_syn(TcpNormalizerState&, TcpSegmentDescriptor&) override; }; @@ -204,7 +217,7 @@ public: TcpNormalizer::NormStatus apply_normalizations( TcpNormalizerState&, TcpSegmentDescriptor&, uint32_t seq, bool stream_is_inorder) override; - bool validate_rst(TcpNormalizerState&, TcpSegmentDescriptor&) override; + TcpNormalizer::RstStatus validate_rst(TcpNormalizerState&, TcpSegmentDescriptor&) override; int handle_paws(TcpNormalizerState&, TcpSegmentDescriptor&) override; int handle_repeated_syn(TcpNormalizerState&, TcpSegmentDescriptor&) override; }; @@ -218,13 +231,13 @@ public: TcpNormalizer::NormStatus apply_normalizations( TcpNormalizerState&, TcpSegmentDescriptor&, uint32_t seq, bool stream_is_inorder) override; - bool validate_rst(TcpNormalizerState&, TcpSegmentDescriptor&) override; + TcpNormalizer::RstStatus validate_rst(TcpNormalizerState&, TcpSegmentDescriptor&) override; int handle_paws(TcpNormalizerState&, TcpSegmentDescriptor&) override; int handle_repeated_syn(TcpNormalizerState&, TcpSegmentDescriptor&) override; }; static inline int handle_repeated_syn_mswin( - TcpStreamTracker* talker, TcpStreamTracker* listener, + TcpStreamTracker* talker, const TcpStreamTracker* listener, const TcpSegmentDescriptor& tsd, TcpSession* session) { /* Windows has some strange behavior here. If the sequence of the reset is the @@ -272,7 +285,7 @@ static inline bool paws_3whs_zero_ts_not_supported( // Older Linux ( <= 2.2 kernel ), Win32 (non 2K3) allow the 3whs to use a 0 timestamp. static inline bool paws_3whs_zero_ts_supported( - TcpStreamTracker* talker, TcpStreamTracker* listener, const TcpSegmentDescriptor& tsd) + TcpStreamTracker* talker, const TcpStreamTracker* listener, const TcpSegmentDescriptor& tsd) { bool check_ts = true; @@ -323,12 +336,6 @@ int TcpNormalizerLast::handle_repeated_syn( return handle_repeated_syn_bsd(tns.peer_tracker, tsd, tns.session); } -bool TcpNormalizerLinux::validate_rst( - TcpNormalizerState& tns, TcpSegmentDescriptor& tsd) -{ - return validate_rst_end_seq_geq(tns, tsd); -} - bool TcpNormalizerLinux::is_paws_ts_checked_required( TcpNormalizerState& tns, TcpSegmentDescriptor&) { @@ -341,12 +348,6 @@ int TcpNormalizerLinux::handle_repeated_syn( return handle_repeated_syn_bsd(tns.peer_tracker, tsd, tns.session); } -bool TcpNormalizerOldLinux::validate_rst( - TcpNormalizerState& tns, TcpSegmentDescriptor& tsd) -{ - return validate_rst_end_seq_geq(tns, tsd); -} - bool TcpNormalizerOldLinux::is_paws_ts_checked_required( TcpNormalizerState& tns, TcpSegmentDescriptor& tsd) { @@ -359,12 +360,6 @@ int TcpNormalizerOldLinux::handle_repeated_syn( return handle_repeated_syn_bsd(tns.peer_tracker, tsd, tns.session); } -bool TcpNormalizerBSD::validate_rst( - TcpNormalizerState& tns, TcpSegmentDescriptor& tsd) -{ - return validate_rst_end_seq_geq(tns, tsd); -} - int TcpNormalizerBSD::handle_repeated_syn( TcpNormalizerState& tns, TcpSegmentDescriptor& tsd) { @@ -378,12 +373,6 @@ int TcpNormalizerMacOS::handle_repeated_syn( return ACTION_NOTHING; } -bool TcpNormalizerSolaris::validate_rst( - TcpNormalizerState& tns, TcpSegmentDescriptor& tsd) -{ - return validate_rst_end_seq_geq(tns, tsd); -} - int TcpNormalizerSolaris::handle_repeated_syn( TcpNormalizerState& tns, TcpSegmentDescriptor& tsd) { @@ -396,10 +385,10 @@ int TcpNormalizerIrix::handle_repeated_syn( return handle_repeated_syn_bsd(tns.peer_tracker, tsd, tns.session); } -bool TcpNormalizerHpux11::validate_rst( + TcpNormalizer::RstStatus TcpNormalizerHpux11::validate_rst( TcpNormalizerState& tns, TcpSegmentDescriptor& tsd) { - return validate_rst_seq_geq(tns, tsd); + return validate_rst_seq_os_hpux11(tns, tsd); } bool TcpNormalizerHpux11::is_paws_ts_checked_required( @@ -468,8 +457,8 @@ TcpNormalizer::NormStatus TcpNormalizerProxy::apply_normalizations( return NORM_OK; } -bool TcpNormalizerProxy::validate_rst(TcpNormalizerState&, TcpSegmentDescriptor&) -{ return true; } + TcpNormalizer::RstStatus TcpNormalizerProxy::validate_rst(TcpNormalizerState&, TcpSegmentDescriptor&) +{ return TcpNormalizer::RST_OK; } int TcpNormalizerProxy::handle_paws(TcpNormalizerState&, TcpSegmentDescriptor&) { return ACTION_NOTHING; } @@ -484,16 +473,16 @@ TcpNormalizer::NormStatus TcpNormalizerMissed3whs::apply_normalizations( return NORM_OK; } -bool TcpNormalizerMissed3whs::validate_rst( + TcpNormalizer::RstStatus TcpNormalizerMissed3whs::validate_rst( TcpNormalizerState& tns, TcpSegmentDescriptor& tsd) { if ( tns.session->flow->two_way_traffic() ) return tns.prev_norm->validate_rst(tns, tsd); if ( !tns.prev_norm->get_name().compare("OS_Hpux11") ) - return validate_rst_seq_geq(tns, tsd); + return validate_rst_seq_os_hpux11(tns, tsd); - return true; + return TcpNormalizer::RST_OK; } int TcpNormalizerMissed3whs::handle_paws(TcpNormalizerState&, TcpSegmentDescriptor&) @@ -584,4 +573,3 @@ TcpNormalizer* TcpNormalizerFactory::get_instance(Normalizer::Policy sp) assert( sp < Normalizer::Policy::MAX_NORM_POLICY ); return normalizers[sp]; } - diff --git a/src/stream/tcp/tcp_normalizers.h b/src/stream/tcp/tcp_normalizers.h index cce303476..0650908d4 100644 --- a/src/stream/tcp/tcp_normalizers.h +++ b/src/stream/tcp/tcp_normalizers.h @@ -90,7 +90,7 @@ public: int handle_paws(TcpSegmentDescriptor& tsd) { return norm->handle_paws(tns, tsd); } - bool validate_rst(TcpSegmentDescriptor& tsd) + TcpNormalizer::RstStatus validate_rst(TcpSegmentDescriptor& tsd) { return norm->validate_rst(tns, tsd); } int handle_repeated_syn(TcpSegmentDescriptor& tsd) diff --git a/src/stream/tcp/tcp_session.cc b/src/stream/tcp/tcp_session.cc index fc89334b4..3fdd087a6 100644 --- a/src/stream/tcp/tcp_session.cc +++ b/src/stream/tcp/tcp_session.cc @@ -417,7 +417,6 @@ bool TcpSession::handle_syn_on_reset_session(TcpSegmentDescriptor& tsd) } else if ( tcph->is_syn_only() ) { - flow->ssn_state.direction = FROM_CLIENT; flow->set_ttl(tsd.get_pkt(), true); init_session_on_syn(tsd); tcpStats.resyns++; @@ -426,7 +425,6 @@ bool TcpSession::handle_syn_on_reset_session(TcpSegmentDescriptor& tsd) } else if ( tcph->is_syn_ack() ) { - flow->ssn_state.direction = FROM_SERVER; flow->set_ttl(tsd.get_pkt(), false); init_session_on_synack(tsd); tcpStats.resyns++; @@ -483,22 +481,34 @@ void TcpSession::handle_data_on_syn(TcpSegmentDescriptor& tsd) } } -void TcpSession::update_session_on_rst(const TcpSegmentDescriptor& tsd, bool flush) +void TcpSession::update_session_on_rst( + TcpSegmentDescriptor& tsd, bool flush, TcpStreamTracker::TcpState next_state) { - Packet* p = tsd.get_pkt(); - if ( flush ) { + Packet* p = tsd.get_pkt(); + flush_listener(p, true); flush_talker(p, true); set_splitter(true, nullptr); set_splitter(false, nullptr); } + + TcpStreamTracker* listener = tsd.get_listener(); + listener->normalizer.trim_rst_payload(tsd); + + if ( listener->normalizer.is_tcp_ips_enabled() ) + listener->set_tcp_state(next_state); + + update_perf_base_state(TcpStreamTracker::TCP_CLOSING); + set_pkt_action_flag(ACTION_RST); + flow->set_session_flags(SSNFLAG_RESET); + // RST is valid, update the talker's TCP state tsd.get_talker()->update_on_rst_sent(); } -void TcpSession::update_paws_timestamps(TcpSegmentDescriptor& tsd) +void TcpSession::update_paws_timestamps(const TcpSegmentDescriptor& tsd) { TcpStreamTracker* listener = tsd.get_listener(); TcpStreamTracker* talker = tsd.get_talker(); @@ -519,12 +529,12 @@ void TcpSession::update_paws_timestamps(TcpSegmentDescriptor& tsd) } } -void TcpSession::check_for_session_hijack(TcpSegmentDescriptor& tsd) +void TcpSession::check_for_session_hijack(const TcpSegmentDescriptor& tsd) { TcpStreamTracker* listener = tsd.get_listener(); TcpStreamTracker* talker = tsd.get_talker(); - Packet* p = tsd.get_pkt(); + const Packet* p = tsd.get_pkt(); if ( !(p->pkth->flags & DAQ_PKT_FLAG_PRE_ROUTING) ) { if ( p->is_eth() ) @@ -725,7 +735,7 @@ void TcpSession::check_small_segment_threshold(const TcpSegmentDescriptor &tsd, void TcpSession::handle_data_segment(TcpSegmentDescriptor& tsd, bool flush) { TcpStreamTracker* listener = tsd.get_listener(); - TcpStreamTracker* talker = tsd.get_talker(); + const TcpStreamTracker* talker = tsd.get_talker(); if ( TcpStreamTracker::TCP_CLOSED != talker->get_tcp_state() ) { @@ -793,7 +803,7 @@ TcpStreamTracker::TcpState TcpSession::get_listener_state(const TcpSegmentDescri void TcpSession::check_for_repeated_syn(TcpSegmentDescriptor& tsd) { TcpStreamTracker* listener = tsd.get_listener(); - TcpStreamTracker* talker = tsd.get_talker(); + const TcpStreamTracker* talker = tsd.get_talker(); uint32_t action = ACTION_NOTHING; if ( !SEQ_EQ(tsd.get_seq(), talker->get_iss()) and @@ -1077,7 +1087,7 @@ int TcpSession::process(Packet* p) // check for and process meta-ack info first if present, the current listener is the // talker for the meta-ack... - DAQ_PktTcpAckData_t* tcp_mack = (DAQ_PktTcpAckData_t*)p->daq_msg->meta[DAQ_PKT_META_TCP_ACK_DATA]; + const DAQ_PktTcpAckData_t* tcp_mack = (DAQ_PktTcpAckData_t*)p->daq_msg->meta[DAQ_PKT_META_TCP_ACK_DATA]; if ( tcp_mack ) { TcpSegmentDescriptor ma_tsd(flow, p, tcp_mack->tcp_ack_seq_num, tcp_mack->tcp_window_size); @@ -1099,9 +1109,9 @@ int TcpSession::process(Packet* p) return process_tcp_packet(tsd, p); } -void TcpSession::init_new_tcp_session(TcpSegmentDescriptor& tsd) +void TcpSession::init_new_tcp_session(const TcpSegmentDescriptor& tsd) { - Packet* p = tsd.get_pkt(); + const Packet* p = tsd.get_pkt(); flow->pkt_type = p->type(); flow->ip_proto = (uint8_t)p->get_ip_proto_next(); @@ -1402,7 +1412,7 @@ void TcpSession::set_pseudo_established(Packet* p) bool TcpSession::check_for_one_sided_session(Packet* p) { - Flow& flow = *p->flow; + const Flow& flow = *p->flow; if ( 0 == ( (SSNFLAG_ESTABLISHED | SSNFLAG_TCP_PSEUDO_EST) & flow.ssn_state.session_flags ) && p->is_from_client_originally() ) { @@ -1438,7 +1448,7 @@ bool TcpSession::check_for_one_sided_session(Packet* p) void TcpSession::check_for_pseudo_established(Packet* p) { - Flow& flow = *p->flow; + const Flow& flow = *p->flow; if ( 0 == ( (SSNFLAG_ESTABLISHED | SSNFLAG_TCP_PSEUDO_EST) & flow.ssn_state.session_flags ) ) { if ( check_for_one_sided_session(p) ) diff --git a/src/stream/tcp/tcp_session.h b/src/stream/tcp/tcp_session.h index 88c0dc3d3..6b7f59fc1 100644 --- a/src/stream/tcp/tcp_session.h +++ b/src/stream/tcp/tcp_session.h @@ -86,11 +86,11 @@ public: TcpStreamTracker::TcpState get_peer_state(const TcpStreamTracker& me) { return me.client_tracker ? server.get_tcp_state() : client.get_tcp_state(); } - void init_new_tcp_session(TcpSegmentDescriptor&); + void init_new_tcp_session(const TcpSegmentDescriptor&); void update_perf_base_state(char new_state); void update_timestamp_tracking(TcpSegmentDescriptor&); - void update_paws_timestamps(TcpSegmentDescriptor&); - void update_session_on_rst(const TcpSegmentDescriptor&, bool); + void update_paws_timestamps(const TcpSegmentDescriptor&); + void update_session_on_rst(TcpSegmentDescriptor&, bool, TcpStreamTracker::TcpState); bool handle_syn_on_reset_session(TcpSegmentDescriptor&); void handle_data_on_syn(TcpSegmentDescriptor&); void update_ignored_session(TcpSegmentDescriptor&); @@ -113,7 +113,7 @@ public: bool is_data_transferred_asymmetrically() const; void check_for_repeated_syn(TcpSegmentDescriptor&); - void check_for_session_hijack(TcpSegmentDescriptor&); + void check_for_session_hijack(const TcpSegmentDescriptor&); bool check_for_window_slam(TcpSegmentDescriptor& tsd); void mark_packet_for_drop(TcpSegmentDescriptor&); void handle_data_segment(TcpSegmentDescriptor&, bool flush = true); diff --git a/src/stream/tcp/tcp_state_close_wait.cc b/src/stream/tcp/tcp_state_close_wait.cc index 49dc6961e..7034da222 100644 --- a/src/stream/tcp/tcp_state_close_wait.cc +++ b/src/stream/tcp/tcp_state_close_wait.cc @@ -111,14 +111,9 @@ bool TcpStateCloseWait::fin_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tr bool TcpStateCloseWait::rst_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) { - if ( trk.update_on_rst_recv(tsd) ) - { - trk.session->update_session_on_rst(tsd, true); - trk.session->update_perf_base_state(TcpStreamTracker::TCP_CLOSING); - trk.session->set_pkt_action_flag(ACTION_RST); + if ( trk.handle_rst_packet(tsd, true) == TcpNormalizer::RST_OK ) tsd.get_flow()->session_state |= STREAM_STATE_CLOSED; - } - + return true; } diff --git a/src/stream/tcp/tcp_state_closed.cc b/src/stream/tcp/tcp_state_closed.cc index 54f160d46..ce806f140 100644 --- a/src/stream/tcp/tcp_state_closed.cc +++ b/src/stream/tcp/tcp_state_closed.cc @@ -106,12 +106,7 @@ bool TcpStateClosed::fin_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) bool TcpStateClosed::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); - } + trk.handle_rst_packet(tsd, false); return true; } diff --git a/src/stream/tcp/tcp_state_closing.cc b/src/stream/tcp/tcp_state_closing.cc index 497b40ded..a151baec3 100644 --- a/src/stream/tcp/tcp_state_closing.cc +++ b/src/stream/tcp/tcp_state_closing.cc @@ -104,13 +104,8 @@ bool TcpStateClosing::fin_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) bool TcpStateClosing::rst_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) { - if ( trk.update_on_rst_recv(tsd) ) - { - trk.session->update_session_on_rst(tsd, true); - trk.session->update_perf_base_state(TcpStreamTracker::TCP_CLOSING); - trk.session->set_pkt_action_flag(ACTION_RST); + if ( trk.handle_rst_packet(tsd, true) == TcpNormalizer::RST_OK) tsd.get_flow()->session_state |= STREAM_STATE_CLOSED; - } return true; } diff --git a/src/stream/tcp/tcp_state_established.cc b/src/stream/tcp/tcp_state_established.cc index fef43f46e..96212b3b6 100644 --- a/src/stream/tcp/tcp_state_established.cc +++ b/src/stream/tcp/tcp_state_established.cc @@ -122,17 +122,11 @@ bool TcpStateEstablished::fin_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& bool TcpStateEstablished::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); + trk.handle_rst_packet(tsd, false); + return true; } diff --git a/src/stream/tcp/tcp_state_fin_wait1.cc b/src/stream/tcp/tcp_state_fin_wait1.cc index 588974255..cbee52bbc 100644 --- a/src/stream/tcp/tcp_state_fin_wait1.cc +++ b/src/stream/tcp/tcp_state_fin_wait1.cc @@ -115,17 +115,12 @@ bool TcpStateFinWait1::fin_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk bool TcpStateFinWait1::rst_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) { - if ( trk.update_on_rst_recv(tsd) ) - { - trk.session->update_session_on_rst(tsd, true); - trk.session->update_perf_base_state(TcpStreamTracker::TCP_CLOSING); - trk.session->set_pkt_action_flag(ACTION_RST); - tsd.get_flow()->session_state |= STREAM_STATE_CLOSED; - } - - // 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); + + if ( trk.handle_rst_packet(tsd, true) == TcpNormalizer::RST_OK ) + tsd.get_flow()->session_state |= STREAM_STATE_CLOSED; + return true; } diff --git a/src/stream/tcp/tcp_state_fin_wait2.cc b/src/stream/tcp/tcp_state_fin_wait2.cc index 50fa81e24..fcb5138fb 100644 --- a/src/stream/tcp/tcp_state_fin_wait2.cc +++ b/src/stream/tcp/tcp_state_fin_wait2.cc @@ -122,13 +122,8 @@ bool TcpStateFinWait2::fin_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk bool TcpStateFinWait2::rst_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) { - if ( trk.update_on_rst_recv(tsd) ) - { - trk.session->update_session_on_rst(tsd, true); - trk.session->update_perf_base_state(TcpStreamTracker::TCP_CLOSING); - trk.session->set_pkt_action_flag(ACTION_RST); + if ( trk.handle_rst_packet(tsd, true) == TcpNormalizer::RST_OK ) tsd.get_flow()->session_state |= STREAM_STATE_CLOSED; - } return true; } diff --git a/src/stream/tcp/tcp_state_last_ack.cc b/src/stream/tcp/tcp_state_last_ack.cc index 123b59fab..f5df4260f 100644 --- a/src/stream/tcp/tcp_state_last_ack.cc +++ b/src/stream/tcp/tcp_state_last_ack.cc @@ -97,16 +97,11 @@ bool TcpStateLastAck::fin_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) bool TcpStateLastAck::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); + + trk.handle_rst_packet(tsd, false); + return true; } diff --git a/src/stream/tcp/tcp_state_mid_stream_recv.cc b/src/stream/tcp/tcp_state_mid_stream_recv.cc index 89231b6b1..127fbbca0 100644 --- a/src/stream/tcp/tcp_state_mid_stream_recv.cc +++ b/src/stream/tcp/tcp_state_mid_stream_recv.cc @@ -142,17 +142,11 @@ bool TcpStateMidStreamRecv::fin_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker 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); + trk.handle_rst_packet(tsd, false); + return true; } diff --git a/src/stream/tcp/tcp_state_mid_stream_sent.cc b/src/stream/tcp/tcp_state_mid_stream_sent.cc index 65c91d853..31170513c 100644 --- a/src/stream/tcp/tcp_state_mid_stream_sent.cc +++ b/src/stream/tcp/tcp_state_mid_stream_sent.cc @@ -131,17 +131,11 @@ bool TcpStateMidStreamSent::fin_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker 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); + trk.handle_rst_packet(tsd, false); + return true; } diff --git a/src/stream/tcp/tcp_state_none.cc b/src/stream/tcp/tcp_state_none.cc index 34bb398a3..899a4c2d3 100644 --- a/src/stream/tcp/tcp_state_none.cc +++ b/src/stream/tcp/tcp_state_none.cc @@ -40,9 +40,6 @@ TcpStateNone::TcpStateNone(TcpStateMachine& tsm) : bool TcpStateNone::syn_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) { - Flow* flow = tsd.get_flow(); - flow->ssn_state.direction = FROM_CLIENT; - trk.init_on_syn_sent(tsd); trk.session->init_new_tcp_session(tsd); return true; @@ -84,13 +81,7 @@ bool TcpStateNone::data_seg_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tr bool TcpStateNone::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); - } - + trk.handle_rst_packet(tsd, false); return true; } diff --git a/src/stream/tcp/tcp_state_syn_recv.cc b/src/stream/tcp/tcp_state_syn_recv.cc index bd1e1e48f..671b5d296 100644 --- a/src/stream/tcp/tcp_state_syn_recv.cc +++ b/src/stream/tcp/tcp_state_syn_recv.cc @@ -46,10 +46,7 @@ bool TcpStateSynRecv::syn_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) flow->set_session_flags(SSNFLAG_ECN_SERVER_REPLY); if ( tsd.is_packet_from_server() ) - { - flow->set_session_flags(SSNFLAG_SEEN_SERVER); trk.session->tel.set_tcp_event(EVENT_4WHS); - } return true; } @@ -172,23 +169,14 @@ bool TcpStateSynRecv::fin_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) bool TcpStateSynRecv::rst_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) { - trk.normalizer.trim_rst_payload(tsd); - if ( trk.normalizer.validate_rst(tsd) ) - { - Flow* flow = tsd.get_flow(); - flow->set_session_flags(SSNFLAG_RESET); - } - else - { - trk.session->tel.set_tcp_event(EVENT_BAD_RST); - trk.normalizer.packet_dropper(tsd, NORM_TCP_BLOCK); - trk.session->set_pkt_action_flag(ACTION_BAD_PKT); - } - - // FIXIT-L might be good to create alert specific to RST with data + TcpStreamTracker::TcpState next_state = trk.is_client_tracker() ? + TcpStreamTracker::TCP_CLOSED : TcpStreamTracker::TCP_LISTEN; + if ( tsd.is_data_segment() ) trk.session->tel.set_tcp_event(EVENT_DATA_AFTER_RST_RCVD); + trk.handle_rst_packet(tsd, false, next_state); + return true; } diff --git a/src/stream/tcp/tcp_state_syn_sent.cc b/src/stream/tcp/tcp_state_syn_sent.cc index a3d635b64..a0b5c9b7a 100644 --- a/src/stream/tcp/tcp_state_syn_sent.cc +++ b/src/stream/tcp/tcp_state_syn_sent.cc @@ -173,19 +173,18 @@ bool TcpStateSynSent::fin_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) bool TcpStateSynSent::rst_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) { - if ( trk.update_on_rst_recv(tsd) ) + if ( trk.is_rst_valid_syn_sent(tsd) == TcpNormalizer::RST_OK ) { - trk.session->update_session_on_rst(tsd, false); + tsd.get_talker()->update_on_rst_sent(); trk.set_tcp_state(TcpStreamTracker::TCP_CLOSED); trk.session->update_perf_base_state(TcpStreamTracker::TCP_CLOSED); trk.session->set_pkt_action_flag(ACTION_RST); tsd.get_flow()->session_state |= STREAM_STATE_CLOSED; - } - - // 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); + if ( tsd.is_data_segment() ) + trk.session->tel.set_tcp_event(EVENT_DATA_AFTER_RST_RCVD); + } + return true; } diff --git a/src/stream/tcp/tcp_state_time_wait.cc b/src/stream/tcp/tcp_state_time_wait.cc index bdbf30c46..706f75afc 100644 --- a/src/stream/tcp/tcp_state_time_wait.cc +++ b/src/stream/tcp/tcp_state_time_wait.cc @@ -82,16 +82,11 @@ bool TcpStateTimeWait::fin_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk bool TcpStateTimeWait::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); - } - if ( tsd.is_data_segment() ) trk.session->tel.set_tcp_event(EVENT_DATA_AFTER_RST_RCVD); + trk.handle_rst_packet(tsd, false); + return true; } diff --git a/src/stream/tcp/tcp_stream_tracker.cc b/src/stream/tcp/tcp_stream_tracker.cc index 4cd432398..81c17eb0d 100644 --- a/src/stream/tcp/tcp_stream_tracker.cc +++ b/src/stream/tcp/tcp_stream_tracker.cc @@ -192,7 +192,7 @@ TcpStreamTracker::TcpEvent TcpStreamTracker::set_tcp_event(const TcpSegmentDescr else if ( tcph->is_rst() ) { tcp_event = TCP_RST_RECV_EVENT; - tcpStats.resets++; + tcpStats.rsts++; } else if ( tcph->is_fin( ) ) { @@ -480,7 +480,6 @@ void TcpStreamTracker::disable_reassembly(Flow* f) void TcpStreamTracker::init_on_syn_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); @@ -516,7 +515,6 @@ void TcpStreamTracker::init_on_syn_recv(const TcpSegmentDescriptor& tsd) void TcpStreamTracker::init_on_synack_sent(TcpSegmentDescriptor& tsd) { - tsd.get_flow()->set_session_flags(SSNFLAG_SEEN_SERVER); if (tsd.get_tcph()->are_flags_set(TH_CWR | TH_ECE)) tsd.get_flow()->set_session_flags(SSNFLAG_ECN_SERVER_REPLY); @@ -563,13 +561,6 @@ void TcpStreamTracker::init_on_synack_recv(const TcpSegmentDescriptor& tsd) void TcpStreamTracker::init_on_data_seg_sent(TcpSegmentDescriptor& tsd) { - Flow* flow = tsd.get_flow(); - - if ( flow->ssn_state.direction == FROM_CLIENT ) - flow->set_session_flags(SSNFLAG_SEEN_CLIENT); - else - flow->set_session_flags(SSNFLAG_SEEN_SERVER); - iss = tsd.get_seq() - 1; irs = tsd.get_ack() - 1; snd_una = tsd.get_seq(); @@ -728,26 +719,64 @@ bool TcpStreamTracker::update_on_3whs_ack(TcpSegmentDescriptor& tsd) return good_ack; } -bool TcpStreamTracker::update_on_rst_recv(TcpSegmentDescriptor& tsd) +void TcpStreamTracker::update_on_bad_rst(TcpSegmentDescriptor& tsd) { - normalizer.trim_rst_payload(tsd); - bool good_rst = normalizer.validate_rst(tsd); - if ( good_rst ) - { - Flow* flow = tsd.get_flow(); + session->tel.set_tcp_event(EVENT_BAD_RST); + normalizer.packet_dropper(tsd, NORM_TCP_BLOCK); + session->set_pkt_action_flag(ACTION_BAD_PKT); +} - flow->set_session_flags(SSNFLAG_RESET); - if ( normalizer.is_tcp_ips_enabled() ) - tcp_state = TcpStreamTracker::TCP_CLOSED; +TcpNormalizer::RstStatus TcpStreamTracker::is_rst_valid_syn_sent(TcpSegmentDescriptor& tsd) +{ + // ack number must ack syn seq + TcpNormalizer::RstStatus rst_status = SEQ_EQ(tsd.get_ack(), snd_nxt) ? + TcpNormalizer::RST_OK : TcpNormalizer::RST_BAD_ACK; + if ( rst_status == TcpNormalizer::RST_OK ) + { + if ( PacketTracer::is_active() ) + PacketTracer::log("stream_tcp: RST is valid in SYN-SENT state, ack %u == snd_nxt %u.\n", + tsd.get_ack(), snd_nxt); + + tcpStats.rsts_ack_ok++; } else { - session->tel.set_tcp_event(EVENT_BAD_RST); - normalizer.packet_dropper(tsd, NORM_TCP_BLOCK); - session->set_pkt_action_flag(ACTION_BAD_PKT); + if ( PacketTracer::is_active() ) + PacketTracer::log("stream_tcp: RST is NOT valid in SYN-SENT state, ack %u != snd_nxt %u.\n", + tsd.get_ack(), snd_nxt); + tcpStats.rsts_ack_bad++; + update_on_bad_rst(tsd); + } + + return rst_status; +} + +TcpNormalizer::RstStatus TcpStreamTracker::handle_rst_packet(TcpSegmentDescriptor& tsd, bool flush, + TcpStreamTracker::TcpState next_state) +{ + // seq number of RST must be in receiver's window + TcpNormalizer::RstStatus rst_status = normalizer.validate_rst(tsd); + switch ( rst_status ) + { + case TcpNormalizer::RST_OK: + session->update_session_on_rst(tsd, flush, next_state); + break; + + case TcpNormalizer::RST_IN_WINDOW: + // per RFC 5961, RSTs in window but not exact match do not cause the + // connection to be closed immediately. Trim the payload but otherwise + // ignore the RST and let the packet be sent. + normalizer.trim_rst_payload(tsd); + break; + + case TcpNormalizer::RST_BAD_ACK: + case TcpNormalizer::RST_BAD_SEQ: + default: + update_on_bad_rst(tsd); + break; } - return good_rst; + return rst_status; } void TcpStreamTracker::update_on_rst_sent() diff --git a/src/stream/tcp/tcp_stream_tracker.h b/src/stream/tcp/tcp_stream_tracker.h index cd93c2be4..a39f9c437 100644 --- a/src/stream/tcp/tcp_stream_tracker.h +++ b/src/stream/tcp/tcp_stream_tracker.h @@ -220,10 +220,6 @@ public: return valid; } - // ack number must ack syn - bool is_rst_valid_in_syn_sent(const TcpSegmentDescriptor& tsd) const - { return tsd.get_ack() == snd_una; } - uint32_t get_ts_last() const { return ts_last; } @@ -293,7 +289,10 @@ public: void update_tracker_no_ack_recv(const TcpSegmentDescriptor&); void update_tracker_no_ack_sent(const TcpSegmentDescriptor&); bool update_on_3whs_ack(TcpSegmentDescriptor&); - bool update_on_rst_recv(TcpSegmentDescriptor&); + void update_on_bad_rst(TcpSegmentDescriptor&); + TcpNormalizer::RstStatus is_rst_valid_syn_sent(TcpSegmentDescriptor&); + TcpNormalizer::RstStatus handle_rst_packet(TcpSegmentDescriptor&, bool flush, + TcpStreamTracker::TcpState next_state = TcpStreamTracker::TCP_CLOSED); void update_on_rst_sent(); bool update_on_fin_recv(TcpSegmentDescriptor&); bool update_on_fin_sent(TcpSegmentDescriptor&);