From: Shawn Turner (shaturne) Date: Fri, 11 Nov 2016 15:25:35 +0000 (-0500) Subject: Merge pull request #702 in SNORT/snort3 from ooofin to master X-Git-Tag: 3.0.0-233~193 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=fd7abc18797aa3054f8f780952b351e4a92cd60b;p=thirdparty%2Fsnort3.git Merge pull request #702 in SNORT/snort3 from ooofin to master Squashed commit of the following: commit 295c5f1b4c1936e3758dce727d3f2f4097d8a193 Author: Bhagya Tholpady Date: Mon Sep 12 16:24:08 2016 -0400 ooofin changes --- diff --git a/src/stream/libtcp/tcp_state_machine.cc b/src/stream/libtcp/tcp_state_machine.cc index 11576fae6..952b6828c 100644 --- a/src/stream/libtcp/tcp_state_machine.cc +++ b/src/stream/libtcp/tcp_state_machine.cc @@ -56,6 +56,15 @@ bool TcpStateMachine::eval(TcpSegmentDescriptor& tsd, TcpStreamTracker& talker, listener.set_tcp_event(tsd); tcp_state_handlers[ tcp_state ]->eval(tsd, listener); tcp_state_handlers[ tcp_state ]->do_post_sm_packet_actions(tsd, listener); + if( listener.process_inorder_fin() ) + { + //FIN is in order or we need to process FIN from state_queue + tcp_state_handlers[ tcp_state ]->eval(tsd, listener); + tcp_state = talker.get_tcp_state( ); + tcp_state_handlers[ tcp_state ]->eval(tsd, talker); + tcp_state_handlers[ tcp_state ]->do_post_sm_packet_actions(tsd, listener); + listener.inorder_fin = false; + } return true; } diff --git a/src/stream/libtcp/tcp_stream_tracker.cc b/src/stream/libtcp/tcp_stream_tracker.cc index 866fdae4e..88ccbbf8b 100644 --- a/src/stream/libtcp/tcp_stream_tracker.cc +++ b/src/stream/libtcp/tcp_stream_tracker.cc @@ -75,7 +75,7 @@ TcpStreamTracker::TcpEvent TcpStreamTracker::set_tcp_event(TcpSegmentDescriptor& tcp_event = TCP_SYN_ACK_SENT_EVENT; else if ( tcph->is_rst() ) tcp_event = TCP_RST_SENT_EVENT; - else if ( tcph->is_fin( ) ) + else if ( tcph->is_fin( ) ) tcp_event = TCP_FIN_SENT_EVENT; else if ( tcph->is_ack() || tcph->is_psh() ) { diff --git a/src/stream/libtcp/tcp_stream_tracker.h b/src/stream/libtcp/tcp_stream_tracker.h index 90f879e30..764056236 100644 --- a/src/stream/libtcp/tcp_stream_tracker.h +++ b/src/stream/libtcp/tcp_stream_tracker.h @@ -323,6 +323,11 @@ public: return rst_pkt_sent; } + bool process_inorder_fin() const + { + return inorder_fin; + } + virtual void init_tcp_state() = 0; virtual void init_toolbox() = 0; @@ -373,6 +378,7 @@ public: uint32_t fin_final_seq = 0; bool rst_pkt_sent = false; + bool inorder_fin = false; // FIXIT-L make these non-public public: diff --git a/src/stream/tcp/tcp_reassembler.cc b/src/stream/tcp/tcp_reassembler.cc index a81add4c9..1874bf5ee 100644 --- a/src/stream/tcp/tcp_reassembler.cc +++ b/src/stream/tcp/tcp_reassembler.cc @@ -523,7 +523,7 @@ int TcpReassembler::flush_data_segments(Packet* p, uint32_t toSeq) seglist.next = tsn->next; // FIXIT-L this is suboptimal - better to exclude fin from toSeq - if ( !tracker->fin_set() or SEQ_LT(toSeq, tracker->fin_final_seq) ) + if ( !tracker->fin_set() or SEQ_LEQ(toSeq, tracker->fin_final_seq) ) tracker->set_tf_flags(TF_MISSING_PKT); break; diff --git a/src/stream/tcp/tcp_session.cc b/src/stream/tcp/tcp_session.cc index fd590da87..507271b87 100644 --- a/src/stream/tcp/tcp_session.cc +++ b/src/stream/tcp/tcp_session.cc @@ -357,6 +357,17 @@ void TcpSession::process_tcp_stream(TcpSegmentDescriptor& tsd) listener->reassembler->set_overlap_count(0); } } +void TcpSession::check_fin_transition_status(TcpSegmentDescriptor& tsd) +{ + if((tsd.get_seg_len() != 0) && + SEQ_EQ(listener->get_fin_final_seq(), listener->r_nxt_ack)) + { + listener->set_tcp_event(TcpStreamTracker::TCP_FIN_RECV_EVENT); + talker->set_tcp_event(TcpStreamTracker::TCP_FIN_SENT_EVENT); + listener->inorder_fin = true; + } +} + int TcpSession::process_tcp_data(TcpSegmentDescriptor& tsd) { @@ -803,6 +814,8 @@ void TcpSession::handle_data_segment(TcpSegmentDescriptor& tsd) or (config->policy == StreamPolicy::OS_PROXY)) { process_tcp_data(tsd); + //Check if all segments are received. Process FIN transition + check_fin_transition_status(tsd); } else { diff --git a/src/stream/tcp/tcp_session.h b/src/stream/tcp/tcp_session.h index e9d8dfa3e..fe758f6f6 100644 --- a/src/stream/tcp/tcp_session.h +++ b/src/stream/tcp/tcp_session.h @@ -77,6 +77,7 @@ public: private: void set_os_policy() override; bool flow_exceeds_config_thresholds(TcpSegmentDescriptor&); + void check_fin_transition_status(TcpSegmentDescriptor&); void process_tcp_stream(TcpSegmentDescriptor&); int process_tcp_data(TcpSegmentDescriptor&); void process_tcp_packet(TcpSegmentDescriptor&); diff --git a/src/stream/tcp/tcp_state_close_wait.cc b/src/stream/tcp/tcp_state_close_wait.cc index abace5fcc..e71153303 100644 --- a/src/stream/tcp/tcp_state_close_wait.cc +++ b/src/stream/tcp/tcp_state_close_wait.cc @@ -107,9 +107,15 @@ bool TcpStateCloseWait::fin_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tr bool TcpStateCloseWait::fin_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) { Flow* flow = tsd.get_flow(); + if( trk.process_inorder_fin() ) + { + trk.update_on_fin_recv(tsd); + return default_state_action(tsd, trk); + } trk.update_tracker_ack_recv(tsd); - if ( SEQ_GEQ(tsd.get_seg_seq(), trk.get_fin_final_seq() ) ) + + if ( SEQ_GT(tsd.get_seg_seq(), trk.get_fin_final_seq() ) ) { DebugMessage(DEBUG_STREAM_STATE, "FIN beyond previous, ignoring\n"); trk.session->tel.set_tcp_event(EVENT_BAD_FIN); diff --git a/src/stream/tcp/tcp_state_closing.cc b/src/stream/tcp/tcp_state_closing.cc index 80b6d948d..e5ecf2233 100644 --- a/src/stream/tcp/tcp_state_closing.cc +++ b/src/stream/tcp/tcp_state_closing.cc @@ -112,7 +112,7 @@ bool TcpStateClosing::fin_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) Flow* flow = tsd.get_flow(); trk.update_tracker_ack_recv(tsd); - if ( SEQ_GEQ(tsd.get_seg_seq(), trk.get_fin_final_seq() ) ) + if ( SEQ_GT(tsd.get_seg_seq(), trk.get_fin_final_seq() ) ) { DebugMessage(DEBUG_STREAM_STATE, "FIN beyond previous, ignoring\n"); trk.session->tel.set_tcp_event(EVENT_BAD_FIN); @@ -160,7 +160,6 @@ bool TcpStateClosing::do_post_sm_packet_actions(TcpSegmentDescriptor& tsd, TcpSt { trk.session->update_paws_timestamps(tsd); trk.session->check_for_window_slam(tsd); - return true; } diff --git a/src/stream/tcp/tcp_state_established.cc b/src/stream/tcp/tcp_state_established.cc index 8b26d448d..3da4897b8 100644 --- a/src/stream/tcp/tcp_state_established.cc +++ b/src/stream/tcp/tcp_state_established.cc @@ -104,9 +104,20 @@ bool TcpStateEstablished::data_seg_recv(TcpSegmentDescriptor& tsd, TcpStreamTrac bool TcpStateEstablished::fin_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) { + TcpStreamTracker* listener = nullptr; + + if ( tsd.get_pkt()->is_from_client() ) + listener = trk.session->server; + else + listener = trk.session->client; trk.update_on_fin_sent(tsd); - trk.session->eof_handle(tsd.get_pkt()); - trk.set_tcp_state(TcpStreamTracker::TCP_FIN_WAIT1); + + if( SEQ_EQ(tsd.get_end_seq(), (listener->r_nxt_ack + tsd.get_seg_len())) || listener->process_inorder_fin() + || !listener->is_segment_seq_valid(tsd) ) + { + trk.session->eof_handle(tsd.get_pkt()); + trk.set_tcp_state(TcpStreamTracker::TCP_FIN_WAIT1); + } return default_state_action(tsd, trk); } @@ -116,13 +127,22 @@ bool TcpStateEstablished::fin_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk.update_tracker_ack_recv(tsd); if ( tsd.get_seg_len() > 0 ) { - trk.session->handle_data_segment(tsd); - trk.flush_data_on_fin_recv(tsd); + trk.session->handle_data_segment(tsd); + trk.flush_data_on_fin_recv(tsd); } - if ( trk.update_on_fin_recv(tsd) ) + if( (tsd.get_end_seq() == trk.r_nxt_ack) || !trk.is_segment_seq_valid(tsd) ) { - trk.session->update_perf_base_state(TcpStreamTracker::TCP_CLOSING); - trk.set_tcp_state(TcpStreamTracker::TCP_CLOSE_WAIT); + if ( trk.update_on_fin_recv(tsd) ) + { + trk.session->update_perf_base_state(TcpStreamTracker::TCP_CLOSING); + trk.set_tcp_state(TcpStreamTracker::TCP_CLOSE_WAIT); + } + } + else + { + //Out of Order FIN received + if ( trk.fin_final_seq == 0 ) + trk.fin_final_seq = tsd.get_seg_seq(); } return default_state_action(tsd, trk); diff --git a/src/stream/tcp/tcp_state_syn_sent.cc b/src/stream/tcp/tcp_state_syn_sent.cc index 881e8b0e3..4a1e04064 100644 --- a/src/stream/tcp/tcp_state_syn_sent.cc +++ b/src/stream/tcp/tcp_state_syn_sent.cc @@ -89,6 +89,7 @@ bool TcpStateSynSent::ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) trk.session->update_timestamp_tracking(tsd); trk.session->update_perf_base_state(TcpStreamTracker::TCP_ESTABLISHED); trk.set_tcp_state(TcpStreamTracker::TCP_ESTABLISHED); + trk.r_nxt_ack = tsd.get_seg_ack(); return default_state_action(tsd, trk); } diff --git a/src/stream/tcp/tcp_state_time_wait.cc b/src/stream/tcp/tcp_state_time_wait.cc index 0900b7fe0..241489db5 100644 --- a/src/stream/tcp/tcp_state_time_wait.cc +++ b/src/stream/tcp/tcp_state_time_wait.cc @@ -103,7 +103,7 @@ bool TcpStateTimeWait::fin_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk bool TcpStateTimeWait::fin_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) { trk.update_tracker_ack_recv(tsd); - if ( SEQ_GEQ(tsd.get_seg_seq(), trk.get_fin_final_seq() ) ) + if ( SEQ_GT(tsd.get_seg_seq(), trk.get_fin_final_seq() ) ) { DebugMessage(DEBUG_STREAM_STATE, "FIN beyond previous, ignoring\n"); trk.session->tel.set_tcp_event(EVENT_BAD_FIN); diff --git a/src/stream/tcp/tcp_tracker.cc b/src/stream/tcp/tcp_tracker.cc index 9f21b89c4..107f40eaf 100644 --- a/src/stream/tcp/tcp_tracker.cc +++ b/src/stream/tcp/tcp_tracker.cc @@ -492,7 +492,7 @@ bool TcpTracker::update_on_fin_recv(TcpSegmentDescriptor& tsd) // set final seq # any packet rx'ed with seq > is bad if ( !fin_set() ) - fin_final_seq = tsd.get_end_seq() + 1; + fin_final_seq = tsd.get_end_seq(); return true; }