]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
Pull request #4923: stream_tcp: enhance rst validation to follow RFC 5961 recommendations
authorDavis McPherson -X (davmcphe - XORIANT CORPORATION at Cisco) <davmcphe@cisco.com>
Sat, 18 Oct 2025 00:23:46 +0000 (00:23 +0000)
committerSteven Baigal (sbaigal) <sbaigal@cisco.com>
Sat, 18 Oct 2025 00:23:46 +0000 (00:23 +0000)
Merge in SNORT/snort3 from ~DAVMCPHE/snort3:stream_tcp_rst_handling to master

Squashed commit of the following:

commit f355fb9799470aae71c2f6b13cea98d981e0ba68
Author: davis mcpherson <davmcphe@cisco.com>
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

23 files changed:
src/stream/tcp/tcp_module.cc
src/stream/tcp/tcp_module.h
src/stream/tcp/tcp_normalizer.cc
src/stream/tcp/tcp_normalizer.h
src/stream/tcp/tcp_normalizers.cc
src/stream/tcp/tcp_normalizers.h
src/stream/tcp/tcp_session.cc
src/stream/tcp/tcp_session.h
src/stream/tcp/tcp_state_close_wait.cc
src/stream/tcp/tcp_state_closed.cc
src/stream/tcp/tcp_state_closing.cc
src/stream/tcp/tcp_state_established.cc
src/stream/tcp/tcp_state_fin_wait1.cc
src/stream/tcp/tcp_state_fin_wait2.cc
src/stream/tcp/tcp_state_last_ack.cc
src/stream/tcp/tcp_state_mid_stream_recv.cc
src/stream/tcp/tcp_state_mid_stream_sent.cc
src/stream/tcp/tcp_state_none.cc
src/stream/tcp/tcp_state_syn_recv.cc
src/stream/tcp/tcp_state_syn_sent.cc
src/stream/tcp/tcp_state_time_wait.cc
src/stream/tcp/tcp_stream_tracker.cc
src/stream/tcp/tcp_stream_tracker.h

index 63e83fc70e255e523922c7e15c2d3ecee371551d..913208ddf941e03d2eef95bfbf786984e157f396 100644 (file)
@@ -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<PegCount*>(&tcpStats); }
 
 void StreamTcpModule::reset_stats()
 {
index 5d7b3814d5de5523c6ef32f276e65ddeb8fd5631..50d5d9b52b742388d7176579faba0282cf2220a8 100644 (file)
@@ -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;
index c6acc6f899464054cf8e22390f93e491d4cfedca..f01526e5e1f3674e12c92c0a17fe0cfb68a00f4c 100644 (file)
@@ -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 %u.\n",
+            tsd.get_seq(), tns.tracker->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(
index 0f1b0ae61d5debe65d1cf1b0d8a47e6f3689d280..474bfc99b2d03d8dfe73793da6e49abb36234742 100644 (file)
@@ -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&);
index 1c052c9b4bafdd5b30b0990913eed07d20356f47..20d7e7a9210e907020500a13a5bb5d99eb4f69f2 100644 (file)
@@ -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];
 }
-
index cce3034761e80bf8a8522994e2c17c7642fc877e..0650908d439d9ed609f8ac9b6ccc60052a6fbd44 100644 (file)
@@ -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)
index fc89334b457b1ba88aa048138cf1bbb4e455d061..3fdd087a60e5b3f80ade658d3ecacfbd1f05d16d 100644 (file)
@@ -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) )
index 88c0dc3d351aae7d7f7a98a013f8440905e2969d..6b7f59fc1cc7c5b6d2344f4508aa0319a8fcd75c 100644 (file)
@@ -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);
index 49dc6961e2f0d0d0c15d4e52a0f4d6aaf74be0a3..7034da222294510ed78b672dd7893afc3e742759 100644 (file)
@@ -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;
 }
 
index 54f160d4648daf952618ad11615b6795cdcec887..ce806f14079f37186987b5e0c39658a54b2bcacc 100644 (file)
@@ -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;
 }
index 497b40deda42a5dd8355f9978366e1fa966cf400..a151baec3d3a6215882082e604e843c6f414fa14 100644 (file)
@@ -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;
 }
index fef43f46e9286340d2187c2e43638658ddf6bab1..96212b3b6cb1fe49258860d43d9cca3fb4a68182 100644 (file)
@@ -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;
 }
 
index 588974255f6ccee82d0205b707d6ad82090dbf98..cbee52bbcb0c3dd56fc7841b26ad0f98fb3ce6b0 100644 (file)
@@ -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;
 }
 
index 50fa81e2422eabe308fa7eb20ae455ea88b70503..fcb5138fbb490171651f2ef07f3990610204a80a 100644 (file)
@@ -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;
 }
index 123b59fabfe1a79a673805e50868780d5a60e61e..f5df4260f4e98730438931079ef14ad6b3f0ccf2 100644 (file)
@@ -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;
 }
 
index 89231b6b1302773e9d746ec86100b80ebadba711..127fbbca0ab6d66533cd8ac07e875eee749c19c3 100644 (file)
@@ -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;
 }
 
index 65c91d853c42617ff9f70f3a647c7e0bdce8b899..31170513c0c92698ac5559f66eb6f12db63c1575 100644 (file)
@@ -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;
 }
 
index 34bb398a39b253262eff5b11c218dd163c033c31..899a4c2d39afd67eaa729b160470a05eca9b5796 100644 (file)
@@ -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;
 }
 
index bd1e1e48f0edc23b09efa3bd13f2b1aadae74714..671b5d296552748ad137c3f1e382e491f5e9f42b 100644 (file)
@@ -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;
 }
 
index a3d635b640f919ae3cf351c860b5c38d52d97014..a0b5c9b7a41ee3193aef6fff240fd419c1960f13 100644 (file)
@@ -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;
 }
 
index bdbf30c46b6c0b0df26f2bef75e3b3d57def95e7..706f75afc29b2aa9e6cd4d3ce8e200f999a96961 100644 (file)
@@ -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;
 }
 
index 4cd4323984542cd26d2f788dad2c2c3d42bbd03d..81c17eb0da054bd5145fdc12ef1dc7120c3f9a26 100644 (file)
@@ -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()
index cd93c2be41b07666bcc2483eaf610d47c9ae78f1..a39f9c43706077711eb411e4877b7e59333d93bb 100644 (file)
@@ -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&);