]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
Pull request #4227: stream_tcp: implement support for proxy mode normalization behavior
authorDavis McPherson -X (davmcphe - XORIANT CORPORATION at Cisco) <davmcphe@cisco.com>
Wed, 6 Mar 2024 14:07:31 +0000 (14:07 +0000)
committerSteven Baigal (sbaigal) <sbaigal@cisco.com>
Wed, 6 Mar 2024 14:07:31 +0000 (14:07 +0000)
Merge in SNORT/snort3 from ~DAVMCPHE/snort3:stream_tcp_proxy to master

Squashed commit of the following:

commit 82260056aa6c8e53a7d6fed23e77ebaf75d8c337
Author: davis mcpherson <davmcphe@cisco.com>
Date:   Thu Feb 22 11:44:08 2024 -0500

    stream_tcp: implement support for proxy mode normalization behavior

src/stream/stream.cc
src/stream/stream.h
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_stream_session.cc

index 4f1aba342a9320b81df6a4bd761f296a7347753e..ccc6c527c83910745eb8014247f0a623ea5b694c 100644 (file)
@@ -233,6 +233,14 @@ int Stream::ignore_flow(
         ctrlPkt, type, ip_proto, srcIP, srcPort, dstIP, dstPort, direction, fd);
 }
 
+void Stream::start_proxy(Flow* flow)
+{
+    assert(flow and flow->session and flow->pkt_type == PktType::TCP);
+
+    TcpStreamSession* tcp_session = (TcpStreamSession*)flow->session;
+    tcp_session->start_proxy();
+}
+
 void Stream::stop_inspection(
     Flow* flow, Packet* p, char dir,
     int32_t /*bytes*/, int /*response*/)
index b9656980e66a04453cc840190562cf994e95cd02..2c03e87620ad9bdd33d93bb54aec669f61fbd41d 100644 (file)
@@ -114,6 +114,10 @@ public:
     // packet_flags field of the Packet struct to indicate the direction determined.
     static uint32_t get_packet_direction(Packet*);
 
+    // Set the stream normalization mode to PROXY.  In this mode wire packets go thru a proxy before snort
+    // sees them.  All stream normalizations are turned off in this mode.
+    static void start_proxy(Flow*);
+
     // Stop inspection on a flow for up to count bytes (-1 to ignore for life or until resume).
     // If response flag is set, automatically resume inspection up to count bytes when a data
     // packet in the other direction is seen.  Also marks the packet to be ignored
index 93e8fdb0ffab621a10ec1c217bbd3aaec82fdb66..49ece67d950e32a3a3843a0ceffa8ef1bb6e2022 100644 (file)
@@ -116,6 +116,7 @@ const PegInfo tcp_pegs[] =
     { CountType::MAX, "max_bytes", "maximum number of bytes queued in any flow" },
     { CountType::SUM, "zero_len_tcp_opt", "number of zero length tcp options" },
     { CountType::SUM, "zero_win_probes", "number of tcp zero window probes" },
+    { CountType::SUM, "proxy_mode_flows", "number of flows set to proxy normalization policy" },
     { CountType::END, nullptr, nullptr }
 };
 
index 07a6c1a0de9201ea89e39007f9ad58f7f9a9c7f9..3188ffc39eeacbe0249d6ad8b1b393a652309c5e 100644 (file)
@@ -116,6 +116,7 @@ struct TcpStats
     PegCount max_bytes;
     PegCount zero_len_tcp_opt;
     PegCount zero_win_probes;
+    PegCount proxy_mode_flows;
 };
 
 extern THREAD_LOCAL struct TcpStats tcpStats;
index 1f94bb8ab440969f2b52b1e4eeca0676b450ce56..586925ab4e31a1d09635c28da9f1cb28a545d821 100644 (file)
@@ -25,6 +25,8 @@
 
 #include "tcp_normalizer.h"
 
+#include "stream/stream.h"
+
 #include "tcp_module.h"
 #include "tcp_stream_session.h"
 #include "tcp_stream_tracker.h"
 
 using namespace snort;
 
