From: Russ Combs (rucombs) Date: Mon, 8 Feb 2016 23:32:19 +0000 (-0500) Subject: Merge pull request #244 in SNORT/snort3 from refactor_process_tcp to master X-Git-Tag: 3.0.0-233~628 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=712aa96b94a40484e2232284df293a0ca1677c41;p=thirdparty%2Fsnort3.git Merge pull request #244 in SNORT/snort3 from refactor_process_tcp to master Squashed commit of the following: commit 4b50ea6df55d95a969c48250633b4729876f9a76 Merge: 39f203a a79c98a Author: davis mcpherson Date: Mon Feb 8 13:25:27 2016 -0500 merge from origin commit 39f203aed4047d0bc16dd2bfa9ee66c6a5766a69 Author: davis mcpherson Date: Thu Dec 17 11:18:50 2015 -0500 continue refactoring of Process TCP into state machine miscellaneous fixs from code review comments - see TP user story 14128 commit a79c98a1c7787bc63d2b1e4efcfc174f160b05a3 Author: davis mcpherson Date: Mon Feb 8 11:49:13 2016 -0500 uncrustify this code commit b5fa677b0cacfa23d1aff58fb58a68dc22e75a53 Merge: 388199f aef8461 Author: davis mcpherson Date: Mon Feb 8 11:22:36 2016 -0500 merge with origin to prep for pull request commit 388199f5d32e9e1965a58181b48ba8b5f49abe0b Author: davis mcpherson Date: Thu Dec 17 11:18:50 2015 -0500 continue refactoring of Process TCP into state machine miscellaneous fixs from code review comments - see TP user story 14128 commit aef846189d4b96be21c0c9d9fcd065b993b6afa8 Merge: 50b1cc3 2d45273 Author: davis mcpherson Date: Thu Feb 4 06:49:35 2016 -0500 merge with origin commit 50b1cc325341e75422f03397daf2ff7ca3853e98 Author: davis mcpherson Date: Thu Dec 17 11:18:50 2015 -0500 continue refactoring of Process TCP into state machine miscellaneous fixs from code review comments - see TP user story 14128 commit 2d45273464d3702e04a91b83486167b9225c1d80 Merge: 374cdb4 7401f08 Author: davis mcpherson Date: Wed Feb 3 14:54:17 2016 -0500 fix merge issue from pull from origin commit 374cdb427a1d61ed558f8e76355a174a141a3220 Author: davis mcpherson Date: Tue Feb 2 22:10:55 2016 -0500 fix changes missed in rebase commit 6c9f64c8b1de540919e50dc05f71d915dcfa1c2d Author: davis mcpherson Date: Thu Dec 17 11:18:50 2015 -0500 continue refactoring of Process TCP into state machine miscellaneous fixs from code review comments - see TP user story 14128 commit 7401f085bde0729c0b057c9b4ddb570285406440 Author: davis mcpherson Date: Thu Dec 17 11:18:50 2015 -0500 continue refactoring of Process TCP into state machine --- diff --git a/src/protocols/packet.h b/src/protocols/packet.h index 53393a8a1..2ac036840 100644 --- a/src/protocols/packet.h +++ b/src/protocols/packet.h @@ -164,6 +164,9 @@ struct SO_PUBLIC Packet static const uint32_t max_dsize = IP_MAXPACKET; /* Boolean functions - general information about this packet */ + inline bool is_eth() const + { return proto_bits & PROTO_BIT__ETH; } + inline bool has_ip() const { return ptrs.ip_api.is_ip(); } @@ -283,14 +286,14 @@ struct SO_PUBLIC Packet static inline void SetExtraData(Packet* p, const uint32_t xid) { p->xtradata_mask |= BIT(xid); } -static inline uint16_t EXTRACT_16BITS(const uint8_t* const p) +static inline uint16_t extract_16bits(const uint8_t* const p) { return ntohs(*(uint16_t*)(p)); } #ifdef WORDS_MUSTALIGN #ifdef __GNUC__ /* force word-aligned ntohl parameter */ -static inline uint32_t EXTRACT_32BITS(const uint8_t* p) +static inline uint32_t extract_32bits(const uint8_t* p) { uint32_t tmp; memmove(&tmp, p, sizeof(uint32_t)); @@ -301,7 +304,7 @@ static inline uint32_t EXTRACT_32BITS(const uint8_t* p) #else /* allows unaligned ntohl parameter - dies w/SIGBUS on SPARCs */ -static inline uint32_t EXTRACT_32BITS(const uint8_t* p) +static inline uint32_t extract_32bits(const uint8_t* p) { return ntohl(*(uint32_t*)p); } #endif diff --git a/src/stream/libtcp/tcp_segment_descriptor.cc b/src/stream/libtcp/tcp_segment_descriptor.cc index 4034a777c..b3620f0cb 100644 --- a/src/stream/libtcp/tcp_segment_descriptor.cc +++ b/src/stream/libtcp/tcp_segment_descriptor.cc @@ -28,16 +28,16 @@ using namespace tcp; -TcpSegmentDescriptor::TcpSegmentDescriptor(Flow* flow, Packet* pkt, TcpEventLogger* tel) : +TcpSegmentDescriptor::TcpSegmentDescriptor(Flow* flow, Packet* pkt, TcpEventLogger& tel) : flow(flow), pkt(pkt) { tcph = pkt->ptrs.tcph; - src_port = ntohs(tcph->th_sport); - dst_port = ntohs(tcph->th_dport); - seq = ntohl(pkt->ptrs.tcph->th_seq); - ack = ntohl(pkt->ptrs.tcph->th_ack); - win = ntohs(pkt->ptrs.tcph->th_win); - end_seq = seq + (uint32_t)pkt->dsize; + src_port = tcph->src_port(); + dst_port = tcph->dst_port(); + seg_seq = tcph->seq(); + seg_ack = tcph->ack(); + seg_wnd = tcph->win(); + end_seq = seg_seq + (uint32_t)pkt->dsize; ts = 0; // don't bump end_seq for fin here we will bump if/when fin is processed @@ -45,7 +45,7 @@ TcpSegmentDescriptor::TcpSegmentDescriptor(Flow* flow, Packet* pkt, TcpEventLogg { end_seq++; if ( !tcph->is_ack() ) - tel->set_tcp_internal_syn_event( ); + tel.set_tcp_internal_syn_event( ); } #ifdef DEBUG_STREAM_EX @@ -67,7 +67,7 @@ uint32_t TcpSegmentDescriptor::init_mss(uint16_t* value) { if ( opt.code == TcpOptCode::MAXSEG ) { - *value = EXTRACT_16BITS(opt.data); + *value = extract_16bits(opt.data); DebugFormat(DEBUG_STREAM_STATE, "Found MSS %u\n", *value); return TF_MSS; } @@ -86,7 +86,6 @@ uint32_t TcpSegmentDescriptor::init_wscale(uint16_t* value) TcpOptIterator iter(tcph, pkt); - // using const because non-const is not supported for (const TcpOption& opt : iter) { if (opt.code == TcpOptCode::WSCALE) @@ -94,12 +93,9 @@ uint32_t TcpSegmentDescriptor::init_wscale(uint16_t* value) *value = (uint16_t)opt.data[0]; DebugFormat(DEBUG_STREAM_STATE, "Found wscale %d\n", *value); - /* If scale specified in option is larger than 14, - * use 14 because of limitation in the math of - * shifting a 32bit value (max scaled window is 2^30th). - * - * See RFC 1323 for details. - */ + // If scale specified in option is larger than 14, use 14 because of limitation + // in the math of shifting a 32bit value (max scaled window is 2^30th). + // See RFC 1323 for details. if (*value > 14) *value = 14; @@ -113,21 +109,21 @@ uint32_t TcpSegmentDescriptor::init_wscale(uint16_t* value) return TF_NONE; } -uint32_t TcpSegmentDescriptor::has_wscale(void) +bool TcpSegmentDescriptor::has_wscale(void) { uint16_t wscale; DebugMessage(DEBUG_STREAM_STATE, "Checking for wscale...\n"); - return init_wscale(&wscale); + return ( init_wscale(&wscale) & TF_WSCALE ) != TF_NONE; } void TcpSegmentDescriptor::print_tsd(void) { LogMessage("Tcp Segment Descriptor:\n"); - LogMessage(" seq: 0x%08X\n", seq); - LogMessage(" ack: 0x%08X\n", ack); - LogMessage(" win: %d\n", win); + LogMessage(" seq: 0x%08X\n", seg_seq); + LogMessage(" ack: 0x%08X\n", seg_ack); + LogMessage(" win: %d\n", seg_wnd); LogMessage(" end: 0x%08X\n", end_seq); } diff --git a/src/stream/libtcp/tcp_segment_descriptor.h b/src/stream/libtcp/tcp_segment_descriptor.h index eac2492f1..6c09e3442 100644 --- a/src/stream/libtcp/tcp_segment_descriptor.h +++ b/src/stream/libtcp/tcp_segment_descriptor.h @@ -31,12 +31,12 @@ class TcpSegmentDescriptor { public: - TcpSegmentDescriptor(Flow*, Packet*, TcpEventLogger*); + TcpSegmentDescriptor(Flow*, Packet*, TcpEventLogger&); virtual ~TcpSegmentDescriptor(); uint32_t init_mss(uint16_t* value); uint32_t init_wscale(uint16_t* value); - uint32_t has_wscale(void); + bool has_wscale(void); Flow* get_flow() const { @@ -53,19 +53,24 @@ public: return tcph; } - void set_seq(uint32_t seq) + void set_seg_seq(uint32_t seq) { - this->seq = seq; + this->seg_seq = seq; } - uint32_t get_seq() const + void update_seg_seq(int32_t offset) { - return seq; + seg_seq += offset; } - uint32_t get_ack() const + uint32_t get_seg_seq() const { - return ack; + return seg_seq; + } + + uint32_t get_seg_ack() const + { + return seg_ack; } void set_end_seq(uint32_t end_seq) @@ -88,14 +93,14 @@ public: return ts; } - void set_win(uint32_t win) + void scale_seg_wnd(uint16_t wscale) { - this->win = win; + this->seg_wnd <<= wscale; } - uint32_t get_win() const + uint32_t get_seg_wnd() const { - return win; + return seg_wnd; } uint16_t get_dst_port() const @@ -113,11 +118,33 @@ public: return flow->ssn_state.direction; } - uint32_t get_data_len() const + uint16_t get_seg_len() const { return pkt->dsize; } + void set_seg_len(uint16_t seg_len) + { + pkt->dsize = seg_len; + } + + void update_seg_len(int32_t offset) + { + pkt->dsize += offset; + } + + bool is_packet_from_server(void) + { + return pkt->packet_flags & PKT_FROM_SERVER; + } + + void slide_segment_in_rcv_window(int32_t offset) + { + seg_seq += offset; + pkt->data += offset; + pkt->dsize -= offset; + } + void print_tsd(void); private: @@ -127,9 +154,9 @@ private: const tcp::TCPHdr* tcph; uint16_t src_port; uint16_t dst_port; - uint32_t seq; - uint32_t ack; - uint32_t win; + uint32_t seg_seq; + uint32_t seg_ack; + uint32_t seg_wnd; uint32_t end_seq; uint32_t ts; }; diff --git a/src/stream/libtcp/tcp_state_handler.cc b/src/stream/libtcp/tcp_state_handler.cc index f6fd6b4e4..b5848e751 100644 --- a/src/stream/libtcp/tcp_state_handler.cc +++ b/src/stream/libtcp/tcp_state_handler.cc @@ -32,15 +32,14 @@ using namespace std; #include "stream_tcp_unit_test.h" #endif -TcpStateHandler::TcpStateHandler(TcpStreamTracker::TcpStates state, TcpStateMachine& tsm) : - tsm(&tsm), tcp_state(state), tcp_event(TcpStreamTracker::TCP_MAX_EVENTS) +TcpStateHandler::TcpStateHandler(TcpStreamTracker::TcpState state, TcpStateMachine& tsm) : + tsm(&tsm), tcp_state(state) { tsm.register_state_handler(state, *this); } TcpStateHandler::TcpStateHandler(void) : - tsm(nullptr), tcp_state(TcpStreamTracker::TCP_CLOSED), - tcp_event(TcpStreamTracker::TCP_MAX_EVENTS) + tsm(nullptr), tcp_state(TcpStreamTracker::TCP_CLOSED) { } @@ -49,10 +48,22 @@ TcpStateHandler::~TcpStateHandler() // TODO Auto-generated destructor stub } +void TcpStateHandler::do_pre_sm_packet_actions(TcpSegmentDescriptor& tsd) +{ + UNUSED(tsd); +} + +void TcpStateHandler::do_post_sm_packet_actions(TcpSegmentDescriptor& tsd) +{ + UNUSED(tsd); +} + bool TcpStateHandler::eval(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { bool handled = false; + do_pre_sm_packet_actions(tsd); + switch ( tcp_event = tracker.get_tcp_event() ) { case TcpStreamTracker::TCP_SYN_SENT_EVENT: @@ -109,82 +120,81 @@ bool TcpStateHandler::eval(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) break; } + do_post_sm_packet_actions(tsd); return handled; } -bool TcpStateHandler::default_state_action( - TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker, const char* func_name) +bool TcpStateHandler::default_state_action(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { #ifdef DEBUG_MSGS - DebugFormat(DEBUG_STREAM_STATE, "Default Implementation of: %s tsd: %p tracker: %p\n", - func_name, &tsd, &tracker); + DebugFormat(DEBUG_STREAM_STATE, "tsd: %p tracker: %p state: %u event: %u\n", + &tsd, &tracker, tracker.get_tcp_state(), tracker.get_tcp_event() ); #else UNUSED(tsd); - UNUSED(func_name); + UNUSED(tracker) #endif - tcp_event = tracker.get_tcp_event(); - return false; + return true; } bool TcpStateHandler::syn_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - return default_state_action(tsd, tracker, __func__); + return default_state_action(tsd, tracker); } bool TcpStateHandler::syn_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - return default_state_action(tsd, tracker, __func__); + return default_state_action(tsd, tracker); } bool TcpStateHandler::syn_ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - return default_state_action(tsd, tracker, __func__); + return default_state_action(tsd, tracker); } bool TcpStateHandler::syn_ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - return default_state_action(tsd, tracker, __func__); + return default_state_action(tsd, tracker); } bool TcpStateHandler::ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - return default_state_action(tsd, tracker, __func__); + return default_state_action(tsd, tracker); } bool TcpStateHandler::ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - return default_state_action(tsd, tracker, __func__); + return default_state_action(tsd, tracker); } bool TcpStateHandler::data_seg_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - return default_state_action(tsd, tracker, __func__); + return default_state_action(tsd, tracker); } bool TcpStateHandler::data_seg_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - return default_state_action(tsd, tracker, __func__); + return default_state_action(tsd, tracker); } bool TcpStateHandler::fin_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - return default_state_action(tsd, tracker, __func__); + return default_state_action(tsd, tracker); } bool TcpStateHandler::fin_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - return default_state_action(tsd, tracker, __func__); + return default_state_action(tsd, tracker); } bool TcpStateHandler::rst_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - return default_state_action(tsd, tracker, __func__); + return default_state_action(tsd, tracker); } bool TcpStateHandler::rst_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - return default_state_action(tsd, tracker, __func__); + return default_state_action(tsd, tracker); } #ifdef UNIT_TEST @@ -196,7 +206,7 @@ SCENARIO("TCP State Handler Base Class", "[state_handlers][stream_tcp]") TcpStateHandler* tsh = new TcpStateHandler; TcpStreamTracker* client_tracker = new TcpStreamTracker(true); TcpStreamTracker* server_tracker = new TcpStreamTracker(false); - TcpEventLogger* tel = new TcpEventLogger; + TcpEventLogger tel; GIVEN("a SYN Packet") { diff --git a/src/stream/libtcp/tcp_state_handler.h b/src/stream/libtcp/tcp_state_handler.h index 2b96168d8..0532dbccc 100644 --- a/src/stream/libtcp/tcp_state_handler.h +++ b/src/stream/libtcp/tcp_state_handler.h @@ -31,28 +31,23 @@ class TcpStateMachine; class TcpStateHandler { public: - TcpStateHandler(TcpStreamTracker::TcpStates, TcpStateMachine&); + TcpStateHandler(TcpStreamTracker::TcpState, TcpStateMachine&); TcpStateHandler(void); virtual ~TcpStateHandler(); virtual bool eval(TcpSegmentDescriptor&, TcpStreamTracker&); - TcpStreamTracker::TcpEvents get_tcp_event() const + TcpStreamTracker::TcpEvent get_tcp_event() const { return tcp_event; } - TcpStreamTracker::TcpStates get_tcp_state() const + TcpStreamTracker::TcpState get_tcp_state() const { return tcp_state; } - void set_tcp_state(TcpStreamTracker::TcpStates tcp_state) - { - this->tcp_state = tcp_state; - } - - void set_tcp_event(TcpStreamTracker::TcpEvents tcp_event) + void set_tcp_event(TcpStreamTracker::TcpEvent tcp_event) { this->tcp_event = tcp_event; } @@ -68,6 +63,9 @@ public: } protected: + virtual void do_pre_sm_packet_actions(TcpSegmentDescriptor&); + virtual void do_post_sm_packet_actions(TcpSegmentDescriptor&); + virtual bool syn_sent(TcpSegmentDescriptor&, TcpStreamTracker&); virtual bool syn_recv(TcpSegmentDescriptor&, TcpStreamTracker&); virtual bool syn_ack_sent(TcpSegmentDescriptor&, TcpStreamTracker&); @@ -81,11 +79,11 @@ protected: virtual bool rst_sent(TcpSegmentDescriptor&, TcpStreamTracker&); virtual bool rst_recv(TcpSegmentDescriptor&, TcpStreamTracker&); - bool default_state_action(TcpSegmentDescriptor&, TcpStreamTracker&, const char*); + bool default_state_action(TcpSegmentDescriptor&, TcpStreamTracker&); const TcpStateMachine* tsm; - TcpStreamTracker::TcpStates tcp_state; - TcpStreamTracker::TcpEvents tcp_event; + TcpStreamTracker::TcpState tcp_state; + TcpStreamTracker::TcpEvent tcp_event = TcpStreamTracker::TCP_MAX_EVENTS; }; #endif diff --git a/src/stream/libtcp/tcp_state_machine.cc b/src/stream/libtcp/tcp_state_machine.cc index fee01408e..bc4ba5cd1 100644 --- a/src/stream/libtcp/tcp_state_machine.cc +++ b/src/stream/libtcp/tcp_state_machine.cc @@ -24,12 +24,12 @@ TcpStateMachine::TcpStateMachine(void) { + TcpStreamTracker::TcpState s; // register a default handler for each state... - for ( TcpStreamTracker::TcpStates state = TcpStreamTracker::TCP_LISTEN; state < - TcpStreamTracker::TCP_MAX_STATES; state++ ) + for ( s = TcpStreamTracker::TCP_LISTEN; s < TcpStreamTracker::TCP_MAX_STATES; s++ ) { - tcp_state_handlers[ state ] = nullptr; - new TcpStateHandler(state, *this); + tcp_state_handlers[ s ] = nullptr; + new TcpStateHandler(s, *this); } } @@ -38,7 +38,7 @@ TcpStateMachine::~TcpStateMachine(void) // TODO Auto-generated destructor stub } -void TcpStateMachine::register_state_handler(TcpStreamTracker::TcpStates state, +void TcpStateMachine::register_state_handler(TcpStreamTracker::TcpState state, TcpStateHandler& handler) { if ( tcp_state_handlers[ state ] != nullptr ) diff --git a/src/stream/libtcp/tcp_state_machine.h b/src/stream/libtcp/tcp_state_machine.h index 286b25280..46d1d14b2 100644 --- a/src/stream/libtcp/tcp_state_machine.h +++ b/src/stream/libtcp/tcp_state_machine.h @@ -32,7 +32,7 @@ public: TcpStateMachine(void); virtual ~TcpStateMachine(void); - virtual void register_state_handler(TcpStreamTracker::TcpStates, TcpStateHandler&); + virtual void register_state_handler(TcpStreamTracker::TcpState, TcpStateHandler&); virtual bool eval(TcpSegmentDescriptor&, TcpStreamTracker&); private: diff --git a/src/stream/libtcp/tcp_stream_tracker.cc b/src/stream/libtcp/tcp_stream_tracker.cc index f04b6da3c..b3914d247 100644 --- a/src/stream/libtcp/tcp_stream_tracker.cc +++ b/src/stream/libtcp/tcp_stream_tracker.cc @@ -41,13 +41,8 @@ const char* tcp_event_names[] = { "TCP_SYN_SENT_EVENT", "TCP_SYN_RECV_EVENT", "TCP_RST_RECV_EVENT" }; TcpStreamTracker::TcpStreamTracker(bool client) : - client_tracker(client), require_3whs(false), snd_una(0), snd_nxt(0), snd_wnd(0), snd_up(0), - snd_wl1(0), snd_wl2(0), iss(0), rcv_nxt(0), rcv_wnd(0), rcv_up(0), irs(0), - ts_last_packet(0), ts_last(0), wscale(0), mss(0), flags(0) + client_tracker(client), tcp_state(client ? TCP_STATE_NONE : TCP_LISTEN) { - memset(mac_addr, '0', sizeof(mac_addr)); - tcp_state = TCP_STATE_NONE; - tcp_event = TCP_MAX_EVENTS; } TcpStreamTracker::~TcpStreamTracker() @@ -55,7 +50,7 @@ TcpStreamTracker::~TcpStreamTracker() // TODO Auto-generated destructor stub } -void TcpStreamTracker::set_tcp_event(TcpSegmentDescriptor& tsd) +TcpStreamTracker::TcpEvent TcpStreamTracker::set_tcp_event(TcpSegmentDescriptor& tsd) { bool talker; const tcp::TCPHdr* tcph = tsd.get_tcph(); @@ -67,48 +62,52 @@ void TcpStreamTracker::set_tcp_event(TcpSegmentDescriptor& tsd) if ( talker ) { + // talker events if ( tcph->is_syn_only() ) tcp_event = TCP_SYN_SENT_EVENT; else if ( tcph->is_syn_ack() ) tcp_event = TCP_SYN_ACK_SENT_EVENT; + else if ( tcph->is_rst() ) + tcp_event = TCP_RST_SENT_EVENT; + else if ( tcph->is_fin( ) ) + tcp_event = TCP_FIN_SENT_EVENT; else if ( tcph->is_ack() || tcph->is_psh() ) { - if ( tsd.get_data_len() > 0 ) + if ( tsd.get_seg_len() > 0 ) tcp_event = TCP_DATA_SEG_SENT_EVENT; else tcp_event = TCP_ACK_SENT_EVENT; } - else if ( tcph->is_rst() ) - tcp_event = TCP_RST_SENT_EVENT; - else if ( tcph->is_fin( ) ) - tcp_event = TCP_FIN_SENT_EVENT; // else if( tsd.get_data_len() > 0 ) // FIXIT - No flags set, how do we handle this? // tcp_event = TCP_DATA_SEG_SENT_EVENT; else tcp_event = TCP_ACK_SENT_EVENT; } - else // server is listening events + else { + // listener events if ( tcph->is_syn_only() ) tcp_event = TCP_SYN_RECV_EVENT; else if ( tcph->is_syn_ack() ) tcp_event = TCP_SYN_ACK_RECV_EVENT; + else if ( tcph->is_rst() ) + tcp_event = TCP_RST_RECV_EVENT; + else if ( tcph->is_fin( ) ) + tcp_event = TCP_FIN_RECV_EVENT; else if ( tcph->is_ack() || tcph->is_psh() ) { - if ( tsd.get_data_len() > 0 ) + if ( tsd.get_seg_len() > 0 ) tcp_event = TCP_DATA_SEG_RECV_EVENT; else tcp_event = TCP_ACK_RECV_EVENT; } - else if ( tcph->is_rst() ) - tcp_event = TCP_RST_RECV_EVENT; - else if ( tcph->is_fin( ) ) - tcp_event = TCP_FIN_RECV_EVENT; -// else if( tsd.get_data_len() > 0 ) // FIXIT - No flags set, how do we handle this? +// else if( tsd.get_data_len() > 0 ) // FIXIT - No flags set, how do we handle this? // tcp_event = TCP_DATA_SEG_RECV_EVENT; else tcp_event = TCP_ACK_RECV_EVENT; } + + return tcp_event; } // Use a for loop and byte comparison, which has proven to be faster on pipelined architectures @@ -116,6 +115,9 @@ void TcpStreamTracker::set_tcp_event(TcpSegmentDescriptor& tsd) // there is no guarantee of memory alignment (and thus performance issues similar to memcmp). bool TcpStreamTracker::compare_mac_addresses(const uint8_t eth_addr[]) { + if ( !mac_addr_valid ) + return true; + for ( int i = 0; i < 6; ++i ) if ( mac_addr[i] != eth_addr[i] ) return false; @@ -128,29 +130,33 @@ void TcpStreamTracker::cache_mac_address(TcpSegmentDescriptor& tsd, uint8_t dire int i; /* Not Ethernet based, nothing to do */ - if ( !( tsd.get_pkt()->proto_bits & PROTO_BIT__ETH ) ) - return; - - // if flag is set, guaranteed to have an eth layer - const eth::EtherHdr* eh = layer::get_eth_layer(tsd.get_pkt() ); - - if ( direction == FROM_CLIENT ) + if ( tsd.get_pkt()->is_eth() ) { - if ( client_tracker ) - for ( i = 0; i < 6; i++ ) - mac_addr[i] = eh->ether_src[i]; - else - for ( i = 0; i < 6; i++ ) - mac_addr[i] = eh->ether_dst[i]; - } - else - { - if ( client_tracker ) - for ( i = 0; i < 6; i++ ) - mac_addr[i] = eh->ether_dst[i]; + // if flag is set, guaranteed to have an eth layer + const eth::EtherHdr* eh = layer::get_eth_layer(tsd.get_pkt() ); + + if ( direction == FROM_CLIENT ) + { + if ( client_tracker ) + for ( i = 0; i < 6; i++ ) + mac_addr[i] = eh->ether_src[i]; + else + for ( i = 0; i < 6; i++ ) + mac_addr[i] = eh->ether_dst[i]; + } else - for ( i = 0; i < 6; i++ ) - mac_addr[i] = eh->ether_src[i]; + { + if ( client_tracker ) + for ( i = 0; i < 6; i++ ) + mac_addr[i] = eh->ether_dst[i]; + else + for ( i = 0; i < 6; i++ ) + mac_addr[i] = eh->ether_src[i]; + } + + mac_addr_valid = true; } + + mac_addr_valid = true; } diff --git a/src/stream/libtcp/tcp_stream_tracker.h b/src/stream/libtcp/tcp_stream_tracker.h index bd633d2a3..e69ca1baa 100644 --- a/src/stream/libtcp/tcp_stream_tracker.h +++ b/src/stream/libtcp/tcp_stream_tracker.h @@ -32,7 +32,7 @@ extern const char* tcp_event_names[]; class TcpStreamTracker { public: - enum TcpStates + enum TcpState { TCP_LISTEN, TCP_SYN_SENT, @@ -49,7 +49,7 @@ public: TCP_MAX_STATES }; - enum TcpEvents + enum TcpEvent { TCP_SYN_SENT_EVENT, TCP_SYN_RECV_EVENT, @@ -74,34 +74,29 @@ public: return client_tracker; } - bool is_3whs_required() const + bool is_server_tracker() const { - return require_3whs; + return !client_tracker; } - void set_require_3whs(bool require3_whs) - { - this->require_3whs = require3_whs; - } - - TcpStates get_tcp_state() const + TcpState get_tcp_state() const { return tcp_state; } - void set_tcp_state(TcpStates tcp_state) + void set_tcp_state(TcpState tcp_state) { this->tcp_state = tcp_state; } - TcpEvents get_tcp_event() const + TcpEvent get_tcp_event() const { return tcp_event; } - void set_tcp_event(TcpSegmentDescriptor& tsd); + TcpEvent set_tcp_event(TcpSegmentDescriptor& tsd); - void set_tcp_event(TcpEvents tcp_event) + void set_tcp_event(TcpEvent tcp_event) { this->tcp_event = tcp_event; } @@ -228,6 +223,8 @@ public: bool is_ack_valid(uint32_t cur) { + // FIXIT - do we need this check? we've alwasy seen something by the time + // we get here /* If we haven't seen anything, ie, low & high are 0, return true */ if ( ( snd_una == 0 ) && ( snd_una == snd_nxt ) ) return 1; @@ -238,7 +235,52 @@ public: // ack number must ack syn bool is_rst_valid_in_syn_sent(TcpSegmentDescriptor& tsd) { - return tsd.get_ack() == snd_una; + return tsd.get_seg_ack() == snd_una; + } + + uint32_t get_ts_last() const + { + return ts_last; + } + + void set_ts_last(uint32_t ts_last) + { + this->ts_last = ts_last; + } + + uint8_t get_tf_flags() const + { + return tf_flags; + } + + void set_tf_flags(uint16_t flags) + { + this->tf_flags |= flags; + } + + void clear_tf_flags(uint16_t flags) + { + this->tf_flags &= ~flags; + } + + uint16_t get_wscale() const + { + return wscale; + } + + void set_wscale(uint16_t wscale) + { + this->wscale = wscale; + } + + uint16_t get_mss() const + { + return mss; + } + + void set_mss(uint16_t mss) + { + this->mss = mss; } void cache_mac_address(TcpSegmentDescriptor& tsd, uint8_t direction); @@ -246,45 +288,50 @@ public: protected: bool client_tracker; - bool require_3whs; + TcpState tcp_state; + TcpEvent tcp_event = TCP_MAX_EVENTS; + bool require_3whs = false; + + uint32_t snd_una = 0; // SND.UNA - send unacknowledged + uint32_t snd_nxt = 0; // SND.NXT - send next + uint32_t snd_wnd = 0; // SND.WND - send window + uint16_t snd_up = 0; // SND.UP - send urgent pointer + uint32_t snd_wl1 = 0; // SND.WL1 - segment sequence number used for last window update + uint32_t snd_wl2 = 0; // SND.WL2 - segment acknowledgment number used for last window update + uint32_t iss = 0; // ISS - initial send sequence number - uint32_t snd_una; // SND.UNA - send unacknowledged - uint32_t snd_nxt; // SND.NXT - send next - uint32_t snd_wnd; // SND.WND - send window - uint16_t snd_up; // SND.UP - send urgent pointer - uint32_t snd_wl1; // SND.WL1 - segment sequence number used for last window update - uint32_t snd_wl2; // SND.WL2 - segment acknowledgment number used for last window update - uint32_t iss; // ISS - initial send sequence number + uint32_t rcv_nxt = 0; // RCV.NXT - receive next + uint32_t rcv_wnd = 0; // RCV.WND - receive window + uint16_t rcv_up = 0; // RCV.UP - receive urgent pointer + uint32_t irs = 0; // IRS - initial receive sequence number - uint32_t rcv_nxt; // RCV.NXT - receive next - uint32_t rcv_wnd; // RCV.WND - receive window - uint16_t rcv_up; // RCV.UP - receive urgent pointer - uint32_t irs; // IRS - initial receive sequence number +// FIXIT - make these non-public - uint32_t ts_last_packet; // timestamp of last packet we got +public: + uint32_t r_nxt_ack = 0; /* next expected ack from remote side */ + uint32_t r_win_base = 0; /* remote side window base sequence number + * (i.e. the last ack we got) */ + +protected: + uint32_t ts_last_packet = 0; + uint32_t ts_last = 0; /* last timestamp (for PAWS) */ + uint16_t tf_flags = 0; - // FIXIT - make this protected + uint8_t mac_addr[6] = {}; + bool mac_addr_valid = false; + + // FIXIT - make this protected... public: - uint32_t ts_last; /* last timestamp (for PAWS) */ uint16_t wscale; /* window scale setting */ uint16_t mss; /* max segment size */ - - uint8_t mac_addr[6]; - uint8_t flags; /* bitmap flags (TF_xxx) */ - -protected: - TcpStates tcp_state; - TcpEvents tcp_event; }; -inline TcpStreamTracker::TcpStates& operator++(TcpStreamTracker::TcpStates& state, int) // <--- - // note -- - // must be - // a reference +// <--- note -- the 'state' parameter must be a reference +inline TcpStreamTracker::TcpState& operator++(TcpStreamTracker::TcpState& state, int) { const int i = static_cast(state); - state = static_cast((i + 1) % ( TcpStreamTracker::TCP_MAX_EVENTS + + state = static_cast((i + 1) % ( TcpStreamTracker::TCP_MAX_EVENTS + 1 ) ); return state; } diff --git a/src/stream/tcp/segment_overlap_editor.cc b/src/stream/tcp/segment_overlap_editor.cc index f644fb1c1..ef758258b 100644 --- a/src/stream/tcp/segment_overlap_editor.cc +++ b/src/stream/tcp/segment_overlap_editor.cc @@ -131,7 +131,7 @@ int SegmentOverlapEditor::generate_bad_segment_event(void) { DebugFormat(DEBUG_STREAM_STATE, "bad segment: overlap with invalid sequence number" "(seq: %X seq_end: %X overlap: %lu\n", seq, seq_end, overlap); - session->tel->EventBadSegment(); + session->tel.EventBadSegment(); inc_tcp_discards(); return STREAM_INSERT_ANOMALY; } @@ -142,7 +142,7 @@ int SegmentOverlapEditor::left_overlap_keep_first(void) DebugFormat(DEBUG_STREAM_STATE, "left overlap %d\n", overlap); - len = tsd->get_pkt()->dsize; + len = tsd->get_seg_len(); overlap = left->seq + left->payload_size - seq; if ( overlap > 0 ) { @@ -152,24 +152,24 @@ int SegmentOverlapEditor::left_overlap_keep_first(void) overlap_count++; DebugMessage(DEBUG_STREAM_STATE, "left overlap, honoring old data\n"); - if ( SEQ_LT(left->seq, tsd->get_seq() ) && SEQ_GT(left->seq + left->payload_size, - tsd->get_seq() + tsd->get_pkt()->dsize) ) + if ( SEQ_LT(left->seq, tsd->get_seg_seq() ) && SEQ_GT(left->seq + left->payload_size, + tsd->get_seg_seq() + tsd->get_seg_len() ) ) { if (tcp_ips_data == NORM_MODE_ON) { - unsigned offset = tsd->get_seq() - left->seq; + unsigned offset = tsd->get_seg_seq() - left->seq; memcpy( ( uint8_t* )tsd->get_pkt()->data, left->payload + offset, - tsd->get_pkt()->dsize); + tsd->get_seg_len() ); tsd->get_pkt()->packet_flags |= PKT_MODIFIED; } tcp_norm_stats[PC_TCP_IPS_DATA][tcp_ips_data]++; } - else if ( SEQ_LT(left->seq, tsd->get_seq() ) ) + else if ( SEQ_LT(left->seq, tsd->get_seg_seq() ) ) { if ( tcp_ips_data == NORM_MODE_ON ) { - unsigned offset = tsd->get_seq() - left->seq; - unsigned length = left->seq + left->payload_size - tsd->get_seq(); + unsigned offset = tsd->get_seg_seq() - left->seq; + unsigned length = left->seq + left->payload_size - tsd->get_seg_seq(); memcpy( ( uint8_t* )tsd->get_pkt()->data, left->payload + offset, length); tsd->get_pkt()->packet_flags |= PKT_MODIFIED; } @@ -191,7 +191,7 @@ int SegmentOverlapEditor::left_overlap_trim_first(void) DebugFormat(DEBUG_STREAM_STATE, "left overlap %d\n", overlap); - len = tsd->get_pkt()->dsize; + len = tsd->get_seg_len(); overlap = left->seq + left->payload_size - seq; if ( overlap > 0 ) { @@ -222,7 +222,7 @@ int SegmentOverlapEditor::left_overlap_keep_last(void) DebugFormat(DEBUG_STREAM_STATE, "left overlap %d\n", overlap); - len = tsd->get_pkt()->dsize; + len = tsd->get_seg_len(); overlap = left->seq + left->payload_size - seq; if ( overlap > 0 ) { @@ -283,8 +283,8 @@ void SegmentOverlapEditor::right_overlap_truncate_new(void) { if (tcp_ips_data == NORM_MODE_ON) { - unsigned offset = right->seq - tsd->get_seq(); - unsigned length = tsd->get_seq() + tsd->get_pkt()->dsize - right->seq; + unsigned offset = right->seq - tsd->get_seg_seq(); + unsigned length = tsd->get_seg_seq() + tsd->get_seg_len() - right->seq; memcpy( ( uint8_t* )tsd->get_pkt()->data + offset, right->payload, length); tsd->get_pkt()->packet_flags |= PKT_MODIFIED; } @@ -301,7 +301,7 @@ int SegmentOverlapEditor::full_right_overlap_truncate_new(void) if ( tcp_ips_data == NORM_MODE_ON ) { - unsigned offset = right->seq - tsd->get_seq(); + unsigned offset = right->seq - tsd->get_seg_seq(); memcpy( ( uint8_t* )tsd->get_pkt()->data + offset, right->payload, right->payload_size); tsd->get_pkt()->packet_flags |= PKT_MODIFIED; } @@ -327,7 +327,7 @@ int SegmentOverlapEditor::full_right_overlap_truncate_new(void) /* insert this one, and see if we need to chunk it up Adjust slide so that is correct relative to orig seq */ - slide = seq - tsd->get_seq(); + slide = seq - tsd->get_seg_seq(); int rc = add_reassembly_segment(*tsd, len, slide, trunc_len, seq, left); if ( rc != STREAM_INSERT_OK ) return rc; diff --git a/src/stream/tcp/segment_overlap_editor.h b/src/stream/tcp/segment_overlap_editor.h index 1e7218d9a..a78991f1b 100644 --- a/src/stream/tcp/segment_overlap_editor.h +++ b/src/stream/tcp/segment_overlap_editor.h @@ -36,12 +36,6 @@ class SegmentOverlapEditor protected: SegmentOverlapEditor(void) - : session(nullptr), reassembly_policy(ReassemblyPolicy::OS_DEFAULT), seglist_base_seq(0), - seg_count(0), seg_bytes_total(0), seg_bytes_logical(0), total_bytes_queued(0), - total_segs_queued(0), overlap_count(0), - tsd(nullptr), left(nullptr), right(nullptr), seq(0), seq_end(0), - len(0), overlap(0), slide(0), trunc_len(0), rdata(nullptr), - rsize(0), rseq(0), keep_segment(true) { tcp_ips_data = Normalize_GetMode(NORM_TCP_IPS); } @@ -53,15 +47,15 @@ protected: this->tsd = &tsd; this->left = left; this->right = right; - seq = tsd.get_seq(); + seq = tsd.get_seg_seq(); seq_end = tsd.get_end_seq(); - len = tsd.get_data_len(); + len = tsd.get_seg_len(); overlap = 0; slide = 0; trunc_len = 0; rdata = tsd.get_pkt()->data; - rsize = tsd.get_data_len(); - rseq = tsd.get_seq(); + rsize = tsd.get_seg_len(); + rseq = tsd.get_seg_seq(); keep_segment = true; } @@ -87,41 +81,37 @@ protected: virtual int insert_left_overlap(void) = 0; virtual void insert_right_overlap(void) = 0; virtual int insert_full_overlap(void) = 0; - virtual int add_reassembly_segment(TcpSegmentDescriptor&, int16_t len, uint32_t slide, uint32_t - trunc, - uint32_t seq, TcpSegmentNode*) = 0; - virtual int dup_reassembly_segment(Packet* p, TcpSegmentNode* left, TcpSegmentNode** retSeg) = - 0; - virtual int delete_reassembly_segment(TcpSegmentNode* seg) = 0; - + virtual int add_reassembly_segment(TcpSegmentDescriptor&, int16_t, uint32_t, uint32_t, uint32_t, TcpSegmentNode*) = 0; + virtual int dup_reassembly_segment(Packet*, TcpSegmentNode*, TcpSegmentNode**) = 0; + virtual int delete_reassembly_segment(TcpSegmentNode*) = 0; virtual void print(void); - TcpSession* session; - ReassemblyPolicy reassembly_policy; + TcpSession* session = nullptr; + ReassemblyPolicy reassembly_policy = ReassemblyPolicy::OS_DEFAULT; NormMode tcp_ips_data; TcpSegmentList seglist; - uint32_t seglist_base_seq; /* seq of first queued segment */ - uint32_t seg_count; /* number of current queued segments */ - uint32_t seg_bytes_total; /* total bytes currently queued */ - uint32_t seg_bytes_logical; /* logical bytes queued (total - overlaps) */ - uint32_t total_bytes_queued; /* total bytes queued (life of session) */ - uint32_t total_segs_queued; /* number of segments queued (life) */ - uint32_t overlap_count; /* overlaps encountered */ - - TcpSegmentDescriptor* tsd; - TcpSegmentNode* left; - TcpSegmentNode* right; - uint32_t seq; - uint32_t seq_end; - uint16_t len; - int32_t overlap; - int32_t slide; - int32_t trunc_len; - const uint8_t* rdata; - uint16_t rsize; - uint32_t rseq; - bool keep_segment; + uint32_t seglist_base_seq = 0; /* seq of first queued segment */ + uint32_t seg_count = 0; /* number of current queued segments */ + uint32_t seg_bytes_total = 0; /* total bytes currently queued */ + uint32_t seg_bytes_logical = 0; /* logical bytes queued (total - overlaps) */ + uint32_t total_bytes_queued = 0; /* total bytes queued (life of session) */ + uint32_t total_segs_queued = 0; /* number of segments queued (life) */ + uint32_t overlap_count = 0; /* overlaps encountered */ + + TcpSegmentDescriptor* tsd = nullptr; + TcpSegmentNode* left = nullptr; + TcpSegmentNode* right = nullptr; + const uint8_t* rdata = nullptr; + uint32_t seq = 0; + uint32_t seq_end = 0; + uint16_t len = 0; + int32_t overlap = 0; + int32_t slide = 0; + int32_t trunc_len = 0; + uint16_t rsize = 0; + uint32_t rseq = 0; + bool keep_segment = true; }; #endif diff --git a/src/stream/tcp/tcp_debug_trace.h b/src/stream/tcp/tcp_debug_trace.h index 33e327d5f..80b9550fa 100644 --- a/src/stream/tcp/tcp_debug_trace.h +++ b/src/stream/tcp/tcp_debug_trace.h @@ -58,17 +58,18 @@ static inline void TraceEvent(const Packet* p, TcpSegmentDescriptor*, uint32_t t // force relative ack to zero if not conveyed if (flags[1] != 'A') - rxd = ntohl(h->th_ack); + rxd = h->ack(); // FIXIT - SYN's seen with ack > 0 and ACK flag not set... if (p->packet_flags & PKT_STREAM_ORDER_OK) order = " (ins)"; else if (p->packet_flags & PKT_STREAM_ORDER_BAD) order = " (oos)"; + uint32_t rseq = ( txd ) ? h->seq() - txd : h->seq(); + uint32_t rack = ( rxd ) ? h->ack() - rxd : h->ack(); fprintf(stdout, "\n" FMTu64("-3") " %s=0x%02x Seq=%-4u Ack=%-4u Win=%-4u Len=%-4u%s\n", //"\n" FMTu64("-3") " %s=0x%02x Seq=%-4u Ack=%-4u Win=%-4u Len=%-4u End=%-4u%s\n", - pc.total_from_daq, flags, h->th_flags, ntohl(h->th_seq) - txd, ntohl(h->th_ack) - rxd, - ntohs(h->th_win), p->dsize, order); + pc.total_from_daq, flags, h->th_flags, rseq, rack, h->win(), p->dsize, order); } static inline void TraceSession(const Flow* lws) @@ -79,11 +80,13 @@ static inline void TraceSession(const Flow* lws) static inline void TraceState(const TcpTracker* a, const TcpTracker* b, const char* s) { - uint32_t why = a->get_snd_nxt() ? LCL(a, get_snd_nxt) : 0; + uint32_t ua = a->get_snd_una() ? LCL(a, get_snd_una) : 0; + uint32_t ns = a->get_snd_nxt() ? LCL(a, get_snd_nxt) : 0; - fprintf(stdout, " %s ST=%s:%02x UA=%-4u NS=%-4u LW=%-5u RN=%-4u RW=%-4u ", s, - statext[a->get_tcp_state()], a->s_mgr.sub_state, LCL(a, get_snd_una), why, - a->get_snd_wnd( ), RMT(a, r_nxt_ack, b), RMT(a, r_win_base, b)); + fprintf(stdout, + " %s ST=%s:%02x UA=%-4u NS=%-4u LW=%-5u RN=%-4u RW=%-4u ISS=%-4u IRS=%-4u ", + s, statext[a->get_tcp_state()], a->s_mgr.sub_state, ua, ns, a->get_snd_wnd( ), + RMT(a, r_nxt_ack, b), RMT(a, r_win_base, b), a->get_iss(), a->get_irs()); if ( a->s_mgr.state_queue != TcpStreamTracker::TCP_STATE_NONE ) fprintf(stdout, "QS=%s QC=0x%02x QA=%-4u", statext[a->s_mgr.state_queue], @@ -118,28 +121,19 @@ static inline void TraceTCP(const Packet* p, const Flow* lws, TcpSegmentDescript sdir = "SRV>"; cdir = "CLI<"; - if (ssn->tcp_init) - { - txd = srv->get_iss(); - rxd = cli->get_iss(); - } + txd = srv->get_iss(); + rxd = srv->get_irs(); } else if (p->packet_flags & PKT_FROM_CLIENT) { sdir = "SRV<"; cdir = "CLI>"; - if (ssn->tcp_init) - { - txd = cli->get_iss(); - rxd = srv->get_iss(); - } + txd = cli->get_iss(); + rxd = cli->get_irs(); } TraceEvent(p, tsd, txd, rxd); - if (!ssn->tcp_init) - return; - if (lws && ssn->lws_init) TraceSession(lws); diff --git a/src/stream/tcp/tcp_defs.h b/src/stream/tcp/tcp_defs.h index 48a3811a4..cc898d629 100644 --- a/src/stream/tcp/tcp_defs.h +++ b/src/stream/tcp/tcp_defs.h @@ -25,22 +25,6 @@ #include "main/snort_debug.h" #include "protocols/packet.h" -#if 0 -/* TCP states */ -#define TCP_STATE_NONE 0 -#define TCP_STATE_LISTEN 1 -#define TCP_STATE_SYN_RCVD 2 -#define TCP_STATE_SYN_SENT 3 -#define TCP_STATE_ESTABLISHED 4 -#define TCP_STATE_CLOSE_WAIT 5 -#define TCP_STATE_LAST_ACK 6 -#define TCP_STATE_FIN_WAIT_1 7 -#define TCP_STATE_CLOSING 8 -#define TCP_STATE_FIN_WAIT_2 9 -#define TCP_STATE_TIME_WAIT 10 -#define TCP_STATE_CLOSED 11 -#endif - /* actions */ #define ACTION_NOTHING 0x00000000 #define ACTION_FLUSH_SENDER_STREAM 0x00000001 @@ -70,6 +54,7 @@ #define PAWS_WINDOW 60 #define PAWS_24DAYS 2073600 /* 24 days in seconds */ +#define SUB_STATE_NONE 0x00 #define SUB_SYN_SENT 0x01 #define SUB_ACK_SENT 0x02 #define SUB_SETUP_OK 0x03 @@ -160,17 +145,6 @@ enum FlushPolicy STREAM_FLPOLICY_ON_DATA, /* protocol aware ips */ }; -#if 0 -struct TcpDataBlock -{ - Packet* pkt; - uint32_t seq; - uint32_t ack; - uint32_t win; - uint32_t end_seq; - uint32_t ts; -}; -#endif //#define DEBUG_STREAM_EX #ifdef DEBUG_STREAM_EX diff --git a/src/stream/tcp/tcp_event_logger.cc b/src/stream/tcp/tcp_event_logger.cc index 94b7fc933..2efbbbfaa 100644 --- a/src/stream/tcp/tcp_event_logger.cc +++ b/src/stream/tcp/tcp_event_logger.cc @@ -16,7 +16,7 @@ // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. //-------------------------------------------------------------------------- -// tcp_events.cc author davis mcpherson +// tcp_event_logger.cc author davis mcpherson // Created on: Jul 30, 2015 #include "main/snort_config.h" diff --git a/src/stream/tcp/tcp_event_logger.h b/src/stream/tcp/tcp_event_logger.h index 74527bd85..007cd0e19 100644 --- a/src/stream/tcp/tcp_event_logger.h +++ b/src/stream/tcp/tcp_event_logger.h @@ -16,7 +16,7 @@ // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. //-------------------------------------------------------------------------- -// tcp_events.h author davis mcpherson +// tcp_event_logger.h author davis mcpherson // Created on: Jul 30, 2015 #ifndef TCP_EVENT_LOGGER_H diff --git a/src/stream/tcp/tcp_normalizer.cc b/src/stream/tcp/tcp_normalizer.cc index 9f71ce30d..ab888ae8c 100644 --- a/src/stream/tcp/tcp_normalizer.cc +++ b/src/stream/tcp/tcp_normalizer.cc @@ -45,8 +45,7 @@ static inline int SetupOK(const TcpTracker* st) } TcpNormalizer::TcpNormalizer(StreamPolicy os_policy, TcpSession* session, TcpTracker* tracker) : - os_policy(os_policy), session(session), tracker(tracker), - peer_tracker(nullptr) + os_policy(os_policy), session(session), tracker(tracker) { tcp_ips_enabled = Normalize_IsEnabled(NORM_TCP_IPS); trim_syn = Normalize_GetMode(NORM_TCP_TRIM_SYN); @@ -56,9 +55,6 @@ TcpNormalizer::TcpNormalizer(StreamPolicy os_policy, TcpSession* session, TcpTra strip_ecn = Normalize_GetMode(NORM_TCP_ECN_STR); tcp_block = Normalize_GetMode(NORM_TCP_BLOCK); opt_block = Normalize_GetMode(NORM_TCP_OPT); - - paws_ts_fudge = 0; - paws_drop_zero_ts = true; } const PegInfo* TcpNormalizer::get_normalization_pegs() @@ -77,8 +73,8 @@ void TcpNormalizer::trim_payload( { if (mode == NORM_MODE_ON) { - uint16_t fat = tsd.get_pkt()->dsize - max; - tsd.get_pkt()->dsize = max; + uint16_t fat = tsd.get_seg_len() - max; + tsd.set_seg_len(max); tsd.get_pkt()->packet_flags |= (PKT_MODIFIED | PKT_RESIZED); tsd.set_end_seq(tsd.get_end_seq() - fat); } @@ -196,9 +192,9 @@ uint32_t TcpNormalizer::get_tcp_timestamp(TcpSegmentDescriptor& tsd, bool strip) tcp::TcpOptIterator iter(tsd.get_tcph(), tsd.get_pkt() ); // using const because non-const is not supported - for (const tcp::TcpOption& opt : iter) + for ( const tcp::TcpOption& opt : iter ) { - if (opt.code == tcp::TcpOptCode::TIMESTAMP) + if ( opt.code == tcp::TcpOptCode::TIMESTAMP ) { bool stripped = false; @@ -207,7 +203,7 @@ uint32_t TcpNormalizer::get_tcp_timestamp(TcpSegmentDescriptor& tsd, bool strip) if (!stripped) { - tsd.set_ts(EXTRACT_32BITS(opt.data) ); + tsd.set_ts(extract_32bits(opt.data) ); DebugFormat(DEBUG_STREAM_STATE, "Found timestamp %lu\n", tsd.get_ts()); return TF_TSTAMP; } @@ -224,10 +220,10 @@ bool TcpNormalizer::validate_rst_seq_geq(TcpSegmentDescriptor& tsd) { DebugFormat(DEBUG_STREAM_STATE, "Checking end_seq (%X) > r_win_base (%X) && seq (%X) < r_nxt_ack(%X)\n", - tsd.get_end_seq(), tracker->r_win_base, tsd.get_seq(), tracker->r_nxt_ack + + tsd.get_end_seq(), tracker->r_win_base, tsd.get_seg_seq(), tracker->r_nxt_ack + get_stream_window(tsd)); - if (SEQ_GEQ(tsd.get_seq(), tracker->r_nxt_ack)) + if ( ( tracker->r_nxt_ack == 0 ) || SEQ_GEQ(tsd.get_seg_seq(), tracker->r_nxt_ack) ) { DebugMessage(DEBUG_STREAM_STATE, "rst is valid seq (>= next seq)!\n"); return true; @@ -241,13 +237,17 @@ bool TcpNormalizer::validate_rst_end_seq_geq(TcpSegmentDescriptor& tsd) { DebugFormat(DEBUG_STREAM_STATE, "Checking end_seq (%X) > r_win_base (%X) && seq (%X) < r_nxt_ack(%X)\n", - tsd.get_end_seq(), tracker->r_win_base, tsd.get_seq(), tracker->r_nxt_ack + + tsd.get_end_seq(), tracker->r_win_base, tsd.get_seg_seq(), tracker->r_nxt_ack + get_stream_window(tsd)); - if (SEQ_GEQ(tsd.get_end_seq(), tracker->r_win_base)) + // FIXIT - check for r_win_base == 0 is hack for uninitialized r_win_base, fix this + if ( tracker->r_win_base == 0 ) + return true; + + if ( SEQ_GEQ(tsd.get_end_seq(), tracker->r_win_base)) { // reset must be admitted when window closed - if (SEQ_LEQ(tsd.get_seq(), tracker->r_win_base + get_stream_window(tsd))) + if (SEQ_LEQ(tsd.get_seg_seq(), tracker->r_win_base + get_stream_window(tsd))) { DebugMessage(DEBUG_STREAM_STATE, "rst is valid seq (within window)!\n"); return true; @@ -262,10 +262,11 @@ bool TcpNormalizer::validate_rst_seq_eq(TcpSegmentDescriptor& tsd) { DebugFormat(DEBUG_STREAM_STATE, "Checking end_seq (%X) > r_win_base (%X) && seq (%X) < r_nxt_ack(%X)\n", - tsd.get_end_seq(), tracker->r_win_base, tsd.get_seq(), tracker->r_nxt_ack + + tsd.get_end_seq(), tracker->r_win_base, tsd.get_seg_seq(), tracker->r_nxt_ack + get_stream_window(tsd)); - if (SEQ_EQ(tsd.get_seq(), tracker->r_nxt_ack)) + // FIXIT - check for r_nxt_ack == 0 is hack for uninitialized r_nxt_ack, fix this + if ( ( tracker->r_nxt_ack == 0 ) || SEQ_EQ(tsd.get_seg_seq(), tracker->r_nxt_ack) ) { DebugMessage(DEBUG_STREAM_STATE, "rst is valid seq (next seq)!\n"); return true; @@ -286,16 +287,16 @@ bool TcpNormalizer::validate_rst(TcpSegmentDescriptor& tsd) int TcpNormalizer::validate_paws_timestamp(TcpSegmentDescriptor& tsd) { - if ( ( (int)( ( tsd.get_ts() - peer_tracker->ts_last ) + paws_ts_fudge ) ) < 0 ) + if ( ( (int)( ( tsd.get_ts() - peer_tracker->get_ts_last() ) + paws_ts_fudge ) ) < 0 ) { DebugMessage(DEBUG_STREAM_STATE, "Packet outside PAWS window, dropping\n"); /* bail, we've got a packet outside the PAWS window! */ //inc_tcp_discards(); - ( ( TcpSession* )tsd.get_flow()->session )->tel->set_tcp_event(EVENT_BAD_TIMESTAMP); + ( ( TcpSession* )tsd.get_flow()->session )->tel.set_tcp_event(EVENT_BAD_TIMESTAMP); packet_dropper(tsd, NORM_TCP_OPT); return ACTION_BAD_PKT; } - else if ( ( peer_tracker->ts_last != 0 ) + else if ( ( peer_tracker->get_ts_last() != 0 ) && ( ( uint32_t )tsd.get_pkt()->pkth->ts.tv_sec > peer_tracker->get_ts_last_packet() + PAWS_24DAYS ) ) { @@ -304,7 +305,7 @@ int TcpNormalizer::validate_paws_timestamp(TcpSegmentDescriptor& tsd) "packet PAWS timestamp way too far ahead of last packet %d %d...\n", tsd.get_pkt()->pkth->ts.tv_sec, peer_tracker->get_ts_last_packet() ); //inc_tcp_discards(); - ( ( TcpSession* )tsd.get_flow()->session )->tel->set_tcp_event(EVENT_BAD_TIMESTAMP); + ( ( TcpSession* )tsd.get_flow()->session )->tel.set_tcp_event(EVENT_BAD_TIMESTAMP); packet_dropper(tsd, NORM_TCP_OPT); return ACTION_BAD_PKT; } @@ -320,10 +321,10 @@ bool TcpNormalizer::is_paws_ts_checked_required(TcpSegmentDescriptor&) return true; } -int TcpNormalizer::validate_paws(TcpSegmentDescriptor& tsd, int* got_ts) +int TcpNormalizer::validate_paws(TcpSegmentDescriptor& tsd) { - *got_ts = get_tcp_timestamp(tsd, false); - if ( *got_ts ) + tcp_ts_flags = get_tcp_timestamp(tsd, false); + if ( tcp_ts_flags ) { bool check_ts = is_paws_ts_checked_required(tsd); @@ -339,18 +340,18 @@ int TcpNormalizer::validate_paws(TcpSegmentDescriptor& tsd, int* got_ts) // with the missing timestamp. Log an alert, but continue to process the packet DebugMessage(DEBUG_STREAM_STATE, "packet no timestamp, had one earlier from this side...ok for now...\n"); - ( ( TcpSession* )tsd.get_flow()->session )->tel->set_tcp_event(EVENT_NO_TIMESTAMP); + ( ( TcpSession* )tsd.get_flow()->session )->tel.set_tcp_event(EVENT_NO_TIMESTAMP); /* Ignore the timestamp for this first packet, next one will checked. */ if ( session->config->policy == StreamPolicy::OS_SOLARIS ) - tracker->flags &= ~TF_TSTAMP; + tracker->clear_tf_flags(TF_TSTAMP); packet_dropper(tsd, NORM_TCP_OPT); return ACTION_NOTHING; } } -int TcpNormalizer::handle_paws_no_timestamps(TcpSegmentDescriptor& tsd, int* got_ts) +int TcpNormalizer::handle_paws_no_timestamps(TcpSegmentDescriptor& tsd) { // if we are not handling timestamps, and this isn't a syn (only), and we have seen a // valid 3way setup, then we strip (nop) the timestamp option. this includes the cases @@ -358,23 +359,25 @@ int TcpNormalizer::handle_paws_no_timestamps(TcpSegmentDescriptor& tsd, int* got int strip = ( SetupOK(peer_tracker) && SetupOK(tracker) ); DebugMessage(DEBUG_STREAM_STATE, "listener not doing timestamps...\n"); - *got_ts = get_tcp_timestamp(tsd, strip); - if (*got_ts) + tcp_ts_flags = get_tcp_timestamp(tsd, strip); + if (tcp_ts_flags) { - if (!(peer_tracker->flags & TF_TSTAMP)) + if (!(peer_tracker->get_tf_flags() & TF_TSTAMP)) { // SYN skipped, may have missed talker's timestamp , so set it now. - peer_tracker->flags |= TF_TSTAMP; if (tsd.get_ts() == 0) - peer_tracker->flags |= TF_TSTAMP_ZERO; + peer_tracker->set_tf_flags(TF_TSTAMP | TF_TSTAMP_ZERO); + else + peer_tracker->set_tf_flags(TF_TSTAMP); } // Only valid to test this if listener is using timestamps. Otherwise, timestamp // in this packet is not used, regardless of its value. - if ( ( paws_drop_zero_ts && ( tsd.get_ts() == 0 ) ) && ( tracker->flags & TF_TSTAMP ) ) + if ( ( paws_drop_zero_ts && ( tsd.get_ts() == 0 ) ) && ( tracker->get_tf_flags() & + TF_TSTAMP ) ) { DebugMessage(DEBUG_STREAM_STATE, "Packet with 0 timestamp, dropping\n"); - ( ( TcpSession* )tsd.get_flow()->session )->tel->set_tcp_event(EVENT_BAD_TIMESTAMP); + ( ( TcpSession* )tsd.get_flow()->session )->tel.set_tcp_event(EVENT_BAD_TIMESTAMP); return ACTION_BAD_PKT; } } @@ -382,7 +385,7 @@ int TcpNormalizer::handle_paws_no_timestamps(TcpSegmentDescriptor& tsd, int* got return ACTION_NOTHING; } -int TcpNormalizer::handle_paws(TcpSegmentDescriptor& tsd, int* got_ts) +int TcpNormalizer::handle_paws(TcpSegmentDescriptor& tsd) { if ( tsd.get_tcph()->is_rst() ) return ACTION_NOTHING; @@ -396,22 +399,22 @@ int TcpNormalizer::handle_paws(TcpSegmentDescriptor& tsd, int* got_ts) } #endif - if ((peer_tracker->flags & TF_TSTAMP) && (tracker->flags & TF_TSTAMP)) + if ((peer_tracker->get_tf_flags() & TF_TSTAMP) && (tracker->get_tf_flags() & TF_TSTAMP)) { DebugMessage(DEBUG_STREAM_STATE, "Checking timestamps for PAWS\n"); - return validate_paws(tsd, got_ts); + return validate_paws(tsd); } else if (tsd.get_tcph()->is_syn_only()) { - *got_ts = get_tcp_timestamp(tsd, 0); - if (*got_ts) - peer_tracker->flags |= TF_TSTAMP; + tcp_ts_flags = get_tcp_timestamp(tsd, 0); + if (tcp_ts_flags) + peer_tracker->set_tf_flags(TF_TSTAMP); return ACTION_NOTHING; } else { - return handle_paws_no_timestamps(tsd, got_ts); + return handle_paws_no_timestamps(tsd); } } diff --git a/src/stream/tcp/tcp_normalizer.h b/src/stream/tcp/tcp_normalizer.h index 9a3f86d40..2df6dfb5c 100644 --- a/src/stream/tcp/tcp_normalizer.h +++ b/src/stream/tcp/tcp_normalizer.h @@ -60,7 +60,7 @@ public: virtual void ecn_stripper(Packet*); virtual uint32_t get_stream_window(TcpSegmentDescriptor&); virtual uint32_t get_tcp_timestamp(TcpSegmentDescriptor&, bool strip); - virtual int handle_paws(TcpSegmentDescriptor&, int*); + virtual int handle_paws(TcpSegmentDescriptor&); virtual bool validate_rst(TcpSegmentDescriptor&); virtual int handle_repeated_syn(TcpSegmentDescriptor&) = 0; virtual uint16_t set_urg_offset(const tcp::TCPHdr* tcph, uint16_t dsize); @@ -128,6 +128,16 @@ public: return tcp_ips_enabled; } + bool handling_timestamps(void) const + { + return tcp_ts_flags != TF_NONE; + } + + uint32_t get_timestamp_flags(void) + { + return tcp_ts_flags; + } + protected: TcpNormalizer(StreamPolicy, TcpSession*, TcpTracker*); virtual void trim_payload(TcpSegmentDescriptor&, uint32_t, NormMode, TcpPegCounts); @@ -138,13 +148,13 @@ protected: virtual int validate_paws_timestamp(TcpSegmentDescriptor&); virtual bool is_paws_ts_checked_required(TcpSegmentDescriptor&); - virtual int validate_paws(TcpSegmentDescriptor&, int*); - virtual int handle_paws_no_timestamps(TcpSegmentDescriptor&, int*); + virtual int validate_paws(TcpSegmentDescriptor&); + virtual int handle_paws_no_timestamps(TcpSegmentDescriptor&); StreamPolicy os_policy; - TcpSession* session; - TcpTracker* tracker; - TcpTracker* peer_tracker; + TcpSession* session = nullptr; + TcpTracker* tracker = nullptr; + TcpTracker* peer_tracker = nullptr; bool tcp_ips_enabled; NormMode trim_syn; NormMode trim_rst; @@ -153,8 +163,9 @@ protected: NormMode strip_ecn; NormMode tcp_block; NormMode opt_block; - int32_t paws_ts_fudge; - bool paws_drop_zero_ts; + int32_t paws_ts_fudge = 0; + bool paws_drop_zero_ts = true; + int tcp_ts_flags = 0; }; #endif diff --git a/src/stream/tcp/tcp_normalizers.cc b/src/stream/tcp/tcp_normalizers.cc index ec43fd7d4..bcc71368c 100644 --- a/src/stream/tcp/tcp_normalizers.cc +++ b/src/stream/tcp/tcp_normalizers.cc @@ -187,7 +187,7 @@ public: { } bool validate_rst(TcpSegmentDescriptor&) override; - int handle_paws(TcpSegmentDescriptor&, int*) override; + int handle_paws(TcpSegmentDescriptor&) override; int handle_repeated_syn(TcpSegmentDescriptor&) override; }; @@ -269,7 +269,7 @@ static inline int handle_repeated_syn_mswin(TcpTracker* talker, TcpTracker* list /* Windows has some strange behaviour here. If the sequence of the reset is the * next expected sequence, it Resets. Otherwise it ignores the 2nd SYN. */ - if (SEQ_EQ(tsd.get_seq(), listener->r_nxt_ack)) + if (SEQ_EQ(tsd.get_seg_seq(), listener->r_nxt_ack)) { DebugMessage(DEBUG_STREAM_STATE, "Got syn on established windows ssn, which causes Reset, bailing\n"); @@ -290,7 +290,7 @@ static inline int handle_repeated_syn_bsd(TcpTracker* talker, TcpSegmentDescript TcpSession* session) { /* If its not a retransmission of the actual SYN... RESET */ - if (!SEQ_EQ(tsd.get_seq(), talker->get_iss())) + if (!SEQ_EQ(tsd.get_seg_seq(), talker->get_iss())) { DebugMessage(DEBUG_STREAM_STATE, "Got syn on established ssn, which causes Reset, bailing\n"); @@ -312,10 +312,10 @@ static inline bool paws_3whs_zero_ts_not_supported(TcpTracker* talker, TcpTracke { bool check_ts = true; - if (talker->flags & TF_TSTAMP_ZERO) + if (talker->get_tf_flags() & TF_TSTAMP_ZERO) { - talker->flags &= ~TF_TSTAMP; - listener->flags &= ~TF_TSTAMP; + talker->clear_tf_flags(TF_TSTAMP); + listener->clear_tf_flags(TF_TSTAMP); check_ts = false; } @@ -328,13 +328,13 @@ static inline bool paws_3whs_zero_ts_supported(TcpTracker* talker, TcpTracker* l { bool check_ts = true; - if ( talker->flags & TF_TSTAMP_ZERO ) + if ( talker->get_tf_flags() & TF_TSTAMP_ZERO ) { - talker->flags &= ~TF_TSTAMP_ZERO; - if ( SEQ_EQ(listener->r_nxt_ack, tsd.get_seq() ) ) + talker->clear_tf_flags(TF_TSTAMP_ZERO); + if ( SEQ_EQ(listener->r_nxt_ack, tsd.get_seg_seq() ) ) { // Ignore timestamp for this first packet, save to check on next - talker->ts_last = tsd.get_ts(); + talker->set_ts_last(tsd.get_ts() ); check_ts = false; } } @@ -452,7 +452,8 @@ bool TcpNormalizerHpux11::validate_rst(TcpSegmentDescriptor& tsd) bool TcpNormalizerHpux11::is_paws_ts_checked_required(TcpSegmentDescriptor& tsd) { /* HPUX 11 ignores timestamps for out of order segments */ - if ((tracker->flags & TF_MISSING_PKT) || !SEQ_EQ(tracker->r_nxt_ack, tsd.get_seq())) + if ((tracker->get_tf_flags() & TF_MISSING_PKT) || !SEQ_EQ(tracker->r_nxt_ack, + tsd.get_seg_seq())) return false; else return true; @@ -509,14 +510,14 @@ bool TcpNormalizerProxy::validate_rst(TcpSegmentDescriptor& tsd) { DebugFormat(DEBUG_STREAM_STATE, "Proxy Normalizer - Not Valid\n end_seq (%X) > r_win_base (%X) && seq (%X) < r_nxt_ack(%X)\n", - tsd.get_end_seq(), tracker->r_win_base, tsd.get_seq(), tracker->r_nxt_ack + + tsd.get_end_seq(), tracker->r_win_base, tsd.get_seg_seq(), tracker->r_nxt_ack + get_stream_window(tsd)); } return false; } -int TcpNormalizerProxy::handle_paws(TcpSegmentDescriptor&, int*) +int TcpNormalizerProxy::handle_paws(TcpSegmentDescriptor&) { return ACTION_NOTHING; } diff --git a/src/stream/tcp/tcp_reassembler.cc b/src/stream/tcp/tcp_reassembler.cc index f7ac2d3ff..7ba1bb135 100644 --- a/src/stream/tcp/tcp_reassembler.cc +++ b/src/stream/tcp/tcp_reassembler.cc @@ -202,10 +202,10 @@ void TcpReassembler::queue_reassembly_segment(TcpSegmentNode* prev, TcpSegmentNo bool TcpReassembler::is_segment_fasttrack(TcpSegmentNode* tail, TcpSegmentDescriptor& tsd) { - DebugFormat(DEBUG_STREAM_STATE, "Checking seq for fast track: %X > %X\n", tsd.get_seq(), + DebugFormat(DEBUG_STREAM_STATE, "Checking seq for fast track: %X > %X\n", tsd.get_seg_seq(), tail->seq + tail->payload_size); - if ( SEQ_EQ(tsd.get_seq(), tail->seq + tail->payload_size) ) + if ( SEQ_EQ(tsd.get_seg_seq(), tail->seq + tail->payload_size) ) return true; return false; @@ -249,7 +249,7 @@ int TcpReassembler::add_reassembly_segment(TcpSegmentDescriptor& tsd, int16_t le } // FIXIT-L don't allocate overlapped part - tsn = TcpSegmentNode::init(tsd.get_pkt()->pkth->ts, tsd.get_pkt()->data, tsd.get_pkt()->dsize); + tsn = TcpSegmentNode::init(tsd); if ( !tsn ) return STREAM_INSERT_FAILED; else if ( TcpSegmentNode::needs_pruning() ) @@ -266,7 +266,7 @@ int TcpReassembler::add_reassembly_segment(TcpSegmentDescriptor& tsd, int16_t le // FIXIT - The urgent ptr handling is broken... urg_offset is set here but currently // not actually referenced anywhere else. In 2.9.7 the FlushStream function did reference // this field but that code has been lost... urg ptr handling needs to be reviewed and fixed - tsn->urg_offset = tracker->normalizer->set_urg_offset(tsd.get_tcph(), tsd.get_pkt()->dsize); + tsn->urg_offset = tracker->normalizer->set_urg_offset(tsd.get_tcph(), tsd.get_seg_len() ); queue_reassembly_segment(left, tsn); seg_bytes_logical += tsn->payload_size; total_bytes_queued += tsn->payload_size; @@ -285,7 +285,7 @@ int TcpReassembler::add_reassembly_segment(TcpSegmentDescriptor& tsd, int16_t le int TcpReassembler::dup_reassembly_segment(Packet* p, TcpSegmentNode* left, TcpSegmentNode** retSeg) { - TcpSegmentNode* tsn = TcpSegmentNode::init(left->tv, left->payload, left->payload_size); + TcpSegmentNode* tsn = TcpSegmentNode::init(*left); if ( !tsn ) return STREAM_INSERT_FAILED; if ( TcpSegmentNode::needs_pruning() ) @@ -414,15 +414,15 @@ int TcpReassembler::purge_to_seq(uint32_t flush_seq) if ( !server_side ) { - int32_t delta = last_ts - session->server->ts_last; + int32_t delta = last_ts - session->server->get_ts_last(); if ( delta > 0 ) - session->server->ts_last = last_ts; + session->server->set_ts_last(last_ts); } else { - int32_t delta = last_ts - session->client->ts_last; + int32_t delta = last_ts - session->client->get_ts_last(); if ( delta > 0 ) - session->client->ts_last = last_ts; + session->client->set_ts_last(last_ts); } return purged_bytes; @@ -467,8 +467,7 @@ int TcpReassembler::purge_flushed_ackd(void) void TcpReassembler::show_rebuilt_packet(Packet* pkt) { - if ( ( session->config->flags & STREAM_CONFIG_SHOW_PACKETS ) - || ( session->config->flags & STREAM_CONFIG_SHOW_PACKETS ) ) + if ( session->config->flags & STREAM_CONFIG_SHOW_PACKETS ) { LogFlow(pkt); LogNetData(pkt->data, pkt->dsize, pkt); @@ -564,12 +563,12 @@ int TcpReassembler::flush_data_segments(Packet* p, uint32_t toSeq, uint8_t* flus // FIXIT-L FIN may be in toSeq causing bogus gap counts. if (((tsn->next && (tsn->seq + tsn->payload_size != tsn->next->seq)) || (!tsn->next && (tsn->seq + tsn->payload_size < toSeq))) - && !(tracker->flags & TF_FIRST_PKT_MISSING)) + && !(tracker->get_tf_flags() & TF_FIRST_PKT_MISSING)) { if ( tsn->next ) seglist.next = tsn->next; - tracker->flags |= TF_MISSING_PKT; + tracker->set_tf_flags(TF_MISSING_PKT); break; } seglist.next = tsn->next; @@ -698,23 +697,18 @@ int TcpReassembler::_flush_to_seq(uint32_t bytes, Packet* p, uint32_t pkt_flags) const uint8_t* s5_pkt_end = s5_pkt->data + s5_pkt->max_dsize; flushed_bytes = flush_data_segments(p, stop_seq, ( uint8_t* )s5_pkt->data, s5_pkt_end); - if ( !flushed_bytes ) + if ( flushed_bytes == 0 ) break; /* No more data... bail */ - else if ( !s5_pkt->dsize ) - { - tcpStats.rebuilt_buffers++; - bytes_processed += flushed_bytes; - } - else - { - s5_pkt->packet_flags |= ( PKT_REBUILT_STREAM | PKT_STREAM_EST ); - - if ( ( p->packet_flags & PKT_PDU_TAIL ) ) - s5_pkt->packet_flags |= PKT_PDU_TAIL; + bytes_processed += flushed_bytes; + seglist_base_seq += flushed_bytes; - tcpStats.rebuilt_packets++; - bytes_processed += flushed_bytes; + if ( s5_pkt->dsize ) + { + if ( p->packet_flags & PKT_PDU_TAIL ) + s5_pkt->packet_flags |= ( PKT_REBUILT_STREAM | PKT_STREAM_EST | PKT_PDU_TAIL ); + else + s5_pkt->packet_flags |= ( PKT_REBUILT_STREAM | PKT_STREAM_EST ); // FIXIT - this came with merge should it be here? //s5_pkt->application_protocol_ordinal = @@ -724,32 +718,30 @@ int TcpReassembler::_flush_to_seq(uint32_t bytes, Packet* p, uint32_t pkt_flags) tcpStats.rebuilt_packets++; tcpStats.rebuilt_bytes += flushed_bytes; - { - ProfileExclude profile_exclude(s5TcpFlushPerfStats); - Snort::detect_rebuilt_packet(s5_pkt); - } + ProfileExclude profile_exclude(s5TcpFlushPerfStats); + Snort::detect_rebuilt_packet(s5_pkt); + } + else + { + tcpStats.rebuilt_buffers++; + tcpStats.rebuilt_buffers++; } - - seglist_base_seq += flushed_bytes; DebugFormat(DEBUG_STREAM_STATE, "setting seglist_base_seq to 0x%X\n", seglist_base_seq); if ( tracker->splitter ) tracker->splitter->update(); - // TBD abort should be by PAF callback only since - // recovery may be possible in some cases - if ( tracker->flags & TF_MISSING_PKT ) + // FIXIT - abort should be by PAF callback only since recovery may be + // possible in some cases + if ( tracker->get_tf_flags() & TF_MISSING_PKT ) { - tracker->flags |= TF_MISSING_PREV_PKT; - tracker->flags |= TF_PKT_MISSED; - tracker->flags &= ~TF_MISSING_PKT; + tracker->set_tf_flags(TF_MISSING_PREV_PKT | TF_PKT_MISSED); + tracker->clear_tf_flags(TF_MISSING_PKT); tcpStats.gaps++; } else - { - tracker->flags &= ~TF_MISSING_PREV_PKT; - } + tracker->clear_tf_flags(TF_MISSING_PREV_PKT); } while ( seglist.next and flush_data_ready( ) ); @@ -776,27 +768,25 @@ int TcpReassembler::flush_to_seq(uint32_t bytes, Packet* p, uint32_t pkt_flags) return 0; } - if ( !flush_data_ready( ) && !( tracker->flags & TF_FORCE_FLUSH ) ) + if ( !flush_data_ready( ) && !( tracker->get_tf_flags() & TF_FORCE_FLUSH ) ) { DebugMessage(DEBUG_STREAM_STATE, "only 1 packet in seglist no need to flush\n"); return 0; } - tracker->flags &= ~TF_MISSING_PKT; - tracker->flags &= ~TF_MISSING_PREV_PKT; + tracker->clear_tf_flags(TF_MISSING_PKT | TF_MISSING_PREV_PKT); /* This will set this flag on the first reassembly * if reassembly for this direction was set midstream */ if ( SEQ_LT(seglist_base_seq, seglist.next->seq) - && !( tracker->flags & TF_FIRST_PKT_MISSING ) ) + && !( tracker->get_tf_flags() & TF_FIRST_PKT_MISSING ) ) { uint32_t missed = seglist.next->seq - seglist_base_seq; if ( missed <= bytes ) bytes -= missed; - tracker->flags |= TF_MISSING_PREV_PKT; - tracker->flags |= TF_PKT_MISSED; + tracker->set_tf_flags(TF_MISSING_PREV_PKT | TF_PKT_MISSED); tcpStats.gaps++; seglist_base_seq = seglist.next->seq; @@ -805,7 +795,7 @@ int TcpReassembler::flush_to_seq(uint32_t bytes, Packet* p, uint32_t pkt_flags) return 0; } - tracker->flags &= ~TF_FIRST_PKT_MISSING; + tracker->clear_tf_flags(TF_FIRST_PKT_MISSING); return _flush_to_seq(bytes, p, pkt_flags); } @@ -896,12 +886,12 @@ void TcpReassembler::final_flush(Packet* p, PegCount& peg, uint32_t dir) tmp_pcap_hdr->ts.tv_usec = seglist.head->tv.tv_usec; } - tracker->flags |= TF_FORCE_FLUSH; + tracker->set_tf_flags(TF_FORCE_FLUSH); if ( flush_stream(p, dir) ) purge_flushed_ackd( ); - tracker->flags &= ~TF_FORCE_FLUSH; + tracker->clear_tf_flags(TF_FORCE_FLUSH); } void TcpReassembler::flush_queued_segments(Flow* flow, bool clear, Packet* p) @@ -1219,7 +1209,7 @@ void TcpReassembler::insert_segment_in_empty_seglist(TcpSegmentDescriptor& tsd) const tcp::TCPHdr* tcph = tsd.get_tcph(); uint32_t overlap = 0; - uint32_t seq = tsd.get_seq(); + uint32_t seq = tsd.get_seg_seq(); if ( tcph->is_syn() ) seq++; @@ -1227,8 +1217,8 @@ void TcpReassembler::insert_segment_in_empty_seglist(TcpSegmentDescriptor& tsd) if ( SEQ_GT(tracker->r_win_base, seq) ) { DebugMessage(DEBUG_STREAM_STATE, "segment overlaps ack'd data...\n"); - overlap = tracker->r_win_base - tsd.get_seq(); - if ( overlap >= tsd.get_pkt()->dsize ) + overlap = tracker->r_win_base - tsd.get_seg_seq(); + if ( overlap >= tsd.get_seg_len() ) { DebugMessage(DEBUG_STREAM_STATE, "full overlap on ack'd data, dropping segment\n"); return; @@ -1236,11 +1226,11 @@ void TcpReassembler::insert_segment_in_empty_seglist(TcpSegmentDescriptor& tsd) } // BLOCK add new block to seglist containing data - add_reassembly_segment(tsd, tsd.get_pkt()->dsize, overlap, 0, tsd.get_seq() + overlap, NULL); + add_reassembly_segment(tsd, tsd.get_seg_len(), overlap, 0, tsd.get_seg_seq() + overlap, NULL); DebugFormat(DEBUG_STREAM_STATE, "Attached new queue to seglist, %d bytes queued, base_seq 0x%X\n", - tsd.get_pkt()->dsize - overlap, seglist_base_seq); + tsd.get_seg_len() - overlap, seglist_base_seq); } void TcpReassembler::init_overlap_editor(TcpSegmentDescriptor& tsd) @@ -1258,15 +1248,15 @@ void TcpReassembler::init_overlap_editor(TcpSegmentDescriptor& tsd) if ( seglist.head && seglist.tail ) { - if ( SEQ_GT(tsd.get_seq(), seglist.head->seq) ) - dist_head = tsd.get_seq() - seglist.head->seq; + if ( SEQ_GT(tsd.get_seg_seq(), seglist.head->seq) ) + dist_head = tsd.get_seg_seq() - seglist.head->seq; else - dist_head = seglist.head->seq - tsd.get_seq(); + dist_head = seglist.head->seq - tsd.get_seg_seq(); - if ( SEQ_GT(tsd.get_seq(), seglist.tail->seq) ) - dist_tail = tsd.get_seq() - seglist.tail->seq; + if ( SEQ_GT(tsd.get_seg_seq(), seglist.tail->seq) ) + dist_tail = tsd.get_seg_seq() - seglist.tail->seq; else - dist_tail = seglist.tail->seq - tsd.get_seq(); + dist_tail = seglist.tail->seq - tsd.get_seg_seq(); } else dist_head = dist_tail = 0; @@ -1286,7 +1276,7 @@ void TcpReassembler::init_overlap_editor(TcpSegmentDescriptor& tsd) ); right = tsn; - if ( SEQ_GEQ(right->seq, tsd.get_seq() ) ) + if ( SEQ_GEQ(right->seq, tsd.get_seg_seq() ) ) break; left = right; } @@ -1309,7 +1299,7 @@ void TcpReassembler::init_overlap_editor(TcpSegmentDescriptor& tsd) ); left = tsn; - if ( SEQ_LT(left->seq, tsd.get_seq() ) ) + if ( SEQ_LT(left->seq, tsd.get_seg_seq() ) ) break; right = left; } @@ -1332,7 +1322,8 @@ int TcpReassembler::insert_segment_in_seglist(TcpSegmentDescriptor& tsd) DebugFormat(DEBUG_STREAM_STATE, "Queuing %d bytes on stream!\nbase_seq: %X seq: %X seq_end: %X\n", - tsd.get_end_seq() - tsd.get_seq(), seglist_base_seq, tsd.get_seq(), tsd.get_end_seq()); + tsd.get_end_seq() - tsd.get_seg_seq(), seglist_base_seq, tsd.get_seg_seq(), + tsd.get_end_seq()); DebugFormat(DEBUG_STREAM_STATE, "%d segments on seglist\n", get_pending_segment_count(0)); DebugMessage(DEBUG_STREAM_STATE, "!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+\n"); @@ -1348,7 +1339,7 @@ int TcpReassembler::insert_segment_in_seglist(TcpSegmentDescriptor& tsd) seglist.tail->seq, seglist.tail->payload_size); // BLOCK add to existing block and/or allocate new block - rc = add_reassembly_segment(tsd, tsd.get_pkt()->dsize, 0, 0, tsd.get_seq(), left); + rc = add_reassembly_segment(tsd, tsd.get_seg_len(), 0, 0, tsd.get_seg_seq(), left); return rc; } @@ -1364,7 +1355,7 @@ int TcpReassembler::insert_segment_in_seglist(TcpSegmentDescriptor& tsd) if ( keep_segment ) { /* Adjust slide so that is correct relative to orig seq */ - slide = seq - tsd.get_seq(); + slide = seq - tsd.get_seg_seq(); rc = add_reassembly_segment(tsd, len, slide, trunc_len, seq, left); } else @@ -1388,21 +1379,15 @@ int TcpReassembler::queue_packet_for_reassembly(TcpSegmentDescriptor& tsd) return STREAM_INSERT_OK; } - if ( SEQ_GT(tracker->r_win_base, tsd.get_seq() ) ) + if ( SEQ_GT(tracker->r_win_base, tsd.get_seg_seq() ) ) { - uint32_t offset = tracker->r_win_base - tsd.get_seq(); + int32_t offset = tracker->r_win_base - tsd.get_seg_seq(); - if ( offset < tsd.get_pkt()->dsize ) + if ( offset < tsd.get_seg_len() ) { - tsd.set_seq(tsd.get_seq() + offset); - tsd.get_pkt()->data += offset; - tsd.get_pkt()->dsize -= (uint16_t)offset; - + tsd.slide_segment_in_rcv_window(offset); rc = insert_segment_in_seglist(tsd); - - tsd.get_pkt()->dsize += (uint16_t)offset; - tsd.get_pkt()->data -= offset; - tsd.set_seq(tsd.get_seq() - offset); + tsd.slide_segment_in_rcv_window(-offset); } } else diff --git a/src/stream/tcp/tcp_reassembler.h b/src/stream/tcp/tcp_reassembler.h index 878e3a9c0..0363c19ef 100644 --- a/src/stream/tcp/tcp_reassembler.h +++ b/src/stream/tcp/tcp_reassembler.h @@ -110,15 +110,8 @@ public: void trace_segments(void); protected: - bool server_side; - TcpTracker* tracker; - uint8_t ignore_dir; - uint8_t packet_dir; - uint32_t flush_count; /* number of flushed queued segments */ - uint32_t xtradata_mask; /* extra data available to log */ - TcpReassembler(TcpSession* session, TcpTracker* tracker, StreamPolicy os_policy, bool server) : - server_side(server), tracker(tracker), flush_count(0), xtradata_mask(0) + server_side(server), tracker(tracker) { this->session = session; set_tcp_reassembly_policy(os_policy); @@ -172,6 +165,13 @@ protected: void fallback(void); uint32_t flush_pdu_ackd(uint32_t* flags); int purge_to_seq(uint32_t flush_seq); + + bool server_side; + TcpTracker* tracker; + uint8_t ignore_dir; + uint8_t packet_dir; + uint32_t flush_count = 0; /* number of flushed queued segments */ + uint32_t xtradata_mask = 0; /* extra data available to log */ }; #endif diff --git a/src/stream/tcp/tcp_segment_node.cc b/src/stream/tcp/tcp_segment_node.cc index 2dfca120b..6285d1af8 100644 --- a/src/stream/tcp/tcp_segment_node.cc +++ b/src/stream/tcp/tcp_segment_node.cc @@ -40,6 +40,15 @@ TcpSegmentNode::~TcpSegmentNode() //------------------------------------------------------------------------- // TcpSegment stuff //------------------------------------------------------------------------- +TcpSegmentNode* TcpSegmentNode::init(TcpSegmentDescriptor& tsd) +{ + return init(tsd.get_pkt()->pkth->ts, tsd.get_pkt()->data, tsd.get_seg_len() ); +} + +TcpSegmentNode* TcpSegmentNode::init(TcpSegmentNode& tsn) +{ + return init(tsn.tv, tsn.payload, tsn.payload_size); +} TcpSegmentNode* TcpSegmentNode::init(const struct timeval& tv, const uint8_t* data, unsigned dsize) { diff --git a/src/stream/tcp/tcp_segment_node.h b/src/stream/tcp/tcp_segment_node.h index 90b05c024..635d1bfe5 100644 --- a/src/stream/tcp/tcp_segment_node.h +++ b/src/stream/tcp/tcp_segment_node.h @@ -26,6 +26,8 @@ #include "protocols/packet.h" #include "flow/memcap.h" +#include "stream/libtcp/tcp_segment_descriptor.h" + extern THREAD_LOCAL Memcap* tcp_memcap; //----------------------------------------------------------------- @@ -40,6 +42,8 @@ public: TcpSegmentNode(); virtual ~TcpSegmentNode(); + static TcpSegmentNode* init(TcpSegmentDescriptor& tsd); + static TcpSegmentNode* init(TcpSegmentNode& tsn); static TcpSegmentNode* init(const struct timeval&, const uint8_t*, unsigned); static bool needs_pruning(void) { diff --git a/src/stream/tcp/tcp_session.cc b/src/stream/tcp/tcp_session.cc index cb6788d9c..cd2a020d9 100644 --- a/src/stream/tcp/tcp_session.cc +++ b/src/stream/tcp/tcp_session.cc @@ -111,6 +111,134 @@ const char* const flush_policy_names[] = }; #endif +DEBUG_WRAP(const char* t = NULL; const char* l = NULL; ) + +TcpSession::TcpSession(Flow* flow) : + Session(flow), client(new TcpTracker(true)), server(new TcpTracker(false)) +{ + // initialize stream tracker state machine... + new TcpStateNone(tsm, *this); + new TcpStateClosed(tsm, *this); + new TcpStateListen(tsm, *this); + new TcpStateSynSent(tsm, *this); + new TcpStateSynRecv(tsm, *this); + new TcpStateEstablished(tsm, *this); + new TcpStateFinWait1(tsm, *this); + new TcpStateFinWait2(tsm, *this); + new TcpStateClosing(tsm, *this); + new TcpStateCloseWait(tsm, *this); + new TcpStateLastAck(tsm, *this); + new TcpStateTimeWait(tsm, *this); +} + +TcpSession::~TcpSession(void) +{ + if (tcp_init) + { + clear_session(1); + + delete client; + delete server; + } +} + +void TcpSession::reset(void) +{ + if (tcp_init) + clear_session(2); +} + +bool TcpSession::setup(Packet*) +{ + // FIXIT-L this it should not be necessary to reset here + reset(); + + client->init_tracker( ); + server->init_tracker( ); + lws_init = tcp_init = false; + no_3whs = false; + pkt_action_mask = ACTION_NOTHING; + ecn = 0; + ingress_index = egress_index = 0; + ingress_group = egress_group = 0; + daq_flags = address_space_id = 0; + + tcpStats.sessions++; + return true; +} + +void TcpSession::cleanup(void) +{ + // this flushes data and then calls TcpSessionClear() + cleanup_session(1); +} + +void TcpSession::clear(void) +{ + if ( tcp_init ) + // this does NOT flush data + clear_session(1); +} + +void TcpSession::restart(Packet* p) +{ + // sanity check since this is called externally + assert(p->ptrs.tcph); + + TcpTracker* talker, * listener; + + if (p->packet_flags & PKT_FROM_SERVER) + { + talker = server; + listener = client; + } + else + { + talker = client; + listener = server; + } + + // FIXIT-H on data / on ack must be based on flush policy + if (p->dsize > 0) + listener->reassembler->flush_on_data_policy(p); + + if (p->ptrs.tcph->is_ack()) + talker->reassembler->flush_on_ack_policy(p); +} + +void TcpSession::print(void) +{ + char buf[64]; + + LogMessage("TcpSession:\n"); + sfip_ntop(&flow->server_ip, buf, sizeof(buf)); + LogMessage(" server IP: %s\n", buf); + sfip_ntop(&flow->client_ip, buf, sizeof(buf)); + LogMessage(" client IP: %s\n", buf); + LogMessage(" server port: %d\n", flow->server_port); + LogMessage(" client port: %d\n", flow->client_port); + LogMessage(" flags: 0x%X\n", flow->get_session_flags()); + LogMessage("Client Tracker:\n"); + client->print(); + LogMessage("Server Tracker:\n"); + server->print(); +} + +void TcpSession::set_splitter(bool to_server, StreamSplitter* ss) +{ + TcpTracker* trk = ( to_server ) ? server : client; + + trk->set_splitter(ss); +} + +StreamSplitter* TcpSession::get_splitter(bool to_server) +{ + if ( to_server ) + return server->splitter; + else + return client->splitter; +} + void TcpSession::update_perf_base_state(char newState) { uint32_t session_flags = flow->get_session_flags(); @@ -281,153 +409,6 @@ static inline int is_mac_address_valid(TcpTracker* talker, TcpTracker* listener, return event_code; } -#ifdef S5_PEDANTIC -// From RFC 793: -// -// Segment Receive Test -// Length Window -// ------- ------- ------------------------------------------- -// -// 0 0 SEG.SEQ = RCV.NXT -// -// 0 >0 RCV.NXT =< SEG.SEQ < RCV.NXT+RCV.WND -// -// >0 0 not acceptable -// -// >0 >0 RCV.NXT =< SEG.SEQ < RCV.NXT+RCV.WND -// or RCV.NXT =< SEG.SEQ+SEG.LEN-1 < RCV.NXT+RCV.WND -// -static inline int ValidSeq(const Packet* p, Flow* flow, TcpTracker* st, TcpSegmentDescriptor& tsd) -{ - uint32_t win = st->normalizer->get_stream_window(flow, st, tsd); - - if ( !p->dsize ) - { - if ( !win ) - { - return ( tsd.get_seq() == st->r_win_base ); - } - return SEQ_LEQ(st->r_win_base, tsd.get_seq()) && - SEQ_LT(tsd.get_seq(), st->r_win_base+win); - } - if ( !win ) - return 0; - - if ( SEQ_LEQ(st->r_win_base, tsd.get_seq()) && - SEQ_LT(tsd.get_seq(), st->r_win_base+win) ) - return 1; - - return SEQ_LEQ(st->r_win_base, tsd.get_end_seq()) && - SEQ_LT(tsd.get_end_seq(), st->r_win_base+win); -} - -#else -static inline int ValidSeq(TcpTracker* st, TcpSegmentDescriptor& tsd) -{ - int right_ok; - uint32_t left_seq; - - DebugFormat(DEBUG_STREAM_STATE, - "Checking end_seq (%X) > r_win_base (%X) && seq (%X) < r_nxt_ack(%X)\n", - tsd.get_end_seq(), st->r_win_base, tsd.get_seq(), st->r_nxt_ack + - st->normalizer->get_stream_window(tsd)); - - if ( SEQ_LT(st->r_nxt_ack, st->r_win_base) ) - left_seq = st->r_nxt_ack; - else - left_seq = st->r_win_base; - - if ( tsd.get_pkt()->dsize ) - right_ok = SEQ_GT(tsd.get_end_seq(), left_seq); - else - right_ok = SEQ_GEQ(tsd.get_end_seq(), left_seq); - - if ( right_ok ) - { - uint32_t win = st->normalizer->get_stream_window(tsd); - - if ( SEQ_LEQ(tsd.get_seq(), st->r_win_base + win) ) - { - DebugMessage(DEBUG_STREAM_STATE, "seq is within window!\n"); - return 1; - } - else - { - DebugMessage(DEBUG_STREAM_STATE, "seq is past the end of the window!\n"); - } - } - else - { - DebugMessage(DEBUG_STREAM_STATE, "end_seq is before win_base\n"); - } - return 0; -} - -#endif - -static inline void UpdateSsn(TcpTracker* rcv, TcpTracker* snd, TcpSegmentDescriptor& tsd) -{ -#if 0 - // FIXIT-L these checks are a hack to avoid off by one normalization - // due to FIN ... if last segment filled a hole, r_nxt_ack is not at - // end of data, FIN is ignored so sequence isn't bumped, and this - // forces seq-- on ACK of FIN. :( - if ( rcv->get_tcp_state() == TcpStreamTracker::TCP_ESTABLISHED && - rcv->s_mgr.state_queue == TcpStreamTracker::TCP_STATE_NONE && - Normalize_IsEnabled(NORM_TCP_IPS) ) - { - // walk the seglist until a gap or tsd.ack whichever is first - // if a gap exists prior to ack, move ack back to start of gap - TcpSegment* seg = snd->seglist; - - // FIXIT-L must check ack oob with empty seglist - // FIXIT-L add lower gap bound to tracker for efficiency? - while ( seg ) - { - uint32_t seq = seg->seq + seg->size; - if ( SEQ_LEQ(tsd.get_ack(), seq) ) - break; - - seg = seg->next; - - if ( !seg || seg->seq > seq ) - { - // normalize here - tsd.set_ack(seq); - tcph->th_ack = htonl(seq); - p->packet_flags |= PKT_MODIFIED; - break; - } - } - } -#endif - // ** if we don't see a segment, we can't track seq at ** below - // so we update the seq by the ack if it is beyond next expected - if ( SEQ_GT(tsd.get_ack(), rcv->get_snd_una() ) ) - rcv->set_snd_una(tsd.get_ack() ); - - // ** this is how we track the last seq number sent - // as is l_unackd is the "last left" seq recvd - snd->set_snd_una(tsd.get_seq() ); - - if ( SEQ_GT(tsd.get_end_seq(), snd->get_snd_nxt() ) ) - snd->set_snd_nxt(tsd.get_end_seq() ); - - if ( !SEQ_EQ(snd->r_win_base, tsd.get_ack() ) ) - { - snd->small_seg_count = 0; - } -#ifdef S5_PEDANTIC - if ( SEQ_GT(tsd.get_ack(), snd->r_win_base) && - SEQ_LEQ(tsd.get_ack(), snd->r_nxt_ack) ) -#else - if ( SEQ_GT(tsd.get_ack(), snd->r_win_base) ) -#endif - snd->r_win_base = tsd.get_ack(); - - snd->set_snd_wnd(tsd.get_win() ); -} - void TcpSession::clear_session(int freeApplicationData) { // update stats @@ -475,7 +456,7 @@ void TcpSession::clear_session(int freeApplicationData) flow->clear(freeApplicationData); // generate event for rate filtering - tel->EventInternal(INTERNAL_EVENT_SESSION_DEL); + tel.EventInternal(INTERNAL_EVENT_SESSION_DEL); DebugFormat(DEBUG_STREAM_STATE, "After cleaning, %lu bytes in use\n", tcp_memcap->used()); @@ -494,55 +475,6 @@ void TcpSession::cleanup_session(int freeApplicationData, Packet* p) clear_session(freeApplicationData); } -#if 0 -static inline int IsWellFormed(Packet* p, TcpTracker* ts) -{ - return ( !ts->mss || (p->dsize <= ts->mss) ); -} - -#endif - -void TcpSession::FinishServerInit(TcpSegmentDescriptor& tsd) -{ - const tcp::TCPHdr* tcph = tsd.get_tcph(); - - server->set_snd_wnd(tsd.get_win() ); - server->set_snd_una(tsd.get_seq() + 1); - server->set_snd_nxt(server->get_snd_una() ); - server->set_iss(tsd.get_seq() ); - - client->r_nxt_ack = tsd.get_end_seq(); - - if ( tcph->is_fin() ) - server->set_snd_nxt(server->get_snd_nxt() - 1); - - if ( !( flow->session_state & STREAM_STATE_MIDSTREAM ) ) - { - server->set_tcp_state(TcpStreamTracker::TCP_SYN_RECV); - client->reassembler->set_seglist_base_seq(server->get_snd_una() ); - client->r_win_base = tsd.get_end_seq(); - } - else - { - client->reassembler->set_seglist_base_seq(tsd.get_seq() ); - client->r_win_base = tsd.get_seq(); - } - - server->flags |= server->normalizer->get_tcp_timestamp(tsd, false); - server->ts_last = tsd.get_ts(); - if (server->ts_last == 0) - server->flags |= TF_TSTAMP_ZERO; - else - server->set_ts_last_packet(tsd.get_pkt()->pkth->ts.tv_sec); - - server->flags |= tsd.init_mss(&server->mss); - server->flags |= tsd.init_wscale(&server->wscale); - -#ifdef DEBUG_STREAM_EX - PrintTcpSession(ssn); -#endif -} - void TcpSession::EndOfFileHandle(Packet* p) { flow->call_handlers(p, true); @@ -559,7 +491,7 @@ bool TcpSession::flow_exceeds_config_thresholds(TcpTracker* rcv, TcpSegmentDescr if ( ( config->flags & STREAM_CONFIG_NO_ASYNC_REASSEMBLY ) && !flow->two_way_traffic() ) return true; - if ( config->max_consec_small_segs && ( tsd.get_pkt()->dsize < + if ( config->max_consec_small_segs && ( tsd.get_seg_len() < config->max_consec_small_seg_size ) ) { rcv->small_seg_count++; @@ -568,7 +500,7 @@ bool TcpSession::flow_exceeds_config_thresholds(TcpTracker* rcv, TcpSegmentDescr { /* Above threshold, log it... in this TCP policy, * action controlled by preprocessor rule. */ - tel->EventMaxSmallSegsExceeded(); + tel.EventMaxSmallSegsExceeded(); /* Reset counter, so we're not too noisy */ rcv->small_seg_count = 0; } @@ -594,7 +526,7 @@ bool TcpSession::flow_exceeds_config_thresholds(TcpTracker* rcv, TcpSegmentDescr void TcpSession::process_tcp_stream(TcpTracker* rcv, TcpSegmentDescriptor& tsd) { DebugFormat(DEBUG_STREAM_STATE, "In ProcessTcpStream(), %d bytes to queue\n", - tsd.get_pkt()->dsize); + tsd.get_seg_len()); if (tsd.get_pkt()->packet_flags & PKT_IGNORE) return; @@ -611,7 +543,7 @@ void TcpSession::process_tcp_stream(TcpTracker* rcv, TcpSegmentDescriptor& tsd) if ( ( config->overlap_limit ) && ( rcv->reassembler->get_overlap_count() > config->overlap_limit ) ) { - tel->EventExcessiveOverlap(); + tel.EventExcessiveOverlap(); rcv->reassembler->set_overlap_count(0); } } @@ -621,7 +553,7 @@ int TcpSession::process_tcp_data(TcpTracker* listener, TcpSegmentDescriptor& tsd Profile profile(s5TcpDataPerfStats); const tcp::TCPHdr* tcph = tsd.get_tcph(); - uint32_t seq = tsd.get_seq(); + uint32_t seq = tsd.get_seg_seq(); if ( tcph->is_syn() ) { @@ -653,7 +585,7 @@ int TcpSession::process_tcp_data(TcpTracker* listener, TcpSegmentDescriptor& tsd if ( listener->s_mgr.state_queue == TcpStreamTracker::TCP_STATE_NONE ) listener->r_nxt_ack = tsd.get_end_seq(); - if (tsd.get_pkt()->dsize != 0) + if (tsd.get_seg_len() != 0) { if (!( flow->get_session_flags() & SSNFLAG_STREAM_ORDER_BAD)) tsd.get_pkt()->packet_flags |= PKT_STREAM_ORDER_OK; @@ -673,7 +605,7 @@ int TcpSession::process_tcp_data(TcpTracker* listener, TcpSegmentDescriptor& tsd // some cases. DebugFormat(DEBUG_STREAM_STATE, "out of order segment (tsd.seq: 0x%X l->r_nxt_ack: 0x%X!\n", - tsd.get_seq(), listener->r_nxt_ack); + tsd.get_seg_seq(), listener->r_nxt_ack); if (listener->s_mgr.state_queue == TcpStreamTracker::TCP_STATE_NONE) { @@ -698,11 +630,11 @@ int TcpSession::process_tcp_data(TcpTracker* listener, TcpSegmentDescriptor& tsd } } - if (tsd.get_pkt()->dsize != 0) + if (tsd.get_seg_len() != 0) { if (!( flow->get_session_flags() & SSNFLAG_STREAM_ORDER_BAD)) { - if (!SEQ_LEQ((tsd.get_seq() + tsd.get_pkt()->dsize), listener->r_nxt_ack)) + if (!SEQ_LEQ((tsd.get_seg_seq() + tsd.get_seg_len()), listener->r_nxt_ack)) flow->set_session_flags(SSNFLAG_STREAM_ORDER_BAD); } process_tcp_stream(listener, tsd); @@ -778,11 +710,10 @@ void TcpSession::init_new_tcp_session(TcpSegmentDescriptor& tsd) flow->set_expire(tsd.get_pkt(), config->session_timeout); update_perf_base_state(TcpStreamTracker::TCP_SYN_SENT); - tel->EventInternal(INTERNAL_EVENT_SESSION_ADD); + tel.EventInternal(INTERNAL_EVENT_SESSION_ADD); - //assert( !tcp_init ); tcp_init = true; - new_ssn = true; + lws_init = true; // FIXIT - this state is bogus... move to tracker init... tcpStats.created++; @@ -804,25 +735,37 @@ void TcpSession::NewTcpSessionOnSynAck(TcpSegmentDescriptor& tsd) tcpStats.sessions_on_syn_ack++; } -void TcpSession::update_session_state(const tcp::TCPHdr* tcph, TcpSegmentDescriptor& tsd) +void TcpSession::update_timestamp_tracking(TcpSegmentDescriptor& tsd) +{ + talker->set_tf_flags(listener->normalizer->get_timestamp_flags()); + if (listener->normalizer->handling_timestamps() + && SEQ_EQ(listener->r_nxt_ack, tsd.get_seg_seq())) + { + talker->set_ts_last_packet(tsd.get_pkt()->pkth->ts.tv_sec); + talker->set_ts_last(tsd.get_ts()); + } +} + +void TcpSession::update_session_on_syn_ack(void) { /* If session is already marked as established */ - if (!(flow->session_state & STREAM_STATE_ESTABLISHED) - && (!require_3whs || config->midstream_allowed(tsd.get_pkt()))) + if ( !( flow->session_state & STREAM_STATE_ESTABLISHED ) ) { - /* If not requiring 3-way Handshake... - TCP session created on TH_SYN above, or maybe on SYN-ACK, or anything else - Need to update Lightweight session state */ - if (tcph->is_syn_ack()) + /* SYN-ACK from server */ + if (flow->session_state != STREAM_STATE_NONE) { - /* SYN-ACK from server */ - if (flow->session_state != STREAM_STATE_NONE) - { - flow->session_state |= STREAM_STATE_SYN_ACK; - update_perf_base_state(TcpStreamTracker::TCP_ESTABLISHED); - } + flow->session_state |= STREAM_STATE_SYN_ACK; + update_perf_base_state(TcpStreamTracker::TCP_ESTABLISHED); } - else if (tcph->is_ack() && (flow->session_state & STREAM_STATE_SYN_ACK)) + } +} + +void TcpSession::update_session_on_ack(void) +{ + /* If session is already marked as established */ + if ( !( flow->session_state & STREAM_STATE_ESTABLISHED ) ) + { + if ( flow->session_state & STREAM_STATE_SYN_ACK ) { flow->session_state |= STREAM_STATE_ACK | STREAM_STATE_ESTABLISHED; update_perf_base_state(TcpStreamTracker::TCP_ESTABLISHED); @@ -830,30 +773,20 @@ void TcpSession::update_session_state(const tcp::TCPHdr* tcph, TcpSegmentDescrip } } -void TcpSession::update_session_on_server_packet(const tcp::TCPHdr* tcph, - TcpSegmentDescriptor& tsd) +void TcpSession::update_session_on_server_packet(TcpSegmentDescriptor& tsd) { DebugMessage(DEBUG_STREAM_STATE, "Stream: Updating on packet from server\n"); flow->set_session_flags(SSNFLAG_SEEN_SERVER); + talker = server; + listener = client; - if (tcp_init) - { - talker = server; - listener = client; - } - - if ( talker and (talker->get_tcp_state() == TcpStreamTracker::TCP_LISTEN) - and tcph->is_syn_only() ) - { - tel->set_tcp_event(EVENT_4WHS); - } /* If we picked this guy up midstream, finish the initialization */ - if ((flow->session_state & STREAM_STATE_MIDSTREAM) && !(flow->session_state & - STREAM_STATE_ESTABLISHED)) + if ( !( flow->session_state & STREAM_STATE_ESTABLISHED ) + && ( flow->session_state & STREAM_STATE_MIDSTREAM ) ) { - FinishServerInit(tsd); - if (tcph->are_flags_set(TH_ECE) && (flow->get_session_flags() & SSNFLAG_ECN_CLIENT_QUERY)) + if (tsd.get_tcph()->are_flags_set(TH_ECE) + && (flow->get_session_flags() & SSNFLAG_ECN_CLIENT_QUERY)) flow->set_session_flags(SSNFLAG_ECN_SERVER_REPLY); if (flow->get_session_flags() & SSNFLAG_SEEN_CLIENT) @@ -875,14 +808,11 @@ void TcpSession::update_session_on_client_packet(TcpSegmentDescriptor& tsd) /* if we got here we had to see the SYN already... */ flow->set_session_flags(SSNFLAG_SEEN_CLIENT); - if (tcp_init) - { - talker = client; - listener = server; - } + talker = client; + listener = server; - if ((flow->session_state & STREAM_STATE_MIDSTREAM) - && !(flow->session_state & STREAM_STATE_ESTABLISHED)) + if ( !( flow->session_state & STREAM_STATE_ESTABLISHED ) + && ( flow->session_state & STREAM_STATE_MIDSTREAM ) ) { /* Midstream and seen server. */ if (flow->get_session_flags() & SSNFLAG_SEEN_SERVER) @@ -896,10 +826,12 @@ void TcpSession::update_session_on_client_packet(TcpSegmentDescriptor& tsd) flow->set_ttl(tsd.get_pkt(), true); } -bool TcpSession::handle_syn_on_reset_session(const tcp::TCPHdr* tcph, TcpSegmentDescriptor& tsd) +bool TcpSession::handle_syn_on_reset_session(TcpSegmentDescriptor& tsd) { - if ( !tcp_init || ( listener->get_tcp_state() == TcpStreamTracker::TCP_CLOSED ) - || ( talker->get_tcp_state() == TcpStreamTracker::TCP_CLOSED ) ) + const tcp::TCPHdr* tcph = tsd.get_tcph(); + if ( tcph->is_syn() && + ( ( listener->get_tcp_state() == TcpStreamTracker::TCP_CLOSED ) + || ( talker->get_tcp_state() == TcpStreamTracker::TCP_CLOSED ) ) ) { /* Listener previously issued a reset Talker is re-SYN-ing */ // FIXIT-L this leads to bogus 129:20 @@ -933,7 +865,7 @@ bool TcpSession::handle_syn_on_reset_session(const tcp::TCPHdr* tcph, TcpSegment tcpStats.resyns++; listener = server; talker = client; - listener->normalizer->ecn_tracker( (tcp::TCPHdr*)tcph, require_3whs); + listener->normalizer->ecn_tracker( (tcp::TCPHdr*)tcph, config->require_3whs() ); flow->update_session_flags(SSNFLAG_SEEN_CLIENT); } else if (tcph->is_syn_ack()) @@ -949,7 +881,7 @@ bool TcpSession::handle_syn_on_reset_session(const tcp::TCPHdr* tcph, TcpSegment listener = client; talker = server; - listener->normalizer->ecn_tracker( (tcp::TCPHdr*)tcph, require_3whs); + listener->normalizer->ecn_tracker( (tcp::TCPHdr*)tcph, config->require_3whs() ); flow->update_session_flags(SSNFLAG_SEEN_SERVER); } } @@ -965,497 +897,186 @@ void TcpSession::update_ignored_session(TcpSegmentDescriptor& tsd) // s5_ignored_session() may be disabling detection too soon if we really want to flush if (stream.ignored_session(flow, tsd.get_pkt())) { - if (talker && (talker->flags & TF_FORCE_FLUSH)) + if ( talker && ( talker->get_tf_flags() & TF_FORCE_FLUSH ) ) { - flush_talker(tsd.get_pkt()); - talker->flags &= ~TF_FORCE_FLUSH; + flush_talker(tsd.get_pkt() ); + talker->clear_tf_flags(TF_FORCE_FLUSH); } - if (listener && (listener->flags & TF_FORCE_FLUSH)) + + if ( listener && ( listener->get_tf_flags() & TF_FORCE_FLUSH ) ) { - flush_listener(tsd.get_pkt()); - listener->flags &= ~TF_FORCE_FLUSH; + flush_listener(tsd.get_pkt() ); + listener->clear_tf_flags(TF_FORCE_FLUSH); } + tsd.get_pkt()->packet_flags |= PKT_IGNORE; pkt_action_mask |= ACTION_DISABLE_INSPECTION; } } -void TcpSession::handle_data_on_syn(const tcp::TCPHdr* tcph, TcpSegmentDescriptor& tsd) +void TcpSession::handle_data_on_syn(TcpSegmentDescriptor& tsd) { - /* Handle data on SYN */ - if ((tsd.get_pkt()->dsize) && tcph->is_syn()) + /* MacOS accepts data on SYN, so don't alert if policy is MACOS */ + if (talker->normalizer->get_os_policy() != StreamPolicy::OS_MACOS) { - /* MacOS accepts data on SYN, so don't alert if policy is MACOS */ - if (talker->normalizer->get_os_policy() != StreamPolicy::OS_MACOS) - { - // remove data on SYN - listener->normalizer->trim_syn_payload(tsd); + // remove data on SYN + listener->normalizer->trim_syn_payload(tsd); - if (Normalize_GetMode(NORM_TCP_TRIM_SYN) == NORM_MODE_OFF) - { - DebugMessage(DEBUG_STREAM_STATE, "Got data on SYN packet, not processing it\n"); - //EventDataOnSyn(config); - tel->set_tcp_event(EVENT_DATA_ON_SYN); - pkt_action_mask |= ACTION_BAD_PKT; - } + if (Normalize_GetMode(NORM_TCP_TRIM_SYN) == NORM_MODE_OFF) + { + DebugMessage(DEBUG_STREAM_STATE, "Got data on SYN packet, not processing it\n"); + tel.set_tcp_event(EVENT_DATA_ON_SYN); + pkt_action_mask |= ACTION_BAD_PKT; } } } -void TcpSession::process_tcp_packet(TcpSegmentDescriptor& tsd) +void TcpSession::update_session_on_rst(TcpSegmentDescriptor& tsd, bool flush) { - Profile profile(s5TcpStatePerfStats); + if ( flush ) + { + flush_listener(tsd.get_pkt()); + flush_talker(tsd.get_pkt()); + set_splitter(true, nullptr); + set_splitter(false, nullptr); + flow->free_application_data(); + } - int got_ts = 0; - talker = nullptr; - listener = nullptr; - const tcp::TCPHdr* tcph = tsd.get_tcph(); + talker->update_on_rst_sent( ); +} - DEBUG_WRAP(const char* t = NULL; const char* l = NULL; ); +void TcpSession::update_paws_timestamps(TcpSegmentDescriptor& tsd) +{ + // update PAWS timestamps + DebugFormat(DEBUG_STREAM_STATE, "PAWS update tsd.seq %lu > listener->r_win_base %lu\n", + tsd.get_seg_seq(), listener->r_win_base); - /* If session is already marked as established */ - update_session_state(tcph, tsd); - - if ( tcph->is_syn() ) - server->normalizer->ecn_tracker( (tcp::TCPHdr*)tcph, config->require_3whs() ); - - if ( tsd.get_pkt()->packet_flags & PKT_FROM_SERVER ) + if ( listener->normalizer->handling_timestamps() + && SEQ_EQ(listener->r_win_base, tsd.get_seg_seq() ) ) { - update_session_on_server_packet(tcph, tsd); - DEBUG_WRAP(t = "Server"; l = "Client"); + if ( ( (int32_t)(tsd.get_ts() - talker->get_ts_last() ) >= 0 ) + || + ( ( uint32_t )tsd.get_pkt()->pkth->ts.tv_sec >= + talker->get_ts_last_packet() + PAWS_24DAYS ) ) + { + DebugMessage(DEBUG_STREAM_STATE, "updating timestamps...\n"); + talker->set_ts_last(tsd.get_ts()); + talker->set_ts_last_packet(tsd.get_pkt()->pkth->ts.tv_sec); + } } else { - update_session_on_client_packet(tsd); - DEBUG_WRAP(t = "Server"; l = "Client"); + DebugMessage(DEBUG_STREAM_STATE, "not updating timestamps...\n"); } +} - //check for SYN on reset session - if ( ( flow->get_session_flags() & SSNFLAG_RESET ) && tcph->is_syn() ) - if ( !handle_syn_on_reset_session(tcph, tsd) ) - return; - - update_ignored_session(tsd); - - handle_data_on_syn(tcph, tsd); - - if (!tcp_init) - return; - - DebugFormat(DEBUG_STREAM_STATE, " %s [talker] state: %s\n", t, - tcp_state_names[talker->get_tcp_state()]); - DebugFormat(DEBUG_STREAM_STATE, " %s state: %s(%d)\n", l, - tcp_state_names[listener->get_tcp_state()], listener->get_tcp_state()); - - // may find better placement to eliminate redundant flag checks - if ( tcph->is_syn() ) - talker->s_mgr.sub_state |= SUB_SYN_SENT; - if ( tcph->is_ack() ) - talker->s_mgr.sub_state |= SUB_ACK_SENT; - - // process SYN ACK on unestablished sessions - if ( ( TcpStreamTracker::TCP_SYN_SENT == listener->get_tcp_state() ) && - ( TcpStreamTracker::TCP_LISTEN == talker->get_tcp_state() ) ) +void TcpSession::check_for_session_hijack(TcpSegmentDescriptor& tsd) +{ + #ifdef DAQ_PKT_FLAG_PRE_ROUTING + if (!(tsd.get_pkt()->pkth->flags & DAQ_PKT_FLAG_PRE_ROUTING)) +#endif { - if ( tcph->is_ack() ) - { - // make sure we've got a valid segment - if (!listener->is_ack_valid(tsd.get_ack() ) ) - { - DebugFormat(DEBUG_STREAM_STATE, - "Pkt Ack is Out of Bounds (%X, %X, %X) = (snd_una, snd_nxt, cur)\n", - listener->get_snd_una(), listener->get_snd_nxt(), tsd.get_ack()); - inc_tcp_discards(); - listener->normalizer->trim_win_payload(tsd); - pkt_action_mask |= ACTION_BAD_PKT; - return; - } - } - - talker->flags |= talker->normalizer->get_tcp_timestamp(tsd, false); - if (tsd.get_ts() == 0) - talker->flags |= TF_TSTAMP_ZERO; - - // catch resets sent by server - if ( tcph->is_rst() ) - { - DebugMessage(DEBUG_STREAM_STATE, "got RST\n"); - - listener->normalizer->trim_rst_payload(tsd); - - // Reset is valid when in SYN_SENT if the ack field ACKs the SYN. - if ( listener->is_rst_valid_in_syn_sent(tsd) ) - { - DebugMessage(DEBUG_STREAM_STATE, "got RST, closing talker\n"); - /* Reset is valid */ - /* Mark session as reset... Leave it around so that any - * additional data sent from one side or the other isn't - * processed (and is dropped in inline mode). - */ - flow->set_session_flags(SSNFLAG_RESET); - talker->set_tcp_state(TcpStreamTracker::TCP_CLOSED); - update_perf_base_state(TcpStreamTracker::TCP_CLOSING); - /* Leave listener open, data may be in transit */ - pkt_action_mask |= ACTION_RST; - return; - } - /* Reset not valid. */ - DebugMessage(DEBUG_STREAM_STATE, "bad sequence number, bailing\n"); - inc_tcp_discards(); - tel->set_tcp_event(EVENT_BAD_RST); - listener->normalizer->packet_dropper(tsd, NORM_TCP_BLOCK); - return; - } - - // finish up server init - if ( tcph->is_syn() ) - { - FinishServerInit(tsd); - if (talker->flags & TF_TSTAMP) - { - talker->set_ts_last_packet(tsd.get_pkt()->pkth->ts.tv_sec); - talker->ts_last = tsd.get_ts(); - } + tel.set_tcp_event(is_mac_address_valid(talker, listener, tsd.get_pkt())); + } +} - DebugMessage(DEBUG_STREAM_STATE, "Finish server init got called!\n"); - } - else - { - DebugMessage(DEBUG_STREAM_STATE, "Finish server init didn't get called!\n"); - } +void TcpSession::handle_fin_recv_in_fw1(TcpSegmentDescriptor& tsd) +{ + Flow* flow = tsd.get_flow(); - if ( tcph->are_flags_set(TH_ECE) && - ( flow->get_session_flags() & SSNFLAG_ECN_CLIENT_QUERY ) ) - flow->set_session_flags(SSNFLAG_ECN_SERVER_REPLY); + DebugMessage(DEBUG_STREAM_STATE, "seq ok, setting state!\n"); - // explicitly set the state - listener->set_tcp_state(TcpStreamTracker::TCP_SYN_SENT); - DebugMessage(DEBUG_STREAM_STATE, "Accepted SYN ACK\n"); - return; + if ( talker->s_mgr.state_queue == TcpStreamTracker::TCP_STATE_NONE ) + { + talker->set_tcp_state(TcpStreamTracker::TCP_LAST_ACK); + EndOfFileHandle(tsd.get_pkt() ); } - /* - * scale the window. Only if BOTH client and server specified - * wscale option as part of 3-way handshake. - * This is per RFC 1323. - */ - if ((talker->flags & TF_WSCALE) && (listener->flags & TF_WSCALE)) - tsd.set_win(tsd.get_win() << talker->wscale); - - /* Check for session hijacking -- compare mac address to the ones - * that were recorded at session startup. */ -#ifdef DAQ_PKT_FLAG_PRE_ROUTING - if (!(tsd.get_pkt()->pkth->flags & DAQ_PKT_FLAG_PRE_ROUTING)) -#endif + if ( flow->get_session_flags() & SSNFLAG_MIDSTREAM ) { - tel->set_tcp_event(is_mac_address_valid (talker, listener, tsd.get_pkt() ) ); + // FIXIT-L this should be handled below in fin section + // but midstream sessions fail the seq test + listener->s_mgr.state_queue = TcpStreamTracker::TCP_TIME_WAIT; + listener->s_mgr.transition_seq = tsd.get_end_seq(); + listener->s_mgr.expected_flags = TH_ACK; } +} - pkt_action_mask |= listener->normalizer->handle_paws(tsd, &got_ts); - - // check RST validity +#if 0 +// process SYN ACK on unestablished sessions +if ( ( listener->get_tcp_state() != TcpStreamTracker::TCP_ESTABLISHED && + TcpStreamTracker::TCP_SYN_ACK_RECV_EVENT == listener->get_tcp_event() ) && + ( TcpStreamTracker::TCP_SYN_ACK_SENT_EVENT == talker->get_tcp_event() ) ) +{ + // catch resets sent by server if ( tcph->is_rst() ) { + DebugMessage(DEBUG_STREAM_STATE, "got RST\n"); + listener->normalizer->trim_rst_payload(tsd); - if (listener->normalizer->validate_rst(tsd)) + // Reset is valid when in SYN_SENT if the ack field ACKs the SYN. + if ( listener->is_rst_valid_in_syn_sent(tsd) ) { - DebugMessage(DEBUG_STREAM_STATE, "Got RST, bailing\n"); - - if (listener->get_tcp_state() == TcpStreamTracker::TCP_FIN_WAIT1 - || listener->get_tcp_state() == TcpStreamTracker::TCP_FIN_WAIT2 - || listener->get_tcp_state() == TcpStreamTracker::TCP_CLOSE_WAIT - || listener->get_tcp_state() == TcpStreamTracker::TCP_CLOSING) - { - flush_talker(tsd.get_pkt()); - flush_listener(tsd.get_pkt()); - set_splitter(true, nullptr); - set_splitter(false, nullptr); - flow->free_application_data(); - } - + DebugMessage(DEBUG_STREAM_STATE, "got RST, closing talker\n"); + /* Reset is valid */ + /* Mark session as reset... Leave it around so that any + * additional data sent from one side or the other isn't + * processed (and is dropped in inline mode). + */ flow->set_session_flags(SSNFLAG_RESET); talker->set_tcp_state(TcpStreamTracker::TCP_CLOSED); - talker->s_mgr.sub_state |= SUB_RST_SENT; update_perf_base_state(TcpStreamTracker::TCP_CLOSING); - - if ( listener->normalizer->is_tcp_ips_enabled() ) - listener->set_tcp_state(TcpStreamTracker::TCP_CLOSED); - - /* else for ids: leave listener open, data may be in transit */ + /* Leave listener open, data may be in transit */ pkt_action_mask |= ACTION_RST; return; } /* Reset not valid. */ DebugMessage(DEBUG_STREAM_STATE, "bad sequence number, bailing\n"); inc_tcp_discards(); - tel->set_tcp_event(EVENT_BAD_RST); + tel.set_tcp_event(EVENT_BAD_RST); listener->normalizer->packet_dropper(tsd, NORM_TCP_BLOCK); return; } - else - { - /* check for valid seqeuence/retrans */ - if (config->policy != StreamPolicy::OS_PROXY - and (listener->get_tcp_state() >= TcpStreamTracker::TCP_ESTABLISHED) - and !ValidSeq(listener, tsd)) - { - DebugMessage(DEBUG_STREAM_STATE, "bad sequence number, bailing\n"); - inc_tcp_discards(); - listener->normalizer->trim_win_payload(tsd); - return; - } - } - - if ( pkt_action_mask & ACTION_BAD_PKT ) - { - DebugMessage(DEBUG_STREAM_STATE, "bad timestamp, bailing\n"); - inc_tcp_discards(); - return; - } - - // update PAWS timestamps - DebugFormat(DEBUG_STREAM_STATE, "PAWS update tsd.seq %lu > listener->r_win_base %lu\n", - tsd.get_seq(), listener->r_win_base); - if (got_ts && SEQ_EQ(listener->r_win_base, tsd.get_seq())) - { - if ( ( int32_t )( tsd.get_ts() - talker->ts_last ) >= 0 || - (uint32_t)tsd.get_pkt()->pkth->ts.tv_sec >= talker->get_ts_last_packet() + PAWS_24DAYS) - { - DebugMessage(DEBUG_STREAM_STATE, "updating timestamps...\n"); - talker->ts_last = tsd.get_ts(); - talker->set_ts_last_packet(tsd.get_pkt()->pkth->ts.tv_sec); - } - } - else - { - DebugMessage(DEBUG_STREAM_STATE, "not updating timestamps...\n"); - } - - // check for repeat SYNs - if ( !new_ssn && tcph->is_syn_only() ) - { - int action; - if (!SEQ_EQ(tsd.get_seq(), talker->get_iss()) && - listener->normalizer->packet_dropper(tsd, NORM_TCP_BLOCK)) - action = ACTION_BAD_PKT; - else if (talker->get_tcp_state() >= TcpStreamTracker::TCP_ESTABLISHED) - action = listener->normalizer->handle_repeated_syn(tsd); - else - action = ACTION_NOTHING; - - if (action != ACTION_NOTHING) - { - /* got a bad SYN on the session, alert! */ - tel->set_tcp_event(EVENT_SYN_ON_EST); - pkt_action_mask |= action; - return; - } - } - - // Check that the window is within the limits - if (config->policy != StreamPolicy::OS_PROXY) - { - if (config->max_window && (tsd.get_win() > config->max_window)) - { - DebugMessage(DEBUG_STREAM_STATE, - "Got window that was beyond the allowed policy value, bailing\n"); - /* got a window too large, alert! */ - tel->set_tcp_event(EVENT_WINDOW_TOO_LARGE); - inc_tcp_discards(); - listener->normalizer->packet_dropper(tsd, NORM_TCP_BLOCK); - pkt_action_mask |= ACTION_BAD_PKT; - return; - } - else if ((tsd.get_pkt()->packet_flags & PKT_FROM_CLIENT) && (tsd.get_win() <= SLAM_MAX) - && (tsd.get_ack() == listener->get_iss() + 1) - && !( tcph->is_fin() | tcph->is_rst() ) - && !(flow->get_session_flags() & SSNFLAG_MIDSTREAM)) - { - DebugMessage(DEBUG_STREAM_STATE, "Window slammed shut!\n"); - /* got a window slam alert! */ - tel->set_tcp_event(EVENT_WINDOW_SLAM); - inc_tcp_discards(); - - if (listener->normalizer->packet_dropper(tsd, NORM_TCP_BLOCK)) - { - pkt_action_mask |= ACTION_BAD_PKT; - return; - } - } - } - - if (talker->s_mgr.state_queue != TcpStreamTracker::TCP_STATE_NONE) - { - DebugFormat(DEBUG_STREAM_STATE, - "Found queued state transition on ack 0x%X, current 0x%X!\n", - talker->s_mgr.transition_seq, tsd.get_ack()); - - if (tsd.get_ack() == talker->s_mgr.transition_seq) - { - DebugMessage(DEBUG_STREAM_STATE, "accepting transition!\n"); - talker->set_tcp_state(talker->s_mgr.state_queue); - talker->s_mgr.state_queue = TcpStreamTracker::TCP_STATE_NONE; - } - } - - // process ACK flags - if ( tcph->is_ack() ) - { - DebugMessage(DEBUG_STREAM_STATE, "Got an ACK...\n"); - DebugFormat(DEBUG_STREAM_STATE, " %s [listener] state: %s\n", l, - tcp_state_names[listener->get_tcp_state()]); - - switch ( listener->get_tcp_state() ) - { - case TcpStreamTracker::TCP_SYN_SENT: - break; - - case TcpStreamTracker::TCP_SYN_RECV: - DebugMessage(DEBUG_STREAM_STATE, "listener state is SYN_SENT...\n"); - if ( listener->is_ack_valid(tsd.get_ack() ) ) - { - UpdateSsn(listener, talker, tsd); - flow->set_session_flags(SSNFLAG_ESTABLISHED); - flow->session_state |= STREAM_STATE_ESTABLISHED; - listener->set_tcp_state(TcpStreamTracker::TCP_ESTABLISHED); - talker->set_tcp_state(TcpStreamTracker::TCP_ESTABLISHED); - update_perf_base_state(TcpStreamTracker::TCP_ESTABLISHED); - /* Indicate this packet completes 3-way handshake */ - tsd.get_pkt()->packet_flags |= PKT_STREAM_TWH; - } - - talker->flags |= got_ts; - if (got_ts && SEQ_EQ(listener->r_nxt_ack, tsd.get_seq())) - { - talker->set_ts_last_packet(tsd.get_pkt()->pkth->ts.tv_sec); - talker->ts_last = tsd.get_ts(); - } - - break; - - case TcpStreamTracker::TCP_ESTABLISHED: - case TcpStreamTracker::TCP_CLOSE_WAIT: - UpdateSsn(listener, talker, tsd); - break; - - case TcpStreamTracker::TCP_FIN_WAIT1: - UpdateSsn(listener, talker, tsd); - - DebugFormat(DEBUG_STREAM_STATE, "tsd.ack %X >= talker->r_nxt_ack %X\n", tsd.get_ack(), - talker->r_nxt_ack); - - if ( SEQ_EQ(tsd.get_ack(), listener->get_snd_nxt() ) ) - { - if ((listener->normalizer->get_os_policy() == StreamPolicy::OS_WINDOWS) && - (tsd.get_win() == 0)) - { - tel->set_tcp_event(EVENT_WINDOW_SLAM); - inc_tcp_discards(); - - if (listener->normalizer->packet_dropper(tsd, NORM_TCP_BLOCK)) - { - pkt_action_mask |= ACTION_BAD_PKT; - return; - } - } - - listener->set_tcp_state(TcpStreamTracker::TCP_FIN_WAIT2); - - if ( tcph->is_fin() ) - { - DebugMessage(DEBUG_STREAM_STATE, "seq ok, setting state!\n"); - - if ( talker->s_mgr.state_queue == TcpStreamTracker::TCP_STATE_NONE ) - { - talker->set_tcp_state(TcpStreamTracker::TCP_LAST_ACK); - EndOfFileHandle(tsd.get_pkt() ); - } - if ( flow->get_session_flags() & SSNFLAG_MIDSTREAM ) - { - // FIXIT-L this should be handled below in fin section - // but midstream sessions fail the seq test - listener->s_mgr.state_queue = TcpStreamTracker::TCP_TIME_WAIT; - listener->s_mgr.transition_seq = tsd.get_end_seq(); - listener->s_mgr.expected_flags = TH_ACK; - } - } - else if ( listener->s_mgr.state_queue == TcpStreamTracker::TCP_CLOSING ) - { - listener->s_mgr.state_queue = TcpStreamTracker::TCP_TIME_WAIT; - listener->s_mgr.transition_seq = tsd.get_end_seq(); - listener->s_mgr.expected_flags = TH_ACK; - } - } - else - { - DebugMessage(DEBUG_STREAM_STATE, "bad ack!\n"); - } - break; - - case TcpStreamTracker::TCP_FIN_WAIT2: - UpdateSsn(listener, talker, tsd); - if ( SEQ_GT(tsd.get_ack(), listener->get_snd_nxt() ) ) - { - tel->set_tcp_event(EVENT_BAD_ACK); - listener->normalizer->packet_dropper(tsd, NORM_TCP_BLOCK); - pkt_action_mask |= ACTION_BAD_PKT; - return; - } - break; - - case TcpStreamTracker::TCP_CLOSING: - UpdateSsn(listener, talker, tsd); - if (SEQ_GEQ(tsd.get_end_seq(), listener->r_nxt_ack)) - listener->set_tcp_state(TcpStreamTracker::TCP_TIME_WAIT); - break; - - case TcpStreamTracker::TCP_LAST_ACK: - UpdateSsn(listener, talker, tsd); - - if ( SEQ_EQ(tsd.get_ack(), listener->get_snd_nxt() ) ) - listener->set_tcp_state(TcpStreamTracker::TCP_CLOSED); - break; - - default: - // FIXIT-L safe to ignore when inline? - break; - } - talker->reassembler->flush_on_ack_policy(tsd.get_pkt() ); - } + // explicitly set the state + //listener->set_tcp_state( TcpStreamTracker::TCP_SYN_SENT ); + DebugMessage(DEBUG_STREAM_STATE, "Accepted SYN ACK\n"); + return; +} +#endif +void TcpSession::handle_data_segment(TcpSegmentDescriptor& tsd) +{ // handle data in the segment - if (tsd.get_pkt()->dsize) + if (tsd.get_seg_len()) { DebugFormat(DEBUG_STREAM_STATE, " %s state: %s(%d) getting data\n", l, tcp_state_names[listener->get_tcp_state()], listener->get_tcp_state()); // FIN means only that sender is done talking, other side may continue yapping. - if ( TcpStreamTracker::TCP_FIN_WAIT2 == talker->get_tcp_state() || - TcpStreamTracker::TCP_TIME_WAIT == talker->get_tcp_state() ) + if (TcpStreamTracker::TCP_FIN_WAIT2 == talker->get_tcp_state() + || TcpStreamTracker::TCP_TIME_WAIT == talker->get_tcp_state()) { // data on a segment when we're not accepting data any more alert! - //EventDataOnClosed(talker->config); - tel->set_tcp_event(EVENT_DATA_ON_CLOSED); + tel.set_tcp_event(EVENT_DATA_ON_CLOSED); pkt_action_mask |= ACTION_BAD_PKT; listener->normalizer->packet_dropper(tsd, NORM_TCP_BLOCK); } - else if ( TcpStreamTracker::TCP_CLOSED == talker->get_tcp_state() ) + else if (TcpStreamTracker::TCP_CLOSED == talker->get_tcp_state()) { // data on a segment when we're not accepting data any more alert! if (flow->get_session_flags() & SSNFLAG_RESET) { //EventDataAfterReset(listener->config); if (talker->s_mgr.sub_state & SUB_RST_SENT) - tel->set_tcp_event(EVENT_DATA_AFTER_RESET); + tel.set_tcp_event(EVENT_DATA_AFTER_RESET); else - tel->set_tcp_event(EVENT_DATA_AFTER_RST_RCVD); + tel.set_tcp_event(EVENT_DATA_AFTER_RST_RCVD); } else { - //EventDataOnClosed(listener->config); - tel->set_tcp_event(EVENT_DATA_ON_CLOSED); + tel.set_tcp_event(EVENT_DATA_ON_CLOSED); } pkt_action_mask |= ACTION_BAD_PKT; listener->normalizer->packet_dropper(tsd, NORM_TCP_BLOCK); @@ -1466,6 +1087,7 @@ void TcpSession::process_tcp_packet(TcpSegmentDescriptor& tsd) flush_policy_names[talker->flush_policy], flush_policy_names[listener->flush_policy]); + // FIXIT - move this to normalizer base class, handle OS_PROXY in derived class if (config->policy != StreamPolicy::OS_PROXY) { // these normalizations can't be done if we missed setup. and @@ -1477,149 +1099,155 @@ void TcpSession::process_tcp_packet(TcpSegmentDescriptor& tsd) TcpTracker* st = listener; // trim to fit in window and mss as needed - st->normalizer->trim_win_payload(tsd, ( st->r_win_base + st->get_snd_wnd() - - st->r_nxt_ack) ); + st->normalizer->trim_win_payload(tsd, (st->r_win_base + st->get_snd_wnd() - + st->r_nxt_ack)); - if (st->mss) - st->normalizer->trim_mss_payload(tsd, st->mss); + if (st->get_mss()) + st->normalizer->trim_mss_payload(tsd, st->get_mss()); - st->normalizer->ecn_stripper(tsd.get_pkt() ); + st->normalizer->ecn_stripper(tsd.get_pkt()); } } + // dunno if this is RFC but fragroute testing expects it for the record, // I've seen FTP data sessions that send data packets with no tcp flags set - if ((tcph->th_flags != 0) - or (config->policy == StreamPolicy::OS_LINUX) + if ((tsd.get_tcph()->th_flags != 0)or (config->policy == StreamPolicy::OS_LINUX) or (config->policy == StreamPolicy::OS_PROXY)) { process_tcp_data(listener, tsd); } else { - tel->set_tcp_event(EVENT_DATA_WITHOUT_FLAGS); + tel.set_tcp_event(EVENT_DATA_WITHOUT_FLAGS); listener->normalizer->packet_dropper(tsd, NORM_TCP_BLOCK); } } - listener->reassembler->flush_on_data_policy(tsd.get_pkt() ); + listener->reassembler->flush_on_data_policy(tsd.get_pkt()); } +} - if ( tcph->is_fin() ) - { - DebugMessage(DEBUG_STREAM_STATE, "Got a FIN...\n"); - DebugFormat(DEBUG_STREAM_STATE, " %s state: %s(%d)\n", l, - tcp_state_names[talker->get_tcp_state()], talker->get_tcp_state()); - DebugFormat(DEBUG_STREAM_STATE, "checking ack (0x%X) vs nxt_ack (0x%X)\n", - tsd.get_end_seq(), listener->r_win_base); +bool TcpSession::handle_fin_recv(TcpSegmentDescriptor& tsd) +{ + if ( !tsd.get_tcph()->is_fin() ) + return true; - if ( SEQ_LT(tsd.get_end_seq(), listener->r_win_base) ) - { - DebugMessage(DEBUG_STREAM_STATE, "FIN inside r_win_base, bailing\n"); - goto dupfin; - } - else + DebugMessage(DEBUG_STREAM_STATE, "Got a FIN...\n"); + DebugFormat(DEBUG_STREAM_STATE, " %s state: %s(%d)\n", l, + tcp_state_names[talker->get_tcp_state()], talker->get_tcp_state()); + DebugFormat(DEBUG_STREAM_STATE, "checking ack (0x%X) vs nxt_ack (0x%X)\n", + tsd.get_end_seq(), listener->r_win_base); + + if ( SEQ_LT(tsd.get_end_seq(), listener->r_win_base) ) + { + DebugMessage(DEBUG_STREAM_STATE, "FIN inside r_win_base, bailing\n"); + return true; + } + else + { + // need substate since we don't change state immediately + if ( (talker->get_tcp_state() >= TcpStreamTracker::TCP_ESTABLISHED ) + && !( talker->s_mgr.sub_state & SUB_FIN_SENT ) ) { - // need substate since we don't change state immediately - if ( (talker->get_tcp_state() >= TcpStreamTracker::TCP_ESTABLISHED ) - && !( talker->s_mgr.sub_state & SUB_FIN_SENT ) ) - { - talker->set_snd_nxt(talker->get_snd_nxt() + 1); + talker->set_snd_nxt(talker->get_snd_nxt() + 1); - //-------------------------------------------------- - // FIXIT-L don't bump r_nxt_ack unless FIN is in seq - // because it causes bogus 129:5 cases - // but doing so causes extra gaps - //if ( SEQ_EQ(tsd.end_seq, listener->r_nxt_ack) ) - listener->r_nxt_ack++; - //-------------------------------------------------- + //-------------------------------------------------- + // FIXIT-L don't bump r_nxt_ack unless FIN is in seq + // because it causes bogus 129:5 cases + // but doing so causes extra gaps + //if ( SEQ_EQ(tsd.end_seq, listener->r_nxt_ack) ) + listener->r_nxt_ack++; + //-------------------------------------------------- - talker->s_mgr.sub_state |= SUB_FIN_SENT; + talker->s_mgr.sub_state |= SUB_FIN_SENT; - if ( ( listener->flush_policy != STREAM_FLPOLICY_ON_ACK ) - && ( listener->flush_policy != STREAM_FLPOLICY_ON_DATA ) - && listener->normalizer->is_tcp_ips_enabled() ) - { - tsd.get_pkt()->packet_flags |= PKT_PDU_TAIL; - } - } - switch (talker->get_tcp_state()) + if ( ( listener->flush_policy != STREAM_FLPOLICY_ON_ACK ) + && ( listener->flush_policy != STREAM_FLPOLICY_ON_DATA ) + && listener->normalizer->is_tcp_ips_enabled() ) { - case TcpStreamTracker::TCP_SYN_RECV: - case TcpStreamTracker::TCP_ESTABLISHED: - if ( talker->s_mgr.state_queue == TcpStreamTracker::TCP_CLOSE_WAIT ) - talker->s_mgr.state_queue = TcpStreamTracker::TCP_CLOSING; - - talker->set_tcp_state(TcpStreamTracker::TCP_FIN_WAIT1); - EndOfFileHandle(tsd.get_pkt() ); + tsd.get_pkt()->packet_flags |= PKT_PDU_TAIL; + } + } + switch (talker->get_tcp_state()) + { + case TcpStreamTracker::TCP_SYN_RECV: + case TcpStreamTracker::TCP_ESTABLISHED: + if ( talker->s_mgr.state_queue == TcpStreamTracker::TCP_CLOSE_WAIT ) + talker->s_mgr.state_queue = TcpStreamTracker::TCP_CLOSING; - if ( !tsd.get_pkt()->dsize ) - listener->reassembler->flush_on_data_policy(tsd.get_pkt() ); + talker->set_tcp_state(TcpStreamTracker::TCP_FIN_WAIT1); + EndOfFileHandle(tsd.get_pkt() ); - update_perf_base_state(TcpStreamTracker::TCP_CLOSING); - break; + if ( !tsd.get_seg_len() ) + listener->reassembler->flush_on_data_policy(tsd.get_pkt() ); - case TcpStreamTracker::TCP_CLOSE_WAIT: - talker->set_tcp_state(TcpStreamTracker::TCP_LAST_ACK); - break; + update_perf_base_state(TcpStreamTracker::TCP_CLOSING); + break; - case TcpStreamTracker::TCP_FIN_WAIT1: - if (!tsd.get_pkt()->dsize) - retransmit_handle(tsd.get_pkt() ); - break; + case TcpStreamTracker::TCP_CLOSE_WAIT: + talker->set_tcp_state(TcpStreamTracker::TCP_LAST_ACK); + break; - default: - /* all other states stay where they are */ - break; - } + case TcpStreamTracker::TCP_FIN_WAIT1: + if (!tsd.get_seg_len()) + retransmit_handle(tsd.get_pkt() ); + break; - if ((talker->get_tcp_state() == TcpStreamTracker::TCP_FIN_WAIT1) || - (talker->get_tcp_state() == TcpStreamTracker::TCP_LAST_ACK)) - { - uint32_t end_seq = (flow->get_session_flags() & SSNFLAG_MIDSTREAM) - ? tsd.get_end_seq() - 1 : tsd.get_end_seq(); + default: + /* all other states stay where they are */ + break; + } - if ((listener->s_mgr.expected_flags == TH_ACK) && SEQ_GEQ(end_seq, - listener->s_mgr.transition_seq)) - { - DebugMessage(DEBUG_STREAM_STATE, "FIN beyond previous, ignoring\n"); - tel->set_tcp_event(EVENT_BAD_FIN); - listener->normalizer->packet_dropper(tsd, NORM_TCP_BLOCK); - pkt_action_mask |= ACTION_BAD_PKT; - return; - } - } + if ((talker->get_tcp_state() == TcpStreamTracker::TCP_FIN_WAIT1) || + (talker->get_tcp_state() == TcpStreamTracker::TCP_LAST_ACK)) + { + uint32_t end_seq = (flow->get_session_flags() & SSNFLAG_MIDSTREAM) + ? tsd.get_end_seq() - 1 : tsd.get_end_seq(); - switch ( listener->get_tcp_state() ) + if ((listener->s_mgr.expected_flags == TH_ACK) && SEQ_GEQ(end_seq, + listener->s_mgr.transition_seq)) { - case TcpStreamTracker::TCP_ESTABLISHED: - listener->s_mgr.state_queue = TcpStreamTracker::TCP_CLOSE_WAIT; - listener->s_mgr.transition_seq = tsd.get_end_seq() + 1; - listener->s_mgr.expected_flags = TH_ACK; - break; - - case TcpStreamTracker::TCP_FIN_WAIT1: - listener->s_mgr.state_queue = TcpStreamTracker::TCP_CLOSING; - listener->s_mgr.transition_seq = tsd.get_end_seq() + 1; - listener->s_mgr.expected_flags = TH_ACK; - break; - - case TcpStreamTracker::TCP_FIN_WAIT2: - listener->s_mgr.state_queue = TcpStreamTracker::TCP_TIME_WAIT; - listener->s_mgr.transition_seq = tsd.get_end_seq() + 1; - listener->s_mgr.expected_flags = TH_ACK; - break; - - default: - // FIXIT - put this here quickly to make compiler happy, what should - // be done when not in one of the 3 states above? - DebugMessage(DEBUG_STREAM_STATE, "No Action In This State\n"); - break; + DebugMessage(DEBUG_STREAM_STATE, "FIN beyond previous, ignoring\n"); + tel.set_tcp_event(EVENT_BAD_FIN); + listener->normalizer->packet_dropper(tsd, NORM_TCP_BLOCK); + pkt_action_mask |= ACTION_BAD_PKT; + return false; } } + + switch ( listener->get_tcp_state() ) + { + case TcpStreamTracker::TCP_ESTABLISHED: + listener->s_mgr.state_queue = TcpStreamTracker::TCP_CLOSE_WAIT; + listener->s_mgr.transition_seq = tsd.get_end_seq() + 1; + listener->s_mgr.expected_flags = TH_ACK; + break; + + case TcpStreamTracker::TCP_FIN_WAIT1: + listener->s_mgr.state_queue = TcpStreamTracker::TCP_CLOSING; + listener->s_mgr.transition_seq = tsd.get_end_seq() + 1; + listener->s_mgr.expected_flags = TH_ACK; + break; + + case TcpStreamTracker::TCP_FIN_WAIT2: + listener->s_mgr.state_queue = TcpStreamTracker::TCP_TIME_WAIT; + listener->s_mgr.transition_seq = tsd.get_end_seq() + 1; + listener->s_mgr.expected_flags = TH_ACK; + break; + + default: + // FIXIT - put this here quickly to make compiler happy, what should + // be done when not in one of the 3 states above? + DebugMessage(DEBUG_STREAM_STATE, "No Action In This State\n"); + break; + } } -dupfin: + return true; +} +void TcpSession::finalize_tcp_packet_processing(TcpSegmentDescriptor& tsd) +{ DebugFormat(DEBUG_STREAM_STATE, " %s [talker] state: %s\n", t, tcp_state_names[talker->get_tcp_state()]); DebugFormat(DEBUG_STREAM_STATE, " %s state: %s(%d)\n", l, @@ -1627,10 +1255,10 @@ dupfin: // handle TIME_WAIT timer stuff if (!flow->two_way_traffic() && - (talker->get_tcp_state() >= TcpStreamTracker::TCP_FIN_WAIT1 || listener->get_tcp_state() >= - TcpStreamTracker::TCP_FIN_WAIT1)) + (talker->get_tcp_state() >= TcpStreamTracker::TCP_FIN_WAIT1 + || listener->get_tcp_state() >= TcpStreamTracker::TCP_FIN_WAIT1)) { - if (tcph->is_fin() && tcph->is_ack()) + if (tsd.get_tcph()->is_fin() && tsd.get_tcph()->is_ack()) { if (talker->get_tcp_state() >= TcpStreamTracker::TCP_FIN_WAIT1) talker->set_tcp_state(TcpStreamTracker::TCP_CLOSED); @@ -1638,7 +1266,7 @@ dupfin: if (listener->get_tcp_state() >= TcpStreamTracker::TCP_FIN_WAIT1) listener->set_tcp_state(TcpStreamTracker::TCP_CLOSED); - listener->flags |= TF_FORCE_FLUSH; + listener->set_tf_flags(TF_FORCE_FLUSH); } } @@ -1648,7 +1276,9 @@ dupfin: talker->get_tcp_state() == TcpStreamTracker::TCP_CLOSED) || (listener->get_tcp_state() == TcpStreamTracker::TCP_TIME_WAIT && talker->get_tcp_state() == TcpStreamTracker::TCP_TIME_WAIT) - || (!flow->two_way_traffic() && (talker->get_tcp_state() == TcpStreamTracker::TCP_CLOSED || + || (!flow->two_way_traffic() && + (talker->get_tcp_state() == TcpStreamTracker::TCP_CLOSED + || listener->get_tcp_state() == TcpStreamTracker::TCP_CLOSED))) { // The last ACK is a part of the session. Delete the session after processing is complete. @@ -1660,154 +1290,110 @@ dupfin: else if ( listener->get_tcp_state() == TcpStreamTracker::TCP_CLOSED && talker->get_tcp_state() == TcpStreamTracker::TCP_SYN_SENT ) { - if ( tcph->is_syn_only() ) + if ( tsd.get_tcph()->is_syn_only() ) flow->set_expire(tsd.get_pkt(), config->session_timeout); } } -//------------------------------------------------------------------------- -// TcpSession methods -//------------------------------------------------------------------------- - -TcpSession::TcpSession(Flow* flow) : - Session(flow), config(nullptr), client(new TcpTracker(true) ), - server(new TcpTracker(false) ), ecn(0), ingress_index(0), - ingress_group(0), egress_index(0), egress_group(0), daq_flags(0), address_space_id(0), - pkt_action_mask(ACTION_NOTHING), require_3whs(true), no_3whs(false) +void TcpSession::process_tcp_packet(TcpSegmentDescriptor& tsd) { - lws_init = tcp_init = false; - new_ssn = false; + Profile profile(s5TcpStatePerfStats); + const tcp::TCPHdr* tcph = tsd.get_tcph(); - tel = new TcpEventLogger; + check_for_session_hijack(tsd); - // initialize stream tracker state machine... - new TcpStateNone(tsm, *this); - new TcpStateClosed(tsm, *this); - new TcpStateListen(tsm, *this); - new TcpStateSynSent(tsm, *this); - new TcpStateSynRecv(tsm, *this); - new TcpStateEstablished(tsm, *this); - new TcpStateFinWait1(tsm, *this); - new TcpStateFinWait2(tsm, *this); - new TcpStateClosing(tsm, *this); - new TcpStateCloseWait(tsm, *this); - new TcpStateLastAck(tsm, *this); - new TcpStateTimeWait(tsm, *this); -} + /* check for valid seqeuence/retrans */ + if ( ( config->policy != StreamPolicy::OS_PROXY ) + && !listener->is_segment_seq_valid(tsd) ) + return; -TcpSession::~TcpSession(void) -{ - if (tcp_init) + if ( pkt_action_mask & ACTION_BAD_PKT ) { - clear_session(1); - - delete client; - delete server; + DebugMessage(DEBUG_STREAM_STATE, "bad timestamp, bailing\n"); + inc_tcp_discards(); + return; } - delete tel; -} - -void TcpSession::reset(void) -{ - if (tcp_init) - clear_session(2); -} - -bool TcpSession::setup(Packet*) -{ - // FIXIT-L this it should not be necessary to reset here - reset(); - - client->init_tracker( ); - server->init_tracker( ); - lws_init = tcp_init = false; - no_3whs = false; - pkt_action_mask = ACTION_NOTHING; - ecn = 0; - ingress_index = egress_index = 0; - ingress_group = egress_group = 0; - daq_flags = address_space_id = 0; - - SESSION_STATS_ADD(tcpStats); - return true; -} + update_paws_timestamps(tsd); -void TcpSession::cleanup(void) -{ - // this flushes data and then calls TcpSessionClear() - cleanup_session(1); -} - -void TcpSession::clear(void) -{ - if ( tcp_init ) - // this does NOT flush data - clear_session(true); -} - -void TcpSession::restart(Packet* p) -{ - // sanity check since this is called externally - assert(p->ptrs.tcph); - - TcpTracker* talker, * listener; - - if (p->packet_flags & PKT_FROM_SERVER) - { - talker = server; - listener = client; - } - else + // check for repeat SYNs + if ( tcph->is_syn_only() ) { - talker = client; - listener = server; - } + int action; + if (!SEQ_EQ(tsd.get_seg_seq(), talker->get_iss()) + && listener->normalizer->packet_dropper(tsd, NORM_TCP_BLOCK)) + action = ACTION_BAD_PKT; + else if (talker->get_tcp_state() >= TcpStreamTracker::TCP_ESTABLISHED) + action = listener->normalizer->handle_repeated_syn(tsd); + else + action = ACTION_NOTHING; - // FIXIT-H on data / on ack must be based on flush policy - if (p->dsize > 0) - listener->reassembler->flush_on_data_policy(p); + if (action != ACTION_NOTHING) + { + /* got a bad SYN on the session, alert! */ + tel.set_tcp_event(EVENT_SYN_ON_EST); + pkt_action_mask |= action; + return; + } + } - if (p->ptrs.tcph->is_ack()) - talker->reassembler->flush_on_ack_policy(p); -} + // Check that the window is within the limits + if ( config->policy != StreamPolicy::OS_PROXY ) + { + if ( config->max_window && (tsd.get_seg_wnd() > config->max_window ) ) + { + DebugMessage(DEBUG_STREAM_STATE, + "Got window that was beyond the allowed policy value, bailing\n"); + /* got a window too large, alert! */ + tel.set_tcp_event(EVENT_WINDOW_TOO_LARGE); + inc_tcp_discards(); + listener->normalizer->packet_dropper(tsd, NORM_TCP_BLOCK); + pkt_action_mask |= ACTION_BAD_PKT; + return; + } + else if ((tsd.get_pkt()->packet_flags & PKT_FROM_CLIENT) + && (tsd.get_seg_wnd() <= SLAM_MAX) + && (tsd.get_seg_ack() == listener->get_iss() + 1) + && !( tcph->is_fin() | tcph->is_rst() ) + && !(flow->get_session_flags() & SSNFLAG_MIDSTREAM)) + { + DebugMessage(DEBUG_STREAM_STATE, "Window slammed shut!\n"); + /* got a window slam alert! */ + tel.set_tcp_event(EVENT_WINDOW_SLAM); + inc_tcp_discards(); -void TcpSession::print(void) -{ - char buf[64]; + if (listener->normalizer->packet_dropper(tsd, NORM_TCP_BLOCK)) + { + pkt_action_mask |= ACTION_BAD_PKT; + return; + } + } + } - LogMessage("TcpSession:\n"); - sfip_ntop(&flow->server_ip, buf, sizeof(buf)); - LogMessage(" server IP: %s\n", buf); - sfip_ntop(&flow->client_ip, buf, sizeof(buf)); - LogMessage(" client IP: %s\n", buf); - LogMessage(" server port: %d\n", flow->server_port); - LogMessage(" client port: %d\n", flow->client_port); - LogMessage(" flags: 0x%X\n", flow->get_session_flags()); - LogMessage("Client Tracker:\n"); - client->print(); - LogMessage("Server Tracker:\n"); - server->print(); -} + if (talker->s_mgr.state_queue != TcpStreamTracker::TCP_STATE_NONE) + { + DebugFormat(DEBUG_STREAM_STATE, + "Found queued state transition on ack 0x%X, current 0x%X!\n", + talker->s_mgr.transition_seq, tsd.get_seg_ack()); -void TcpSession::set_splitter(bool to_server, StreamSplitter* ss) -{ - TcpTracker* trk = ( to_server ) ? server : client; + if (tsd.get_seg_ack() == talker->s_mgr.transition_seq) + { + DebugMessage(DEBUG_STREAM_STATE, "accepting transition!\n"); + talker->set_tcp_state(talker->s_mgr.state_queue); + talker->s_mgr.state_queue = TcpStreamTracker::TCP_STATE_NONE; + } + } - trk->set_splitter(ss); -} + // handle data in the segment + handle_data_segment(tsd); -StreamSplitter* TcpSession::get_splitter(bool to_server) -{ - if ( to_server ) - return server->splitter; - else - return client->splitter; + if ( handle_fin_recv(tsd) ) + finalize_tcp_packet_processing(tsd); } void TcpSession::flush_server(Packet* p) { - server->flags |= TF_FORCE_FLUSH; + server->set_tf_flags(TF_FORCE_FLUSH); // If rebuilt packet, don't flush now because we'll overwrite the packet being processed. if ( p->packet_flags & PKT_REBUILT_STREAM ) @@ -1820,12 +1406,12 @@ void TcpSession::flush_server(Packet* p) if ( server->reassembler->flush_stream(p, PKT_FROM_SERVER) ) server->reassembler->purge_flushed_ackd( ); - server->flags &= ~TF_FORCE_FLUSH; + server->clear_tf_flags(TF_FORCE_FLUSH); } void TcpSession::flush_client(Packet* p) { - client->flags |= TF_FORCE_FLUSH; + client->set_tf_flags(TF_FORCE_FLUSH); // If rebuilt packet, don't flush now because we'll overwrite the packet being processed. if ( p->packet_flags & PKT_REBUILT_STREAM ) @@ -1837,7 +1423,7 @@ void TcpSession::flush_client(Packet* p) if ( client->reassembler->flush_stream(p, PKT_FROM_CLIENT) ) client->reassembler->purge_flushed_ackd( ); - client->flags &= ~TF_FORCE_FLUSH; + client->clear_tf_flags(TF_FORCE_FLUSH); } void TcpSession::flush_listener(Packet* p) @@ -1864,11 +1450,11 @@ void TcpSession::flush_listener(Packet* p) if ( dir != 0 ) { - listener->flags |= TF_FORCE_FLUSH; + listener->set_tf_flags(TF_FORCE_FLUSH); if ( listener->reassembler->flush_stream(p, dir) ) listener->reassembler->purge_flushed_ackd( ); - listener->flags &= ~TF_FORCE_FLUSH; + listener->clear_tf_flags(TF_FORCE_FLUSH); } } @@ -1896,11 +1482,11 @@ void TcpSession::flush_talker(Packet* p) if (dir != 0) { - talker->flags |= TF_FORCE_FLUSH; + talker->set_tf_flags(TF_FORCE_FLUSH); if ( talker->reassembler->flush_stream(p, dir) ) talker->reassembler->purge_flushed_ackd( ); - talker->flags &= ~TF_FORCE_FLUSH; + talker->clear_tf_flags(TF_FORCE_FLUSH); } } @@ -2033,13 +1619,13 @@ bool TcpSession::is_sequenced(uint8_t dir) { if (dir & SSN_DIR_FROM_CLIENT) { - if (server->flags & (TF_MISSING_PREV_PKT | TF_MISSING_PKT)) + if ( server->get_tf_flags() & ( TF_MISSING_PREV_PKT | TF_MISSING_PKT ) ) return false; } - if (dir & SSN_DIR_FROM_SERVER) + if ( dir & SSN_DIR_FROM_SERVER ) { - if (client->flags & (TF_MISSING_PREV_PKT | TF_MISSING_PKT)) + if ( client->get_tf_flags() & ( TF_MISSING_PREV_PKT | TF_MISSING_PKT ) ) return false; } @@ -2052,22 +1638,22 @@ uint8_t TcpSession::missing_in_reassembled(uint8_t dir) { if (dir & SSN_DIR_FROM_CLIENT) { - if ((server->flags & TF_MISSING_PKT) - && (server->flags & TF_MISSING_PREV_PKT)) + if ( (server->get_tf_flags() & TF_MISSING_PKT) + && (server->get_tf_flags() & TF_MISSING_PREV_PKT)) return SSN_MISSING_BOTH; - else if (server->flags & TF_MISSING_PREV_PKT) + else if (server->get_tf_flags() & TF_MISSING_PREV_PKT) return SSN_MISSING_BEFORE; - else if (server->flags & TF_MISSING_PKT) + else if (server->get_tf_flags() & TF_MISSING_PKT) return SSN_MISSING_AFTER; } else if (dir & SSN_DIR_FROM_SERVER) { - if ((client->flags & TF_MISSING_PKT) - && (client->flags & TF_MISSING_PREV_PKT)) + if ((client->get_tf_flags() & TF_MISSING_PKT) + && (client->get_tf_flags() & TF_MISSING_PREV_PKT)) return SSN_MISSING_BOTH; - else if (client->flags & TF_MISSING_PREV_PKT) + else if (client->get_tf_flags() & TF_MISSING_PREV_PKT) return SSN_MISSING_BEFORE; - else if (client->flags & TF_MISSING_PKT) + else if (client->get_tf_flags() & TF_MISSING_PKT) return SSN_MISSING_AFTER; } @@ -2078,13 +1664,13 @@ bool TcpSession::are_packets_missing(uint8_t dir) { if (dir & SSN_DIR_FROM_CLIENT) { - if (server->flags & TF_PKT_MISSED) + if (server->get_tf_flags() & TF_PKT_MISSED) return true; } if (dir & SSN_DIR_FROM_SERVER) { - if (client->flags & TF_PKT_MISSED) + if (client->get_tf_flags() & TF_PKT_MISSED) return true; } @@ -2191,6 +1777,15 @@ void TcpSession::SwapPacketHeaderFoo(void) } } +static inline void set_window_scale(TcpTracker& talker, TcpTracker& listener, + TcpSegmentDescriptor& tsd) +{ + // scale the window. Only if BOTH client and server specified wscale option as part + // of 3-way handshake. This is per RFC 1323. + if ( ( talker.get_tf_flags() & TF_WSCALE ) && ( listener.get_tf_flags() & TF_WSCALE ) ) + tsd.scale_seg_wnd(talker.get_wscale() ); +} + /* * Main entry point for TCP */ @@ -2204,7 +1799,7 @@ int TcpSession::process(Packet* p) DebugFormat((DEBUG_STREAM|DEBUG_STREAM_STATE), "Got TCP Packet 0x%X:%d -> 0x%X:%d %s\nseq: 0x%X ack:0x%X dsize: %u\n", p->ptrs.ip_api.get_src(), p->ptrs.sp, p->ptrs.ip_api.get_dst(), p->ptrs.dp, flagbuf, - ntohl(p->ptrs.tcph->th_seq), ntohl(p->ptrs.tcph->th_ack), p->dsize); + p->ptrs.tcph->seq(), p->ptrs.tcph->ack(), p->dsize); ); // FIXIT-L can't get here without protocol being set to TCP, is this really needed?? @@ -2228,69 +1823,10 @@ int TcpSession::process(Packet* p) } TcpSegmentDescriptor tsd(flow, p, tel); - if (!lws_init) - { - // FIXIT - should only do ths once... - if (config == nullptr ) - { - config = get_tcp_cfg(flow->ssn_server); - require_3whs = config->require_3whs(); - client->set_require_3whs(require_3whs); - server->set_require_3whs(require_3whs); - } - set_os_policy( ); - - // FIXIT most of this now looks out of place or redundant - if ( require_3whs ) - { - if (p->ptrs.tcph->is_syn_only()) - { - /* SYN only */ - flow->session_state = STREAM_STATE_SYN; - } - else - { - // If we're within the "startup" window, try to handle - // this packet as midstream pickup -- allows for - // connections that already existed before snort started. - if (config->midstream_allowed(p)) - goto midstream_pickup_allowed; - - // Do nothing with this packet since we require a 3-way ;) - DEBUG_WRAP( - DebugMessage(DEBUG_STREAM_STATE, - "Stream: Requiring 3-way Handshake, but failed to retrieve session" - " object for non SYN packet.\n"); - ); - if ( !p->ptrs.tcph->is_syn_only() && !p->ptrs.tcph->is_rst() && !no_3whs ) - { - tel->EventNo3whs(); - no_3whs = true; - } -#ifdef REG_TEST - S5TraceTCP(p, flow, &tsd, 1); -#endif - return 0; - } - } - else - { -midstream_pickup_allowed: - if ( !p->ptrs.tcph->is_syn_ack() - && !p->dsize - && !(tsd.has_wscale() & TF_WSCALE) ) - { -#ifdef REG_TEST - S5TraceTCP(p, flow, &tsd, 1); -#endif - return 0; - } + if (config == nullptr ) + config = get_tcp_cfg(flow->ssn_server); - if (p->ptrs.tcph->is_syn()) - flow->session_state |= STREAM_STATE_SYN; - } - lws_init = true; - } + set_os_policy( ); // Check if the session is expired. Should be done before we do something with // the packet...Insert a packet, or handle state change SYN, FIN, RST, etc. @@ -2314,19 +1850,50 @@ midstream_pickup_allowed: } // FIXIT - need to do something here to handle check for need to swap trackers - new_ssn = false; - if ( tsm.eval(tsd, *server) ) - tsm.eval(tsd, *client); - // FIXIT - this should change once tcp sm fully implemented pkt_action_mask = ACTION_NOTHING; - tel->clear_tcp_events(); + tel.clear_tcp_events(); + + // process thru state machine...talker first + if ( p->packet_flags & PKT_FROM_CLIENT ) + { + update_session_on_client_packet(tsd); + DEBUG_WRAP(t = "Server"; l = "Client"); + } + else + { + update_session_on_server_packet(tsd); + DEBUG_WRAP(t = "Server"; l = "Client"); + } + + DebugFormat(DEBUG_STREAM_STATE, " %s [talker] state: %s\n", t, + tcp_state_names[talker->get_tcp_state()]); + DebugFormat(DEBUG_STREAM_STATE, " %s state: %s(%d)\n", l, + tcp_state_names[listener->get_tcp_state()], listener->get_tcp_state()); + + update_ignored_session(tsd); + // FIXIT - temp hack...move this to state handlers... + if ( listener->get_tcp_state() >= TcpStreamTracker::TCP_ESTABLISHED ) + pkt_action_mask |= listener->normalizer->handle_paws(tsd); + set_window_scale(*talker, *listener, tsd); + + if ( ( flow->get_session_flags() & SSNFLAG_RESET ) + && !handle_syn_on_reset_session(tsd) ) + return false; + + if ( tsm.eval(tsd, *talker) ) + tsm.eval(tsd, *listener); + else + { + S5TraceTCP(p, flow, &tsd, 1); + return 0; + } - if ( tcp_init || tsd.get_pkt()->dsize) + if ( tcp_init || tsd.get_seg_len()) process_tcp_packet(tsd); // FIXIT - end - tel->log_tcp_events(); + tel.log_tcp_events(); DebugMessage(DEBUG_STREAM_STATE, "Finished Stream TCP cleanly!\n---------------------------------------------------\n"); diff --git a/src/stream/tcp/tcp_session.h b/src/stream/tcp/tcp_session.h index d96f5cc20..9574a773f 100644 --- a/src/stream/tcp/tcp_session.h +++ b/src/stream/tcp/tcp_session.h @@ -57,9 +57,6 @@ public: void set_splitter(bool, StreamSplitter*) override; StreamSplitter* get_splitter(bool) override; - void init_new_tcp_session(TcpSegmentDescriptor& tsd); - void update_session_state(const tcp::TCPHdr* tcph, TcpSegmentDescriptor& tsd); - void update_direction(char dir, const sfip_t*, uint16_t port) override; bool add_alert(Packet*, uint32_t gid, uint32_t sid) override; @@ -104,40 +101,62 @@ public: static void set_memcap(class Memcap&); static void sinit(void); static void sterm(void); - void update_session_on_server_packet(const tcp::TCPHdr* tcph, TcpSegmentDescriptor& tsd); - void update_session_on_client_packet(TcpSegmentDescriptor& tsd); - bool handle_syn_on_reset_session(const tcp::TCPHdr* tcph, TcpSegmentDescriptor& tsd); - void update_ignored_session(TcpSegmentDescriptor& tsd); - TcpEventLogger* tel; - TcpStreamConfig* config; - TcpTracker* client; - TcpTracker* server; - uint8_t ecn; - bool lws_init; - bool tcp_init; + void init_new_tcp_session(TcpSegmentDescriptor&); + void update_timestamp_tracking(TcpSegmentDescriptor&); + void update_session_on_syn_ack(void); + void update_session_on_ack(void); + void update_session_on_server_packet(TcpSegmentDescriptor&); + void update_session_on_client_packet(TcpSegmentDescriptor&); + void update_session_on_rst(TcpSegmentDescriptor&, bool); + bool handle_syn_on_reset_session(TcpSegmentDescriptor&); + void handle_data_on_syn(TcpSegmentDescriptor&); + void handle_fin_recv_in_fw1(TcpSegmentDescriptor&); + bool handle_fin_recv(TcpSegmentDescriptor&); + void finalize_tcp_packet_processing(TcpSegmentDescriptor&); + + void update_ignored_session(TcpSegmentDescriptor&); + + void generate_no_3whs_event(void) + { + if ( !no_3whs ) + { + tel.EventNo3whs(); + no_3whs = true; + } + } - int32_t ingress_index; /* Index of the inbound interface. */ - int32_t ingress_group; /* Index of the inbound group. */ - int32_t egress_index; /* Index of the outbound interface. */ - int32_t egress_group; /* Index of the outbound group. */ - uint32_t daq_flags; /* Flags for the packet (DAQ_PKT_FLAG_*) */ - uint16_t address_space_id; + void set_pkt_action_flag(uint32_t flag) + { + pkt_action_mask |= flag; + } - uint32_t pkt_action_mask; - bool require_3whs; - bool no_3whs; + void update_paws_timestamps(TcpSegmentDescriptor&); + void check_for_session_hijack(TcpSegmentDescriptor&); + void handle_data_segment(TcpSegmentDescriptor&); - // FIXIT - deprecate this once tcp state machine is fully implemented - bool new_ssn; + TcpTracker* client; + TcpTracker* server; + TcpEventLogger tel; + TcpStreamConfig* config = nullptr; + bool lws_init = false; + bool tcp_init = false; + uint8_t ecn = 0; + int32_t ingress_index = 0; + int32_t ingress_group = 0; + int32_t egress_index = 0; + int32_t egress_group = 0; + uint32_t daq_flags = 0; + uint16_t address_space_id = 0; + uint32_t pkt_action_mask = ACTION_NOTHING; private: void EndOfFileHandle(Packet* p); - bool flow_exceeds_config_thresholds(TcpTracker* rcv, TcpSegmentDescriptor& tsd); - void process_tcp_stream(TcpTracker* rcv, TcpSegmentDescriptor& tsd); - int process_tcp_data(TcpTracker* listener, TcpSegmentDescriptor& tsd); + bool flow_exceeds_config_thresholds(TcpTracker*, TcpSegmentDescriptor&); + void process_tcp_stream(TcpTracker*, TcpSegmentDescriptor&); + int process_tcp_data(TcpTracker*, TcpSegmentDescriptor&); void process_tcp_packet(TcpSegmentDescriptor&); - void FinishServerInit(TcpSegmentDescriptor& tsd); + void FinishServerInit(TcpSegmentDescriptor&); void swap_trackers(void); void NewTcpSessionOnSyn(TcpSegmentDescriptor&); @@ -148,10 +167,11 @@ private: void clear_session(int freeApplicationData); int process_dis(Packet*); - void handle_data_on_syn(const tcp::TCPHdr* tcph, TcpSegmentDescriptor& tsd); + void update_on_3whs_complete(TcpSegmentDescriptor&); - TcpTracker* talker; - TcpTracker* listener; + bool no_3whs = false; + TcpTracker* talker = nullptr; + TcpTracker* listener = nullptr; TcpStateMachine tsm; }; diff --git a/src/stream/tcp/tcp_state_close_wait.cc b/src/stream/tcp/tcp_state_close_wait.cc index 63e70b5a6..ffdb84d3d 100644 --- a/src/stream/tcp/tcp_state_close_wait.cc +++ b/src/stream/tcp/tcp_state_close_wait.cc @@ -32,8 +32,8 @@ using namespace std; #include "catch/catch.hpp" #endif -TcpStateCloseWait::TcpStateCloseWait(TcpStateMachine& tsm, TcpSession& session) : - TcpStateHandler(TcpStreamTracker::TCP_CLOSE_WAIT, tsm), session(session) +TcpStateCloseWait::TcpStateCloseWait(TcpStateMachine& tsm, TcpSession& ssn) : + TcpStateHandler(TcpStreamTracker::TCP_CLOSE_WAIT, tsm), session(ssn) { } @@ -43,85 +43,117 @@ TcpStateCloseWait::~TcpStateCloseWait() bool TcpStateCloseWait::syn_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); - return default_state_action(tsd, trk, __func__); + trk.s_mgr.sub_state |= SUB_SYN_SENT; + + return default_state_action(tsd, trk); } bool TcpStateCloseWait::syn_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); + + trk.normalizer->ecn_tracker(tsd.get_tcph(), session.config->require_3whs() ); + + if ( tsd.get_seg_len() ) + session.handle_data_on_syn(tsd); - return default_state_action(tsd, trk, __func__); + return default_state_action(tsd, trk); } bool TcpStateCloseWait::syn_ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); - return default_state_action(tsd, trk, __func__); + trk.s_mgr.sub_state |= ( SUB_SYN_SENT | SUB_ACK_SENT ); + + return default_state_action(tsd, trk); } bool TcpStateCloseWait::syn_ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); - return default_state_action(tsd, trk, __func__); + return default_state_action(tsd, trk); } bool TcpStateCloseWait::ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); + + trk.update_tracker_ack_sent(tsd); - return default_state_action(tsd, trk, __func__); + return default_state_action(tsd, trk); } bool TcpStateCloseWait::ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); + + trk.update_tracker_ack_recv(tsd); - return default_state_action(tsd, trk, __func__); + return default_state_action(tsd, trk); } bool TcpStateCloseWait::data_seg_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); - return default_state_action(tsd, trk, __func__); + trk.update_tracker_ack_sent(tsd); + + return default_state_action(tsd, trk); } bool TcpStateCloseWait::data_seg_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); + + trk.update_tracker_ack_recv(tsd); - return default_state_action(tsd, trk, __func__); + return default_state_action(tsd, trk); } bool TcpStateCloseWait::fin_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); + + trk.update_tracker_ack_sent(tsd); - return default_state_action(tsd, trk, __func__); + return default_state_action(tsd, trk); } bool TcpStateCloseWait::fin_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); - return default_state_action(tsd, trk, __func__); + trk.update_tracker_ack_recv(tsd); + + return default_state_action(tsd, trk); } bool TcpStateCloseWait::rst_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); - return default_state_action(tsd, trk, __func__); + return default_state_action(tsd, trk); } bool TcpStateCloseWait::rst_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); - - return default_state_action(tsd, trk, __func__); + auto& trk = static_cast< TcpTracker& >( tracker ); + + if ( trk.update_on_rst_recv(tsd) ) + { + session.update_session_on_rst(tsd, true); + session.update_perf_base_state(TcpStreamTracker::TCP_CLOSING); + session.set_pkt_action_flag(ACTION_RST); + } + else + { + session.tel.set_tcp_event(EVENT_BAD_RST); + } + + return default_state_action(tsd, trk); } diff --git a/src/stream/tcp/tcp_state_closed.cc b/src/stream/tcp/tcp_state_closed.cc index f0050a169..5cc2696ed 100644 --- a/src/stream/tcp/tcp_state_closed.cc +++ b/src/stream/tcp/tcp_state_closed.cc @@ -24,6 +24,7 @@ #include "tcp_module.h" #include "tcp_tracker.h" #include "tcp_session.h" +#include "tcp_normalizer.h" #include "tcp_state_closed.h" #ifdef UNIT_TEST @@ -42,62 +43,118 @@ TcpStateClosed::~TcpStateClosed() bool TcpStateClosed::syn_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - return default_state_action(tsd, tracker, __func__); + auto& trk = static_cast< TcpTracker& >( tracker ); + Flow* flow = tsd.get_flow(); + + trk.s_mgr.sub_state |= SUB_SYN_SENT; + + return default_state_action(tsd, tracker); } bool TcpStateClosed::syn_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - return default_state_action(tsd, tracker, __func__); + auto& trk = static_cast< TcpTracker& >( tracker ); + + trk.normalizer->ecn_tracker(tsd.get_tcph(), session.config->require_3whs() ); + if ( tsd.get_seg_len() ) + session.handle_data_on_syn(tsd); + + return default_state_action(tsd, tracker); } bool TcpStateClosed::syn_ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - return default_state_action(tsd, tracker, __func__); + auto& trk = static_cast< TcpTracker& >( tracker ); + + trk.s_mgr.sub_state |= ( SUB_SYN_SENT | SUB_ACK_SENT ); + + return default_state_action(tsd, tracker); } bool TcpStateClosed::syn_ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - return default_state_action(tsd, tracker, __func__); + auto& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, tracker); } bool TcpStateClosed::ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - return default_state_action(tsd, tracker, __func__); + auto& trk = static_cast< TcpTracker& >( tracker ); + + trk.update_tracker_ack_sent(tsd); + + return default_state_action(tsd, tracker); } bool TcpStateClosed::ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - return default_state_action(tsd, tracker, __func__); + auto& trk = static_cast< TcpTracker& >( tracker ); + + trk.update_tracker_ack_recv(tsd); + + return default_state_action(tsd, tracker); } bool TcpStateClosed::data_seg_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - return default_state_action(tsd, tracker, __func__); + auto& trk = static_cast< TcpTracker& >( tracker ); + + trk.update_tracker_ack_sent(tsd); + + return default_state_action(tsd, tracker); } bool TcpStateClosed::data_seg_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - return default_state_action(tsd, tracker, __func__); + auto& trk = static_cast< TcpTracker& >( tracker ); + + trk.update_tracker_ack_recv(tsd); + + return default_state_action(tsd, tracker); } bool TcpStateClosed::fin_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - return default_state_action(tsd, tracker, __func__); + auto& trk = static_cast< TcpTracker& >( tracker ); + + trk.update_tracker_ack_sent(tsd); + + return default_state_action(tsd, tracker); } bool TcpStateClosed::fin_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - return default_state_action(tsd, tracker, __func__); + auto& trk = static_cast< TcpTracker& >( tracker ); + + trk.update_tracker_ack_recv(tsd); + + return default_state_action(tsd, tracker); } bool TcpStateClosed::rst_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - return default_state_action(tsd, tracker, __func__); + auto& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, tracker); } bool TcpStateClosed::rst_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - return default_state_action(tsd, tracker, __func__); + auto& trk = static_cast< TcpTracker& >( tracker ); + + if ( trk.update_on_rst_recv(tsd) ) + { + session.update_session_on_rst(tsd, false); + session.update_perf_base_state(TcpStreamTracker::TCP_CLOSING); + session.set_pkt_action_flag(ACTION_RST); + } + else + { + session.tel.set_tcp_event(EVENT_BAD_RST); + } + + return default_state_action(tsd, tracker); } #ifdef FOO // FIXIT - UNIT_TEST need work!! diff --git a/src/stream/tcp/tcp_state_closing.cc b/src/stream/tcp/tcp_state_closing.cc index b6db44be3..5304b7068 100644 --- a/src/stream/tcp/tcp_state_closing.cc +++ b/src/stream/tcp/tcp_state_closing.cc @@ -32,8 +32,8 @@ using namespace std; #include "catch/catch.hpp" #endif -TcpStateClosing::TcpStateClosing(TcpStateMachine& tsm, TcpSession& session) : - TcpStateHandler(TcpStreamTracker::TCP_CLOSING, tsm), session(session) +TcpStateClosing::TcpStateClosing(TcpStateMachine& tsm, TcpSession& ssn) : + TcpStateHandler(TcpStreamTracker::TCP_CLOSING, tsm), session(ssn) { } @@ -43,85 +43,122 @@ TcpStateClosing::~TcpStateClosing() bool TcpStateClosing::syn_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); - return default_state_action(tsd, trk, __func__); + trk.s_mgr.sub_state |= SUB_SYN_SENT; + + return default_state_action(tsd, trk); } bool TcpStateClosing::syn_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); + + trk.normalizer->ecn_tracker(tsd.get_tcph(), session.config->require_3whs() ); + if ( tsd.get_seg_len() ) + session.handle_data_on_syn(tsd); - return default_state_action(tsd, trk, __func__); + return default_state_action(tsd, trk); } bool TcpStateClosing::syn_ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); + + trk.s_mgr.sub_state |= ( SUB_SYN_SENT | SUB_ACK_SENT ); - return default_state_action(tsd, trk, __func__); + return default_state_action(tsd, trk); } bool TcpStateClosing::syn_ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); - return default_state_action(tsd, trk, __func__); + return default_state_action(tsd, trk); } bool TcpStateClosing::ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); - return default_state_action(tsd, trk, __func__); + trk.update_tracker_ack_sent(tsd); + + return default_state_action(tsd, trk); } bool TcpStateClosing::ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); + + trk.update_tracker_ack_recv(tsd); + if ( SEQ_GEQ(tsd.get_end_seq(), trk.r_nxt_ack) ) + trk.set_tcp_state(TcpStreamTracker::TCP_TIME_WAIT); - return default_state_action(tsd, trk, __func__); + return default_state_action(tsd, trk); } bool TcpStateClosing::data_seg_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); - return default_state_action(tsd, trk, __func__); + trk.update_tracker_ack_sent(tsd); + + return default_state_action(tsd, trk); } bool TcpStateClosing::data_seg_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); + + trk.update_tracker_ack_recv(tsd); + if ( SEQ_GEQ(tsd.get_end_seq(), trk.r_nxt_ack) ) + trk.set_tcp_state(TcpStreamTracker::TCP_TIME_WAIT); - return default_state_action(tsd, trk, __func__); + return default_state_action(tsd, trk); } bool TcpStateClosing::fin_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); + + trk.update_tracker_ack_sent(tsd); - return default_state_action(tsd, trk, __func__); + return default_state_action(tsd, trk); } bool TcpStateClosing::fin_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); - return default_state_action(tsd, trk, __func__); + trk.update_tracker_ack_recv(tsd); + if ( SEQ_GEQ(tsd.get_end_seq(), trk.r_nxt_ack) ) + trk.set_tcp_state(TcpStreamTracker::TCP_TIME_WAIT); + + return default_state_action(tsd, trk); } bool TcpStateClosing::rst_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); - return default_state_action(tsd, trk, __func__); + return default_state_action(tsd, trk); } bool TcpStateClosing::rst_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); - - return default_state_action(tsd, trk, __func__); + auto& trk = static_cast< TcpTracker& >( tracker ); + + if ( trk.update_on_rst_recv(tsd) ) + { + session.update_session_on_rst(tsd, true); + session.update_perf_base_state(TcpStreamTracker::TCP_CLOSING); + session.set_pkt_action_flag(ACTION_RST); + } + else + { + session.tel.set_tcp_event(EVENT_BAD_RST); + } + + return default_state_action(tsd, trk); } diff --git a/src/stream/tcp/tcp_state_established.cc b/src/stream/tcp/tcp_state_established.cc index 9f8de6396..06ff3004d 100644 --- a/src/stream/tcp/tcp_state_established.cc +++ b/src/stream/tcp/tcp_state_established.cc @@ -25,8 +25,8 @@ #include "tcp_normalizer.h" #include "tcp_state_established.h" -TcpStateEstablished::TcpStateEstablished(TcpStateMachine& tsm, TcpSession& session) : - TcpStateHandler(TcpStreamTracker::TCP_ESTABLISHED, tsm), session(session) +TcpStateEstablished::TcpStateEstablished(TcpStateMachine& tsm, TcpSession& ssn) : + TcpStateHandler(TcpStreamTracker::TCP_ESTABLISHED, tsm), session(ssn) { } @@ -36,85 +36,119 @@ TcpStateEstablished::~TcpStateEstablished() bool TcpStateEstablished::syn_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); - return default_state_action(tsd, trk, __func__); + trk.s_mgr.sub_state |= SUB_SYN_SENT; + + return default_state_action(tsd, trk); } bool TcpStateEstablished::syn_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); - return default_state_action(tsd, trk, __func__); + trk.normalizer->ecn_tracker(tsd.get_tcph(), session.config->require_3whs() ); + return default_state_action(tsd, trk); } bool TcpStateEstablished::syn_ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); + + if ( session.config->midstream_allowed(tsd.get_pkt()) ) + { + session.update_session_on_syn_ack( ); + } + + if ( trk.is_server_tracker() ) + trk.normalizer->ecn_tracker(tsd.get_tcph(), session.config->require_3whs() ); - return default_state_action(tsd, trk, __func__); + return default_state_action(tsd, trk); } bool TcpStateEstablished::syn_ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); - return default_state_action(tsd, trk, __func__); + return default_state_action(tsd, trk); } bool TcpStateEstablished::ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); - return default_state_action(tsd, trk, __func__); + trk.update_tracker_ack_sent(tsd); + + return default_state_action(tsd, trk); } bool TcpStateEstablished::ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); + + trk.update_tracker_ack_recv(tsd); - return default_state_action(tsd, trk, __func__); + return default_state_action(tsd, trk); } bool TcpStateEstablished::data_seg_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); - return default_state_action(tsd, trk, __func__); + trk.update_tracker_ack_sent(tsd); + + return default_state_action(tsd, trk); } bool TcpStateEstablished::data_seg_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); + + trk.update_tracker_ack_recv(tsd); - return default_state_action(tsd, trk, __func__); + return default_state_action(tsd, trk); } bool TcpStateEstablished::fin_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); + + trk.update_tracker_ack_sent(tsd); - return default_state_action(tsd, trk, __func__); + return default_state_action(tsd, trk); } bool TcpStateEstablished::fin_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); - return default_state_action(tsd, trk, __func__); + trk.update_tracker_ack_recv(tsd); + + return default_state_action(tsd, trk); } bool TcpStateEstablished::rst_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); - return default_state_action(tsd, trk, __func__); + return default_state_action(tsd, trk); } bool TcpStateEstablished::rst_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); - - return default_state_action(tsd, trk, __func__); + auto& trk = static_cast< TcpTracker& >( tracker ); + + if ( trk.update_on_rst_recv(tsd) ) + { + session.update_session_on_rst(tsd, false); + session.update_perf_base_state(TcpStreamTracker::TCP_CLOSING); + session.set_pkt_action_flag(ACTION_RST); + } + else + { + session.tel.set_tcp_event(EVENT_BAD_RST); + } + + return default_state_action(tsd, trk); } diff --git a/src/stream/tcp/tcp_state_fin_wait1.cc b/src/stream/tcp/tcp_state_fin_wait1.cc index a55421734..6b51eaf3f 100644 --- a/src/stream/tcp/tcp_state_fin_wait1.cc +++ b/src/stream/tcp/tcp_state_fin_wait1.cc @@ -43,85 +43,154 @@ TcpStateFinWait1::~TcpStateFinWait1() bool TcpStateFinWait1::syn_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); - return default_state_action(tsd, trk, __func__); + trk.s_mgr.sub_state |= SUB_SYN_SENT; + + return default_state_action(tsd, trk); } bool TcpStateFinWait1::syn_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); + + trk.normalizer->ecn_tracker(tsd.get_tcph(), session.config->require_3whs() ); + if ( tsd.get_seg_len() ) + session.handle_data_on_syn(tsd); - return default_state_action(tsd, trk, __func__); + return default_state_action(tsd, trk); } bool TcpStateFinWait1::syn_ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); + + trk.s_mgr.sub_state |= ( SUB_SYN_SENT | SUB_ACK_SENT ); - return default_state_action(tsd, trk, __func__); + return default_state_action(tsd, trk); } bool TcpStateFinWait1::syn_ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); - return default_state_action(tsd, trk, __func__); + return default_state_action(tsd, trk); } bool TcpStateFinWait1::ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); - return default_state_action(tsd, trk, __func__); + trk.update_tracker_ack_sent(tsd); + + return default_state_action(tsd, trk); } bool TcpStateFinWait1::ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); + + trk.update_tracker_ack_recv(tsd); + check_for_window_slam(tsd, trk); - return default_state_action(tsd, trk, __func__); + return default_state_action(tsd, trk); } bool TcpStateFinWait1::data_seg_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); + + trk.update_tracker_ack_sent(tsd); - return default_state_action(tsd, trk, __func__); + return default_state_action(tsd, trk); } bool TcpStateFinWait1::data_seg_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); - return default_state_action(tsd, trk, __func__); + trk.update_tracker_ack_recv(tsd); + check_for_window_slam(tsd, trk); + + return default_state_action(tsd, trk); } bool TcpStateFinWait1::fin_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); + + trk.update_tracker_ack_sent(tsd); - return default_state_action(tsd, trk, __func__); + return default_state_action(tsd, trk); } bool TcpStateFinWait1::fin_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); + + trk.update_tracker_ack_recv(tsd); - return default_state_action(tsd, trk, __func__); + if ( check_for_window_slam(tsd, trk) ) + session.handle_fin_recv_in_fw1(tsd); + + return default_state_action(tsd, trk); } bool TcpStateFinWait1::rst_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); - return default_state_action(tsd, trk, __func__); + return default_state_action(tsd, trk); } bool TcpStateFinWait1::rst_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); + + if ( trk.update_on_rst_recv(tsd) ) + { + session.update_session_on_rst(tsd, true); + session.update_perf_base_state(TcpStreamTracker::TCP_CLOSING); + session.set_pkt_action_flag(ACTION_RST); + } + else + { + session.tel.set_tcp_event(EVENT_BAD_RST); + } + + return default_state_action(tsd, trk); +} - return default_state_action(tsd, trk, __func__); +bool TcpStateFinWait1::check_for_window_slam(TcpSegmentDescriptor& tsd, TcpTracker& trk) +{ + DebugFormat(DEBUG_STREAM_STATE, "tsd.ack %X >= listener->snd_nxt %X\n", + tsd.get_seg_ack(), trk.get_snd_nxt()); + + if ( SEQ_EQ(tsd.get_seg_ack(), trk.get_snd_nxt() ) ) + { + if ( (trk.normalizer->get_os_policy() == StreamPolicy::OS_WINDOWS) + && (tsd.get_seg_wnd() == 0)) + { + session.tel.set_tcp_event(EVENT_WINDOW_SLAM); + inc_tcp_discards(); + + if (trk.normalizer->packet_dropper(tsd, NORM_TCP_BLOCK)) + { + session.set_pkt_action_flag(ACTION_BAD_PKT); + return false; + } + } + + trk.set_tcp_state(TcpStreamTracker::TCP_FIN_WAIT2); + + if ( trk.s_mgr.state_queue == TcpStreamTracker::TCP_CLOSING ) + { + trk.s_mgr.state_queue = TcpStreamTracker::TCP_TIME_WAIT; + trk.s_mgr.transition_seq = tsd.get_end_seq(); + trk.s_mgr.expected_flags = TH_ACK; + } + } + + return true; } diff --git a/src/stream/tcp/tcp_state_fin_wait1.h b/src/stream/tcp/tcp_state_fin_wait1.h index c55af9e55..e362231a9 100644 --- a/src/stream/tcp/tcp_state_fin_wait1.h +++ b/src/stream/tcp/tcp_state_fin_wait1.h @@ -46,6 +46,8 @@ public: bool rst_recv(TcpSegmentDescriptor&, TcpStreamTracker&) override; private: + bool check_for_window_slam(TcpSegmentDescriptor& tsd, TcpTracker& trk); + TcpSession& session; }; diff --git a/src/stream/tcp/tcp_state_fin_wait2.cc b/src/stream/tcp/tcp_state_fin_wait2.cc index e39b11db7..4fd6e0f0f 100644 --- a/src/stream/tcp/tcp_state_fin_wait2.cc +++ b/src/stream/tcp/tcp_state_fin_wait2.cc @@ -32,8 +32,8 @@ using namespace std; #include "catch/catch.hpp" #endif -TcpStateFinWait2::TcpStateFinWait2(TcpStateMachine& tsm, TcpSession& session) : - TcpStateHandler(TcpStreamTracker::TCP_FIN_WAIT2, tsm), session(session) +TcpStateFinWait2::TcpStateFinWait2(TcpStateMachine& tsm, TcpSession& ssn) : + TcpStateHandler(TcpStreamTracker::TCP_FIN_WAIT2, tsm), session(ssn) { } @@ -43,85 +43,117 @@ TcpStateFinWait2::~TcpStateFinWait2() bool TcpStateFinWait2::syn_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); - return default_state_action(tsd, trk, __func__); + trk.s_mgr.sub_state |= SUB_SYN_SENT; + + return default_state_action(tsd, trk); } bool TcpStateFinWait2::syn_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); + + trk.normalizer->ecn_tracker(tsd.get_tcph(), session.config->require_3whs() ); + if ( tsd.get_seg_len() ) + session.handle_data_on_syn(tsd); - return default_state_action(tsd, trk, __func__); + return default_state_action(tsd, trk); } bool TcpStateFinWait2::syn_ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); - return default_state_action(tsd, trk, __func__); + trk.s_mgr.sub_state |= ( SUB_SYN_SENT | SUB_ACK_SENT ); + + return default_state_action(tsd, trk); } bool TcpStateFinWait2::syn_ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); - return default_state_action(tsd, trk, __func__); + return default_state_action(tsd, trk); } bool TcpStateFinWait2::ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); + + trk.update_tracker_ack_sent(tsd); - return default_state_action(tsd, trk, __func__); + return default_state_action(tsd, trk); } bool TcpStateFinWait2::ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); - - return default_state_action(tsd, trk, __func__); + auto& trk = static_cast< TcpTracker& >( tracker ); + + if ( SEQ_GT(tsd.get_seg_ack(), trk.get_snd_nxt() ) ) + { + trk.normalizer->packet_dropper(tsd, NORM_TCP_BLOCK); + session.tel.set_tcp_event(EVENT_BAD_ACK); + session.set_pkt_action_flag(ACTION_BAD_PKT); + } + else + trk.update_tracker_ack_recv(tsd); + + return default_state_action(tsd, trk); } bool TcpStateFinWait2::data_seg_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); + + trk.update_tracker_ack_sent(tsd); - return default_state_action(tsd, trk, __func__); + return default_state_action(tsd, trk); } bool TcpStateFinWait2::data_seg_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); - return default_state_action(tsd, trk, __func__); + return default_state_action(tsd, trk); } bool TcpStateFinWait2::fin_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); - return default_state_action(tsd, trk, __func__); + return default_state_action(tsd, trk); } bool TcpStateFinWait2::fin_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); - return default_state_action(tsd, trk, __func__); + return default_state_action(tsd, trk); } bool TcpStateFinWait2::rst_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); - return default_state_action(tsd, trk, __func__); + return default_state_action(tsd, trk); } bool TcpStateFinWait2::rst_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); - - return default_state_action(tsd, trk, __func__); + auto& trk = static_cast< TcpTracker& >( tracker ); + + if ( trk.update_on_rst_recv(tsd) ) + { + session.update_session_on_rst(tsd, true); + session.update_perf_base_state(TcpStreamTracker::TCP_CLOSING); + session.set_pkt_action_flag(ACTION_RST); + } + else + { + session.tel.set_tcp_event(EVENT_BAD_RST); + } + + return default_state_action(tsd, trk); } diff --git a/src/stream/tcp/tcp_state_last_ack.cc b/src/stream/tcp/tcp_state_last_ack.cc index 57ab5ac63..6d2f796a7 100644 --- a/src/stream/tcp/tcp_state_last_ack.cc +++ b/src/stream/tcp/tcp_state_last_ack.cc @@ -32,8 +32,8 @@ using namespace std; #include "catch/catch.hpp" #endif -TcpStateLastAck::TcpStateLastAck(TcpStateMachine& tsm, TcpSession& session) : - TcpStateHandler(TcpStreamTracker::TCP_LAST_ACK, tsm), session(session) +TcpStateLastAck::TcpStateLastAck(TcpStateMachine& tsm, TcpSession& ssn) : + TcpStateHandler(TcpStreamTracker::TCP_LAST_ACK, tsm), session(ssn) { } @@ -43,85 +43,122 @@ TcpStateLastAck::~TcpStateLastAck() bool TcpStateLastAck::syn_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); - return default_state_action(tsd, trk, __func__); + trk.s_mgr.sub_state |= SUB_SYN_SENT; + + return default_state_action(tsd, trk); } bool TcpStateLastAck::syn_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); + + trk.normalizer->ecn_tracker(tsd.get_tcph(), session.config->require_3whs() ); + if ( tsd.get_seg_len() ) + session.handle_data_on_syn(tsd); - return default_state_action(tsd, trk, __func__); + return default_state_action(tsd, trk); } bool TcpStateLastAck::syn_ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); + + trk.s_mgr.sub_state |= ( SUB_SYN_SENT | SUB_ACK_SENT ); - return default_state_action(tsd, trk, __func__); + return default_state_action(tsd, trk); } bool TcpStateLastAck::syn_ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); - return default_state_action(tsd, trk, __func__); + return default_state_action(tsd, trk); } bool TcpStateLastAck::ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); - return default_state_action(tsd, trk, __func__); + trk.update_tracker_ack_sent(tsd); + + return default_state_action(tsd, trk); } bool TcpStateLastAck::ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); + + trk.update_tracker_ack_recv(tsd); + if ( SEQ_EQ(tsd.get_seg_ack(), trk.get_snd_nxt() ) ) + trk.set_tcp_state(TcpStreamTracker::TCP_CLOSED); - return default_state_action(tsd, trk, __func__); + return default_state_action(tsd, trk); } bool TcpStateLastAck::data_seg_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); - return default_state_action(tsd, trk, __func__); + trk.update_tracker_ack_sent(tsd); + + return default_state_action(tsd, trk); } bool TcpStateLastAck::data_seg_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); + + trk.update_tracker_ack_recv(tsd); + if ( SEQ_EQ(tsd.get_seg_ack(), trk.get_snd_nxt() ) ) + trk.set_tcp_state(TcpStreamTracker::TCP_CLOSED); - return default_state_action(tsd, trk, __func__); + return default_state_action(tsd, trk); } bool TcpStateLastAck::fin_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); + + trk.update_tracker_ack_sent(tsd); - return default_state_action(tsd, trk, __func__); + return default_state_action(tsd, trk); } bool TcpStateLastAck::fin_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); - return default_state_action(tsd, trk, __func__); + trk.update_tracker_ack_recv(tsd); + if ( SEQ_EQ(tsd.get_seg_ack(), trk.get_snd_nxt() ) ) + trk.set_tcp_state(TcpStreamTracker::TCP_CLOSED); + + return default_state_action(tsd, trk); } bool TcpStateLastAck::rst_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); - return default_state_action(tsd, trk, __func__); + return default_state_action(tsd, trk); } bool TcpStateLastAck::rst_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); - - return default_state_action(tsd, trk, __func__); + auto& trk = static_cast< TcpTracker& >( tracker ); + + if ( trk.update_on_rst_recv(tsd) ) + { + session.update_session_on_rst(tsd, false); + session.update_perf_base_state(TcpStreamTracker::TCP_CLOSING); + session.set_pkt_action_flag(ACTION_RST); + } + else + { + session.tel.set_tcp_event(EVENT_BAD_RST); + } + + return default_state_action(tsd, trk); } diff --git a/src/stream/tcp/tcp_state_listen.cc b/src/stream/tcp/tcp_state_listen.cc index 630741d34..a70a1e94e 100644 --- a/src/stream/tcp/tcp_state_listen.cc +++ b/src/stream/tcp/tcp_state_listen.cc @@ -36,85 +36,228 @@ TcpStateListen::~TcpStateListen() bool TcpStateListen::syn_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); - return default_state_action(tsd, trk, __func__); + if ( session.config->require_3whs() || tsd.has_wscale() || ( tsd.get_seg_len() > 0 ) ) + { + // FIXIT - do we need this check? only server goes into Listen state... + if ( tsd.get_pkt()->packet_flags & PKT_FROM_SERVER ) + session.tel.set_tcp_event(EVENT_4WHS); + } + + trk.s_mgr.sub_state |= SUB_SYN_SENT; + + return default_state_action(tsd, trk); } bool TcpStateListen::syn_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); + + if ( true || session.config->require_3whs() || tsd.has_wscale() || ( tsd.get_seg_len() > 0 ) ) + { + trk.init_on_syn_recv(tsd); + trk.normalizer->ecn_tracker(tsd.get_tcph(), session.config->require_3whs() ); + if ( tsd.get_seg_len() ) + session.handle_data_on_syn(tsd); + } - return default_state_action(tsd, trk, __func__); + return default_state_action(tsd, trk); } bool TcpStateListen::syn_ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + Flow* flow = tsd.get_flow(); + auto& trk = static_cast< TcpTracker& >( tracker ); - return default_state_action(tsd, trk, __func__); + flow->session_state |= ( STREAM_STATE_SYN | STREAM_STATE_SYN_ACK ); + + if ( session.config->midstream_allowed(tsd.get_pkt() ) ) + { + trk.init_on_synack_sent(tsd); + trk.normalizer->ecn_tracker(tsd.get_tcph(), session.config->require_3whs() ); + session.init_new_tcp_session(tsd); + } + else if ( session.config->require_3whs() ) + { + session.generate_no_3whs_event(); + return false; + } + + return default_state_action(tsd, trk); } bool TcpStateListen::syn_ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); + + if ( !session.config->require_3whs() || session.config->midstream_allowed(tsd.get_pkt() ) ) + { + trk.init_on_synack_recv(tsd); + } + else if ( session.config->require_3whs() ) + { + session.generate_no_3whs_event(); + return false; + } - return default_state_action(tsd, trk, __func__); + return default_state_action(tsd, trk); } bool TcpStateListen::ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); - return default_state_action(tsd, trk, __func__); + if ( session.config->midstream_allowed(tsd.get_pkt() ) && ( tsd.has_wscale() || + ( tsd.get_seg_len() > 0 ) ) ) + { + Flow* flow = tsd.get_flow(); + + /* FIXIT: do we need to verify the ACK field is >= the seq of the SYN-ACK? + 3-way Handshake complete, create TCP session */ + flow->session_state |= ( STREAM_STATE_ACK | STREAM_STATE_SYN_ACK | + STREAM_STATE_ESTABLISHED ); + trk.init_on_3whs_ack_sent(tsd); + session.init_new_tcp_session(tsd); + session.update_perf_base_state(TcpStreamTracker::TCP_ESTABLISHED); + tcpStats.sessions_on_3way++; + } + else if ( session.config->require_3whs() ) + { + session.generate_no_3whs_event(); + return false; + } + + return default_state_action(tsd, trk); } bool TcpStateListen::ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); + + if ( session.config->midstream_allowed(tsd.get_pkt() ) && ( tsd.has_wscale() || + ( tsd.get_seg_len() > 0 ) ) ) + { + Flow* flow = tsd.get_flow(); - return default_state_action(tsd, trk, __func__); + if ( !tsd.get_tcph()->is_rst() && ( flow->session_state & STREAM_STATE_SYN_ACK ) ) + { + trk.init_on_3whs_ack_recv(tsd); + trk.normalizer->ecn_tracker(tsd.get_tcph(), session.config->require_3whs() ); + } + } + else if ( session.config->require_3whs() ) + { + session.generate_no_3whs_event(); + return false; + } + + return default_state_action(tsd, trk); } bool TcpStateListen::data_seg_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); + + if ( session.config->midstream_allowed(tsd.get_pkt() ) ) + { + Flow* flow = tsd.get_flow(); - return default_state_action(tsd, trk, __func__); + flow->session_state |= STREAM_STATE_MIDSTREAM; + flow->set_session_flags(SSNFLAG_MIDSTREAM); + + trk.init_on_data_seg_sent(tsd); + session.init_new_tcp_session(tsd); + + if ( flow->session_state & STREAM_STATE_ESTABLISHED ) + session.update_perf_base_state(TcpStreamTracker::TCP_ESTABLISHED); + + tcpStats.sessions_on_data++; + } + else if ( session.config->require_3whs() ) + { + session.generate_no_3whs_event(); + return false; + } + + return default_state_action(tsd, trk); } bool TcpStateListen::data_seg_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); + + if ( session.config->midstream_allowed(tsd.get_pkt() ) ) + { + Flow* flow = tsd.get_flow(); - return default_state_action(tsd, trk, __func__); + flow->session_state |= STREAM_STATE_MIDSTREAM; + flow->set_session_flags(SSNFLAG_MIDSTREAM); + trk.init_on_data_seg_recv(tsd); + trk.normalizer->ecn_tracker(tsd.get_tcph(), session.config->require_3whs() ); + } + else if ( session.config->require_3whs() ) + { + session.generate_no_3whs_event(); + return false; + } + + return default_state_action(tsd, trk); } bool TcpStateListen::fin_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); + + if ( session.config->midstream_allowed(tsd.get_pkt() ) ) + { + } + else if ( session.config->require_3whs() ) + { + session.generate_no_3whs_event(); + return false; + } - return default_state_action(tsd, trk, __func__); + return default_state_action(tsd, trk); } bool TcpStateListen::fin_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); + + if ( session.config->midstream_allowed(tsd.get_pkt() ) ) + { + // FIXIT - handle this + } + else if ( session.config->require_3whs() ) + { + session.generate_no_3whs_event(); + return false; + } - return default_state_action(tsd, trk, __func__); + return default_state_action(tsd, trk); } bool TcpStateListen::rst_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); - return default_state_action(tsd, trk, __func__); + if ( session.config->midstream_allowed(tsd.get_pkt() ) ) + { + } + + return default_state_action(tsd, trk); } bool TcpStateListen::rst_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); + + if ( session.config->midstream_allowed(tsd.get_pkt() ) ) + { + // FIXIT - handle this + } - return default_state_action(tsd, trk, __func__); + return default_state_action(tsd, trk); } diff --git a/src/stream/tcp/tcp_state_none.cc b/src/stream/tcp/tcp_state_none.cc index 5eae1573e..660eee303 100644 --- a/src/stream/tcp/tcp_state_none.cc +++ b/src/stream/tcp/tcp_state_none.cc @@ -32,8 +32,8 @@ #include "stream/libtcp/stream_tcp_unit_test.h" #endif -TcpStateNone::TcpStateNone(TcpStateMachine& tsm, TcpSession& session) : - TcpStateHandler(TcpStreamTracker::TCP_STATE_NONE, tsm), session(session) +TcpStateNone::TcpStateNone(TcpStateMachine& tsm, TcpSession& ssn) : + TcpStateHandler(TcpStreamTracker::TCP_STATE_NONE, tsm), session(ssn) { } @@ -44,132 +44,126 @@ TcpStateNone::~TcpStateNone() bool TcpStateNone::syn_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { Flow* flow = tsd.get_flow(); - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); flow->ssn_state.direction = FROM_CLIENT; - flow->session_state |= STREAM_STATE_SYN; - if ( trk.is_3whs_required() || ( tsd.has_wscale() & TF_WSCALE ) || - ( tsd.get_pkt()->dsize > 0 ) ) - { - trk.init_on_syn_sent(tsd); - session.init_new_tcp_session(tsd); - tcpStats.sessions_on_syn++; - } + flow->session_state |= STREAM_STATE_SYN; + trk.init_on_syn_sent(tsd); + session.init_new_tcp_session(tsd); - return true; + return default_state_action(tsd, trk); } bool TcpStateNone::syn_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); - - if ( trk.is_3whs_required() || ( tsd.has_wscale() & TF_WSCALE ) || - ( tsd.get_pkt()->dsize > 0 ) ) - { - trk.init_on_syn_recv(tsd); - trk.normalizer->ecn_tracker(tsd.get_tcph(), trk.is_3whs_required() ); - } + auto& trk = static_cast< TcpTracker& >( tracker ); - return true; + // FIXIT - syn received on undefined client, figure this out and do the right thing + return default_state_action(tsd, trk); } bool TcpStateNone::syn_ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { Flow* flow = tsd.get_flow(); - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); - /* SYN-ACK from server */ - if ( ( flow->session_state == STREAM_STATE_NONE) - || ( flow->get_session_flags() & SSNFLAG_RESET ) ) - { - DebugMessage(DEBUG_STREAM_STATE, - "Stream SYN|ACK PACKET, set session directioon to FROM_SERVER.\n"); - flow->ssn_state.direction = FROM_SERVER; - } - - flow->session_state |= STREAM_STATE_SYN_ACK; - - if ( !trk.is_3whs_required() || session.config->midstream_allowed(tsd.get_pkt()) ) + if ( !session.config->require_3whs() || session.config->midstream_allowed(tsd.get_pkt() ) ) { + flow->session_state |= ( STREAM_STATE_SYN | STREAM_STATE_SYN_ACK ); trk.init_on_synack_sent(tsd); session.init_new_tcp_session(tsd); - tcpStats.sessions_on_syn_ack++; + trk.normalizer->ecn_tracker(tsd.get_tcph(), session.config->require_3whs() ); + } + else if ( session.config->require_3whs() ) + { + session.generate_no_3whs_event(); + return false; } - return true; + return default_state_action(tsd, trk); } bool TcpStateNone::syn_ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); - if ( !trk.is_3whs_required() || session.config->midstream_allowed(tsd.get_pkt()) ) + if ( session.config->midstream_allowed(tsd.get_pkt() ) ) { trk.init_on_synack_recv(tsd); + trk.normalizer->ecn_tracker(tsd.get_tcph(), session.config->require_3whs() ); + } + else if ( session.config->require_3whs() ) + { + session.generate_no_3whs_event(); + return false; } - trk.normalizer->ecn_tracker(tsd.get_tcph(), trk.is_3whs_required() ); - - return true; + return default_state_action(tsd, trk); } bool TcpStateNone::ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - Flow* flow = tsd.get_flow(); - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); - if ( !tsd.get_tcph()->is_rst() && ( flow->session_state & STREAM_STATE_SYN_ACK ) ) + if ( session.config->midstream_allowed(tsd.get_pkt() ) && ( tsd.has_wscale() || + ( tsd.get_seg_len() > 0 ) ) ) { + Flow* flow = tsd.get_flow(); + /* FIXIT: do we need to verify the ACK field is >= the seq of the SYN-ACK? 3-way Handshake complete, create TCP session */ - flow->session_state |= ( STREAM_STATE_ACK | STREAM_STATE_ESTABLISHED ); + flow->session_state |= ( STREAM_STATE_ACK | STREAM_STATE_SYN_ACK | + STREAM_STATE_ESTABLISHED ); trk.init_on_3whs_ack_sent(tsd); session.init_new_tcp_session(tsd); session.update_perf_base_state(TcpStreamTracker::TCP_ESTABLISHED); tcpStats.sessions_on_3way++; } + else if ( session.config->require_3whs() ) + { + session.generate_no_3whs_event(); + return false; + } - return true; + return default_state_action(tsd, trk); } bool TcpStateNone::ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - Flow* flow = tsd.get_flow(); - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); + + if ( session.config->midstream_allowed(tsd.get_pkt() ) && ( tsd.has_wscale() || + ( tsd.get_seg_len() > 0 ) ) ) + { + Flow* flow = tsd.get_flow(); - if ( !tsd.get_tcph()->is_rst() && ( flow->session_state & STREAM_STATE_SYN_ACK ) ) + if ( !tsd.get_tcph()->is_rst() && ( flow->session_state & STREAM_STATE_SYN_ACK ) ) + { + trk.init_on_3whs_ack_recv(tsd); + trk.normalizer->ecn_tracker(tsd.get_tcph(), session.config->require_3whs() ); + } + } + else if ( session.config->require_3whs() ) { - trk.init_on_3whs_ack_recv(tsd); - trk.normalizer->ecn_tracker(tsd.get_tcph(), trk.is_3whs_required() ); + session.generate_no_3whs_event(); + return false; } - return true; + return default_state_action(tsd, trk); } bool TcpStateNone::data_seg_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); - // FIXIT - are these necessary (see checks in TcpSession::process, but should get rid of those - if ( !trk.is_3whs_required() || session.config->midstream_allowed(tsd.get_pkt()) ) + if ( session.config->midstream_allowed(tsd.get_pkt() ) ) { Flow* flow = tsd.get_flow(); flow->session_state |= STREAM_STATE_MIDSTREAM; flow->set_session_flags(SSNFLAG_MIDSTREAM); - if (tsd.get_pkt()->ptrs.sp > tsd.get_pkt()->ptrs.dp) - { - flow->ssn_state.direction = FROM_CLIENT; - flow->set_session_flags(SSNFLAG_SEEN_CLIENT); - } - else - { - flow->ssn_state.direction = FROM_SERVER; - flow->set_session_flags(SSNFLAG_SEEN_SERVER); - } - trk.init_on_data_seg_sent(tsd); session.init_new_tcp_session(tsd); @@ -178,65 +172,94 @@ bool TcpStateNone::data_seg_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tr tcpStats.sessions_on_data++; } + else if ( session.config->require_3whs() ) + { + session.generate_no_3whs_event(); + return false; + } - return true; + return default_state_action(tsd, trk); } bool TcpStateNone::data_seg_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); - if ( !trk.is_3whs_required() || session.config->midstream_allowed(tsd.get_pkt()) ) + if ( session.config->midstream_allowed(tsd.get_pkt() ) ) { Flow* flow = tsd.get_flow(); flow->session_state |= STREAM_STATE_MIDSTREAM; flow->set_session_flags(SSNFLAG_MIDSTREAM); - if (tsd.get_pkt()->ptrs.sp > tsd.get_pkt()->ptrs.dp) - { - flow->ssn_state.direction = FROM_CLIENT; - flow->set_session_flags(SSNFLAG_SEEN_CLIENT); - } - else - { - flow->ssn_state.direction = FROM_SERVER; - flow->set_session_flags(SSNFLAG_SEEN_SERVER); - } - trk.init_on_data_seg_recv(tsd); - trk.normalizer->ecn_tracker(tsd.get_tcph(), trk.is_3whs_required() ); + trk.normalizer->ecn_tracker(tsd.get_tcph(), session.config->require_3whs() ); + } + else if ( session.config->require_3whs() ) + { + session.generate_no_3whs_event(); + return false; } - return true; + return default_state_action(tsd, trk); } bool TcpStateNone::fin_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); - return default_state_action(tsd, trk, __func__); + if ( session.config->midstream_allowed(tsd.get_pkt() ) ) + { + // FIXIT - handle this + } + else if ( session.config->require_3whs() ) + { + session.generate_no_3whs_event(); + return false; + } + + return default_state_action(tsd, trk); } bool TcpStateNone::fin_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); - return default_state_action(tsd, trk, __func__); + if ( session.config->midstream_allowed(tsd.get_pkt() ) ) + { + // FIXIT - handle this + } + else if ( session.config->require_3whs() ) + { + session.generate_no_3whs_event(); + return false; + } + + return default_state_action(tsd, trk); } bool TcpStateNone::rst_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); + + if ( session.config->midstream_allowed(tsd.get_pkt() ) ) + { + // FIXIT - handle this + } - return default_state_action(tsd, trk, __func__); + return default_state_action(tsd, trk); } bool TcpStateNone::rst_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); + + if ( session.config->midstream_allowed(tsd.get_pkt() ) ) + { + // FIXIT - handle this + } - return default_state_action(tsd, trk, __func__); + return default_state_action(tsd, trk); } #ifdef FOO // FIXIT - UNIT_TEST need work!! diff --git a/src/stream/tcp/tcp_state_syn_recv.cc b/src/stream/tcp/tcp_state_syn_recv.cc index a3a6e647a..5447a35c0 100644 --- a/src/stream/tcp/tcp_state_syn_recv.cc +++ b/src/stream/tcp/tcp_state_syn_recv.cc @@ -28,8 +28,8 @@ using namespace std; #include "tcp_normalizer.h" #include "tcp_state_syn_recv.h" -TcpStateSynRecv::TcpStateSynRecv(TcpStateMachine& tsm, TcpSession& session) : - TcpStateHandler(TcpStreamTracker::TCP_SYN_RECV, tsm), session(session) +TcpStateSynRecv::TcpStateSynRecv(TcpStateMachine& tsm, TcpSession& ssn) : + TcpStateHandler(TcpStreamTracker::TCP_SYN_RECV, tsm), session(ssn) { } @@ -39,85 +39,168 @@ TcpStateSynRecv::~TcpStateSynRecv() bool TcpStateSynRecv::syn_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + Flow* flow = tsd.get_flow(); + auto& trk = static_cast< TcpTracker& >( tracker ); - return default_state_action(tsd, trk, __func__); + trk.finish_server_init(tsd); + trk.normalizer->ecn_tracker(tsd.get_tcph(), session.config->require_3whs() ); + session.update_timestamp_tracking(tsd); + if ( tsd.get_tcph()->are_flags_set(TH_ECE) && + ( flow->get_session_flags() & SSNFLAG_ECN_CLIENT_QUERY ) ) + flow->set_session_flags(SSNFLAG_ECN_SERVER_REPLY); + + if ( tsd.get_pkt()->packet_flags & PKT_FROM_SERVER ) + { + flow->set_session_flags(SSNFLAG_SEEN_SERVER); + session.tel.set_tcp_event(EVENT_4WHS); + } + + trk.s_mgr.sub_state |= SUB_SYN_SENT; + + return default_state_action(tsd, trk); } bool TcpStateSynRecv::syn_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); + + if ( tsd.get_seg_len() ) + session.handle_data_on_syn(tsd); - return default_state_action(tsd, trk, __func__); + return default_state_action(tsd, trk); } bool TcpStateSynRecv::syn_ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + Flow* flow = tsd.get_flow(); + auto& trk = static_cast< TcpTracker& >( tracker ); - return default_state_action(tsd, trk, __func__); + // FIXIT - verify ack being sent is valid... + trk.finish_server_init(tsd); + trk.normalizer->ecn_tracker(tsd.get_tcph(), session.config->require_3whs() ); + flow->session_state |= STREAM_STATE_SYN_ACK; + + trk.s_mgr.sub_state |= ( SUB_SYN_SENT | SUB_ACK_SENT ); + + return default_state_action(tsd, trk); } bool TcpStateSynRecv::syn_ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); + + if ( trk.is_ack_valid(tsd.get_seg_ack() ) ) + { + Flow* flow = tsd.get_flow(); + + trk.update_tracker_ack_recv(tsd); + trk.normalizer->ecn_tracker(tsd.get_tcph(), session.config->require_3whs() ); + flow->set_session_flags(SSNFLAG_ESTABLISHED); + flow->session_state |= ( STREAM_STATE_ACK | STREAM_STATE_ESTABLISHED ); + session.update_perf_base_state(TcpStreamTracker::TCP_ESTABLISHED); + trk.set_tcp_state(TcpStreamTracker::TCP_ESTABLISHED); + } - return default_state_action(tsd, trk, __func__); + return default_state_action(tsd, trk); } bool TcpStateSynRecv::ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); - return default_state_action(tsd, trk, __func__); + if ( session.config->midstream_allowed(tsd.get_pkt()) ) + { + session.update_session_on_ack( ); + } + trk.s_mgr.sub_state |= SUB_ACK_SENT; + + return default_state_action(tsd, trk); } bool TcpStateSynRecv::ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); + + if ( trk.is_ack_valid(tsd.get_seg_ack() ) ) + { + trk.update_tracker_ack_recv(tsd); + tsd.get_pkt()->packet_flags |= PKT_STREAM_TWH; + session.update_perf_base_state(TcpStreamTracker::TCP_ESTABLISHED); + trk.set_tcp_state(TcpStreamTracker::TCP_ESTABLISHED); + } - return default_state_action(tsd, trk, __func__); + return default_state_action(tsd, trk); } bool TcpStateSynRecv::data_seg_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); - return default_state_action(tsd, trk, __func__); + trk.s_mgr.sub_state |= SUB_ACK_SENT; + + return default_state_action(tsd, trk); } bool TcpStateSynRecv::data_seg_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); + + if ( trk.is_ack_valid(tsd.get_seg_ack() ) ) + { + trk.update_tracker_ack_recv(tsd); + tsd.get_pkt()->packet_flags |= PKT_STREAM_TWH; + session.update_perf_base_state(TcpStreamTracker::TCP_ESTABLISHED); + trk.set_tcp_state(TcpStreamTracker::TCP_ESTABLISHED); + } - return default_state_action(tsd, trk, __func__); + return default_state_action(tsd, trk); } bool TcpStateSynRecv::fin_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); - return default_state_action(tsd, trk, __func__); + trk.s_mgr.sub_state |= SUB_ACK_SENT; + + return default_state_action(tsd, trk); } bool TcpStateSynRecv::fin_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); - - return default_state_action(tsd, trk, __func__); + auto& trk = static_cast< TcpTracker& >( tracker ); + if ( tsd.get_tcph()->is_ack() ) + { + Flow* flow = tsd.get_flow(); + flow->session_state |= STREAM_STATE_ACK; + trk.update_tracker_ack_recv(tsd); + trk.set_tcp_state(TcpStreamTracker::TCP_CLOSE_WAIT); + } + + return default_state_action(tsd, trk); } bool TcpStateSynRecv::rst_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); - return default_state_action(tsd, trk, __func__); + return default_state_action(tsd, trk); } bool TcpStateSynRecv::rst_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); - - return default_state_action(tsd, trk, __func__); + auto& trk = static_cast< TcpTracker& >( tracker ); + + if ( trk.update_on_rst_recv(tsd) ) + { + session.update_session_on_rst(tsd, false); + session.update_perf_base_state(TcpStreamTracker::TCP_CLOSING); + session.set_pkt_action_flag(ACTION_RST); + } + else + { + session.tel.set_tcp_event(EVENT_BAD_RST); + } + + 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 66c428761..65d25817e 100644 --- a/src/stream/tcp/tcp_state_syn_sent.cc +++ b/src/stream/tcp/tcp_state_syn_sent.cc @@ -32,8 +32,8 @@ using namespace std; #include "catch/catch.hpp" #endif -TcpStateSynSent::TcpStateSynSent(TcpStateMachine& tsm, TcpSession& session) : - TcpStateHandler(TcpStreamTracker::TCP_SYN_SENT, tsm), session(session) +TcpStateSynSent::TcpStateSynSent(TcpStateMachine& tsm, TcpSession& ssn) : + TcpStateHandler(TcpStreamTracker::TCP_SYN_SENT, tsm), session(ssn) { } @@ -43,85 +43,132 @@ TcpStateSynSent::~TcpStateSynSent() bool TcpStateSynSent::syn_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); - return default_state_action(tsd, trk, __func__); + trk.s_mgr.sub_state |= SUB_SYN_SENT; + + return default_state_action(tsd, trk); } bool TcpStateSynSent::syn_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); + + trk.finish_client_init(tsd); + if ( tsd.get_seg_len() ) + session.handle_data_on_syn(tsd); + trk.set_tcp_state(TcpStreamTracker::TCP_SYN_RECV); - return default_state_action(tsd, trk, __func__); + return default_state_action(tsd, trk); } bool TcpStateSynSent::syn_ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); - return default_state_action(tsd, trk, __func__); + trk.s_mgr.sub_state |= ( SUB_SYN_SENT | SUB_ACK_SENT ); + + return default_state_action(tsd, trk); } bool TcpStateSynSent::syn_ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); - - return default_state_action(tsd, trk, __func__); + auto& trk = static_cast< TcpTracker& >( tracker ); + + if ( trk.update_on_3whs_ack(tsd) ) + { + session.update_timestamp_tracking(tsd); + if ( tsd.get_seg_len() ) + session.handle_data_on_syn(tsd); + } + else + session.set_pkt_action_flag(ACTION_BAD_PKT); + + return default_state_action(tsd, trk); } bool TcpStateSynSent::ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); - - return default_state_action(tsd, trk, __func__); + Flow* flow = tsd.get_flow(); + auto& trk = static_cast< TcpTracker& >( tracker ); + + // FIXIT - verify ack being sent is valid... + trk.update_tracker_ack_sent(tsd); + flow->set_session_flags(SSNFLAG_ESTABLISHED); + flow->session_state |= ( STREAM_STATE_ACK | STREAM_STATE_ESTABLISHED ); + session.update_timestamp_tracking(tsd); + session.update_perf_base_state(TcpStreamTracker::TCP_ESTABLISHED); + trk.set_tcp_state(TcpStreamTracker::TCP_ESTABLISHED); + + return default_state_action(tsd, trk); } bool TcpStateSynSent::ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); - return default_state_action(tsd, trk, __func__); + return default_state_action(tsd, trk); } bool TcpStateSynSent::data_seg_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); - - return default_state_action(tsd, trk, __func__); + Flow* flow = tsd.get_flow(); + auto& trk = static_cast< TcpTracker& >( tracker ); + + // FIXIT - verify ack being sent is valid... + trk.update_tracker_ack_sent(tsd); + flow->set_session_flags(SSNFLAG_ESTABLISHED); + flow->session_state |= ( STREAM_STATE_ACK | STREAM_STATE_ESTABLISHED ); + session.update_timestamp_tracking(tsd); + session.update_perf_base_state(TcpStreamTracker::TCP_ESTABLISHED); + trk.set_tcp_state(TcpStreamTracker::TCP_ESTABLISHED); + + return default_state_action(tsd, trk); } bool TcpStateSynSent::data_seg_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); - return default_state_action(tsd, trk, __func__); + return default_state_action(tsd, trk); } bool TcpStateSynSent::fin_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); - return default_state_action(tsd, trk, __func__); + return default_state_action(tsd, trk); } bool TcpStateSynSent::fin_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); - return default_state_action(tsd, trk, __func__); + return default_state_action(tsd, trk); } bool TcpStateSynSent::rst_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); - return default_state_action(tsd, trk, __func__); + return default_state_action(tsd, trk); } bool TcpStateSynSent::rst_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); - - return default_state_action(tsd, trk, __func__); + auto& trk = static_cast< TcpTracker& >( tracker ); + + if ( trk.update_on_rst_recv(tsd) ) + { + session.update_session_on_rst(tsd, false); + session.update_perf_base_state(TcpStreamTracker::TCP_CLOSING); + session.set_pkt_action_flag(ACTION_RST); + } + else + { + session.tel.set_tcp_event(EVENT_BAD_RST); + } + + 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 e7abaef8f..9bb8b7400 100644 --- a/src/stream/tcp/tcp_state_time_wait.cc +++ b/src/stream/tcp/tcp_state_time_wait.cc @@ -32,8 +32,8 @@ using namespace std; #include "catch/catch.hpp" #endif -TcpStateTimeWait::TcpStateTimeWait(TcpStateMachine& tsm, TcpSession& session) : - TcpStateHandler(TcpStreamTracker::TCP_TIME_WAIT, tsm), session(session) +TcpStateTimeWait::TcpStateTimeWait(TcpStateMachine& tsm, TcpSession& ssn) : + TcpStateHandler(TcpStreamTracker::TCP_TIME_WAIT, tsm), session(ssn) { } @@ -43,85 +43,104 @@ TcpStateTimeWait::~TcpStateTimeWait() bool TcpStateTimeWait::syn_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); - return default_state_action(tsd, trk, __func__); + trk.s_mgr.sub_state |= SUB_SYN_SENT; + + return default_state_action(tsd, trk); } bool TcpStateTimeWait::syn_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); + + trk.normalizer->ecn_tracker(tsd.get_tcph(), session.config->require_3whs() ); + if ( tsd.get_seg_len() ) + session.handle_data_on_syn(tsd); - return default_state_action(tsd, trk, __func__); + return true; } bool TcpStateTimeWait::syn_ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); - return default_state_action(tsd, trk, __func__); + trk.s_mgr.sub_state |= ( SUB_SYN_SENT | SUB_ACK_SENT ); + + return default_state_action(tsd, trk); } bool TcpStateTimeWait::syn_ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); - return default_state_action(tsd, trk, __func__); + return default_state_action(tsd, trk); } bool TcpStateTimeWait::ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); - return default_state_action(tsd, trk, __func__); + return default_state_action(tsd, trk); } bool TcpStateTimeWait::ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); - return default_state_action(tsd, trk, __func__); + return default_state_action(tsd, trk); } bool TcpStateTimeWait::data_seg_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); - return default_state_action(tsd, trk, __func__); + return default_state_action(tsd, trk); } bool TcpStateTimeWait::data_seg_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); - return default_state_action(tsd, trk, __func__); + return default_state_action(tsd, trk); } bool TcpStateTimeWait::fin_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); - return default_state_action(tsd, trk, __func__); + return default_state_action(tsd, trk); } bool TcpStateTimeWait::fin_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); - return default_state_action(tsd, trk, __func__); + return default_state_action(tsd, trk); } bool TcpStateTimeWait::rst_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + auto& trk = static_cast< TcpTracker& >( tracker ); - return default_state_action(tsd, trk, __func__); + return default_state_action(tsd, trk); } bool TcpStateTimeWait::rst_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - TcpTracker& trk = static_cast< TcpTracker& >( tracker ); - - return default_state_action(tsd, trk, __func__); + auto& trk = static_cast< TcpTracker& >( tracker ); + + if ( trk.update_on_rst_recv(tsd) ) + { + session.update_session_on_rst(tsd, false); + session.update_perf_base_state(TcpStreamTracker::TCP_CLOSING); + session.set_pkt_action_flag(ACTION_RST); + } + else + { + session.tel.set_tcp_event(EVENT_BAD_RST); + } + + return default_state_action(tsd, trk); } diff --git a/src/stream/tcp/tcp_stream_config.cc b/src/stream/tcp/tcp_stream_config.cc index 181335b4f..710943dfb 100644 --- a/src/stream/tcp/tcp_stream_config.cc +++ b/src/stream/tcp/tcp_stream_config.cc @@ -20,50 +20,14 @@ // Created on: Oct 22, 2015 #include "main/snort_config.h" -#include "time/packet_time.h" -#include "stream/stream.h" #include "tcp_stream_config.h" -static const char* const reassembly_policy_names[] = { "no policy", "first", - "last", "linux", "old_linux", "bsd", - "macos", "solaris", "irix", - "hpux11", "hpux10", "windows", "win_2003", - "vista", "proxy" }; +static const char* const reassembly_policy_names[] = +{ "no policy", "first", "last", "linux", "old_linux", "bsd", "macos", "solaris", "irix", + "hpux11", "hpux10", "windows", "win_2003", "vista", "proxy" }; TcpStreamConfig::TcpStreamConfig(void) { - policy = StreamPolicy::OS_DEFAULT; - reassembly_policy = ReassemblyPolicy::OS_DEFAULT; - - flags = 0; - flush_factor = 0; - - session_timeout = STREAM_DEFAULT_SSN_TIMEOUT; - max_window = 0; - overlap_limit = 0; - - max_queued_bytes = STREAM_DEFAULT_MAX_QUEUED_BYTES; - max_queued_segs = STREAM_DEFAULT_MAX_QUEUED_SEGS; - - max_consec_small_segs = STREAM_DEFAULT_CONSEC_SMALL_SEGS; - max_consec_small_seg_size = STREAM_DEFAULT_MAX_SMALL_SEG_SIZE; - - hs_timeout = -1; - footprint = 0; - paf_max = 16384; -} - -bool TcpStreamConfig::require_3whs(void) -{ - return hs_timeout >= 0; -} - -bool TcpStreamConfig::midstream_allowed(Packet* p) -{ - if ( ( hs_timeout < 0 ) || ( p->pkth->ts.tv_sec - packet_first_time() < hs_timeout ) ) - return true; - - return false; } void TcpStreamConfig::show_config(void) diff --git a/src/stream/tcp/tcp_stream_config.h b/src/stream/tcp/tcp_stream_config.h index 584c3cfc3..4dd590f0b 100644 --- a/src/stream/tcp/tcp_stream_config.h +++ b/src/stream/tcp/tcp_stream_config.h @@ -22,6 +22,9 @@ #ifndef TCP_STREAM_CONFIG_H #define TCP_STREAM_CONFIG_H +#include "time/packet_time.h" +#include "stream/stream.h" + #include "tcp_defs.h" class TcpStreamConfig @@ -29,31 +32,42 @@ class TcpStreamConfig public: TcpStreamConfig(void); - bool require_3whs(void); - bool midstream_allowed(Packet*); + bool require_3whs(void) + { + return hs_timeout >= 0; + } + + bool midstream_allowed(Packet* p) + { + if ( ( hs_timeout < 0 ) || ( p->pkth->ts.tv_sec - packet_first_time() < hs_timeout ) ) + return true; + + return false; + } + int verify_config(SnortConfig*); void show_config(void); static void show_config(TcpStreamConfig*); - StreamPolicy policy; - ReassemblyPolicy reassembly_policy; + StreamPolicy policy = StreamPolicy::OS_DEFAULT; + ReassemblyPolicy reassembly_policy = ReassemblyPolicy::OS_DEFAULT; - uint16_t flags; - uint16_t flush_factor; + uint16_t flags = 0; + uint16_t flush_factor = 0; - uint32_t session_timeout; - uint32_t max_window; - uint32_t overlap_limit; + uint32_t session_timeout = STREAM_DEFAULT_SSN_TIMEOUT; + uint32_t max_window = 0; + uint32_t overlap_limit = 0; - uint32_t max_queued_bytes; - uint32_t max_queued_segs; + uint32_t max_queued_bytes = STREAM_DEFAULT_MAX_QUEUED_BYTES; + uint32_t max_queued_segs = STREAM_DEFAULT_MAX_QUEUED_SEGS; - uint32_t max_consec_small_segs; - uint32_t max_consec_small_seg_size; + uint32_t max_consec_small_segs = STREAM_DEFAULT_CONSEC_SMALL_SEGS; + uint32_t max_consec_small_seg_size = STREAM_DEFAULT_MAX_SMALL_SEG_SIZE; - int hs_timeout; - int footprint; - unsigned paf_max; + int hs_timeout = -1; + int footprint = 0; + uint32_t paf_max = 16384; }; #endif diff --git a/src/stream/tcp/tcp_tracker.cc b/src/stream/tcp/tcp_tracker.cc index 326bb3c5a..470d99d52 100644 --- a/src/stream/tcp/tcp_tracker.cc +++ b/src/stream/tcp/tcp_tracker.cc @@ -26,10 +26,8 @@ #include "tcp_tracker.h" TcpTracker::TcpTracker(bool client) : - TcpStreamTracker(client), splitter(nullptr), normalizer(nullptr), reassembler(nullptr) + TcpStreamTracker(client) { - tcp_event = TCP_MAX_EVENTS; - init_tracker( ); } TcpTracker::~TcpTracker(void) @@ -41,19 +39,19 @@ TcpTracker::~TcpTracker(void) void TcpTracker::init_tracker(void) { - memset(&s_mgr, 0, sizeof( StateMgr ) ); + memset(&s_mgr, 0, sizeof(s_mgr)); s_mgr.state_queue = TcpStreamTracker::TCP_STATE_NONE; - - tcp_state = TcpStreamTracker::TCP_STATE_NONE; + tcp_state = ( client_tracker ) ? + TcpStreamTracker::TCP_STATE_NONE : TcpStreamTracker::TCP_LISTEN; flush_policy = STREAM_FLPOLICY_IGNORE; - memset(&paf_state, 0, sizeof( PAF_State ) ); + memset(&paf_state, 0, sizeof(paf_state)); snd_una = snd_nxt = snd_wnd = 0; r_nxt_ack = r_win_base = iss = ts_last = ts_last_packet = 0; small_seg_count = wscale = mss = 0; - memset(mac_addr, 0, 6); - flags = 0; + tf_flags = 0; alert_count = 0; - memset(alerts, 0, sizeof( alerts ) ); + memset(&alerts, 0, sizeof(alerts)); + memset(&mac_addr, 0, sizeof(mac_addr)); delete splitter; splitter = nullptr; @@ -111,27 +109,25 @@ void TcpTracker::init_on_syn_sent(TcpSegmentDescriptor& tsd) if ( tsd.get_tcph()->are_flags_set(TH_CWR | TH_ECE) ) tsd.get_flow()->set_session_flags(SSNFLAG_ECN_CLIENT_QUERY); - iss = tsd.get_seq(); - snd_una = tsd.get_seq() + 1; - if ( tsd.get_seq() == tsd.get_end_seq() ) - snd_nxt = snd_una; - else - snd_nxt = snd_una + ( tsd.get_end_seq() - tsd.get_seq() - 1 ); + iss = tsd.get_seg_seq(); + snd_una = iss; + snd_nxt = tsd.get_end_seq(); + snd_wnd = tsd.get_seg_wnd(); - snd_wnd = tsd.get_win(); ts_last_packet = tsd.get_pkt()->pkth->ts.tv_sec; - - flags |= normalizer->get_tcp_timestamp(tsd, false); + tf_flags |= normalizer->get_tcp_timestamp(tsd, false); ts_last = tsd.get_ts(); if (ts_last == 0) - flags |= TF_TSTAMP_ZERO; - flags |= tsd.init_mss(&mss); - flags |= tsd.init_wscale(&wscale); + tf_flags |= TF_TSTAMP_ZERO; + tf_flags |= tsd.init_mss(&mss); + tf_flags |= tsd.init_wscale(&wscale); + s_mgr.sub_state |= SUB_SYN_SENT; cache_mac_address(tsd, FROM_CLIENT); set_splitter(tsd.get_flow() ); init_flush_policy( ); + tcpStats.sessions_on_syn++; tcp_state = TcpStreamTracker::TCP_SYN_SENT; } @@ -139,15 +135,17 @@ void TcpTracker::init_on_syn_recv(TcpSegmentDescriptor& tsd) { Profile profile(s5TcpNewSessPerfStats); - reassembler->set_seglist_base_seq(tsd.get_seq() + 1); - r_nxt_ack = tsd.get_seq() + 1; - r_win_base = tsd.get_seq() + 1; + irs = tsd.get_seg_seq(); + // FIXIT - can we really set the vars below now? + r_nxt_ack = tsd.get_seg_seq() + 1; + r_win_base = tsd.get_seg_seq() + 1; + reassembler->set_seglist_base_seq(tsd.get_seg_seq() + 1); cache_mac_address(tsd, FROM_CLIENT); set_splitter(tsd.get_flow() ); init_flush_policy( ); - tcp_state = TcpStreamTracker::TCP_LISTEN; + tcp_state = TcpStreamTracker::TCP_SYN_RECV; } void TcpTracker::init_on_synack_sent(TcpSegmentDescriptor& tsd) @@ -160,27 +158,30 @@ void TcpTracker::init_on_synack_sent(TcpSegmentDescriptor& tsd) if (tsd.get_tcph()->are_flags_set(TH_CWR | TH_ECE)) tsd.get_flow()->set_session_flags(SSNFLAG_ECN_SERVER_REPLY); - iss =tsd.get_seq(); - snd_una = tsd.get_seq() + 1; - snd_nxt = snd_una; - snd_wnd = tsd.get_win(); + iss = tsd.get_seg_seq(); + irs = tsd.get_seg_ack() - 1; + snd_una = tsd.get_seg_seq(); + snd_nxt = tsd.get_end_seq(); + snd_wnd = tsd.get_seg_wnd(); - reassembler->set_seglist_base_seq(tsd.get_ack() ); - r_win_base = tsd.get_ack(); - r_nxt_ack = tsd.get_ack(); - ts_last_packet = tsd.get_pkt()->pkth->ts.tv_sec; + r_win_base = tsd.get_seg_ack(); + r_nxt_ack = tsd.get_seg_ack(); + reassembler->set_seglist_base_seq(tsd.get_seg_ack() ); - flags |= normalizer->get_tcp_timestamp(tsd, false); + ts_last_packet = tsd.get_pkt()->pkth->ts.tv_sec; + tf_flags |= normalizer->get_tcp_timestamp(tsd, false); ts_last = tsd.get_ts(); if ( ts_last == 0 ) - flags |= TF_TSTAMP_ZERO; - flags |= tsd.init_mss(&mss); - flags |= tsd.init_wscale(&wscale); + tf_flags |= TF_TSTAMP_ZERO; + tf_flags |= tsd.init_mss(&mss); + tf_flags |= tsd.init_wscale(&wscale); + s_mgr.sub_state |= ( SUB_SYN_SENT | SUB_ACK_SENT ); cache_mac_address(tsd, FROM_SERVER); set_splitter(tsd.get_flow() ); init_flush_policy(); + tcpStats.sessions_on_syn_ack++; tcp_state = TcpStreamTracker::TCP_SYN_RECV; } @@ -188,11 +189,14 @@ void TcpTracker::init_on_synack_recv(TcpSegmentDescriptor& tsd) { Profile profile(s5TcpNewSessPerfStats); - reassembler->set_seglist_base_seq(tsd.get_seq() + 1); - iss = tsd.get_ack() - 1; - r_nxt_ack = tsd.get_seq() + 1; - r_win_base = tsd.get_seq() + 1; - snd_nxt = tsd.get_ack(); + iss = tsd.get_seg_ack() - 1; + irs = tsd.get_seg_seq(); + snd_una = tsd.get_seg_ack(); + snd_nxt = snd_una; + + r_nxt_ack = tsd.get_seg_seq() + 1; + r_win_base = tsd.get_seg_seq() + 1; + reassembler->set_seglist_base_seq(tsd.get_seg_seq() + 1); cache_mac_address(tsd, FROM_SERVER); set_splitter(tsd.get_flow() ); @@ -210,17 +214,22 @@ void TcpTracker::init_on_3whs_ack_sent(TcpSegmentDescriptor& tsd) if ( tsd.get_tcph()->are_flags_set(TH_CWR | TH_ECE) ) tsd.get_flow()->set_session_flags(SSNFLAG_ECN_CLIENT_QUERY); - iss = tsd.get_seq(); - snd_una = tsd.get_seq() + 1; - snd_nxt = tsd.get_seq() + 1; - snd_wnd = tsd.get_win(); + iss = tsd.get_seg_seq(); + snd_una = tsd.get_seg_seq(); + snd_nxt = snd_una; + snd_wnd = tsd.get_seg_wnd(); + + r_win_base = tsd.get_seg_ack(); + r_nxt_ack = tsd.get_seg_ack(); + ts_last_packet = tsd.get_pkt()->pkth->ts.tv_sec; - flags |= normalizer->get_tcp_timestamp(tsd, false); + tf_flags |= normalizer->get_tcp_timestamp(tsd, false); ts_last = tsd.get_ts(); if (ts_last == 0) - flags |= TF_TSTAMP_ZERO; - flags |= tsd.init_mss(&mss); - flags |= tsd.init_wscale(&wscale); + tf_flags |= TF_TSTAMP_ZERO; + tf_flags |= tsd.init_mss(&mss); + tf_flags |= tsd.init_wscale(&wscale); + s_mgr.sub_state |= SUB_ACK_SENT; cache_mac_address(tsd, FROM_CLIENT); set_splitter(tsd.get_flow() ); @@ -232,9 +241,14 @@ void TcpTracker::init_on_3whs_ack_recv(TcpSegmentDescriptor& tsd) { Profile profile(s5TcpNewSessPerfStats); - reassembler->set_seglist_base_seq(tsd.get_seq() + 1); - r_nxt_ack = tsd.get_seq() + 1; - r_win_base = tsd.get_seq() + 1; + iss = tsd.get_seg_ack() - 1; + irs = tsd.get_seg_seq(); + snd_una = tsd.get_seg_ack(); + snd_nxt = snd_una; + + r_nxt_ack = tsd.get_seg_seq(); + r_win_base = tsd.get_seg_seq(); + reassembler->set_seglist_base_seq(tsd.get_seg_seq() + 1); cache_mac_address(tsd, FROM_CLIENT); set_splitter(tsd.get_flow() ); @@ -246,29 +260,31 @@ void TcpTracker::init_on_data_seg_sent(TcpSegmentDescriptor& tsd) { Profile profile(s5TcpNewSessPerfStats); - iss = tsd.get_seq(); - snd_una = tsd.get_seq(); - snd_nxt = tsd.get_seq(); - snd_wnd = tsd.get_win(); - if ( tsd.get_direction() == FROM_SERVER ) - { - r_win_base = tsd.get_ack(); - r_nxt_ack = tsd.get_ack(); - reassembler->set_seglist_base_seq(tsd.get_ack() ); - } + Flow* flow = tsd.get_flow(); + + if ( flow->ssn_state.direction == FROM_CLIENT ) + flow->set_session_flags(SSNFLAG_SEEN_CLIENT); else - { - r_win_base = 0; - r_nxt_ack = 0; - } + flow->set_session_flags(SSNFLAG_SEEN_SERVER); + + // FIXIT - should we init these? + iss = tsd.get_seg_seq(); + irs = tsd.get_seg_ack(); + snd_una = tsd.get_seg_seq(); + snd_nxt = snd_una + tsd.get_seg_len(); + snd_wnd = tsd.get_seg_wnd(); + + r_win_base = tsd.get_seg_ack(); + r_nxt_ack = tsd.get_seg_ack(); + reassembler->set_seglist_base_seq(tsd.get_seg_ack() ); ts_last_packet = tsd.get_pkt()->pkth->ts.tv_sec; - flags |= normalizer->get_tcp_timestamp(tsd, 0); + tf_flags |= normalizer->get_tcp_timestamp(tsd, 0); ts_last = tsd.get_ts(); if (ts_last == 0) - flags |= TF_TSTAMP_ZERO; - flags |= tsd.init_mss(&mss); - flags |= tsd.init_wscale(&wscale); + tf_flags |= TF_TSTAMP_ZERO; + tf_flags |= ( tsd.init_mss(&mss) | tsd.init_wscale(&wscale) ); + s_mgr.sub_state |= SUB_ACK_SENT; cache_mac_address(tsd, tsd.get_direction() ); set_splitter(tsd.get_flow() ); @@ -280,15 +296,16 @@ void TcpTracker::init_on_data_seg_recv(TcpSegmentDescriptor& tsd) { Profile profile(s5TcpNewSessPerfStats); - if ( tsd.get_direction() == FROM_SERVER ) - iss = tsd.get_ack() - 1; - else - snd_una = tsd.get_ack() - 1; - - r_nxt_ack = tsd.get_seq(); - r_win_base = tsd.get_seq(); + // FIXIT - should we init these? + iss = tsd.get_seg_ack(); + irs = tsd.get_seg_seq(); + snd_una = tsd.get_seg_ack(); + snd_nxt = snd_una; snd_wnd = 0; /* reset later */ - reassembler->set_seglist_base_seq(tsd.get_seq() ); + + r_nxt_ack = tsd.get_seg_seq(); + r_win_base = tsd.get_seg_seq(); + reassembler->set_seglist_base_seq(tsd.get_seg_seq() ); cache_mac_address(tsd, tsd.get_direction() ); set_splitter(tsd.get_flow() ); @@ -296,6 +313,245 @@ void TcpTracker::init_on_data_seg_recv(TcpSegmentDescriptor& tsd) tcp_state = TcpStreamTracker::TCP_ESTABLISHED; } +void TcpTracker::finish_server_init(TcpSegmentDescriptor& tsd) +{ + iss = tsd.get_seg_seq(); + snd_una = tsd.get_seg_seq(); + snd_nxt = tsd.get_end_seq(); + snd_wnd = tsd.get_seg_wnd(); + + // FIXIT - move this to fin handler for syn_recv state .. + //if ( tcph->is_fin() ) + // server->set_snd_nxt(server->get_snd_nxt() - 1); + + tf_flags |= normalizer->get_tcp_timestamp(tsd, false); + ts_last = tsd.get_ts(); + if ( ts_last != 0 ) + ts_last_packet = tsd.get_pkt()->pkth->ts.tv_sec; + else + tf_flags |= TF_TSTAMP_ZERO; + + tf_flags |= ( tsd.init_mss(&mss) | tsd.init_wscale(&wscale) ); +} + +void TcpTracker::finish_client_init(TcpSegmentDescriptor& tsd) +{ + Flow* flow = tsd.get_flow(); + + r_nxt_ack = tsd.get_end_seq(); + + if ( !( flow->session_state & STREAM_STATE_MIDSTREAM ) ) + { + reassembler->set_seglist_base_seq(tsd.get_seg_seq() + 1); + r_win_base = tsd.get_end_seq(); + } + else + { + reassembler->set_seglist_base_seq(tsd.get_seg_seq() ); + r_win_base = tsd.get_seg_seq(); + } +} + +void TcpTracker::update_tracker_ack_recv(TcpSegmentDescriptor& tsd) +{ + if ( SEQ_GT(tsd.get_seg_ack(), snd_una) ) + { + snd_una = tsd.get_seg_ack(); + if ( snd_nxt < snd_una ) + snd_nxt = snd_una + 1; + } +} + +void TcpTracker::update_tracker_ack_sent(TcpSegmentDescriptor& tsd) +{ + // ** this is how we track the last seq number sent + // as is l_unackd is the "last left" seq recvd + //snd_una = tsd.get_seg_seq(); + + // FIXIT - add check to validate ack... + + if ( SEQ_GT(tsd.get_end_seq(), snd_nxt) ) + snd_nxt = tsd.get_end_seq(); + + if ( !SEQ_EQ(r_win_base, tsd.get_seg_ack() ) ) + small_seg_count = 0; + +#ifdef S5_PEDANTIC + if ( SEQ_GT(tsd.get_seg_ack(), r_win_base) && + SEQ_LEQ(tsd.get_seg_ack(), r_nxt_ack) ) +#else + if ( SEQ_GT(tsd.get_seg_ack(), r_win_base) ) +#endif + r_win_base = tsd.get_seg_ack(); + + snd_wnd = tsd.get_seg_wnd(); + + s_mgr.sub_state |= SUB_ACK_SENT; + + reassembler->flush_on_ack_policy(tsd.get_pkt() ); +} + +bool TcpTracker::update_on_3whs_ack(TcpSegmentDescriptor& tsd) +{ + bool good_ack = true; + + if ( is_ack_valid(tsd.get_seg_ack()) ) + { + Flow* flow = tsd.get_flow(); + + irs = tsd.get_seg_seq(); + finish_client_init(tsd); + update_tracker_ack_recv(tsd); + flow->set_session_flags(SSNFLAG_ESTABLISHED); + flow->session_state |= ( STREAM_STATE_ACK | STREAM_STATE_ESTABLISHED ); + + /* Indicate this packet completes 3-way handshake */ + tsd.get_pkt()->packet_flags |= PKT_STREAM_TWH; + tcp_state = TcpStreamTracker::TCP_ESTABLISHED; + } + else + { + DebugFormat(DEBUG_STREAM_STATE, + "Pkt Ack is Out of Bounds (%X, %X, %X) = (snd_una, snd_nxt, cur)\n", + snd_una, snd_nxt, tsd.get_seg_ack()); + inc_tcp_discards(); + normalizer->trim_win_payload(tsd); + good_ack = false; + } + + return good_ack; +} + +bool TcpTracker::update_on_rst_recv(TcpSegmentDescriptor& tsd) +{ + bool good_rst = true; + + normalizer->trim_rst_payload(tsd); + if ( normalizer->validate_rst(tsd) ) + { + Flow* flow = tsd.get_flow(); + + DebugMessage(DEBUG_STREAM_STATE, "Received Valid RST, bailing\n"); + flow->set_session_flags(SSNFLAG_RESET); + if ( normalizer->is_tcp_ips_enabled() ) + tcp_state = TcpStreamTracker::TCP_CLOSED; + } + else + { + DebugMessage(DEBUG_STREAM_STATE, "Received RST with bad sequence number, bailing\n"); + inc_tcp_discards(); + normalizer->packet_dropper(tsd, NORM_TCP_BLOCK); + good_rst = false; + } + + return good_rst; +} + +void TcpTracker::update_on_rst_sent(void) +{ + tcp_state = TcpStreamTracker::TCP_CLOSED; + s_mgr.sub_state |= SUB_RST_SENT; +} + +#ifdef S5_PEDANTIC +// From RFC 793: +// +// Segment Receive Test +// Length Window +// ------- ------- ------------------------------------------- +// +// 0 0 SEG.SEQ = RCV.NXT +// +// 0 >0 RCV.NXT =< SEG.SEQ < RCV.NXT+RCV.WND +// +// >0 0 not acceptable +// +// >0 >0 RCV.NXT =< SEG.SEQ < RCV.NXT+RCV.WND +// or RCV.NXT =< SEG.SEQ+SEG.LEN-1 < RCV.NXT+RCV.WND +// +bool ValidSeq(const Packet* p, Flow* flow, TcpTracker* st, TcpSegmentDescriptor& tsd) +{ + uint32_t win = normalizer->get_stream_window(flow, st, tsd); + + if ( !p->dsize ) + { + if ( !win ) + { + return ( tsd.get_seg_seq() == r_win_base ); + } + return SEQ_LEQ(r_win_base, tsd.get_seg_seq()) && + SEQ_LT(tsd.get_seg_seq(), r_win_base+win); + } + if ( !win ) + return 0; + + if ( SEQ_LEQ(r_win_base, tsd.get_seg_seq()) && + SEQ_LT(tsd.get_seg_seq(), r_win_base+win) ) + return 1; + + return SEQ_LEQ(r_win_base, tsd.get_end_seq()) && + SEQ_LT(tsd.get_end_seq(), r_win_base+win); +} + +#endif + +bool TcpTracker::is_segment_seq_valid(TcpSegmentDescriptor& tsd) +{ + bool valid_seq = true; + + /* check for valid seqeuence/retrans */ + if ( tcp_state >= TcpStreamTracker::TCP_ESTABLISHED ) + { + //and + //and !ValidSeq(listener, tsd)) + int right_ok; + uint32_t left_seq; + + DebugFormat(DEBUG_STREAM_STATE, + "Checking end_seq (%X) > r_win_base (%X) && seq (%X) < r_nxt_ack(%X)\n", + tsd.get_end_seq(), r_win_base, tsd.get_seg_seq(), r_nxt_ack + + normalizer->get_stream_window(tsd)); + + if ( SEQ_LT(r_nxt_ack, r_win_base) ) + left_seq = r_nxt_ack; + else + left_seq = r_win_base; + + if ( tsd.get_seg_len() ) + right_ok = SEQ_GT(tsd.get_end_seq(), left_seq); + else + right_ok = SEQ_GEQ(tsd.get_end_seq(), left_seq); + + if ( right_ok ) + { + uint32_t win = normalizer->get_stream_window(tsd); + + if ( SEQ_LEQ(tsd.get_seg_seq(), r_win_base + win) ) + { + DebugMessage(DEBUG_STREAM_STATE, "seq is within window!\n"); + } + else + { + DebugMessage(DEBUG_STREAM_STATE, "seq is past the end of the window!\n"); + valid_seq = false; + } + } + else + { + DebugMessage(DEBUG_STREAM_STATE, "end_seq is before win_base\n"); + valid_seq = false; + } + } + + if ( !valid_seq ) + { + inc_tcp_discards(); + normalizer->trim_win_payload(tsd); + } + + return valid_seq; +} + void TcpTracker::print(void) { LogMessage(" + TcpTracker +\n"); diff --git a/src/stream/tcp/tcp_tracker.h b/src/stream/tcp/tcp_tracker.h index 7813e5b7f..b44227c36 100644 --- a/src/stream/tcp/tcp_tracker.h +++ b/src/stream/tcp/tcp_tracker.h @@ -29,7 +29,7 @@ struct StateMgr { uint8_t sub_state; - enum TcpStreamTracker::TcpStates state_queue; + enum TcpStreamTracker::TcpState state_queue; uint8_t expected_flags; uint32_t transition_seq; uint32_t stq_get_seq; @@ -79,6 +79,7 @@ class TcpTracker : public TcpStreamTracker public: TcpTracker(bool); virtual ~TcpTracker(void); + void init_tracker(void); void print(void); void init_flush_policy(void); @@ -93,26 +94,29 @@ public: void init_on_3whs_ack_recv(TcpSegmentDescriptor& tsd); void init_on_data_seg_sent(TcpSegmentDescriptor& tsd); void init_on_data_seg_recv(TcpSegmentDescriptor& tsd); - + void finish_server_init(TcpSegmentDescriptor& tsd); + void finish_client_init(TcpSegmentDescriptor& tsd); + + void update_tracker_ack_recv(TcpSegmentDescriptor& tsd); + void update_tracker_ack_sent(TcpSegmentDescriptor& tsd); + bool update_on_3whs_ack(TcpSegmentDescriptor& tsd); + bool update_on_rst_recv(TcpSegmentDescriptor& tsd); + void update_on_rst_sent(void); + + bool is_segment_seq_valid(TcpSegmentDescriptor& tsd); + + StreamSplitter* splitter = nullptr; + TcpNormalizer* normalizer = nullptr; + TcpReassembler* reassembler = nullptr; + uint32_t small_seg_count = 0; + uint8_t alert_count = 0; + StreamAlertInfo alerts[MAX_SESSION_ALERTS]; StateMgr s_mgr; /* state tracking goodies */ - + FlushPolicy flush_policy = STREAM_FLPOLICY_IGNORE; // this is intended to be private to paf but is included // directly to avoid the need for allocation; do not directly // manipulate within this module. PAF_State paf_state; // for tracking protocol aware flushing - FlushPolicy flush_policy; - StreamSplitter* splitter; - TcpNormalizer* normalizer; - TcpReassembler* reassembler; - - uint32_t r_nxt_ack; /* next expected ack from remote side */ - uint32_t r_win_base; /* remote side window base sequence number - * (i.e. the last ack we got) */ - - uint32_t small_seg_count; - - uint8_t alert_count; /* number alerts stored (up to MAX_SESSION_ALERTS) */ - StreamAlertInfo alerts[MAX_SESSION_ALERTS]; /* history of alerts */ }; #endif