+TcpNormalizer::NormStatus TcpNormalizer::apply_normalizations(
+    TcpNormalizerState& tns, TcpSegmentDescriptor& tsd, uint32_t seq, bool stream_is_inorder)
+{
+    // if this is a midstream pickup then skip normalizations
+    if ( Stream::is_midstream(tsd.get_flow()) )
+        return NORM_OK;
+
+    // these normalizations can't be done if we missed setup. and
+    // window is zero in one direction until we've seen both sides.
+    if ( tsd.get_flow()->two_way_traffic() )
+    {
+        // drop packet if sequence num is invalid
+        if ( !tns.tracker->is_segment_seq_valid(tsd) )
+        {
+            tcpStats.invalid_seq_num++;
+            trim_win_payload(tns, tsd);
+            return NORM_BAD_SEQ;
+        }
+
+        // trim to fit in listener's window and mss
+        trim_win_payload(tns, tsd,
+            (tns.tracker->r_win_base + tns.tracker->get_snd_wnd() - tns.tracker->rcv_nxt));
+
+        if ( tns.tracker->get_mss() )
+            trim_mss_payload(tns, tsd, tns.tracker->get_mss());
+
+        ecn_stripper(tns, tsd);
+    }
+
+    if ( stream_is_inorder )
+    {
+        if ( get_stream_window(tns, tsd) == 0 )
+        {
+            if ( !data_inside_window(tns, tsd) )
+            {
+                trim_win_payload(tns, tsd, 0, tsd.is_nap_policy_inline());
+                return NORM_TRIMMED;
+            }
+
+            if ( tns.tracker->get_iss() )
+            {
+                tcpStats.zero_win_probes++;
+                set_zwp_seq(tns, seq);
+                trim_win_payload(tns, tsd, MAX_ZERO_WIN_PROBE_LEN, tsd.is_nap_policy_inline());
+            }
+        }
+    }
+    else if ( get_stream_window(tns, tsd) == 0 )
+    {
+        if ( SEQ_EQ(seq, get_zwp_seq(tns)) )
+        {
+            tcpStats.zero_win_probes++;
+            trim_win_payload(tns, tsd, MAX_ZERO_WIN_PROBE_LEN, tsd.is_nap_policy_inline());
+            return NORM_TRIMMED;
+        }
+
+        trim_win_payload(tns, tsd, 0, tsd.is_nap_policy_inline());
+        return NORM_TRIMMED;
+    }
+
+    return NORM_OK;
+}
+
 bool TcpNormalizer::trim_payload(TcpNormalizerState&, TcpSegmentDescriptor& tsd, uint32_t max,
     NormMode mode, PegCounts peg, bool force)
 {
index de331344c88f7af309f24d4ac7867a83e56ad4d8..10b119af95ef3a0e8980c5bda0b711653b6e53b3 100644 (file)
@@ -61,10 +61,14 @@ class TcpNormalizer
 {
 public:
     using State = TcpNormalizerState;
+    enum NormStatus { NORM_BAD_SEQ = -1, NORM_TRIMMED = 0, NORM_OK = 1 };
 
     virtual ~TcpNormalizer() = default;
 
     virtual void init(State&) { }
+
+    virtual NormStatus apply_normalizations(
+        State&, TcpSegmentDescriptor&, uint32_t seq, bool stream_is_inorder);
     virtual void session_blocker(State&, TcpSegmentDescriptor&);
     virtual bool packet_dropper(State&, TcpSegmentDescriptor&, NormFlags);
     virtual bool trim_syn_payload(State&, TcpSegmentDescriptor&, uint32_t max = 0);
@@ -86,6 +90,9 @@ public:
 
     static void reset_stats();
 
+    std::string& get_name()
+    { return my_name; }
+
 protected:
     TcpNormalizer() = default;
 
@@ -101,6 +108,8 @@ protected:
     virtual bool is_paws_ts_checked_required(State&, TcpSegmentDescriptor&);
     virtual int validate_paws(State&, TcpSegmentDescriptor&);
     virtual int handle_paws_no_timestamps(State&, TcpSegmentDescriptor&);
+
+    std::string my_name;
 };
 
 #endif
index fb44a089c77c209669f8d14b9e74c63e98dfc08e..4baa058dbff1397839fd4f2559ad5e7478d1dcfb 100644 (file)
@@ -35,7 +35,9 @@ using namespace snort;
 class TcpNormalizerFirst : public TcpNormalizer
 {
 public:
-    TcpNormalizerFirst() = default;
+    TcpNormalizerFirst()
+    { my_name = "OS_First"; }
+
 
     int handle_repeated_syn(TcpNormalizerState&, TcpSegmentDescriptor&) override;
 };
@@ -43,7 +45,9 @@ public:
 class TcpNormalizerLast : public TcpNormalizer
 {
 public:
-    TcpNormalizerLast() = default;
+    TcpNormalizerLast()
+    { my_name = "OS_Last"; }
+
 
     int handle_repeated_syn(TcpNormalizerState&, TcpSegmentDescriptor&) override;
 };
@@ -51,7 +55,9 @@ public:
 class TcpNormalizerLinux : public TcpNormalizer
 {
 public:
-    TcpNormalizerLinux() = default;
+    TcpNormalizerLinux()
+    { my_name = "OS_Linux"; }
+
 
     void init(TcpNormalizerState& tns) override
     {
@@ -67,7 +73,9 @@ public:
 class TcpNormalizerOldLinux : public TcpNormalizer
 {
 public:
-    TcpNormalizerOldLinux() = default;
+    TcpNormalizerOldLinux()
+    { my_name = "OS_OldLinux"; }
+
 
     void init(TcpNormalizerState& tns) override
     { tns.paws_drop_zero_ts = false; }
@@ -80,7 +88,9 @@ public:
 class TcpNormalizerBSD : public TcpNormalizer
 {
 public:
-    TcpNormalizerBSD() = default;
+    TcpNormalizerBSD()
+    { my_name = "OS_BSD"; }
+
 
     bool validate_rst(TcpNormalizerState&, TcpSegmentDescriptor&) override;
     int handle_repeated_syn(TcpNormalizerState&, TcpSegmentDescriptor&) override;
@@ -89,7 +99,9 @@ public:
 class TcpNormalizerMacOS : public TcpNormalizer
 {
 public:
-    TcpNormalizerMacOS() = default;
+    TcpNormalizerMacOS()
+    { my_name = "OS_MacOS"; }
+
 
     int handle_repeated_syn(TcpNormalizerState&, TcpSegmentDescriptor&) override;
 };
@@ -97,7 +109,9 @@ public:
 class TcpNormalizerSolaris : public TcpNormalizer
 {
 public:
-    TcpNormalizerSolaris() = default;
+    TcpNormalizerSolaris()
+    { my_name = "OS_Solaris"; }
+
 
     void init(TcpNormalizerState& tns) override
     { tns.paws_drop_zero_ts = false; }
@@ -109,7 +123,9 @@ public:
 class TcpNormalizerIrix : public TcpNormalizer
 {
 public:
-    TcpNormalizerIrix() = default;
+    TcpNormalizerIrix()
+    { my_name = "OS_Irix"; }
+
 
     int handle_repeated_syn(TcpNormalizerState&, TcpSegmentDescriptor&) override;
 };
@@ -117,7 +133,9 @@ public:
 class TcpNormalizerHpux11 : public TcpNormalizer
 {
 public:
-    TcpNormalizerHpux11() = default;
+    TcpNormalizerHpux11()
+    { my_name = "OS_Hpux11"; }
+
 
     bool validate_rst(TcpNormalizerState&, TcpSegmentDescriptor&) override;
     bool is_paws_ts_checked_required(TcpNormalizerState&, TcpSegmentDescriptor&) override;
@@ -127,7 +145,9 @@ public:
 class TcpNormalizerHpux10 : public TcpNormalizer
 {
 public:
-    TcpNormalizerHpux10() = default;
+    TcpNormalizerHpux10()
+    { my_name = "OS_Hpux10"; }
+
 
     int handle_repeated_syn(TcpNormalizerState&, TcpSegmentDescriptor&) override;
 };
@@ -135,7 +155,9 @@ public:
 class TcpNormalizerWindows : public TcpNormalizer
 {
 public:
-    TcpNormalizerWindows() = default;
+    TcpNormalizerWindows()
+    { my_name = "OS_Windows"; }
+
 
     void init(TcpNormalizerState& tns) override
     { tns.paws_drop_zero_ts = false; }
@@ -147,7 +169,9 @@ public:
 class TcpNormalizerWindows2K3 : public TcpNormalizer
 {
 public:
-    TcpNormalizerWindows2K3() = default;
+    TcpNormalizerWindows2K3()
+    { my_name = "OS_Windows2K3"; }
+
 
     void init(TcpNormalizerState& tns) override
     { tns.paws_drop_zero_ts = false; }
@@ -159,7 +183,9 @@ public:
 class TcpNormalizerVista : public TcpNormalizer
 {
 public:
-    TcpNormalizerVista() = default;
+    TcpNormalizerVista()
+    { my_name = "OS_Vista"; }
+
 
     void init(TcpNormalizerState& tns) override
     { tns.paws_drop_zero_ts = false; }
@@ -171,8 +197,11 @@ public:
 class TcpNormalizerProxy : public TcpNormalizer
 {
 public:
-    TcpNormalizerProxy() = default;
+    TcpNormalizerProxy()
+    { my_name = "OS_Proxy"; }
 
+    TcpNormalizer::NormStatus apply_normalizations(
+        TcpNormalizerState&, TcpSegmentDescriptor&, uint32_t seq, bool stream_is_inorder) override;
     bool validate_rst(TcpNormalizerState&, TcpSegmentDescriptor&) override;
     int handle_paws(TcpNormalizerState&, TcpSegmentDescriptor&) override;
     int handle_repeated_syn(TcpNormalizerState&, TcpSegmentDescriptor&) override;
@@ -362,8 +391,8 @@ bool TcpNormalizerHpux11::is_paws_ts_checked_required(
     TcpNormalizerState& tns, TcpSegmentDescriptor& tsd)
 {
     /* HPUX 11 ignores timestamps for out of order segments */
-    if ( (tns.tracker->get_tf_flags() & TF_MISSING_PKT) || !SEQ_EQ(tns.tracker->rcv_nxt,
-        tsd.get_seq()) )
+    if ( (tns.tracker->get_tf_flags() & TF_MISSING_PKT)
+        || !SEQ_EQ(tns.tracker->rcv_nxt, tsd.get_seq()) )
         return false;
     else
         return true;
@@ -417,11 +446,17 @@ int TcpNormalizerVista::handle_repeated_syn(
     return handle_repeated_syn_mswin(tns.peer_tracker, tns.tracker, tsd, tns.session);
 }
 
+TcpNormalizer::NormStatus TcpNormalizerProxy::apply_normalizations(
+    TcpNormalizerState&, TcpSegmentDescriptor&, uint32_t, bool)
+{
+    // when Proxy policy is active packet normalizations are skipped
+    return NORM_OK;
+}
+
 bool TcpNormalizerProxy::validate_rst(
     TcpNormalizerState&, TcpSegmentDescriptor&)
-
 {
-    return false;
+    return true;
 }
 
 int TcpNormalizerProxy::handle_paws(
index 12831943694cbcfc4347c3225a6dbc9b9f447b19..2715100d0ab19119c66f24258daa4ca462c008eb 100644 (file)
@@ -50,6 +50,9 @@ public:
     void reset()
     { init(StreamPolicy::OS_DEFAULT, nullptr, nullptr, nullptr); }
 
+    TcpNormalizer::NormStatus apply_normalizations(TcpSegmentDescriptor& tsd, uint32_t seq, bool stream_is_inorder)
+    { return norm->apply_normalizations(tns, tsd, seq, stream_is_inorder); }
+
     void session_blocker(TcpSegmentDescriptor& tsd)
     { norm->session_blocker(tns, tsd); }
 
index 9498414cc427bc5c129b72fa4029e9b85d80d2c1..b1773731be112365155551c0c1cf23794a4d9729 100644 (file)
@@ -410,29 +410,6 @@ bool TcpSession::flow_exceeds_config_thresholds(TcpSegmentDescriptor& tsd)
     return false;
 }
 
-void TcpSession::process_tcp_stream(TcpSegmentDescriptor& tsd)
-{
-    if ( tsd.are_packet_flags_set(PKT_IGNORE) )
-        return;
-
-    set_packet_header_foo(tsd);
-
-    if ( flow_exceeds_config_thresholds(tsd) )
-        return;
-
-    TcpStreamTracker* listener = tsd.get_listener();
-
-    listener->reassembler.queue_packet_for_reassembly(tsd);
-
-    // Alert if overlap limit exceeded
-    if ( (tcp_config->overlap_limit)
-        && (listener->reassembler.get_overlap_count() > tcp_config->overlap_limit) )
-    {
-        tel.set_tcp_event(EVENT_EXCESSIVE_OVERLAP);
-        listener->reassembler.set_overlap_count(0);
-    }
-}
-
 void TcpSession::update_stream_order(const TcpSegmentDescriptor& tsd, bool aligned)
 {
     TcpStreamTracker* listener = tsd.get_listener();
@@ -483,79 +460,6 @@ void TcpSession::update_stream_order(const TcpSegmentDescriptor& tsd, bool align
     }
 }
 
-int TcpSession::process_tcp_data(TcpSegmentDescriptor& tsd)
-{
-    TcpStreamTracker* listener = tsd.get_listener();
-    const tcp::TCPHdr* tcph = tsd.get_tcph();
-    uint32_t seq = tsd.get_seq();
-
-    if ( tcph->is_syn() )
-        seq++;
-
-    /* we're aligned, so that's nice anyway */
-    if (seq == listener->rcv_nxt)
-    {
-        /* check if we're in the window */
-        if ( tcp_config->policy != StreamPolicy::OS_PROXY
-            and !Stream::is_midstream(flow) and listener->normalizer.get_stream_window(tsd) == 0 )
-        {
-            if ( !listener->normalizer.data_inside_window(tsd) )
-            {
-                listener->normalizer.trim_win_payload(tsd, 0, tsd.is_nap_policy_inline());
-                return STREAM_UNALIGNED;
-            }
-
-            if( listener->get_iss() )
-            {
-                tcpStats.zero_win_probes++;
-                listener->normalizer.set_zwp_seq(seq);
-                listener->normalizer.trim_win_payload(tsd, MAX_ZERO_WIN_PROBE_LEN, tsd.is_nap_policy_inline());
-            }
-        }
-
-        /* move the ack boundary up, this is the only way we'll accept data */
-        // FIXIT-L for ips, must move all the way to first hole or right end
-        listener->rcv_nxt = tsd.get_end_seq();
-
-        if ( tsd.is_data_segment() )
-        {
-            update_stream_order(tsd, true);
-            process_tcp_stream(tsd);
-            return STREAM_ALIGNED;
-        }
-    }
-    else
-    {
-        // pkt is out of order, do some target-based shizzle here...
-        // NO, we don't want to simply bail.  Some platforms favor unack'd dup data over the
-        // original data.  Let the reassembly policy decide how to handle the overlapping data.
-        // See HP, Solaris, et al. for those that favor duplicate data over the original in
-        // some cases.
-
-        /* check if we're in the window */
-        if ( tcp_config->policy != StreamPolicy::OS_PROXY
-            and !Stream::is_midstream(flow) and listener->normalizer.get_stream_window(tsd) == 0 )
-        {
-            if ( SEQ_EQ(seq, listener->normalizer.get_zwp_seq()) )
-            {
-                tcpStats.zero_win_probes++;
-                listener->normalizer.trim_win_payload(tsd, MAX_ZERO_WIN_PROBE_LEN, tsd.is_nap_policy_inline());
-                return STREAM_UNALIGNED;
-            }
-
-            listener->normalizer.trim_win_payload(tsd, 0, tsd.is_nap_policy_inline());
-            return STREAM_UNALIGNED;
-        }
-        if ( tsd.is_data_segment() )
-        {
-            update_stream_order(tsd, false);
-            process_tcp_stream(tsd);
-        }
-    }
-
-    return STREAM_UNALIGNED;
-}
-
 void TcpSession::set_os_policy()
 {
     StreamPolicy client_os_policy = flow->ssn_policy ?
@@ -865,33 +769,45 @@ void TcpSession::handle_data_segment(TcpSegmentDescriptor& tsd, bool flush)
         else
             server.set_tcp_options_len(tcp_options_len);
 
-        // FIXIT-M move this to normalizer base class, handle OS_PROXY in derived class
-        if ( tcp_config->policy != StreamPolicy::OS_PROXY )
+        uint32_t seq = tsd.get_tcph()->is_syn() ? tsd.get_seq() + 1 : tsd.get_seq();
+        bool stream_is_inorder = ( seq == listener->rcv_nxt );
+
+        int rc =  listener->normalizer.apply_normalizations(tsd, seq, stream_is_inorder);
+        switch ( rc )
         {
-            // these normalizations can't be done if we missed setup. and
-            // window is zero in one direction until we've seen both sides.
-            if ( !(Stream::is_midstream(flow)) && flow->two_way_traffic() )
+        case TcpNormalizer::NORM_OK:
+            if ( stream_is_inorder )
+                listener->rcv_nxt = tsd.get_end_seq();
+
+            update_stream_order(tsd, stream_is_inorder);
+
+            // don't queue data if we are ignoring or queue thresholds are exceeded
+            if ( !tsd.are_packet_flags_set(PKT_IGNORE) and !flow_exceeds_config_thresholds(tsd) )
             {
-                // drop packet if sequence num is invalid
-                if ( !listener->is_segment_seq_valid(tsd) )
+                set_packet_header_foo(tsd);
+                listener->reassembler.queue_packet_for_reassembly(tsd);
+
+                // Alert if overlap limit exceeded
+                if ( (tcp_config->overlap_limit)
+                    && (listener->reassembler.get_overlap_count() > tcp_config->overlap_limit) )
                 {
-                    tcpStats.invalid_seq_num++;
-                    listener->normalizer.trim_win_payload(tsd);
-                    return;
+                    tel.set_tcp_event(EVENT_EXCESSIVE_OVERLAP);
+                    listener->reassembler.set_overlap_count(0);
                 }
+            }
+            break;
 
-                // trim to fit in listener's window and mss
-                listener->normalizer.trim_win_payload
-                    (tsd, (listener->r_win_base + listener->get_snd_wnd() - listener->rcv_nxt));
+        case TcpNormalizer::NORM_TRIMMED:
+            break;
 
-                if ( listener->get_mss() )
-                    listener->normalizer.trim_mss_payload(tsd, listener->get_mss());
+        case TcpNormalizer::NORM_BAD_SEQ:
+            return;
 
-                listener->normalizer.ecn_stripper(tsd);
-            }
-        }
+        default:
+            assert(false);
+            break;
 
-        process_tcp_data(tsd);
+        }
     }
 
     if ( flush )
index 47c70940d9ed6f699c879af37cecf7ed459e6ed6..aa4136a9d42006f100779d4fcfb716f884c0c075 100644 (file)
@@ -75,8 +75,6 @@ public:
 
 private:
     int process_tcp_packet(TcpSegmentDescriptor&, const snort::Packet*);
-    void process_tcp_stream(TcpSegmentDescriptor&);
-    int process_tcp_data(TcpSegmentDescriptor&);
     void set_os_policy() override;
     bool flow_exceeds_config_thresholds(TcpSegmentDescriptor&);
     void update_stream_order(const TcpSegmentDescriptor&, bool aligned);
index 078170cd643fbac31f9c57f4cf89e75bbf853315..d005ef5b4ab5abf15d137b727ec0dfe3b49deb84 100644 (file)
@@ -26,6 +26,7 @@
 #include "tcp_stream_session.h"
 
 #include "framework/data_bus.h"
+#include "packet_tracer/packet_tracer.h"
 #include "pub_sub/stream_event_ids.h"
 #include "stream/stream.h"
 #include "stream/tcp/tcp_ha.h"
@@ -338,7 +339,15 @@ StreamSplitter* TcpStreamSession::get_splitter(bool to_server)
 }
 
 void TcpStreamSession::start_proxy()
-{ tcp_config->policy = StreamPolicy::OS_PROXY; }
+{
+    if ( PacketTracer::is_active() )
+        PacketTracer::log("Stream TCP normalization policy set to Proxy mode.  Normalizations will be skipped\n");
+
+    tcp_config->policy = StreamPolicy::OS_PROXY;
+    client.normalizer.init(tcp_config->policy, this, &client, &server);
+    server.normalizer.init(tcp_config->policy, this, &server, &client);
+    ++tcpStats.proxy_mode_flows;
+}
 
 void TcpStreamSession::set_established(const TcpSegmentDescriptor& tsd)
 {