From: Russ Combs (rucombs) Date: Thu, 7 Jan 2016 21:19:51 +0000 (-0500) Subject: Merge pull request #192 in SNORT/snort3 from tcp_session_rewrite to master X-Git-Tag: 3.0.0-233~670 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=4cef8a6df08b69cca202b8124be449e468b30d03;p=thirdparty%2Fsnort3.git Merge pull request #192 in SNORT/snort3 from tcp_session_rewrite to master Squashed commit of the following: commit 68ead9daa9a035d13c934046f67e33e04430eba0 Author: davis mcpherson Date: Thu Jan 7 16:12:20 2016 -0500 delete random scripts commit b69195f273f93d2cafcef0011d899f137e6ed4ea Author: davis mcpherson Date: Thu Jan 7 15:55:03 2016 -0500 uncrustify stream tcp source code commit 403a52c3cf7f33bef448e755aebfc050399eb77f Author: davis mcpherson Date: Wed Oct 21 20:10:38 2015 -0400 refactor tcp session functions into the TcpSession class revert paf.cc to be linked into libstream, delete tcpssn object ref from call to SetPacketHeaderFoo (it is a member func of TcpSession refactor flush functions to reduce duplicate code tcp state machine and state handler updates to support handler registration with state machine rename state handler files to follow more logical convention move TcpTracker to its own file, instantiate tcp state machine and handlers pass tsd as ref, initial refactoring to split funcs that do client & server tracker work refactoring of tcp session init functions ecn was being initialized twice, back to 0 after set in session from packet switch to do server side processing first make event logger real class, refactoring to continue down road to tcp sm complete move of tcp session init to state machine, add default state handlers for all states init direction on data seg rcvd with no session some tweaks from reg testing continue refactoring ProcessTcp into functions for related code blocks refactor ignored session and data on syn processing to functions add direction as parameter to method for caching the mac address getter for tcp segment length fixed to return length from Packet rename TcpSegment class to TcpSegmentNode --- diff --git a/src/protocols/tcp.h b/src/protocols/tcp.h index 17a18051d..50b0bae33 100644 --- a/src/protocols/tcp.h +++ b/src/protocols/tcp.h @@ -128,6 +128,9 @@ struct TCPHdr inline bool is_ack() const { return (th_flags & TH_ACK); } + inline bool is_psh() const + { return (th_flags & TH_PUSH); } + inline bool is_rst() const { return (th_flags & TH_RST); } diff --git a/src/stream/libtcp/stream_tcp_unit_test.cc b/src/stream/libtcp/stream_tcp_unit_test.cc index 7c5faf4e2..5dbd6109e 100644 --- a/src/stream/libtcp/stream_tcp_unit_test.cc +++ b/src/stream/libtcp/stream_tcp_unit_test.cc @@ -30,108 +30,122 @@ #include "stream_tcp_unit_test.h" // SYN PACKET -// IP 192.168.0.89.9012 > p3nlh044.shr.prod.phx3.secureserver.net.http: Flags [S], seq 9050, win 8192, length 0 - uint8_t cooked_syn[] = "\x00\x21\x91\x01\xb2\x48\xaa\x00\x04\x00\x0a\x04\x08\x00\x45\x00\x00\x28\x00\x01\x00\x00\x40\x06\x88\x96\xc0\xa8\x00\x59\x48\xa7\xe8\x90\x23\x34\x00\x50\x00\x00\x23\x5a\x00\x00\x00\x00\x50\x02\x20\x00\x56\xcb\x00\x00"; +// IP 192.168.0.89.9012 > p3nlh044.shr.prod.phx3.secureserver.net.http: Flags [S], seq 9050, win +// 8192, length 0 +uint8_t cooked_syn[] = + "\x00\x21\x91\x01\xb2\x48\xaa\x00\x04\x00\x0a\x04\x08\x00\x45\x00\x00\x28\x00\x01\x00\x00\x40\x06\x88\x96\xc0\xa8\x00\x59\x48\xa7\xe8\x90\x23\x34\x00\x50\x00\x00\x23\x5a\x00\x00\x00\x00\x50\x02\x20\x00\x56\xcb\x00\x00"; // SYN-ACK PACKET -// IP p3nlh044.shr.prod.phx3.secureserver.net.http > 192.168.0.89.9012: Flags [S.], seq 9025, ack 9051, win 8192, length 0 - uint8_t cooked_syn_ack[] = "\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x08\x00\x45\x00\x00\x28\x00\x01\x00\x00\x40\x06\x88\x96\x48\xa7\xe8\x90\xc0\xa8\x00\x59\x00\x50\x23\x34\x00\x00\x23\x41\x00\x00\x23\x5b\x50\x12\x20\x00\x33\x79\x00\x00"; +// IP p3nlh044.shr.prod.phx3.secureserver.net.http > 192.168.0.89.9012: Flags [S.], seq 9025, ack +// 9051, win 8192, length 0 +uint8_t cooked_syn_ack[] = + "\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x08\x00\x45\x00\x00\x28\x00\x01\x00\x00\x40\x06\x88\x96\x48\xa7\xe8\x90\xc0\xa8\x00\x59\x00\x50\x23\x34\x00\x00\x23\x41\x00\x00\x23\x5b\x50\x12\x20\x00\x33\x79\x00\x00"; // ACK PACKET -// IP 192.168.0.89.9012 > p3nlh044.shr.prod.phx3.secureserver.net.http: Flags [.], ack 1, win 8192, length 0 - uint8_t cooked_ack[] = "\x00\x21\x91\x01\xb2\x48\xaa\x00\x04\x00\x0a\x04\x08\x00\x45\x00\x00\x28\x00\x01\x00\x00\x40\x06\x88\x96\xc0\xa8\x00\x59\x48\xa7\xe8\x90\x23\x34\x00\x50\x00\x00\x23\x5b\x00\x00\x23\x42\x50\x10\x20\x00\x33\x7a\x00\x00"; +// IP 192.168.0.89.9012 > p3nlh044.shr.prod.phx3.secureserver.net.http: Flags [.], ack 1, win 8192, +// length 0 +uint8_t cooked_ack[] = + "\x00\x21\x91\x01\xb2\x48\xaa\x00\x04\x00\x0a\x04\x08\x00\x45\x00\x00\x28\x00\x01\x00\x00\x40\x06\x88\x96\xc0\xa8\x00\x59\x48\xa7\xe8\x90\x23\x34\x00\x50\x00\x00\x23\x5b\x00\x00\x23\x42\x50\x10\x20\x00\x33\x7a\x00\x00"; // FIXIT - this is not a FIN PACKET yet... -// IP 192.168.0.89.9012 > p3nlh044.shr.prod.phx3.secureserver.net.http: Flags [.], ack 1, win 8192, length 0 - uint8_t cooked_fin[] = "\x00\x21\x91\x01\xb2\x48\xaa\x00\x04\x00\x0a\x04\x08\x00\x45\x00\x00\x28\x00\x01\x00\x00\x40\x06\x88\x96\xc0\xa8\x00\x59\x48\xa7\xe8\x90\x23\x34\x00\x50\x00\x00\x23\x5b\x00\x00\x23\x42\x50\x10\x20\x00\x33\x7a\x00\x00"; +// IP 192.168.0.89.9012 > p3nlh044.shr.prod.phx3.secureserver.net.http: Flags [.], ack 1, win 8192, +// length 0 +uint8_t cooked_fin[] = + "\x00\x21\x91\x01\xb2\x48\xaa\x00\x04\x00\x0a\x04\x08\x00\x45\x00\x00\x28\x00\x01\x00\x00\x40\x06\x88\x96\xc0\xa8\x00\x59\x48\xa7\xe8\x90\x23\x34\x00\x50\x00\x00\x23\x5b\x00\x00\x23\x42\x50\x10\x20\x00\x33\x7a\x00\x00"; // FIXIT - this is not a RST PACKET yet... -// IP 192.168.0.89.9012 > p3nlh044.shr.prod.phx3.secureserver.net.http: Flags [.], ack 1, win 8192, length 0 - uint8_t cooked_rst[] = "\x00\x21\x91\x01\xb2\x48\xaa\x00\x04\x00\x0a\x04\x08\x00\x45\x00\x00\x28\x00\x01\x00\x00\x40\x06\x88\x96\xc0\xa8\x00\x59\x48\xa7\xe8\x90\x23\x34\x00\x50\x00\x00\x23\x5b\x00\x00\x23\x42\x50\x10\x20\x00\x33\x7a\x00\x00"; +// IP 192.168.0.89.9012 > p3nlh044.shr.prod.phx3.secureserver.net.http: Flags [.], ack 1, win 8192, +// length 0 +uint8_t cooked_rst[] = + "\x00\x21\x91\x01\xb2\x48\xaa\x00\x04\x00\x0a\x04\x08\x00\x45\x00\x00\x28\x00\x01\x00\x00\x40\x06\x88\x96\xc0\xa8\x00\x59\x48\xa7\xe8\x90\x23\x34\x00\x50\x00\x00\x23\x5b\x00\x00\x23\x42\x50\x10\x20\x00\x33\x7a\x00\x00"; // DATA PACKET -// IP 192.168.0.89.9012 > p3nlh044.shr.prod.phx3.secureserver.net.http: Flags [P.], seq 1:43, ack 1, win 8192, length 42 - uint8_t cooked_data[] = "\x00\x21\x91\x01\xb2\x48\xaa\x00\x04\x00\x0a\x04\x08\x00\x45\x00\x00\x52\x00\x01\x00\x00\x40\x06\x88\x6c\xc0\xa8\x00\x59\x48\xa7\xe8\x90\x23\x34\x00\x50\x00\x00\x23\x5b\x00\x00\x23\x42\x50\x18\x20\x00\x14\x83\x00\x00\x47\x45\x54\x20\x2f\x20\x48\x54\x54\x50\x2f\x31\x2e\x31\x0d\x0a\x48\x6f\x73\x74\x3a\x20\x77\x77\x77\x2e\x6d\x61\x6c\x66\x6f\x72\x67\x65\x2e\x63\x6f\x6d\x0d\x0a\x0d\x0a"; +// IP 192.168.0.89.9012 > p3nlh044.shr.prod.phx3.secureserver.net.http: Flags [P.], seq 1:43, ack +// 1, win 8192, length 42 +uint8_t cooked_data[] = + "\x00\x21\x91\x01\xb2\x48\xaa\x00\x04\x00\x0a\x04\x08\x00\x45\x00\x00\x52\x00\x01\x00\x00\x40\x06\x88\x6c\xc0\xa8\x00\x59\x48\xa7\xe8\x90\x23\x34\x00\x50\x00\x00\x23\x5b\x00\x00\x23\x42\x50\x18\x20\x00\x14\x83\x00\x00\x47\x45\x54\x20\x2f\x20\x48\x54\x54\x50\x2f\x31\x2e\x31\x0d\x0a\x48\x6f\x73\x74\x3a\x20\x77\x77\x77\x2e\x6d\x61\x6c\x66\x6f\x72\x67\x65\x2e\x63\x6f\x6d\x0d\x0a\x0d\x0a"; DAQ_PktHdr_t daqHdr; static DAQ_PktHdr_t* initDaqHdr( ) { - gettimeofday( &daqHdr.ts, NULL ); + gettimeofday(&daqHdr.ts, NULL); return &daqHdr; } -static Packet* init_packet( Flow* flow, uint32_t talker ) +static Packet* init_packet(Flow* flow, uint32_t talker) { Packet* pkt = new Packet; pkt->flow = flow; pkt->packet_flags = talker; + pkt->proto_bits &= ~PROTO_BIT__ETH; pkt->pkth = initDaqHdr(); pkt->dsize = 0; return pkt; } -Packet* get_syn_packet( Flow* flow ) +Packet* get_syn_packet(Flow* flow) { - Packet* pkt = init_packet( flow, PKT_FROM_CLIENT ); + Packet* pkt = init_packet(flow, PKT_FROM_CLIENT); - pkt->pkt = cooked_syn; - pkt->ptrs.tcph = ( tcp::TCPHdr * ) ( cooked_syn + 34 ); + pkt->pkt = cooked_syn; + pkt->ptrs.tcph = ( tcp::TCPHdr* )( cooked_syn + 34 ); - return pkt; + return pkt; } -Packet* get_syn_ack_packet( Flow* flow ) +Packet* get_syn_ack_packet(Flow* flow) { - Packet* pkt = init_packet( flow, PKT_FROM_SERVER ); + Packet* pkt = init_packet(flow, PKT_FROM_SERVER); - pkt->pkt = cooked_syn_ack; - pkt->ptrs.tcph = ( tcp::TCPHdr * ) ( cooked_syn_ack + 34 ); + pkt->pkt = cooked_syn_ack; + pkt->ptrs.tcph = ( tcp::TCPHdr* )( cooked_syn_ack + 34 ); - return pkt; + return pkt; } -Packet *get_ack_packet( Flow* flow ) +Packet* get_ack_packet(Flow* flow) { - Packet* pkt = init_packet( flow, PKT_FROM_CLIENT ); + Packet* pkt = init_packet(flow, PKT_FROM_CLIENT); - pkt->pkt = cooked_ack; - pkt->ptrs.tcph = ( tcp::TCPHdr * ) ( cooked_ack + 34 ); + pkt->pkt = cooked_ack; + pkt->ptrs.tcph = ( tcp::TCPHdr* )( cooked_ack + 34 ); - return pkt; + return pkt; } -Packet *get_fin_packet( Flow* flow ) +Packet* get_fin_packet(Flow* flow) { - Packet* pkt = init_packet( flow, PKT_FROM_CLIENT ); + Packet* pkt = init_packet(flow, PKT_FROM_CLIENT); - pkt->pkt = cooked_fin; - pkt->ptrs.tcph = ( tcp::TCPHdr * ) ( cooked_fin + 34 ); + pkt->pkt = cooked_fin; + pkt->ptrs.tcph = ( tcp::TCPHdr* )( cooked_fin + 34 ); - return pkt; + return pkt; } -Packet *get_rst_packet( Flow* flow ) +Packet* get_rst_packet(Flow* flow) { - Packet* pkt = init_packet( flow, PKT_FROM_CLIENT ); + Packet* pkt = init_packet(flow, PKT_FROM_CLIENT); - pkt->pkt = cooked_rst; - pkt->ptrs.tcph = ( tcp::TCPHdr * ) ( cooked_rst + 34 ); + pkt->pkt = cooked_rst; + pkt->ptrs.tcph = ( tcp::TCPHdr* )( cooked_rst + 34 ); - return pkt; + return pkt; } -Packet *get_data_packet( Flow* flow ) +Packet* get_data_packet(Flow* flow) { - Packet* pkt = init_packet( flow, PKT_FROM_CLIENT ); + Packet* pkt = init_packet(flow, PKT_FROM_CLIENT); - pkt->pkt = cooked_data; - pkt->ptrs.tcph = ( tcp::TCPHdr * ) ( cooked_data + 34 ); - pkt->dsize = 42; + pkt->pkt = cooked_data; + pkt->ptrs.tcph = ( tcp::TCPHdr* )( cooked_data + 34 ); + pkt->dsize = 42; - return pkt; + return pkt; } + #endif diff --git a/src/stream/libtcp/stream_tcp_unit_test.h b/src/stream/libtcp/stream_tcp_unit_test.h index 11a0cffa1..e6daacd86 100644 --- a/src/stream/libtcp/stream_tcp_unit_test.h +++ b/src/stream/libtcp/stream_tcp_unit_test.h @@ -26,12 +26,12 @@ #include "protocols/packet.h" -Packet *get_syn_packet( Flow* ); -Packet *get_syn_ack_packet( Flow* ); -Packet *get_ack_packet( Flow* ); -Packet *get_fin_packet( Flow* ); -Packet *get_rst_packet( Flow* ); -Packet *get_data_packet( Flow* ); +Packet* get_syn_packet(Flow*); +Packet* get_syn_ack_packet(Flow*); +Packet* get_ack_packet(Flow*); +Packet* get_fin_packet(Flow*); +Packet* get_rst_packet(Flow*); +Packet* get_data_packet(Flow*); #endif diff --git a/src/stream/libtcp/tcp_segment_descriptor.cc b/src/stream/libtcp/tcp_segment_descriptor.cc index 18ab91a5c..93f19f65c 100644 --- a/src/stream/libtcp/tcp_segment_descriptor.cc +++ b/src/stream/libtcp/tcp_segment_descriptor.cc @@ -16,26 +16,41 @@ // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. //-------------------------------------------------------------------------- -// tcp_segment_descriptor.cc author davis mcpherson +// tcp_segment_descriptor.cc author davis mcpherson // Created on: Jul 30, 2015 +#include "main/snort_debug.h" + +#include "stream/tcp/tcp_defs.h" +#include "protocols/tcp_options.h" +#include "stream/tcp/tcp_event_logger.h" #include "tcp_segment_descriptor.h" -TcpSegmentDescriptor::TcpSegmentDescriptor( Flow* flow, Packet* pkt ) : - flow( flow ), pkt( pkt ) -{ - direction = flow->ssn_state.direction; +using namespace tcp; +TcpSegmentDescriptor::TcpSegmentDescriptor(Flow* flow, Packet* pkt, TcpEventLogger* tel) : + flow(flow), pkt(pkt) +{ tcph = pkt->ptrs.tcph; - data_len = pkt->dsize; - src_port = ntohs(tcph->th_sport); - dst_port = ntohs(pkt->ptrs.tcph->th_dport); + 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; + end_seq = seq + (uint32_t)pkt->dsize; ts = 0; + + // don't bump end_seq for fin here we will bump if/when fin is processed + if ( tcph->is_syn() ) + { + end_seq++; + if ( !tcph->is_ack() ) + tel->set_tcp_internal_syn_event( ); + } + + #ifdef DEBUG_STREAM_EX + print_tsd( ); + #endif } TcpSegmentDescriptor::~TcpSegmentDescriptor() @@ -43,3 +58,76 @@ TcpSegmentDescriptor::~TcpSegmentDescriptor() // TODO Auto-generated destructor stub } +uint32_t TcpSegmentDescriptor::init_mss(uint16_t* value) +{ + DebugMessage(DEBUG_STREAM_STATE, "Getting MSS...\n"); + + TcpOptIterator iter(tcph, pkt); + for ( const TcpOption& opt : iter ) + { + if ( opt.code == TcpOptCode::MAXSEG ) + { + *value = EXTRACT_16BITS(opt.data); + DebugFormat(DEBUG_STREAM_STATE, "Found MSS %u\n", *value); + return TF_MSS; + } + } + + *value = 0; + + DebugMessage(DEBUG_STREAM_STATE, "No MSS...\n"); + + return TF_NONE; +} + +uint32_t TcpSegmentDescriptor::init_wscale(uint16_t* value) +{ + DebugMessage(DEBUG_STREAM_STATE, "Getting wscale...\n"); + + TcpOptIterator iter(tcph, pkt); + + // using const because non-const is not supported + for (const TcpOption& opt : iter) + { + if (opt.code == TcpOptCode::WSCALE) + { + *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 (*value > 14) + *value = 14; + + return TF_WSCALE; + } + } + + *value = 0; + DebugMessage(DEBUG_STREAM_STATE, "No wscale...\n"); + + return TF_NONE; +} + +uint32_t TcpSegmentDescriptor::has_wscale(void) +{ + uint16_t wscale; + + DebugMessage(DEBUG_STREAM_STATE, "Checking for wscale...\n"); + + return init_wscale(&wscale); +} + +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(" 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 365726fcb..71ae7ef72 100644 --- a/src/stream/libtcp/tcp_segment_descriptor.h +++ b/src/stream/libtcp/tcp_segment_descriptor.h @@ -26,49 +26,76 @@ #include "protocols/tcp.h" #include "protocols/packet.h" +#include "stream/tcp/tcp_event_logger.h" + class TcpSegmentDescriptor { public: - TcpSegmentDescriptor( Flow*, Packet* ); + TcpSegmentDescriptor(Flow*, Packet*, TcpEventLogger*); virtual ~TcpSegmentDescriptor(); - const Flow* get_flow() const + uint32_t init_mss(uint16_t* value); + uint32_t init_wscale(uint16_t* value); + uint32_t has_wscale(void); + + Flow* get_flow() const { return flow; } - const Packet* get_pkt() const + Packet* get_pkt() const { return pkt; } + const tcp::TCPHdr* get_tcph() const { return tcph; } + void set_seq(uint32_t seq) + { + this->seq = seq; + } + + uint32_t get_seq() const + { + return seq; + } + uint32_t get_ack() const { return ack; } + void set_end_seq(uint32_t end_seq) + { + this->end_seq = end_seq; + } + uint32_t get_end_seq() const { return end_seq; } - uint32_t get_seq() const + void set_ts(uint32_t ts) { - return seq; + this->ts = ts; } uint32_t get_ts() const { - return ts; + return ts; + } + + void set_win(uint32_t win) + { + this->win = win; } - uint16_t get_win() const + uint32_t get_win() const { - return win; + return win; } uint16_t get_dst_port() const @@ -83,39 +110,29 @@ public: uint8_t get_direction() const { - return direction; - } - - void set_direction(uint8_t direction) - { - this->direction = direction; + return flow->ssn_state.direction; } uint32_t get_data_len() const { - return data_len; + return pkt->dsize; } - void set_data_len(uint32_t data_len) - { - this->data_len = data_len; - } + void print_tsd(void); private: - Flow* flow; + Flow* flow; Packet* pkt; - uint8_t direction; - const tcp::TCPHdr* tcph; - uint32_t data_len; uint16_t src_port; uint16_t dst_port; uint32_t seq; uint32_t ack; - uint16_t win; + uint32_t win; uint32_t end_seq; uint32_t ts; }; #endif + diff --git a/src/stream/libtcp/tcp_state_handler.cc b/src/stream/libtcp/tcp_state_handler.cc index 10b854842..a7b18aace 100644 --- a/src/stream/libtcp/tcp_state_handler.cc +++ b/src/stream/libtcp/tcp_state_handler.cc @@ -22,349 +22,358 @@ #include using namespace std; -#include "tcp_state_handler.h" - #include "main/snort_debug.h" +#include "tcp_state_machine.h" +#include "tcp_state_handler.h" + #ifdef UNIT_TEST #include "catch/catch.hpp" #include "stream_tcp_unit_test.h" #endif - -TcpStateHandler::TcpStateHandler() : - tcp_event( TcpStreamTracker::TCP_MAX_EVENTS ) +TcpStateHandler::TcpStateHandler(TcpStreamTracker::TcpStates state, TcpStateMachine& tsm) : + tsm(&tsm), tcp_state(state), tcp_event(TcpStreamTracker::TCP_MAX_EVENTS) { - // TODO Auto-generated constructor stub + tsm.register_state_handler(state, *this); +} +TcpStateHandler::TcpStateHandler(void) : + tsm(nullptr), tcp_state(TcpStreamTracker::TCP_CLOSED), + tcp_event(TcpStreamTracker::TCP_MAX_EVENTS) +{ } TcpStateHandler::~TcpStateHandler() { // TODO Auto-generated destructor stub - } -void TcpStateHandler::eval( TcpSegmentDescriptor &tcp_seg, TcpStreamTracker &tracker ) +bool TcpStateHandler::eval(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - switch( tcp_event = tracker.get_tcp_event() ) + bool handled = false; + + switch ( tcp_event = tracker.get_tcp_event() ) { case TcpStreamTracker::TCP_SYN_SENT_EVENT: - syn_sent( tcp_seg, tracker ); + handled = syn_sent(tsd, tracker); break; case TcpStreamTracker::TCP_SYN_RECV_EVENT: - syn_recv( tcp_seg, tracker ); + handled = syn_recv(tsd, tracker); break; case TcpStreamTracker::TCP_SYN_ACK_SENT_EVENT: - syn_ack_sent( tcp_seg, tracker ); + handled = syn_ack_sent(tsd, tracker); break; case TcpStreamTracker::TCP_SYN_ACK_RECV_EVENT: - syn_ack_recv( tcp_seg, tracker ); + handled = syn_ack_recv(tsd, tracker); break; case TcpStreamTracker::TCP_ACK_SENT_EVENT: - ack_sent( tcp_seg, tracker ); + handled = ack_sent(tsd, tracker); break; case TcpStreamTracker::TCP_ACK_RECV_EVENT: - ack_recv( tcp_seg, tracker ); + handled = ack_recv(tsd, tracker); break; case TcpStreamTracker::TCP_DATA_SEG_SENT_EVENT: - data_seg_sent( tcp_seg, tracker ); + handled = data_seg_sent(tsd, tracker); break; case TcpStreamTracker::TCP_DATA_SEG_RECV_EVENT: - data_seg_recv( tcp_seg, tracker ); + handled = data_seg_recv(tsd, tracker); break; case TcpStreamTracker::TCP_FIN_SENT_EVENT: - fin_sent( tcp_seg, tracker ); + handled = fin_sent(tsd, tracker); break; case TcpStreamTracker::TCP_FIN_RECV_EVENT: - fin_recv( tcp_seg, tracker ); + handled = fin_recv(tsd, tracker); break; case TcpStreamTracker::TCP_RST_SENT_EVENT: - rst_sent( tcp_seg, tracker ); + handled = rst_sent(tsd, tracker); break; case TcpStreamTracker::TCP_RST_RECV_EVENT: - rst_recv( tcp_seg, tracker ); + handled = rst_recv(tsd, tracker); break; case TcpStreamTracker::TCP_MAX_EVENTS: default: cout << "Invalid Tcp Event " << tracker.get_tcp_event() << endl; break; - } + + return handled; } -void TcpStateHandler::default_state_action( - TcpSegmentDescriptor* tcp_seg, TcpStreamTracker* tracker, const char* func_name ) +bool TcpStateHandler::default_state_action( + TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker, const char* func_name) { #ifdef DEBUG_MSGS - DebugFormat(DEBUG_STREAM_STATE, "Default Implementation of: %s tcp_seg: %p tracker: %p\n", - func_name, tcp_seg, tracker ); + DebugFormat(DEBUG_STREAM_STATE, "Default Implementation of: %s tsd: %p tracker: %p\n", + func_name, &tsd, &tracker); #else - UNUSED(tcp_seg); + UNUSED(tsd); UNUSED(func_name); #endif - tcp_event = tracker->get_tcp_event(); + tcp_event = tracker.get_tcp_event(); + return false; } -void TcpStateHandler::syn_sent( TcpSegmentDescriptor &tcp_seg, TcpStreamTracker &tracker ) +bool TcpStateHandler::syn_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - default_state_action( &tcp_seg, &tracker, __func__ ); + return default_state_action(tsd, tracker, __func__); } -void TcpStateHandler::syn_recv(TcpSegmentDescriptor &tcp_seg, TcpStreamTracker &tracker) +bool TcpStateHandler::syn_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - default_state_action( &tcp_seg, &tracker, __func__ ); + return default_state_action(tsd, tracker, __func__); } -void TcpStateHandler::syn_ack_sent(TcpSegmentDescriptor &tcp_seg, TcpStreamTracker &tracker) +bool TcpStateHandler::syn_ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - default_state_action( &tcp_seg, &tracker, __func__ ); + return default_state_action(tsd, tracker, __func__); } -void TcpStateHandler::syn_ack_recv(TcpSegmentDescriptor &tcp_seg, TcpStreamTracker &tracker) +bool TcpStateHandler::syn_ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - default_state_action( &tcp_seg, &tracker, __func__ ); + return default_state_action(tsd, tracker, __func__); } -void TcpStateHandler::ack_sent(TcpSegmentDescriptor &tcp_seg, TcpStreamTracker &tracker) +bool TcpStateHandler::ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - default_state_action( &tcp_seg, &tracker, __func__ ); + return default_state_action(tsd, tracker, __func__); } -void TcpStateHandler::ack_recv(TcpSegmentDescriptor &tcp_seg, TcpStreamTracker &tracker) +bool TcpStateHandler::ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - default_state_action( &tcp_seg, &tracker, __func__ ); + return default_state_action(tsd, tracker, __func__); } -void TcpStateHandler::data_seg_sent(TcpSegmentDescriptor &tcp_seg, TcpStreamTracker &tracker) +bool TcpStateHandler::data_seg_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - default_state_action( &tcp_seg, &tracker, __func__ ); + return default_state_action(tsd, tracker, __func__); } -void TcpStateHandler::data_seg_recv(TcpSegmentDescriptor &tcp_seg, TcpStreamTracker &tracker) +bool TcpStateHandler::data_seg_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - default_state_action( &tcp_seg, &tracker, __func__ ); + return default_state_action(tsd, tracker, __func__); } -void TcpStateHandler::fin_sent(TcpSegmentDescriptor &tcp_seg, TcpStreamTracker &tracker) +bool TcpStateHandler::fin_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - default_state_action( &tcp_seg, &tracker, __func__ ); + return default_state_action(tsd, tracker, __func__); } -void TcpStateHandler::fin_recv(TcpSegmentDescriptor &tcp_seg, TcpStreamTracker &tracker) +bool TcpStateHandler::fin_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - default_state_action( &tcp_seg, &tracker, __func__ ); + return default_state_action(tsd, tracker, __func__); } -void TcpStateHandler::rst_sent(TcpSegmentDescriptor &tcp_seg, TcpStreamTracker &tracker) +bool TcpStateHandler::rst_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - default_state_action( &tcp_seg, &tracker, __func__ ); + return default_state_action(tsd, tracker, __func__); } -void TcpStateHandler::rst_recv(TcpSegmentDescriptor &tcp_seg, TcpStreamTracker &tracker) +bool TcpStateHandler::rst_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - default_state_action( &tcp_seg, &tracker, __func__ ); + return default_state_action(tsd, tracker, __func__); } #ifdef UNIT_TEST SCENARIO("TCP State Handler Base Class", "[state_handlers][stream_tcp]") { - // initialization code here - Flow* flow = new Flow; - TcpStateHandler* tsh = new TcpStateHandler; - TcpStreamTracker* client_tracker = new TcpStreamTracker( true ); - TcpStreamTracker* server_tracker = new TcpStreamTracker( false ); - - GIVEN("a SYN Packet") - { - Packet* pkt = get_syn_packet( flow ); - REQUIRE( ( pkt != nullptr ) ); - - WHEN("SYN is sent") - { - TcpSegmentDescriptor* tcp_seg = new TcpSegmentDescriptor( flow, pkt ); - REQUIRE( ( tcp_seg != nullptr ) ); - client_tracker->set_tcp_event( TcpStreamTracker::TCP_SYN_SENT_EVENT ); - tsh->eval( *tcp_seg, *client_tracker ); - THEN("Event should be TCP_SYN_SENT_EVENT") - { - CHECK( ( tsh->get_tcp_event() == client_tracker->get_tcp_event() ) ); - } - delete tcp_seg; - } - - SECTION("SYN is received") - { - TcpSegmentDescriptor* tcp_seg = new TcpSegmentDescriptor( flow, pkt ); - REQUIRE( ( tcp_seg != nullptr ) ); - server_tracker->set_tcp_event( TcpStreamTracker::TCP_SYN_RECV_EVENT ); - tsh->eval( *tcp_seg, *server_tracker ); - CHECK( ( tsh->get_tcp_event() == server_tracker->get_tcp_event() ) ); - delete tcp_seg; - } - - delete pkt; - } - - SECTION("syn_ack_packet") - { - Packet* pkt = get_syn_ack_packet( flow ); - REQUIRE( ( pkt != nullptr ) ); - - SECTION("syn_ack_sent") - { - TcpSegmentDescriptor* tcp_seg = new TcpSegmentDescriptor( flow, pkt ); - REQUIRE( ( tcp_seg != nullptr ) ); - client_tracker->set_tcp_event( TcpStreamTracker::TCP_SYN_ACK_SENT_EVENT ); - tsh->eval( *tcp_seg, *client_tracker ); - CHECK( ( tsh->get_tcp_event() == client_tracker->get_tcp_event() ) ); - delete tcp_seg; - } - - SECTION("syn_ack_recv") - { - TcpSegmentDescriptor* tcp_seg = new TcpSegmentDescriptor( flow, pkt ); - REQUIRE( ( tcp_seg != nullptr ) ); - server_tracker->set_tcp_event( TcpStreamTracker::TCP_SYN_ACK_RECV_EVENT ); - tsh->eval( *tcp_seg, *server_tracker ); - CHECK( ( tsh->get_tcp_event() == server_tracker->get_tcp_event() ) ); - delete tcp_seg; - } - - delete pkt; - } - - SECTION("ack_packet") - { - Packet* pkt = get_ack_packet( flow ); - REQUIRE( ( pkt != nullptr ) ); - - SECTION("ack_sent") - { - TcpSegmentDescriptor* tcp_seg = new TcpSegmentDescriptor( flow, pkt ); - REQUIRE( ( tcp_seg != nullptr ) ); - client_tracker->set_tcp_event( TcpStreamTracker::TCP_ACK_SENT_EVENT ); - tsh->eval( *tcp_seg, *client_tracker ); - CHECK( ( tsh->get_tcp_event() == client_tracker->get_tcp_event() ) ); - delete tcp_seg; - } - - SECTION("ack_recv") - { - TcpSegmentDescriptor* tcp_seg = new TcpSegmentDescriptor( flow, pkt ); - REQUIRE( ( tcp_seg != nullptr ) ); - server_tracker->set_tcp_event( TcpStreamTracker::TCP_ACK_RECV_EVENT ); - tsh->eval( *tcp_seg, *server_tracker ); - CHECK( ( tsh->get_tcp_event() == server_tracker->get_tcp_event() ) ); - delete tcp_seg; - } - - delete pkt; - } - - SECTION("data_seg_packet") - { - Packet* pkt = get_data_packet( flow ); - REQUIRE( ( pkt != nullptr ) ); - - SECTION("data_seg_sent") - { - TcpSegmentDescriptor* tcp_seg = new TcpSegmentDescriptor( flow, pkt ); - REQUIRE( ( tcp_seg != nullptr ) ); - client_tracker->set_tcp_event( TcpStreamTracker::TCP_DATA_SEG_SENT_EVENT ); - tsh->eval( *tcp_seg, *client_tracker ); - CHECK( ( tsh->get_tcp_event() == client_tracker->get_tcp_event() ) ); - delete tcp_seg; - } - - SECTION("data_seg_recv") - { - TcpSegmentDescriptor* tcp_seg = new TcpSegmentDescriptor( flow, pkt ); - REQUIRE( ( tcp_seg != nullptr ) ); - server_tracker->set_tcp_event( TcpStreamTracker::TCP_DATA_SEG_RECV_EVENT ); - tsh->eval( *tcp_seg, *server_tracker ); - CHECK( ( tsh->get_tcp_event() == server_tracker->get_tcp_event() ) ); - delete tcp_seg; - } - - delete pkt; - } - - SECTION("fin_packet") - { - Packet* pkt = get_fin_packet( flow ); - REQUIRE( ( pkt != nullptr ) ); - - SECTION("fin_sent") - { - TcpSegmentDescriptor* tcp_seg = new TcpSegmentDescriptor( flow, pkt ); - REQUIRE( ( tcp_seg != nullptr ) ); - client_tracker->set_tcp_event( TcpStreamTracker::TCP_FIN_SENT_EVENT ); - tsh->eval( *tcp_seg, *client_tracker ); - CHECK( ( tsh->get_tcp_event() == client_tracker->get_tcp_event() ) ); - delete tcp_seg; - } - - SECTION("fin_recv") - { - TcpSegmentDescriptor* tcp_seg = new TcpSegmentDescriptor( flow, pkt ); - REQUIRE( ( tcp_seg != nullptr ) ); - server_tracker->set_tcp_event( TcpStreamTracker::TCP_FIN_RECV_EVENT ); - tsh->eval( *tcp_seg, *server_tracker ); - CHECK( ( tsh->get_tcp_event() == server_tracker->get_tcp_event() ) ); - delete tcp_seg; - } - - delete pkt; - } - - SECTION("rst_packet") - { - Packet* pkt = get_rst_packet( flow ); - REQUIRE( ( pkt != nullptr ) ); - - SECTION("rst_sent") - { - TcpSegmentDescriptor* tcp_seg = new TcpSegmentDescriptor( flow, pkt ); - REQUIRE( ( tcp_seg != nullptr ) ); - client_tracker->set_tcp_event( TcpStreamTracker::TCP_RST_SENT_EVENT ); - tsh->eval( *tcp_seg, *client_tracker ); - CHECK( ( tsh->get_tcp_event() == client_tracker->get_tcp_event() ) ); - delete tcp_seg; - } - - SECTION("rst_recv") - { - TcpSegmentDescriptor* tcp_seg = new TcpSegmentDescriptor( flow, pkt ); - REQUIRE( ( tcp_seg != nullptr ) ); - server_tracker->set_tcp_event( TcpStreamTracker::TCP_RST_RECV_EVENT ); - tsh->eval( *tcp_seg, *server_tracker ); - CHECK( ( tsh->get_tcp_event() == server_tracker->get_tcp_event() ) ); - delete tcp_seg; - } - - delete pkt; - } - - delete flow; - delete tsh; - delete client_tracker; - delete server_tracker; + // initialization code here + Flow* flow = new Flow; + TcpStateHandler* tsh = new TcpStateHandler; + TcpStreamTracker* client_tracker = new TcpStreamTracker(true); + TcpStreamTracker* server_tracker = new TcpStreamTracker(false); + TcpEventLogger* tel = new TcpEventLogger; + + GIVEN("a SYN Packet") + { + Packet* pkt = get_syn_packet(flow); + REQUIRE( ( pkt != nullptr ) ); + + WHEN("SYN is sent") + { + TcpSegmentDescriptor* tsd = new TcpSegmentDescriptor(flow, pkt, tel); + REQUIRE( ( tsd != nullptr ) ); + client_tracker->set_tcp_event(TcpStreamTracker::TCP_SYN_SENT_EVENT); + tsh->eval(*tsd, *client_tracker); + THEN("Event should be TCP_SYN_SENT_EVENT") + { + CHECK( ( tsh->get_tcp_event() == client_tracker->get_tcp_event() ) ); + } + delete tsd; + } + + SECTION("SYN is received") + { + TcpSegmentDescriptor* tsd = new TcpSegmentDescriptor(flow, pkt, tel); + REQUIRE( ( tsd != nullptr ) ); + server_tracker->set_tcp_event(TcpStreamTracker::TCP_SYN_RECV_EVENT); + tsh->eval(*tsd, *server_tracker); + CHECK( ( tsh->get_tcp_event() == server_tracker->get_tcp_event() ) ); + delete tsd; + } + + delete pkt; + } + SECTION("syn_ack_packet") + { + Packet* pkt = get_syn_ack_packet(flow); + REQUIRE( ( pkt != nullptr ) ); + + SECTION("syn_ack_sent") + { + TcpSegmentDescriptor* tsd = new TcpSegmentDescriptor(flow, pkt, tel); + REQUIRE( ( tsd != nullptr ) ); + client_tracker->set_tcp_event(TcpStreamTracker::TCP_SYN_ACK_SENT_EVENT); + tsh->eval(*tsd, *client_tracker); + CHECK( ( tsh->get_tcp_event() == client_tracker->get_tcp_event() ) ); + delete tsd; + } + + SECTION("syn_ack_recv") + { + TcpSegmentDescriptor* tsd = new TcpSegmentDescriptor(flow, pkt, tel); + REQUIRE( ( tsd != nullptr ) ); + server_tracker->set_tcp_event(TcpStreamTracker::TCP_SYN_ACK_RECV_EVENT); + tsh->eval(*tsd, *server_tracker); + CHECK( ( tsh->get_tcp_event() == server_tracker->get_tcp_event() ) ); + delete tsd; + } + + delete pkt; + } + + SECTION("ack_packet") + { + Packet* pkt = get_ack_packet(flow); + REQUIRE( ( pkt != nullptr ) ); + + SECTION("ack_sent") + { + TcpSegmentDescriptor* tsd = new TcpSegmentDescriptor(flow, pkt, tel); + REQUIRE( ( tsd != nullptr ) ); + client_tracker->set_tcp_event(TcpStreamTracker::TCP_ACK_SENT_EVENT); + tsh->eval(*tsd, *client_tracker); + CHECK( ( tsh->get_tcp_event() == client_tracker->get_tcp_event() ) ); + delete tsd; + } + + SECTION("ack_recv") + { + TcpSegmentDescriptor* tsd = new TcpSegmentDescriptor(flow, pkt, tel); + REQUIRE( ( tsd != nullptr ) ); + server_tracker->set_tcp_event(TcpStreamTracker::TCP_ACK_RECV_EVENT); + tsh->eval(*tsd, *server_tracker); + CHECK( ( tsh->get_tcp_event() == server_tracker->get_tcp_event() ) ); + delete tsd; + } + + delete pkt; + } + + SECTION("data_seg_packet") + { + Packet* pkt = get_data_packet(flow); + REQUIRE( ( pkt != nullptr ) ); + + SECTION("data_seg_sent") + { + TcpSegmentDescriptor* tsd = new TcpSegmentDescriptor(flow, pkt, tel); + REQUIRE( ( tsd != nullptr ) ); + client_tracker->set_tcp_event(TcpStreamTracker::TCP_DATA_SEG_SENT_EVENT); + tsh->eval(*tsd, *client_tracker); + CHECK( ( tsh->get_tcp_event() == client_tracker->get_tcp_event() ) ); + delete tsd; + } + + SECTION("data_seg_recv") + { + TcpSegmentDescriptor* tsd = new TcpSegmentDescriptor(flow, pkt, tel); + REQUIRE( ( tsd != nullptr ) ); + server_tracker->set_tcp_event(TcpStreamTracker::TCP_DATA_SEG_RECV_EVENT); + tsh->eval(*tsd, *server_tracker); + CHECK( ( tsh->get_tcp_event() == server_tracker->get_tcp_event() ) ); + delete tsd; + } + + delete pkt; + } + + SECTION("fin_packet") + { + Packet* pkt = get_fin_packet(flow); + REQUIRE( ( pkt != nullptr ) ); + + SECTION("fin_sent") + { + TcpSegmentDescriptor* tsd = new TcpSegmentDescriptor(flow, pkt, tel); + REQUIRE( ( tsd != nullptr ) ); + client_tracker->set_tcp_event(TcpStreamTracker::TCP_FIN_SENT_EVENT); + tsh->eval(*tsd, *client_tracker); + CHECK( ( tsh->get_tcp_event() == client_tracker->get_tcp_event() ) ); + delete tsd; + } + + SECTION("fin_recv") + { + TcpSegmentDescriptor* tsd = new TcpSegmentDescriptor(flow, pkt, tel); + REQUIRE( ( tsd != nullptr ) ); + server_tracker->set_tcp_event(TcpStreamTracker::TCP_FIN_RECV_EVENT); + tsh->eval(*tsd, *server_tracker); + CHECK( ( tsh->get_tcp_event() == server_tracker->get_tcp_event() ) ); + delete tsd; + } + + delete pkt; + } + + SECTION("rst_packet") + { + Packet* pkt = get_rst_packet(flow); + REQUIRE( ( pkt != nullptr ) ); + + SECTION("rst_sent") + { + TcpSegmentDescriptor* tsd = new TcpSegmentDescriptor(flow, pkt, tel); + REQUIRE( ( tsd != nullptr ) ); + client_tracker->set_tcp_event(TcpStreamTracker::TCP_RST_SENT_EVENT); + tsh->eval(*tsd, *client_tracker); + CHECK( ( tsh->get_tcp_event() == client_tracker->get_tcp_event() ) ); + delete tsd; + } + + SECTION("rst_recv") + { + TcpSegmentDescriptor* tsd = new TcpSegmentDescriptor(flow, pkt, tel); + REQUIRE( ( tsd != nullptr ) ); + server_tracker->set_tcp_event(TcpStreamTracker::TCP_RST_RECV_EVENT); + tsh->eval(*tsd, *server_tracker); + CHECK( ( tsh->get_tcp_event() == server_tracker->get_tcp_event() ) ); + delete tsd; + } + + delete pkt; + } + + delete flow; + delete tsh; + delete client_tracker; + delete server_tracker; } #endif + diff --git a/src/stream/libtcp/tcp_state_handler.h b/src/stream/libtcp/tcp_state_handler.h index 96cb88c6d..30b3d0a6e 100644 --- a/src/stream/libtcp/tcp_state_handler.h +++ b/src/stream/libtcp/tcp_state_handler.h @@ -26,36 +26,67 @@ #include "tcp_segment_descriptor.h" #include "tcp_stream_tracker.h" +class TcpStateMachine; + class TcpStateHandler { - public: - TcpStateHandler(); + TcpStateHandler(TcpStreamTracker::TcpStates, TcpStateMachine&); + TcpStateHandler(void); virtual ~TcpStateHandler(); - virtual void eval(TcpSegmentDescriptor&, TcpStreamTracker&); + virtual bool eval(TcpSegmentDescriptor&, TcpStreamTracker&); - TcpStreamTracker::TcpEvents get_tcp_event() const { + TcpStreamTracker::TcpEvents get_tcp_event() const + { return tcp_event; } + TcpStreamTracker::TcpStates 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) + { + this->tcp_event = tcp_event; + } + + const TcpStateMachine* get_tsm() const + { + return tsm; + } + + void set_tsm(const TcpStateMachine* tsm) + { + this->tsm = tsm; + } + protected: - virtual void syn_sent(TcpSegmentDescriptor&, TcpStreamTracker&); - virtual void syn_recv(TcpSegmentDescriptor&, TcpStreamTracker&); - virtual void syn_ack_sent(TcpSegmentDescriptor&, TcpStreamTracker&); - virtual void syn_ack_recv(TcpSegmentDescriptor&, TcpStreamTracker&); - virtual void ack_sent(TcpSegmentDescriptor&, TcpStreamTracker&); - virtual void ack_recv(TcpSegmentDescriptor&, TcpStreamTracker&); - virtual void data_seg_sent(TcpSegmentDescriptor&, TcpStreamTracker&); - virtual void data_seg_recv(TcpSegmentDescriptor&, TcpStreamTracker&); - virtual void fin_sent(TcpSegmentDescriptor&, TcpStreamTracker&); - virtual void fin_recv(TcpSegmentDescriptor&, TcpStreamTracker&); - virtual void rst_sent(TcpSegmentDescriptor&, TcpStreamTracker&); - virtual void rst_recv(TcpSegmentDescriptor&, TcpStreamTracker&); - - void default_state_action( TcpSegmentDescriptor*, TcpStreamTracker*, const char* ); + virtual bool syn_sent(TcpSegmentDescriptor&, TcpStreamTracker&); + virtual bool syn_recv(TcpSegmentDescriptor&, TcpStreamTracker&); + virtual bool syn_ack_sent(TcpSegmentDescriptor&, TcpStreamTracker&); + virtual bool syn_ack_recv(TcpSegmentDescriptor&, TcpStreamTracker&); + virtual bool ack_sent(TcpSegmentDescriptor&, TcpStreamTracker&); + virtual bool ack_recv(TcpSegmentDescriptor&, TcpStreamTracker&); + virtual bool data_seg_sent(TcpSegmentDescriptor&, TcpStreamTracker&); + virtual bool data_seg_recv(TcpSegmentDescriptor&, TcpStreamTracker&); + virtual bool fin_sent(TcpSegmentDescriptor&, TcpStreamTracker&); + virtual bool fin_recv(TcpSegmentDescriptor&, TcpStreamTracker&); + virtual bool rst_sent(TcpSegmentDescriptor&, TcpStreamTracker&); + virtual bool rst_recv(TcpSegmentDescriptor&, TcpStreamTracker&); + + bool default_state_action(TcpSegmentDescriptor&, TcpStreamTracker&, const char*); + const TcpStateMachine* tsm; + TcpStreamTracker::TcpStates tcp_state; TcpStreamTracker::TcpEvents tcp_event; }; #endif + diff --git a/src/stream/libtcp/tcp_state_machine.cc b/src/stream/libtcp/tcp_state_machine.cc index d31ece3a6..38f0dc631 100644 --- a/src/stream/libtcp/tcp_state_machine.cc +++ b/src/stream/libtcp/tcp_state_machine.cc @@ -19,32 +19,37 @@ // tcp_state_machine.cc author davis mcpherson // Created on: Jul 29, 2015 +#include "tcp_stream_tracker.h" #include "tcp_state_machine.h" -const char* tcp_state_names[] = -{ "TCP_LISTEN", "TCP_SYN_SENT", "TCP_SYN_RECV", "TCP_ESTABLISHED","TCP_FIN_WAIT1", - "TCP_FIN_WAIT2", "TCP_CLOSE_WAIT", "TCP_CLOSING", "TCP_LAST_ACK", - "TCP_TIME_WAIT", "TCP_CLOSED" -}; - -const char *tcp_event_names[] = { "TCP_SYN_SENT_EVENT", "TCP_SYN_RECV_EVENT", - "TCP_SYN_ACK_SENT_EVENT", "TCP_SYN_ACK_RECV_EVENT", "TCP_ACK_SENT_EVENT", - "TCP_ACK_RECV_EVENT", "TCP_DATA_SEG_SENT_EVENT", "TCP_DATA_SEG_RECV_EVENT", - "TCP_FIN_SENT_EVENT", "TCP_FIN_RECV_EVENT", "TCP_RST_SENT_EVENT", "TCP_RST_RECV_EVENT" }; - +TcpStateMachine::TcpStateMachine(void) +{ + // register a default handler for each state... + for ( TcpStreamTracker::TcpStates state = TcpStreamTracker::TCP_LISTEN; state < + TcpStreamTracker::TCP_MAX_STATES; state++ ) + { + tcp_state_handlers[ state ] = nullptr; + new TcpStateHandler(state, *this); + } +} -TcpStateMachine::~TcpStateMachine() +TcpStateMachine::~TcpStateMachine(void) { // TODO Auto-generated destructor stub } -TcpStateMachine::TcpStateMachine() + +void TcpStateMachine::register_state_handler(TcpStreamTracker::TcpStates state, + TcpStateHandler& handler) { - // TODO Auto-generated constructor stub + if ( tcp_state_handlers[ state ] != nullptr ) + delete tcp_state_handlers[ state ]; + tcp_state_handlers[ state ] = &handler; } -void TcpStateMachine::eval( TcpSegmentDescriptor &tcp_seg, TcpStreamTracker &tracker ) +bool TcpStateMachine::eval(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { - tracker.set_tcp_event( tcp_seg, tracker.is_client_tracker( ) ); - tcp_state_handlers[ tracker.get_tcp_state( ) ]->eval( tcp_seg, tracker ); + tracker.set_tcp_event(tsd); + return tcp_state_handlers[ tracker.get_tcp_state( ) ]->eval(tsd, tracker); } + diff --git a/src/stream/libtcp/tcp_state_machine.h b/src/stream/libtcp/tcp_state_machine.h index 644f4c44a..d9ef3e141 100644 --- a/src/stream/libtcp/tcp_state_machine.h +++ b/src/stream/libtcp/tcp_state_machine.h @@ -26,20 +26,19 @@ #include "tcp_stream_tracker.h" #include "tcp_segment_descriptor.h" -extern const char* tcp_state_names[]; -extern const char* tcp_event_names[]; - class TcpStateMachine { public: - virtual ~TcpStateMachine(); + TcpStateMachine(void); + virtual ~TcpStateMachine(void); - virtual void eval(TcpSegmentDescriptor&, TcpStreamTracker&); + virtual void register_state_handler(TcpStreamTracker::TcpStates, TcpStateHandler&); + virtual bool eval(TcpSegmentDescriptor&, TcpStreamTracker&); private: - TcpStateMachine(); - TcpStateHandler *tcp_state_handlers[ TcpStreamTracker::TCP_MAX_STATES ]; + TcpStateHandler* tcp_state_handlers[ TcpStreamTracker::TCP_MAX_STATES ]; }; #endif + diff --git a/src/stream/libtcp/tcp_stream_tracker.cc b/src/stream/libtcp/tcp_stream_tracker.cc index 57980676f..e7de1f1b6 100644 --- a/src/stream/libtcp/tcp_stream_tracker.cc +++ b/src/stream/libtcp/tcp_stream_tracker.cc @@ -19,13 +19,34 @@ // tcp_stream_tracker.cpp author davis mcpherson // Created on: Jun 24, 2015 -#include "tcp_stream_tracker.h" +#include "protocols/tcp_options.h" +#include "protocols/tcp.h" +#include "protocols/eth.h" +#include "profiler/profiler.h" + #include "stream/stream.h" +#include "tcp_stream_tracker.h" + +const char* tcp_state_names[] = +{ "TCP_LISTEN", "TCP_SYN_SENT", "TCP_SYN_RECV", "TCP_ESTABLISHED","TCP_FIN_WAIT1", + "TCP_FIN_WAIT2", "TCP_CLOSE_WAIT", "TCP_CLOSING", "TCP_LAST_ACK", + "TCP_TIME_WAIT", "TCP_CLOSED", "TCP_STATE_NONE",}; -TcpStreamTracker::TcpStreamTracker( bool client ) : - client_tracker( client ) +const char* tcp_event_names[] = { "TCP_SYN_SENT_EVENT", "TCP_SYN_RECV_EVENT", + "TCP_SYN_ACK_SENT_EVENT", "TCP_SYN_ACK_RECV_EVENT", + "TCP_ACK_SENT_EVENT", + "TCP_ACK_RECV_EVENT", "TCP_DATA_SEG_SENT_EVENT", + "TCP_DATA_SEG_RECV_EVENT", + "TCP_FIN_SENT_EVENT", "TCP_FIN_RECV_EVENT", "TCP_RST_SENT_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) { - tcp_state = ( client ) ? TCP_CLOSED : TCP_LISTEN; + memset(mac_addr, '0', sizeof(mac_addr)); + tcp_state = TCP_STATE_NONE; tcp_event = TCP_MAX_EVENTS; } @@ -34,51 +55,102 @@ TcpStreamTracker::~TcpStreamTracker() // TODO Auto-generated destructor stub } -void TcpStreamTracker::set_tcp_event( TcpSegmentDescriptor &tcp_seg, bool client ) +void TcpStreamTracker::set_tcp_event(TcpSegmentDescriptor& tsd) { - bool talker; + bool talker; + const tcp::TCPHdr* tcph = tsd.get_tcph(); - if( tcp_seg.get_direction( ) == FROM_CLIENT ) - talker = ( client ) ? true : false; + if ( tsd.get_pkt()->packet_flags & PKT_FROM_CLIENT ) + talker = ( client_tracker ) ? true : false; else - talker = ( client ) ? false : true; + talker = ( client_tracker ) ? false : true; - if( talker ) + if ( talker ) { - if( tcp_seg.get_tcph()->is_syn_only() ) + if ( tcph->is_syn_only() ) tcp_event = TCP_SYN_SENT_EVENT; - else if( tcp_seg.get_tcph()->is_syn_ack() ) + else if ( tcph->is_syn_ack() ) tcp_event = TCP_SYN_ACK_SENT_EVENT; - else if( tcp_seg.get_tcph()->is_ack() ) + else if ( tcph->is_ack() || tcph->is_psh() ) { - if( tcp_seg.get_data_len() > 0 ) + if ( tsd.get_data_len() > 0 ) tcp_event = TCP_DATA_SEG_SENT_EVENT; else tcp_event = TCP_ACK_SENT_EVENT; } - else if( tcp_seg.get_tcph()->is_rst() ) + else if ( tcph->is_rst() ) tcp_event = TCP_RST_SENT_EVENT; - else if( tcp_seg.get_tcph()->is_fin( ) ) + 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_MAX_EVENTS; + tcp_event = TCP_ACK_SENT_EVENT; } else // server is listening events { - if( tcp_seg.get_tcph()->is_syn_only() ) - tcp_event = TCP_SYN_RECV_EVENT; - else if( tcp_seg.get_tcph()->is_syn_ack() ) - tcp_event = TCP_SYN_ACK_RECV_EVENT; - else if( tcp_seg.get_tcph()->is_ack() ) - { - if( tcp_seg.get_data_len() > 0 ) - tcp_event = TCP_DATA_SEG_RECV_EVENT; - else - tcp_event = TCP_ACK_RECV_EVENT; - } - else if( tcp_seg.get_tcph()->is_rst() ) - tcp_event = TCP_RST_RECV_EVENT; - else if( tcp_seg.get_tcph()->is_fin( ) ) - tcp_event = TCP_FIN_RECV_EVENT; + 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_ack() || tcph->is_psh() ) + { + if ( tsd.get_data_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? +// tcp_event = TCP_DATA_SEG_RECV_EVENT; + else + tcp_event = TCP_ACK_RECV_EVENT; } } + +// Use a for loop and byte comparison, which has proven to be faster on pipelined architectures +// compared to a memcmp (setup for memcmp is slow). Not using a 4 byte and 2 byte long because +// there is no guarantee of memory alignment (and thus performance issues similar to memcmp). +bool TcpStreamTracker::compare_mac_addresses(const uint8_t eth_addr[]) +{ + for ( int i = 0; i < 6; ++i ) + if ( mac_addr[i] != eth_addr[i] ) + return false; + + return true; +} + +void TcpStreamTracker::cache_mac_address(TcpSegmentDescriptor& tsd, uint8_t direction) +{ + 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 ( 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]; + else + for ( i = 0; i < 6; i++ ) + mac_addr[i] = eh->ether_src[i]; + } +} + diff --git a/src/stream/libtcp/tcp_stream_tracker.h b/src/stream/libtcp/tcp_stream_tracker.h index 95f678eae..3a811344c 100644 --- a/src/stream/libtcp/tcp_stream_tracker.h +++ b/src/stream/libtcp/tcp_stream_tracker.h @@ -26,183 +26,268 @@ #include "tcp_segment_descriptor.h" +extern const char* tcp_state_names[]; +extern const char* tcp_event_names[]; + class TcpStreamTracker { public: enum TcpStates - { - TCP_LISTEN, - TCP_SYN_SENT, - TCP_SYN_RECV, - TCP_ESTABLISHED, - TCP_FIN_WAIT1, - TCP_FIN_WAIT2, - TCP_CLOSE_WAIT, - TCP_CLOSING, - TCP_LAST_ACK, - TCP_TIME_WAIT, - TCP_CLOSED, - TCP_MAX_STATES - }; - - enum TcpEvents - { - TCP_SYN_SENT_EVENT, - TCP_SYN_RECV_EVENT, - TCP_SYN_ACK_SENT_EVENT, - TCP_SYN_ACK_RECV_EVENT, - TCP_ACK_SENT_EVENT, - TCP_ACK_RECV_EVENT, - TCP_DATA_SEG_SENT_EVENT, - TCP_DATA_SEG_RECV_EVENT, - TCP_FIN_SENT_EVENT, - TCP_FIN_RECV_EVENT, - TCP_RST_SENT_EVENT, - TCP_RST_RECV_EVENT, - TCP_MAX_EVENTS - }; - - TcpStreamTracker( bool ); + { + TCP_LISTEN, + TCP_SYN_SENT, + TCP_SYN_RECV, + TCP_ESTABLISHED, + TCP_FIN_WAIT1, + TCP_FIN_WAIT2, + TCP_CLOSE_WAIT, + TCP_CLOSING, + TCP_LAST_ACK, + TCP_TIME_WAIT, + TCP_CLOSED, + TCP_STATE_NONE, + TCP_MAX_STATES + }; + + enum TcpEvents + { + TCP_SYN_SENT_EVENT, + TCP_SYN_RECV_EVENT, + TCP_SYN_ACK_SENT_EVENT, + TCP_SYN_ACK_RECV_EVENT, + TCP_ACK_SENT_EVENT, + TCP_ACK_RECV_EVENT, + TCP_DATA_SEG_SENT_EVENT, + TCP_DATA_SEG_RECV_EVENT, + TCP_FIN_SENT_EVENT, + TCP_FIN_RECV_EVENT, + TCP_RST_SENT_EVENT, + TCP_RST_RECV_EVENT, + TCP_MAX_EVENTS + }; + + TcpStreamTracker(bool); virtual ~TcpStreamTracker(); - bool is_client_tracker() const { + bool is_client_tracker() const + { return client_tracker; } - TcpStates get_tcp_state() const { + bool is_3whs_required() const + { + return require_3whs; + } + + void set_require_3whs(bool require3_whs) + { + this->require_3whs = require3_whs; + } + + TcpStates get_tcp_state() const + { return tcp_state; } - void set_tcp_state(TcpStates tcp_state) { + void set_tcp_state(TcpStates tcp_state) + { this->tcp_state = tcp_state; } - TcpEvents get_tcp_event() const { + TcpEvents get_tcp_event() const + { return tcp_event; } - void set_tcp_event( TcpSegmentDescriptor &tcp_seg, bool client ); + void set_tcp_event(TcpSegmentDescriptor& tsd); - void set_tcp_event(TcpEvents tcp_event) { + void set_tcp_event(TcpEvents tcp_event) + { this->tcp_event = tcp_event; } - uint32_t get_irs() const { - return irs; - } - - void set_irs(uint32_t irs) { - this->irs = irs; - } - - uint32_t get_iss() const { - return iss; + uint32_t get_rcv_nxt() const + { + return rcv_nxt; } - void set_iss(uint32_t iss) { - this->iss = iss; + void set_rcv_nxt(uint32_t rcv_nxt) + { + this->rcv_nxt = rcv_nxt; } - uint32_t get_rcv_nxt() const { - return rcv_nxt; + uint32_t get_rcv_wnd() const + { + return rcv_wnd; } - void set_rcv_nxt(uint32_t rcv_nxt) { - this->rcv_nxt = rcv_nxt; + void set_rcv_wnd(uint32_t rcv_wnd) + { + this->rcv_wnd = rcv_wnd; } - uint16_t get_rcv_up() const { + uint16_t get_rcv_up() const + { return rcv_up; } - void set_rcv_up(uint16_t rcv_up) { + void set_rcv_up(uint16_t rcv_up) + { this->rcv_up = rcv_up; } - uint16_t get_rcv_wnd() const { - return rcv_wnd; + uint32_t get_irs() const + { + return irs; } - void set_rcv_wnd(uint16_t rcv_wnd) { - this->rcv_wnd = rcv_wnd; + void set_irs(uint32_t irs) + { + this->irs = irs; } - uint32_t get_snd_nxt() const { - return snd_nxt; + uint32_t get_snd_una() const + { + return snd_una; } - void set_snd_nxt(uint32_t snd_nxt) { - this->snd_nxt = snd_nxt; + void set_snd_una(uint32_t snd_una) + { + this->snd_una = snd_una; } - uint32_t get_snd_una() const { - return snd_una; + uint32_t get_snd_nxt() const + { + return snd_nxt; } - void set_snd_una(uint32_t snd_una) { - this->snd_una = snd_una; + void set_snd_nxt(uint32_t snd_nxt) + { + this->snd_nxt = snd_nxt; } - uint16_t get_snd_up() const { + uint16_t get_snd_up() const + { return snd_up; } - void set_snd_up(uint16_t snd_up) { + void set_snd_up(uint16_t snd_up) + { this->snd_up = snd_up; } - uint32_t get_snd_wl1() const { + uint32_t get_snd_wl1() const + { return snd_wl1; } - void set_snd_wl1(uint32_t snd_wl1) { + void set_snd_wl1(uint32_t snd_wl1) + { this->snd_wl1 = snd_wl1; } - uint32_t get_snd_wl2() const { + uint32_t get_snd_wl2() const + { return snd_wl2; } - void set_snd_wl2(uint32_t snd_wl2) { + void set_snd_wl2(uint32_t snd_wl2) + { this->snd_wl2 = snd_wl2; } - uint16_t get_snd_wnd() const { + uint32_t get_snd_wnd() const + { return snd_wnd; } - void set_snd_wnd(uint16_t snd_wnd) { + void set_snd_wnd(uint32_t snd_wnd) + { this->snd_wnd = snd_wnd; } - uint32_t get_ts_last_packet() const { + uint32_t get_iss() const + { + return iss; + } + + void set_iss(uint32_t iss) + { + this->iss = iss; + } + + uint32_t get_ts_last_packet() const + { return ts_last_packet; } - void set_ts_last_packet(uint32_t ts_last_packet) { + void set_ts_last_packet(uint32_t ts_last_packet) + { this->ts_last_packet = ts_last_packet; } + bool is_ack_valid(uint32_t cur) + { + /* If we haven't seen anything, ie, low & high are 0, return true */ + if ( ( snd_una == 0 ) && ( snd_una == snd_nxt ) ) + return 1; + + return ( SEQ_GEQ(cur, snd_una) && SEQ_LEQ(cur, snd_nxt) ); + } + + // ack number must ack syn + bool is_rst_valid_in_syn_sent(TcpSegmentDescriptor& tsd) + { + return tsd.get_ack() == snd_una; + } + + void cache_mac_address(TcpSegmentDescriptor& tsd, uint8_t direction); + bool compare_mac_addresses(const uint8_t eth_addr[]); + protected: + bool client_tracker; + bool require_3whs; + uint32_t snd_una; // SND.UNA - send unacknowledged uint32_t snd_nxt; // SND.NXT - send next - uint16_t snd_wnd; // SND.WND - send window + 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; // RCV.NXT - receive next - uint16_t rcv_wnd; // RCV.WND - receive window + 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 uint32_t ts_last_packet; // timestamp of last packet we got - bool client_tracker; + // 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 +{ + const int i = static_cast(state); + state = static_cast((i + 1) % ( TcpStreamTracker::TCP_MAX_EVENTS + + 1 ) ); + return state; +} + #endif + diff --git a/src/stream/tcp/CMakeLists.txt b/src/stream/tcp/CMakeLists.txt index 0f3495e18..755ea184c 100644 --- a/src/stream/tcp/CMakeLists.txt +++ b/src/stream/tcp/CMakeLists.txt @@ -7,23 +7,48 @@ add_library( stream_tcp STATIC tcp_module.cc tcp_module.h tcp_defs.h - tcp_events.h + tcp_event_logger.h + tcp_event_logger.cc + tcp_stream_config.h + tcp_stream_config.cc tcp_normalizer.h tcp_normalizer.cc tcp_normalizers.h tcp_normalizers.cc - tcp_segment.h - tcp_segment.cc + tcp_segment_node.h + tcp_segment_node.cc tcp_reassembler.h tcp_reassembler.cc tcp_reassemblers.h tcp_reassemblers.cc + tcp_tracker.cc + tcp_tracker.h tcp_session.cc tcp_session.h - tcp_closed_state.cc - tcp_listen_state.cc - tcp_syn_sent_state.cc - tcp_syn_recv_state.cc + tcp_state_closed.cc + tcp_state_close_wait.cc + tcp_state_closing.cc + tcp_state_established.cc + tcp_state_fin_wait1.cc + tcp_state_fin_wait2.cc + tcp_state_last_ack.cc + tcp_state_listen.cc + tcp_state_none.cc + tcp_state_syn_recv.cc + tcp_state_syn_sent.cc + tcp_state_time_wait.cc + tcp_state_closed.h + tcp_state_close_wait.h + tcp_state_closing.h + tcp_state_established.h + tcp_state_fin_wait1.h + tcp_state_fin_wait2.h + tcp_state_last_ack.h + tcp_state_listen.h + tcp_state_none.h + tcp_state_syn_recv.h + tcp_state_syn_sent.h + tcp_state_time_wait.h ips_stream_reassemble.cc ips_stream_size.cc ) diff --git a/src/stream/tcp/Makefile.am b/src/stream/tcp/Makefile.am index 2287d814c..a639e8063 100644 --- a/src/stream/tcp/Makefile.am +++ b/src/stream/tcp/Makefile.am @@ -10,27 +10,48 @@ tcp_module.cc \ tcp_module.h \ tcp_debug_trace.h \ tcp_defs.h \ -tcp_events.h \ +tcp_event_logger.h \ +tcp_event_logger.cc \ +tcp_stream_config.h \ +tcp_stream_config.cc \ tcp_normalizer.h \ tcp_normalizer.cc \ tcp_normalizers.h \ tcp_normalizers.cc \ -tcp_segment.h \ -tcp_segment.cc \ +tcp_segment_node.h \ +tcp_segment_node.cc \ tcp_reassembler.h \ tcp_reassembler.cc \ tcp_reassemblers.h \ tcp_reassemblers.cc \ +tcp_tracker.cc \ +tcp_tracker.h \ tcp_session.cc \ tcp_session.h \ -tcp_closed_state.h \ -tcp_closed_state.cc \ -tcp_listen_state.cc \ -tcp_listen_state.h \ -tcp_syn_sent_state.cc \ -tcp_syn_sent_state.h \ -tcp_syn_recv_state.cc \ -tcp_syn_recv_state.h \ +tcp_state_closed.cc \ +tcp_state_close_wait.cc \ +tcp_state_closing.cc \ +tcp_state_established.cc \ +tcp_state_fin_wait1.cc \ +tcp_state_fin_wait2.cc \ +tcp_state_last_ack.cc \ +tcp_state_listen.cc \ +tcp_state_none.cc \ +tcp_state_syn_recv.cc \ +tcp_state_syn_sent.cc \ +tcp_state_time_wait.cc \ +tcp_state_closed.h \ +tcp_state_close_wait.h \ +tcp_state_closing.h \ +tcp_state_established.h \ +tcp_state_fin_wait1.h \ +tcp_state_fin_wait2.h \ +tcp_state_last_ack.h \ +tcp_state_listen.h \ +tcp_state_none.h \ +tcp_state_syn_recv.h \ +tcp_state_syn_sent.h \ +tcp_state_time_wait.h \ ips_stream_reassemble.cc \ ips_stream_size.cc diff --git a/src/stream/tcp/ips_stream_reassemble.cc b/src/stream/tcp/ips_stream_reassemble.cc index 21ccf531f..a4a469a01 100644 --- a/src/stream/tcp/ips_stream_reassemble.cc +++ b/src/stream/tcp/ips_stream_reassemble.cc @@ -123,13 +123,13 @@ int ReassembleOption::eval(Cursor&, Packet* pkt) { if ( srod.direction & SSN_DIR_FROM_SERVER ) { - tcpssn->server.flush_policy = STREAM_FLPOLICY_IGNORE; + tcpssn->server->flush_policy = STREAM_FLPOLICY_IGNORE; stream.set_splitter(lwssn, true); } if ( srod.direction & SSN_DIR_FROM_CLIENT ) { - tcpssn->client.flush_policy = STREAM_FLPOLICY_IGNORE; + tcpssn->client->flush_policy = STREAM_FLPOLICY_IGNORE; stream.set_splitter(lwssn, false); } } @@ -139,13 +139,13 @@ int ReassembleOption::eval(Cursor&, Packet* pkt) // FIXIT-M PAF need to check for ips / on-data if ( srod.direction & SSN_DIR_FROM_SERVER ) { - tcpssn->server.flush_policy = STREAM_FLPOLICY_ON_ACK; + tcpssn->server->flush_policy = STREAM_FLPOLICY_ON_ACK; stream.set_splitter(lwssn, true, new AtomSplitter(true)); } if ( srod.direction & SSN_DIR_FROM_CLIENT ) { - tcpssn->client.flush_policy = STREAM_FLPOLICY_ON_ACK; + tcpssn->client->flush_policy = STREAM_FLPOLICY_ON_ACK; stream.set_splitter(lwssn, false, new AtomSplitter(false)); } } @@ -160,7 +160,6 @@ int ReassembleOption::eval(Cursor&, Packet* pkt) } } - if (srod.alert) return DETECTION_OPTION_MATCH; @@ -291,19 +290,19 @@ TEST_CASE("IPS Stream Reassemble", "[ips_stream_reassemble][stream_tcp]") { // initialization code here REQUIRE( ( ips_stream_reassemble->api_version == ((BASE_API_VERSION << 16) | 0) ) ); - REQUIRE( ( strcmp( ips_stream_reassemble->name, s_name ) == 0 ) ); - ReassembleModule* reassembler = ( ReassembleModule* ) ips_stream_reassemble->mod_ctor(); + REQUIRE( ( strcmp(ips_stream_reassemble->name, s_name) == 0 ) ); + ReassembleModule* reassembler = ( ReassembleModule* )ips_stream_reassemble->mod_ctor(); REQUIRE( ( reassembler != nullptr ) ); Flow* flow = new Flow; - Packet* pkt = get_syn_packet( flow ); - pkt->flow->session = new TcpSession( flow ); - Cursor cursor( pkt ); + Packet* pkt = get_syn_packet(flow); + pkt->flow->session = new TcpSession(flow); + Cursor cursor(pkt); SECTION("reassembler initialization") { - bool status = reassembler->begin( nullptr, 0, snort_conf ); - CHECK( status ); + bool status = reassembler->begin(nullptr, 0, snort_conf); + CHECK(status); CHECK( ( reassembler->srod.enable == 0 ) ); CHECK( ( reassembler->srod.direction == 0 ) ); CHECK( ( reassembler->srod.alert == 1 ) ); @@ -314,18 +313,17 @@ TEST_CASE("IPS Stream Reassemble", "[ips_stream_reassemble][stream_tcp]") SECTION("eval enable off") { reassembler->srod.direction = SSN_DIR_FROM_SERVER; - IpsOption* ropt = reassemble_api.ctor( reassembler, nullptr ); - int rc = ropt->eval( cursor, pkt ); + IpsOption* ropt = reassemble_api.ctor(reassembler, nullptr); + int rc = ropt->eval(cursor, pkt); CHECK( ( rc == DETECTION_OPTION_MATCH ) ); - StreamSplitter* ss = stream.get_splitter( flow, true ); + StreamSplitter* ss = stream.get_splitter(flow, true); CHECK( ( ss != nullptr ) ); CHECK( ( !ss->is_paf() ) ); - CHECK( ( ( ( TcpSession* ) pkt->flow->session)->server.flush_policy - == STREAM_FLPOLICY_IGNORE ) ); + CHECK( ( ( ( TcpSession* )pkt->flow->session)->server.flush_policy + == STREAM_FLPOLICY_IGNORE ) ); } #endif - } - #endif + diff --git a/src/stream/tcp/ips_stream_size.cc b/src/stream/tcp/ips_stream_size.cc index 2fff925b1..a019034f8 100644 --- a/src/stream/tcp/ips_stream_size.cc +++ b/src/stream/tcp/ips_stream_size.cc @@ -107,26 +107,26 @@ int SizeOption::eval(Cursor&, Packet* pkt) uint32_t client_size; uint32_t server_size; - if (tcpssn->client.l_nxt_seq > tcpssn->client.isn) + if (tcpssn->client->get_snd_nxt() > tcpssn->client->get_iss()) { /* the normal case... */ - client_size = tcpssn->client.l_nxt_seq - tcpssn->client.isn; + client_size = tcpssn->client->get_snd_nxt() - tcpssn->client->get_iss(); } else { /* the seq num wrapping case... */ - client_size = tcpssn->client.isn - tcpssn->client.l_nxt_seq; + client_size = tcpssn->client->get_iss() - tcpssn->client->get_snd_nxt(); } - if (tcpssn->server.l_nxt_seq > tcpssn->server.isn) + if (tcpssn->server->get_snd_nxt() > tcpssn->server->get_iss()) { /* the normal case... */ - server_size = tcpssn->server.l_nxt_seq - tcpssn->server.isn; + server_size = tcpssn->server->get_snd_nxt() - tcpssn->server->get_iss(); } else { /* the seq num wrapping case... */ - server_size = tcpssn->server.isn - tcpssn->server.l_nxt_seq; + server_size = tcpssn->server->get_iss() - tcpssn->server->get_snd_nxt(); } int result = DETECTION_OPTION_NO_MATCH; diff --git a/src/stream/tcp/segment_overlap_editor.cc b/src/stream/tcp/segment_overlap_editor.cc index 14fd57365..110ef1cf5 100644 --- a/src/stream/tcp/segment_overlap_editor.cc +++ b/src/stream/tcp/segment_overlap_editor.cc @@ -23,17 +23,17 @@ #include "protocols/packet.h" #include "tcp_module.h" -#include "tcp_events.h" +#include "tcp_event_logger.h" #include "tcp_normalizer.h" #include "tcp_reassembler.h" #include "segment_overlap_editor.h" -bool SegmentOverlapEditor::is_segment_retransmit( void ) +bool SegmentOverlapEditor::is_segment_retransmit(void) { // Don't want to count retransmits as overlaps or do anything // else with them. Account for retransmits of multiple PDUs // in one segment. - if( right->is_retransmit( rdata, rsize, rseq ) ) + if ( right->is_retransmit(rdata, rsize, rseq) ) { rdata += right->payload_size; rsize -= right->payload_size; @@ -43,10 +43,10 @@ bool SegmentOverlapEditor::is_segment_retransmit( void ) left = right; right = right->next; - if( rsize == 0 ) + if ( rsize == 0 ) { // All data was retransmitted - session->retransmit_process( tdb->pkt ); + session->retransmit_process(tsd->get_pkt() ); keep_segment = false; } @@ -56,36 +56,36 @@ bool SegmentOverlapEditor::is_segment_retransmit( void ) return false; } -int SegmentOverlapEditor::eval_left( void ) +int SegmentOverlapEditor::eval_left(void) { int rc = STREAM_INSERT_OK; - if( left ) - rc = insert_left_overlap(); + if ( left ) + rc = insert_left_overlap(); return rc; } -int SegmentOverlapEditor::eval_right( void ) +int SegmentOverlapEditor::eval_right(void) { - while( right && SEQ_LT( right->seq, seq_end ) ) + while ( right && SEQ_LT(right->seq, seq_end) ) { trunc_len = 0; - overlap = ( int ) ( seq_end - right->seq ); + overlap = ( int )( seq_end - right->seq ); DebugFormat(DEBUG_STREAM_STATE, "right overlap(%d): len: %d right->seq: 0x%X seq: 0x%X\n", - overlap, len, right->seq, seq); + overlap, len, right->seq, seq); // Treat sequence number overlap as a retransmission, only check right side since // left side happens rarely - session->retransmit_handle( tdb->pkt ); + session->retransmit_handle(tsd->get_pkt() ); - if( overlap < right->payload_size ) + if ( overlap < right->payload_size ) { - if( right->is_retransmit( rdata, rsize, rseq ) ) + if ( right->is_retransmit(rdata, rsize, rseq) ) { // All data was retransmitted - session->retransmit_process( tdb->pkt ); + session->retransmit_process(tsd->get_pkt() ); keep_segment = false; } else @@ -102,13 +102,13 @@ int SegmentOverlapEditor::eval_right( void ) // Don't want to count retransmits as overlaps or do anything // else with them. Account for retransmits of multiple PDUs // in one segment. - if( is_segment_retransmit() ) + if ( is_segment_retransmit() ) continue; tcpStats.overlaps++; overlap_count++; int rc = insert_full_overlap(); - if( rc != STREAM_INSERT_OK ) + if ( rc != STREAM_INSERT_OK ) return rc; } } @@ -116,34 +116,35 @@ int SegmentOverlapEditor::eval_right( void ) return STREAM_INSERT_OK; } -void SegmentOverlapEditor::drop_old_segment( void ) +void SegmentOverlapEditor::drop_old_segment(void) { - DebugFormat(DEBUG_STREAM_STATE, "full right overlap, dropping old segment at seq %d, size %d\n", - right->seq, right->payload_size); + DebugFormat(DEBUG_STREAM_STATE, + "full right overlap, dropping old segment at seq %d, size %d\n", + right->seq, right->payload_size); - TcpSegment* drop_seg = right; + TcpSegmentNode* drop_seg = right; right = right->next; - delete_reassembly_segment( drop_seg ); + delete_reassembly_segment(drop_seg); } -int SegmentOverlapEditor::generate_bad_segment_event( void ) +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); - EventBadSegment(); + "(seq: %X seq_end: %X overlap: %lu\n", seq, seq_end, overlap); + session->tel->EventBadSegment(); inc_tcp_discards(); return STREAM_INSERT_ANOMALY; } -int SegmentOverlapEditor::left_overlap_keep_first( void ) +int SegmentOverlapEditor::left_overlap_keep_first(void) { int rc = STREAM_INSERT_OK; DebugFormat(DEBUG_STREAM_STATE, "left overlap %d\n", overlap); - len = tdb->pkt->dsize; + len = tsd->get_pkt()->dsize; overlap = left->seq + left->payload_size - seq; - if( overlap > 0 ) + if ( overlap > 0 ) { // NOTE that overlap will always be less than left->size since // seq is always greater than left->seq @@ -151,25 +152,27 @@ int SegmentOverlapEditor::left_overlap_keep_first( void ) overlap_count++; DebugMessage(DEBUG_STREAM_STATE, "left overlap, honoring old data\n"); - if( SEQ_LT( left->seq, tdb->seq ) && SEQ_GT( left->seq + left->payload_size, tdb->seq + tdb->pkt->dsize ) ) + if ( SEQ_LT(left->seq, tsd->get_seq() ) && SEQ_GT(left->seq + left->payload_size, + tsd->get_seq() + tsd->get_pkt()->dsize) ) { if (tcp_ips_data == NORM_MODE_ON) { - unsigned offset = tdb->seq - left->seq; - memcpy( ( uint8_t* ) tdb->pkt->data, left->payload + offset, tdb->pkt->dsize ); - tdb->pkt->packet_flags |= PKT_MODIFIED; + unsigned offset = tsd->get_seq() - left->seq; + memcpy( ( uint8_t* )tsd->get_pkt()->data, left->payload + offset, + tsd->get_pkt()->dsize); + tsd->get_pkt()->packet_flags |= PKT_MODIFIED; } normStats[PC_TCP_IPS_DATA][tcp_ips_data]++; sfBase.iPegs[PERF_COUNT_TCP_IPS_DATA][tcp_ips_data]++; } - else if( SEQ_LT( left->seq, tdb->seq ) ) + else if ( SEQ_LT(left->seq, tsd->get_seq() ) ) { - if( tcp_ips_data == NORM_MODE_ON ) + if ( tcp_ips_data == NORM_MODE_ON ) { - unsigned offset = tdb->seq - left->seq; - unsigned length = left->seq + left->payload_size - tdb->seq; - memcpy( ( uint8_t* ) tdb->pkt->data, left->payload + offset, length ); - tdb->pkt->packet_flags |= PKT_MODIFIED; + unsigned offset = tsd->get_seq() - left->seq; + unsigned length = left->seq + left->payload_size - tsd->get_seq(); + memcpy( ( uint8_t* )tsd->get_pkt()->data, left->payload + offset, length); + tsd->get_pkt()->packet_flags |= PKT_MODIFIED; } normStats[PC_TCP_IPS_DATA][tcp_ips_data]++; @@ -177,7 +180,7 @@ int SegmentOverlapEditor::left_overlap_keep_first( void ) } seq += overlap; - if( SEQ_LEQ( seq_end, seq ) ) + if ( SEQ_LEQ(seq_end, seq) ) return generate_bad_segment_event(); } @@ -190,24 +193,24 @@ int SegmentOverlapEditor::left_overlap_trim_first(void) DebugFormat(DEBUG_STREAM_STATE, "left overlap %d\n", overlap); - len = tdb->pkt->dsize; + len = tsd->get_pkt()->dsize; overlap = left->seq + left->payload_size - seq; - if( overlap > 0 ) + if ( overlap > 0 ) { tcpStats.overlaps++; overlap_count++; - if( SEQ_LT( left->seq, seq ) && SEQ_GEQ( left->seq + left->payload_size, seq + len ) ) + if ( SEQ_LT(left->seq, seq) && SEQ_GEQ(left->seq + left->payload_size, seq + len) ) { // existing packet overlaps new on both sides. Drop the new data. DebugMessage(DEBUG_STREAM_STATE, "left overlap, honoring old data\n"); seq += overlap; - if( SEQ_LEQ( seq_end, seq ) ) + if ( SEQ_LEQ(seq_end, seq) ) return generate_bad_segment_event(); } /* Otherwise, trim the old data accordingly */ - left->payload_size -= ( int16_t ) overlap; + left->payload_size -= ( int16_t )overlap; seg_bytes_logical -= overlap; DebugMessage(DEBUG_STREAM_STATE, "left overlap, honoring new data\n"); } @@ -215,55 +218,54 @@ int SegmentOverlapEditor::left_overlap_trim_first(void) return rc; } -int SegmentOverlapEditor::left_overlap_keep_last( void ) +int SegmentOverlapEditor::left_overlap_keep_last(void) { int rc = STREAM_INSERT_OK; DebugFormat(DEBUG_STREAM_STATE, "left overlap %d\n", overlap); - len = tdb->pkt->dsize; + len = tsd->get_pkt()->dsize; overlap = left->seq + left->payload_size - seq; - if( overlap > 0 ) + if ( overlap > 0 ) { tcpStats.overlaps++; overlap_count++; /* True "Last" policy" */ - if( SEQ_LT( left->seq, seq ) && SEQ_GT( left->seq + left->payload_size, seq + len ) ) + if ( SEQ_LT(left->seq, seq) && SEQ_GT(left->seq + left->payload_size, seq + len) ) { /* New data is overlapped on both sides by existing data. Existing data needs to be * split and the new data inserted in the middle. * Need to duplicate left. Adjust that seq by + (seq + len) and * size by - (seq + len - left->seq). */ - int rc = dup_reassembly_segment( tdb->pkt, left, &right ); - if( rc != STREAM_INSERT_OK ) + int rc = dup_reassembly_segment(tsd->get_pkt(), left, &right); + if ( rc != STREAM_INSERT_OK ) return rc; - left->payload_size -= ( int16_t ) overlap; + left->payload_size -= ( int16_t )overlap; seg_bytes_logical -= overlap; right->seq = seq + len; - uint16_t delta = ( int16_t ) ( right->seq - left->seq ); + uint16_t delta = ( int16_t )( right->seq - left->seq ); right->payload_size -= delta; right->payload += delta; seg_bytes_logical -= delta; } else { - left->payload_size -= (int16_t) overlap; + left->payload_size -= (int16_t)overlap; seg_bytes_logical -= overlap; } - } return rc; } -void SegmentOverlapEditor::right_overlap_truncate_existing( void ) +void SegmentOverlapEditor::right_overlap_truncate_existing(void) { DebugMessage(DEBUG_STREAM_STATE, "Got partial right overlap\n"); - if ( SEQ_EQ( right->seq, seq ) && ( reassembly_policy != ReassemblyPolicy::OS_LAST ) ) + if ( SEQ_EQ(right->seq, seq) && ( reassembly_policy != ReassemblyPolicy::OS_LAST ) ) { slide = ( right->seq + right->payload_size - seq ); seq += slide; @@ -273,20 +275,20 @@ void SegmentOverlapEditor::right_overlap_truncate_existing( void ) /* partial overlap */ right->seq += overlap; right->payload += overlap; - right->payload_size -= (int16_t) overlap; + right->payload_size -= (int16_t)overlap; seg_bytes_logical -= overlap; total_bytes_queued -= overlap; } } -void SegmentOverlapEditor::right_overlap_truncate_new( void ) +void SegmentOverlapEditor::right_overlap_truncate_new(void) { if (tcp_ips_data == NORM_MODE_ON) { - unsigned offset = right->seq - tdb->seq; - unsigned length = tdb->seq + tdb->pkt->dsize - right->seq; - memcpy( ( uint8_t* ) tdb->pkt->data + offset, right->payload, length ); - tdb->pkt->packet_flags |= PKT_MODIFIED; + unsigned offset = right->seq - tsd->get_seq(); + unsigned length = tsd->get_seq() + tsd->get_pkt()->dsize - right->seq; + memcpy( ( uint8_t* )tsd->get_pkt()->data + offset, right->payload, length); + tsd->get_pkt()->packet_flags |= PKT_MODIFIED; } normStats[PC_TCP_IPS_DATA][tcp_ips_data]++; @@ -296,21 +298,21 @@ void SegmentOverlapEditor::right_overlap_truncate_new( void ) // REASSEMBLY_POLICY_FIRST: // REASSEMBLY_POLICY_VISTA: -int SegmentOverlapEditor::full_right_overlap_truncate_new( void ) +int SegmentOverlapEditor::full_right_overlap_truncate_new(void) { DebugMessage(DEBUG_STREAM_STATE, "Got full right overlap, truncating new\n"); - if( tcp_ips_data == NORM_MODE_ON ) + if ( tcp_ips_data == NORM_MODE_ON ) { - unsigned offset = right->seq - tdb->seq; - memcpy( ( uint8_t* ) tdb->pkt->data + offset, right->payload, right->payload_size ); - tdb->pkt->packet_flags |= PKT_MODIFIED; + unsigned offset = right->seq - tsd->get_seq(); + memcpy( ( uint8_t* )tsd->get_pkt()->data + offset, right->payload, right->payload_size); + tsd->get_pkt()->packet_flags |= PKT_MODIFIED; } normStats[PC_TCP_IPS_DATA][tcp_ips_data]++; sfBase.iPegs[PERF_COUNT_TCP_IPS_DATA][tcp_ips_data]++; - if( SEQ_EQ( right->seq, seq ) ) + if ( SEQ_EQ(right->seq, seq) ) { /* Overlap is greater than or equal to right->size * slide gets set before insertion */ @@ -319,7 +321,7 @@ int SegmentOverlapEditor::full_right_overlap_truncate_new( void ) right = right->next; /* Adjusted seq is fully overlapped */ - if( SEQ_EQ( seq, seq_end ) ) + if ( SEQ_EQ(seq, seq_end) ) return generate_bad_segment_event(); } else @@ -329,9 +331,9 @@ 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 - tdb->seq; - int rc = add_reassembly_segment( tdb, len, slide, trunc_len, seq, left ); - if( rc != STREAM_INSERT_OK ) + slide = seq - tsd->get_seq(); + int rc = add_reassembly_segment(*tsd, len, slide, trunc_len, seq, left); + if ( rc != STREAM_INSERT_OK ) return rc; // Set seq to end of right since overlap was greater than or equal to right->size and @@ -350,16 +352,16 @@ int SegmentOverlapEditor::full_right_overlap_truncate_new( void ) // REASSEMBLY_POLICY_WINDOWS2K3: // REASSEMBLY_POLICY_BSD: // REASSEMBLY_POLICY_MACOS: -int SegmentOverlapEditor::full_right_overlap_os1( void ) +int SegmentOverlapEditor::full_right_overlap_os1(void) { - if( SEQ_GEQ( seq_end, right->seq + right->payload_size ) && SEQ_LT( seq, right->seq ) ) + if ( SEQ_GEQ(seq_end, right->seq + right->payload_size) && SEQ_LT(seq, right->seq) ) { drop_old_segment(); } else { int rc = full_right_overlap_truncate_new(); - if( rc != STREAM_INSERT_OK ) + if ( rc != STREAM_INSERT_OK ) return rc; } @@ -369,20 +371,20 @@ int SegmentOverlapEditor::full_right_overlap_os1( void ) // REASSEMBLY_POLICY_LINUX: // REASSEMBLY_POLICY_HPUX10: // REASSEMBLY_POLICY_IRIX: -int SegmentOverlapEditor::full_right_overlap_os2( void ) +int SegmentOverlapEditor::full_right_overlap_os2(void) { - if( SEQ_GEQ( seq_end, right->seq + right->payload_size ) && SEQ_LT( seq, right->seq ) ) + if ( SEQ_GEQ(seq_end, right->seq + right->payload_size) && SEQ_LT(seq, right->seq) ) { drop_old_segment(); } - else if( SEQ_GT( seq_end, right->seq + right->payload_size ) && SEQ_EQ( seq, right->seq ) ) + else if ( SEQ_GT(seq_end, right->seq + right->payload_size) && SEQ_EQ(seq, right->seq) ) { drop_old_segment(); } else { int rc = full_right_overlap_truncate_new(); - if( rc != STREAM_INSERT_OK ) + if ( rc != STREAM_INSERT_OK ) return rc; } @@ -391,15 +393,15 @@ int SegmentOverlapEditor::full_right_overlap_os2( void ) // REASSEMBLY_POLICY_HPUX11: // REASSEMBLY_POLICY_SOLARIS: -int SegmentOverlapEditor::full_right_overlap_os3( void ) +int SegmentOverlapEditor::full_right_overlap_os3(void) { // If this packet is wholly overlapping and the same size as a previous one and we have not // received the one immediately preceeding, we take the FIRST. - if( SEQ_EQ( right->seq, seq ) && ( right->payload_size == len ) - && ( left && !SEQ_EQ( left->seq + left->payload_size, seq ) ) ) + if ( SEQ_EQ(right->seq, seq) && ( right->payload_size == len ) + && ( left && !SEQ_EQ(left->seq + left->payload_size, seq) ) ) { trunc_len += overlap; - if( SEQ_LEQ( ( int )( seq_end - trunc_len ), seq ) ) + if ( SEQ_LEQ( ( int )( seq_end - trunc_len ), seq) ) return generate_bad_segment_event(); } else @@ -412,13 +414,25 @@ int SegmentOverlapEditor::full_right_overlap_os3( void ) // REASSEMBLY_POLICY_OLD_LINUX: // REASSEMBLY_POLICY_LAST: -int SegmentOverlapEditor::full_right_overlap_os4( void ) +int SegmentOverlapEditor::full_right_overlap_os4(void) { drop_old_segment(); return STREAM_INSERT_OK; } -int SegmentOverlapEditor::full_right_overlap_os5( void ) +int SegmentOverlapEditor::full_right_overlap_os5(void) { return full_right_overlap_truncate_new(); } + +void SegmentOverlapEditor::print(void) +{ + LogMessage(" seglist_base_seq: %X\n", seglist_base_seq); + LogMessage(" seglist head: %p\n", (void*)seglist.head); + LogMessage(" seglist tail: %p\n", (void*)seglist.tail); + LogMessage(" seglist next: %p\n", (void*)seglist.next); + LogMessage(" seg_count: %d\n", seg_count); + LogMessage(" seg_bytes_total: %d\n", seg_bytes_total); + LogMessage(" seg_bytes_logical: %d\n", seg_bytes_logical); +} + diff --git a/src/stream/tcp/segment_overlap_editor.h b/src/stream/tcp/segment_overlap_editor.h index d9291a64e..1e304328b 100644 --- a/src/stream/tcp/segment_overlap_editor.h +++ b/src/stream/tcp/segment_overlap_editor.h @@ -23,7 +23,7 @@ #define SEGMENT_OVERLAP_EDITOR_H #include "tcp_defs.h" -#include "tcp_segment.h" +#include "tcp_segment_node.h" #include "tcp_session.h" #define STREAM_INSERT_OK 0 @@ -35,62 +35,66 @@ 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), - tdb( 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 ) + 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); } - virtual ~SegmentOverlapEditor( void ) { } + virtual ~SegmentOverlapEditor(void) { } - void init_soe( TcpDataBlock* tdb, TcpSegment* left, TcpSegment* right ) + void init_soe(TcpSegmentDescriptor& tsd, TcpSegmentNode* left, TcpSegmentNode* right) { - this->tdb = tdb; + this->tsd = &tsd; this->left = left; this->right = right; - seq = tdb->seq; - seq_end = tdb->end_seq; - len = tdb->pkt->dsize; + seq = tsd.get_seq(); + seq_end = tsd.get_end_seq(); + len = tsd.get_data_len(); overlap = 0; slide = 0; trunc_len = 0; - rdata = tdb->pkt->data; - rsize = tdb->pkt->dsize; - rseq = tdb->seq; + rdata = tsd.get_pkt()->data; + rsize = tsd.get_data_len(); + rseq = tsd.get_seq(); keep_segment = true; } - int eval_left( void ); - int eval_right( void ); - - virtual bool is_segment_retransmit( void ); - virtual void drop_old_segment( void ); - virtual int generate_bad_segment_event( void ); - - virtual int left_overlap_keep_first( void ); - virtual int left_overlap_trim_first( void ); - virtual int left_overlap_keep_last( void ); - virtual void right_overlap_truncate_existing( void ); - virtual void right_overlap_truncate_new( void ); - virtual int full_right_overlap_truncate_new( void ); - virtual int full_right_overlap_os1( void ); - virtual int full_right_overlap_os2( void ); - virtual int full_right_overlap_os3( void ); - virtual int full_right_overlap_os4( void ); - virtual int full_right_overlap_os5( void ); - - 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( TcpDataBlock*, int16_t len, uint32_t slide, uint32_t trunc, - uint32_t seq, TcpSegment * ) = 0; - virtual int dup_reassembly_segment(Packet *p, TcpSegment *left, TcpSegment **retSeg) = 0; - virtual int delete_reassembly_segment( TcpSegment* seg ) = 0; + int eval_left(void); + int eval_right(void); + + virtual bool is_segment_retransmit(void); + virtual void drop_old_segment(void); + virtual int generate_bad_segment_event(void); + + virtual int left_overlap_keep_first(void); + virtual int left_overlap_trim_first(void); + virtual int left_overlap_keep_last(void); + virtual void right_overlap_truncate_existing(void); + virtual void right_overlap_truncate_new(void); + virtual int full_right_overlap_truncate_new(void); + virtual int full_right_overlap_os1(void); + virtual int full_right_overlap_os2(void); + virtual int full_right_overlap_os3(void); + virtual int full_right_overlap_os4(void); + virtual int full_right_overlap_os5(void); + + 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 void print(void); TcpSession* session; ReassemblyPolicy reassembly_policy; @@ -105,9 +109,9 @@ protected: uint32_t total_segs_queued; /* number of segments queued (life) */ uint32_t overlap_count; /* overlaps encountered */ - TcpDataBlock* tdb; - TcpSegment* left; - TcpSegment* right; + TcpSegmentDescriptor* tsd; + TcpSegmentNode* left; + TcpSegmentNode* right; uint32_t seq; uint32_t seq_end; uint16_t len; @@ -121,3 +125,4 @@ protected: }; #endif + diff --git a/src/stream/tcp/stream_tcp.cc b/src/stream/tcp/stream_tcp.cc index 6355c6fec..ddde4911f 100644 --- a/src/stream/tcp/stream_tcp.cc +++ b/src/stream/tcp/stream_tcp.cc @@ -36,7 +36,7 @@ class StreamTcp : public Inspector { public: - StreamTcp(StreamTcpConfig*); + StreamTcp(TcpStreamConfig*); ~StreamTcp(); void show(SnortConfig*) override; @@ -48,10 +48,10 @@ public: void eval(Packet*) override; public: - StreamTcpConfig* config; + TcpStreamConfig* config; }; -StreamTcp::StreamTcp (StreamTcpConfig* c) +StreamTcp::StreamTcp (TcpStreamConfig* c) { config = c; } @@ -63,7 +63,7 @@ StreamTcp::~StreamTcp() void StreamTcp::show(SnortConfig*) { - TcpSession::show(config); + TcpStreamConfig::show_config(config); } bool StreamTcp::configure(SnortConfig*) @@ -89,7 +89,7 @@ void StreamTcp::eval(Packet*) assert(false); } -StreamTcpConfig* get_tcp_cfg(Inspector* ins) +TcpStreamConfig* get_tcp_cfg(Inspector* ins) { assert(ins); return ((StreamTcp*)ins)->config; diff --git a/src/stream/tcp/stream_tcp.h b/src/stream/tcp/stream_tcp.h index 412b7c327..1b50248a4 100644 --- a/src/stream/tcp/stream_tcp.h +++ b/src/stream/tcp/stream_tcp.h @@ -24,45 +24,18 @@ #include "protocols/packet.h" #include "tcp_defs.h" - -struct StreamTcpConfig -{ - StreamPolicy policy; - ReassemblyPolicy reassembly_policy; - - uint16_t flags; - uint16_t flush_factor; - - uint32_t session_timeout; - uint32_t max_window; - uint32_t overlap_limit; - - uint32_t max_queued_bytes; - uint32_t max_queued_segs; - - uint32_t max_consec_small_segs; - uint32_t max_consec_small_seg_size; - - int hs_timeout; - int footprint; - unsigned paf_max; - - StreamTcpConfig(); - - bool require_3whs(); - bool midstream_allowed(Packet*); -}; +#include "tcp_stream_config.h" // misc stuff Session* get_tcp_session(Flow*); -StreamTcpConfig* get_tcp_cfg(Inspector*); +TcpStreamConfig* get_tcp_cfg(Inspector*); void tcp_sinit(); void tcp_sterm(); void tcp_sum(); void tcp_stats(); void tcp_reset_stats(); -void tcp_show(StreamTcpConfig*); +void tcp_show(TcpStreamConfig*); #endif diff --git a/src/stream/tcp/tcp_closed_state.cc b/src/stream/tcp/tcp_closed_state.cc deleted file mode 100644 index 201957eab..000000000 --- a/src/stream/tcp/tcp_closed_state.cc +++ /dev/null @@ -1,282 +0,0 @@ -//-------------------------------------------------------------------------- -// Copyright (C) 2015-2015 Cisco and/or its affiliates. All rights reserved. -// -// This program is free software; you can redistribute it and/or modify it -// under the terms of the GNU General Public License Version 2 as published -// by the Free Software Foundation. You may not use, modify or distribute -// this program under any other version of the GNU General Public License. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// General Public License for more details. -// -// You should have received a copy of the GNU General Public License along -// with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -//-------------------------------------------------------------------------- - -// tcp_closed_state.cc author davis mcpherson -// Created on: Jul 30, 2015 - -#include "tcp_closed_state.h" - -#include "stream/stream.h" - -#ifdef UNIT_TEST -#include "catch/catch.hpp" -#include "stream/libtcp/stream_tcp_unit_test.h" -#endif - -TcpClosedState::TcpClosedState() -{ - // TODO Auto-generated constructor stub - -} - -TcpClosedState::~TcpClosedState() -{ - // TODO Auto-generated destructor stub -} - -void TcpClosedState::syn_sent( TcpSegmentDescriptor &tcp_seg, TcpStreamTracker &tracker ) -{ - tracker.set_iss( tcp_seg.get_seq() ); - tracker.set_snd_una( tcp_seg.get_seq() + 1 ); - tracker.set_snd_nxt( tcp_seg.get_end_seq() ); - tracker.set_snd_wnd( tcp_seg.get_win() ); - tracker.set_ts_last_packet( tcp_seg.get_pkt()->pkth->ts.tv_sec ); - - tracker.set_tcp_state( TcpStreamTracker::TCP_SYN_SENT ); -} - -void TcpClosedState::syn_recv(TcpSegmentDescriptor &tcp_seg, TcpStreamTracker &tracker) -{ - default_state_action( &tcp_seg, &tracker, __func__ ); -} - -void TcpClosedState::syn_ack_sent(TcpSegmentDescriptor &tcp_seg, TcpStreamTracker &tracker) -{ - default_state_action( &tcp_seg, &tracker, __func__ ); -} - -void TcpClosedState::syn_ack_recv(TcpSegmentDescriptor &tcp_seg, TcpStreamTracker &tracker) -{ - default_state_action( &tcp_seg, &tracker, __func__ ); -} - -void TcpClosedState::ack_sent(TcpSegmentDescriptor &tcp_seg, TcpStreamTracker &tracker) -{ - default_state_action( &tcp_seg, &tracker, __func__ ); -} - -void TcpClosedState::ack_recv(TcpSegmentDescriptor &tcp_seg, TcpStreamTracker &tracker) -{ - default_state_action( &tcp_seg, &tracker, __func__ ); -} - -void TcpClosedState::data_seg_sent(TcpSegmentDescriptor &tcp_seg, TcpStreamTracker &tracker) -{ - default_state_action( &tcp_seg, &tracker, __func__ ); -} - -void TcpClosedState::data_seg_recv(TcpSegmentDescriptor &tcp_seg, TcpStreamTracker &tracker) -{ - default_state_action( &tcp_seg, &tracker, __func__ ); -} - -void TcpClosedState::fin_sent(TcpSegmentDescriptor &tcp_seg, TcpStreamTracker &tracker) -{ - default_state_action( &tcp_seg, &tracker, __func__ ); -} - -void TcpClosedState::fin_recv(TcpSegmentDescriptor &tcp_seg, TcpStreamTracker &tracker) -{ - default_state_action( &tcp_seg, &tracker, __func__ ); -} - -void TcpClosedState::rst_sent(TcpSegmentDescriptor &tcp_seg, TcpStreamTracker &tracker) -{ - default_state_action( &tcp_seg, &tracker, __func__ ); -} - -void TcpClosedState::rst_recv(TcpSegmentDescriptor &tcp_seg, TcpStreamTracker &tracker) -{ - default_state_action( &tcp_seg, &tracker, __func__ ); -} - -#ifdef UNIT_TEST - -TEST_CASE("TCP State Closed", "[tcp_closed_state][stream_tcp]") -{ - // initialization code here - Flow* flow = new Flow; - TcpStateHandler* tsh = new TcpClosedState; - TcpStreamTracker* client_tracker = new TcpStreamTracker( true ); - - SECTION("syn_packet") - { - Packet* pkt = get_syn_packet( flow ); - REQUIRE( ( pkt != nullptr ) ); - - SECTION("syn_sent") - { - flow->ssn_state.direction = FROM_CLIENT; - TcpSegmentDescriptor tcp_seg( flow, pkt ); - client_tracker->set_tcp_event( tcp_seg, client_tracker->is_client_tracker( ) ); - tsh->eval( tcp_seg, *client_tracker ); - CHECK( TcpStreamTracker::TCP_SYN_SENT_EVENT == client_tracker->get_tcp_event() ); - CHECK( ( client_tracker->get_iss() == 9050 ) ); - CHECK( ( client_tracker->get_snd_una() == 9051 ) ); - CHECK( ( client_tracker->get_snd_nxt() == 9050 ) ); - CHECK( ( client_tracker->get_snd_wnd() == 8192 ) ); - } - - SECTION("syn_recv") - { - flow->ssn_state.direction = FROM_SERVER; - TcpSegmentDescriptor tcp_seg( flow, pkt ); - client_tracker->set_tcp_event( tcp_seg, client_tracker->is_client_tracker( ) ); - tsh->eval( tcp_seg, *client_tracker ); - CHECK( ( tsh->get_tcp_event() == client_tracker->get_tcp_event() ) ); - } - - delete pkt; - } - - SECTION("syn_ack_packet") - { - Packet* pkt = get_syn_ack_packet( flow ); - REQUIRE( ( pkt != nullptr ) ); - - SECTION("syn_ack_sent") - { - flow->ssn_state.direction = FROM_CLIENT; - TcpSegmentDescriptor tcp_seg( flow, pkt ); - client_tracker->set_tcp_event( tcp_seg, client_tracker->is_client_tracker( ) ); - tsh->eval( tcp_seg, *client_tracker ); - CHECK( ( tsh->get_tcp_event() == client_tracker->get_tcp_event() ) ); - } - - SECTION("syn_ack_recv") - { - flow->ssn_state.direction = FROM_SERVER; - TcpSegmentDescriptor tcp_seg( flow, pkt ); - client_tracker->set_tcp_event( tcp_seg, client_tracker->is_client_tracker( ) ); - tsh->eval( tcp_seg, *client_tracker ); - CHECK( ( tsh->get_tcp_event() == client_tracker->get_tcp_event() ) ); - } - - delete pkt; - } - - SECTION("ack_packet") - { - Packet* pkt = get_ack_packet( flow ); - REQUIRE( ( pkt != nullptr ) ); - - SECTION("ack_sent") - { - flow->ssn_state.direction = FROM_CLIENT; - TcpSegmentDescriptor tcp_seg( flow, pkt ); - client_tracker->set_tcp_event( tcp_seg, client_tracker->is_client_tracker( ) ); - tsh->eval( tcp_seg, *client_tracker ); - CHECK( ( tsh->get_tcp_event() == client_tracker->get_tcp_event() ) ); - } - - SECTION("ack_recv") - { - flow->ssn_state.direction = FROM_SERVER; - TcpSegmentDescriptor tcp_seg( flow, pkt ); - client_tracker->set_tcp_event( tcp_seg, client_tracker->is_client_tracker( ) ); - tsh->eval( tcp_seg, *client_tracker ); - CHECK( ( tsh->get_tcp_event() == client_tracker->get_tcp_event() ) ); - } - - delete pkt; - } - - SECTION("data_seg_packet") - { - Packet* pkt = get_data_packet( flow ); - REQUIRE( ( pkt != nullptr ) ); - - SECTION("data_seg_sent") - { - flow->ssn_state.direction = FROM_CLIENT; - TcpSegmentDescriptor tcp_seg( flow, pkt ); - client_tracker->set_tcp_event( tcp_seg, client_tracker->is_client_tracker( ) ); - tsh->eval( tcp_seg, *client_tracker ); - CHECK( ( tsh->get_tcp_event() == client_tracker->get_tcp_event() ) ); - } - - SECTION("data_seg_recv") - { - flow->ssn_state.direction = FROM_SERVER; - TcpSegmentDescriptor tcp_seg( flow, pkt ); - client_tracker->set_tcp_event( tcp_seg, client_tracker->is_client_tracker( ) ); - tsh->eval( tcp_seg, *client_tracker ); - CHECK( ( tsh->get_tcp_event() == client_tracker->get_tcp_event() ) ); - } - - delete pkt; - } - - SECTION("fin_packet") - { - Packet* pkt = get_fin_packet( flow ); - REQUIRE( ( pkt != nullptr ) ); - - SECTION("fin_sent") - { - flow->ssn_state.direction = FROM_CLIENT; - TcpSegmentDescriptor tcp_seg( flow, pkt ); - client_tracker->set_tcp_event( tcp_seg, client_tracker->is_client_tracker( ) ); - tsh->eval( tcp_seg, *client_tracker ); - CHECK( ( tsh->get_tcp_event() == client_tracker->get_tcp_event() ) ); - } - - SECTION("fin_recv") - { - flow->ssn_state.direction = FROM_SERVER; - TcpSegmentDescriptor tcp_seg( flow, pkt ); - client_tracker->set_tcp_event( tcp_seg, client_tracker->is_client_tracker( ) ); - tsh->eval( tcp_seg, *client_tracker ); - CHECK( ( tsh->get_tcp_event() == client_tracker->get_tcp_event() ) ); - } - - delete pkt; - } - - SECTION("rst_packet") - { - Packet* pkt = get_rst_packet( flow ); - REQUIRE( ( pkt != nullptr )); - - SECTION("rst_sent") - { - flow->ssn_state.direction = FROM_CLIENT; - TcpSegmentDescriptor tcp_seg( flow, pkt ); - client_tracker->set_tcp_event( tcp_seg, client_tracker->is_client_tracker( ) ); - tsh->eval( tcp_seg, *client_tracker ); - CHECK( ( tsh->get_tcp_event() == client_tracker->get_tcp_event() )); - } - - SECTION("rst_recv") - { - flow->ssn_state.direction = FROM_SERVER; - TcpSegmentDescriptor tcp_seg( flow, pkt ); - client_tracker->set_tcp_event( tcp_seg, client_tracker->is_client_tracker( ) ); - tsh->eval( tcp_seg, *client_tracker ); - CHECK( ( tsh->get_tcp_event() == client_tracker->get_tcp_event() ) ); - } - - delete pkt; - } - - delete flow; - delete tsh; - delete client_tracker; -} - -#endif diff --git a/src/stream/tcp/tcp_closed_state.h b/src/stream/tcp/tcp_closed_state.h deleted file mode 100644 index b545738ed..000000000 --- a/src/stream/tcp/tcp_closed_state.h +++ /dev/null @@ -1,47 +0,0 @@ -//-------------------------------------------------------------------------- -// Copyright (C) 2015-2015 Cisco and/or its affiliates. All rights reserved. -// -// This program is free software; you can redistribute it and/or modify it -// under the terms of the GNU General Public License Version 2 as published -// by the Free Software Foundation. You may not use, modify or distribute -// this program under any other version of the GNU General Public License. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// General Public License for more details. -// -// You should have received a copy of the GNU General Public License along -// with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -//-------------------------------------------------------------------------- - -// tcp_closed_state.h author davis mcpherson -// Created on: Jul 30, 2015 - -#ifndef TCP_CLOSED_STATE_H -#define TCP_CLOSED_STATE_H - -#include "stream/libtcp/tcp_state_handler.h" - -class TcpClosedState: public TcpStateHandler -{ -public: - TcpClosedState(); - virtual ~TcpClosedState(); - - void syn_sent(TcpSegmentDescriptor&, TcpStreamTracker&); - void syn_recv(TcpSegmentDescriptor&, TcpStreamTracker&); - void syn_ack_sent(TcpSegmentDescriptor&, TcpStreamTracker&); - void syn_ack_recv(TcpSegmentDescriptor&, TcpStreamTracker&); - void ack_sent(TcpSegmentDescriptor&, TcpStreamTracker&); - void ack_recv(TcpSegmentDescriptor&, TcpStreamTracker&); - void data_seg_sent(TcpSegmentDescriptor&, TcpStreamTracker&); - void data_seg_recv(TcpSegmentDescriptor&, TcpStreamTracker&); - void fin_sent(TcpSegmentDescriptor&, TcpStreamTracker&); - void fin_recv(TcpSegmentDescriptor&, TcpStreamTracker&); - void rst_sent(TcpSegmentDescriptor&, TcpStreamTracker&); - void rst_recv(TcpSegmentDescriptor&, TcpStreamTracker&); -}; - -#endif diff --git a/src/stream/tcp/tcp_debug_trace.h b/src/stream/tcp/tcp_debug_trace.h index b101e45b6..b852995a9 100644 --- a/src/stream/tcp/tcp_debug_trace.h +++ b/src/stream/tcp/tcp_debug_trace.h @@ -26,15 +26,15 @@ #include "tcp_reassembler.h" #ifndef REG_TEST -#define S5TraceTCP(pkt, flow, tdb, evt) +#define S5TraceTCP(pkt, flow, tsd, evt) #else -#define LCL(p, x) (p->x - p->isn) -#define RMT(p, x, q) (p->x - (q ? q->isn : 0)) +#define LCL(p, x) (p->x() - p->get_iss()) +#define RMT(p, x, q) (p->x - (q ? q->get_iss() : 0)) static const char* const statext[] = { - "NON", "LST", "SYR", "SYS", "EST", "CLW", - "LAK", "FW1", "CLG", "FW2", "TWT", "CLD" + "LST", "SYS", "SYR", "EST", "FW1", "FW2", "CLW", + "CLG", "LAK", "TWT", "CLD", "NON" }; static const char* const flushxt[] = { "IGN", "FPR", "PRE", "PRO", "PAF" }; @@ -42,7 +42,7 @@ static const char* const flushxt[] = { "IGN", "FPR", "PRE", "PRO", "PAF" }; // FIXIT-L this should not be thread specific static THREAD_LOCAL int s5_trace_enabled = -1; -static inline void TraceEvent(const Packet* p, TcpDataBlock*, uint32_t txd, uint32_t rxd) +static inline void TraceEvent(const Packet* p, TcpSegmentDescriptor*, uint32_t txd, uint32_t rxd) { int i; char flags[7] = "UAPRSF"; @@ -66,34 +66,37 @@ static inline void TraceEvent(const Packet* p, TcpDataBlock*, uint32_t txd, uint order = " (oos)"; 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); + //"\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); } static inline void TraceSession(const Flow* lws) { - fprintf( stdout, " LWS: ST=0x%x SF=0x%x CP=%u SP=%u\n", (unsigned)lws->session_state, - lws->ssn_state.session_flags, lws->client_port, lws->server_port ); + fprintf(stdout, " LWS: ST=0x%x SF=0x%x CP=%u SP=%u\n", (unsigned)lws->session_state, + lws->ssn_state.session_flags, lws->client_port, lws->server_port); } static inline void TraceState(const TcpTracker* a, const TcpTracker* b, const char* s) { - uint32_t why = a->l_nxt_seq ? LCL(a, l_nxt_seq) : 0; + uint32_t why = 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->s_mgr.state], - a->s_mgr.sub_state, LCL(a, l_unackd), why, a->l_window, 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 ", 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)); - if (a->s_mgr.state_queue) - fprintf(stdout, "QS=%s QC=0x%02x QA=%-4u", statext[a->s_mgr.state_queue], a->s_mgr.expected_flags, - RMT(a, s_mgr.transition_seq, b)); + 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], + a->s_mgr.expected_flags, RMT(a, s_mgr.transition_seq, b)); fprintf(stdout, "\n"); unsigned paf = (a->splitter and a->splitter->is_paf()) ? 2 : 0; unsigned fpt = a->flush_policy ? 192 : 0; - fprintf( stdout, " FP=%s:%-4u SC=%-4u FL=%-4u SL=%-5u BS=%-4u", flushxt[a->flush_policy + paf], fpt, - a->reassembler->get_seg_count(), a->reassembler->get_flush_count(), - a->reassembler->get_seg_bytes_logical(), a->reassembler->get_seglist_base_seq() - b->isn); + fprintf(stdout, " FP=%s:%-4u SC=%-4u FL=%-4u SL=%-5u BS=%-4u", + flushxt[a->flush_policy + paf], fpt, + a->reassembler->get_seg_count(), a->reassembler->get_flush_count(), + a->reassembler->get_seg_bytes_logical(), + a->reassembler->get_seglist_base_seq() - b->get_iss()); if (s5_trace_enabled == 2) a->reassembler->trace_segments(); @@ -101,13 +104,13 @@ static inline void TraceState(const TcpTracker* a, const TcpTracker* b, const ch fprintf(stdout, "\n"); } -static inline void TraceTCP(const Packet* p, const Flow* lws, TcpDataBlock* tdb, int event) +static inline void TraceTCP(const Packet* p, const Flow* lws, TcpSegmentDescriptor* tsd, int event) { - const TcpSession* ssn = (TcpSession*) lws->session; - const TcpTracker* srv = ssn ? &ssn->server : NULL; - const TcpTracker* cli = ssn ? &ssn->client : NULL; + const TcpSession* ssn = (TcpSession*)lws->session; + const TcpTracker* srv = ssn ? ssn->server : NULL; + const TcpTracker* cli = ssn ? ssn->client : NULL; - const char* cdir = "?", *sdir = "?"; + const char* cdir = "?", * sdir = "?"; uint32_t txd = 0, rxd = 0; if (p->packet_flags & PKT_FROM_SERVER) @@ -117,21 +120,22 @@ static inline void TraceTCP(const Packet* p, const Flow* lws, TcpDataBlock* tdb, if (ssn->tcp_init) { - txd = srv->isn; - rxd = cli->isn; + txd = srv->get_iss(); + rxd = cli->get_iss(); } - } else if (p->packet_flags & PKT_FROM_CLIENT) + } + else if (p->packet_flags & PKT_FROM_CLIENT) { sdir = "SRV<"; cdir = "CLI>"; if (ssn->tcp_init) { - txd = cli->isn; - rxd = srv->isn; + txd = cli->get_iss(); + rxd = srv->get_iss(); } } - TraceEvent(p, tdb, txd, rxd); + TraceEvent(p, tsd, txd, rxd); if (!ssn->tcp_init) return; @@ -146,7 +150,8 @@ static inline void TraceTCP(const Packet* p, const Flow* lws, TcpDataBlock* tdb, } } -static inline void S5TraceTCP(const Packet* p, const Flow* lws, TcpDataBlock* tdb, int event) +static inline void S5TraceTCP(const Packet* p, const Flow* lws, TcpSegmentDescriptor* tsd, int + event) { if (!s5_trace_enabled) return; @@ -165,8 +170,9 @@ static inline void S5TraceTCP(const Packet* p, const Flow* lws, TcpDataBlock* td s5_trace_enabled = atoi(s5t); } - TraceTCP(p, lws, tdb, event); + TraceTCP(p, lws, tsd, event); } + #endif // REG_TEST #endif diff --git a/src/stream/tcp/tcp_defs.h b/src/stream/tcp/tcp_defs.h index 3cd9dc277..c8b0e5f1b 100644 --- a/src/stream/tcp/tcp_defs.h +++ b/src/stream/tcp/tcp_defs.h @@ -16,7 +16,7 @@ // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. //-------------------------------------------------------------------------- -// tcp_defs.h author davis mcpherson +// tcp_defs.h author davis mcpherson // Created on: Jul 31, 2015 #ifndef TCP_DEFS_H @@ -25,6 +25,7 @@ #include "main/snort_debug.h" #include "protocols/packet.h" +#if 0 /* TCP states */ #define TCP_STATE_NONE 0 #define TCP_STATE_LISTEN 1 @@ -38,6 +39,7 @@ #define TCP_STATE_FIN_WAIT_2 9 #define TCP_STATE_TIME_WAIT 10 #define TCP_STATE_CLOSED 11 +#endif /* actions */ #define ACTION_NOTHING 0x00000000 @@ -54,7 +56,6 @@ #define ACTION_LWSSN_CLOSED 0x00000800 #define ACTION_DISABLE_INSPECTION 0x00001000 - #define TF_NONE 0x0000 #define TF_WSCALE 0x0001 #define TF_TSTAMP 0x0002 @@ -75,6 +76,18 @@ #define SUB_RST_SENT 0x04 #define SUB_FIN_SENT 0x08 +#define STREAM_UNALIGNED 0 +#define STREAM_ALIGNED 1 + +#define STREAM_DEFAULT_MAX_QUEUED_BYTES 1048576 /* 1 MB */ +#define AVG_PKT_SIZE 400 +#define STREAM_DEFAULT_MAX_QUEUED_SEGS ( STREAM_DEFAULT_MAX_QUEUED_BYTES / AVG_PKT_SIZE ) + +#define STREAM_DEFAULT_MAX_SMALL_SEG_SIZE 0 /* disabled */ +#define STREAM_DEFAULT_CONSEC_SMALL_SEGS 0 /* disabled */ + +#define SLAM_MAX 4 + // target-based policy types - changes to this enum require changes to stream_api.h::TCP_POLICIES enum class StreamPolicy { @@ -98,9 +111,9 @@ enum class StreamPolicy }; // increment operator... -inline StreamPolicy& operator++( StreamPolicy &c ) +inline StreamPolicy& operator++(StreamPolicy& c) { - if( c < StreamPolicy::OS_END_OF_LIST ) + if ( c < StreamPolicy::OS_END_OF_LIST ) c = static_cast( static_cast(c) + 1 ); else c = StreamPolicy::OS_END_OF_LIST; @@ -130,9 +143,9 @@ enum class ReassemblyPolicy }; // increment operator... -inline ReassemblyPolicy& operator++( ReassemblyPolicy &c ) +inline ReassemblyPolicy& operator++(ReassemblyPolicy& c) { - if( c < ReassemblyPolicy::OS_END_OF_LIST ) + if ( c < ReassemblyPolicy::OS_END_OF_LIST ) c = static_cast( static_cast(c) + 1 ); else c = ReassemblyPolicy::OS_END_OF_LIST; @@ -147,6 +160,7 @@ enum FlushPolicy STREAM_FLPOLICY_ON_DATA, /* protocol aware ips */ }; +#if 0 struct TcpDataBlock { Packet* pkt; @@ -156,7 +170,7 @@ struct TcpDataBlock uint32_t end_seq; uint32_t ts; }; - +#endif //#define DEBUG_STREAM_EX #ifdef DEBUG_STREAM_EX @@ -166,3 +180,4 @@ struct TcpDataBlock #endif #endif + diff --git a/src/stream/tcp/tcp_events.h b/src/stream/tcp/tcp_event_logger.cc similarity index 58% rename from src/stream/tcp/tcp_events.h rename to src/stream/tcp/tcp_event_logger.cc index 7ed4a3499..b43d3a590 100644 --- a/src/stream/tcp/tcp_events.h +++ b/src/stream/tcp/tcp_event_logger.cc @@ -16,222 +16,209 @@ // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. //-------------------------------------------------------------------------- -// tcp_events.h author davis mcpherson +// tcp_events.cc author davis mcpherson // Created on: Jul 30, 2015 -#ifndef TCP_EVENTS_H -#define TCP_EVENTS_H - #include "main/snort_config.h" #include "events/event_queue.h" #include "filters/sfrf.h" #include "detection/rules.h" + #include "tcp_defs.h" #include "tcp_module.h" +#include "tcp_event_logger.h" + +void TcpEventLogger::set_tcp_internal_syn_event(void) +{ + tcp_events |= INTERNAL_EVENT_SYN_RECEIVED; +} -/* events */ -#define EVENT_SYN_ON_EST 0x00000001 -#define EVENT_DATA_ON_SYN 0x00000002 -#define EVENT_DATA_ON_CLOSED 0x00000004 -#define EVENT_BAD_TIMESTAMP 0x00000008 -#define EVENT_WINDOW_TOO_LARGE 0x00000010 -#define EVENT_DATA_AFTER_RESET 0x00000020 -#define EVENT_SESSION_HIJACK_CLIENT 0x00000040 -#define EVENT_SESSION_HIJACK_SERVER 0x00000080 -#define EVENT_DATA_WITHOUT_FLAGS 0x00000100 -#define EVENT_4WHS 0x00000200 -#define EVENT_NO_TIMESTAMP 0x00000400 -#define EVENT_BAD_RST 0x00000800 -#define EVENT_BAD_FIN 0x00001000 -#define EVENT_BAD_ACK 0x00002000 -#define EVENT_DATA_AFTER_RST_RCVD 0x00004000 -#define EVENT_WINDOW_SLAM 0x00008000 -#define EVENT_NO_3WHS 0x00010000 - -static inline void EventSynOnEst() +void TcpEventLogger::EventSynOnEst(void) { SnortEventqAdd(GID_STREAM_TCP, STREAM_TCP_SYN_ON_EST); tcpStats.events++; } -static inline void EventExcessiveOverlap() +void TcpEventLogger::EventExcessiveOverlap(void) { SnortEventqAdd(GID_STREAM_TCP, STREAM_TCP_EXCESSIVE_TCP_OVERLAPS); tcpStats.events++; } -static inline void EventBadTimestamp() +void TcpEventLogger::EventBadTimestamp(void) { SnortEventqAdd(GID_STREAM_TCP, STREAM_TCP_BAD_TIMESTAMP); tcpStats.events++; } -static inline void EventWindowTooLarge() +void TcpEventLogger::EventWindowTooLarge(void) { SnortEventqAdd(GID_STREAM_TCP, STREAM_TCP_WINDOW_TOO_LARGE); tcpStats.events++; } -static inline void EventDataOnSyn() +void TcpEventLogger::EventDataOnSyn(void) { SnortEventqAdd(GID_STREAM_TCP, STREAM_TCP_DATA_ON_SYN); tcpStats.events++; } -static inline void EventDataOnClosed() +void TcpEventLogger::EventDataOnClosed(void) { SnortEventqAdd(GID_STREAM_TCP, STREAM_TCP_DATA_ON_CLOSED); tcpStats.events++; } -static inline void EventDataAfterReset() +void TcpEventLogger::EventDataAfterReset(void) { SnortEventqAdd(GID_STREAM_TCP, STREAM_TCP_DATA_AFTER_RESET); tcpStats.events++; } -static inline void EventBadSegment() +void TcpEventLogger::EventBadSegment(void) { SnortEventqAdd(GID_STREAM_TCP, STREAM_TCP_BAD_SEGMENT); tcpStats.events++; } -static inline void EventSessionHijackedClient() +void TcpEventLogger::EventSessionHijackedClient(void) { SnortEventqAdd(GID_STREAM_TCP, STREAM_TCP_SESSION_HIJACKED_CLIENT); tcpStats.events++; } -static inline void EventSessionHijackedServer() +void TcpEventLogger::EventSessionHijackedServer(void) { SnortEventqAdd(GID_STREAM_TCP, STREAM_TCP_SESSION_HIJACKED_SERVER); tcpStats.events++; } -static inline void EventDataWithoutFlags() +void TcpEventLogger::EventDataWithoutFlags(void) { SnortEventqAdd(GID_STREAM_TCP, STREAM_TCP_DATA_WITHOUT_FLAGS); tcpStats.events++; } -static inline void EventMaxSmallSegsExceeded() +void TcpEventLogger::EventMaxSmallSegsExceeded(void) { SnortEventqAdd(GID_STREAM_TCP, STREAM_TCP_SMALL_SEGMENT); tcpStats.events++; } -static inline void Event4whs() +void TcpEventLogger::Event4whs(void) { SnortEventqAdd(GID_STREAM_TCP, STREAM_TCP_4WAY_HANDSHAKE); tcpStats.events++; } -static inline void EventNoTimestamp() +void TcpEventLogger::EventNoTimestamp(void) { SnortEventqAdd(GID_STREAM_TCP, STREAM_TCP_NO_TIMESTAMP); tcpStats.events++; } -static inline void EventBadReset() +void TcpEventLogger::EventBadReset(void) { SnortEventqAdd(GID_STREAM_TCP, STREAM_TCP_BAD_RST); tcpStats.events++; } -static inline void EventBadFin() +void TcpEventLogger::EventBadFin(void) { SnortEventqAdd(GID_STREAM_TCP, STREAM_TCP_BAD_FIN); tcpStats.events++; } -static inline void EventBadAck() +void TcpEventLogger::EventBadAck(void) { SnortEventqAdd(GID_STREAM_TCP, STREAM_TCP_BAD_ACK); tcpStats.events++; } -static inline void EventDataAfterRstRcvd() +void TcpEventLogger::EventDataAfterRstRcvd(void) { SnortEventqAdd(GID_STREAM_TCP, STREAM_TCP_DATA_AFTER_RST_RCVD); tcpStats.events++; } -static inline void EventInternal(uint32_t eventSid) +void TcpEventLogger::EventInternal(uint32_t eventSid) { if (!InternalEventIsEnabled(snort_conf->rate_filter_config, eventSid)) return; tcpStats.internalEvents++; - STREAM_DEBUG_WRAP( DebugMessage(DEBUG_STREAM_STATE, "Stream raised internal event %d\n", eventSid); ); + STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Stream raised internal event %d\n", + eventSid); ); SnortEventqAdd(GENERATOR_INTERNAL, eventSid); } -static inline void EventWindowSlam() +void TcpEventLogger::EventWindowSlam(void) { SnortEventqAdd(GID_STREAM_TCP, STREAM_TCP_WINDOW_SLAM); tcpStats.events++; } -static inline void EventNo3whs() +void TcpEventLogger::EventNo3whs(void) { SnortEventqAdd(GID_STREAM_TCP, STREAM_TCP_NO_3WHS); tcpStats.events++; } -static inline void LogTcpEvents(int eventcode) +void TcpEventLogger::log_tcp_events(void) { - if (!eventcode) + if ( !tcp_events ) return; - if (eventcode & EVENT_SYN_ON_EST) + if (tcp_events & EVENT_SYN_ON_EST) EventSynOnEst(); - if (eventcode & EVENT_DATA_ON_SYN) + if (tcp_events & EVENT_DATA_ON_SYN) EventDataOnSyn(); - if (eventcode & EVENT_DATA_ON_CLOSED) + if (tcp_events & EVENT_DATA_ON_CLOSED) EventDataOnClosed(); - if (eventcode & EVENT_BAD_TIMESTAMP) + if (tcp_events & EVENT_BAD_TIMESTAMP) EventBadTimestamp(); - if (eventcode & EVENT_WINDOW_TOO_LARGE) + if (tcp_events & EVENT_WINDOW_TOO_LARGE) EventWindowTooLarge(); - if (eventcode & EVENT_DATA_AFTER_RESET) + if (tcp_events & EVENT_DATA_AFTER_RESET) EventDataAfterReset(); - if (eventcode & EVENT_SESSION_HIJACK_CLIENT) + if (tcp_events & EVENT_SESSION_HIJACK_CLIENT) EventSessionHijackedClient(); - if (eventcode & EVENT_SESSION_HIJACK_SERVER) + if (tcp_events & EVENT_SESSION_HIJACK_SERVER) EventSessionHijackedServer(); - if (eventcode & EVENT_DATA_WITHOUT_FLAGS) + if (tcp_events & EVENT_DATA_WITHOUT_FLAGS) EventDataWithoutFlags(); - if (eventcode & EVENT_4WHS) + if (tcp_events & EVENT_4WHS) Event4whs(); - if (eventcode & EVENT_NO_TIMESTAMP) + if (tcp_events & EVENT_NO_TIMESTAMP) EventNoTimestamp(); - if (eventcode & EVENT_BAD_RST) + if (tcp_events & EVENT_BAD_RST) EventBadReset(); - if (eventcode & EVENT_BAD_FIN) + if (tcp_events & EVENT_BAD_FIN) EventBadFin(); - if (eventcode & EVENT_BAD_ACK) + if (tcp_events & EVENT_BAD_ACK) EventBadAck(); - if (eventcode & EVENT_DATA_AFTER_RST_RCVD) + if (tcp_events & EVENT_DATA_AFTER_RST_RCVD) EventDataAfterRstRcvd(); - if (eventcode & EVENT_WINDOW_SLAM) + if (tcp_events & EVENT_WINDOW_SLAM) EventWindowSlam(); + + tcp_events = 0; } -#endif diff --git a/src/stream/tcp/tcp_event_logger.h b/src/stream/tcp/tcp_event_logger.h new file mode 100644 index 000000000..1a2622928 --- /dev/null +++ b/src/stream/tcp/tcp_event_logger.h @@ -0,0 +1,95 @@ +//-------------------------------------------------------------------------- +// Copyright (C) 2014-2015 Cisco and/or its affiliates. All rights reserved. +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License Version 2 as published +// by the Free Software Foundation. You may not use, modify or distribute +// this program under any other version of the GNU General Public License. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +//-------------------------------------------------------------------------- + +// tcp_events.h author davis mcpherson +// Created on: Jul 30, 2015 + +#ifndef TCP_EVENT_LOGGER_H +#define TCP_EVENT_LOGGER_H + +/* events */ +#define EVENT_SYN_ON_EST 0x00000001 +#define EVENT_DATA_ON_SYN 0x00000002 +#define EVENT_DATA_ON_CLOSED 0x00000004 +#define EVENT_BAD_TIMESTAMP 0x00000008 +#define EVENT_WINDOW_TOO_LARGE 0x00000010 +#define EVENT_DATA_AFTER_RESET 0x00000020 +#define EVENT_SESSION_HIJACK_CLIENT 0x00000040 +#define EVENT_SESSION_HIJACK_SERVER 0x00000080 +#define EVENT_DATA_WITHOUT_FLAGS 0x00000100 +#define EVENT_4WHS 0x00000200 +#define EVENT_NO_TIMESTAMP 0x00000400 +#define EVENT_BAD_RST 0x00000800 +#define EVENT_BAD_FIN 0x00001000 +#define EVENT_BAD_ACK 0x00002000 +#define EVENT_DATA_AFTER_RST_RCVD 0x00004000 +#define EVENT_WINDOW_SLAM 0x00008000 +#define EVENT_NO_3WHS 0x00010000 + +class TcpEventLogger +{ +public: + TcpEventLogger(void) : + tcp_events(0) + { + } + + ~TcpEventLogger(void) + { + } + + void clear_tcp_events(void) + { + tcp_events = 0; + } + + void set_tcp_event(int eventcode) + { + tcp_events |= eventcode; + } + + void set_tcp_internal_syn_event(void); + + void EventSynOnEst(void); + void EventExcessiveOverlap(void); + void EventBadTimestamp(void); + void EventWindowTooLarge(void); + void EventDataOnSyn(void); + void EventDataOnClosed(void); + void EventDataAfterReset(void); + void EventBadSegment(void); + void EventSessionHijackedClient(void); + void EventSessionHijackedServer(void); + void EventDataWithoutFlags(void); + void EventMaxSmallSegsExceeded(void); + void Event4whs(void); + void EventNoTimestamp(void); + void EventBadReset(void); + void EventBadFin(void); + void EventBadAck(void); + void EventDataAfterRstRcvd(void); + void EventInternal(uint32_t eventSid); + void EventWindowSlam(void); + void EventNo3whs(void); + void log_tcp_events(void); + +private: + uint32_t tcp_events; +}; +#endif + diff --git a/src/stream/tcp/tcp_listen_state.cc b/src/stream/tcp/tcp_listen_state.cc deleted file mode 100644 index 785d3c3af..000000000 --- a/src/stream/tcp/tcp_listen_state.cc +++ /dev/null @@ -1,34 +0,0 @@ -//-------------------------------------------------------------------------- -// Copyright (C) 2015-2015 Cisco and/or its affiliates. All rights reserved. -// -// This program is free software; you can redistribute it and/or modify it -// under the terms of the GNU General Public License Version 2 as published -// by the Free Software Foundation. You may not use, modify or distribute -// this program under any other version of the GNU General Public License. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// General Public License for more details. -// -// You should have received a copy of the GNU General Public License along -// with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -//-------------------------------------------------------------------------- - -// tcp_listen_state.cc author davis mcpherson -// Created on: Jul 30, 2015 - -#include "tcp_listen_state.h" - -TcpListenState::TcpListenState() -{ - // TODO Auto-generated constructor stub - -} - -TcpListenState::~TcpListenState() -{ - // TODO Auto-generated destructor stub -} - diff --git a/src/stream/tcp/tcp_module.cc b/src/stream/tcp/tcp_module.cc index 19fc33512..70cd28f88 100644 --- a/src/stream/tcp/tcp_module.cc +++ b/src/stream/tcp/tcp_module.cc @@ -41,7 +41,8 @@ THREAD_LOCAL ProfileStats s5TcpPAFPerfStats; THREAD_LOCAL ProfileStats s5TcpFlushPerfStats; THREAD_LOCAL ProfileStats s5TcpBuildPacketPerfStats; -const PegInfo tcp_pegs[] = { +const PegInfo tcp_pegs[] = +{ { "sessions", "total sessions" }, { "timeouts", "sessions timed out" }, { "resyns", "SYN received on established session" }, @@ -267,9 +268,9 @@ ProfileStats* StreamTcpModule::get_profile( return nullptr; } -StreamTcpConfig* StreamTcpModule::get_data() +TcpStreamConfig* StreamTcpModule::get_data() { - StreamTcpConfig* temp = config; + TcpStreamConfig* temp = config; config = nullptr; return temp; } @@ -347,7 +348,7 @@ bool StreamTcpModule::begin(const char* fqn, int, SnortConfig*) if ( config ) return false; - config = new StreamTcpConfig; + config = new TcpStreamConfig; return true; } diff --git a/src/stream/tcp/tcp_module.h b/src/stream/tcp/tcp_module.h index f7707cf28..cd07f94c5 100644 --- a/src/stream/tcp/tcp_module.h +++ b/src/stream/tcp/tcp_module.h @@ -28,6 +28,7 @@ #include "main/thread.h" #include "framework/module.h" #include "stream/stream.h" +#include "tcp_stream_config.h" #define GID_STREAM_TCP 129 @@ -100,6 +101,7 @@ static inline void inc_tcp_discards() { tcpStats.discards++; } + //------------------------------------------------------------------------- // stream_tcp module //------------------------------------------------------------------------- @@ -108,9 +110,8 @@ static inline void inc_tcp_discards() #define MOD_HELP "stream inspector for TCP flow tracking and stream normalization and reassembly" struct SnortConfig; -struct StreamTcpConfig; -class StreamTcpModule: public Module +class StreamTcpModule : public Module { public: StreamTcpModule(); @@ -127,15 +128,15 @@ public: return GID_STREAM_TCP; } - StreamTcpConfig* get_data(); + TcpStreamConfig* get_data(); ProfileStats* get_profile(unsigned, const char*&, const char*&) const - override; + override; const PegInfo* get_pegs() const override; PegCount* get_counts() const override; private: - StreamTcpConfig* config; + TcpStreamConfig* config; }; #endif diff --git a/src/stream/tcp/tcp_normalizer.cc b/src/stream/tcp/tcp_normalizer.cc index 51f1dc119..8b98ae46d 100644 --- a/src/stream/tcp/tcp_normalizer.cc +++ b/src/stream/tcp/tcp_normalizer.cc @@ -22,7 +22,7 @@ #include "packet_io/active.h" #include "tcp_normalizer.h" -#include "tcp_events.h" +#include "tcp_event_logger.h" THREAD_LOCAL PegCount normStats[PC_MAX][NORM_MODE_MAX]; @@ -44,18 +44,18 @@ static inline int SetupOK(const TcpTracker* st) return ((st->s_mgr.sub_state & SUB_SETUP_OK) == SUB_SETUP_OK); } -TcpNormalizer::TcpNormalizer( StreamPolicy os_policy, TcpSession* session, TcpTracker* tracker ) : - os_policy( os_policy ), session( session ), tracker( tracker ), - peer_tracker( nullptr ) +TcpNormalizer::TcpNormalizer(StreamPolicy os_policy, TcpSession* session, TcpTracker* tracker) : + os_policy(os_policy), session(session), tracker(tracker), + peer_tracker(nullptr) { - tcp_ips_enabled = Normalize_IsEnabled( NORM_TCP_IPS ); - trim_syn = Normalize_GetMode( NORM_TCP_TRIM_SYN ); - trim_rst = Normalize_GetMode( NORM_TCP_TRIM_RST ); - trim_win = Normalize_GetMode( NORM_TCP_TRIM_WIN ); - trim_mss = Normalize_GetMode( NORM_TCP_TRIM_MSS ); - strip_ecn = Normalize_GetMode( NORM_TCP_ECN_STR ); - tcp_block = Normalize_GetMode( NORM_TCP_BLOCK ); - opt_block = Normalize_GetMode( NORM_TCP_OPT ); + tcp_ips_enabled = Normalize_IsEnabled(NORM_TCP_IPS); + trim_syn = Normalize_GetMode(NORM_TCP_TRIM_SYN); + trim_rst = Normalize_GetMode(NORM_TCP_TRIM_RST); + trim_win = Normalize_GetMode(NORM_TCP_TRIM_WIN); + trim_mss = Normalize_GetMode(NORM_TCP_TRIM_MSS); + 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; @@ -73,14 +73,14 @@ NormPegs TcpNormalizer::get_normalization_counts(unsigned& c) } void TcpNormalizer::trim_payload( - TcpDataBlock* tdb, uint32_t max, NormMode mode, PegCounts peg, PerfCounts perfc) + TcpSegmentDescriptor& tsd, uint32_t max, NormMode mode, PegCounts peg, PerfCounts perfc) { if (mode == NORM_MODE_ON) { - uint16_t fat = tdb->pkt->dsize - max; - tdb->pkt->dsize = max; - tdb->pkt->packet_flags |= (PKT_MODIFIED | PKT_RESIZED); - tdb->end_seq -= fat; + uint16_t fat = tsd.get_pkt()->dsize - max; + tsd.get_pkt()->dsize = max; + tsd.get_pkt()->packet_flags |= (PKT_MODIFIED | PKT_RESIZED); + tsd.set_end_seq(tsd.get_end_seq() - fat); } normStats[peg][mode]++; @@ -88,22 +88,23 @@ void TcpNormalizer::trim_payload( } bool TcpNormalizer::strip_tcp_timestamp( - TcpDataBlock* tdb, const tcp::TcpOption* opt, NormMode mode) + TcpSegmentDescriptor& tsd, const tcp::TcpOption* opt, NormMode mode) { - normStats[PC_TCP_TS_NOP][mode]++; - sfBase.iPegs[PERF_COUNT_TCP_TS_NOP][mode]++; - - if (mode == NORM_MODE_ON) - { - // set raw option bytes to nops - memset((void *) opt, (uint32_t) tcp::TcpOptCode::NOP, tcp::TCPOLEN_TIMESTAMP); - tdb->pkt->packet_flags |= PKT_MODIFIED; - return true; - } - - return false; - } -bool TcpNormalizer::packet_dropper(TcpDataBlock* tdb, NormFlags f) + normStats[PC_TCP_TS_NOP][mode]++; + sfBase.iPegs[PERF_COUNT_TCP_TS_NOP][mode]++; + + if (mode == NORM_MODE_ON) + { + // set raw option bytes to nops + memset((void*)opt, (uint32_t)tcp::TcpOptCode::NOP, tcp::TCPOLEN_TIMESTAMP); + tsd.get_pkt()->packet_flags |= PKT_MODIFIED; + return true; + } + + return false; +} + +bool TcpNormalizer::packet_dropper(TcpSegmentDescriptor& tsd, NormFlags f) { const NormMode mode = (f == NORM_TCP_BLOCK) ? tcp_block : opt_block; @@ -112,55 +113,55 @@ bool TcpNormalizer::packet_dropper(TcpDataBlock* tdb, NormFlags f) if (mode == NORM_MODE_ON) { - Active::drop_packet(tdb->pkt); + Active::drop_packet(tsd.get_pkt()); return true; } return false; } -void TcpNormalizer::trim_syn_payload(TcpDataBlock* tdb, uint32_t max) +void TcpNormalizer::trim_syn_payload(TcpSegmentDescriptor& tsd, uint32_t max) { - if (tdb->pkt->dsize > max) - trim_payload(tdb, max, trim_syn, PC_TCP_TRIM_SYN, PERF_COUNT_TCP_TRIM_SYN); + if (tsd.get_pkt()->dsize > max) + trim_payload(tsd, max, trim_syn, PC_TCP_TRIM_SYN, PERF_COUNT_TCP_TRIM_SYN); } -void TcpNormalizer::trim_rst_payload(TcpDataBlock* tdb, uint32_t max) +void TcpNormalizer::trim_rst_payload(TcpSegmentDescriptor& tsd, uint32_t max) { - if (tdb->pkt->dsize > max) - trim_payload(tdb, max, trim_rst, PC_TCP_TRIM_RST, PERF_COUNT_TCP_TRIM_RST); + if (tsd.get_pkt()->dsize > max) + trim_payload(tsd, max, trim_rst, PC_TCP_TRIM_RST, PERF_COUNT_TCP_TRIM_RST); } -void TcpNormalizer::trim_win_payload(TcpDataBlock* tdb, uint32_t max) +void TcpNormalizer::trim_win_payload(TcpSegmentDescriptor& tsd, uint32_t max) { - if (tdb->pkt->dsize > max) - trim_payload(tdb, max, trim_win, PC_TCP_TRIM_WIN, PERF_COUNT_TCP_TRIM_WIN); + if (tsd.get_pkt()->dsize > max) + trim_payload(tsd, max, trim_win, PC_TCP_TRIM_WIN, PERF_COUNT_TCP_TRIM_WIN); } -void TcpNormalizer::trim_mss_payload(TcpDataBlock* tdb, uint32_t max) +void TcpNormalizer::trim_mss_payload(TcpSegmentDescriptor& tsd, uint32_t max) { - if (tdb->pkt->dsize > max) - trim_payload(tdb, max, trim_mss, PC_TCP_TRIM_MSS, PERF_COUNT_TCP_TRIM_MSS); + if (tsd.get_pkt()->dsize > max) + trim_payload(tsd, max, trim_mss, PC_TCP_TRIM_MSS, PERF_COUNT_TCP_TRIM_MSS); } -void TcpNormalizer::ecn_tracker( tcp::TCPHdr* tcph, bool req3way ) +void TcpNormalizer::ecn_tracker(const tcp::TCPHdr* tcph, bool req3way) { - if( tcph->is_syn_ack() ) + if ( tcph->is_syn_ack() ) { - if( !req3way || session->ecn ) + if ( !req3way || session->ecn ) session->ecn = ((tcph->th_flags & (TH_ECE | TH_CWR)) == TH_ECE); } - else if( tcph->is_syn() ) + else if ( tcph->is_syn() ) session->ecn = tcph->are_flags_set(TH_ECE | TH_CWR); } -void TcpNormalizer::ecn_stripper( Packet* p ) +void TcpNormalizer::ecn_stripper(Packet* p) { if (!session->ecn && (p->ptrs.tcph->th_flags & (TH_ECE | TH_CWR))) { if (strip_ecn == NORM_MODE_ON) { - ((tcp::TCPHdr*) p->ptrs.tcph)->th_flags &= ~(TH_ECE | TH_CWR); + ((tcp::TCPHdr*)p->ptrs.tcph)->th_flags &= ~(TH_ECE | TH_CWR); p->packet_flags |= PKT_MODIFIED; } @@ -170,33 +171,33 @@ void TcpNormalizer::ecn_stripper( Packet* p ) } // don't use the window if we may have missed scaling -// one way zero window is unitialized +// one way zero window is uninitialized // two way zero window is actually closed (regardless of scaling) -uint32_t TcpNormalizer::get_stream_window( TcpDataBlock* tdb ) +uint32_t TcpNormalizer::get_stream_window(TcpSegmentDescriptor& tsd) { int32_t window; - if( tracker->l_window ) + if ( tracker->get_snd_wnd() ) { - if( !(session->flow->session_state & STREAM_STATE_MIDSTREAM ) ) - return tracker->l_window; + if ( !(session->flow->session_state & STREAM_STATE_MIDSTREAM ) ) + return tracker->get_snd_wnd(); } - else if( session->flow->two_way_traffic() ) - return tracker->l_window; + else if ( session->flow->two_way_traffic() ) + return tracker->get_snd_wnd(); // ensure the data is in the window - window = tdb->end_seq - tracker->r_win_base; - if (window < 0) + window = tsd.get_end_seq() - tracker->r_win_base; + if ( window < 0 ) window = 0; - return (uint32_t) window; + return (uint32_t)window; } -uint32_t TcpNormalizer::get_tcp_timestamp(TcpDataBlock* tdb, bool strip) +uint32_t TcpNormalizer::get_tcp_timestamp(TcpSegmentDescriptor& tsd, bool strip) { DebugMessage(DEBUG_STREAM_STATE, "Getting timestamp...\n"); - tcp::TcpOptIterator iter(tdb->pkt->ptrs.tcph, tdb->pkt); + tcp::TcpOptIterator iter(tsd.get_tcph(), tsd.get_pkt() ); // using const because non-const is not supported for (const tcp::TcpOption& opt : iter) @@ -206,29 +207,31 @@ uint32_t TcpNormalizer::get_tcp_timestamp(TcpDataBlock* tdb, bool strip) bool stripped = false; if (strip) - stripped = strip_tcp_timestamp(tdb, &opt, opt_block); + stripped = strip_tcp_timestamp(tsd, &opt, opt_block); - if(!stripped) + if (!stripped) { - tdb->ts = EXTRACT_32BITS(opt.data); - DebugFormat(DEBUG_STREAM_STATE, "Found timestamp %lu\n", tdb->ts); + tsd.set_ts(EXTRACT_32BITS(opt.data) ); + DebugFormat(DEBUG_STREAM_STATE, "Found timestamp %lu\n", tsd.get_ts()); return TF_TSTAMP; } } } - tdb->ts = 0; + tsd.set_ts(0); DebugMessage(DEBUG_STREAM_STATE, "No timestamp...\n"); return TF_NONE; } -bool TcpNormalizer::validate_rst_seq_geq( TcpDataBlock* tdb ) +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", - tdb->end_seq, tracker->r_win_base, tdb->seq, tracker->r_nxt_ack + get_stream_window( tdb )); + 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 + + get_stream_window(tsd)); - if (SEQ_GEQ(tdb->seq, tracker->r_nxt_ack)) + if (SEQ_GEQ(tsd.get_seq(), tracker->r_nxt_ack)) { DebugMessage(DEBUG_STREAM_STATE, "rst is valid seq (>= next seq)!\n"); return true; @@ -238,31 +241,35 @@ bool TcpNormalizer::validate_rst_seq_geq( TcpDataBlock* tdb ) return false; } -bool TcpNormalizer::validate_rst_end_seq_geq( TcpDataBlock* tdb ) +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", - tdb->end_seq, tracker->r_win_base, tdb->seq, tracker->r_nxt_ack + get_stream_window( tdb )); - - if (SEQ_GEQ(tdb->end_seq, tracker->r_win_base)) - { - // reset must be admitted when window closed - if (SEQ_LEQ(tdb->seq, tracker->r_win_base + get_stream_window( tdb ))) - { - DebugMessage(DEBUG_STREAM_STATE, "rst is valid seq (within window)!\n"); - return true; - } - } - - DebugMessage(DEBUG_STREAM_STATE, "rst is not valid seq (within window)!\n"); - return false; + 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 + + get_stream_window(tsd)); + + 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))) + { + DebugMessage(DEBUG_STREAM_STATE, "rst is valid seq (within window)!\n"); + return true; + } + } + + DebugMessage(DEBUG_STREAM_STATE, "rst is not valid seq (within window)!\n"); + return false; } -bool TcpNormalizer::validate_rst_seq_eq( TcpDataBlock* tdb ) +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", - tdb->end_seq, tracker->r_win_base, tdb->seq, tracker->r_nxt_ack + get_stream_window( tdb )); + 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 + + get_stream_window(tsd)); - if (SEQ_EQ(tdb->seq, tracker->r_nxt_ack)) + if (SEQ_EQ(tsd.get_seq(), tracker->r_nxt_ack)) { DebugMessage(DEBUG_STREAM_STATE, "rst is valid seq (next seq)!\n"); return true; @@ -276,31 +283,33 @@ bool TcpNormalizer::validate_rst_seq_eq( TcpDataBlock* tdb ) // for all states but syn-sent (handled above). however, we // validate here based on how various implementations actually // handle a rst. -bool TcpNormalizer::validate_rst( TcpDataBlock* tdb ) +bool TcpNormalizer::validate_rst(TcpSegmentDescriptor& tsd) { - return validate_rst_seq_eq( tdb ); + return validate_rst_seq_eq(tsd); } -int TcpNormalizer::validate_paws_timestamp( TcpDataBlock* tdb, int* eventcode ) +int TcpNormalizer::validate_paws_timestamp(TcpSegmentDescriptor& tsd) { - if( ( (int) ( ( tdb->ts - peer_tracker->ts_last ) + paws_ts_fudge ) ) < 0 ) + if ( ( (int)( ( tsd.get_ts() - peer_tracker->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(); - *eventcode |= EVENT_BAD_TIMESTAMP; - packet_dropper(tdb, NORM_TCP_OPT); + ( ( 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 ) - && ( ( uint32_t ) tdb->pkt->pkth->ts.tv_sec > peer_tracker->ts_last_pkt + PAWS_24DAYS ) ) + else if ( ( peer_tracker->ts_last != 0 ) + && ( ( uint32_t )tsd.get_pkt()->pkth->ts.tv_sec > peer_tracker->get_ts_last_packet() + + PAWS_24DAYS ) ) { /* this packet is from way too far into the future */ - DebugFormat(DEBUG_STREAM_STATE, "packet PAWS timestamp way too far ahead of last packet %d %d...\n", - tdb->pkt->pkth->ts.tv_sec, peer_tracker->ts_last_pkt); + DebugFormat(DEBUG_STREAM_STATE, + "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(); - *eventcode |= EVENT_BAD_TIMESTAMP; - packet_dropper(tdb, NORM_TCP_OPT); + ( ( TcpSession* )tsd.get_flow()->session )->tel->set_tcp_event(EVENT_BAD_TIMESTAMP); + packet_dropper(tsd, NORM_TCP_OPT); return ACTION_BAD_PKT; } else @@ -310,20 +319,20 @@ int TcpNormalizer::validate_paws_timestamp( TcpDataBlock* tdb, int* eventcode ) } } -bool TcpNormalizer::is_paws_ts_checked_required( TcpDataBlock* ) +bool TcpNormalizer::is_paws_ts_checked_required(TcpSegmentDescriptor&) { return true; } -int TcpNormalizer::validate_paws( TcpDataBlock* tdb, int* eventcode, int* got_ts ) +int TcpNormalizer::validate_paws(TcpSegmentDescriptor& tsd, int* got_ts) { - *got_ts = get_tcp_timestamp(tdb, false); - if (*got_ts) + *got_ts = get_tcp_timestamp(tsd, false); + if ( *got_ts ) { - bool check_ts = is_paws_ts_checked_required( tdb ); + bool check_ts = is_paws_ts_checked_required(tsd); - if (check_ts) - return validate_paws_timestamp( tdb, eventcode ); + if ( check_ts ) + return validate_paws_timestamp(tsd); else return ACTION_NOTHING; } @@ -332,43 +341,44 @@ int TcpNormalizer::validate_paws( TcpDataBlock* tdb, int* eventcode, int* got_ts // we've got a packet with no timestamp, but 3whs indicated talker was doing // timestamps. This breaks protocol, however, some servers still ack the packet // 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"); - *eventcode |= EVENT_NO_TIMESTAMP; + 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); /* Ignore the timestamp for this first packet, next one will checked. */ - if (tracker->config->policy == StreamPolicy::OS_SOLARIS) + if ( session->config->policy == StreamPolicy::OS_SOLARIS ) tracker->flags &= ~TF_TSTAMP; - packet_dropper(tdb, NORM_TCP_OPT); + packet_dropper(tsd, NORM_TCP_OPT); return ACTION_NOTHING; } } -int TcpNormalizer::handle_paws_no_timestamps(TcpDataBlock* tdb, int* eventcode, int* got_ts) +int TcpNormalizer::handle_paws_no_timestamps(TcpSegmentDescriptor& tsd, int* got_ts) { // 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 // where we disable timestamp handling. - int strip = ( SetupOK( peer_tracker ) && SetupOK( tracker ) ); + int strip = ( SetupOK(peer_tracker) && SetupOK(tracker) ); DebugMessage(DEBUG_STREAM_STATE, "listener not doing timestamps...\n"); - *got_ts = get_tcp_timestamp(tdb, strip); + *got_ts = get_tcp_timestamp(tsd, strip); if (*got_ts) { if (!(peer_tracker->flags & TF_TSTAMP)) { // SYN skipped, may have missed talker's timestamp , so set it now. peer_tracker->flags |= TF_TSTAMP; - if (tdb->ts == 0) + if (tsd.get_ts() == 0) peer_tracker->flags |= TF_TSTAMP_ZERO; } // 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 && ( tdb->ts == 0 ) ) && ( tracker->flags & TF_TSTAMP ) ) + if ( ( paws_drop_zero_ts && ( tsd.get_ts() == 0 ) ) && ( tracker->flags & TF_TSTAMP ) ) { DebugMessage(DEBUG_STREAM_STATE, "Packet with 0 timestamp, dropping\n"); - *eventcode |= EVENT_BAD_TIMESTAMP; + ( ( TcpSession* )tsd.get_flow()->session )->tel->set_tcp_event(EVENT_BAD_TIMESTAMP); return ACTION_BAD_PKT; } } @@ -376,13 +386,13 @@ int TcpNormalizer::handle_paws_no_timestamps(TcpDataBlock* tdb, int* eventcode, return ACTION_NOTHING; } -int TcpNormalizer::handle_paws(TcpDataBlock* tdb, int* eventcode, int* got_ts) +int TcpNormalizer::handle_paws(TcpSegmentDescriptor& tsd, int* got_ts) { - if ( tdb->pkt->ptrs.tcph->is_rst() ) + if ( tsd.get_tcph()->is_rst() ) return ACTION_NOTHING; #if 0 - if ( tdb->pkt->ptrs.tcph->is_ack() && Normalize_IsEnabled(NORM_TCP_OPT) ) + if ( tsd.get_tcph()->is_ack() && Normalize_IsEnabled(NORM_TCP_OPT) ) { // FIXIT-L validate tsecr here (check that it was previously sent) // checking for the most recent ts is easy enough must check if @@ -393,11 +403,11 @@ int TcpNormalizer::handle_paws(TcpDataBlock* tdb, int* eventcode, int* got_ts) if ((peer_tracker->flags & TF_TSTAMP) && (tracker->flags & TF_TSTAMP)) { DebugMessage(DEBUG_STREAM_STATE, "Checking timestamps for PAWS\n"); - return validate_paws( tdb, eventcode, got_ts ); + return validate_paws(tsd, got_ts); } - else if (tdb->pkt->ptrs.tcph->is_syn_only()) + else if (tsd.get_tcph()->is_syn_only()) { - *got_ts = get_tcp_timestamp(tdb, 0); + *got_ts = get_tcp_timestamp(tsd, 0); if (*got_ts) peer_tracker->flags |= TF_TSTAMP; @@ -405,15 +415,15 @@ int TcpNormalizer::handle_paws(TcpDataBlock* tdb, int* eventcode, int* got_ts) } else { - return handle_paws_no_timestamps( tdb, eventcode, got_ts ); + return handle_paws_no_timestamps(tsd, got_ts); } } -uint16_t TcpNormalizer::set_urg_offset( const tcp::TCPHdr* tcph, uint16_t dsize ) +uint16_t TcpNormalizer::set_urg_offset(const tcp::TCPHdr* tcph, uint16_t dsize) { uint16_t urg_offset = 0; - if(tcph->are_flags_set( TH_URG) ) + if (tcph->are_flags_set(TH_URG) ) { urg_offset = tcph->urp(); @@ -425,3 +435,4 @@ uint16_t TcpNormalizer::set_urg_offset( const tcp::TCPHdr* tcph, uint16_t dsize return urg_offset; } + diff --git a/src/stream/tcp/tcp_normalizer.h b/src/stream/tcp/tcp_normalizer.h index 9a4e4051b..1e77183c2 100644 --- a/src/stream/tcp/tcp_normalizer.h +++ b/src/stream/tcp/tcp_normalizer.h @@ -51,24 +51,24 @@ public: virtual ~TcpNormalizer( ) { } - virtual bool packet_dropper (TcpDataBlock*, NormFlags ); - virtual void trim_syn_payload( TcpDataBlock*, uint32_t max = 0 ); - virtual void trim_rst_payload( TcpDataBlock*, uint32_t max = 0 ); - virtual void trim_win_payload( TcpDataBlock*, uint32_t max = 0 ); - virtual void trim_mss_payload( TcpDataBlock*, uint32_t max = 0 ); - virtual void ecn_tracker( tcp::TCPHdr*, bool req3way ); - virtual void ecn_stripper( Packet* ); - virtual uint32_t get_stream_window( TcpDataBlock* ); - virtual uint32_t get_tcp_timestamp( TcpDataBlock *, bool strip ); - virtual int handle_paws( TcpDataBlock*, int*, int* ); - virtual bool validate_rst( TcpDataBlock* ); - virtual int handle_repeated_syn( TcpDataBlock* ) = 0; - virtual uint16_t set_urg_offset( const tcp::TCPHdr* tcph, uint16_t dsize ); - - static const PegInfo* get_normalization_pegs( void ); - static NormPegs get_normalization_counts( unsigned& ); - - void set_peer_tracker( TcpTracker* peer_tracker ) + virtual bool packet_dropper (TcpSegmentDescriptor&, NormFlags); + virtual void trim_syn_payload(TcpSegmentDescriptor&, uint32_t max = 0); + virtual void trim_rst_payload(TcpSegmentDescriptor&, uint32_t max = 0); + virtual void trim_win_payload(TcpSegmentDescriptor&, uint32_t max = 0); + virtual void trim_mss_payload(TcpSegmentDescriptor&, uint32_t max = 0); + virtual void ecn_tracker(const tcp::TCPHdr*, bool req3way); + 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 bool validate_rst(TcpSegmentDescriptor&); + virtual int handle_repeated_syn(TcpSegmentDescriptor&) = 0; + virtual uint16_t set_urg_offset(const tcp::TCPHdr* tcph, uint16_t dsize); + + static const PegInfo* get_normalization_pegs(void); + static NormPegs get_normalization_counts(unsigned&); + + void set_peer_tracker(TcpTracker* peer_tracker) { this->peer_tracker = peer_tracker; } @@ -129,17 +129,17 @@ public: } protected: - TcpNormalizer( StreamPolicy, TcpSession*, TcpTracker* ); - virtual void trim_payload( TcpDataBlock*, uint32_t, NormMode, PegCounts, PerfCounts ); - virtual bool strip_tcp_timestamp( TcpDataBlock*, const tcp::TcpOption*, NormMode ); - virtual bool validate_rst_seq_geq( TcpDataBlock* ); - virtual bool validate_rst_end_seq_geq( TcpDataBlock* ); - virtual bool validate_rst_seq_eq( TcpDataBlock* ); - - virtual int validate_paws_timestamp( TcpDataBlock*, int* ); - virtual bool is_paws_ts_checked_required( TcpDataBlock* ); - virtual int validate_paws( TcpDataBlock*, int*, int* ); - virtual int handle_paws_no_timestamps( TcpDataBlock*, int* , int* ); + TcpNormalizer(StreamPolicy, TcpSession*, TcpTracker*); + virtual void trim_payload(TcpSegmentDescriptor&, uint32_t, NormMode, PegCounts, PerfCounts); + virtual bool strip_tcp_timestamp(TcpSegmentDescriptor&, const tcp::TcpOption*, NormMode); + virtual bool validate_rst_seq_geq(TcpSegmentDescriptor&); + virtual bool validate_rst_end_seq_geq(TcpSegmentDescriptor&); + virtual bool validate_rst_seq_eq(TcpSegmentDescriptor&); + + 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*); StreamPolicy os_policy; TcpSession* session; @@ -158,3 +158,4 @@ protected: }; #endif + diff --git a/src/stream/tcp/tcp_normalizers.cc b/src/stream/tcp/tcp_normalizers.cc index ab315abe2..00ab9d9ab 100644 --- a/src/stream/tcp/tcp_normalizers.cc +++ b/src/stream/tcp/tcp_normalizers.cc @@ -26,286 +26,289 @@ class TcpNormalizerFirst : public TcpNormalizer { public: - TcpNormalizerFirst( TcpSession* session, TcpTracker* tracker ) : - TcpNormalizer( StreamPolicy::OS_FIRST, session, tracker ) + TcpNormalizerFirst(TcpSession* session, TcpTracker* tracker) : + TcpNormalizer(StreamPolicy::OS_FIRST, session, tracker) { } - int handle_repeated_syn( TcpDataBlock* ) override; + int handle_repeated_syn(TcpSegmentDescriptor&) override; }; class TcpNormalizerLast : public TcpNormalizer { public: - TcpNormalizerLast( TcpSession* session, TcpTracker* tracker ) : - TcpNormalizer( StreamPolicy::OS_LAST, session, tracker ) + TcpNormalizerLast(TcpSession* session, TcpTracker* tracker) : + TcpNormalizer(StreamPolicy::OS_LAST, session, tracker) { } - int handle_repeated_syn( TcpDataBlock* ) override; + int handle_repeated_syn(TcpSegmentDescriptor&) override; }; class TcpNormalizerLinux : public TcpNormalizer { public: - TcpNormalizerLinux( TcpSession* session, TcpTracker* tracker ) : - TcpNormalizer( StreamPolicy::OS_LINUX, session, tracker ) + TcpNormalizerLinux(TcpSession* session, TcpTracker* tracker) : + TcpNormalizer(StreamPolicy::OS_LINUX, session, tracker) { // Linux 2.6 accepts timestamp values that are off by one. so set fudge factor */ paws_ts_fudge = 1; } - bool validate_rst( TcpDataBlock* ) override; - bool is_paws_ts_checked_required( TcpDataBlock* ) override; - int handle_repeated_syn( TcpDataBlock* ) override; - uint16_t set_urg_offset( const tcp::TCPHdr* tcph, uint16_t dsize ) override; - + bool validate_rst(TcpSegmentDescriptor&) override; + bool is_paws_ts_checked_required(TcpSegmentDescriptor&) override; + int handle_repeated_syn(TcpSegmentDescriptor&) override; + uint16_t set_urg_offset(const tcp::TCPHdr* tcph, uint16_t dsize) override; }; class TcpNormalizerOldLinux : public TcpNormalizer { public: - TcpNormalizerOldLinux( TcpSession* session, TcpTracker* tracker ) : - TcpNormalizer( StreamPolicy::OS_OLD_LINUX, session, tracker ) + TcpNormalizerOldLinux(TcpSession* session, TcpTracker* tracker) : + TcpNormalizer(StreamPolicy::OS_OLD_LINUX, session, tracker) { paws_drop_zero_ts = false; } - bool validate_rst( TcpDataBlock* ) override; - bool is_paws_ts_checked_required( TcpDataBlock* ) override; - int handle_repeated_syn( TcpDataBlock* ) override; - uint16_t set_urg_offset( const tcp::TCPHdr* tcph, uint16_t dsize ) override; - + bool validate_rst(TcpSegmentDescriptor&) override; + bool is_paws_ts_checked_required(TcpSegmentDescriptor&) override; + int handle_repeated_syn(TcpSegmentDescriptor&) override; + uint16_t set_urg_offset(const tcp::TCPHdr* tcph, uint16_t dsize) override; }; class TcpNormalizerBSD : public TcpNormalizer { public: - TcpNormalizerBSD( TcpSession* session, TcpTracker* tracker ) : - TcpNormalizer( StreamPolicy::OS_BSD, session, tracker ) + TcpNormalizerBSD(TcpSession* session, TcpTracker* tracker) : + TcpNormalizer(StreamPolicy::OS_BSD, session, tracker) { } - bool validate_rst( TcpDataBlock* ) override; - int handle_repeated_syn( TcpDataBlock* ) override; + bool validate_rst(TcpSegmentDescriptor&) override; + int handle_repeated_syn(TcpSegmentDescriptor&) override; }; class TcpNormalizerMacOS : public TcpNormalizer { public: - TcpNormalizerMacOS( TcpSession* session, TcpTracker* tracker ) : - TcpNormalizer( StreamPolicy::OS_MACOS, session, tracker ) + TcpNormalizerMacOS(TcpSession* session, TcpTracker* tracker) : + TcpNormalizer(StreamPolicy::OS_MACOS, session, tracker) { } - int handle_repeated_syn( TcpDataBlock* ) override; + int handle_repeated_syn(TcpSegmentDescriptor&) override; }; class TcpNormalizerSolaris : public TcpNormalizer { public: - TcpNormalizerSolaris( TcpSession* session, TcpTracker* tracker ) : - TcpNormalizer( StreamPolicy::OS_SOLARIS, session, tracker ) + TcpNormalizerSolaris(TcpSession* session, TcpTracker* tracker) : + TcpNormalizer(StreamPolicy::OS_SOLARIS, session, tracker) { paws_drop_zero_ts = false; } - bool validate_rst( TcpDataBlock* ) override; - int handle_repeated_syn( TcpDataBlock* ) override; + bool validate_rst(TcpSegmentDescriptor&) override; + int handle_repeated_syn(TcpSegmentDescriptor&) override; }; class TcpNormalizerIrix : public TcpNormalizer { public: - TcpNormalizerIrix( TcpSession* session, TcpTracker* tracker ) : - TcpNormalizer( StreamPolicy::OS_IRIX, session, tracker ) + TcpNormalizerIrix(TcpSession* session, TcpTracker* tracker) : + TcpNormalizer(StreamPolicy::OS_IRIX, session, tracker) { } - int handle_repeated_syn( TcpDataBlock* ) override; + int handle_repeated_syn(TcpSegmentDescriptor&) override; }; class TcpNormalizerHpux11 : public TcpNormalizer { public: - TcpNormalizerHpux11( TcpSession* session, TcpTracker* tracker ) : - TcpNormalizer( StreamPolicy::OS_HPUX11, session, tracker ) + TcpNormalizerHpux11(TcpSession* session, TcpTracker* tracker) : + TcpNormalizer(StreamPolicy::OS_HPUX11, session, tracker) { } - bool validate_rst( TcpDataBlock* ) override; - bool is_paws_ts_checked_required( TcpDataBlock* ) override; - int handle_repeated_syn( TcpDataBlock* ) override; + bool validate_rst(TcpSegmentDescriptor&) override; + bool is_paws_ts_checked_required(TcpSegmentDescriptor&) override; + int handle_repeated_syn(TcpSegmentDescriptor&) override; }; class TcpNormalizerHpux10 : public TcpNormalizer { public: - TcpNormalizerHpux10( TcpSession* session, TcpTracker* tracker ) : - TcpNormalizer( StreamPolicy::OS_HPUX10, session, tracker ) + TcpNormalizerHpux10(TcpSession* session, TcpTracker* tracker) : + TcpNormalizer(StreamPolicy::OS_HPUX10, session, tracker) { } - int handle_repeated_syn( TcpDataBlock* ) override; + int handle_repeated_syn(TcpSegmentDescriptor&) override; }; class TcpNormalizerWindows : public TcpNormalizer { public: - TcpNormalizerWindows( TcpSession* session, TcpTracker* tracker ) : - TcpNormalizer( StreamPolicy::OS_WINDOWS, session, tracker ) + TcpNormalizerWindows(TcpSession* session, TcpTracker* tracker) : + TcpNormalizer(StreamPolicy::OS_WINDOWS, session, tracker) { paws_drop_zero_ts = false; } - bool is_paws_ts_checked_required( TcpDataBlock* ) override; - int handle_repeated_syn( TcpDataBlock* ) override; + bool is_paws_ts_checked_required(TcpSegmentDescriptor&) override; + int handle_repeated_syn(TcpSegmentDescriptor&) override; }; class TcpNormalizerWindows2K3 : public TcpNormalizer { public: - TcpNormalizerWindows2K3( TcpSession* session, TcpTracker* tracker ) : - TcpNormalizer( StreamPolicy::OS_WINDOWS2K3, session, tracker ) + TcpNormalizerWindows2K3(TcpSession* session, TcpTracker* tracker) : + TcpNormalizer(StreamPolicy::OS_WINDOWS2K3, session, tracker) { paws_drop_zero_ts = false; } - bool is_paws_ts_checked_required( TcpDataBlock* ) override; - int handle_repeated_syn( TcpDataBlock* ) override; + bool is_paws_ts_checked_required(TcpSegmentDescriptor&) override; + int handle_repeated_syn(TcpSegmentDescriptor&) override; }; class TcpNormalizerVista : public TcpNormalizer { public: - TcpNormalizerVista( TcpSession* session, TcpTracker* tracker ) : - TcpNormalizer( StreamPolicy::OS_VISTA, session, tracker ) + TcpNormalizerVista(TcpSession* session, TcpTracker* tracker) : + TcpNormalizer(StreamPolicy::OS_VISTA, session, tracker) { paws_drop_zero_ts = false; } - bool is_paws_ts_checked_required( TcpDataBlock*) override; - int handle_repeated_syn( TcpDataBlock* ) override; + bool is_paws_ts_checked_required(TcpSegmentDescriptor&) override; + int handle_repeated_syn(TcpSegmentDescriptor&) override; }; class TcpNormalizerProxy : public TcpNormalizer { public: - TcpNormalizerProxy( TcpSession* session, TcpTracker* tracker ) : - TcpNormalizer( StreamPolicy::OS_PROXY, session, tracker ) + TcpNormalizerProxy(TcpSession* session, TcpTracker* tracker) : + TcpNormalizer(StreamPolicy::OS_PROXY, session, tracker) { } - bool validate_rst(TcpDataBlock* ) override; - int handle_paws( TcpDataBlock*,int*, int* ) override; - int handle_repeated_syn( TcpDataBlock* ) override; + bool validate_rst(TcpSegmentDescriptor&) override; + int handle_paws(TcpSegmentDescriptor&, int*) override; + int handle_repeated_syn(TcpSegmentDescriptor&) override; }; -TcpNormalizer* TcpNormalizerFactory::create( StreamPolicy os_policy, TcpSession* session, - TcpTracker* tracker, TcpTracker* peer ) +TcpNormalizer* TcpNormalizerFactory::create(TcpSession* session, StreamPolicy os_policy, + TcpTracker* tracker, TcpTracker* peer) { TcpNormalizer* normalizer; switch (os_policy) { case StreamPolicy::OS_FIRST: - normalizer = new TcpNormalizerFirst( session, tracker ); + normalizer = new TcpNormalizerFirst(session, tracker); break; case StreamPolicy::OS_LAST: - normalizer = new TcpNormalizerLast( session, tracker ); + normalizer = new TcpNormalizerLast(session, tracker); break; case StreamPolicy::OS_LINUX: - normalizer = new TcpNormalizerLinux( session, tracker ); + normalizer = new TcpNormalizerLinux(session, tracker); break; case StreamPolicy::OS_OLD_LINUX: - normalizer = new TcpNormalizerOldLinux( session, tracker ); + normalizer = new TcpNormalizerOldLinux(session, tracker); break; case StreamPolicy::OS_BSD: - normalizer = new TcpNormalizerBSD( session, tracker ); + normalizer = new TcpNormalizerBSD(session, tracker); break; case StreamPolicy::OS_MACOS: - normalizer = new TcpNormalizerMacOS( session, tracker ); + normalizer = new TcpNormalizerMacOS(session, tracker); break; case StreamPolicy::OS_SOLARIS: - normalizer = new TcpNormalizerSolaris( session, tracker ); + normalizer = new TcpNormalizerSolaris(session, tracker); break; case StreamPolicy::OS_IRIX: - normalizer = new TcpNormalizerIrix( session, tracker ); + normalizer = new TcpNormalizerIrix(session, tracker); break; case StreamPolicy::OS_HPUX11: - normalizer = new TcpNormalizerHpux11( session, tracker ); + normalizer = new TcpNormalizerHpux11(session, tracker); break; case StreamPolicy::OS_HPUX10: - normalizer = new TcpNormalizerHpux10( session, tracker ); + normalizer = new TcpNormalizerHpux10(session, tracker); break; case StreamPolicy::OS_WINDOWS: - normalizer = new TcpNormalizerWindows( session, tracker ); + normalizer = new TcpNormalizerWindows(session, tracker); break; case StreamPolicy::OS_WINDOWS2K3: - normalizer = new TcpNormalizerWindows2K3( session, tracker ); + normalizer = new TcpNormalizerWindows2K3(session, tracker); break; case StreamPolicy::OS_VISTA: - normalizer = new TcpNormalizerVista( session, tracker ); + normalizer = new TcpNormalizerVista(session, tracker); break; case StreamPolicy::OS_PROXY: - normalizer = new TcpNormalizerProxy( session, tracker ); + normalizer = new TcpNormalizerProxy(session, tracker); break; default: - normalizer = new TcpNormalizerBSD( session, tracker ); + normalizer = new TcpNormalizerBSD(session, tracker); break; } - normalizer->set_peer_tracker( peer ); + normalizer->set_peer_tracker(peer); return normalizer; } -static inline int handle_repeated_syn_mswin( TcpTracker* talker, TcpTracker* listener, - TcpDataBlock* tdb, TcpSession* session ) +static inline int handle_repeated_syn_mswin(TcpTracker* talker, TcpTracker* listener, + TcpSegmentDescriptor& tsd, TcpSession* session) { /* 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(tdb->seq, listener->r_nxt_ack)) + if (SEQ_EQ(tsd.get_seq(), listener->r_nxt_ack)) { - DebugMessage(DEBUG_STREAM_STATE, "Got syn on established windows ssn, which causes Reset, bailing\n"); - session->flow->set_session_flags( SSNFLAG_RESET ); - talker->s_mgr.state = TCP_STATE_CLOSED; + DebugMessage(DEBUG_STREAM_STATE, + "Got syn on established windows ssn, which causes Reset, bailing\n"); + session->flow->set_session_flags(SSNFLAG_RESET); + talker->set_tcp_state(TcpStreamTracker::TCP_CLOSED); return ACTION_RST; } else { - DebugMessage(DEBUG_STREAM_STATE, "Got syn on established windows ssn, not causing Reset, bailing\n"); + DebugMessage(DEBUG_STREAM_STATE, + "Got syn on established windows ssn, not causing Reset, bailing\n"); inc_tcp_discards(); return ACTION_NOTHING; } } -static inline int handle_repeated_syn_bsd( TcpTracker* talker, TcpDataBlock* tdb, TcpSession* session ) +static inline int handle_repeated_syn_bsd(TcpTracker* talker, TcpSegmentDescriptor& tsd, + TcpSession* session) { /* If its not a retransmission of the actual SYN... RESET */ - if (!SEQ_EQ(tdb->seq, talker->isn)) - { - DebugMessage(DEBUG_STREAM_STATE, "Got syn on established ssn, which causes Reset, bailing\n"); - session->flow->set_session_flags( SSNFLAG_RESET ); - talker->s_mgr.state = TCP_STATE_CLOSED; - return ACTION_RST; - } - else - { - DebugMessage(DEBUG_STREAM_STATE, "Got syn on established ssn, not causing Reset, bailing\n"); - inc_tcp_discards(); - return ACTION_NOTHING; - } + if (!SEQ_EQ(tsd.get_seq(), talker->get_iss())) + { + DebugMessage(DEBUG_STREAM_STATE, + "Got syn on established ssn, which causes Reset, bailing\n"); + session->flow->set_session_flags(SSNFLAG_RESET); + talker->set_tcp_state(TcpStreamTracker::TCP_CLOSED); + return ACTION_RST; + } + else + { + DebugMessage(DEBUG_STREAM_STATE, + "Got syn on established ssn, not causing Reset, bailing\n"); + inc_tcp_discards(); + return ACTION_NOTHING; + } } // Linux, Win2k3 et al. do not support timestamps if the 3whs used a 0 timestamp. -static inline bool paws_3whs_zero_ts_not_supported(TcpTracker* talker, TcpTracker* listener ) +static inline bool paws_3whs_zero_ts_not_supported(TcpTracker* talker, TcpTracker* listener) { bool check_ts = true; @@ -320,17 +323,18 @@ static inline bool paws_3whs_zero_ts_not_supported(TcpTracker* talker, TcpTracke } // Older Linux ( <= 2.2 kernel ), Win32 (non 2K3) allow the 3whs to use a 0 timestamp. -static inline bool paws_3whs_zero_ts_supported(TcpTracker* talker, TcpTracker* listener, TcpDataBlock* tdb) +static inline bool paws_3whs_zero_ts_supported(TcpTracker* talker, TcpTracker* listener, + TcpSegmentDescriptor& tsd) { bool check_ts = true; - if( talker->flags & TF_TSTAMP_ZERO ) + if ( talker->flags & TF_TSTAMP_ZERO ) { talker->flags &= ~TF_TSTAMP_ZERO; - if( SEQ_EQ( listener->r_nxt_ack, tdb->seq ) ) + if ( SEQ_EQ(listener->r_nxt_ack, tsd.get_seq() ) ) { // Ignore timestamp for this first packet, save to check on next - talker->ts_last = tdb->ts; + talker->ts_last = tsd.get_ts(); check_ts = false; } } @@ -338,187 +342,187 @@ static inline bool paws_3whs_zero_ts_supported(TcpTracker* talker, TcpTracker* l return check_ts; } -static inline uint16_t set_urg_offset_linux( const tcp::TCPHdr* tcph, uint16_t dsize ) +static inline uint16_t set_urg_offset_linux(const tcp::TCPHdr* tcph, uint16_t dsize) { uint16_t urg_offset = 0; - if(tcph->are_flags_set( TH_URG) ) + if (tcph->are_flags_set(TH_URG) ) { urg_offset = tcph->urp(); - // Linux, Old linux discard data from urgent pointer If urg pointer is 0, - // it's treated as a 1 - if (tcph->urp() < dsize) - if (urg_offset == 0) - urg_offset = 1; + // Linux, Old linux discard data from urgent pointer If urg pointer is 0, + // it's treated as a 1 + if (tcph->urp() < dsize) + if (urg_offset == 0) + urg_offset = 1; } return urg_offset; } -int TcpNormalizerFirst::handle_repeated_syn( TcpDataBlock* tdb ) +int TcpNormalizerFirst::handle_repeated_syn(TcpSegmentDescriptor& tsd) { - return handle_repeated_syn_bsd( peer_tracker, tdb, session ); + return handle_repeated_syn_bsd(peer_tracker, tsd, session); } -int TcpNormalizerLast::handle_repeated_syn( TcpDataBlock* tdb ) +int TcpNormalizerLast::handle_repeated_syn(TcpSegmentDescriptor& tsd) { - return handle_repeated_syn_bsd( peer_tracker, tdb, session ); + return handle_repeated_syn_bsd(peer_tracker, tsd, session); } -bool TcpNormalizerLinux::validate_rst( TcpDataBlock *tdb ) +bool TcpNormalizerLinux::validate_rst(TcpSegmentDescriptor& tsd) { - return validate_rst_end_seq_geq( tdb ); + return validate_rst_end_seq_geq(tsd); } -bool TcpNormalizerLinux::is_paws_ts_checked_required( TcpDataBlock* ) +bool TcpNormalizerLinux::is_paws_ts_checked_required(TcpSegmentDescriptor&) { - return paws_3whs_zero_ts_not_supported( peer_tracker, tracker ); + return paws_3whs_zero_ts_not_supported(peer_tracker, tracker); } -int TcpNormalizerLinux::handle_repeated_syn( TcpDataBlock* tdb ) +int TcpNormalizerLinux::handle_repeated_syn(TcpSegmentDescriptor& tsd) { - return handle_repeated_syn_bsd( peer_tracker, tdb, session ); + return handle_repeated_syn_bsd(peer_tracker, tsd, session); } -uint16_t TcpNormalizerLinux::set_urg_offset( const tcp::TCPHdr* tcph, uint16_t dsize ) +uint16_t TcpNormalizerLinux::set_urg_offset(const tcp::TCPHdr* tcph, uint16_t dsize) { - return set_urg_offset_linux( tcph, dsize ); + return set_urg_offset_linux(tcph, dsize); } -bool TcpNormalizerOldLinux::validate_rst( TcpDataBlock *tdb ) +bool TcpNormalizerOldLinux::validate_rst(TcpSegmentDescriptor& tsd) { - return validate_rst_end_seq_geq( tdb ); + return validate_rst_end_seq_geq(tsd); } -bool TcpNormalizerOldLinux::is_paws_ts_checked_required( TcpDataBlock* tdb) +bool TcpNormalizerOldLinux::is_paws_ts_checked_required(TcpSegmentDescriptor& tsd) { - return paws_3whs_zero_ts_supported( peer_tracker, tracker, tdb ); + return paws_3whs_zero_ts_supported(peer_tracker, tracker, tsd); } -int TcpNormalizerOldLinux::handle_repeated_syn( TcpDataBlock* tdb ) +int TcpNormalizerOldLinux::handle_repeated_syn(TcpSegmentDescriptor& tsd) { - return handle_repeated_syn_bsd( peer_tracker, tdb, session ); + return handle_repeated_syn_bsd(peer_tracker, tsd, session); } -uint16_t TcpNormalizerOldLinux::set_urg_offset( const tcp::TCPHdr* tcph, uint16_t dsize ) +uint16_t TcpNormalizerOldLinux::set_urg_offset(const tcp::TCPHdr* tcph, uint16_t dsize) { - return set_urg_offset_linux( tcph, dsize ); + return set_urg_offset_linux(tcph, dsize); } -bool TcpNormalizerBSD::validate_rst( TcpDataBlock *tdb ) +bool TcpNormalizerBSD::validate_rst(TcpSegmentDescriptor& tsd) { - return validate_rst_end_seq_geq( tdb ); + return validate_rst_end_seq_geq(tsd); } -int TcpNormalizerBSD::handle_repeated_syn( TcpDataBlock* tdb ) +int TcpNormalizerBSD::handle_repeated_syn(TcpSegmentDescriptor& tsd) { - return handle_repeated_syn_bsd( peer_tracker, tdb, session ); + return handle_repeated_syn_bsd(peer_tracker, tsd, session); } -int TcpNormalizerMacOS::handle_repeated_syn( TcpDataBlock* ) +int TcpNormalizerMacOS::handle_repeated_syn(TcpSegmentDescriptor&) { /* MACOS ignores a 2nd SYN, regardless of the sequence number. */ - DebugMessage(DEBUG_STREAM_STATE, "Got syn on established macos ssn, not causing Reset, bailing\n"); + DebugMessage(DEBUG_STREAM_STATE, + "Got syn on established macos ssn, not causing Reset, bailing\n"); inc_tcp_discards(); return ACTION_NOTHING; } -bool TcpNormalizerSolaris::validate_rst( TcpDataBlock* tdb ) +bool TcpNormalizerSolaris::validate_rst(TcpSegmentDescriptor& tsd) { - return validate_rst_end_seq_geq( tdb ); + return validate_rst_end_seq_geq(tsd); } -int TcpNormalizerSolaris::handle_repeated_syn( TcpDataBlock* tdb ) +int TcpNormalizerSolaris::handle_repeated_syn(TcpSegmentDescriptor& tsd) { - return handle_repeated_syn_bsd( peer_tracker, tdb, session ); + return handle_repeated_syn_bsd(peer_tracker, tsd, session); } -int TcpNormalizerIrix::handle_repeated_syn( TcpDataBlock* tdb ) +int TcpNormalizerIrix::handle_repeated_syn(TcpSegmentDescriptor& tsd) { - return handle_repeated_syn_bsd( peer_tracker, tdb, session ); + return handle_repeated_syn_bsd(peer_tracker, tsd, session); } -bool TcpNormalizerHpux11::validate_rst( TcpDataBlock *tdb ) +bool TcpNormalizerHpux11::validate_rst(TcpSegmentDescriptor& tsd) { - return validate_rst_seq_geq( tdb ); + return validate_rst_seq_geq(tsd); } -bool TcpNormalizerHpux11::is_paws_ts_checked_required( TcpDataBlock* tdb ) +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, tdb->seq)) + if ((tracker->flags & TF_MISSING_PKT) || !SEQ_EQ(tracker->r_nxt_ack, tsd.get_seq())) return false; else return true; } -int TcpNormalizerHpux11::handle_repeated_syn( TcpDataBlock* tdb ) +int TcpNormalizerHpux11::handle_repeated_syn(TcpSegmentDescriptor& tsd) { - return handle_repeated_syn_bsd( peer_tracker, tdb, session ); + return handle_repeated_syn_bsd(peer_tracker, tsd, session); } -int TcpNormalizerHpux10::handle_repeated_syn( TcpDataBlock* tdb ) +int TcpNormalizerHpux10::handle_repeated_syn(TcpSegmentDescriptor& tsd) { - return handle_repeated_syn_bsd( peer_tracker, tdb, session ); + return handle_repeated_syn_bsd(peer_tracker, tsd, session); } -bool TcpNormalizerWindows::is_paws_ts_checked_required( TcpDataBlock* tdb) +bool TcpNormalizerWindows::is_paws_ts_checked_required(TcpSegmentDescriptor& tsd) { - return paws_3whs_zero_ts_supported( peer_tracker, tracker, tdb ); + return paws_3whs_zero_ts_supported(peer_tracker, tracker, tsd); } -int TcpNormalizerWindows::handle_repeated_syn( TcpDataBlock *tdb ) +int TcpNormalizerWindows::handle_repeated_syn(TcpSegmentDescriptor& tsd) { - return handle_repeated_syn_mswin( peer_tracker, tracker, tdb, session ); + return handle_repeated_syn_mswin(peer_tracker, tracker, tsd, session); } - -int TcpNormalizerWindows2K3::handle_repeated_syn( TcpDataBlock *tdb ) +int TcpNormalizerWindows2K3::handle_repeated_syn(TcpSegmentDescriptor& tsd) { - return handle_repeated_syn_mswin( peer_tracker, tracker, tdb, session ); + return handle_repeated_syn_mswin(peer_tracker, tracker, tsd, session); } -bool TcpNormalizerWindows2K3::is_paws_ts_checked_required( TcpDataBlock* ) +bool TcpNormalizerWindows2K3::is_paws_ts_checked_required(TcpSegmentDescriptor&) { - return paws_3whs_zero_ts_not_supported( peer_tracker, tracker ); + return paws_3whs_zero_ts_not_supported(peer_tracker, tracker); } -bool TcpNormalizerVista::is_paws_ts_checked_required( TcpDataBlock* tdb) +bool TcpNormalizerVista::is_paws_ts_checked_required(TcpSegmentDescriptor& tsd) { - return paws_3whs_zero_ts_supported( peer_tracker, tracker, tdb ); + return paws_3whs_zero_ts_supported(peer_tracker, tracker, tsd); } -int TcpNormalizerVista::handle_repeated_syn( TcpDataBlock *tdb ) +int TcpNormalizerVista::handle_repeated_syn(TcpSegmentDescriptor& tsd) { - return handle_repeated_syn_mswin( peer_tracker, tracker, tdb, session ); + return handle_repeated_syn_mswin(peer_tracker, tracker, tsd, session); } -bool TcpNormalizerProxy::validate_rst( TcpDataBlock *tdb ) +bool TcpNormalizerProxy::validate_rst(TcpSegmentDescriptor& tsd) { #ifndef DEBUG_MSGS - UNUSED( tdb ); + UNUSED(tsd); #endif // FIXIT - will session->flow ever be null? i would think not, remove this check if possible - if( session->flow ) + if ( session->flow ) { - DebugFormat(DEBUG_STREAM_STATE, "Proxy Normalizer - Not Valid\n end_seq (%X) > r_win_base (%X) && seq (%X) < r_nxt_ack(%X)\n", - tdb->end_seq, tracker->r_win_base, tdb->seq, tracker->r_nxt_ack + get_stream_window( tdb )); + 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 + + get_stream_window(tsd)); } return false; } -int TcpNormalizerProxy::handle_paws(TcpDataBlock*, int*, int*) +int TcpNormalizerProxy::handle_paws(TcpSegmentDescriptor&, int*) { return ACTION_NOTHING; } -int TcpNormalizerProxy::handle_repeated_syn( TcpDataBlock* ) +int TcpNormalizerProxy::handle_repeated_syn(TcpSegmentDescriptor&) { return ACTION_NOTHING; } - - diff --git a/src/stream/tcp/tcp_normalizers.h b/src/stream/tcp/tcp_normalizers.h index 26d487588..0eb25a3e4 100644 --- a/src/stream/tcp/tcp_normalizers.h +++ b/src/stream/tcp/tcp_normalizers.h @@ -28,7 +28,7 @@ class TcpNormalizerFactory { public: - static TcpNormalizer* create( StreamPolicy, TcpSession*, TcpTracker*, TcpTracker* ); + static TcpNormalizer* create(TcpSession*, StreamPolicy, TcpTracker*, TcpTracker*); }; #endif diff --git a/src/stream/tcp/tcp_reassembler.cc b/src/stream/tcp/tcp_reassembler.cc index 647d83870..c4da2d541 100644 --- a/src/stream/tcp/tcp_reassembler.cc +++ b/src/stream/tcp/tcp_reassembler.cc @@ -34,7 +34,7 @@ #include "tcp_module.h" #include "tcp_session.h" -#include "tcp_events.h" +#include "tcp_event_logger.h" #include "tcp_normalizer.h" #include "tcp_reassembler.h" @@ -67,24 +67,24 @@ void TcpReassembler::set_tcp_reassembly_policy(StreamPolicy os_policy) void TcpReassembler::trace_segments(void) { - TcpSegment* ss = seglist.head; + TcpSegmentNode* tsn = seglist.head; uint32_t sx = tracker->r_win_base; unsigned segs = 0, bytes = 0; - while ( ss ) + while ( tsn ) { - if (SEQ_LT(sx, ss->seq)) - fprintf(stdout, " +%u", ss->seq - sx); - else if (SEQ_GT(sx, ss->seq)) - fprintf(stdout, " -%u", sx - ss->seq); + if (SEQ_LT(sx, tsn->seq)) + fprintf(stdout, " +%u", tsn->seq - sx); + else if (SEQ_GT(sx, tsn->seq)) + fprintf(stdout, " -%u", sx - tsn->seq); - fprintf(stdout, " %u", ss->payload_size); + fprintf(stdout, " %u", tsn->payload_size); segs++; - bytes += ss->payload_size; + bytes += tsn->payload_size; - sx = ss->seq + ss->payload_size; - ss = ss->next; + sx = tsn->seq + tsn->payload_size; + tsn = tsn->next; } assert(seg_count == segs); assert(seg_bytes_logical == bytes); @@ -98,22 +98,22 @@ bool TcpReassembler::is_segment_pending_flush(void) uint32_t TcpReassembler::get_pending_segment_count(unsigned max) { uint32_t n = seg_count - flush_count; - TcpSegment* ss; + TcpSegmentNode* tsn; if ( !n || max == 1 ) return n; n = 0; - ss = seglist.head; - while ( ss ) + tsn = seglist.head; + while ( tsn ) { - if ( !ss->buffered && SEQ_LT(ss->seq, tracker->r_win_base) ) + if ( !tsn->buffered && SEQ_LT(tsn->seq, tracker->r_win_base) ) n++; if ( max && n == max ) return n; - ss = ss->next; + tsn = tsn->next; } return n; @@ -132,90 +132,90 @@ bool TcpReassembler::flush_data_ready(void) return ( get_pending_segment_count(2) > 1 ); // FIXIT-L return false? } -int TcpReassembler::delete_reassembly_segment(TcpSegment* seg) +int TcpReassembler::delete_reassembly_segment(TcpSegmentNode* tsn) { int ret; - assert(seg); + assert(tsn); - DebugFormat(DEBUG_STREAM_STATE, "Dropping segment at seq %X, len %d\n", seg->seq, - seg->payload_size); + DebugFormat(DEBUG_STREAM_STATE, "Dropping segment at seq %X, len %d\n", tsn->seq, + tsn->payload_size); - if (seg->prev) - seg->prev->next = seg->next; + if (tsn->prev) + tsn->prev->next = tsn->next; else - seglist.head = seg->next; + seglist.head = tsn->next; - if (seg->next) - seg->next->prev = seg->prev; + if (tsn->next) + tsn->next->prev = tsn->prev; else - seglist.tail = seg->prev; + seglist.tail = tsn->prev; - seg_bytes_logical -= seg->payload_size; - seg_bytes_total -= seg->orig_dsize; + seg_bytes_logical -= tsn->payload_size; + seg_bytes_total -= tsn->orig_dsize; - ret = seg->orig_dsize; + ret = tsn->orig_dsize; - if (seg->buffered) + if (tsn->buffered) { tcpStats.segs_used++; flush_count--; } - if (seglist.next == seg) + if (seglist.next == tsn) seglist.next = NULL; - seg->term( ); + tsn->term( ); seg_count--; return ret; } -int TcpReassembler::trim_delete_reassembly_segment(TcpSegment* seg, uint32_t flush_seq) +int TcpReassembler::trim_delete_reassembly_segment(TcpSegmentNode* tsn, uint32_t flush_seq) { - if ( paf_active(&tracker->paf_state) && ( ( seg->seq + seg->payload_size ) > flush_seq ) ) + if ( paf_active(&tracker->paf_state) && ( ( tsn->seq + tsn->payload_size ) > flush_seq ) ) { - uint32_t delta = flush_seq - seg->seq; + uint32_t delta = flush_seq - tsn->seq; - if (delta < seg->payload_size) + if (delta < tsn->payload_size) { DebugFormat(DEBUG_STREAM_STATE, "Left-Trimming segment at seq %X, len %d, delta %u\n", - seg->seq, seg->payload_size, delta); + tsn->seq, tsn->payload_size, delta); - seg->seq = flush_seq; - seg->payload_size -= (uint16_t)delta; + tsn->seq = flush_seq; + tsn->payload_size -= (uint16_t)delta; seg_bytes_logical -= delta; return 0; } } - return delete_reassembly_segment(seg); + return delete_reassembly_segment(tsn); } -void TcpReassembler::queue_reassembly_segment(TcpSegment* prev, TcpSegment* ss) +void TcpReassembler::queue_reassembly_segment(TcpSegmentNode* prev, TcpSegmentNode* tsn) { - seglist.insert(prev, ss); + seglist.insert(prev, tsn); seg_count++; - seg_bytes_total += ss->orig_dsize; + seg_bytes_total += tsn->orig_dsize; total_segs_queued++; tcpStats.segs_queued++; } -bool TcpReassembler::is_segment_fasttrack(TcpSegment* tail, TcpDataBlock* tdb) +bool TcpReassembler::is_segment_fasttrack(TcpSegmentNode* tail, TcpSegmentDescriptor& tsd) { - DebugFormat(DEBUG_STREAM_STATE, "Checking seq for fast track: %X > %X\n", tdb->seq, + DebugFormat(DEBUG_STREAM_STATE, "Checking seq for fast track: %X > %X\n", tsd.get_seq(), tail->seq + tail->payload_size); - if ( SEQ_EQ(tdb->seq, tail->seq + tail->payload_size) ) + if ( SEQ_EQ(tsd.get_seq(), tail->seq + tail->payload_size) ) return true; return false; } -int TcpReassembler::add_reassembly_segment(TcpDataBlock* tdb, int16_t len, uint32_t slide, +int TcpReassembler::add_reassembly_segment(TcpSegmentDescriptor& tsd, int16_t len, uint32_t slide, uint32_t trunc_len, - uint32_t seq, TcpSegment* left) + uint32_t seq, TcpSegmentNode* left) { - TcpSegment* ss = nullptr; + TcpSegmentNode* tsn = nullptr; int32_t newSize = len - slide - trunc_len; if ( newSize <= 0 ) @@ -224,11 +224,11 @@ int TcpReassembler::add_reassembly_segment(TcpDataBlock* tdb, int16_t len, uint3 DebugFormat(DEBUG_STREAM_STATE, "zero size TCP data after left & right trimming " "(len: %d slide: %d trunc: %d)\n", len, slide, trunc_len); inc_tcp_discards(); - tracker->normalizer->trim_win_payload(tdb); + tracker->normalizer->trim_win_payload(tsd); #ifdef DEBUG_STREAM_EX { - TcpSegment* idx = seglist.head; + TcpSegmentNode* idx = seglist.head; unsigned long i = 0; DebugFormat(DEBUG_STREAM_STATE, "Dumping seglist, %d segments\n", tracker->seg_count); while (idx) @@ -249,33 +249,32 @@ int TcpReassembler::add_reassembly_segment(TcpDataBlock* tdb, int16_t len, uint3 } // FIXIT-L don't allocate overlapped part - ss = TcpSegment::init(tdb->pkt->pkth->ts, tdb->pkt->data, tdb->pkt->dsize); - if ( !ss ) + tsn = TcpSegmentNode::init(tsd.get_pkt()->pkth->ts, tsd.get_pkt()->data, tsd.get_pkt()->dsize); + if ( !tsn ) return STREAM_INSERT_FAILED; - else if ( TcpSegment::needs_pruning() ) + else if ( TcpSegmentNode::needs_pruning() ) { sfBase.iStreamFaults++; - flow_con->prune_flows(PktType::TCP, tdb->pkt); + flow_con->prune_flows(PktType::TCP, tsd.get_pkt() ); } - ss->payload = ss->data + slide; - ss->payload_size = (uint16_t)newSize; - ss->seq = seq; - ss->ts = tdb->ts; + tsn->payload = tsn->data + slide; + tsn->payload_size = (uint16_t)newSize; + tsn->seq = seq; + tsn->ts = tsd.get_ts(); // 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 - ss->urg_offset = tracker->normalizer->set_urg_offset(tdb->pkt->ptrs.tcph, tdb->pkt->dsize); - - queue_reassembly_segment(left, ss); - seg_bytes_logical += ss->payload_size; - total_bytes_queued += ss->payload_size; - tdb->pkt->packet_flags |= PKT_STREAM_INSERT; + tsn->urg_offset = tracker->normalizer->set_urg_offset(tsd.get_tcph(), tsd.get_pkt()->dsize); + queue_reassembly_segment(left, tsn); + seg_bytes_logical += tsn->payload_size; + total_bytes_queued += tsn->payload_size; + tsd.get_pkt()->packet_flags |= PKT_STREAM_INSERT; DebugFormat(DEBUG_STREAM_STATE, "added %d bytes on segment list @ seq: 0x%X, total %lu, %d segments queued\n", - ss->payload_size, ss->seq, seg_bytes_logical, get_pending_segment_count(0)); + tsn->payload_size, tsn->seq, seg_bytes_logical, get_pending_segment_count(0)); #ifdef SEG_TEST CheckSegments(tracker); @@ -283,12 +282,13 @@ int TcpReassembler::add_reassembly_segment(TcpDataBlock* tdb, int16_t len, uint3 return STREAM_INSERT_OK; } -int TcpReassembler::dup_reassembly_segment(Packet* p, TcpSegment* left, TcpSegment** retSeg) +int TcpReassembler::dup_reassembly_segment(Packet* p, TcpSegmentNode* left, + TcpSegmentNode** retSeg) { - TcpSegment* ss = TcpSegment::init(left->tv, left->payload, left->payload_size); - if ( !ss ) + TcpSegmentNode* tsn = TcpSegmentNode::init(left->tv, left->payload, left->payload_size); + if ( !tsn ) return STREAM_INSERT_FAILED; - if ( TcpSegment::needs_pruning() ) + if ( TcpSegmentNode::needs_pruning() ) { sfBase.iStreamFaults++; flow_con->prune_flows(PktType::TCP, p); @@ -297,17 +297,17 @@ int TcpReassembler::dup_reassembly_segment(Packet* p, TcpSegment* left, TcpSegme tcpStats.segs_split++; // twiddle the values for overlaps - ss->payload = ss->data; - ss->payload_size = left->payload_size; - ss->seq = left->seq; + tsn->payload = tsn->data; + tsn->payload_size = left->payload_size; + tsn->seq = left->seq; - queue_reassembly_segment(left, ss); + queue_reassembly_segment(left, tsn); DebugFormat(DEBUG_STREAM_STATE, "added %d bytes on segment list @ seq: 0x%X, total %lu, %d segments queued\n", - ss->payload_size, ss->seq, seg_bytes_logical, get_pending_segment_count(0)); + tsn->payload_size, tsn->seq, seg_bytes_logical, get_pending_segment_count(0)); - *retSeg = ss; + *retSeg = tsn; return STREAM_INSERT_OK; } @@ -343,8 +343,8 @@ int TcpReassembler::purge_alerts(uint32_t /*flush_seq*/, Flow* flow) int TcpReassembler::purge_to_seq(uint32_t flush_seq) { - TcpSegment* ss = nullptr; - TcpSegment* dump_me = nullptr; + TcpSegmentNode* tsn = nullptr; + TcpSegmentNode* dump_me = nullptr; int purged_bytes = 0; uint32_t last_ts = 0; @@ -358,17 +358,17 @@ int TcpReassembler::purge_to_seq(uint32_t flush_seq) return 0; } - ss = seglist.head; + tsn = seglist.head; DebugFormat(DEBUG_STREAM_STATE, "In purge_to_seq, start seq = 0x%X end seq = 0x%X delta %d\n", - ss->seq, flush_seq, flush_seq-ss->seq); + tsn->seq, flush_seq, flush_seq-tsn->seq); - while ( ss ) + while ( tsn ) { - DebugFormat(DEBUG_STREAM_STATE, "s: %X sz: %d\n", ss->seq, ss->payload_size); - dump_me = ss; + DebugFormat(DEBUG_STREAM_STATE, "s: %X sz: %d\n", tsn->seq, tsn->payload_size); + dump_me = tsn; - ss = ss->next; + tsn = tsn->next; if ( SEQ_LT(dump_me->seq, flush_seq) ) { if (dump_me->ts > last_ts) @@ -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->ts_last; if ( delta > 0 ) - session->server.ts_last = last_ts; + session->server->ts_last = last_ts; } else { - int32_t delta = last_ts - session->client.ts_last; + int32_t delta = last_ts - session->client->ts_last; if ( delta > 0 ) - session->client.ts_last = last_ts; + session->client->ts_last = last_ts; } return purged_bytes; @@ -430,13 +430,13 @@ int TcpReassembler::purge_to_seq(uint32_t flush_seq) // purge_flushed_ackd(): // must only purge flushed and acked bytes we may flush partial segments -// must adjust seq->seq and seg->size when a flush gets only the initial +// must adjust seq->seq and tsn->size when a flush gets only the initial // part of a segment // * FIXIT-L need flag to mark any reassembled packets that have a gap // (if we reassemble such) int TcpReassembler::purge_flushed_ackd(void) { - TcpSegment* seg = seglist.head; + TcpSegmentNode* tsn = seglist.head; uint32_t seq; if (!seglist.head) @@ -444,9 +444,9 @@ int TcpReassembler::purge_flushed_ackd(void) seq = seglist.head->seq; - while ( seg && seg->buffered ) + while ( tsn && tsn->buffered ) { - uint32_t end = seg->seq + seg->payload_size; + uint32_t end = tsn->seq + tsn->payload_size; if ( SEQ_GT(end, tracker->r_win_base) ) { @@ -454,7 +454,7 @@ int TcpReassembler::purge_flushed_ackd(void) break; } seq = end; - seg = seg->next; + tsn = tsn->next; } if ( seq != seglist.head->seq ) return purge_to_seq(seq); @@ -467,26 +467,26 @@ int TcpReassembler::purge_flushed_ackd(void) void TcpReassembler::show_rebuilt_packet(Packet* pkt) { - if ( ( session->client.config->flags & STREAM_CONFIG_SHOW_PACKETS ) - || ( session->server.config->flags & STREAM_CONFIG_SHOW_PACKETS ) ) + if ( ( session->config->flags & STREAM_CONFIG_SHOW_PACKETS ) + || ( session->config->flags & STREAM_CONFIG_SHOW_PACKETS ) ) { LogFlow(pkt); LogNetData(pkt->data, pkt->dsize, pkt); } } -uint32_t TcpReassembler::get_flush_data_len(TcpSegment* ss, uint32_t to_seq, +uint32_t TcpReassembler::get_flush_data_len(TcpSegmentNode* tsn, uint32_t to_seq, uint32_t flushBufSize) { - unsigned int flushSize = ss->payload_size; + unsigned int flushSize = tsn->payload_size; // copy only till flush buffer gets full if ( flushSize > flushBufSize ) flushSize = flushBufSize; // copy only to flush point - if ( paf_active(&tracker->paf_state) && SEQ_GT(ss->seq + flushSize, to_seq) ) - flushSize = to_seq - ss->seq; + if ( paf_active(&tracker->paf_state) && SEQ_GT(tsn->seq + flushSize, to_seq) ) + flushSize = to_seq - tsn->seq; return flushSize; } @@ -506,20 +506,21 @@ int TcpReassembler::flush_data_segments(Packet* p, uint32_t toSeq, uint8_t* flus uint32_t total = toSeq - seglist.next->seq; while ( SEQ_LT(seglist.next->seq, toSeq) ) { - TcpSegment* ss = seglist.next, * sr = nullptr; + TcpSegmentNode* tsn = seglist.next, * sr = nullptr; unsigned flushbuf_size = flushbuf_end - flushbuf; - unsigned bytes_to_copy = get_flush_data_len(ss, toSeq, flushbuf_size); + unsigned bytes_to_copy = get_flush_data_len(tsn, toSeq, flushbuf_size); unsigned bytes_copied = 0; assert(bytes_to_copy); - DebugFormat(DEBUG_STREAM_STATE, "Flushing %u bytes from %X\n", bytes_to_copy, ss->seq); + DebugFormat(DEBUG_STREAM_STATE, "Flushing %u bytes from %X\n", bytes_to_copy, tsn->seq); - if ( !ss->next || ( bytes_to_copy < ss->payload_size ) || SEQ_EQ(ss->seq + bytes_to_copy, + if ( !tsn->next || ( bytes_to_copy < tsn->payload_size ) || SEQ_EQ(tsn->seq + + bytes_to_copy, toSeq) ) flags |= PKT_PDU_TAIL; const StreamBuffer* sb = tracker->splitter->reassemble(p->flow, total, bytes_flushed, - ss->payload, + tsn->payload, bytes_to_copy, flags, bytes_copied); flags = 0; if ( sb ) @@ -539,39 +540,39 @@ int TcpReassembler::flush_data_segments(Packet* p, uint32_t toSeq, uint8_t* flus flushbuf += bytes_to_copy; bytes_flushed += bytes_to_copy; - if ( bytes_to_copy < ss->payload_size - && dup_reassembly_segment(nullptr, ss, &sr) == STREAM_INSERT_OK ) + if ( bytes_to_copy < tsn->payload_size + && dup_reassembly_segment(nullptr, tsn, &sr) == STREAM_INSERT_OK ) { - ss->payload_size = bytes_to_copy; + tsn->payload_size = bytes_to_copy; sr->seq += bytes_to_copy; sr->payload_size -= bytes_to_copy; sr->payload += bytes_to_copy; } - ss->buffered = true; + tsn->buffered = true; flush_count++; segs++; if ( flushbuf >= flushbuf_end ) break; - if ( SEQ_EQ(ss->seq + bytes_to_copy, toSeq) ) + if ( SEQ_EQ(tsn->seq + bytes_to_copy, toSeq) ) break; /* Check for a gap/missing packet */ // FIXIT-L PAF should account for missing data and resume // scanning at the start of next PDU instead of aborting. // FIXIT-L FIN may be in toSeq causing bogus gap counts. - if (((ss->next && (ss->seq + ss->payload_size != ss->next->seq)) - || (!ss->next && (ss->seq + ss->payload_size < toSeq))) + 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)) { - if ( ss->next ) - seglist.next = ss->next; + if ( tsn->next ) + seglist.next = tsn->next; tracker->flags |= TF_MISSING_PKT; break; } - seglist.next = ss->next; + seglist.next = tsn->next; if ( sb || !seglist.next ) break; @@ -809,20 +810,17 @@ int TcpReassembler::flush_to_seq(uint32_t bytes, Packet* p, uint32_t pkt_flags) return _flush_to_seq(bytes, p, pkt_flags); } -/* - * get the footprint for the current seglist, the difference - * between our base sequence and the last ack'd sequence we - * received - */ +// FIXIT - the seq number math in the following 2 funcs does not handle wrapping +// get the footprint for the current seglist, the difference between our +// base sequence and the last ack'd sequence we received uint32_t TcpReassembler::get_q_footprint(void) { - uint32_t fp; + int32_t fp; if ( tracker == nullptr ) return 0; fp = tracker->r_win_base - seglist_base_seq; - if ( fp <= 0 ) return 0; @@ -835,32 +833,32 @@ uint32_t TcpReassembler::get_q_footprint(void) // to avoid the while loop, etc. below. uint32_t TcpReassembler::get_q_sequenced(void) { - uint32_t len; - TcpSegment* seg = tracker ? seglist.head : nullptr; - TcpSegment* base = nullptr; + int32_t len; + TcpSegmentNode* tsn = tracker ? seglist.head : nullptr; + TcpSegmentNode* base = nullptr; - if ( !seg ) + if ( !tsn ) return 0; - if ( session->flow->two_way_traffic() && SEQ_LT(tracker->r_win_base, seg->seq) ) + if ( session->flow->two_way_traffic() && SEQ_LT(tracker->r_win_base, tsn->seq) ) return 0; - while ( seg->next && ( seg->next->seq == seg->seq + seg->payload_size ) ) + while ( tsn->next && ( tsn->next->seq == tsn->seq + tsn->payload_size ) ) { - if ( !seg->buffered && !base ) - base = seg; - seg = seg->next; + if ( !tsn->buffered && !base ) + base = tsn; + tsn = tsn->next; } - if ( !seg->buffered && !base ) - base = seg; + if ( !tsn->buffered && !base ) + base = tsn; if ( !base ) return 0; seglist.next = base; seglist_base_seq = base->seq; - len = seg->seq + seg->payload_size - base->seq; + len = tsn->seq + tsn->payload_size - base->seq; return ( len > 0 ) ? len : 0; } @@ -958,29 +956,29 @@ uint32_t TcpReassembler::flush_pdu_ips(uint32_t* flags) Profile profile(s5TcpPAFPerfStats); uint32_t total = 0, avail; - TcpSegment* seg; + TcpSegmentNode* tsn; avail = get_q_sequenced( ); - seg = seglist.next; + tsn = seglist.next; // * must stop if gap (checked in paf_check) - while ( seg && *flags && ( total < avail ) ) + while ( tsn && *flags && ( total < avail ) ) { int32_t flush_pt; - uint32_t size = seg->payload_size; - uint32_t end = seg->seq + seg->payload_size; + uint32_t size = tsn->payload_size; + uint32_t end = tsn->seq + tsn->payload_size; uint32_t pos = paf_position(&tracker->paf_state); total += size; if ( paf_initialized(&tracker->paf_state) && SEQ_LEQ(end, pos) ) { - seg = seg->next; + tsn = tsn->next; continue; } flush_pt = paf_check(tracker->splitter, &tracker->paf_state, session->flow, - seg->payload, size, total, seg->seq, flags); + tsn->payload, size, total, tsn->seq, flags); if (flush_pt >= 0) { @@ -992,7 +990,7 @@ uint32_t TcpReassembler::flush_pdu_ips(uint32_t* flags) } return flush_pt; } - seg = seg->next; + tsn = tsn->next; } return -1; @@ -1003,7 +1001,7 @@ void TcpReassembler::fallback(void) bool c2s = tracker->splitter->to_server(); delete tracker->splitter; - tracker->splitter = new AtomSplitter(c2s, tracker->config->paf_max); + tracker->splitter = new AtomSplitter(c2s, session->config->paf_max); tracker->paf_state.paf = StreamSplitter::SEARCH; } @@ -1027,31 +1025,31 @@ uint32_t TcpReassembler::flush_pdu_ackd(uint32_t* flags) Profile profile(s5TcpPAFPerfStats); uint32_t total = 0; - TcpSegment* seg = SEQ_LT(seglist_base_seq, tracker->r_win_base) ? seglist.head : nullptr; + TcpSegmentNode* tsn = SEQ_LT(seglist_base_seq, tracker->r_win_base) ? seglist.head : nullptr; // must stop if not acked - // must use adjusted size of seg if not fully acked + // must use adjusted size of tsn if not fully acked // must stop if gap (checked in paf_check) - while (seg && *flags && SEQ_LT(seg->seq, tracker->r_win_base)) + while (tsn && *flags && SEQ_LT(tsn->seq, tracker->r_win_base)) { int32_t flush_pt; - uint32_t size = seg->payload_size; - uint32_t end = seg->seq + seg->payload_size; + uint32_t size = tsn->payload_size; + uint32_t end = tsn->seq + tsn->payload_size; uint32_t pos = paf_position(&tracker->paf_state); if ( paf_initialized(&tracker->paf_state) && SEQ_LEQ(end, pos) ) { total += size; - seg = seg->next; + tsn = tsn->next; continue; } if ( SEQ_GT(end, tracker->r_win_base)) - size = tracker->r_win_base - seg->seq; + size = tracker->r_win_base - tsn->seq; total += size; flush_pt = paf_check(tracker->splitter, &tracker->paf_state, session->flow, - seg->payload, size, total, seg->seq, flags); + tsn->payload, size, total, tsn->seq, flags); if ( flush_pt >= 0 ) { @@ -1072,7 +1070,7 @@ uint32_t TcpReassembler::flush_pdu_ackd(uint32_t* flags) } return flush_pt; } - seg = seg->next; + tsn = tsn->next; } return -1; @@ -1110,7 +1108,7 @@ int TcpReassembler::flush_on_data_policy(Packet* p) // if this payload is exactly one pdu, don't // actually flush, just use the raw packet if ( listener->seglist.next && - ( tdb->seq == listener->seglist.next->seq ) && + ( tsd.seq == listener->seglist.next->seq ) && ( flush_amt == listener->seglist.next->payload_size ) && ( flush_amt == p->dsize ) ) { @@ -1190,6 +1188,7 @@ int TcpReassembler::flush_on_ack_policy(Packet* p) flags = get_reverse_packet_dir(p); flush_amt = flush_pdu_ackd(&flags); } + if (!flags && tracker->splitter->is_paf()) { fallback( ); @@ -1215,12 +1214,12 @@ void TcpReassembler::purge_segment_list(void) seg_bytes_logical = 0; } -void TcpReassembler::insert_segment_in_empty_seglist(TcpDataBlock* tdb) +void TcpReassembler::insert_segment_in_empty_seglist(TcpSegmentDescriptor& tsd) { - const tcp::TCPHdr* tcph = tdb->pkt->ptrs.tcph; + const tcp::TCPHdr* tcph = tsd.get_tcph(); uint32_t overlap = 0; - uint32_t seq = tdb->seq; + uint32_t seq = tsd.get_seq(); if ( tcph->is_syn() ) seq++; @@ -1228,8 +1227,8 @@ void TcpReassembler::insert_segment_in_empty_seglist(TcpDataBlock* tdb) if ( SEQ_GT(tracker->r_win_base, seq) ) { DebugMessage(DEBUG_STREAM_STATE, "segment overlaps ack'd data...\n"); - overlap = tracker->r_win_base - tdb->seq; - if ( overlap >= tdb->pkt->dsize ) + overlap = tracker->r_win_base - tsd.get_seq(); + if ( overlap >= tsd.get_pkt()->dsize ) { DebugMessage(DEBUG_STREAM_STATE, "full overlap on ack'd data, dropping segment\n"); return; @@ -1237,85 +1236,85 @@ void TcpReassembler::insert_segment_in_empty_seglist(TcpDataBlock* tdb) } // BLOCK add new block to seglist containing data - add_reassembly_segment(tdb, tdb->pkt->dsize, overlap, 0, tdb->seq + overlap, NULL); + add_reassembly_segment(tsd, tsd.get_pkt()->dsize, overlap, 0, tsd.get_seq() + overlap, NULL); DebugFormat(DEBUG_STREAM_STATE, "Attached new queue to seglist, %d bytes queued, base_seq 0x%X\n", - tdb->pkt->dsize-overlap, seglist_base_seq); + tsd.get_pkt()->dsize - overlap, seglist_base_seq); } -void TcpReassembler::init_overlap_editor(TcpDataBlock* tdb) +void TcpReassembler::init_overlap_editor(TcpSegmentDescriptor& tsd) { - TcpSegment* left = nullptr; - TcpSegment* right = nullptr; - TcpSegment* ss = nullptr; + TcpSegmentNode* left = nullptr; + TcpSegmentNode* right = nullptr; + TcpSegmentNode* tsn = nullptr; int32_t dist_head; int32_t dist_tail; DEBUG_WRAP( - TcpSegment *lastptr = NULL; + TcpSegmentNode *lastptr = NULL; uint32_t base_seq = seglist_base_seq; int last = 0; ); if ( seglist.head && seglist.tail ) { - if ( SEQ_GT(tdb->seq, seglist.head->seq) ) - dist_head = tdb->seq - seglist.head->seq; + if ( SEQ_GT(tsd.get_seq(), seglist.head->seq) ) + dist_head = tsd.get_seq() - seglist.head->seq; else - dist_head = seglist.head->seq - tdb->seq; + dist_head = seglist.head->seq - tsd.get_seq(); - if ( SEQ_GT(tdb->seq, seglist.tail->seq) ) - dist_tail = tdb->seq - seglist.tail->seq; + if ( SEQ_GT(tsd.get_seq(), seglist.tail->seq) ) + dist_tail = tsd.get_seq() - seglist.tail->seq; else - dist_tail = seglist.tail->seq - tdb->seq; + dist_tail = seglist.tail->seq - tsd.get_seq(); } else dist_head = dist_tail = 0; if ( SEQ_LEQ(dist_head, dist_tail) ) { - for ( ss = seglist.head; ss; ss = ss->next ) + for ( tsn = seglist.head; tsn; tsn = tsn->next ) { DEBUG_WRAP( - DebugFormat(DEBUG_STREAM_STATE, "ss: %p seq: 0x%X size: %lu delta: %d\n", - ss, ss->seq, ss->payload_size, ( ss->seq - base_seq ) - last); - last = ss->seq - base_seq; - lastptr = ss; + DebugFormat(DEBUG_STREAM_STATE, "tsn: %p seq: 0x%X size: %lu delta: %d\n", + tsn, tsn->seq, tsn->payload_size, ( tsn->seq - base_seq ) - last); + last = tsn->seq - base_seq; + lastptr = tsn; - DebugFormat(DEBUG_STREAM_STATE, " lastptr: %p ss->next: %p ss->prev: %p\n", - lastptr, ss->next, ss->prev); + DebugFormat(DEBUG_STREAM_STATE, " lastptr: %p tsn->next: %p tsn->prev: %p\n", + lastptr, tsn->next, tsn->prev); ); - right = ss; - if ( SEQ_GEQ(right->seq, tdb->seq) ) + right = tsn; + if ( SEQ_GEQ(right->seq, tsd.get_seq() ) ) break; left = right; } - if ( ss == nullptr ) + if ( tsn == nullptr ) right = nullptr; } else { - for ( ss = seglist.tail; ss; ss = ss->prev ) + for ( tsn = seglist.tail; tsn; tsn = tsn->prev ) { DEBUG_WRAP( - DebugFormat(DEBUG_STREAM_STATE, "ss: %p seq: 0x%X size: %lu delta: %d\n", - ss, ss->seq, ss->payload_size, ( ss->seq - base_seq ) - last); - last = ss->seq - base_seq; - lastptr = ss; + DebugFormat(DEBUG_STREAM_STATE, "tsn: %p seq: 0x%X size: %lu delta: %d\n", + tsn, tsn->seq, tsn->payload_size, ( tsn->seq - base_seq ) - last); + last = tsn->seq - base_seq; + lastptr = tsn; - DebugFormat(DEBUG_STREAM_STATE, " lastptr: %p ss->next: %p ss->prev: %p\n", - lastptr, ss->next, ss->prev); + DebugFormat(DEBUG_STREAM_STATE, " lastptr: %p tsn->next: %p tsn->prev: %p\n", + lastptr, tsn->next, tsn->prev); ); - left = ss; - if ( SEQ_LT(left->seq, tdb->seq) ) + left = tsn; + if ( SEQ_LT(left->seq, tsd.get_seq() ) ) break; right = left; } - if (ss == nullptr) + if (tsn == nullptr) left = nullptr; } @@ -1324,36 +1323,36 @@ void TcpReassembler::init_overlap_editor(TcpDataBlock* tdb) DebugFormat(DEBUG_STREAM_STATE, "left: %p:0x%X right: %p:0x%X\n", left, left ? left->seq : 0, right, right ? right->seq : 0); - init_soe(tdb, left, right); + init_soe(tsd, left, right); } -int TcpReassembler::insert_segment_in_seglist(TcpDataBlock* tdb) +int TcpReassembler::insert_segment_in_seglist(TcpSegmentDescriptor& tsd) { int rc = STREAM_INSERT_OK; DebugFormat(DEBUG_STREAM_STATE, "Queuing %d bytes on stream!\nbase_seq: %X seq: %X seq_end: %X\n", - tdb->end_seq - tdb->seq, seglist_base_seq, tdb->seq, tdb->end_seq); + tsd.get_end_seq() - tsd.get_seq(), seglist_base_seq, tsd.get_seq(), tsd.get_end_seq()); DebugFormat(DEBUG_STREAM_STATE, "%d segments on seglist\n", get_pending_segment_count(0)); DebugMessage(DEBUG_STREAM_STATE, "!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+\n"); DebugMessage(DEBUG_STREAM_STATE, "!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+\n"); // NORM fast tracks are in sequence - no norms - if ( seglist.tail && is_segment_fasttrack(seglist.tail, tdb) ) + if ( seglist.tail && is_segment_fasttrack(seglist.tail, tsd) ) { /* segment fit cleanly at the end of the segment list */ - TcpSegment* left = seglist.tail; + TcpSegmentNode* left = seglist.tail; DebugFormat(DEBUG_STREAM_STATE, "Fast tracking segment! (tail_seq %X size %d)\n", seglist.tail->seq, seglist.tail->payload_size); // BLOCK add to existing block and/or allocate new block - rc = add_reassembly_segment(tdb, tdb->pkt->dsize, 0, 0, tdb->seq, left); + rc = add_reassembly_segment(tsd, tsd.get_pkt()->dsize, 0, 0, tsd.get_seq(), left); return rc; } - init_overlap_editor(tdb); + init_overlap_editor(tsd); rc = eval_left(); if ( rc != STREAM_INSERT_OK ) return rc; @@ -1365,8 +1364,8 @@ int TcpReassembler::insert_segment_in_seglist(TcpDataBlock* tdb) if ( keep_segment ) { /* Adjust slide so that is correct relative to orig seq */ - slide = seq - tdb->seq; - rc = add_reassembly_segment(tdb, len, slide, trunc_len, seq, left); + slide = seq - tsd.get_seq(); + rc = add_reassembly_segment(tsd, len, slide, trunc_len, seq, left); } else { @@ -1377,7 +1376,7 @@ int TcpReassembler::insert_segment_in_seglist(TcpDataBlock* tdb) return rc; } -int TcpReassembler::queue_packet_for_reassembly(TcpDataBlock* tdb) +int TcpReassembler::queue_packet_for_reassembly(TcpSegmentDescriptor& tsd) { Profile profile(s5TcpInsertPerfStats); @@ -1385,29 +1384,29 @@ int TcpReassembler::queue_packet_for_reassembly(TcpDataBlock* tdb) if ( seg_count == 0 ) { - insert_segment_in_empty_seglist(tdb); + insert_segment_in_empty_seglist(tsd); return STREAM_INSERT_OK; } - if ( SEQ_GT(tracker->r_win_base, tdb->seq) ) + if ( SEQ_GT(tracker->r_win_base, tsd.get_seq() ) ) { - uint32_t offset = tracker->r_win_base - tdb->seq; + uint32_t offset = tracker->r_win_base - tsd.get_seq(); - if ( offset < tdb->pkt->dsize ) + if ( offset < tsd.get_pkt()->dsize ) { - tdb->seq += offset; - tdb->pkt->data += offset; - tdb->pkt->dsize -= (uint16_t)offset; + tsd.set_seq(tsd.get_seq() + offset); + tsd.get_pkt()->data += offset; + tsd.get_pkt()->dsize -= (uint16_t)offset; - rc = insert_segment_in_seglist(tdb); + rc = insert_segment_in_seglist(tsd); - tdb->pkt->dsize += (uint16_t)offset; - tdb->pkt->data -= offset; - tdb->seq -= offset; + tsd.get_pkt()->dsize += (uint16_t)offset; + tsd.get_pkt()->data -= offset; + tsd.set_seq(tsd.get_seq() - offset); } } else - rc = insert_segment_in_seglist(tdb); + rc = insert_segment_in_seglist(tsd); return rc; } @@ -1415,18 +1414,18 @@ int TcpReassembler::queue_packet_for_reassembly(TcpDataBlock* tdb) #ifdef SEG_TEST static void CheckSegments(const TcpTracker* a) { - TcpSegment* ss = a->seglist.head; - uint32_t sx = ss ? ss->seq : 0; + TcpSegmentNode* tsn = a->seglist.head; + uint32_t sx = tsn ? tsn->seq : 0; - while ( ss ) + while ( tsn ) { - if ( SEQ_GT(sx, ss->seq) ) + if ( SEQ_GT(sx, tsn->seq) ) { const int SEGBORK = 0; assert(SEGBORK); } - sx = ss->seq + ss->payload_size; - ss = ss->next; + sx = tsn->seq + tsn->payload_size; + tsn = tsn->next; } } diff --git a/src/stream/tcp/tcp_reassembler.h b/src/stream/tcp/tcp_reassembler.h index fa3df59d7..f14b6b8f1 100644 --- a/src/stream/tcp/tcp_reassembler.h +++ b/src/stream/tcp/tcp_reassembler.h @@ -30,8 +30,8 @@ #include "stream/stream_api.h" #include "segment_overlap_editor.h" -#include "tcp_segment.h" #include "tcp_defs.h" +#include "tcp_segment_node.h" class TcpSession; struct TcpTracker; @@ -41,31 +41,20 @@ extern THREAD_LOCAL Packet* s5_pkt; class TcpReassembler : public SegmentOverlapEditor { public: - virtual ~TcpReassembler() { } - - virtual int add_reassembly_segment(TcpDataBlock*, int16_t len, uint32_t slide, uint32_t trunc, uint32_t seq, - TcpSegment *left) override; - int dup_reassembly_segment(Packet *p, TcpSegment *left, TcpSegment **retSeg) override; - int delete_reassembly_segment( TcpSegment* seg ) override; - - void set_tcp_reassembly_policy( StreamPolicy os_policy ); - virtual int queue_packet_for_reassembly( TcpDataBlock * ); - virtual void insert_segment_in_empty_seglist( TcpDataBlock *tdb ); - virtual int insert_segment_in_seglist( TcpDataBlock* tdb ); - virtual void purge_segment_list( void ); - virtual int flush_stream( Packet *p, uint32_t dir); - virtual int purge_flushed_ackd( void ); - virtual void flush_queued_segments(Flow* flow, bool clear, Packet* p = nullptr); - virtual bool is_segment_pending_flush( void ); - virtual uint32_t get_pending_segment_count( unsigned max ); - virtual int flush_on_data_policy( Packet* ); - virtual int flush_on_ack_policy( Packet* ); - void trace_segments( void ); + virtual ~TcpReassembler() { } + virtual int queue_packet_for_reassembly(TcpSegmentDescriptor&); + virtual void purge_segment_list(void); + virtual int flush_stream(Packet* p, uint32_t dir); + virtual int purge_flushed_ackd(void); + virtual void flush_queued_segments(Flow* flow, bool clear, Packet* p = nullptr); + virtual bool is_segment_pending_flush(void); + virtual int flush_on_data_policy(Packet*); + virtual int flush_on_ack_policy(Packet*); void set_seglist_base_seq(uint32_t seglist_base_seq) { this->seglist_base_seq = seglist_base_seq; - DebugFormat(DEBUG_STREAM_STATE, "seglist_base_seq = %X\n", seglist_base_seq ); + DebugFormat(DEBUG_STREAM_STATE, "seglist_base_seq = %X\n", seglist_base_seq); } uint32_t get_seglist_base_seq() const @@ -118,7 +107,7 @@ public: return reassembly_policy; } - int purge_to_seq( uint32_t flush_seq ); + void trace_segments(void); protected: bool server_side; @@ -128,13 +117,13 @@ protected: 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 ) + TcpReassembler(TcpSession* session, TcpTracker* tracker, StreamPolicy os_policy, bool server) : + server_side(server), tracker(tracker), flush_count(0), xtradata_mask(0) { this->session = session; - set_tcp_reassembly_policy( os_policy ); + set_tcp_reassembly_policy(os_policy); - if( server_side ) + if ( server_side ) { ignore_dir = SSN_DIR_FROM_CLIENT; packet_dir = PKT_FROM_CLIENT; @@ -150,26 +139,40 @@ protected: seglist.next = nullptr; } - bool flush_data_ready( void ); - int trim_delete_reassembly_segment( TcpSegment* seg, uint32_t flush_seq); - void queue_reassembly_segment(TcpSegment *prev, TcpSegment *ss); - void init_overlap_editor( TcpDataBlock* tdb ); - bool is_segment_fasttrack(TcpSegment *tail, TcpDataBlock *tdb); - int purge_alerts( uint32_t /*flush_seq*/, Flow* flow); - void show_rebuilt_packet( Packet* pkt ); - uint32_t get_flush_data_len( TcpSegment *ss, uint32_t to_seq, uint32_t flushBufSize); - int flush_data_segments(Packet* p, uint32_t toSeq, uint8_t *flushbuf, const uint8_t *flushbuf_end); + int add_reassembly_segment(TcpSegmentDescriptor&, int16_t len, uint32_t slide, uint32_t trunc, + uint32_t seq, TcpSegmentNode* left) override; + int dup_reassembly_segment(Packet* p, TcpSegmentNode* left, TcpSegmentNode** retSeg) override; + int delete_reassembly_segment(TcpSegmentNode* seg) override; + + virtual void insert_segment_in_empty_seglist(TcpSegmentDescriptor&); + virtual int insert_segment_in_seglist(TcpSegmentDescriptor&); + + void set_tcp_reassembly_policy(StreamPolicy os_policy); + virtual uint32_t get_pending_segment_count(unsigned max); + + bool flush_data_ready(void); + int trim_delete_reassembly_segment(TcpSegmentNode* seg, uint32_t flush_seq); + void queue_reassembly_segment(TcpSegmentNode* prev, TcpSegmentNode* ss); + void init_overlap_editor(TcpSegmentDescriptor&); + bool is_segment_fasttrack(TcpSegmentNode* tail, TcpSegmentDescriptor&); + int purge_alerts(uint32_t /*flush_seq*/, Flow* flow); + void show_rebuilt_packet(Packet* pkt); + uint32_t get_flush_data_len(TcpSegmentNode* ss, uint32_t to_seq, uint32_t flushBufSize); + int flush_data_segments(Packet* p, uint32_t toSeq, uint8_t* flushbuf, const + uint8_t* flushbuf_end); void prep_s5_pkt(Flow* flow, Packet* p, uint32_t pkt_flags); - int _flush_to_seq( uint32_t bytes, Packet *p, uint32_t pkt_flags ); - int flush_to_seq( uint32_t bytes, Packet *p, uint32_t pkt_flags ); - uint32_t get_q_footprint( void ); - uint32_t get_q_sequenced( void ); + int _flush_to_seq(uint32_t bytes, Packet* p, uint32_t pkt_flags); + int flush_to_seq(uint32_t bytes, Packet* p, uint32_t pkt_flags); + uint32_t get_q_footprint(void); + uint32_t get_q_sequenced(void); void final_flush(Packet* p, PegCount& peg, uint32_t dir); uint32_t get_reverse_packet_dir(const Packet* p); uint32_t get_forward_packet_dir(const Packet* p); - uint32_t flush_pdu_ips( uint32_t* flags ); - void fallback( void ); - uint32_t flush_pdu_ackd( uint32_t* flags ); + uint32_t flush_pdu_ips(uint32_t* flags); + void fallback(void); + uint32_t flush_pdu_ackd(uint32_t* flags); + int purge_to_seq(uint32_t flush_seq); }; #endif + diff --git a/src/stream/tcp/tcp_reassemblers.cc b/src/stream/tcp/tcp_reassemblers.cc index 8b50bbcd3..34972720b 100644 --- a/src/stream/tcp/tcp_reassemblers.cc +++ b/src/stream/tcp/tcp_reassemblers.cc @@ -20,16 +20,16 @@ // Created on: Oct 9, 2015 #include "tcp_module.h" -#include "tcp_events.h" +#include "tcp_event_logger.h" #include "tcp_session.h" #include "tcp_reassemblers.h" class TcpReassemblerFirst : public TcpReassembler { public: - TcpReassemblerFirst( TcpSession* session, TcpTracker* tracker, bool server ) : - TcpReassembler( session, tracker, StreamPolicy::OS_FIRST, server ) - { } + TcpReassemblerFirst(TcpSession* session, TcpTracker* tracker, bool server) : + TcpReassembler(session, tracker, StreamPolicy::OS_FIRST, server) + { } private: int insert_left_overlap(void) override @@ -51,9 +51,9 @@ private: class TcpReassemblerLast : public TcpReassembler { public: - TcpReassemblerLast( TcpSession* session, TcpTracker* tracker, bool server ) : - TcpReassembler( session, tracker, StreamPolicy::OS_LAST, server ) - { } + TcpReassemblerLast(TcpSession* session, TcpTracker* tracker, bool server) : + TcpReassembler(session, tracker, StreamPolicy::OS_LAST, server) + { } private: int insert_left_overlap(void) override @@ -75,9 +75,9 @@ private: class TcpReassemblerLinux : public TcpReassembler { public: - TcpReassemblerLinux( TcpSession* session, TcpTracker* tracker, bool server ) : - TcpReassembler( session, tracker, StreamPolicy::OS_LINUX, server ) - { } + TcpReassemblerLinux(TcpSession* session, TcpTracker* tracker, bool server) : + TcpReassembler(session, tracker, StreamPolicy::OS_LINUX, server) + { } private: int insert_left_overlap(void) override @@ -99,9 +99,9 @@ private: class TcpReassemblerOldLinux : public TcpReassembler { public: - TcpReassemblerOldLinux( TcpSession* session, TcpTracker* tracker, bool server ) : - TcpReassembler( session, tracker, StreamPolicy::OS_OLD_LINUX, server ) - { } + TcpReassemblerOldLinux(TcpSession* session, TcpTracker* tracker, bool server) : + TcpReassembler(session, tracker, StreamPolicy::OS_OLD_LINUX, server) + { } private: int insert_left_overlap(void) override @@ -123,9 +123,9 @@ private: class TcpReassemblerBSD : public TcpReassembler { public: - TcpReassemblerBSD( TcpSession* session, TcpTracker* tracker, bool server ) : - TcpReassembler( session, tracker, StreamPolicy::OS_BSD, server ) - { } + TcpReassemblerBSD(TcpSession* session, TcpTracker* tracker, bool server) : + TcpReassembler(session, tracker, StreamPolicy::OS_BSD, server) + { } private: int insert_left_overlap(void) override @@ -147,9 +147,9 @@ private: class TcpReassemblerMacOS : public TcpReassembler { public: - TcpReassemblerMacOS( TcpSession* session, TcpTracker* tracker, bool server ) : - TcpReassembler( session, tracker, StreamPolicy::OS_MACOS, server ) - { } + TcpReassemblerMacOS(TcpSession* session, TcpTracker* tracker, bool server) : + TcpReassembler(session, tracker, StreamPolicy::OS_MACOS, server) + { } private: int insert_left_overlap(void) override @@ -171,9 +171,9 @@ private: class TcpReassemblerSolaris : public TcpReassembler { public: - TcpReassemblerSolaris( TcpSession* session, TcpTracker* tracker, bool server ) : - TcpReassembler( session, tracker, StreamPolicy::OS_SOLARIS, server ) - { } + TcpReassemblerSolaris(TcpSession* session, TcpTracker* tracker, bool server) : + TcpReassembler(session, tracker, StreamPolicy::OS_SOLARIS, server) + { } private: int insert_left_overlap(void) override @@ -195,9 +195,9 @@ private: class TcpReassemblerIrix : public TcpReassembler { public: - TcpReassemblerIrix( TcpSession* session, TcpTracker* tracker, bool server ) : - TcpReassembler( session, tracker, StreamPolicy::OS_IRIX, server ) - { } + TcpReassemblerIrix(TcpSession* session, TcpTracker* tracker, bool server) : + TcpReassembler(session, tracker, StreamPolicy::OS_IRIX, server) + { } private: int insert_left_overlap(void) override @@ -214,15 +214,14 @@ private: { return full_right_overlap_os2( ); } - }; class TcpReassemblerHpux11 : public TcpReassembler { public: - TcpReassemblerHpux11( TcpSession* session, TcpTracker* tracker, bool server ) : - TcpReassembler( session, tracker, StreamPolicy::OS_HPUX11, server ) - { } + TcpReassemblerHpux11(TcpSession* session, TcpTracker* tracker, bool server) : + TcpReassembler(session, tracker, StreamPolicy::OS_HPUX11, server) + { } private: int insert_left_overlap(void) override @@ -244,57 +243,57 @@ private: class TcpReassemblerHpux10 : public TcpReassembler { public: - TcpReassemblerHpux10( TcpSession* session, TcpTracker* tracker, bool server ) : - TcpReassembler( session, tracker, StreamPolicy::OS_HPUX10, server ) - { } + TcpReassemblerHpux10(TcpSession* session, TcpTracker* tracker, bool server) : + TcpReassembler(session, tracker, StreamPolicy::OS_HPUX10, server) + { } private: int insert_left_overlap(void) override - { + { return left_overlap_keep_first( ); - } + } void insert_right_overlap(void) override - { + { right_overlap_truncate_existing( ); - } + } int insert_full_overlap(void) override - { + { return full_right_overlap_os2( ); - } + } }; class TcpReassemblerWindows : public TcpReassembler { public: - TcpReassemblerWindows( TcpSession* session, TcpTracker* tracker, bool server ) : - TcpReassembler( session, tracker, StreamPolicy::OS_WINDOWS, server ) - { } + TcpReassemblerWindows(TcpSession* session, TcpTracker* tracker, bool server) : + TcpReassembler(session, tracker, StreamPolicy::OS_WINDOWS, server) + { } private: int insert_left_overlap(void) override - { - return left_overlap_keep_first( ); - } - - void insert_right_overlap(void) override - { - right_overlap_truncate_existing( ); - } - - int insert_full_overlap(void) override - { - return full_right_overlap_os1( ); - } + { + return left_overlap_keep_first( ); + } + + void insert_right_overlap(void) override + { + right_overlap_truncate_existing( ); + } + + int insert_full_overlap(void) override + { + return full_right_overlap_os1( ); + } }; class TcpReassemblerWindows2K3 : public TcpReassembler { public: - TcpReassemblerWindows2K3( TcpSession* session, TcpTracker* tracker, bool server) : - TcpReassembler( session, tracker, StreamPolicy::OS_WINDOWS2K3, server ) - { } + TcpReassemblerWindows2K3(TcpSession* session, TcpTracker* tracker, bool server) : + TcpReassembler(session, tracker, StreamPolicy::OS_WINDOWS2K3, server) + { } private: int insert_left_overlap(void) override @@ -316,9 +315,9 @@ private: class TcpReassemblerVista : public TcpReassembler { public: - TcpReassemblerVista( TcpSession* session, TcpTracker* tracker, bool server ) : - TcpReassembler( session, tracker, StreamPolicy::OS_VISTA, server ) - { } + TcpReassemblerVista(TcpSession* session, TcpTracker* tracker, bool server) : + TcpReassembler(session, tracker, StreamPolicy::OS_VISTA, server) + { } private: int insert_left_overlap(void) override @@ -340,8 +339,8 @@ private: class TcpReassemblerProxy : public TcpReassemblerFirst { public: - TcpReassemblerProxy( TcpSession* session, TcpTracker* tracker, bool server ) : - TcpReassemblerFirst( session, tracker, server ) + TcpReassemblerProxy(TcpSession* session, TcpTracker* tracker, bool server) : + TcpReassemblerFirst(session, tracker, server) { tcp_ips_data = NORM_MODE_OFF; } @@ -363,78 +362,77 @@ private: } }; -TcpReassembler* TcpReassemblerFactory::create( TcpSession* session, TcpTracker* tracker, - StreamPolicy os_policy, bool server ) +TcpReassembler* TcpReassemblerFactory::create(TcpSession* session, TcpTracker* tracker, + StreamPolicy os_policy, bool server) { NormMode tcp_ips_data = Normalize_GetMode(NORM_TCP_IPS); if (tcp_ips_data == NORM_MODE_ON) - return new TcpReassemblerFirst( session, tracker, server ); + return new TcpReassemblerFirst(session, tracker, server); else { switch (os_policy) { case StreamPolicy::OS_FIRST: - return new TcpReassemblerFirst( session, tracker, server ); + return new TcpReassemblerFirst(session, tracker, server); break; case StreamPolicy::OS_LAST: - return new TcpReassemblerLast( session, tracker, server ); + return new TcpReassemblerLast(session, tracker, server); break; case StreamPolicy::OS_LINUX: - return new TcpReassemblerLinux( session, tracker, server ); + return new TcpReassemblerLinux(session, tracker, server); break; case StreamPolicy::OS_OLD_LINUX: - return new TcpReassemblerOldLinux( session, tracker, server ); + return new TcpReassemblerOldLinux(session, tracker, server); break; case StreamPolicy::OS_BSD: - return new TcpReassemblerBSD( session, tracker, server ); + return new TcpReassemblerBSD(session, tracker, server); break; case StreamPolicy::OS_MACOS: - return new TcpReassemblerMacOS( session, tracker, server ); + return new TcpReassemblerMacOS(session, tracker, server); break; case StreamPolicy::OS_SOLARIS: - return new TcpReassemblerSolaris( session, tracker, server ); + return new TcpReassemblerSolaris(session, tracker, server); break; case StreamPolicy::OS_IRIX: - return new TcpReassemblerIrix( session, tracker, server ); + return new TcpReassemblerIrix(session, tracker, server); break; case StreamPolicy::OS_HPUX11: - return new TcpReassemblerHpux11( session, tracker, server ); + return new TcpReassemblerHpux11(session, tracker, server); break; case StreamPolicy::OS_HPUX10: - return new TcpReassemblerHpux10( session, tracker, server ); + return new TcpReassemblerHpux10(session, tracker, server); break; case StreamPolicy::OS_WINDOWS: - return new TcpReassemblerWindows( session, tracker, server ); + return new TcpReassemblerWindows(session, tracker, server); break; case StreamPolicy::OS_WINDOWS2K3: - return new TcpReassemblerWindows2K3( session, tracker, server ); + return new TcpReassemblerWindows2K3(session, tracker, server); break; case StreamPolicy::OS_VISTA: - return new TcpReassemblerVista( session, tracker, server ); + return new TcpReassemblerVista(session, tracker, server); break; case StreamPolicy::OS_PROXY: - return new TcpReassemblerProxy( session, tracker, server ); + return new TcpReassemblerProxy(session, tracker, server); break; default: - return new TcpReassemblerBSD( session, tracker, server ); + return new TcpReassemblerBSD(session, tracker, server); break; } - } } diff --git a/src/stream/tcp/tcp_reassemblers.h b/src/stream/tcp/tcp_reassemblers.h index 72fb081d7..5ee793a70 100644 --- a/src/stream/tcp/tcp_reassemblers.h +++ b/src/stream/tcp/tcp_reassemblers.h @@ -28,8 +28,9 @@ class TcpReassemblerFactory { public: - static TcpReassembler* create( TcpSession* session, TcpTracker* tracker, - StreamPolicy os_policy, bool server ); + static TcpReassembler* create(TcpSession* session, TcpTracker* tracker, + StreamPolicy os_policy, bool server); }; #endif + diff --git a/src/stream/tcp/tcp_segment.cc b/src/stream/tcp/tcp_segment_node.cc similarity index 67% rename from src/stream/tcp/tcp_segment.cc rename to src/stream/tcp/tcp_segment_node.cc index 69fc1e0ab..f3a4ce6a6 100644 --- a/src/stream/tcp/tcp_segment.cc +++ b/src/stream/tcp/tcp_segment_node.cc @@ -19,22 +19,21 @@ // tcp_segment.cc author davis mcpherson // Created on: Sep 21, 2015 +#include #include "flow/flow_control.h" #include "perf_monitor/perf.h" #include "protocols/packet.h" #include "tcp_module.h" -#include "tcp_segment.h" THREAD_LOCAL Memcap* tcp_memcap = nullptr; -TcpSegment::TcpSegment() : - prev( nullptr ), next( nullptr ), tv( { 0, 0 } ), ts( 0 ), seq( 0 ), orig_dsize( 0 ), - payload_size( 0 ), urg_offset( 0 ), buffered( false ), data(nullptr), payload( nullptr ) +TcpSegmentNode::TcpSegmentNode() : + prev(nullptr), next(nullptr), tv({ 0, 0 }), ts(0), seq(0), orig_dsize(0), + payload_size(0), urg_offset(0), buffered(false), data(nullptr), payload(nullptr) { - } -TcpSegment::~TcpSegment() +TcpSegmentNode::~TcpSegmentNode() { // TODO Auto-generated destructor stub } @@ -43,19 +42,19 @@ TcpSegment::~TcpSegment() // TcpSegment stuff //------------------------------------------------------------------------- -TcpSegment* TcpSegment::init( const struct timeval& tv, const uint8_t* data, unsigned dsize) +TcpSegmentNode* TcpSegmentNode::init(const struct timeval& tv, const uint8_t* data, unsigned dsize) { - TcpSegment* ss; + TcpSegmentNode* ss; - tcp_memcap->alloc( dsize ); - ss = new TcpSegment; - if( !ss ) + tcp_memcap->alloc(dsize); + ss = new TcpSegmentNode; + if ( !ss ) { - tcp_memcap->dealloc( dsize ); + tcp_memcap->dealloc(dsize); return nullptr; } - ss->data = ( uint8_t * ) malloc( dsize ); + ss->data = ( uint8_t* )malloc(dsize); ss->payload = ss->data; ss->tv = tv; memcpy(ss->payload, data, dsize); @@ -65,23 +64,24 @@ TcpSegment* TcpSegment::init( const struct timeval& tv, const uint8_t* data, uns return ss; } -void TcpSegment::term( void ) +void TcpSegmentNode::term(void) { - tcp_memcap->dealloc( orig_dsize ); - free( data ); + tcp_memcap->dealloc(orig_dsize); + free(data); tcpStats.segs_released++; delete this; } -bool TcpSegment::is_retransmit( const uint8_t* rdata, uint16_t rsize, uint32_t rseq ) +bool TcpSegmentNode::is_retransmit(const uint8_t* rdata, uint16_t rsize, uint32_t rseq) { // retransmit must have same payload at same place - if( !SEQ_EQ( seq, rseq ) ) + if ( !SEQ_EQ(seq, rseq) ) return false; - if( ( ( payload_size <= rsize ) and !memcmp( data, rdata, payload_size ) ) - or ( ( payload_size > rsize ) and !memcmp( data, rdata, rsize ) ) ) + if ( ( ( payload_size <= rsize )and !memcmp(data, rdata, payload_size) ) + or ( ( payload_size > rsize )and !memcmp(data, rdata, rsize) ) ) return true; return false; } + diff --git a/src/stream/tcp/tcp_segment.h b/src/stream/tcp/tcp_segment_node.h similarity index 74% rename from src/stream/tcp/tcp_segment.h rename to src/stream/tcp/tcp_segment_node.h index 1f85af287..c4c22f56c 100644 --- a/src/stream/tcp/tcp_segment.h +++ b/src/stream/tcp/tcp_segment_node.h @@ -22,6 +22,7 @@ #ifndef TCP_SEGMENT_H #define TCP_SEGMENT_H +#include "main/snort_debug.h" #include "protocols/packet.h" #include "flow/memcap.h" @@ -33,24 +34,23 @@ extern THREAD_LOCAL Memcap* tcp_memcap; // ... however, use of padding below is critical, adjust if needed //----------------------------------------------------------------- - -class TcpSegment +class TcpSegmentNode { public: - TcpSegment(); - virtual ~TcpSegment(); + TcpSegmentNode(); + virtual ~TcpSegmentNode(); - static TcpSegment* init( const struct timeval&, const uint8_t*, unsigned ); - static bool needs_pruning( void ) + static TcpSegmentNode* init(const struct timeval&, const uint8_t*, unsigned); + static bool needs_pruning(void) { return tcp_memcap->at_max(); } - void term( void ); - bool is_retransmit( const uint8_t*, uint16_t size, uint32_t ); + void term(void); + bool is_retransmit(const uint8_t*, uint16_t size, uint32_t); - TcpSegment *prev; - TcpSegment *next; + TcpSegmentNode* prev; + TcpSegmentNode* next; struct timeval tv; uint32_t ts; @@ -62,27 +62,38 @@ public: uint8_t* data; uint8_t* payload; - }; class TcpSegmentList { public: - TcpSegment *head; - TcpSegment *tail; + TcpSegmentList(void) : + head(nullptr), tail(nullptr), next(nullptr), count(0) + { + } + + ~TcpSegmentList(void) + { + clear( ); + } + + TcpSegmentNode* head; + TcpSegmentNode* tail; // FIXIT-P seglist_base_seq is the sequence number to flush from // and is valid even when seglist is empty. next points to // the segment to flush from and is set per packet. should keep // up to date. - TcpSegment* next; + TcpSegmentNode* next; + + uint32_t count; - uint32_t clear( void ) + uint32_t clear(void) { - TcpSegment *dump_me; + TcpSegmentNode* dump_me; int i = 0; - DebugMessage(DEBUG_STREAM_STATE, "Clearing ssment list.\n"); + DebugMessage(DEBUG_STREAM_STATE, "Clearing segment list.\n"); while ( head ) { i++; @@ -92,18 +103,19 @@ public: } head = tail = next = nullptr; + count = 0; DebugFormat(DEBUG_STREAM_STATE, "Dropped %d segments\n", i); return i; } - void insert( TcpSegment *prev, TcpSegment *ss ) + void insert(TcpSegmentNode* prev, TcpSegmentNode* ss) { - if( prev ) + if ( prev ) { ss->next = prev->next; ss->prev = prev; prev->next = ss; - if( ss->next ) + if ( ss->next ) ss->next->prev = ss; else tail = ss; @@ -111,26 +123,31 @@ public: else { ss->next = head; - if( ss->next ) + if ( ss->next ) ss->next->prev = ss; else tail = ss; head = ss; } + + count++; } - void remove( TcpSegment *ss ) + void remove(TcpSegmentNode* ss) { if (ss->prev) ss->prev->next = ss->next; else - head = ss->next; + head = ss->next; if (ss->next) ss->next->prev = ss->prev; else tail = ss->prev; + + count--; } }; #endif + diff --git a/src/stream/tcp/tcp_session.cc b/src/stream/tcp/tcp_session.cc index 381d414a3..41f23b5ba 100644 --- a/src/stream/tcp/tcp_session.cc +++ b/src/stream/tcp/tcp_session.cc @@ -42,8 +42,6 @@ * - limit on number of overlapping packets (done, SAS) */ -#include "tcp_session.h" - #ifdef HAVE_CONFIG_H #include "config.h" #endif @@ -51,24 +49,6 @@ #include #include -#include "stream_tcp.h" -#include "tcp_module.h" - -// TBD-EDM - these includes are for functions moved to a new file to group related functionality -// in specific files ... these functional groups will be further refactored as the stream tcp -// rewrite continues... -#include "tcp_events.h" -#include "tcp_debug_trace.h" - -#include "stream/libtcp/tcp_state_handler.h" -#include "tcp_closed_state.h" -#include "tcp_listen_state.h" -#include "tcp_syn_sent_state.h" -#include "tcp_syn_recv_state.h" -#include "tcp_normalizers.h" -#include "tcp_reassemblers.h" -// TBD-EDM - #include "main/snort_types.h" #include "main/snort_debug.h" #include "main/snort_config.h" @@ -96,49 +76,30 @@ #include "sfip/sf_ip.h" #include "filters/sfrf.h" -using namespace tcp; - -/* M A C R O S **************************************************/ - -#define STREAM_UNALIGNED 0 -#define STREAM_ALIGNED 1 - -#define STREAM_DEFAULT_MAX_QUEUED_BYTES 1048576 /* 1 MB */ -#define AVG_PKT_SIZE 400 -#define STREAM_DEFAULT_MAX_QUEUED_SEGS (STREAM_DEFAULT_MAX_QUEUED_BYTES/AVG_PKT_SIZE) - -#define STREAM_DEFAULT_MAX_SMALL_SEG_SIZE 0 /* disabled */ -#define STREAM_DEFAULT_CONSEC_SMALL_SEGS 0 /* disabled */ - -#define SLAM_MAX 4 - -/* P R O T O T Y P E S ********************************************/ - -static int ProcessTcp(Flow*, TcpDataBlock*, StreamTcpConfig*); +#include "stream/paf.h" +#include "stream_tcp.h" +#include "tcp_module.h" +#include "tcp_event_logger.h" +#include "tcp_debug_trace.h" -/* G L O B A L S **************************************************/ +#include "tcp_state_none.h" +#include "tcp_state_closed.h" +#include "tcp_state_listen.h" +#include "tcp_state_syn_sent.h" +#include "tcp_state_syn_recv.h" +#include "tcp_state_established.h" +#include "tcp_state_close_wait.h" +#include "tcp_state_closing.h" +#include "tcp_state_fin_wait1.h" +#include "tcp_state_fin_wait2.h" +#include "tcp_state_last_ack.h" +#include "tcp_state_time_wait.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" }; +#include "tcp_normalizers.h" +#include "tcp_reassemblers.h" +#include "tcp_session.h" #ifdef DEBUG -static const char* const state_names[] = -{ - "none", - "listen", - "syn_rcvd", - "syn_sent", - "established", - "close_wait", - "last_ack", - "fin_wait_1", - "closing", - "fin_wait_2", - "time_wait", - "closed" -}; - const char* const flush_policy_names[] = { "ignore", @@ -147,144 +108,90 @@ const char* const flush_policy_names[] = }; #endif -//------------------------------------------------------------------------- -// flush policy stuff -//------------------------------------------------------------------------- - -static inline void init_flush_policy(Flow*, TcpTracker* trk) -{ - if (!trk->splitter) - trk->flush_policy = STREAM_FLPOLICY_IGNORE; - else if (!trk->normalizer->is_tcp_ips_enabled() ) - trk->flush_policy = STREAM_FLPOLICY_ON_ACK; - else - trk->flush_policy = STREAM_FLPOLICY_ON_DATA; -} - -void StreamUpdatePerfBaseState(SFBASE *sf_base, Flow *flow, char newState) +void TcpSession::update_perf_base_state(SFBASE* sf_base, char newState) { - if (!flow) - return; - uint32_t session_flags = flow->get_session_flags(); - switch (newState) + switch ( newState ) { - case TCP_STATE_SYN_SENT: - if (!(session_flags & SSNFLAG_COUNTED_INITIALIZE)) - { - sf_base->iSessionsInitializing++; - session_flags |= SSNFLAG_COUNTED_INITIALIZE; - } - break; - - case TCP_STATE_ESTABLISHED: - if (!(session_flags & SSNFLAG_COUNTED_ESTABLISH)) - { - sf_base->iSessionsEstablished++; + case TcpStreamTracker::TCP_SYN_SENT: + if ( !( session_flags & SSNFLAG_COUNTED_INITIALIZE ) ) + { + sf_base->iSessionsInitializing++; + session_flags |= SSNFLAG_COUNTED_INITIALIZE; + } + break; - if (perfmon_config && (perfmon_config->perf_flags & SFPERF_FLOWIP)) - UpdateFlowIPState(&sfFlow, &flow->client_ip, &flow->server_ip, SFS_STATE_TCP_ESTABLISHED); + case TcpStreamTracker::TCP_ESTABLISHED: + if ( !( session_flags & SSNFLAG_COUNTED_ESTABLISH ) ) + { + sf_base->iSessionsEstablished++; - session_flags |= SSNFLAG_COUNTED_ESTABLISH; + if ( perfmon_config && ( perfmon_config->perf_flags & SFPERF_FLOWIP ) ) + UpdateFlowIPState(&sfFlow, &flow->client_ip, + &flow->server_ip, SFS_STATE_TCP_ESTABLISHED); - if ((session_flags & SSNFLAG_COUNTED_INITIALIZE) - && !(session_flags & SSNFLAG_COUNTED_CLOSING)) - { - assert(sf_base->iSessionsInitializing); - sf_base->iSessionsInitializing--; - } - } - break; + session_flags |= SSNFLAG_COUNTED_ESTABLISH; - case TCP_STATE_CLOSING: - if (!(session_flags & SSNFLAG_COUNTED_CLOSING)) + if ( ( session_flags & SSNFLAG_COUNTED_INITIALIZE ) + && !( session_flags & SSNFLAG_COUNTED_CLOSING ) ) { - sf_base->iSessionsClosing++; - session_flags |= SSNFLAG_COUNTED_CLOSING; - - if (session_flags & SSNFLAG_COUNTED_ESTABLISH) - { - assert(sf_base->iSessionsEstablished); - sf_base->iSessionsEstablished--; - - if (perfmon_config && (perfmon_config->perf_flags & SFPERF_FLOWIP)) - UpdateFlowIPState(&sfFlow, &flow->client_ip, &flow->server_ip, SFS_STATE_TCP_CLOSED); - } - else if (session_flags & SSNFLAG_COUNTED_INITIALIZE) - { - assert(sf_base->iSessionsInitializing); - sf_base->iSessionsInitializing--; - } + assert(sf_base->iSessionsInitializing); + sf_base->iSessionsInitializing--; } - break; + } + break; - case TCP_STATE_CLOSED: - if ( session_flags & SSNFLAG_COUNTED_CLOSING ) - { - assert(sf_base->iSessionsClosing); - sf_base->iSessionsClosing--; - } - else if (session_flags & SSNFLAG_COUNTED_ESTABLISH) + case TcpStreamTracker::TCP_CLOSING: + if ( !( session_flags & SSNFLAG_COUNTED_CLOSING ) ) + { + sf_base->iSessionsClosing++; + session_flags |= SSNFLAG_COUNTED_CLOSING; + + if ( session_flags & SSNFLAG_COUNTED_ESTABLISH ) { assert(sf_base->iSessionsEstablished); sf_base->iSessionsEstablished--; - if (perfmon_config && (perfmon_config->perf_flags & SFPERF_FLOWIP)) - UpdateFlowIPState(&sfFlow, &flow->client_ip, &flow->server_ip, SFS_STATE_TCP_CLOSED); + if ( perfmon_config && ( perfmon_config->perf_flags & SFPERF_FLOWIP ) ) + UpdateFlowIPState(&sfFlow, &flow->client_ip, + &flow->server_ip, SFS_STATE_TCP_CLOSED); } - else if (session_flags & SSNFLAG_COUNTED_INITIALIZE) + else if ( session_flags & SSNFLAG_COUNTED_INITIALIZE ) { assert(sf_base->iSessionsInitializing); sf_base->iSessionsInitializing--; } - break; - - default: - break; - } - - flow->update_session_flags( session_flags ); - sf_base->stream_mem_in_use = tcp_memcap->used(); -} - -//------------------------------------------------------------------------- -// config methods -//------------------------------------------------------------------------- - -StreamTcpConfig::StreamTcpConfig() -{ - 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; + } + break; - hs_timeout = -1; - footprint = 0; - paf_max = 16384; -} + case TcpStreamTracker::TCP_CLOSED: + if ( session_flags & SSNFLAG_COUNTED_CLOSING ) + { + assert(sf_base->iSessionsClosing); + sf_base->iSessionsClosing--; + } + else if ( session_flags & SSNFLAG_COUNTED_ESTABLISH ) + { + assert(sf_base->iSessionsEstablished); + sf_base->iSessionsEstablished--; -inline bool StreamTcpConfig::require_3whs() -{ - return hs_timeout >= 0; -} + if ( perfmon_config && ( perfmon_config->perf_flags & SFPERF_FLOWIP ) ) + UpdateFlowIPState(&sfFlow, &flow->client_ip, + &flow->server_ip, SFS_STATE_TCP_CLOSED); + } + else if ( session_flags & SSNFLAG_COUNTED_INITIALIZE ) + { + assert(sf_base->iSessionsInitializing); + sf_base->iSessionsInitializing--; + } + break; -inline bool StreamTcpConfig::midstream_allowed(Packet* p) -{ - if ((hs_timeout < 0) || (p->pkth->ts.tv_sec - packet_first_time() < hs_timeout)) - return true; + default: + break; + } - return false; + flow->update_session_flags(session_flags); + sf_base->stream_mem_in_use = tcp_memcap->used(); } //------------------------------------------------------------------------- @@ -300,117 +207,9 @@ inline bool StreamTcpConfig::midstream_allowed(Packet* p) // make sense of the code in this file. //------------------------------------------------------------------------- -static void StreamPrintTcpConfig(StreamTcpConfig* config) -{ - LogMessage("Stream TCP Policy config:\n"); - LogMessage(" Reassembly Policy: %s\n", - reassembly_policy_names[ static_cast( config->reassembly_policy ) ] ); - LogMessage(" Timeout: %d seconds\n", config->session_timeout); - - if (config->max_window != 0) - LogMessage(" Max TCP Window: %u\n", config->max_window); - - if (config->overlap_limit) - LogMessage(" Limit on TCP Overlaps: %d\n", config->overlap_limit); - - if (config->max_queued_bytes != 0) - LogMessage(" Maximum number of bytes to queue per session: %d\n", config->max_queued_bytes); - - if (config->max_queued_segs != 0) - LogMessage(" Maximum number of segs to queue per session: %d\n", config->max_queued_segs); - - if (config->flags) - { - LogMessage(" Options:\n"); - if (config->flags & STREAM_CONFIG_IGNORE_ANY) - LogMessage(" Ignore Any -> Any Rules: YES\n"); - - if (config->flags & STREAM_CONFIG_NO_ASYNC_REASSEMBLY) - LogMessage( " Don't queue packets on one-sided sessions: YES\n"); - } - - if (config->hs_timeout < 0) - LogMessage(" Require 3-Way Handshake: NO\n"); - else - LogMessage(" Require 3-Way Handshake: after %d seconds\n", config->hs_timeout); - -#ifdef REG_TEST - LogMessage(" TCP Session Size: %lu\n",sizeof(TcpSession)); -#endif -} - -//------------------------------------------------------------------------- -// attribute table foo -//------------------------------------------------------------------------- - -int StreamVerifyTcpConfig(SnortConfig*, StreamTcpConfig*) -{ - return 0; -} - #ifdef DEBUG_STREAM_EX -static void PrintStateMgr(StateMgr* s) -{ - LogMessage("StateMgr:\n"); - LogMessage(" state: %s\n", state_names[s->state]); - LogMessage(" state_queue: %s\n", state_names[s->state_queue]); - LogMessage(" expected_flags: 0x%X\n", s->expected_flags); - LogMessage(" transition_seq: 0x%X\n", s->transition_seq); - LogMessage(" stq_get_seq: %d\n", s->stq_get_seq); -} - -static void PrintTcpTracker(TcpTracker *s) -{ - LogMessage(" + TcpTracker +\n"); - LogMessage(" isn: 0x%X\n", s->isn); - LogMessage(" ts_last: %u\n", s->ts_last); - LogMessage(" wscale: %u\n", s->wscale); - LogMessage(" mss: 0x%08X\n", s->mss); - LogMessage(" l_unackd: %X\n", s->l_unackd); - LogMessage(" l_nxt_seq: %X\n", s->l_nxt_seq); - LogMessage(" l_window: %u\n", s->l_window); - LogMessage(" r_nxt_ack: %X\n", s->r_nxt_ack); - LogMessage(" r_win_base: %X\n", s->r_win_base); - LogMessage(" seglist_base_seq: %X\n", s->reassembler->get_seglist_base_seq( )); - LogMessage(" seglist: %p\n", (void*)s->seglist); - LogMessage(" seglist_tail: %p\n", (void*)s->seglist_tail); - LogMessage(" seg_count: %d\n", s->reassembler->get_seg_count()); - LogMessage(" seg_bytes_total: %d\n", s->reassembler->get_seg_bytes_total()); - LogMessage(" seg_bytes_logical: %d\n", s->get_seg_bytes_logical() ); - - PrintStateMgr(&s->s_mgr); -} - -static void PrintTcpSession(TcpSession* ts) -{ - char buf[64]; - - LogMessage("TcpSession:\n"); - sfip_ntop(&ts->flow->server_ip, buf, sizeof(buf)); - LogMessage(" server IP: %s\n", buf); - sfip_ntop(&ts->flow->client_ip, buf, sizeof(buf)); - LogMessage(" client IP: %s\n", buf); - - LogMessage(" server port: %d\n", ts->flow->server_port); - LogMessage(" client port: %d\n", ts->flow->client_port); - - LogMessage(" flags: 0x%X\n", ts->flow->get_session_flags()); - - LogMessage("Client Tracker:\n"); - PrintTcpTracker(&ts->client); - LogMessage("Server Tracker:\n"); - PrintTcpTracker(&ts->server); -} - -static void PrintTcpDataBlock(TcpDataBlock* tdb) -{ - LogMessage("TcpDataBlock:\n"); - LogMessage(" seq: 0x%08X\n", tdb->seq); - LogMessage(" ack: 0x%08X\n", tdb->ack); - LogMessage(" win: %d\n", tdb->win); - LogMessage(" end: 0x%08X\n", tdb->end_seq); -} - +// FIXIT - FlushMgr is no longer defined - confirm this and delete or refactor to use +// what replaced FlushMgr static void PrintFlushMgr(FlushMgr* fm) { if (fm == NULL) @@ -418,47 +217,69 @@ static void PrintFlushMgr(FlushMgr* fm) switch (fm->flush_policy) { - case STREAM_FLPOLICY_IGNORE: - DebugMessage( DEBUG_STREAM_STATE, " IGNORE\n"); - break; + case STREAM_FLPOLICY_IGNORE: + DebugMessage(DEBUG_STREAM_STATE, " IGNORE\n"); + break; - case STREAM_FLPOLICY_ON_ACK: - DebugMessage( DEBUG_STREAM_STATE, " PROTOCOL\n"); - break; + case STREAM_FLPOLICY_ON_ACK: + DebugMessage(DEBUG_STREAM_STATE, " PROTOCOL\n"); + break; - case STREAM_FLPOLICY_ON_DATA: - DebugMessage( DEBUG_STREAM_STATE, " PROTOCOL_IPS\n"); - break; + case STREAM_FLPOLICY_ON_DATA: + DebugMessage(DEBUG_STREAM_STATE, " PROTOCOL_IPS\n"); + break; } } #endif // DEBUG_STREAM_EX +static inline int is_mac_address_valid(TcpTracker* talker, TcpTracker* listener, Packet* p) +{ + int event_code = 0; + bool t_hijack = true, l_hijack = true; -//------------------------------------------------------------------------- -// ssn ingress is client; ssn egress is server + if (!(p->proto_bits & PROTO_BIT__ETH)) + return 0; -//------------------------------------------------------------------------- + // if flag is set, gauranteed to have an eth layer + const eth::EtherHdr* eh = layer::get_eth_layer(p); -static inline int IsBetween(uint32_t low, uint32_t high, uint32_t cur) -{ - DebugFormat(DEBUG_STREAM_STATE, "(%X, %X, %X) = (low, high, cur)\n", low,high,cur); + if ( talker->compare_mac_addresses(eh->ether_src) ) + { + t_hijack = false; + if ( listener->compare_mac_addresses(eh->ether_dst) ) + l_hijack = false; + } + else if ( listener->compare_mac_addresses(eh->ether_dst) ) + l_hijack = false; - /* If we haven't seen anything, ie, low & high are 0, return true */ - if ((low == 0) && (low == high)) - return 1; + if ( t_hijack & l_hijack ) + { + if ( talker->compare_mac_addresses(eh->ether_dst) && + listener->compare_mac_addresses(eh->ether_src) ) + // this is probably a tap + return event_code; + } - return (SEQ_GEQ(cur, low) && SEQ_LEQ(cur, high)); -} + if ( t_hijack ) + { + if ( p->packet_flags & PKT_FROM_CLIENT ) + event_code |= EVENT_SESSION_HIJACK_CLIENT; + else + event_code |= EVENT_SESSION_HIJACK_SERVER; + } + if ( l_hijack ) + { + if ( p->packet_flags & PKT_FROM_CLIENT ) + event_code |= EVENT_SESSION_HIJACK_SERVER; + else + event_code |= EVENT_SESSION_HIJACK_CLIENT; + } -// ack number must ack syn -static inline int ValidRstSynSent(TcpTracker *st, TcpDataBlock *tdb) -{ - return tdb->ack == st->l_unackd; + return event_code; } - #ifdef S5_PEDANTIC // From RFC 793: // @@ -475,58 +296,61 @@ static inline int ValidRstSynSent(TcpTracker *st, TcpDataBlock *tdb) // >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, TcpDataBlock *tdb ) +static inline int ValidSeq(const Packet* p, Flow* flow, TcpTracker* st, TcpSegmentDescriptor& tsd) { - uint32_t win = st->normalizer->get_stream_window(flow, st, tdb); + uint32_t win = st->normalizer->get_stream_window(flow, st, tsd); if ( !p->dsize ) { if ( !win ) { - return ( tdb->seq == st->r_win_base ); + return ( tsd.get_seq() == st->r_win_base ); } - return SEQ_LEQ(st->r_win_base, tdb->seq) && - SEQ_LT(tdb->seq, st->r_win_base+win); + 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, tdb->seq) && - SEQ_LT(tdb->seq, st->r_win_base+win) ) + 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, tdb->end_seq) && - SEQ_LT(tdb->end_seq, st->r_win_base+win); + 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, TcpDataBlock *tdb) +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", - tdb->end_seq, st->r_win_base, tdb->seq, st->r_nxt_ack + st->normalizer->get_stream_window( tdb )); + 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)) + 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 (tdb->pkt->dsize) - right_ok = SEQ_GT(tdb->end_seq, left_seq); + if ( tsd.get_pkt()->dsize ) + right_ok = SEQ_GT(tsd.get_end_seq(), left_seq); else - right_ok = SEQ_GEQ(tdb->end_seq, left_seq); + right_ok = SEQ_GEQ(tsd.get_end_seq(), left_seq); - if (right_ok) + if ( right_ok ) { - uint32_t win = st->normalizer->get_stream_window( tdb ); + uint32_t win = st->normalizer->get_stream_window(tsd); - if (SEQ_LEQ(tdb->seq, st->r_win_base + win)) + if ( SEQ_LEQ(tsd.get_seq(), st->r_win_base + win) ) { DebugMessage(DEBUG_STREAM_STATE, "seq is within window!\n"); return 1; - } else + } + else { DebugMessage(DEBUG_STREAM_STATE, "seq is past the end of the window!\n"); } @@ -540,294 +364,192 @@ static inline int ValidSeq( TcpTracker *st, TcpDataBlock *tdb) #endif -static inline void UpdateSsn( TcpTracker *rcv, TcpTracker *snd, TcpDataBlock *tdb) +static inline void UpdateSsn(TcpTracker* rcv, TcpTracker* snd, TcpSegmentDescriptor& tsd) { #if 0 - if ( - // 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. :( - rcv->s_mgr.state == TCP_STATE_ESTABLISHED && - rcv->s_mgr.state_queue == TCP_STATE_NONE && - Normalize_IsEnabled(NORM_TCP_IPS) ) - { - // walk the seglist until a gap or tdb->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 ) - { + // 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(tdb->ack, seq) ) - break; + if ( SEQ_LEQ(tsd.get_ack(), seq) ) + break; seg = seg->next; if ( !seg || seg->seq > seq ) { // normalize here - tdb->ack = seq; + 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(tdb->ack, rcv->l_unackd)) - rcv->l_unackd = tdb->ack; + 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->l_unackd = tdb->seq; + snd->set_snd_una(tsd.get_seq() ); - if (SEQ_GT(tdb->end_seq, snd->l_nxt_seq)) - snd->l_nxt_seq = tdb->end_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, tdb->ack)) + if ( !SEQ_EQ(snd->r_win_base, tsd.get_ack() ) ) { snd->small_seg_count = 0; } #ifdef S5_PEDANTIC - if ( SEQ_GT(tdb->ack, snd->r_win_base) && - SEQ_LEQ(tdb->ack, snd->r_nxt_ack) ) + if ( SEQ_GT(tsd.get_ack(), snd->r_win_base) && + SEQ_LEQ(tsd.get_ack(), snd->r_nxt_ack) ) #else - if (SEQ_GT(tdb->ack, snd->r_win_base)) + if ( SEQ_GT(tsd.get_ack(), snd->r_win_base) ) #endif - snd->r_win_base = tdb->ack; - - snd->l_window = tdb->win; -} - -static inline void SetupTcpDataBlock(TcpDataBlock* tdb, Packet* p) -{ - tdb->pkt = p; - tdb->seq = ntohl(p->ptrs.tcph->th_seq); - tdb->ack = ntohl(p->ptrs.tcph->th_ack); - tdb->win = ntohs(p->ptrs.tcph->th_win); - tdb->end_seq = tdb->seq + (uint32_t) p->dsize; - tdb->ts = 0; - - if( p->ptrs.tcph->is_syn() ) - { - tdb->end_seq++; - if( !p->ptrs.tcph->is_ack() ) - EventInternal(INTERNAL_EVENT_SYN_RECEIVED); - } - // don't bump end_seq for fin here - // we will bump if/when fin is processed + snd->r_win_base = tsd.get_ack(); -#ifdef DEBUG_STREAM_EX - PrintTcpDataBlock(&tdb); -#endif + snd->set_snd_wnd(tsd.get_win() ); } - -static void TcpSessionClear(Flow* flow, TcpSession* tcpssn, int freeApplicationData) +void TcpSession::clear_session(int freeApplicationData) { // update stats - if (tcpssn->tcp_init) + if ( tcp_init ) tcpStats.trackers_released++; - else if (tcpssn->lws_init) + else if ( lws_init ) tcpStats.no_pickups++; else return; - StreamUpdatePerfBaseState(&sfBase, tcpssn->flow, TCP_STATE_CLOSED); + update_perf_base_state(&sfBase, TcpStreamTracker::TCP_CLOSED); RemoveStreamSession(&sfBase); - if (flow->get_session_flags() & SSNFLAG_PRUNED) + if ( flow->get_session_flags() & SSNFLAG_PRUNED ) CloseStreamSession(&sfBase, SESSION_CLOSED_PRUNED); - else if (flow->get_session_flags() & SSNFLAG_TIMEDOUT) + else if ( flow->get_session_flags() & SSNFLAG_TIMEDOUT ) CloseStreamSession(&sfBase, SESSION_CLOSED_TIMEDOUT); else CloseStreamSession(&sfBase, SESSION_CLOSED_NORMALLY); - tcpssn->set_splitter(true, nullptr); - tcpssn->set_splitter(false, nullptr); + set_splitter(true, nullptr); + set_splitter(false, nullptr); DebugFormat(DEBUG_STREAM_STATE, "In TcpSessionClear, %lu bytes in use\n", tcp_memcap->used()); - if( tcpssn->client.reassembler ) + if ( client->reassembler ) { - DebugFormat(DEBUG_STREAM_STATE, "client has %d segs queued, freeing all.\n", tcpssn->client.reassembler->get_seg_count()); - tcpssn->client.reassembler->purge_segment_list( ); + DebugFormat(DEBUG_STREAM_STATE, "client has %d segs queued, freeing all.\n", + client->reassembler->get_seg_count()); + client->reassembler->purge_segment_list(); } - if( tcpssn->server.reassembler ) + if ( server->reassembler ) { - DebugFormat(DEBUG_STREAM_STATE, "server has %d segs queued, freeing all\n", tcpssn->server.reassembler->get_seg_count()); - tcpssn->server.reassembler->purge_segment_list( ); + DebugFormat(DEBUG_STREAM_STATE, "server has %d segs queued, freeing all\n", + server->reassembler->get_seg_count()); + server->reassembler->purge_segment_list(); } - paf_clear(&tcpssn->client.paf_state); - paf_clear(&tcpssn->server.paf_state); + paf_clear(&client->paf_state); + paf_clear(&server->paf_state); // update light-weight state - if (freeApplicationData == 2) + if ( freeApplicationData == 2 ) flow->restart(true); else flow->clear(freeApplicationData); // generate event for rate filtering - 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()); - tcpssn->lws_init = tcpssn->tcp_init = false; -} - - -static void TcpSessionCleanup(Flow* flow, int freeApplicationData, Packet* p = - nullptr) -{ - TcpSession* tcpssn = (TcpSession*) flow->session; - - if( tcpssn->tcp_init ) - { - // FIXIT - this function does both client & server sides...refactor to do one and - // call for each - tcpssn->client.reassembler->flush_queued_segments(flow, true, p); - tcpssn->server.reassembler->flush_queued_segments(flow, true, p); - TcpSessionClear(flow, tcpssn, freeApplicationData); - } -} - - -static uint32_t StreamGetMss( Packet* p, uint16_t* value ) -{ - DebugMessage(DEBUG_STREAM_STATE, "Getting MSS...\n"); - - TcpOptIterator iter(p->ptrs.tcph, p); - for (const TcpOption& opt : iter) - { - if (opt.code == TcpOptCode::MAXSEG) - { - *value = EXTRACT_16BITS(opt.data); - DebugFormat(DEBUG_STREAM_STATE, "Found MSS %u\n", *value); - return TF_MSS; - } - } - - *value = 0; - - DebugMessage(DEBUG_STREAM_STATE, "No MSS...\n"); - - return TF_NONE; -} - -static uint32_t StreamGetWscale(Packet* p, uint16_t* value) -{ - DebugMessage(DEBUG_STREAM_STATE, "Getting wscale...\n"); - - TcpOptIterator iter(p->ptrs.tcph, p); - - // using const because non-const is not supported - for (const TcpOption& opt : iter) - { - if (opt.code == TcpOptCode::WSCALE) - { - *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 (*value > 14) - *value = 14; - - return TF_WSCALE; - } - } - - *value = 0; - DebugMessage(DEBUG_STREAM_STATE, "No wscale...\n"); - - return TF_NONE; + lws_init = tcp_init = false; } -static uint32_t StreamPacketHasWscale( Packet* p ) +void TcpSession::cleanup_session(int freeApplicationData, Packet* p) { - uint16_t wscale; + // FIXIT - this function does both client & server sides...refactor to do one and + // call for each + if ( client->reassembler != nullptr ) + client->reassembler->flush_queued_segments(flow, true, p); + if ( server->reassembler != nullptr ) + server->reassembler->flush_queued_segments(flow, true, p); - DebugMessage(DEBUG_STREAM_STATE, "Checking for wscale...\n"); - - return StreamGetWscale(p, &wscale); + clear_session(freeApplicationData); } #if 0 -static inline int IsWellFormed(Packet *p, TcpTracker *ts) +static inline int IsWellFormed(Packet* p, TcpTracker* ts) { return ( !ts->mss || (p->dsize <= ts->mss) ); } #endif -static void FinishServerInit( TcpDataBlock* tdb, TcpSession* ssn ) +void TcpSession::FinishServerInit(TcpSegmentDescriptor& tsd) { - TcpTracker* server; - TcpTracker* client; - const tcp::TCPHdr* tcph = tdb->pkt->ptrs.tcph; - - // FIXIT - can tcp session be null at this point? - if( !ssn ) - return; + const tcp::TCPHdr* tcph = tsd.get_tcph(); - server = &ssn->server; - client = &ssn->client; + 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() ); - server->l_window = tdb->win; - server->l_unackd = tdb->seq + 1; - server->l_nxt_seq = server->l_unackd; - server->isn = tdb->seq; + client->r_nxt_ack = tsd.get_end_seq(); - client->r_nxt_ack = tdb->end_seq; + if ( tcph->is_fin() ) + server->set_snd_nxt(server->get_snd_nxt() - 1); - if( tcph->is_fin() ) - server->l_nxt_seq--; - - if( !( ssn->flow->session_state & STREAM_STATE_MIDSTREAM ) ) + if ( !( flow->session_state & STREAM_STATE_MIDSTREAM ) ) { - server->s_mgr.state = TCP_STATE_SYN_RCVD; - client->reassembler->set_seglist_base_seq( server->l_unackd ); - client->r_win_base = tdb->end_seq; + 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( tdb->seq ); - client->r_win_base = tdb->seq; + client->reassembler->set_seglist_base_seq(tsd.get_seq() ); + client->r_win_base = tsd.get_seq(); } - server->flags |= server->normalizer->get_tcp_timestamp(tdb, false); - server->ts_last = tdb->ts; + 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->ts_last_pkt = tdb->pkt->pkth->ts.tv_sec; + server->set_ts_last_packet(tsd.get_pkt()->pkth->ts.tv_sec); - server->flags |= StreamGetMss(tdb->pkt, &server->mss); - server->flags |= StreamGetWscale(tdb->pkt, &server->wscale); + server->flags |= tsd.init_mss(&server->mss); + server->flags |= tsd.init_wscale(&server->wscale); #ifdef DEBUG_STREAM_EX PrintTcpSession(ssn); #endif } -static inline void EndOfFileHandle(Packet* p, TcpSession* tcpssn) +void TcpSession::EndOfFileHandle(Packet* p) { - tcpssn->flow->call_handlers(p, true); + flow->call_handlers(p, true); } -static inline bool flow_exceeds_config_thresholds( TcpTracker *rcv, TcpSession *tcpssn, TcpDataBlock *tdb, - StreamTcpConfig* config ) +bool TcpSession::flow_exceeds_config_thresholds(TcpTracker* rcv, TcpSegmentDescriptor& tsd) { if (rcv->flush_policy == STREAM_FLPOLICY_IGNORE) { @@ -835,32 +557,33 @@ static inline bool flow_exceeds_config_thresholds( TcpTracker *rcv, TcpSession * return true; } - if( ( config->flags & STREAM_CONFIG_NO_ASYNC_REASSEMBLY ) && !tcpssn->flow->two_way_traffic() ) + if ( ( config->flags & STREAM_CONFIG_NO_ASYNC_REASSEMBLY ) && !flow->two_way_traffic() ) return true; - if( config->max_consec_small_segs && ( tdb->pkt->dsize < config->max_consec_small_seg_size ) ) + if ( config->max_consec_small_segs && ( tsd.get_pkt()->dsize < + config->max_consec_small_seg_size ) ) { rcv->small_seg_count++; - if( rcv->small_seg_count > config->max_consec_small_segs ) + if ( rcv->small_seg_count > config->max_consec_small_segs ) { /* Above threshold, log it... in this TCP policy, * action controlled by preprocessor rule. */ - EventMaxSmallSegsExceeded(); + tel->EventMaxSmallSegsExceeded(); /* Reset counter, so we're not too noisy */ rcv->small_seg_count = 0; } } - if( config->max_queued_bytes - && ( rcv->reassembler->get_seg_bytes_total() > config->max_queued_bytes ) ) + if ( config->max_queued_bytes + && ( rcv->reassembler->get_seg_bytes_total() > config->max_queued_bytes ) ) { tcpStats.max_bytes++; return true; } - if( config->max_queued_segs - && ( rcv->reassembler->get_seg_count() + 1 > config->max_queued_segs ) ) + if ( config->max_queued_segs + && ( rcv->reassembler->get_seg_count() + 1 > config->max_queued_segs ) ) { tcpStats.max_segs++; return true; @@ -869,40 +592,39 @@ static inline bool flow_exceeds_config_thresholds( TcpTracker *rcv, TcpSession * return false; } -static void ProcessTcpStream(TcpTracker *rcv, TcpSession *tcpssn, TcpDataBlock *tdb, - StreamTcpConfig* config) +void TcpSession::process_tcp_stream(TcpTracker* rcv, TcpSegmentDescriptor& tsd) { - DebugFormat(DEBUG_STREAM_STATE, "In ProcessTcpStream(), %d bytes to queue\n", tdb->pkt->dsize); + DebugFormat(DEBUG_STREAM_STATE, "In ProcessTcpStream(), %d bytes to queue\n", + tsd.get_pkt()->dsize); - if (tdb->pkt->packet_flags & PKT_IGNORE) + if (tsd.get_pkt()->packet_flags & PKT_IGNORE) return; - tcpssn->SetPacketHeaderFoo( tdb->pkt ); + SetPacketHeaderFoo(tsd.get_pkt() ); - if( flow_exceeds_config_thresholds( rcv, tcpssn, tdb, config ) ) + if ( flow_exceeds_config_thresholds(rcv, tsd) ) return; DebugMessage(DEBUG_STREAM_STATE, "queuing segment\n"); - rcv->reassembler->queue_packet_for_reassembly( tdb ); + rcv->reassembler->queue_packet_for_reassembly(tsd); // Alert if overlap limit exceeded - if( ( rcv->config->overlap_limit ) - && ( rcv->reassembler->get_overlap_count() > rcv->config->overlap_limit ) ) + if ( ( config->overlap_limit ) + && ( rcv->reassembler->get_overlap_count() > config->overlap_limit ) ) { - EventExcessiveOverlap(); - rcv->reassembler->set_overlap_count( 0 ); + tel->EventExcessiveOverlap(); + rcv->reassembler->set_overlap_count(0); } } -static int ProcessTcpData(TcpTracker *listener, TcpSession *tcpssn, - TcpDataBlock *tdb, StreamTcpConfig *config) +int TcpSession::process_tcp_data(TcpTracker* listener, TcpSegmentDescriptor& tsd) { Profile profile(s5TcpDataPerfStats); - const tcp::TCPHdr* tcph = tdb->pkt->ptrs.tcph; - uint32_t seq = tdb->seq; + const tcp::TCPHdr* tcph = tsd.get_tcph(); + uint32_t seq = tsd.get_seq(); - if( tcph->is_syn() ) + if ( tcph->is_syn() ) { if (listener->normalizer->get_os_policy() == StreamPolicy::OS_MACOS) seq++; @@ -910,7 +632,7 @@ static int ProcessTcpData(TcpTracker *listener, TcpSession *tcpssn, else { DebugMessage(DEBUG_STREAM_STATE, "Bailing, data on SYN, not MAC Policy!\n"); - listener->normalizer->trim_syn_payload( tdb ); + listener->normalizer->trim_syn_payload(tsd); return STREAM_UNALIGNED; } } @@ -919,25 +641,25 @@ static int ProcessTcpData(TcpTracker *listener, TcpSession *tcpssn, if (seq == listener->r_nxt_ack) { /* check if we're in the window */ - if (listener->config->policy != StreamPolicy::OS_PROXY - and listener->normalizer->get_stream_window( tdb ) == 0) + if (config->policy != StreamPolicy::OS_PROXY + and listener->normalizer->get_stream_window(tsd) == 0) { DebugMessage(DEBUG_STREAM_STATE, "Bailing, we're out of the window!\n"); - listener->normalizer->trim_win_payload( tdb ); + listener->normalizer->trim_win_payload(tsd); return STREAM_UNALIGNED; } /* move the ack boundry up, this is the only way we'll accept data */ // FIXIT-L for ips, must move all the way to first hole or right end - if (listener->s_mgr.state_queue == TCP_STATE_NONE) - listener->r_nxt_ack = tdb->end_seq; + if ( listener->s_mgr.state_queue == TcpStreamTracker::TCP_STATE_NONE ) + listener->r_nxt_ack = tsd.get_end_seq(); - if (tdb->pkt->dsize != 0) + if (tsd.get_pkt()->dsize != 0) { - if (!(tcpssn->flow->get_session_flags() & SSNFLAG_STREAM_ORDER_BAD)) - tdb->pkt->packet_flags |= PKT_STREAM_ORDER_OK; + if (!( flow->get_session_flags() & SSNFLAG_STREAM_ORDER_BAD)) + tsd.get_pkt()->packet_flags |= PKT_STREAM_ORDER_OK; - ProcessTcpStream(listener, tcpssn, tdb, config); + process_tcp_stream(listener, tsd); /* set flags to session flags */ return STREAM_ALIGNED; @@ -950,849 +672,416 @@ static int ProcessTcpData(TcpTracker *listener, TcpSession *tcpssn, // original data. Let the reassembly policy decide how to handle the overlapping data. // See HP, Solaris, et al. for those that favor duplicate data over the original in // some cases. - DebugFormat(DEBUG_STREAM_STATE, "out of order segment (tdb->seq: 0x%X l->r_nxt_ack: 0x%X!\n", - tdb->seq, listener->r_nxt_ack); + 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); - if (listener->s_mgr.state_queue == TCP_STATE_NONE) + if (listener->s_mgr.state_queue == TcpStreamTracker::TCP_STATE_NONE) { /* check if we're in the window */ - if (listener->config->policy != StreamPolicy::OS_PROXY - and listener->normalizer->get_stream_window( tdb ) == 0) + if (config->policy != StreamPolicy::OS_PROXY + and listener->normalizer->get_stream_window(tsd) == 0) { DebugMessage(DEBUG_STREAM_STATE, "Bailing, we're out of the window!\n"); - listener->normalizer->trim_win_payload( tdb ); + listener->normalizer->trim_win_payload(tsd); return STREAM_UNALIGNED; } - if ((listener->s_mgr.state == TCP_STATE_ESTABLISHED) - && (listener->flush_policy == STREAM_FLPOLICY_IGNORE)) + if ((listener->get_tcp_state() == TcpStreamTracker::TCP_ESTABLISHED) + && (listener->flush_policy == STREAM_FLPOLICY_IGNORE)) { - if (SEQ_GT(tdb->end_seq, listener->r_nxt_ack)) + if (SEQ_GT(tsd.get_end_seq(), listener->r_nxt_ack)) { // set next ack so we are within the window going forward on this side. // FIXIT-L for ips, must move all the way to first hole or right end - listener->r_nxt_ack = tdb->end_seq; + listener->r_nxt_ack = tsd.get_end_seq(); } } } - if (tdb->pkt->dsize != 0) + if (tsd.get_pkt()->dsize != 0) { - if (!(tcpssn->flow->get_session_flags() & SSNFLAG_STREAM_ORDER_BAD)) + if (!( flow->get_session_flags() & SSNFLAG_STREAM_ORDER_BAD)) { - if (!SEQ_LEQ((tdb->seq + tdb->pkt->dsize), listener->r_nxt_ack)) - tcpssn->flow->set_session_flags( SSNFLAG_STREAM_ORDER_BAD ); + if (!SEQ_LEQ((tsd.get_seq() + tsd.get_pkt()->dsize), listener->r_nxt_ack)) + flow->set_session_flags(SSNFLAG_STREAM_ORDER_BAD); } - ProcessTcpStream(listener, tcpssn, tdb, config); + process_tcp_stream(listener, tsd); } } return STREAM_UNALIGNED; } -static void set_os_policy(Flow* flow, TcpSession* tcpssn) +void TcpSession::set_os_policy(void) { StreamPolicy client_os_policy = flow->ssn_policy ? - static_cast( flow->ssn_policy ) : tcpssn->client.config->policy; - StreamPolicy server_os_policy = flow->ssn_policy ? - static_cast( flow->ssn_policy ) : tcpssn->server.config->policy; - - if( tcpssn->client.normalizer == nullptr ) - tcpssn->client.normalizer = TcpNormalizerFactory::create( client_os_policy, tcpssn, - &tcpssn->client, &tcpssn->server ); - - if( tcpssn->server.normalizer == nullptr ) - tcpssn->server.normalizer = TcpNormalizerFactory::create( server_os_policy, tcpssn, - &tcpssn->server, &tcpssn->client ); - - if( tcpssn->client.reassembler == nullptr ) - tcpssn->client.reassembler = TcpReassemblerFactory::create( tcpssn, &tcpssn->client, client_os_policy, false ); - - if( tcpssn->server.reassembler == nullptr ) - tcpssn->server.reassembler = TcpReassemblerFactory::create( tcpssn, &tcpssn->server, server_os_policy, true ); -} - -/* Use a for loop and byte comparison, which has proven to be - * faster on pipelined architectures compared to a memcmp (setup - * for memcmp is slow). Not using a 4 byte and 2 byte long because - * there is no guarantee of memory alignment (and thus performance - * issues similar to memcmp). */ -static inline int ValidMacAddress(TcpTracker *talker, TcpTracker *listener, Packet *p) -{ - int i, j, ret = 0; - - if (!(p->proto_bits & PROTO_BIT__ETH)) - return 0; - - // if flag is set, gauranteed to have an eth layer - const eth::EtherHdr* eh = layer::get_eth_layer(p); - - for (i = 0; i < 6; ++i) - { - if ((talker->mac_addr[i] != eh->ether_src[i])) - break; - } - for (j = 0; j < 6; ++j) - { - if (listener->mac_addr[j] != eh->ether_dst[j]) - break; - } - - // FIXIT-L make this swap check configurable - if (i < 6 && j < 6) - { - if (!memcmp(talker->mac_addr, eh->ether_dst, 6) - && !memcmp(listener->mac_addr, eh->ether_src, 6)) - // this is prolly a tap - return 0; - } - - if (i < 6) - { - if (p->packet_flags & PKT_FROM_CLIENT) - ret |= EVENT_SESSION_HIJACK_CLIENT; - else - ret |= EVENT_SESSION_HIJACK_SERVER; - } - if (j < 6) - { - if (p->packet_flags & PKT_FROM_CLIENT) - ret |= EVENT_SESSION_HIJACK_SERVER; - else - ret |= EVENT_SESSION_HIJACK_CLIENT; - } - return ret; -} - -static inline void CopyMacAddr(Packet* p, TcpSession* tcpssn, int dir) -{ - int i; - - /* Not ethernet based, nothing to do */ - if (!(p->proto_bits & PROTO_BIT__ETH)) - return; - - // if flag is set, gauranteed to have an eth layer - const eth::EtherHdr* eh = layer::get_eth_layer(p); - - if (dir == FROM_CLIENT) - { - /* Client is SRC */ - for (i = 0; i < 6; i++) - { - tcpssn->client.mac_addr[i] = eh->ether_src[i]; - tcpssn->server.mac_addr[i] = eh->ether_dst[i]; - } - } - else - { - /* Server is SRC */ - for (i = 0; i < 6; i++) - { - tcpssn->server.mac_addr[i] = eh->ether_src[i]; - tcpssn->client.mac_addr[i] = eh->ether_dst[i]; - } - } -} - -static void NewTcpSession(Packet* p, Flow* flow, StreamTcpConfig* dstPolicy, TcpSession* tss) -{ - Inspector* ins = flow->gadget; - - if (!ins) - ins = flow->clouseau; - - if (ins) - { - stream.set_splitter(flow, true, ins->get_splitter(true)); - stream.set_splitter(flow, false, ins->get_splitter(false)); - } - else - { - stream.set_splitter(flow, true, new AtomSplitter(true)); - stream.set_splitter(flow, false, new AtomSplitter(false)); - } - - { - DebugMessage(DEBUG_STREAM_STATE, "adding TcpSession to lightweight session\n"); - flow->protocol = p->type(); - tss->flow = flow; - - /* New session, previous was marked as reset. Clear the reset flag. */ - uint32_t session_flags = flow->clear_session_flags( SSNFLAG_RESET ); - if ((session_flags & SSNFLAG_CLIENT_SWAP) && !(session_flags & SSNFLAG_CLIENT_SWAPPED)) - { - TcpTracker trk = tss->client; - sfip_t ip = flow->client_ip; - uint16_t port = flow->client_port; - - tss->client = tss->server; - tss->server = trk; - - flow->client_ip = flow->server_ip; - flow->server_ip = ip; - - flow->client_port = flow->server_port; - flow->server_port = port; - - if (!flow->two_way_traffic()) - { - if (session_flags & SSNFLAG_SEEN_CLIENT) - { - session_flags ^= SSNFLAG_SEEN_CLIENT; - session_flags |= SSNFLAG_SEEN_SERVER; - } - else if (session_flags & SSNFLAG_SEEN_SERVER) - { - session_flags ^= SSNFLAG_SEEN_SERVER; - session_flags |= SSNFLAG_SEEN_CLIENT; - } - } - - session_flags |= SSNFLAG_CLIENT_SWAPPED; - flow->update_session_flags( session_flags ); - } - init_flush_policy(flow, &tss->server); - init_flush_policy(flow, &tss->client); - -#ifdef DEBUG_STREAM_EX - PrintTcpSession(tss); -#endif - flow->set_expire(p, dstPolicy->session_timeout); - - AddStreamSession(&sfBase, - flow->session_state & STREAM_STATE_MIDSTREAM ? SSNFLAG_MIDSTREAM : 0); - - StreamUpdatePerfBaseState(&sfBase, tss->flow, TCP_STATE_SYN_SENT); - - EventInternal(INTERNAL_EVENT_SESSION_ADD); - - tss->ecn = 0; - assert(!tss->tcp_init); - tss->tcp_init = true; - - tcpStats.trackers_created++; - } -} - -static void NewTcpSessionOnSyn(Flow* flow, TcpDataBlock* tdb, StreamTcpConfig* dstPolicy) -{ - Profile profile(s5TcpNewSessPerfStats); - - const tcp::TCPHdr* tcph = tdb->pkt->ptrs.tcph; - TcpSession* tss; - - /****************************************************************** - * start new sessions on proper SYN packets - *****************************************************************/ - tss = (TcpSession*) flow->session; - DebugMessage(DEBUG_STREAM_STATE, "Creating new session tracker on SYN!\n"); - - flow->set_session_flags( SSNFLAG_SEEN_CLIENT ); - - if (tcph->are_flags_set(TH_CWR | TH_ECE)) - flow->set_session_flags( SSNFLAG_ECN_CLIENT_QUERY ); - - /* setup the stream trackers */ - /* Set the StreamTcpConfig for each direction (pkt from client) */ - tss->client.config = dstPolicy; // FIXIT-M use external binding for both dirs - tss->server.config = dstPolicy; // (applies to all the blocks in this funk) - set_os_policy(flow, tss); - - tss->client.s_mgr.state = TCP_STATE_SYN_SENT; - tss->client.isn = tdb->seq; - tss->client.l_unackd = tdb->seq + 1; - tss->client.l_nxt_seq = tss->client.l_unackd; - - if (tdb->seq != tdb->end_seq) - tss->client.l_nxt_seq += (tdb->end_seq - tdb->seq - 1); - - tss->client.l_window = tdb->win; - tss->client.ts_last_pkt = tdb->pkt->pkth->ts.tv_sec; - - tss->server.reassembler->set_seglist_base_seq( tss->client.l_unackd ); - tss->server.r_nxt_ack = tss->client.l_unackd; - tss->server.r_win_base = tdb->seq + 1; - tss->server.s_mgr.state = TCP_STATE_LISTEN; - - tss->client.flags |= tss->client.normalizer->get_tcp_timestamp(tdb, false); - tss->client.ts_last = tdb->ts; - if (tss->client.ts_last == 0) - tss->client.flags |= TF_TSTAMP_ZERO; - tss->client.flags |= StreamGetMss(tdb->pkt, &tss->client.mss); - tss->client.flags |= StreamGetWscale(tdb->pkt, &tss->client.wscale); - - CopyMacAddr(tdb->pkt, tss, FROM_CLIENT); - - tcpStats.sessions_on_syn++; - NewTcpSession(tdb->pkt, flow, dstPolicy, tss); -} - -static void NewTcpSessionOnSynAck(Flow* flow, TcpDataBlock* tdb, StreamTcpConfig* dstPolicy) -{ - Profile profile(s5TcpNewSessPerfStats); - - const tcp::TCPHdr* tcph = tdb->pkt->ptrs.tcph; - TcpSession* tss; - - tss = (TcpSession*) flow->session; - DebugMessage(DEBUG_STREAM_STATE, "Creating new session tracker on SYN_ACK!\n"); - - flow->set_session_flags( SSNFLAG_SEEN_SERVER ); - if (tcph->are_flags_set(TH_CWR | TH_ECE)) - flow->set_session_flags( SSNFLAG_ECN_SERVER_REPLY ); - - /* setup the stream trackers */ - /* Set the config for each direction (pkt from server) */ - tss->server.config = dstPolicy; - tss->client.config = dstPolicy; - set_os_policy(flow, tss); - - tss->server.s_mgr.state = TCP_STATE_SYN_RCVD; - tss->server.isn = tdb->seq; - tss->server.l_unackd = tdb->seq + 1; - tss->server.l_nxt_seq = tss->server.l_unackd; - tss->server.l_window = tdb->win; - - tss->server.reassembler->set_seglist_base_seq( tdb->ack ); - tss->server.r_win_base = tdb->ack; - tss->server.r_nxt_ack = tdb->ack; - tss->server.ts_last_pkt = tdb->pkt->pkth->ts.tv_sec; - - tss->client.reassembler->set_seglist_base_seq( tss->server.l_unackd ); - tss->client.r_nxt_ack = tss->server.l_unackd; - tss->client.r_win_base = tdb->seq + 1; - tss->client.l_nxt_seq = tdb->ack; - tss->client.isn = tdb->ack - 1; - tss->client.s_mgr.state = TCP_STATE_SYN_SENT; - - tss->server.flags |= tss->server.normalizer->get_tcp_timestamp(tdb, false); - tss->server.ts_last = tdb->ts; - if (tss->server.ts_last == 0) - tss->server.flags |= TF_TSTAMP_ZERO; - tss->server.flags |= StreamGetMss(tdb->pkt, &tss->server.mss); - tss->server.flags |= StreamGetWscale(tdb->pkt, &tss->server.wscale); - - CopyMacAddr(tdb->pkt, tss, FROM_SERVER); - - tcpStats.sessions_on_syn_ack++; - NewTcpSession(tdb->pkt, flow, dstPolicy, tss); -} - -static void NewTcpSessionOn3Way(Flow* flow, TcpDataBlock* tdb, - StreamTcpConfig* dstPolicy) -{ - Profile profile(s5TcpNewSessPerfStats); - - const tcp::TCPHdr* tcph = tdb->pkt->ptrs.tcph; - TcpSession* tss; - - /****************************************************************** - * start new sessions on completion of 3-way (ACK only, no data) - *****************************************************************/ - tss = ( TcpSession* ) flow->session; - DebugMessage(DEBUG_STREAM_STATE, "Creating new session tracker on ACK!\n"); - - flow->set_session_flags( SSNFLAG_SEEN_CLIENT ); - - if (tcph->are_flags_set(TH_CWR | TH_ECE)) - flow->set_session_flags( SSNFLAG_ECN_CLIENT_QUERY ); - - /* setup the stream trackers */ - /* Set the config for each direction (pkt from client) */ - tss->client.config = dstPolicy; - tss->server.config = dstPolicy; - set_os_policy( flow, tss ); - - tss->client.s_mgr.state = TCP_STATE_ESTABLISHED; - tss->client.isn = tdb->seq; - tss->client.l_unackd = tdb->seq + 1; - tss->client.l_nxt_seq = tss->client.l_unackd; - tss->client.l_window = tdb->win; - - tss->client.ts_last_pkt = tdb->pkt->pkth->ts.tv_sec; - - tss->server.reassembler->set_seglist_base_seq( tss->client.l_unackd ); - tss->server.r_nxt_ack = tss->client.l_unackd; - tss->server.r_win_base = tdb->seq + 1; - tss->server.s_mgr.state = TCP_STATE_ESTABLISHED; - - tss->client.flags |= tss->client.normalizer->get_tcp_timestamp(tdb, false); - tss->client.ts_last = tdb->ts; - if (tss->client.ts_last == 0) - tss->client.flags |= TF_TSTAMP_ZERO; - tss->client.flags |= StreamGetMss(tdb->pkt, &tss->client.mss); - tss->client.flags |= StreamGetWscale(tdb->pkt, &tss->client.wscale); - - CopyMacAddr(tdb->pkt, tss, FROM_CLIENT); - - tcpStats.sessions_on_3way++; - NewTcpSession(tdb->pkt, flow, dstPolicy, tss); -} - -static void NewTcpSessionOnData(Flow* flow, TcpDataBlock* tdb, StreamTcpConfig* dstPolicy) -{ - Profile profile(s5TcpNewSessPerfStats); - - const tcp::TCPHdr* tcph = tdb->pkt->ptrs.tcph; - TcpSession* tss; - - tss = (TcpSession*) flow->session; - DebugMessage(DEBUG_STREAM_STATE, "Creating new session tracker on data packet (ACK|PSH)!\n"); - - /* Set the config for each direction (pkt from client) */ - tss->client.config = dstPolicy; - tss->server.config = dstPolicy; - set_os_policy(flow, tss); - if (flow->ssn_state.direction == FROM_CLIENT) - { - DebugMessage(DEBUG_STREAM_STATE, "Session direction is FROM_CLIENT\n"); - - /* Sender is client (src port is higher) */ - flow->set_session_flags( SSNFLAG_SEEN_CLIENT ); - if (tcph->are_flags_set(TH_CWR | TH_ECE)) - flow->set_session_flags( SSNFLAG_ECN_CLIENT_QUERY ); - - /* setup the stream trackers */ - tss->client.s_mgr.state = TCP_STATE_ESTABLISHED; - tss->client.isn = tdb->seq; - tss->client.l_unackd = tdb->seq; - tss->client.l_nxt_seq = tss->client.l_unackd; - tss->client.l_window = tdb->win; - - tss->client.ts_last_pkt = tdb->pkt->pkth->ts.tv_sec; - - tss->server.reassembler->set_seglist_base_seq( tss->client.l_unackd ); - tss->server.r_nxt_ack = tss->client.l_unackd; - tss->server.r_win_base = tdb->seq; - tss->server.l_window = 0; /* reset later */ - - /* Next server packet is what was ACKd */ - //tss->server.l_nxt_seq = tdb->ack + 1; - tss->server.l_unackd = tdb->ack - 1; - tss->server.s_mgr.state = TCP_STATE_ESTABLISHED; - - tss->client.flags |= tss->client.normalizer->get_tcp_timestamp(tdb, false); - tss->client.ts_last = tdb->ts; - if (tss->client.ts_last == 0) - tss->client.flags |= TF_TSTAMP_ZERO; - - tss->client.flags |= StreamGetMss(tdb->pkt, &tss->client.mss); - tss->client.flags |= StreamGetWscale(tdb->pkt, &tss->client.wscale); - - CopyMacAddr(tdb->pkt, tss, FROM_CLIENT); - } - else - { - DebugMessage(DEBUG_STREAM_STATE, "Session direction is FROM_SERVER\n"); - - /* Sender is server (src port is lower) */ - flow->set_session_flags( SSNFLAG_SEEN_SERVER ); - - /* setup the stream trackers */ - tss->server.s_mgr.state = TCP_STATE_ESTABLISHED; - tss->server.isn = tdb->seq; - tss->server.l_unackd = tdb->seq; - tss->server.l_nxt_seq = tss->server.l_unackd; - tss->server.l_window = tdb->win; - - tss->server.reassembler->set_seglist_base_seq( tdb->ack ); - tss->server.r_win_base = tdb->ack; - tss->server.r_nxt_ack = tdb->ack; - tss->server.ts_last_pkt = tdb->pkt->pkth->ts.tv_sec; - - tss->client.reassembler->set_seglist_base_seq( tss->server.l_unackd ); - tss->client.r_nxt_ack = tss->server.l_unackd; - tss->client.r_win_base = tdb->seq; - tss->client.l_window = 0; /* reset later */ - tss->client.isn = tdb->ack - 1; - tss->client.s_mgr.state = TCP_STATE_ESTABLISHED; - - tss->server.flags |= tss->server.normalizer->get_tcp_timestamp(tdb, 0); - tss->server.ts_last = tdb->ts; - if (tss->server.ts_last == 0) - tss->server.flags |= TF_TSTAMP_ZERO; - - tss->server.flags |= StreamGetMss(tdb->pkt, &tss->server.mss); - tss->server.flags |= StreamGetWscale(tdb->pkt, &tss->server.wscale); - - CopyMacAddr(tdb->pkt, tss, FROM_SERVER); - } - - tcpStats.sessions_on_data++; - NewTcpSession(tdb->pkt, flow, dstPolicy, tss); -} - -static int ProcessTcp(Flow* flow, TcpDataBlock* tdb, StreamTcpConfig* config) -{ - Profile profile(s5TcpStatePerfStats); - - int retcode = ACTION_NOTHING; - int eventcode = 0; - int got_ts = 0; - int new_ssn = 0; - int ts_action = ACTION_NOTHING; - const tcp::TCPHdr* tcph = tdb->pkt->ptrs.tcph; - TcpSession* tcpssn = NULL; - TcpTracker* talker = NULL; - TcpTracker* listener = NULL; - DEBUG_WRAP( const char* t = NULL; const char* l = NULL; ); - - if (flow->protocol != PktType::TCP) - { - DebugMessage(DEBUG_STREAM_STATE, "Lightweight session not TCP on TCP packet\n"); - return retcode; - } - - tcpssn = ( TcpSession* ) flow->session; - - if (!tcpssn->tcp_init) - { - // FIXIT-L expected flow should be checked by flow_con before we - // get here - char ignore = flow_con->expected_flow(flow, tdb->pkt); - - if (ignore) - { - tcpssn->server.flush_policy = STREAM_FLPOLICY_IGNORE; - tcpssn->client.flush_policy = STREAM_FLPOLICY_IGNORE; - return retcode; - } - - bool require3Way = config->require_3whs(); - bool allow_midstream = config->midstream_allowed(tdb->pkt); - - if (tcph->is_syn_only()) - { - DebugMessage(DEBUG_STREAM_STATE, "Stream SYN PACKET, establishing lightweight session direction.\n"); - /* SYN packet from client */ - flow->ssn_state.direction = FROM_CLIENT; - flow->session_state |= STREAM_STATE_SYN; - - if (require3Way || (StreamPacketHasWscale(tdb->pkt) & TF_WSCALE) || (tdb->pkt->dsize > 0)) - { - /* Create TCP session if we - * 1) require 3-WAY HS, OR - * 2) client sent wscale option, OR - * 3) have data - */ - NewTcpSessionOnSyn( flow, tdb, config); - new_ssn = 1; - tcpssn->server.normalizer->ecn_tracker( (tcp::TCPHdr *) tcph, require3Way ); - } - - /* Nothing left todo here */ - } - else if (tcph->is_syn_ack()) - { - /* 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, establishing lightweight session direction.\n"); - flow->ssn_state.direction = FROM_SERVER; - } - - flow->session_state |= STREAM_STATE_SYN_ACK; - - if (!require3Way || allow_midstream) - { - NewTcpSessionOnSynAck(flow, tdb, config); - new_ssn = 1; - } - - tcpssn->client.normalizer->ecn_tracker( (tcp::TCPHdr *) tcph, require3Way ); - } - else if (tcph->is_ack() && !tcph->is_rst() && (flow->session_state & STREAM_STATE_SYN_ACK)) - { - /* 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; - NewTcpSessionOn3Way(flow, tdb, config); - new_ssn = 1; - tcpssn->server.normalizer->ecn_tracker( (tcp::TCPHdr *) tcph, require3Way ); - StreamUpdatePerfBaseState(&sfBase, flow, TCP_STATE_ESTABLISHED); - } - else if (tdb->pkt->dsize && (!require3Way || allow_midstream)) - { - /* create session on data, need to figure out direction, etc - Assume from client, can update later */ - if (tdb->pkt->ptrs.sp > tdb->pkt->ptrs.dp) - flow->ssn_state.direction = FROM_CLIENT; - else - flow->ssn_state.direction = FROM_SERVER; + static_cast( flow->ssn_policy ) : config->policy; + StreamPolicy server_os_policy = flow->ssn_policy ? + static_cast( flow->ssn_policy ) : config->policy; - flow->session_state |= STREAM_STATE_MIDSTREAM; - flow->set_session_flags( SSNFLAG_MIDSTREAM ); + if ( client->normalizer == nullptr ) + client->normalizer = TcpNormalizerFactory::create(this, client_os_policy, client, server); - NewTcpSessionOnData(flow, tdb, config); - new_ssn = 1; - if(flow->ssn_state.direction == FROM_CLIENT) - tcpssn->server.normalizer->ecn_tracker( (tcp::TCPHdr *) tcph, require3Way ); - else - tcpssn->client.normalizer->ecn_tracker( (tcp::TCPHdr *) tcph, require3Way ); + if ( server->normalizer == nullptr ) + server->normalizer = TcpNormalizerFactory::create(this, server_os_policy, server, client); - if (flow->session_state & STREAM_STATE_ESTABLISHED) - StreamUpdatePerfBaseState(&sfBase, flow, TCP_STATE_ESTABLISHED); - } - else if (!tdb->pkt->dsize) - { - // Do nothing. - return retcode; - } - } - else + if ( client->reassembler == nullptr ) + client->reassembler = TcpReassemblerFactory::create(this, client, client_os_policy, false); + + if ( server->reassembler == nullptr ) + server->reassembler = TcpReassemblerFactory::create(this, server, server_os_policy, true); +} + +// FIXIT - check for need to swap client/server is ifdef'ed out... +void TcpSession::swap_trackers(void) +{ + uint32_t session_flags = flow->get_session_flags( ); + if ( ( session_flags & SSNFLAG_CLIENT_SWAP ) && !( session_flags & SSNFLAG_CLIENT_SWAPPED ) ) { - /* If session is already marked as established */ - if (!(flow->session_state & STREAM_STATE_ESTABLISHED) - && (!config->require_3whs() || config->midstream_allowed(tdb->pkt))) - { - /* If not requiring 3-way Handshake... */ + TcpTracker* trk = client; + client = server; + server = trk; - /* TCP session created on TH_SYN above, - * or maybe on SYN-ACK, or anything else */ + sfip_t ip = flow->client_ip; + flow->client_ip = flow->server_ip; + flow->server_ip = ip; - /* Need to update Lightweight session state */ - if (tcph->is_syn_ack()) + uint16_t port = flow->client_port; + flow->client_port = flow->server_port; + flow->server_port = port; + + if ( !flow->two_way_traffic() ) + { + if ( session_flags & SSNFLAG_SEEN_CLIENT ) { - /* SYN-ACK from server */ - if (flow->session_state != STREAM_STATE_NONE) - { - flow->session_state |= STREAM_STATE_SYN_ACK; - } + session_flags ^= SSNFLAG_SEEN_CLIENT; + session_flags |= SSNFLAG_SEEN_SERVER; } - else if (tcph->is_ack() && (flow->session_state & STREAM_STATE_SYN_ACK)) + else if ( session_flags & SSNFLAG_SEEN_SERVER ) { - flow->session_state |= STREAM_STATE_ACK | STREAM_STATE_ESTABLISHED; - StreamUpdatePerfBaseState(&sfBase, flow, TCP_STATE_ESTABLISHED); + session_flags ^= SSNFLAG_SEEN_SERVER; + session_flags |= SSNFLAG_SEEN_CLIENT; } } - if (tcph->is_syn()) - tcpssn->server.normalizer->ecn_tracker( (tcp::TCPHdr *) tcph, config->require_3whs() ); + + session_flags |= SSNFLAG_CLIENT_SWAPPED; + flow->update_session_flags(session_flags); } +} - if (tdb->pkt->packet_flags & PKT_FROM_SERVER) - { - DebugMessage(DEBUG_STREAM_STATE, "Stream: Updating on packet from server\n"); - flow->set_session_flags( SSNFLAG_SEEN_SERVER ); +void TcpSession::init_new_tcp_session(TcpSegmentDescriptor& tsd) +{ + flow->protocol = tsd.get_pkt()->type(); - if (tcpssn->tcp_init) - { - talker = &tcpssn->server; - listener = &tcpssn->client; - } + /* New session, previous was marked as reset. Clear the reset flag. */ + flow->clear_session_flags(SSNFLAG_RESET); + flow->set_expire(tsd.get_pkt(), config->session_timeout); + AddStreamSession(&sfBase, flow->session_state & STREAM_STATE_MIDSTREAM ? SSNFLAG_MIDSTREAM : 0); + update_perf_base_state(&sfBase, TcpStreamTracker::TCP_SYN_SENT); + tel->EventInternal(INTERNAL_EVENT_SESSION_ADD); - DEBUG_WRAP( - t = "Server"; - l = "Client"); + //assert( !tcp_init ); + tcp_init = true; + new_ssn = true; - if( talker && ( talker->s_mgr.state == TCP_STATE_LISTEN ) && tcph->is_syn_only() ) - eventcode |= EVENT_4WHS; + // FIXIT - this state is bogus... move to tracker init... + tcpStats.trackers_created++; +} - /* If we picked this guy up midstream, finish the initialization */ - if ((flow->session_state & STREAM_STATE_MIDSTREAM) && !(flow->session_state & STREAM_STATE_ESTABLISHED)) - { - FinishServerInit(tdb, tcpssn); - if( tcph->are_flags_set( TH_ECE ) && ( flow->get_session_flags() & SSNFLAG_ECN_CLIENT_QUERY ) ) - flow->set_session_flags( SSNFLAG_ECN_SERVER_REPLY ); +void TcpSession::NewTcpSessionOnSyn(TcpSegmentDescriptor& tsd) +{ + server->init_on_syn_recv(tsd); + client->init_on_syn_sent(tsd); + init_new_tcp_session(tsd); + tcpStats.sessions_on_syn++; +} + +void TcpSession::NewTcpSessionOnSynAck(TcpSegmentDescriptor& tsd) +{ + server->init_on_synack_sent(tsd); + client->init_on_synack_recv(tsd); + init_new_tcp_session(tsd); + tcpStats.sessions_on_syn_ack++; +} - if( flow->get_session_flags() & SSNFLAG_SEEN_CLIENT ) +void TcpSession::update_session_state(const tcp::TCPHdr* tcph, TcpSegmentDescriptor& tsd) +{ + /* If session is already marked as established */ + if (!(flow->session_state & STREAM_STATE_ESTABLISHED) + && (!require_3whs || config->midstream_allowed(tsd.get_pkt()))) + { + /* 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) { - // should TCP state go to established too? - flow->session_state |= STREAM_STATE_ESTABLISHED; - flow->set_session_flags( SSNFLAG_ESTABLISHED ); - StreamUpdatePerfBaseState( &sfBase, flow, TCP_STATE_ESTABLISHED ); + flow->session_state |= STREAM_STATE_SYN_ACK; } } - if (!flow->inner_server_ttl) - flow->set_ttl(tdb->pkt, false); + else if (tcph->is_ack() && (flow->session_state & STREAM_STATE_SYN_ACK)) + { + flow->session_state |= STREAM_STATE_ACK | STREAM_STATE_ESTABLISHED; + update_perf_base_state(&sfBase, TcpStreamTracker::TCP_ESTABLISHED); + } } - else +} + +void TcpSession::update_session_on_server_packet(const tcp::TCPHdr* tcph, + TcpSegmentDescriptor& tsd) +{ + DebugMessage(DEBUG_STREAM_STATE, "Stream: Updating on packet from server\n"); + + flow->set_session_flags(SSNFLAG_SEEN_SERVER); + if (tcp_init) + { + talker = server; + listener = client; + } + + if (talker && (talker->get_tcp_state() == TcpStreamTracker::TCP_LISTEN) && 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)) { - DebugMessage(DEBUG_STREAM_STATE, "Stream: Updating on packet from client\n"); - /* if we got here we had to see the SYN already... */ - flow->set_session_flags( SSNFLAG_SEEN_CLIENT ); - if (tcpssn->tcp_init) + FinishServerInit(tsd); + if (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) { - talker = &tcpssn->client; - listener = &tcpssn->server; + // should TCP state go to established too? + flow->session_state |= STREAM_STATE_ESTABLISHED; + flow->set_session_flags(SSNFLAG_ESTABLISHED); + update_perf_base_state(&sfBase, TcpStreamTracker::TCP_ESTABLISHED); } + } + + if (!flow->inner_server_ttl) + flow->set_ttl(tsd.get_pkt(), false); +} + +void TcpSession::update_session_on_client_packet(TcpSegmentDescriptor& tsd) +{ + DebugMessage(DEBUG_STREAM_STATE, "Stream: Updating on packet from client\n"); - DEBUG_WRAP( - t = "Server"; - l = "Client"); + /* 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; + } - if ((flow->session_state & STREAM_STATE_MIDSTREAM) && !(flow->session_state & STREAM_STATE_ESTABLISHED)) + if ((flow->session_state & STREAM_STATE_MIDSTREAM) + && !(flow->session_state & STREAM_STATE_ESTABLISHED)) + { + /* Midstream and seen server. */ + if (flow->get_session_flags() & SSNFLAG_SEEN_SERVER) { - /* Midstream and seen server. */ - if (flow->get_session_flags() & SSNFLAG_SEEN_SERVER) - { - flow->session_state |= STREAM_STATE_ESTABLISHED; - flow->set_session_flags( SSNFLAG_ESTABLISHED ); - } + flow->session_state |= STREAM_STATE_ESTABLISHED; + flow->set_session_flags(SSNFLAG_ESTABLISHED); } - if (!flow->inner_client_ttl) - flow->set_ttl(tdb->pkt, true); } - /* - * check for SYN on reset session - */ - if( ( flow->get_session_flags() & SSNFLAG_RESET ) && tcph->is_syn() ) + if (!flow->inner_client_ttl) + flow->set_ttl(tsd.get_pkt(), true); +} + +bool TcpSession::handle_syn_on_reset_session(const tcp::TCPHdr* tcph, TcpSegmentDescriptor& tsd) +{ + if ( !tcp_init || ( listener->get_tcp_state() == TcpStreamTracker::TCP_CLOSED ) + || ( talker->get_tcp_state() == TcpStreamTracker::TCP_CLOSED ) ) { - if ( !tcpssn->tcp_init || ( listener->s_mgr.state == TCP_STATE_CLOSED ) - || ( talker->s_mgr.state == TCP_STATE_CLOSED ) ) - { - /* Listener previously issued a reset - Talker is re-SYN-ing */ - // FIXIT-L this leads to bogus 129:20 - TcpSessionCleanup(flow, 1); + /* Listener previously issued a reset Talker is re-SYN-ing */ + // FIXIT-L this leads to bogus 129:20 + cleanup_session(1); - if( tcph->is_rst() ) - { - /* FIXIT-M In inline mode, only one of the normalizations - * can occur. If the first normalization - * fires, there is nothing for the second normalization - * to do. However, in inline-test mode, since - * nothing is actually normalized, both of the - * following functions report that they 'would' - * normalize. i.e., both functions increment their - * count even though only one function can ever - * perform a normalization. - */ + if ( tcph->is_rst() ) + { + /* FIXIT-M In inline mode, only one of the normalizations + * can occur. If the first normalization + * fires, there is nothing for the second normalization + * to do. However, in inline-test mode, since + * nothing is actually normalized, both of the + * following functions report that they 'would' + * normalize. i.e., both functions increment their + * count even though only one function can ever + * perform a normalization. + */ - /* Got SYN/RST. We're done. */ - listener->normalizer->trim_syn_payload( tdb ); - listener->normalizer->trim_rst_payload( tdb ); - return retcode | ACTION_RST; - } - else if (tcph->is_syn_only()) + /* Got SYN/RST. We're done. */ + listener->normalizer->trim_syn_payload(tsd); + listener->normalizer->trim_rst_payload(tsd); + pkt_action_mask |= ACTION_RST; + return false; + } + else if (tcph->is_syn_only()) + { + flow->ssn_state.direction = FROM_CLIENT; + flow->session_state = STREAM_STATE_SYN; + flow->set_ttl(tsd.get_pkt(), true); + NewTcpSessionOnSyn(tsd); + tcpStats.resyns++; + listener = server; + talker = client; + listener->normalizer->ecn_tracker( (tcp::TCPHdr*)tcph, require_3whs); + flow->update_session_flags(SSNFLAG_SEEN_CLIENT); + } + else if (tcph->is_syn_ack()) + { + if (config->midstream_allowed(tsd.get_pkt())) { - flow->ssn_state.direction = FROM_CLIENT; - flow->session_state = STREAM_STATE_SYN; - flow->set_ttl(tdb->pkt, true); - NewTcpSessionOnSyn( flow, tdb, config); + flow->ssn_state.direction = FROM_SERVER; + flow->session_state = STREAM_STATE_SYN_ACK; + flow->set_ttl(tsd.get_pkt(), false); + NewTcpSessionOnSynAck(tsd); tcpStats.resyns++; - new_ssn = 1; - - bool require3Way = config->require_3whs(); - listener = &tcpssn->server; - talker = &tcpssn->client; - listener->normalizer->ecn_tracker( (tcp::TCPHdr *) tcph, require3Way ); - flow->update_session_flags( SSNFLAG_SEEN_CLIENT ); } - else if (tcph->is_syn_ack()) - { - if (config->midstream_allowed(tdb->pkt)) - { - flow->ssn_state.direction = FROM_SERVER; - flow->session_state = STREAM_STATE_SYN_ACK; - flow->set_ttl(tdb->pkt, false); - NewTcpSessionOnSynAck( flow, tdb, config); - tcpStats.resyns++; - tcpssn = (TcpSession*) flow->session; - new_ssn = 1; - } - bool require3Way = config->require_3whs(); - listener = &tcpssn->client; - talker = &tcpssn->server; - listener->normalizer->ecn_tracker( (tcp::TCPHdr *) tcph, require3Way ); - flow->update_session_flags( SSNFLAG_SEEN_SERVER ); - } + listener = client; + talker = server; + listener->normalizer->ecn_tracker( (tcp::TCPHdr*)tcph, require_3whs); + flow->update_session_flags(SSNFLAG_SEEN_SERVER); } - - DebugMessage(DEBUG_STREAM_STATE, "Got SYN pkt on reset ssn, re-SYN-ing\n"); } + DebugMessage(DEBUG_STREAM_STATE, "Got SYN pkt on reset ssn, re-SYN-ing\n"); + + return true; +} + +void TcpSession::update_ignored_session(TcpSegmentDescriptor& tsd) +{ // FIXIT-L why flush here instead of just purge? // s5_ignored_session() may be disabling detection too soon if we really want to flush - if (stream.ignored_session(flow, tdb->pkt)) + if (stream.ignored_session(flow, tsd.get_pkt())) { if (talker && (talker->flags & TF_FORCE_FLUSH)) { - tcpssn->flush_talker(tdb->pkt); + flush_talker(tsd.get_pkt()); talker->flags &= ~TF_FORCE_FLUSH; } if (listener && (listener->flags & TF_FORCE_FLUSH)) { - tcpssn->flush_listener(tdb->pkt); + flush_listener(tsd.get_pkt()); listener->flags &= ~TF_FORCE_FLUSH; } - tdb->pkt->packet_flags |= PKT_IGNORE; - retcode |= ACTION_DISABLE_INSPECTION; + 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) +{ /* Handle data on SYN */ - if ((tdb->pkt->dsize) && tcph->is_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) { // remove data on SYN - listener->normalizer->trim_syn_payload( tdb ); + 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); - eventcode |= EVENT_DATA_ON_SYN; - retcode |= ACTION_BAD_PKT; + tel->set_tcp_event(EVENT_DATA_ON_SYN); + pkt_action_mask |= ACTION_BAD_PKT; } } } +} - if (!tcpssn->tcp_init) +void TcpSession::process_tcp_packet(TcpSegmentDescriptor& tsd) +{ + Profile profile(s5TcpStatePerfStats); + + int got_ts = 0; + talker = nullptr; + listener = nullptr; + const tcp::TCPHdr* tcph = tsd.get_tcph(); + + DEBUG_WRAP(const char* t = NULL; const char* l = NULL; ); + + /* 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 ) { - LogTcpEvents(eventcode); - return retcode; + update_session_on_server_packet(tcph, tsd); + DEBUG_WRAP(t = "Server"; l = "Client"); } + else + { + update_session_on_client_packet(tsd); + DEBUG_WRAP(t = "Server"; l = "Client"); + } + + //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, state_names[talker->s_mgr.state]); - DebugFormat(DEBUG_STREAM_STATE, " %s state: %s(%d)\n", l, state_names[listener->s_mgr.state], listener->s_mgr.state); + 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() ) + if ( tcph->is_syn() ) talker->s_mgr.sub_state |= SUB_SYN_SENT; - if( tcph->is_ack() ) + if ( tcph->is_ack() ) talker->s_mgr.sub_state |= SUB_ACK_SENT; - /* - * process SYN ACK on unestablished sessions - */ - if ((TCP_STATE_SYN_SENT == listener->s_mgr.state) && (TCP_STATE_LISTEN == talker->s_mgr.state)) + // process SYN ACK on unestablished sessions + if ( ( TcpStreamTracker::TCP_SYN_SENT == listener->get_tcp_state() ) && + ( TcpStreamTracker::TCP_LISTEN == talker->get_tcp_state() ) ) { - if( tcph->is_ack() ) + if ( tcph->is_ack() ) { - /* - * make sure we've got a valid segment - */ - if (!IsBetween(listener->l_unackd, listener->l_nxt_seq, tdb->ack)) + // make sure we've got a valid segment + if (!listener->is_ack_valid(tsd.get_ack() ) ) { - DebugMessage(DEBUG_STREAM_STATE, "Pkt ack is out of bounds, bailing!\n"); + 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( tdb ); - LogTcpEvents(eventcode); - return retcode | ACTION_BAD_PKT; + listener->normalizer->trim_win_payload(tsd); + pkt_action_mask |= ACTION_BAD_PKT; + return; } } - talker->flags |= talker->normalizer->get_tcp_timestamp(tdb, false); - if (tdb->ts == 0) + 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() ) + // catch resets sent by server + if ( tcph->is_rst() ) { DebugMessage(DEBUG_STREAM_STATE, "got RST\n"); - listener->normalizer->trim_rst_payload( tdb ); + listener->normalizer->trim_rst_payload(tsd); - /* Reset is valid when in SYN_SENT if the - * ack field ACKs the SYN. - */ - if (ValidRstSynSent(listener, tdb)) + // 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 */ @@ -1800,30 +1089,29 @@ static int ProcessTcp(Flow* flow, TcpDataBlock* tdb, StreamTcpConfig* config) * 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->s_mgr.state = TCP_STATE_CLOSED; - StreamUpdatePerfBaseState(&sfBase, flow, TCP_STATE_CLOSING); + flow->set_session_flags(SSNFLAG_RESET); + talker->set_tcp_state(TcpStreamTracker::TCP_CLOSED); + update_perf_base_state(&sfBase, TcpStreamTracker::TCP_CLOSING); /* Leave listener open, data may be in transit */ - LogTcpEvents(eventcode); - return retcode | ACTION_RST; + pkt_action_mask |= ACTION_RST; + return; } /* Reset not valid. */ DebugMessage(DEBUG_STREAM_STATE, "bad sequence number, bailing\n"); inc_tcp_discards(); - eventcode |= EVENT_BAD_RST; - listener->normalizer->packet_dropper(tdb, NORM_TCP_BLOCK); - LogTcpEvents(eventcode); - return retcode; + tel->set_tcp_event(EVENT_BAD_RST); + listener->normalizer->packet_dropper(tsd, NORM_TCP_BLOCK); + return; } // finish up server init - if( tcph->is_syn() ) + if ( tcph->is_syn() ) { - FinishServerInit(tdb, tcpssn); + FinishServerInit(tsd); if (talker->flags & TF_TSTAMP) { - talker->ts_last_pkt = tdb->pkt->pkth->ts.tv_sec; - talker->ts_last = tdb->ts; + talker->set_ts_last_packet(tsd.get_pkt()->pkth->ts.tv_sec); + talker->ts_last = tsd.get_ts(); } DebugMessage(DEBUG_STREAM_STATE, "Finish server init got called!\n"); @@ -1833,14 +1121,14 @@ static int ProcessTcp(Flow* flow, TcpDataBlock* tdb, StreamTcpConfig* config) DebugMessage(DEBUG_STREAM_STATE, "Finish server init didn't get called!\n"); } - if( tcph->are_flags_set( TH_ECE ) && ( flow->get_session_flags() & SSNFLAG_ECN_CLIENT_QUERY ) ) - flow->set_session_flags( SSNFLAG_ECN_SERVER_REPLY ); + if ( tcph->are_flags_set(TH_ECE) && + ( flow->get_session_flags() & SSNFLAG_ECN_CLIENT_QUERY ) ) + flow->set_session_flags(SSNFLAG_ECN_SERVER_REPLY); // explicitly set the state - listener->s_mgr.state = TCP_STATE_SYN_SENT; + listener->set_tcp_state(TcpStreamTracker::TCP_SYN_SENT); DebugMessage(DEBUG_STREAM_STATE, "Accepted SYN ACK\n"); - LogTcpEvents(eventcode); - return retcode; + return; } /* @@ -1849,327 +1137,331 @@ static int ProcessTcp(Flow* flow, TcpDataBlock* tdb, StreamTcpConfig* config) * This is per RFC 1323. */ if ((talker->flags & TF_WSCALE) && (listener->flags & TF_WSCALE)) - tdb->win <<= talker->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 (!(tdb->pkt->pkth->flags & DAQ_PKT_FLAG_PRE_ROUTING)) + if (!(tsd.get_pkt()->pkth->flags & DAQ_PKT_FLAG_PRE_ROUTING)) #endif { - eventcode |= ValidMacAddress(talker, listener, tdb->pkt); + tel->set_tcp_event(is_mac_address_valid (talker, listener, tsd.get_pkt() ) ); } - ts_action = listener->normalizer->handle_paws( tdb, &eventcode, &got_ts ); + pkt_action_mask |= listener->normalizer->handle_paws(tsd, &got_ts); // check RST validity - if( tcph->is_rst() ) + if ( tcph->is_rst() ) { - listener->normalizer->trim_rst_payload( tdb ); + listener->normalizer->trim_rst_payload(tsd); - if (listener->normalizer->validate_rst( tdb )) + if (listener->normalizer->validate_rst(tsd)) { DebugMessage(DEBUG_STREAM_STATE, "Got RST, bailing\n"); - if (listener->s_mgr.state == TCP_STATE_FIN_WAIT_1 - || listener->s_mgr.state == TCP_STATE_FIN_WAIT_2 - || listener->s_mgr.state == TCP_STATE_CLOSE_WAIT - || listener->s_mgr.state == TCP_STATE_CLOSING) + 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) { - tcpssn->flush_talker(tdb->pkt); - tcpssn->flush_listener(tdb->pkt); - tcpssn->set_splitter(true, nullptr); - tcpssn->set_splitter(false, nullptr); + flush_talker(tsd.get_pkt()); + flush_listener(tsd.get_pkt()); + set_splitter(true, nullptr); + set_splitter(false, nullptr); flow->free_application_data(); } - flow->set_session_flags( SSNFLAG_RESET ); - talker->s_mgr.state = TCP_STATE_CLOSED; - talker->s_mgr.sub_state |= SUB_RST_SENT; - StreamUpdatePerfBaseState(&sfBase, flow, TCP_STATE_CLOSING); - if( listener->normalizer->is_tcp_ips_enabled() ) - listener->s_mgr.state = TCP_STATE_CLOSED; + 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(&sfBase, TcpStreamTracker::TCP_CLOSING); - /* else for ids: - leave listener open, data may be in transit */ + if ( listener->normalizer->is_tcp_ips_enabled() ) + listener->set_tcp_state(TcpStreamTracker::TCP_CLOSED); - LogTcpEvents(eventcode); - return retcode | ACTION_RST; + /* else for ids: 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(); - eventcode |= EVENT_BAD_RST; - listener->normalizer->packet_dropper(tdb, NORM_TCP_BLOCK); - LogTcpEvents(eventcode); - return retcode | ts_action; + tel->set_tcp_event(EVENT_BAD_RST); + listener->normalizer->packet_dropper(tsd, NORM_TCP_BLOCK); + return; } else { /* check for valid seqeuence/retrans */ - if (listener->config->policy != StreamPolicy::OS_PROXY - and (listener->s_mgr.state >= TCP_STATE_ESTABLISHED) - and !ValidSeq( listener, tdb )) + 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( tdb ); - LogTcpEvents(eventcode); - return retcode | ts_action; + listener->normalizer->trim_win_payload(tsd); + return; } } - if (ts_action != ACTION_NOTHING) + if ( pkt_action_mask & ACTION_BAD_PKT ) { DebugMessage(DEBUG_STREAM_STATE, "bad timestamp, bailing\n"); inc_tcp_discards(); - // this packet was normalized elsewhere - LogTcpEvents(eventcode); - return retcode | ts_action; + return; } // update PAWS timestamps - DebugFormat(DEBUG_STREAM_STATE, "PAWS update tdb->seq %lu > listener->r_win_base %lu\n", - tdb->seq, listener->r_win_base); - if (got_ts && SEQ_EQ(listener->r_win_base, tdb->seq)) + 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) (tdb->ts - talker->ts_last) >= 0|| - (uint32_t)tdb->pkt->pkth->ts.tv_sec >= talker->ts_last_pkt + PAWS_24DAYS) + 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 = tdb->ts; - talker->ts_last_pkt = tdb->pkt->pkth->ts.tv_sec; + talker->ts_last = tsd.get_ts(); + talker->set_ts_last_packet(tsd.get_pkt()->pkth->ts.tv_sec); } - } else + } + else { DebugMessage(DEBUG_STREAM_STATE, "not updating timestamps...\n"); } // check for repeat SYNs - if( !new_ssn && tcph->is_syn_only() ) + if ( !new_ssn && tcph->is_syn_only() ) { int action; - if (!SEQ_EQ(tdb->seq, talker->isn) && listener->normalizer->packet_dropper(tdb, NORM_TCP_BLOCK)) + if (!SEQ_EQ(tsd.get_seq(), talker->get_iss()) && + listener->normalizer->packet_dropper(tsd, NORM_TCP_BLOCK)) action = ACTION_BAD_PKT; - else if (talker->s_mgr.state >= TCP_STATE_ESTABLISHED) - action = listener->normalizer->handle_repeated_syn( tdb ); + 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! */ - eventcode |= EVENT_SYN_ON_EST; - LogTcpEvents(eventcode); - return retcode | action; + tel->set_tcp_event(EVENT_SYN_ON_EST); + pkt_action_mask |= action; + return; } } // Check that the window is within the limits - if (listener->config->policy != StreamPolicy::OS_PROXY) + if (config->policy != StreamPolicy::OS_PROXY) { - if (listener->config->max_window && (tdb->win > listener->config->max_window)) + 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"); + DebugMessage(DEBUG_STREAM_STATE, + "Got window that was beyond the allowed policy value, bailing\n"); /* got a window too large, alert! */ - eventcode |= EVENT_WINDOW_TOO_LARGE; + tel->set_tcp_event(EVENT_WINDOW_TOO_LARGE); inc_tcp_discards(); - listener->normalizer->packet_dropper(tdb, NORM_TCP_BLOCK); - LogTcpEvents(eventcode); - return retcode | ACTION_BAD_PKT; + listener->normalizer->packet_dropper(tsd, NORM_TCP_BLOCK); + pkt_action_mask |= ACTION_BAD_PKT; + return; } - else if ((tdb->pkt->packet_flags & PKT_FROM_CLIENT) && (tdb->win <= SLAM_MAX) - && (tdb->ack == listener->isn + 1) - && !( tcph->is_fin() | tcph->is_rst() ) - && !(flow->get_session_flags() & SSNFLAG_MIDSTREAM)) + 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! */ - eventcode |= EVENT_WINDOW_SLAM; + tel->set_tcp_event(EVENT_WINDOW_SLAM); inc_tcp_discards(); - if (listener->normalizer->packet_dropper(tdb, NORM_TCP_BLOCK)) + if (listener->normalizer->packet_dropper(tsd, NORM_TCP_BLOCK)) { - LogTcpEvents(eventcode); - return retcode | ACTION_BAD_PKT; + pkt_action_mask |= ACTION_BAD_PKT; + return; } } } - if (talker->s_mgr.state_queue != TCP_STATE_NONE) + 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, tdb->ack); + 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 (tdb->ack == talker->s_mgr.transition_seq) + if (tsd.get_ack() == talker->s_mgr.transition_seq) { DebugMessage(DEBUG_STREAM_STATE, "accepting transition!\n"); - talker->s_mgr.state = talker->s_mgr.state_queue; - talker->s_mgr.state_queue = TCP_STATE_NONE; + 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() ) + if ( tcph->is_ack() ) { DebugMessage(DEBUG_STREAM_STATE, "Got an ACK...\n"); - DebugFormat(DEBUG_STREAM_STATE, " %s [listener] state: %s\n", l, state_names[listener->s_mgr.state]); + DebugFormat(DEBUG_STREAM_STATE, " %s [listener] state: %s\n", l, + tcp_state_names[listener->get_tcp_state()]); - switch (listener->s_mgr.state) + switch ( listener->get_tcp_state() ) { - case TCP_STATE_SYN_SENT: - break; + case TcpStreamTracker::TCP_SYN_SENT: + break; - case TCP_STATE_SYN_RCVD: - DebugMessage(DEBUG_STREAM_STATE, "listener state is SYN_SENT...\n"); - if (IsBetween(listener->l_unackd, listener->l_nxt_seq, tdb->ack)) - { - UpdateSsn(listener, talker, tdb); - flow->set_session_flags( SSNFLAG_ESTABLISHED ); - flow->session_state |= STREAM_STATE_ESTABLISHED; - listener->s_mgr.state = TCP_STATE_ESTABLISHED; - talker->s_mgr.state = TCP_STATE_ESTABLISHED; - StreamUpdatePerfBaseState(&sfBase, flow, TCP_STATE_ESTABLISHED); - /* Indicate this packet completes 3-way handshake */ - tdb->pkt->packet_flags |= PKT_STREAM_TWH; - } + 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(&sfBase, 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, tdb->seq)) - { - talker->ts_last_pkt = tdb->pkt->pkth->ts.tv_sec; - talker->ts_last = tdb->ts; - } + 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; + break; - case TCP_STATE_ESTABLISHED: - case TCP_STATE_CLOSE_WAIT: - UpdateSsn( listener, talker, tdb); - break; + case TcpStreamTracker::TCP_ESTABLISHED: + case TcpStreamTracker::TCP_CLOSE_WAIT: + UpdateSsn(listener, talker, tsd); + break; - case TCP_STATE_FIN_WAIT_1: - UpdateSsn(listener, talker, tdb); + case TcpStreamTracker::TCP_FIN_WAIT1: + UpdateSsn(listener, talker, tsd); - DebugFormat(DEBUG_STREAM_STATE, "tdb->ack %X >= talker->r_nxt_ack %X\n", tdb->ack, talker->r_nxt_ack); + DebugFormat(DEBUG_STREAM_STATE, "tsd.ack %X >= talker->r_nxt_ack %X\n", tsd.get_ack(), + talker->r_nxt_ack); - if (SEQ_EQ(tdb->ack, listener->l_nxt_seq)) + if ( SEQ_EQ(tsd.get_ack(), listener->get_snd_nxt() ) ) + { + if ((listener->normalizer->get_os_policy() == StreamPolicy::OS_WINDOWS) && + (tsd.get_win() == 0)) { - if ((listener->normalizer->get_os_policy() == StreamPolicy::OS_WINDOWS) && (tdb->win == 0)) + tel->set_tcp_event(EVENT_WINDOW_SLAM); + inc_tcp_discards(); + + if (listener->normalizer->packet_dropper(tsd, NORM_TCP_BLOCK)) { - eventcode |= EVENT_WINDOW_SLAM; - inc_tcp_discards(); - - if (listener->normalizer->packet_dropper(tdb, NORM_TCP_BLOCK)) - { - LogTcpEvents(eventcode); - return retcode | ACTION_BAD_PKT; - } + pkt_action_mask |= ACTION_BAD_PKT; + return; } + } - listener->s_mgr.state = TCP_STATE_FIN_WAIT_2; + listener->set_tcp_state(TcpStreamTracker::TCP_FIN_WAIT2); - if( tcph->is_fin() ) + if ( tcph->is_fin() ) + { + DebugMessage(DEBUG_STREAM_STATE, "seq ok, setting state!\n"); + + if ( talker->s_mgr.state_queue == TcpStreamTracker::TCP_STATE_NONE ) { - DebugMessage(DEBUG_STREAM_STATE, "seq ok, setting state!\n"); - - if (talker->s_mgr.state_queue == TCP_STATE_NONE) - { - talker->s_mgr.state = TCP_STATE_LAST_ACK; - EndOfFileHandle(tdb->pkt, tcpssn); - } - 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 = TCP_STATE_TIME_WAIT; - listener->s_mgr.transition_seq = tdb->end_seq; - listener->s_mgr.expected_flags = TH_ACK; - } - } else if (listener->s_mgr.state_queue == TCP_STATE_CLOSING) + talker->set_tcp_state(TcpStreamTracker::TCP_LAST_ACK); + EndOfFileHandle(tsd.get_pkt() ); + } + if ( flow->get_session_flags() & SSNFLAG_MIDSTREAM ) { - listener->s_mgr.state_queue = TCP_STATE_TIME_WAIT; - listener->s_mgr.transition_seq = tdb->end_seq; + // 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 - { - DebugMessage(DEBUG_STREAM_STATE, "bad ack!\n"); } - break; - - case TCP_STATE_FIN_WAIT_2: - UpdateSsn(listener, talker, tdb); - if (SEQ_GT(tdb->ack, listener->l_nxt_seq)) + else if ( listener->s_mgr.state_queue == TcpStreamTracker::TCP_CLOSING ) { - eventcode |= EVENT_BAD_ACK; - LogTcpEvents(eventcode); - listener->normalizer->packet_dropper(tdb, NORM_TCP_BLOCK); - return retcode | ACTION_BAD_PKT; + 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; } - break; + } + else + { + DebugMessage(DEBUG_STREAM_STATE, "bad ack!\n"); + } + break; - case TCP_STATE_CLOSING: - UpdateSsn(listener, talker, tdb); - if (SEQ_GEQ(tdb->end_seq, listener->r_nxt_ack)) - listener->s_mgr.state = TCP_STATE_TIME_WAIT; - 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 TCP_STATE_LAST_ACK: - UpdateSsn( listener, talker, tdb); + 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; - if (SEQ_EQ(tdb->ack, listener->l_nxt_seq)) - listener->s_mgr.state = TCP_STATE_CLOSED; - break; + case TcpStreamTracker::TCP_LAST_ACK: + UpdateSsn(listener, talker, tsd); - default: - // FIXIT-L safe to ignore when inline? - break; + 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( tdb->pkt ); + talker->reassembler->flush_on_ack_policy(tsd.get_pkt() ); } // handle data in the segment - if (tdb->pkt->dsize) + if (tsd.get_pkt()->dsize) { DebugFormat(DEBUG_STREAM_STATE, " %s state: %s(%d) getting data\n", - l, state_names[listener->s_mgr.state], listener->s_mgr.state); + 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 ( talker->s_mgr.state == TCP_STATE_FIN_WAIT_2 - or talker->s_mgr.state == TCP_STATE_TIME_WAIT ) + 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); - eventcode |= EVENT_DATA_ON_CLOSED; - retcode |= ACTION_BAD_PKT; - listener->normalizer->packet_dropper(tdb, NORM_TCP_BLOCK); + tel->set_tcp_event(EVENT_DATA_ON_CLOSED); + pkt_action_mask |= ACTION_BAD_PKT; + listener->normalizer->packet_dropper(tsd, NORM_TCP_BLOCK); } - else if (talker->s_mgr.state == TCP_STATE_CLOSED) + 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) - eventcode |= EVENT_DATA_AFTER_RESET; + tel->set_tcp_event(EVENT_DATA_AFTER_RESET); else - eventcode |= EVENT_DATA_AFTER_RST_RCVD; + tel->set_tcp_event(EVENT_DATA_AFTER_RST_RCVD); } else { //EventDataOnClosed(listener->config); - eventcode |= EVENT_DATA_ON_CLOSED; + tel->set_tcp_event(EVENT_DATA_ON_CLOSED); } - retcode |= ACTION_BAD_PKT; - listener->normalizer->packet_dropper(tdb, NORM_TCP_BLOCK); + pkt_action_mask |= ACTION_BAD_PKT; + listener->normalizer->packet_dropper(tsd, NORM_TCP_BLOCK); } else { - DebugFormat(DEBUG_STREAM_STATE, "Queuing data on listener, t %s, l %s...\n", - flush_policy_names[talker->flush_policy], flush_policy_names[listener->flush_policy]); + flush_policy_names[talker->flush_policy], + flush_policy_names[listener->flush_policy]); if (config->policy != StreamPolicy::OS_PROXY) { @@ -2182,39 +1474,42 @@ static int ProcessTcp(Flow* flow, TcpDataBlock* tdb, StreamTcpConfig* config) TcpTracker* st = listener; // trim to fit in window and mss as needed - st->normalizer->trim_win_payload(tdb, (st->r_win_base + st->l_window) - 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( tdb, st->mss ); + st->normalizer->trim_mss_payload(tsd, st->mss); - st->normalizer->ecn_stripper( tdb->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) - or (config->policy == StreamPolicy::OS_PROXY)) + or (config->policy == StreamPolicy::OS_LINUX) + or (config->policy == StreamPolicy::OS_PROXY)) { - ProcessTcpData( listener, tcpssn, tdb, config); + process_tcp_data(listener, tsd); } else { - eventcode |= EVENT_DATA_WITHOUT_FLAGS; - listener->normalizer->packet_dropper(tdb, NORM_TCP_BLOCK); + tel->set_tcp_event(EVENT_DATA_WITHOUT_FLAGS); + listener->normalizer->packet_dropper(tsd, NORM_TCP_BLOCK); } } - listener->reassembler->flush_on_data_policy( tdb->pkt ); + listener->reassembler->flush_on_data_policy(tsd.get_pkt() ); } - if( tcph->is_fin() ) + if ( tcph->is_fin() ) { DebugMessage(DEBUG_STREAM_STATE, "Got a FIN...\n"); - DebugFormat(DEBUG_STREAM_STATE, " %s state: %s(%d)\n", l, state_names[talker->s_mgr.state], talker->s_mgr.state); - DebugFormat(DEBUG_STREAM_STATE, "checking ack (0x%X) vs nxt_ack (0x%X)\n", tdb->end_seq, listener->r_win_base); + 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(tdb->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"); goto dupfin; @@ -2222,210 +1517,230 @@ static int ProcessTcp(Flow* flow, TcpDataBlock* tdb, StreamTcpConfig* config) else { // need substate since we don't change state immediately - if ((talker->s_mgr.state >= TCP_STATE_ESTABLISHED) && !(talker->s_mgr.sub_state & SUB_FIN_SENT)) + if ( (talker->get_tcp_state() >= TcpStreamTracker::TCP_ESTABLISHED ) + && !( talker->s_mgr.sub_state & SUB_FIN_SENT ) ) { - talker->l_nxt_seq++; + 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(tdb->end_seq, listener->r_nxt_ack) ) + //if ( SEQ_EQ(tsd.end_seq, listener->r_nxt_ack) ) listener->r_nxt_ack++; //-------------------------------------------------- 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() ) + if ( ( listener->flush_policy != STREAM_FLPOLICY_ON_ACK ) + && ( listener->flush_policy != STREAM_FLPOLICY_ON_DATA ) + && listener->normalizer->is_tcp_ips_enabled() ) { - tdb->pkt->packet_flags |= PKT_PDU_TAIL; + tsd.get_pkt()->packet_flags |= PKT_PDU_TAIL; } } - switch (talker->s_mgr.state) + switch (talker->get_tcp_state()) { - case TCP_STATE_SYN_RCVD: - case TCP_STATE_ESTABLISHED: - if (talker->s_mgr.state_queue == TCP_STATE_CLOSE_WAIT) - talker->s_mgr.state_queue = TCP_STATE_CLOSING; + 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->s_mgr.state = TCP_STATE_FIN_WAIT_1; - EndOfFileHandle(tdb->pkt, tcpssn); + talker->set_tcp_state(TcpStreamTracker::TCP_FIN_WAIT1); + EndOfFileHandle(tsd.get_pkt() ); - if (!tdb->pkt->dsize) - listener->reassembler->flush_on_data_policy( tdb->pkt ); + if ( !tsd.get_pkt()->dsize ) + listener->reassembler->flush_on_data_policy(tsd.get_pkt() ); - StreamUpdatePerfBaseState(&sfBase, tcpssn->flow, TCP_STATE_CLOSING); - break; + update_perf_base_state(&sfBase, TcpStreamTracker::TCP_CLOSING); + break; - case TCP_STATE_CLOSE_WAIT: - talker->s_mgr.state = TCP_STATE_LAST_ACK; - break; + case TcpStreamTracker::TCP_CLOSE_WAIT: + talker->set_tcp_state(TcpStreamTracker::TCP_LAST_ACK); + break; - case TCP_STATE_FIN_WAIT_1: - if (!tdb->pkt->dsize) - tcpssn->retransmit_handle( tdb->pkt ); - break; + case TcpStreamTracker::TCP_FIN_WAIT1: + if (!tsd.get_pkt()->dsize) + retransmit_handle(tsd.get_pkt() ); + break; - default: - /* all other states stay where they are */ - break; + default: + /* all other states stay where they are */ + break; } - if ((talker->s_mgr.state == TCP_STATE_FIN_WAIT_1) || (talker->s_mgr.state == TCP_STATE_LAST_ACK)) + 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) - ? tdb->end_seq - 1 : tdb->end_seq; + ? tsd.get_end_seq() - 1 : tsd.get_end_seq(); - if ((listener->s_mgr.expected_flags == TH_ACK) && SEQ_GEQ(end_seq, listener->s_mgr.transition_seq)) + 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"); - eventcode |= EVENT_BAD_FIN; - LogTcpEvents(eventcode); - listener->normalizer->packet_dropper(tdb, NORM_TCP_BLOCK); - return retcode | ACTION_BAD_PKT; + tel->set_tcp_event(EVENT_BAD_FIN); + listener->normalizer->packet_dropper(tsd, NORM_TCP_BLOCK); + pkt_action_mask |= ACTION_BAD_PKT; + return; } } - switch (listener->s_mgr.state) + switch ( listener->get_tcp_state() ) { - case TCP_STATE_ESTABLISHED: - listener->s_mgr.state_queue = TCP_STATE_CLOSE_WAIT; - listener->s_mgr.transition_seq = tdb->end_seq + 1; - listener->s_mgr.expected_flags = TH_ACK; - break; + 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 TCP_STATE_FIN_WAIT_1: - listener->s_mgr.state_queue = TCP_STATE_CLOSING; - listener->s_mgr.transition_seq = tdb->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 TCP_STATE_FIN_WAIT_2: - listener->s_mgr.state_queue = TCP_STATE_TIME_WAIT; - listener->s_mgr.transition_seq = tdb->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: - DebugFormat(DEBUG_STREAM_STATE, " %s [talker] state: %s\n", t, state_names[talker->s_mgr.state]); - DebugFormat(DEBUG_STREAM_STATE, " %s state: %s(%d)\n", l, state_names[listener->s_mgr.state], listener->s_mgr.state); + 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()); // handle TIME_WAIT timer stuff if (!flow->two_way_traffic() && - (talker->s_mgr.state >= TCP_STATE_FIN_WAIT_1 || listener->s_mgr.state >= TCP_STATE_FIN_WAIT_1)) + (talker->get_tcp_state() >= TcpStreamTracker::TCP_FIN_WAIT1 || listener->get_tcp_state() >= + TcpStreamTracker::TCP_FIN_WAIT1)) { if (tcph->is_fin() && tcph->is_ack()) { - if (talker->s_mgr.state >= TCP_STATE_FIN_WAIT_1) - talker->s_mgr.state = TCP_STATE_CLOSED; - if (listener->s_mgr.state >= TCP_STATE_FIN_WAIT_1) - listener->s_mgr.state = TCP_STATE_CLOSED; + if (talker->get_tcp_state() >= TcpStreamTracker::TCP_FIN_WAIT1) + talker->set_tcp_state(TcpStreamTracker::TCP_CLOSED); + + if (listener->get_tcp_state() >= TcpStreamTracker::TCP_FIN_WAIT1) + listener->set_tcp_state(TcpStreamTracker::TCP_CLOSED); + listener->flags |= TF_FORCE_FLUSH; } } - if ( (talker->s_mgr.state == TCP_STATE_TIME_WAIT && listener->s_mgr.state == TCP_STATE_CLOSED) - || (listener->s_mgr.state == TCP_STATE_TIME_WAIT && talker->s_mgr.state == TCP_STATE_CLOSED) - || (listener->s_mgr.state == TCP_STATE_TIME_WAIT && talker->s_mgr.state == TCP_STATE_TIME_WAIT) - || (!flow->two_way_traffic() && (talker->s_mgr.state == TCP_STATE_CLOSED || listener->s_mgr.state == TCP_STATE_CLOSED))) + if ( ( talker->get_tcp_state() == TcpStreamTracker::TCP_TIME_WAIT && + listener->get_tcp_state() == TcpStreamTracker::TCP_CLOSED) + || (listener->get_tcp_state() == TcpStreamTracker::TCP_TIME_WAIT && + 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 || + listener->get_tcp_state() == TcpStreamTracker::TCP_CLOSED))) { // The last ACK is a part of the session. Delete the session after processing is complete. - LogTcpEvents(eventcode); - TcpSessionCleanup(flow, 0, tdb->pkt); + cleanup_session(0, tsd.get_pkt() ); flow->session_state |= STREAM_STATE_CLOSED; - return retcode | ACTION_LWSSN_CLOSED; + pkt_action_mask |= ACTION_LWSSN_CLOSED; + return; } - else if( listener->s_mgr.state == TCP_STATE_CLOSED - && talker->s_mgr.state == TCP_STATE_SYN_SENT ) + else if ( listener->get_tcp_state() == TcpStreamTracker::TCP_CLOSED + && talker->get_tcp_state() == TcpStreamTracker::TCP_SYN_SENT ) { - if( tcph->is_syn_only() ) - flow->set_expire(tdb->pkt, config->session_timeout); + if ( tcph->is_syn_only() ) + flow->set_expire(tsd.get_pkt(), config->session_timeout); } - - LogTcpEvents(eventcode); - return retcode; } - //------------------------------------------------------------------------- // TcpSession methods //------------------------------------------------------------------------- TcpSession::TcpSession(Flow* flow) : - Session(flow), ecn(0), event_mask(0) + 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) { lws_init = tcp_init = false; + new_ssn = false; + + tel = new TcpEventLogger; - memset(&client, 0, sizeof(TcpTracker)); - memset(&server, 0, sizeof(TcpTracker)); + // 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() +TcpSession::~TcpSession(void) { if (tcp_init) - TcpSessionClear(flow, (TcpSession*) flow->session, 1); - - delete client.normalizer; - delete server.normalizer; - delete client.reassembler; - delete server.reassembler; + { + clear_session(1); + + delete client; + delete server; + } + + delete tel; } -void TcpSession::reset() +void TcpSession::reset(void) { if (tcp_init) - TcpSessionClear(flow, (TcpSession*) flow->session, 2); + clear_session(2); } bool TcpSession::setup(Packet*) { - - TcpStateHandler* tsh = new TcpStateHandler; - // FIXIT-L this it should not be necessary to reset here reset(); + client->init_tracker( ); + server->init_tracker( ); lws_init = tcp_init = false; - event_mask = 0; + no_3whs = false; + pkt_action_mask = ACTION_NOTHING; ecn = 0; - - memset(&client, 0, offsetof(TcpTracker, alerts)); - memset(&server, 0, offsetof(TcpTracker, alerts)); - ingress_index = egress_index = 0; ingress_group = egress_group = 0; daq_flags = address_space_id = 0; - // FIXIT - this is just temp...remove... - delete tsh; - tsh = new TcpClosedState; - delete tsh; - tsh = new TcpListenState; - delete tsh; - tsh = new TcpSynSentState; - delete tsh; - tcpStats.sessions++; return true; } -void TcpSession::cleanup() +void TcpSession::cleanup(void) { // this flushes data and then calls TcpSessionClear() - TcpSessionCleanup(flow, 1); + cleanup_session(1); } -void TcpSession::clear() +void TcpSession::clear(void) { - if( tcp_init ) + if ( tcp_init ) // this does NOT flush data - TcpSessionClear(flow, this, 1); + clear_session(true); } void TcpSession::restart(Packet* p) @@ -2433,134 +1748,121 @@ void TcpSession::restart(Packet* p) // sanity check since this is called externally assert(p->ptrs.tcph); - TcpTracker* talker, *listener; + TcpTracker* talker, * listener; if (p->packet_flags & PKT_FROM_SERVER) { - talker = &server; - listener = &client; + talker = server; + listener = client; } else { - talker = &client; - listener = &server; + 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 ); + listener->reassembler->flush_on_data_policy(p); if (p->ptrs.tcph->is_ack()) - talker->reassembler->flush_on_ack_policy( p ); + talker->reassembler->flush_on_ack_policy(p); } -void TcpSession::set_splitter(bool c2s, StreamSplitter* ss) +void TcpSession::print(void) { - TcpTracker* trk; - - if (c2s) - trk = &server; - else - trk = &client; - - if (trk->splitter && tcp_init) - delete trk->splitter; - - trk->splitter = ss; + char buf[64]; - if (ss) - paf_setup(&trk->paf_state); - else - trk->flush_policy = STREAM_FLPOLICY_IGNORE; + 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(); } -StreamSplitter* TcpSession::get_splitter(bool c2s) +void TcpSession::set_splitter(bool to_server, StreamSplitter* ss) { - if (c2s) - return server.splitter; + TcpTracker* trk = ( to_server ) ? server : client; - return client.splitter; + trk->set_splitter(ss); } -void TcpSession::flush_server(Packet *p) +StreamSplitter* TcpSession::get_splitter(bool to_server) { - int flushed; - TcpTracker *flushTracker = &server; + if ( to_server ) + return server->splitter; + else + return client->splitter; +} - flushTracker->flags |= TF_FORCE_FLUSH; +void TcpSession::flush_server(Packet* p) +{ + server->flags |= TF_FORCE_FLUSH; - /* If this is a rebuilt packet, don't flush now because we'll - * overwrite the packet being processed. - */ - if (p->packet_flags & PKT_REBUILT_STREAM) + // If rebuilt packet, don't flush now because we'll overwrite the packet being processed. + if ( p->packet_flags & PKT_REBUILT_STREAM ) { - /* We'll check & clear the TF_FORCE_FLUSH next time through */ + // We'll check & clear the TF_FORCE_FLUSH next time through return; } - /* Need to convert the addresses to network order */ - flushed = flushTracker->reassembler->flush_stream( p, PKT_FROM_SERVER); + // Need to convert the addresses to network order + if ( server->reassembler->flush_stream(p, PKT_FROM_SERVER) ) + server->reassembler->purge_flushed_ackd( ); - if (flushed) - flushTracker->reassembler->purge_flushed_ackd( ); - - flushTracker->flags &= ~TF_FORCE_FLUSH; + server->flags &= ~TF_FORCE_FLUSH; } void TcpSession::flush_client(Packet* p) { - int flushed; - TcpTracker *flushTracker = &client; - - flushTracker->flags |= TF_FORCE_FLUSH; + client->flags |= TF_FORCE_FLUSH; - /* If this is a rebuilt packet, don't flush now because we'll - * overwrite the packet being processed. - */ - if (p->packet_flags & PKT_REBUILT_STREAM) + // If rebuilt packet, don't flush now because we'll overwrite the packet being processed. + if ( p->packet_flags & PKT_REBUILT_STREAM ) { - /* We'll check & clear the TF_FORCE_FLUSH next time through */ + // We'll check & clear the TF_FORCE_FLUSH next time through return; } - /* Need to convert the addresses to network order */ - flushed = flushTracker->reassembler->flush_stream(p, PKT_FROM_CLIENT); - - if (flushed) - flushTracker->reassembler->purge_flushed_ackd( ); + if ( client->reassembler->flush_stream(p, PKT_FROM_CLIENT) ) + client->reassembler->purge_flushed_ackd( ); - flushTracker->flags &= ~TF_FORCE_FLUSH; + client->flags &= ~TF_FORCE_FLUSH; } void TcpSession::flush_listener(Packet* p) { - TcpTracker *listener = NULL; + TcpTracker* listener = nullptr; uint32_t dir = 0; - int flushed = 0; /* figure out direction of this packet -- we should've already * looked at it, so the packet_flags are already set. */ - if (p->packet_flags & PKT_FROM_SERVER) + if ( p->packet_flags & PKT_FROM_SERVER ) { DebugMessage(DEBUG_STREAM_STATE, "Flushing listener on packet from server\n"); - listener = &client; + listener = client; /* dir of flush is the data from the opposite side */ dir = PKT_FROM_SERVER; } - else if (p->packet_flags & PKT_FROM_CLIENT) + else if ( p->packet_flags & PKT_FROM_CLIENT ) { DebugMessage(DEBUG_STREAM_STATE, "Flushing listener on packet from client\n"); - listener = &server; + listener = server; /* dir of flush is the data from the opposite side */ dir = PKT_FROM_CLIENT; } - if (dir != 0) + if ( dir != 0 ) { listener->flags |= TF_FORCE_FLUSH; - flushed = listener->reassembler->flush_stream( p, dir); - - if (flushed) + if ( listener->reassembler->flush_stream(p, dir) ) listener->reassembler->purge_flushed_ackd( ); listener->flags &= ~TF_FORCE_FLUSH; @@ -2569,23 +1871,22 @@ void TcpSession::flush_listener(Packet* p) void TcpSession::flush_talker(Packet* p) { - TcpTracker *talker = NULL; + TcpTracker* talker = nullptr; uint32_t dir = 0; - int flushed = 0; /* figure out direction of this packet -- we should've already * looked at it, so the packet_flags are already set. */ - if (p->packet_flags & PKT_FROM_SERVER) + if ( p->packet_flags & PKT_FROM_SERVER ) { DebugMessage(DEBUG_STREAM_STATE, "Flushing talker on packet from server\n"); - talker = &server; + talker = server; /* dir of flush is the data from the opposite side */ dir = PKT_FROM_CLIENT; } - else if (p->packet_flags & PKT_FROM_CLIENT) + else if ( p->packet_flags & PKT_FROM_CLIENT ) { DebugMessage(DEBUG_STREAM_STATE, "Flushing talker on packet from client\n"); - talker = &client; + talker = client; /* dir of flush is the data from the opposite side */ dir = PKT_FROM_SERVER; } @@ -2593,9 +1894,7 @@ void TcpSession::flush_talker(Packet* p) if (dir != 0) { talker->flags |= TF_FORCE_FLUSH; - flushed = talker->reassembler->flush_stream(p, dir); - - if (flushed) + if ( talker->reassembler->flush_stream(p, dir) ) talker->reassembler->purge_flushed_ackd( ); talker->flags &= ~TF_FORCE_FLUSH; @@ -2606,13 +1905,13 @@ void TcpSession::flush_talker(Packet* p) // packet / PDU split because PDU rules won't run on raw packets bool TcpSession::add_alert(Packet* p, uint32_t gid, uint32_t sid) { - TcpTracker *st; + TcpTracker* st; StreamAlertInfo* ai; if (sfip_equals(p->ptrs.ip_api.get_src(), &flow->client_ip)) - st = &server; + st = server; else - st = &client; + st = client; if (st->alert_count >= MAX_SESSION_ALERTS) return false; @@ -2633,12 +1932,12 @@ bool TcpSession::check_alerted(Packet* p, uint32_t gid, uint32_t sid) if (!(p->packet_flags & PKT_REBUILT_STREAM)) return false; - TcpTracker *st; + TcpTracker* st; if (sfip_equals(p->ptrs.ip_api.get_src(), &flow->client_ip)) - st = &server; + st = server; else - st = &client; + st = client; for (int i = 0; i < st->alert_count; i++) { @@ -2654,17 +1953,17 @@ bool TcpSession::check_alerted(Packet* p, uint32_t gid, uint32_t sid) return false; } -int TcpSession::update_alert(Packet *p, uint32_t gid, uint32_t sid, - uint32_t event_id, uint32_t event_second) +int TcpSession::update_alert(Packet* p, uint32_t gid, uint32_t sid, + uint32_t event_id, uint32_t event_second) { - TcpTracker *st; + TcpTracker* st; int i; uint32_t seq_num; if (sfip_equals(p->ptrs.ip_api.get_src(), &flow->client_ip)) - st = &server; + st = server; else - st = &client; + st = client; seq_num = 0; @@ -2685,41 +1984,41 @@ int TcpSession::update_alert(Packet *p, uint32_t gid, uint32_t sid, void TcpSession::set_extra_data(Packet* p, uint32_t xid) { - TcpTracker *st; + TcpTracker* st; if (sfip_equals(p->ptrs.ip_api.get_src(), &flow->client_ip)) - st = &server; + st = server; else - st = &client; + st = client; - st->reassembler->set_xtradata_mask( st->reassembler->get_xtradata_mask() | BIT(xid) ); + st->reassembler->set_xtradata_mask(st->reassembler->get_xtradata_mask() | BIT(xid) ); } void TcpSession::clear_extra_data(Packet* p, uint32_t xid) { - TcpTracker *st; + TcpTracker* st; if (sfip_equals(p->ptrs.ip_api.get_src(), &flow->client_ip)) - st = &server; + st = server; else - st = &client; + st = client; if (xid) - st->reassembler->set_xtradata_mask( st->reassembler->get_xtradata_mask() & ~BIT(xid) ); + st->reassembler->set_xtradata_mask(st->reassembler->get_xtradata_mask() & ~BIT(xid) ); else - st->reassembler->set_xtradata_mask( 0 ); + st->reassembler->set_xtradata_mask(0); } -uint8_t TcpSession::get_reassembly_direction() +uint8_t TcpSession::get_reassembly_direction(void) { uint8_t dir = SSN_DIR_NONE; - if (server.flush_policy != STREAM_FLPOLICY_IGNORE) + if (server->flush_policy != STREAM_FLPOLICY_IGNORE) { dir |= SSN_DIR_FROM_CLIENT; } - if (client.flush_policy != STREAM_FLPOLICY_IGNORE) + if (client->flush_policy != STREAM_FLPOLICY_IGNORE) { dir |= SSN_DIR_FROM_SERVER; } @@ -2731,13 +2030,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->flags & (TF_MISSING_PREV_PKT | TF_MISSING_PKT)) return false; } if (dir & SSN_DIR_FROM_SERVER) { - if (client.flags & (TF_MISSING_PREV_PKT | TF_MISSING_PKT)) + if (client->flags & (TF_MISSING_PREV_PKT | TF_MISSING_PKT)) return false; } @@ -2750,22 +2049,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->flags & TF_MISSING_PKT) + && (server->flags & TF_MISSING_PREV_PKT)) return SSN_MISSING_BOTH; - else if (server.flags & TF_MISSING_PREV_PKT) + else if (server->flags & TF_MISSING_PREV_PKT) return SSN_MISSING_BEFORE; - else if (server.flags & TF_MISSING_PKT) + else if (server->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->flags & TF_MISSING_PKT) + && (client->flags & TF_MISSING_PREV_PKT)) return SSN_MISSING_BOTH; - else if (client.flags & TF_MISSING_PREV_PKT) + else if (client->flags & TF_MISSING_PREV_PKT) return SSN_MISSING_BEFORE; - else if (client.flags & TF_MISSING_PKT) + else if (client->flags & TF_MISSING_PKT) return SSN_MISSING_AFTER; } @@ -2776,13 +2075,13 @@ bool TcpSession::are_packets_missing(uint8_t dir) { if (dir & SSN_DIR_FROM_CLIENT) { - if (server.flags & TF_PKT_MISSED) + if (server->flags & TF_PKT_MISSED) return true; } if (dir & SSN_DIR_FROM_SERVER) { - if (client.flags & TF_PKT_MISSED) + if (client->flags & TF_PKT_MISSED) return true; } @@ -2793,7 +2092,7 @@ void TcpSession::update_direction(char dir, const sfip_t* ip, uint16_t port) { sfip_t tmpIp; uint16_t tmpPort; - TcpTracker tmpTracker; + TcpTracker* tracker; if (sfip_equals(&flow->client_ip, ip) && (flow->client_port == port)) { @@ -2813,8 +2112,6 @@ void TcpSession::update_direction(char dir, const sfip_t* ip, uint16_t port) } /* Swap them -- leave flow->ssn_state.direction the same */ - - /* XXX: Gotta be a more efficient way to do this without the memcpy */ tmpIp = flow->client_ip; tmpPort = flow->client_port; flow->client_ip = flow->server_ip; @@ -2823,12 +2120,12 @@ void TcpSession::update_direction(char dir, const sfip_t* ip, uint16_t port) flow->server_port = tmpPort; SwapPacketHeaderFoo( ); - memcpy(&tmpTracker, &client, sizeof(TcpTracker)); - memcpy(&client, &server, sizeof(TcpTracker)); - memcpy(&server, &tmpTracker, sizeof(TcpTracker)); + tracker = client; + client = server; + server = tracker; } -void TcpSession::SetPacketHeaderFoo( const Packet* p ) +void TcpSession::SetPacketHeaderFoo(const Packet* p) { if ( daq_flags & DAQ_PKT_FLAG_NOT_FORWARDING ) { @@ -2854,7 +2151,7 @@ void TcpSession::SetPacketHeaderFoo( const Packet* p ) address_space_id = p->pkth->address_space_id; } -void TcpSession::GetPacketHeaderFoo( DAQ_PktHdr_t* pkth, uint32_t dir ) +void TcpSession::GetPacketHeaderFoo(DAQ_PktHdr_t* pkth, uint32_t dir) { if ( (dir & PKT_FROM_CLIENT) || (daq_flags & DAQ_PKT_FLAG_NOT_FORWARDING) ) { @@ -2875,7 +2172,7 @@ void TcpSession::GetPacketHeaderFoo( DAQ_PktHdr_t* pkth, uint32_t dir ) pkth->address_space_id = address_space_id; } -void TcpSession::SwapPacketHeaderFoo( void ) +void TcpSession::SwapPacketHeaderFoo(void) { if ( egress_index != DAQ_PKTHDR_UNKNOWN ) { @@ -2891,8 +2188,6 @@ void TcpSession::SwapPacketHeaderFoo( void ) } } - - /* * Main entry point for TCP */ @@ -2900,30 +2195,50 @@ int TcpSession::process(Packet* p) { Profile profile(s5TcpPerfStats); - TcpDataBlock tdb; - int status; - DEBUG_WRAP( - char flagbuf[9]; - CreateTCPFlagString(p->ptrs.tcph, flagbuf); - 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); - ); - - if (stream.blocked_session(flow, p) - || (flow->session_state & STREAM_STATE_IGNORE)) + char flagbuf[9]; + CreateTCPFlagString(p->ptrs.tcph, flagbuf); + 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); + ); + + // FIXIT-L can't get here without protocol being set to TCP, is this really needed?? + if (flow->protocol != PktType::TCP) + { + DebugMessage(DEBUG_STREAM_STATE, "Lightweight session not TCP on TCP packet\n"); return ACTION_NOTHING; + } - SetupTcpDataBlock(&tdb, p); + if (stream.blocked_session(flow, p) || (flow->session_state & STREAM_STATE_IGNORE)) + return ACTION_NOTHING; - StreamTcpConfig* config = get_tcp_cfg(flow->ssn_server); + // FIXIT-L expected flow should be checked by flow_con before we get here + // harmonize this with that and the checks above + char ignore = flow_con->expected_flow(flow, p); + if (ignore) + { + server->flush_policy = STREAM_FLPOLICY_IGNORE; + client->flush_policy = STREAM_FLPOLICY_IGNORE; + return ACTION_NOTHING; + } + 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 (config->require_3whs()) + if ( require_3whs ) { if (p->ptrs.tcph->is_syn_only()) { @@ -2940,18 +2255,17 @@ int TcpSession::process(Packet* p) // 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_rst() && !(event_mask & EVENT_NO_3WHS)) + 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 ) { - EventNo3whs(); - event_mask |= EVENT_NO_3WHS; + tel->EventNo3whs(); + no_3whs = true; } - #ifdef REG_TEST - S5TraceTCP(p, flow, &tdb, 1); + S5TraceTCP(p, flow, &tsd, 1); #endif return 0; } @@ -2960,13 +2274,13 @@ int TcpSession::process(Packet* p) { midstream_pickup_allowed: if ( !p->ptrs.tcph->is_syn_ack() - && !p->dsize - && !(StreamPacketHasWscale(p) & TF_WSCALE) ) + && !p->dsize + && !(tsd.has_wscale() & TF_WSCALE) ) { #ifdef REG_TEST - S5TraceTCP(p, flow, &tdb, 1); + S5TraceTCP(p, flow, &tsd, 1); #endif - return 0; + return 0; } if (p->ptrs.tcph->is_syn()) @@ -2974,11 +2288,9 @@ midstream_pickup_allowed: } lws_init = true; } - /* - * Check if the session is expired. - * Should be done before we do something with the packet... - * ie, Insert a packet, or handle state change SYN, FIN, RST, etc. - */ + + // 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. if (stream.expired_session(flow, p)) { /* Session is timed out */ @@ -2986,53 +2298,68 @@ midstream_pickup_allowed: { /* If this one has been reset, delete the TCP * portion, and start a new. */ - TcpSessionCleanup(flow, 1); + cleanup_session(1); } else { DebugMessage(DEBUG_STREAM_STATE, "Stream TCP session timedout!\n"); /* Not reset, simply time'd out. Clean it up */ - TcpSessionCleanup(flow, 1); + cleanup_session(1); } tcpStats.timeouts++; } - status = ProcessTcp(flow, &tdb, config); + // 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(); + + if ( tcp_init || tsd.get_pkt()->dsize) + process_tcp_packet(tsd); + // FIXIT - end - DebugMessage(DEBUG_STREAM_STATE, "Finished Stream TCP cleanly!\n---------------------------------------------------\n"); + tel->log_tcp_events(); - if (!(status & ACTION_LWSSN_CLOSED)) + DebugMessage(DEBUG_STREAM_STATE, + "Finished Stream TCP cleanly!\n---------------------------------------------------\n"); + + if (!(pkt_action_mask & ACTION_LWSSN_CLOSED)) { flow->markup_packet_flags(p); flow->set_expire(p, config->session_timeout); } - if (status & ACTION_DISABLE_INSPECTION) + if (pkt_action_mask & ACTION_DISABLE_INSPECTION) { DisableInspection(p); - DebugFormat(DEBUG_STREAM_STATE, "Stream Ignoring packet from %d. Session marked as ignore\n", - p->packet_flags & PKT_FROM_SERVER ? "server" : "client"); + DebugFormat(DEBUG_STREAM_STATE, + "Stream Ignoring packet from %d. Session marked as ignore\n", + p->packet_flags & PKT_FROM_SERVER ? "server" : "client"); } - S5TraceTCP(p, flow, &tdb, 0); + S5TraceTCP(p, flow, &tsd, 0); return 0; } -void TcpSession::flush() +void TcpSession::flush(void) { - if( ( server.reassembler->is_segment_pending_flush() ) || (client.reassembler->is_segment_pending_flush() ) ) + if ( ( server->reassembler->is_segment_pending_flush() ) || + (client->reassembler->is_segment_pending_flush() ) ) { - server.reassembler->flush_queued_segments( flow, false ); - client.reassembler->flush_queued_segments( flow, false ); + server->reassembler->flush_queued_segments(flow, false); + client->reassembler->flush_queued_segments(flow, false); } } -void TcpSession::start_proxy() +void TcpSession::start_proxy(void) { - client.config->policy = StreamPolicy::OS_PROXY; - server.config->policy = StreamPolicy::OS_PROXY; + config->policy = StreamPolicy::OS_PROXY; } //------------------------------------------------------------------------- @@ -3044,13 +2371,13 @@ void TcpSession::set_memcap(Memcap& mc) tcp_memcap = &mc; } -void TcpSession::sinit() +void TcpSession::sinit(void) { s5_pkt = PacketManager::encode_new(); //AtomSplitter::init(); // FIXIT-L PAF implement } -void TcpSession::sterm() +void TcpSession::sterm(void) { if (s5_pkt) { @@ -3059,8 +2386,3 @@ void TcpSession::sterm() } } -void TcpSession::show(StreamTcpConfig* tcp_config) -{ - StreamPrintTcpConfig(tcp_config); -} - diff --git a/src/stream/tcp/tcp_session.h b/src/stream/tcp/tcp_session.h index e6dbc8dfb..6f29d6d4a 100644 --- a/src/stream/tcp/tcp_session.h +++ b/src/stream/tcp/tcp_session.h @@ -24,114 +24,26 @@ #include "config.h" #endif +#include "perf_monitor/perf_base.h" #include "detection/detect.h" #include "flow/session.h" +#include "stream/libtcp/tcp_state_machine.h" #include "stream_tcp.h" -#include "stream/paf.h" #include "tcp_defs.h" - -/* Only track a maximum number of alerts per session */ -#define MAX_SESSION_ALERTS 8 +#include "tcp_stream_config.h" +#include "tcp_tracker.h" #ifdef DEBUG extern const char* const flush_policy_names[]; #endif -class TcpNormalizer; -class TcpReassembler; - -struct StateMgr -{ - uint8_t state; - uint8_t sub_state; - uint8_t state_queue; - uint8_t expected_flags; - uint32_t transition_seq; - uint32_t stq_get_seq; -}; - -//------------------------------------------------------------------------- -// extra, extra - read all about it! -// -- u2 is the only output plugin that currently supports extra data -// -- extra data may be captured before or after alerts -// -- extra data may be per packet or persistent (saved on session) -// -// -- per packet extra data is logged iff we alert on the packet -// containing the extra data - u2 drives this -// -- an extra data mask is added to Packet to indicate when per packet -// extra data is available -// -// -- persistent extra data must be logged exactly once for each alert -// regardless of capture/alert ordering - s5 purge_alerts drives this -// -- an extra data mask is added to the session trackers to indicate that -// persistent extra data is available -// -// -- event id and second are added to the session alert trackers so that -// the extra data can be correlated with events -// -- event id and second are not available when check_alerted() -// is called; u2 calls StreamUpdateSessionAlertTcp as events are logged -// to set these fields -//------------------------------------------------------------------------- - -struct StreamAlertInfo -{ - /* For storing alerts that have already been seen on the session */ - uint32_t sid; - uint32_t gid; - uint32_t seq; - // if we log extra data, event_* is used to correlate with alert - uint32_t event_id; - uint32_t event_second; -}; - -struct TcpTracker -{ - StateMgr s_mgr; /* state tracking goodies */ - class StreamSplitter* splitter; - FlushPolicy flush_policy; - - // 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 - - StreamTcpConfig* config; - - /* Local for these variables means the local part of the connection. For - * example, if this particular TcpTracker was tracking the client side - * of a connection, the l_unackd value would represent the client side of - * the connection's last unacked sequence number - */ - uint32_t l_unackd; /* local unack'd seq number */ - uint32_t l_nxt_seq; /* local next expected sequence */ - uint32_t l_window; /* local receive window */ - - 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 isn; /* initial sequence number */ - uint32_t ts_last; /* last timestamp (for PAWS) */ - uint32_t ts_last_pkt; /* last packet timestamp we got */ - - TcpNormalizer* normalizer; - TcpReassembler* reassembler; - uint32_t small_seg_count; - - uint16_t wscale; /* window scale setting */ - uint16_t mss; /* max segment size */ - - uint8_t mac_addr[6]; - uint8_t flags; /* bitmap flags (TF_xxx) */ - - uint8_t alert_count; /* number alerts stored (up to MAX_SESSION_ALERTS) */ - StreamAlertInfo alerts[MAX_SESSION_ALERTS]; /* history of alerts */ -}; +class TcpEventLogger; // FIXIT-L session tracking must be split from reassembly // into a separate module a la ip_session.cc and ip_defrag.cc // (of course defrag should also be cleaned up) -class TcpSession: public Session +class TcpSession : public Session { public: TcpSession(Flow*); @@ -139,79 +51,109 @@ public: bool setup(Packet*) override; int process(Packet*) override; - void clear() override; - void cleanup() override; + void clear(void) override; + void cleanup(void) override; void restart(Packet*) override; + void print(void); + + 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; bool check_alerted(Packet*, uint32_t gid, uint32_t sid) override; - int update_alert(Packet*, uint32_t /*gid*/, uint32_t /*sid*/, - uint32_t /*event_id*/, uint32_t /*event_second*/) override; + uint32_t /*event_id*/, uint32_t /*event_second*/) override; void flush_client(Packet*) override; void flush_server(Packet*) override; void flush_talker(Packet*) override; void flush_listener(Packet*) override; - void set_splitter(bool /*c2s*/, StreamSplitter*) override; - StreamSplitter* get_splitter(bool /*c2s*/) override; void set_extra_data(Packet*, uint32_t /*flag*/) override; void clear_extra_data(Packet*, uint32_t /*flag*/) override; bool is_sequenced(uint8_t /*dir*/) override; bool are_packets_missing(uint8_t /*dir*/) override; - uint8_t get_reassembly_direction() override; + uint8_t get_reassembly_direction(void) override; uint8_t missing_in_reassembled(uint8_t /*dir*/) override; - void SetPacketHeaderFoo( const Packet* p ); - void GetPacketHeaderFoo( DAQ_PktHdr_t* pkth, uint32_t dir ); - void SwapPacketHeaderFoo( void ); + void update_perf_base_state(SFBASE* sf_base, char newState); + void SetPacketHeaderFoo(const Packet* p); + void GetPacketHeaderFoo(DAQ_PktHdr_t* pkth, uint32_t dir); + void SwapPacketHeaderFoo(void); // FIXIT - these 2 function names convey no meaning afaict... figure out // why are they called and name appropriately... - void retransmit_process( Packet* p ) + void retransmit_process(Packet* p) { // Data has already been analyzed so don't bother looking at it again. - DisableDetect( p ); + DisableDetect(p); } - void retransmit_handle( Packet* p ) + void retransmit_handle(Packet* p) { - flow->call_handlers(p, false); + flow->call_handlers(p, false); } - void reset(); - void flush(); - void start_proxy(); - -public: - TcpTracker client; - TcpTracker server; - + void reset(void); + void flush(void); + void start_proxy(void); static void set_memcap(class Memcap&); - - static void sinit(); - static void sterm(); - - static void show(StreamTcpConfig*); + 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; int32_t ingress_index; /* Index of the inbound interface. */ - int32_t egress_index; /* Index of the outbound 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; - uint8_t ecn; - bool lws_init; - bool tcp_init; - uint32_t event_mask; + uint32_t pkt_action_mask; + bool require_3whs; + bool no_3whs; + + // FIXIT - deprecate this once tcp state machine is fully implemented + bool new_ssn; 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); + void process_tcp_packet(TcpSegmentDescriptor&); + void FinishServerInit(TcpSegmentDescriptor& tsd); + void swap_trackers(void); + + void NewTcpSessionOnSyn(TcpSegmentDescriptor&); + void NewTcpSessionOnSynAck(TcpSegmentDescriptor&); + void set_os_policy(void); + + void cleanup_session(int freeApplicationData, Packet* p = nullptr); + void clear_session(int freeApplicationData); + int process_dis(Packet*); + void handle_data_on_syn(const tcp::TCPHdr* tcph, TcpSegmentDescriptor& tsd); + + TcpTracker* talker; + TcpTracker* listener; + TcpStateMachine tsm; }; #endif diff --git a/src/stream/tcp/tcp_state_close_wait.cc b/src/stream/tcp/tcp_state_close_wait.cc new file mode 100644 index 000000000..c2fad573a --- /dev/null +++ b/src/stream/tcp/tcp_state_close_wait.cc @@ -0,0 +1,127 @@ +//-------------------------------------------------------------------------- +// Copyright (C) 2015-2015 Cisco and/or its affiliates. All rights reserved. +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License Version 2 as published +// by the Free Software Foundation. You may not use, modify or distribute +// this program under any other version of the GNU General Public License. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +//-------------------------------------------------------------------------- + +// tcp_state_close_wait.cc author davis mcpherson +// Created on: Aug 5, 2015 + +#include +using namespace std; + +#include "tcp_module.h" +#include "tcp_tracker.h" +#include "tcp_session.h" +#include "tcp_normalizer.h" +#include "tcp_state_close_wait.h" + +#ifdef UNIT_TEST +#include "catch/catch.hpp" +#endif + +TcpStateCloseWait::TcpStateCloseWait(TcpStateMachine& tsm, TcpSession& session) : + TcpStateHandler(TcpStreamTracker::TCP_CLOSE_WAIT, tsm), session(session) +{ +} + +TcpStateCloseWait::~TcpStateCloseWait() +{ +} + +bool TcpStateCloseWait::syn_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateCloseWait::syn_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateCloseWait::syn_ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateCloseWait::syn_ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateCloseWait::ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateCloseWait::ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateCloseWait::data_seg_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateCloseWait::data_seg_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateCloseWait::fin_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateCloseWait::fin_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateCloseWait::rst_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateCloseWait::rst_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + diff --git a/src/stream/tcp/tcp_state_close_wait.h b/src/stream/tcp/tcp_state_close_wait.h new file mode 100644 index 000000000..768680bd8 --- /dev/null +++ b/src/stream/tcp/tcp_state_close_wait.h @@ -0,0 +1,53 @@ +//-------------------------------------------------------------------------- +// Copyright (C) 2015-2015 Cisco and/or its affiliates. All rights reserved. +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License Version 2 as published +// by the Free Software Foundation. You may not use, modify or distribute +// this program under any other version of the GNU General Public License. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +//-------------------------------------------------------------------------- + +// tcp_state_close_wait.h author davis mcpherson +// Created on: Aug 5, 2015 + +#ifndef TCP_STATE_CLOSE_WAIT_H +#define TCP_STATE_CLOSE_WAIT_H + +#include "stream/libtcp/tcp_state_handler.h" + +class TcpSession; + +class TcpStateCloseWait : public TcpStateHandler +{ +public: + TcpStateCloseWait(TcpStateMachine&, TcpSession&); + virtual ~TcpStateCloseWait(void); + + bool syn_sent(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool syn_recv(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool syn_ack_sent(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool syn_ack_recv(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool ack_sent(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool ack_recv(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool data_seg_sent(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool data_seg_recv(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool fin_sent(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool fin_recv(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool rst_sent(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool rst_recv(TcpSegmentDescriptor&, TcpStreamTracker&) override; + +private: + TcpSession& session; +}; + +#endif + diff --git a/src/stream/tcp/tcp_state_closed.cc b/src/stream/tcp/tcp_state_closed.cc new file mode 100644 index 000000000..0abd1c2e8 --- /dev/null +++ b/src/stream/tcp/tcp_state_closed.cc @@ -0,0 +1,325 @@ +//-------------------------------------------------------------------------- +// Copyright (C) 2015-2015 Cisco and/or its affiliates. All rights reserved. +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License Version 2 as published +// by the Free Software Foundation. You may not use, modify or distribute +// this program under any other version of the GNU General Public License. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +//-------------------------------------------------------------------------- + +// tcp_state_closed.cc author davis mcpherson +// Created on: Jul 30, 2015 + +#include "stream/stream.h" + +#include "tcp_module.h" +#include "tcp_tracker.h" +#include "tcp_session.h" +#include "tcp_state_closed.h" + +#ifdef UNIT_TEST +#include "catch/catch.hpp" +#include "stream/libtcp/stream_tcp_unit_test.h" +#endif + +TcpStateClosed::TcpStateClosed(TcpStateMachine& tsm, TcpSession& session) : + TcpStateHandler(TcpStreamTracker::TCP_CLOSED, tsm), session(session) +{ +} + +TcpStateClosed::~TcpStateClosed() +{ +} + +bool TcpStateClosed::syn_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, tracker, __func__); +} + +bool TcpStateClosed::syn_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, tracker, __func__); +} + +bool TcpStateClosed::syn_ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, tracker, __func__); +} + +bool TcpStateClosed::syn_ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, tracker, __func__); +} + +bool TcpStateClosed::ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, tracker, __func__); +} + +bool TcpStateClosed::ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, tracker, __func__); +} + +bool TcpStateClosed::data_seg_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, tracker, __func__); +} + +bool TcpStateClosed::data_seg_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, tracker, __func__); +} + +bool TcpStateClosed::fin_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, tracker, __func__); +} + +bool TcpStateClosed::fin_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, tracker, __func__); +} + +bool TcpStateClosed::rst_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, tracker, __func__); +} + +bool TcpStateClosed::rst_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, tracker, __func__); +} + +#ifdef FOO // FIXIT - UNIT_TEST need work!! +#include "tcp_normalizers.h" +#include "tcp_reassemblers.h" + +TEST_CASE("TCP State Closed", "[tcp_closed_state][stream_tcp]") +{ + // initialization code here + Flow* flow = new Flow; + TcpTracker* ctrk = new TcpTracker(true); + TcpTracker* strk = new TcpTracker(false); + TcpEventLogger* tel = new TcpEventLogger; + TcpSession* session = new TcpSession(flow); + TcpStateMachine* tsm = new TcpStateMachine; + TcpStateHandler* tsh = new TcpStateClosed(*tsm, *session); + ctrk->normalizer = TcpNormalizerFactory::create(session, StreamPolicy::OS_LINUX, ctrk, strk); + strk->normalizer = TcpNormalizerFactory::create(session, StreamPolicy::OS_LINUX, strk, ctrk); + ctrk->reassembler = TcpReassemblerFactory::create(session, ctrk, StreamPolicy::OS_LINUX, + false); + strk->reassembler = TcpReassemblerFactory::create(session, strk, StreamPolicy::OS_LINUX, true); + + SECTION("syn_packet") + { + Packet* pkt = get_syn_packet(flow); + REQUIRE( ( pkt != nullptr ) ); + + SECTION("syn_sent") + { + flow->ssn_state.direction = FROM_CLIENT; + TcpSegmentDescriptor tsd(flow, pkt, tel); + ctrk->set_tcp_event(tsd); + ctrk->set_require_3whs(false); + tsh->eval(tsd, *ctrk); + CHECK(TcpStreamTracker::TCP_SYN_SENT_EVENT == ctrk->get_tcp_event() ); + //CHECK( ( ctrk->get_iss() == 9050 ) ); + //CHECK( ( ctrk->get_snd_una() == 9051 ) ); + //CHECK( ( ctrk->get_snd_nxt() == 9050 ) ); + //CHECK( ( ctrk->get_snd_wnd() == 8192 ) ); + } + + SECTION("syn_recv") + { + flow->ssn_state.direction = FROM_SERVER; + TcpSegmentDescriptor tsd(flow, pkt, tel); + ctrk->set_tcp_event(tsd); + tsh->eval(tsd, *ctrk); + CHECK( ( tsh->get_tcp_event() == ctrk->get_tcp_event() ) ); + } + + delete pkt; + } + + SECTION("syn_ack_packet") + { + Packet* pkt = get_syn_ack_packet(flow); + REQUIRE( ( pkt != nullptr ) ); + + SECTION("syn_ack_sent") + { + flow->ssn_state.direction = FROM_CLIENT; + TcpSegmentDescriptor tsd(flow, pkt, tel); + ctrk->set_tcp_event(tsd); + ctrk->set_require_3whs(false); + tsh->eval(tsd, *ctrk); + CHECK( ( tsh->get_tcp_event() == ctrk->get_tcp_event() ) ); + } + + SECTION("syn_ack_recv") + { + flow->ssn_state.direction = FROM_SERVER; + TcpSegmentDescriptor tsd(flow, pkt, tel); + ctrk->set_tcp_event(tsd); + ctrk->set_require_3whs(false); + tsh->eval(tsd, *ctrk); + CHECK( ( tsh->get_tcp_event() == ctrk->get_tcp_event() ) ); + } + + delete pkt; + } + + SECTION("ack_packet") + { + Packet* pkt = get_ack_packet(flow); + REQUIRE( ( pkt != nullptr ) ); + + SECTION("ack_sent") + { + flow->ssn_state.direction = FROM_CLIENT; + TcpSegmentDescriptor tsd(flow, pkt, tel); + ctrk->set_tcp_event(tsd); + ctrk->set_require_3whs(false); + tsh->eval(tsd, *ctrk); + CHECK( ( tsh->get_tcp_event() == ctrk->get_tcp_event() ) ); + } + + SECTION("ack_recv") + { + flow->ssn_state.direction = FROM_SERVER; + TcpSegmentDescriptor tsd(flow, pkt, tel); + ctrk->set_tcp_event(tsd); + ctrk->set_require_3whs(false); + tsh->eval(tsd, *ctrk); + CHECK( ( tsh->get_tcp_event() == ctrk->get_tcp_event() ) ); + } + + delete pkt; + } + + SECTION("data_seg_packet") + { + Packet* pkt = get_data_packet(flow); + REQUIRE( ( pkt != nullptr ) ); + + SECTION("data_seg_sent") + { + flow->ssn_state.direction = FROM_CLIENT; + TcpSegmentDescriptor tsd(flow, pkt, tel); + ctrk->set_tcp_event(tsd); + ctrk->set_require_3whs(false); + tsh->eval(tsd, *ctrk); + CHECK( ( tsh->get_tcp_event() == ctrk->get_tcp_event() ) ); + } + + SECTION("data_seg_recv") + { + flow->ssn_state.direction = FROM_SERVER; + TcpSegmentDescriptor tsd(flow, pkt, tel); + ctrk->set_tcp_event(tsd); + ctrk->set_require_3whs(false); + tsh->eval(tsd, *ctrk); + CHECK( ( tsh->get_tcp_event() == ctrk->get_tcp_event() ) ); + } + + delete pkt; + } + + SECTION("fin_packet") + { + Packet* pkt = get_fin_packet(flow); + REQUIRE( ( pkt != nullptr ) ); + + SECTION("fin_sent") + { + flow->ssn_state.direction = FROM_CLIENT; + TcpSegmentDescriptor tsd(flow, pkt, tel); + ctrk->set_tcp_event(tsd); + ctrk->set_require_3whs(false); + tsh->eval(tsd, *ctrk); + CHECK( ( tsh->get_tcp_event() == ctrk->get_tcp_event() ) ); + } + + SECTION("fin_recv") + { + flow->ssn_state.direction = FROM_SERVER; + TcpSegmentDescriptor tsd(flow, pkt, tel); + ctrk->set_tcp_event(tsd); + ctrk->set_require_3whs(false); + tsh->eval(tsd, *ctrk); + CHECK( ( tsh->get_tcp_event() == ctrk->get_tcp_event() ) ); + } + + delete pkt; + } + + SECTION("rst_packet") + { + Packet* pkt = get_rst_packet(flow); + REQUIRE( ( pkt != nullptr )); + + SECTION("rst_sent") + { + flow->ssn_state.direction = FROM_CLIENT; + TcpSegmentDescriptor tsd(flow, pkt, tel); + ctrk->set_tcp_event(tsd); + ctrk->set_require_3whs(false); + tsh->eval(tsd, *ctrk); + CHECK( ( tsh->get_tcp_event() == ctrk->get_tcp_event() )); + } + + SECTION("rst_recv") + { + flow->ssn_state.direction = FROM_SERVER; + TcpSegmentDescriptor tsd(flow, pkt, tel); + ctrk->set_tcp_event(tsd); + ctrk->set_require_3whs(false); + tsh->eval(tsd, *ctrk); + CHECK( ( tsh->get_tcp_event() == ctrk->get_tcp_event() ) ); + } + + delete pkt; + } + + delete flow; + delete tsh; + delete ctrk; + delete strk; +} + +#endif + diff --git a/src/stream/tcp/tcp_state_closed.h b/src/stream/tcp/tcp_state_closed.h new file mode 100644 index 000000000..701e55298 --- /dev/null +++ b/src/stream/tcp/tcp_state_closed.h @@ -0,0 +1,53 @@ +//-------------------------------------------------------------------------- +// Copyright (C) 2015-2015 Cisco and/or its affiliates. All rights reserved. +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License Version 2 as published +// by the Free Software Foundation. You may not use, modify or distribute +// this program under any other version of the GNU General Public License. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +//-------------------------------------------------------------------------- + +// tcp_state_closed.h author davis mcpherson +// Created on: Jul 30, 2015 + +#ifndef TCP_STATE_CLOSED_H +#define TCP_STATE_CLOSED_H + +#include "stream/libtcp/tcp_state_handler.h" + +class TcpSession; + +class TcpStateClosed : public TcpStateHandler +{ +public: + TcpStateClosed(TcpStateMachine&, TcpSession&); + virtual ~TcpStateClosed(void); + + bool syn_sent(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool syn_recv(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool syn_ack_sent(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool syn_ack_recv(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool ack_sent(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool ack_recv(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool data_seg_sent(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool data_seg_recv(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool fin_sent(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool fin_recv(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool rst_sent(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool rst_recv(TcpSegmentDescriptor&, TcpStreamTracker&) override; + +private: + TcpSession& session; +}; + +#endif + diff --git a/src/stream/tcp/tcp_state_closing.cc b/src/stream/tcp/tcp_state_closing.cc new file mode 100644 index 000000000..c6b82b0d0 --- /dev/null +++ b/src/stream/tcp/tcp_state_closing.cc @@ -0,0 +1,127 @@ +//-------------------------------------------------------------------------- +// Copyright (C) 2015-2015 Cisco and/or its affiliates. All rights reserved. +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License Version 2 as published +// by the Free Software Foundation. You may not use, modify or distribute +// this program under any other version of the GNU General Public License. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +//-------------------------------------------------------------------------- + +// tcp_state_closing.cc author davis mcpherson +// Created on: Aug 5, 2015 + +#include +using namespace std; + +#include "tcp_module.h" +#include "tcp_tracker.h" +#include "tcp_session.h" +#include "tcp_normalizer.h" +#include "tcp_state_closing.h" + +#ifdef UNIT_TEST +#include "catch/catch.hpp" +#endif + +TcpStateClosing::TcpStateClosing(TcpStateMachine& tsm, TcpSession& session) : + TcpStateHandler(TcpStreamTracker::TCP_CLOSING, tsm), session(session) +{ +} + +TcpStateClosing::~TcpStateClosing() +{ +} + +bool TcpStateClosing::syn_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateClosing::syn_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateClosing::syn_ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateClosing::syn_ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateClosing::ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateClosing::ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateClosing::data_seg_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateClosing::data_seg_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateClosing::fin_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateClosing::fin_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateClosing::rst_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateClosing::rst_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + diff --git a/src/stream/tcp/tcp_state_closing.h b/src/stream/tcp/tcp_state_closing.h new file mode 100644 index 000000000..d30276e57 --- /dev/null +++ b/src/stream/tcp/tcp_state_closing.h @@ -0,0 +1,53 @@ +//-------------------------------------------------------------------------- +// Copyright (C) 2015-2015 Cisco and/or its affiliates. All rights reserved. +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License Version 2 as published +// by the Free Software Foundation. You may not use, modify or distribute +// this program under any other version of the GNU General Public License. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +//-------------------------------------------------------------------------- + +// tcp_state_closing.h author davis mcpherson +// Created on: Aug 5, 2015 + +#ifndef TCP_STATE_CLOSING_H +#define TCP_STATE_CLOSING_H + +#include "stream/libtcp/tcp_state_handler.h" + +class TcpSession; + +class TcpStateClosing : public TcpStateHandler +{ +public: + TcpStateClosing(TcpStateMachine&, TcpSession&); + virtual ~TcpStateClosing(void); + + bool syn_sent(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool syn_recv(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool syn_ack_sent(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool syn_ack_recv(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool ack_sent(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool ack_recv(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool data_seg_sent(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool data_seg_recv(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool fin_sent(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool fin_recv(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool rst_sent(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool rst_recv(TcpSegmentDescriptor&, TcpStreamTracker&) override; + +private: + TcpSession& session; +}; + +#endif + diff --git a/src/stream/tcp/tcp_state_established.cc b/src/stream/tcp/tcp_state_established.cc new file mode 100644 index 000000000..a29600e22 --- /dev/null +++ b/src/stream/tcp/tcp_state_established.cc @@ -0,0 +1,120 @@ +//-------------------------------------------------------------------------- +// Copyright (C) 2015-2015 Cisco and/or its affiliates. All rights reserved. +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License Version 2 as published +// by the Free Software Foundation. You may not use, modify or distribute +// this program under any other version of the GNU General Public License. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +//-------------------------------------------------------------------------- + +// tcp_state_established.cc author davis mcpherson +// Created on: Jul 30, 2015 + +#include "tcp_module.h" +#include "tcp_tracker.h" +#include "tcp_session.h" +#include "tcp_normalizer.h" +#include "tcp_state_established.h" + +TcpStateEstablished::TcpStateEstablished(TcpStateMachine& tsm, TcpSession& session) : + TcpStateHandler(TcpStreamTracker::TCP_ESTABLISHED, tsm), session(session) +{ +} + +TcpStateEstablished::~TcpStateEstablished() +{ +} + +bool TcpStateEstablished::syn_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateEstablished::syn_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateEstablished::syn_ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateEstablished::syn_ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateEstablished::ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateEstablished::ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateEstablished::data_seg_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateEstablished::data_seg_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateEstablished::fin_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateEstablished::fin_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateEstablished::rst_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateEstablished::rst_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + diff --git a/src/stream/tcp/tcp_state_established.h b/src/stream/tcp/tcp_state_established.h new file mode 100644 index 000000000..e2aa71746 --- /dev/null +++ b/src/stream/tcp/tcp_state_established.h @@ -0,0 +1,53 @@ +//-------------------------------------------------------------------------- +// Copyright (C) 2015-2015 Cisco and/or its affiliates. All rights reserved. +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License Version 2 as published +// by the Free Software Foundation. You may not use, modify or distribute +// this program under any other version of the GNU General Public License. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +//-------------------------------------------------------------------------- + +// tcp_state_established.h author davis mcpherson +// Created on: Jul 30, 2015 + +#ifndef TCP_STATE_ESTABLISHED_H +#define TCP_STATE_ESTABLISHED_H + +#include "stream/libtcp/tcp_state_handler.h" + +class TcpSession; + +class TcpStateEstablished : public TcpStateHandler +{ +public: + TcpStateEstablished(TcpStateMachine&, TcpSession&); + virtual ~TcpStateEstablished(void); + + bool syn_sent(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool syn_recv(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool syn_ack_sent(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool syn_ack_recv(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool ack_sent(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool ack_recv(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool data_seg_sent(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool data_seg_recv(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool fin_sent(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool fin_recv(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool rst_sent(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool rst_recv(TcpSegmentDescriptor&, TcpStreamTracker&) override; + +private: + TcpSession& session; +}; + +#endif + diff --git a/src/stream/tcp/tcp_state_fin_wait1.cc b/src/stream/tcp/tcp_state_fin_wait1.cc new file mode 100644 index 000000000..9085ebfdb --- /dev/null +++ b/src/stream/tcp/tcp_state_fin_wait1.cc @@ -0,0 +1,127 @@ +//-------------------------------------------------------------------------- +// Copyright (C) 2015-2015 Cisco and/or its affiliates. All rights reserved. +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License Version 2 as published +// by the Free Software Foundation. You may not use, modify or distribute +// this program under any other version of the GNU General Public License. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +//-------------------------------------------------------------------------- + +// tcp_state_fin_wait1.cc author davis mcpherson +// Created on: Aug 5, 2015 + +#include +using namespace std; + +#include "tcp_module.h" +#include "tcp_tracker.h" +#include "tcp_session.h" +#include "tcp_normalizer.h" +#include "tcp_state_fin_wait1.h" + +#ifdef UNIT_TEST +#include "catch/catch.hpp" +#endif + +TcpStateFinWait1::TcpStateFinWait1(TcpStateMachine& tsm, TcpSession& session) : + TcpStateHandler(TcpStreamTracker::TCP_FIN_WAIT1, tsm), session(session) +{ +} + +TcpStateFinWait1::~TcpStateFinWait1() +{ +} + +bool TcpStateFinWait1::syn_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateFinWait1::syn_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateFinWait1::syn_ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateFinWait1::syn_ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateFinWait1::ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateFinWait1::ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateFinWait1::data_seg_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateFinWait1::data_seg_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateFinWait1::fin_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateFinWait1::fin_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateFinWait1::rst_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateFinWait1::rst_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + diff --git a/src/stream/tcp/tcp_state_fin_wait1.h b/src/stream/tcp/tcp_state_fin_wait1.h new file mode 100644 index 000000000..bb6bd59bd --- /dev/null +++ b/src/stream/tcp/tcp_state_fin_wait1.h @@ -0,0 +1,53 @@ +//-------------------------------------------------------------------------- +// Copyright (C) 2015-2015 Cisco and/or its affiliates. All rights reserved. +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License Version 2 as published +// by the Free Software Foundation. You may not use, modify or distribute +// this program under any other version of the GNU General Public License. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +//-------------------------------------------------------------------------- + +// tcp_state_fin_wait1.h author davis mcpherson +// Created on: Aug 5, 2015 + +#ifndef TCP_STATE_FIN_WAIT1_H +#define TCP_STATE_FIN_WAIT1_H + +#include "stream/libtcp/tcp_state_handler.h" + +class TcpSession; + +class TcpStateFinWait1 : public TcpStateHandler +{ +public: + TcpStateFinWait1(TcpStateMachine&, TcpSession&); + virtual ~TcpStateFinWait1(void); + + bool syn_sent(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool syn_recv(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool syn_ack_sent(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool syn_ack_recv(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool ack_sent(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool ack_recv(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool data_seg_sent(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool data_seg_recv(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool fin_sent(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool fin_recv(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool rst_sent(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool rst_recv(TcpSegmentDescriptor&, TcpStreamTracker&) override; + +private: + TcpSession& session; +}; + +#endif + diff --git a/src/stream/tcp/tcp_state_fin_wait2.cc b/src/stream/tcp/tcp_state_fin_wait2.cc new file mode 100644 index 000000000..1afcc5a41 --- /dev/null +++ b/src/stream/tcp/tcp_state_fin_wait2.cc @@ -0,0 +1,127 @@ +//-------------------------------------------------------------------------- +// Copyright (C) 2015-2015 Cisco and/or its affiliates. All rights reserved. +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License Version 2 as published +// by the Free Software Foundation. You may not use, modify or distribute +// this program under any other version of the GNU General Public License. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +//-------------------------------------------------------------------------- + +// tcp_state_fin_wait2.cc author davis mcpherson +// Created on: Aug 5, 2015 + +#include +using namespace std; + +#include "tcp_module.h" +#include "tcp_tracker.h" +#include "tcp_session.h" +#include "tcp_normalizer.h" +#include "tcp_state_fin_wait2.h" + +#ifdef UNIT_TEST +#include "catch/catch.hpp" +#endif + +TcpStateFinWait2::TcpStateFinWait2(TcpStateMachine& tsm, TcpSession& session) : + TcpStateHandler(TcpStreamTracker::TCP_FIN_WAIT2, tsm), session(session) +{ +} + +TcpStateFinWait2::~TcpStateFinWait2() +{ +} + +bool TcpStateFinWait2::syn_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateFinWait2::syn_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateFinWait2::syn_ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateFinWait2::syn_ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateFinWait2::ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateFinWait2::ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateFinWait2::data_seg_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateFinWait2::data_seg_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateFinWait2::fin_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateFinWait2::fin_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateFinWait2::rst_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateFinWait2::rst_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + diff --git a/src/stream/tcp/tcp_state_fin_wait2.h b/src/stream/tcp/tcp_state_fin_wait2.h new file mode 100644 index 000000000..911e14263 --- /dev/null +++ b/src/stream/tcp/tcp_state_fin_wait2.h @@ -0,0 +1,53 @@ +//-------------------------------------------------------------------------- +// Copyright (C) 2015-2015 Cisco and/or its affiliates. All rights reserved. +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License Version 2 as published +// by the Free Software Foundation. You may not use, modify or distribute +// this program under any other version of the GNU General Public License. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +//-------------------------------------------------------------------------- + +// tcp_state_fin_wait2.h author davis mcpherson +// Created on: Aug 5, 2015 + +#ifndef TCP_STATE_FIN_WAIT2_H +#define TCP_STATE_FIN_WAIT2_H + +#include "stream/libtcp/tcp_state_handler.h" + +class TcpSession; + +class TcpStateFinWait2 : public TcpStateHandler +{ +public: + TcpStateFinWait2(TcpStateMachine&, TcpSession&); + virtual ~TcpStateFinWait2(void); + + bool syn_sent(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool syn_recv(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool syn_ack_sent(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool syn_ack_recv(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool ack_sent(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool ack_recv(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool data_seg_sent(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool data_seg_recv(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool fin_sent(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool fin_recv(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool rst_sent(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool rst_recv(TcpSegmentDescriptor&, TcpStreamTracker&) override; + +private: + TcpSession& session; +}; + +#endif + diff --git a/src/stream/tcp/tcp_state_last_ack.cc b/src/stream/tcp/tcp_state_last_ack.cc new file mode 100644 index 000000000..40683a3f0 --- /dev/null +++ b/src/stream/tcp/tcp_state_last_ack.cc @@ -0,0 +1,127 @@ +//-------------------------------------------------------------------------- +// Copyright (C) 2015-2015 Cisco and/or its affiliates. All rights reserved. +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License Version 2 as published +// by the Free Software Foundation. You may not use, modify or distribute +// this program under any other version of the GNU General Public License. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +//-------------------------------------------------------------------------- + +// tcp_state_last_ack.cc author davis mcpherson +// Created on: Aug 5, 2015 + +#include +using namespace std; + +#include "tcp_module.h" +#include "tcp_tracker.h" +#include "tcp_session.h" +#include "tcp_normalizer.h" +#include "tcp_state_last_ack.h" + +#ifdef UNIT_TEST +#include "catch/catch.hpp" +#endif + +TcpStateLastAck::TcpStateLastAck(TcpStateMachine& tsm, TcpSession& session) : + TcpStateHandler(TcpStreamTracker::TCP_LAST_ACK, tsm), session(session) +{ +} + +TcpStateLastAck::~TcpStateLastAck() +{ +} + +bool TcpStateLastAck::syn_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateLastAck::syn_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateLastAck::syn_ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateLastAck::syn_ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateLastAck::ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateLastAck::ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateLastAck::data_seg_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateLastAck::data_seg_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateLastAck::fin_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateLastAck::fin_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateLastAck::rst_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateLastAck::rst_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + diff --git a/src/stream/tcp/tcp_state_last_ack.h b/src/stream/tcp/tcp_state_last_ack.h new file mode 100644 index 000000000..760121005 --- /dev/null +++ b/src/stream/tcp/tcp_state_last_ack.h @@ -0,0 +1,53 @@ +//-------------------------------------------------------------------------- +// Copyright (C) 2015-2015 Cisco and/or its affiliates. All rights reserved. +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License Version 2 as published +// by the Free Software Foundation. You may not use, modify or distribute +// this program under any other version of the GNU General Public License. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +//-------------------------------------------------------------------------- + +// tcp_state_last_ack.h author davis mcpherson +// Created on: Aug 5, 2015 + +#ifndef TCP_STATE_LAST_ACK_H +#define TCP_STATE_LAST_ACK_H + +#include "stream/libtcp/tcp_state_handler.h" + +class TcpSession; + +class TcpStateLastAck : public TcpStateHandler +{ +public: + TcpStateLastAck(TcpStateMachine&, TcpSession&); + virtual ~TcpStateLastAck(void); + + bool syn_sent(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool syn_recv(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool syn_ack_sent(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool syn_ack_recv(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool ack_sent(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool ack_recv(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool data_seg_sent(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool data_seg_recv(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool fin_sent(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool fin_recv(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool rst_sent(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool rst_recv(TcpSegmentDescriptor&, TcpStreamTracker&) override; + +private: + TcpSession& session; +}; + +#endif + diff --git a/src/stream/tcp/tcp_state_listen.cc b/src/stream/tcp/tcp_state_listen.cc new file mode 100644 index 000000000..5d5b72d90 --- /dev/null +++ b/src/stream/tcp/tcp_state_listen.cc @@ -0,0 +1,120 @@ +//-------------------------------------------------------------------------- +// Copyright (C) 2015-2015 Cisco and/or its affiliates. All rights reserved. +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License Version 2 as published +// by the Free Software Foundation. You may not use, modify or distribute +// this program under any other version of the GNU General Public License. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +//-------------------------------------------------------------------------- + +// tcp_state_listen.cc author davis mcpherson +// Created on: Jul 30, 2015 + +#include "tcp_module.h" +#include "tcp_tracker.h" +#include "tcp_session.h" +#include "tcp_normalizer.h" +#include "tcp_state_listen.h" + +TcpStateListen::TcpStateListen(TcpStateMachine& tsm, TcpSession&) : + TcpStateHandler(TcpStreamTracker::TCP_LISTEN, tsm), session(session) +{ +} + +TcpStateListen::~TcpStateListen() +{ +} + +bool TcpStateListen::syn_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateListen::syn_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateListen::syn_ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateListen::syn_ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateListen::ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateListen::ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateListen::data_seg_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateListen::data_seg_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateListen::fin_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateListen::fin_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateListen::rst_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateListen::rst_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + diff --git a/src/stream/tcp/tcp_state_listen.h b/src/stream/tcp/tcp_state_listen.h new file mode 100644 index 000000000..a13c71a87 --- /dev/null +++ b/src/stream/tcp/tcp_state_listen.h @@ -0,0 +1,53 @@ +//-------------------------------------------------------------------------- +// Copyright (C) 2015-2015 Cisco and/or its affiliates. All rights reserved. +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License Version 2 as published +// by the Free Software Foundation. You may not use, modify or distribute +// this program under any other version of the GNU General Public License. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +//-------------------------------------------------------------------------- + +// tcp_listen_state.h author davis mcpherson +// Created on: Jul 30, 2015 + +#ifndef TCP_STATE_LISTEN_H +#define TCP_STATE_LISTEN_H + +#include "stream/libtcp/tcp_state_handler.h" + +class TcpSession; + +class TcpStateListen : public TcpStateHandler +{ +public: + TcpStateListen(TcpStateMachine&, TcpSession&); + virtual ~TcpStateListen(void); + + bool syn_sent(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool syn_recv(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool syn_ack_sent(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool syn_ack_recv(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool ack_sent(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool ack_recv(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool data_seg_sent(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool data_seg_recv(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool fin_sent(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool fin_recv(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool rst_sent(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool rst_recv(TcpSegmentDescriptor&, TcpStreamTracker&) override; + +private: + TcpSession& session; +}; + +#endif + diff --git a/src/stream/tcp/tcp_state_none.cc b/src/stream/tcp/tcp_state_none.cc new file mode 100644 index 000000000..11a6b31bf --- /dev/null +++ b/src/stream/tcp/tcp_state_none.cc @@ -0,0 +1,440 @@ +//-------------------------------------------------------------------------- +// Copyright (C) 2015-2015 Cisco and/or its affiliates. All rights reserved. +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License Version 2 as published +// by the Free Software Foundation. You may not use, modify or distribute +// this program under any other version of the GNU General Public License. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +//-------------------------------------------------------------------------- + +// tcp_state_none.cc author davis mcpherson +// Created on: Jul 30, 2015 + +#include "stream/stream.h" + +#include "tcp_module.h" +#include "tcp_tracker.h" +#include "tcp_session.h" +#include "tcp_normalizer.h" +#include "tcp_state_none.h" + +#ifdef UNIT_TEST +#include "catch/catch.hpp" +#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() +{ +} + +bool TcpStateNone::syn_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + Flow* flow = tsd.get_flow(); + TcpTracker& 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++; + } + + return true; +} + +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() ); + } + + return true; +} + +bool TcpStateNone::syn_ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + Flow* flow = tsd.get_flow(); + TcpTracker& 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()) ) + { + trk.init_on_synack_sent(tsd); + session.init_new_tcp_session(tsd); + tcpStats.sessions_on_syn_ack++; + } + + return true; +} + +bool TcpStateNone::syn_ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + if ( !trk.is_3whs_required() || session.config->midstream_allowed(tsd.get_pkt()) ) + { + trk.init_on_synack_recv(tsd); + } + + trk.normalizer->ecn_tracker(tsd.get_tcph(), trk.is_3whs_required() ); + + return true; +} + +bool TcpStateNone::ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + Flow* flow = tsd.get_flow(); + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + if ( !tsd.get_tcph()->is_rst() && ( flow->session_state & STREAM_STATE_SYN_ACK ) ) + { + /* 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 ); + trk.init_on_3whs_ack_sent(tsd); + session.init_new_tcp_session(tsd); + session.update_perf_base_state(&sfBase, TcpStreamTracker::TCP_ESTABLISHED); + tcpStats.sessions_on_3way++; + } + + return true; +} + +bool TcpStateNone::ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + Flow* flow = tsd.get_flow(); + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + 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(), trk.is_3whs_required() ); + } + + return true; +} + +bool TcpStateNone::data_seg_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& 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()) ) + { + 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); + + if ( flow->session_state & STREAM_STATE_ESTABLISHED ) + session.update_perf_base_state(&sfBase, TcpStreamTracker::TCP_ESTABLISHED); + + tcpStats.sessions_on_data++; + } + + return true; +} + +bool TcpStateNone::data_seg_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + if ( !trk.is_3whs_required() || 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() ); + } + + return true; +} + +bool TcpStateNone::fin_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateNone::fin_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateNone::rst_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateNone::rst_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +#ifdef FOO // FIXIT - UNIT_TEST need work!! +#include "tcp_normalizers.h" +#include "tcp_reassemblers.h" + +TEST_CASE("TCP State None", "[tcp_none_state][stream_tcp]") +{ + // initialization code here + Flow* flow = new Flow; + TcpTracker* ctrk = new TcpTracker(true); + TcpTracker* strk = new TcpTracker(false); + TcpEventLogger* tel = new TcpEventLogger; + TcpSession* session = new TcpSession(flow); + TcpStateMachine* tsm = new TcpStateMachine; + TcpStateHandler* tsh = new TcpStateNone(*tsm, *session); + ctrk->normalizer = TcpNormalizerFactory::create(session, StreamPolicy::OS_LINUX, ctrk, strk); + strk->normalizer = TcpNormalizerFactory::create(session, StreamPolicy::OS_LINUX, strk, ctrk); + ctrk->reassembler = TcpReassemblerFactory::create(session, ctrk, StreamPolicy::OS_LINUX, + false); + strk->reassembler = TcpReassemblerFactory::create(session, strk, StreamPolicy::OS_LINUX, true); + + SECTION("syn_packet") + { + Packet* pkt = get_syn_packet(flow); + REQUIRE( ( pkt != nullptr ) ); + + SECTION("syn_sent") + { + flow->ssn_state.direction = FROM_CLIENT; + TcpSegmentDescriptor tsd(flow, pkt, tel); + ctrk->set_tcp_event(tsd); + ctrk->set_require_3whs(false); + tsh->eval(tsd, *ctrk); + CHECK(TcpStreamTracker::TCP_SYN_SENT_EVENT == ctrk->get_tcp_event() ); + //CHECK( ( ctrk->get_iss() == 9050 ) ); + //CHECK( ( ctrk->get_snd_una() == 9051 ) ); + //CHECK( ( ctrk->get_snd_nxt() == 9050 ) ); + //CHECK( ( ctrk->get_snd_wnd() == 8192 ) ); + } + + SECTION("syn_recv") + { + flow->ssn_state.direction = FROM_SERVER; + TcpSegmentDescriptor tsd(flow, pkt, tel); + ctrk->set_tcp_event(tsd); + tsh->eval(tsd, *ctrk); + CHECK( ( tsh->get_tcp_event() == ctrk->get_tcp_event() ) ); + } + + delete pkt; + } + + SECTION("syn_ack_packet") + { + Packet* pkt = get_syn_ack_packet(flow); + REQUIRE( ( pkt != nullptr ) ); + + SECTION("syn_ack_sent") + { + flow->ssn_state.direction = FROM_CLIENT; + TcpSegmentDescriptor tsd(flow, pkt, tel); + ctrk->set_tcp_event(tsd); + ctrk->set_require_3whs(false); + tsh->eval(tsd, *ctrk); + CHECK( ( tsh->get_tcp_event() == ctrk->get_tcp_event() ) ); + } + + SECTION("syn_ack_recv") + { + flow->ssn_state.direction = FROM_SERVER; + TcpSegmentDescriptor tsd(flow, pkt, tel); + ctrk->set_tcp_event(tsd); + ctrk->set_require_3whs(false); + tsh->eval(tsd, *ctrk); + CHECK( ( tsh->get_tcp_event() == ctrk->get_tcp_event() ) ); + } + + delete pkt; + } + + SECTION("ack_packet") + { + Packet* pkt = get_ack_packet(flow); + REQUIRE( ( pkt != nullptr ) ); + + SECTION("ack_sent") + { + flow->ssn_state.direction = FROM_CLIENT; + TcpSegmentDescriptor tsd(flow, pkt, tel); + ctrk->set_tcp_event(tsd); + ctrk->set_require_3whs(false); + tsh->eval(tsd, *ctrk); + CHECK( ( tsh->get_tcp_event() == ctrk->get_tcp_event() ) ); + } + + SECTION("ack_recv") + { + flow->ssn_state.direction = FROM_SERVER; + TcpSegmentDescriptor tsd(flow, pkt, tel); + ctrk->set_tcp_event(tsd); + ctrk->set_require_3whs(false); + tsh->eval(tsd, *ctrk); + CHECK( ( tsh->get_tcp_event() == ctrk->get_tcp_event() ) ); + } + + delete pkt; + } + + SECTION("data_seg_packet") + { + Packet* pkt = get_data_packet(flow); + REQUIRE( ( pkt != nullptr ) ); + + SECTION("data_seg_sent") + { + flow->ssn_state.direction = FROM_CLIENT; + TcpSegmentDescriptor tsd(flow, pkt, tel); + ctrk->set_tcp_event(tsd); + ctrk->set_require_3whs(false); + tsh->eval(tsd, *ctrk); + CHECK( ( tsh->get_tcp_event() == ctrk->get_tcp_event() ) ); + } + + SECTION("data_seg_recv") + { + flow->ssn_state.direction = FROM_SERVER; + TcpSegmentDescriptor tsd(flow, pkt, tel); + ctrk->set_tcp_event(tsd); + ctrk->set_require_3whs(false); + tsh->eval(tsd, *ctrk); + CHECK( ( tsh->get_tcp_event() == ctrk->get_tcp_event() ) ); + } + + delete pkt; + } + + SECTION("fin_packet") + { + Packet* pkt = get_fin_packet(flow); + REQUIRE( ( pkt != nullptr ) ); + + SECTION("fin_sent") + { + flow->ssn_state.direction = FROM_CLIENT; + TcpSegmentDescriptor tsd(flow, pkt, tel); + ctrk->set_tcp_event(tsd); + ctrk->set_require_3whs(false); + tsh->eval(tsd, *ctrk); + CHECK( ( tsh->get_tcp_event() == ctrk->get_tcp_event() ) ); + } + + SECTION("fin_recv") + { + flow->ssn_state.direction = FROM_SERVER; + TcpSegmentDescriptor tsd(flow, pkt, tel); + ctrk->set_tcp_event(tsd); + ctrk->set_require_3whs(false); + tsh->eval(tsd, *ctrk); + CHECK( ( tsh->get_tcp_event() == ctrk->get_tcp_event() ) ); + } + + delete pkt; + } + + SECTION("rst_packet") + { + Packet* pkt = get_rst_packet(flow); + REQUIRE( ( pkt != nullptr )); + + SECTION("rst_sent") + { + flow->ssn_state.direction = FROM_CLIENT; + TcpSegmentDescriptor tsd(flow, pkt, tel); + ctrk->set_tcp_event(tsd); + ctrk->set_require_3whs(false); + tsh->eval(tsd, *ctrk); + CHECK( ( tsh->get_tcp_event() == ctrk->get_tcp_event() )); + } + + SECTION("rst_recv") + { + flow->ssn_state.direction = FROM_SERVER; + TcpSegmentDescriptor tsd(flow, pkt, tel); + ctrk->set_tcp_event(tsd); + ctrk->set_require_3whs(false); + tsh->eval(tsd, *ctrk); + CHECK( ( tsh->get_tcp_event() == ctrk->get_tcp_event() ) ); + } + + delete pkt; + } + + delete flow; + delete tsh; + delete ctrk; + delete strk; +} + +#endif + diff --git a/src/stream/tcp/tcp_state_none.h b/src/stream/tcp/tcp_state_none.h new file mode 100644 index 000000000..293e6c1d9 --- /dev/null +++ b/src/stream/tcp/tcp_state_none.h @@ -0,0 +1,53 @@ +//-------------------------------------------------------------------------- +// Copyright (C) 2015-2015 Cisco and/or its affiliates. All rights reserved. +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License Version 2 as published +// by the Free Software Foundation. You may not use, modify or distribute +// this program under any other version of the GNU General Public License. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +//-------------------------------------------------------------------------- + +// tcp_state_none.h author davis mcpherson +// Created on: Jul 30, 2015 + +#ifndef TCP_STATE_NONE_H +#define TCP_STATE_NONE_H + +#include "stream/libtcp/tcp_state_handler.h" + +class TcpSession; + +class TcpStateNone : public TcpStateHandler +{ +public: + TcpStateNone(TcpStateMachine&, TcpSession&); + virtual ~TcpStateNone(void); + + bool syn_sent(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool syn_recv(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool syn_ack_sent(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool syn_ack_recv(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool ack_sent(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool ack_recv(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool data_seg_sent(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool data_seg_recv(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool fin_sent(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool fin_recv(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool rst_sent(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool rst_recv(TcpSegmentDescriptor&, TcpStreamTracker&) override; + +private: + TcpSession& session; +}; + +#endif + diff --git a/src/stream/tcp/tcp_state_syn_recv.cc b/src/stream/tcp/tcp_state_syn_recv.cc new file mode 100644 index 000000000..4ec6ecff2 --- /dev/null +++ b/src/stream/tcp/tcp_state_syn_recv.cc @@ -0,0 +1,123 @@ +//-------------------------------------------------------------------------- +// Copyright (C) 2015-2015 Cisco and/or its affiliates. All rights reserved. +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License Version 2 as published +// by the Free Software Foundation. You may not use, modify or distribute +// this program under any other version of the GNU General Public License. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +//-------------------------------------------------------------------------- + +// tcp_state_syn_recv.cc author davis mcpherson +// Created on: Aug 5, 2015 + +#include +using namespace std; + +#include "tcp_module.h" +#include "tcp_tracker.h" +#include "tcp_session.h" +#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() +{ +} + +bool TcpStateSynRecv::syn_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateSynRecv::syn_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateSynRecv::syn_ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateSynRecv::syn_ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateSynRecv::ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateSynRecv::ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateSynRecv::data_seg_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateSynRecv::data_seg_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateSynRecv::fin_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateSynRecv::fin_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateSynRecv::rst_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateSynRecv::rst_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + diff --git a/src/stream/tcp/tcp_syn_recv_state.h b/src/stream/tcp/tcp_state_syn_recv.h similarity index 51% rename from src/stream/tcp/tcp_syn_recv_state.h rename to src/stream/tcp/tcp_state_syn_recv.h index 55fe6a45d..70b380307 100644 --- a/src/stream/tcp/tcp_syn_recv_state.h +++ b/src/stream/tcp/tcp_state_syn_recv.h @@ -19,29 +19,35 @@ // tcp_syn_recv_state.h author davis mcpherson // Created on: Aug 5, 2015 -#ifndef TCP_SYN_RECV_STATE_H -#define TCP_SYN_RECV_STATE_H +#ifndef TCP_STATE_SYN_RECV_H +#define TCP_STATE_SYN_RECV_H #include "stream/libtcp/tcp_state_handler.h" -class TcpSynRecvState: public TcpStateHandler +class TcpSession; + +class TcpStateSynRecv : public TcpStateHandler { public: - TcpSynRecvState(); - virtual ~TcpSynRecvState(); - - void syn_sent(TcpSegmentDescriptor&, TcpStreamTracker&); - void syn_recv(TcpSegmentDescriptor&, TcpStreamTracker&); - void syn_ack_sent(TcpSegmentDescriptor&, TcpStreamTracker&); - void syn_ack_recv(TcpSegmentDescriptor&, TcpStreamTracker&); - void ack_sent(TcpSegmentDescriptor&, TcpStreamTracker&); - void ack_recv(TcpSegmentDescriptor&, TcpStreamTracker&); - void data_seg_sent(TcpSegmentDescriptor&, TcpStreamTracker&); - void data_seg_recv(TcpSegmentDescriptor&, TcpStreamTracker&); - void fin_sent(TcpSegmentDescriptor&, TcpStreamTracker&); - void fin_recv(TcpSegmentDescriptor&, TcpStreamTracker&); - void rst_sent(TcpSegmentDescriptor&, TcpStreamTracker&); - void rst_recv(TcpSegmentDescriptor&, TcpStreamTracker&); + TcpStateSynRecv(TcpStateMachine&, TcpSession&); + virtual ~TcpStateSynRecv(void); + + bool syn_sent(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool syn_recv(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool syn_ack_sent(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool syn_ack_recv(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool ack_sent(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool ack_recv(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool data_seg_sent(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool data_seg_recv(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool fin_sent(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool fin_recv(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool rst_sent(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool rst_recv(TcpSegmentDescriptor&, TcpStreamTracker&) override; + +private: + TcpSession& session; }; #endif + diff --git a/src/stream/tcp/tcp_state_syn_sent.cc b/src/stream/tcp/tcp_state_syn_sent.cc new file mode 100644 index 000000000..b0841e1b2 --- /dev/null +++ b/src/stream/tcp/tcp_state_syn_sent.cc @@ -0,0 +1,127 @@ +//-------------------------------------------------------------------------- +// Copyright (C) 2015-2015 Cisco and/or its affiliates. All rights reserved. +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License Version 2 as published +// by the Free Software Foundation. You may not use, modify or distribute +// this program under any other version of the GNU General Public License. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +//-------------------------------------------------------------------------- + +// tcp_state_syn_sent.cc author davis mcpherson +// Created on: Aug 5, 2015 + +#include +using namespace std; + +#include "tcp_module.h" +#include "tcp_tracker.h" +#include "tcp_session.h" +#include "tcp_normalizer.h" +#include "tcp_state_syn_sent.h" + +#ifdef UNIT_TEST +#include "catch/catch.hpp" +#endif + +TcpStateSynSent::TcpStateSynSent(TcpStateMachine& tsm, TcpSession& session) : + TcpStateHandler(TcpStreamTracker::TCP_SYN_SENT, tsm), session(session) +{ +} + +TcpStateSynSent::~TcpStateSynSent() +{ +} + +bool TcpStateSynSent::syn_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateSynSent::syn_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateSynSent::syn_ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateSynSent::syn_ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateSynSent::ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateSynSent::ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateSynSent::data_seg_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateSynSent::data_seg_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateSynSent::fin_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateSynSent::fin_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateSynSent::rst_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateSynSent::rst_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + diff --git a/src/stream/tcp/tcp_syn_sent_state.h b/src/stream/tcp/tcp_state_syn_sent.h similarity index 51% rename from src/stream/tcp/tcp_syn_sent_state.h rename to src/stream/tcp/tcp_state_syn_sent.h index 8687234ef..a76be1ecb 100644 --- a/src/stream/tcp/tcp_syn_sent_state.h +++ b/src/stream/tcp/tcp_state_syn_sent.h @@ -19,29 +19,35 @@ // tcp_syn_sent_state.h author davis mcpherson // Created on: Aug 5, 2015 -#ifndef TCP_SYN_SENT_STATE_H -#define TCP_SYN_SENT_STATE_H +#ifndef TCP_STATE_SYN_SENT_H +#define TCP_STATE_SYN_SENT_H #include "stream/libtcp/tcp_state_handler.h" -class TcpSynSentState: public TcpStateHandler +class TcpSession; + +class TcpStateSynSent : public TcpStateHandler { public: - TcpSynSentState(); - virtual ~TcpSynSentState(); - - void syn_sent(TcpSegmentDescriptor&, TcpStreamTracker&); - void syn_recv(TcpSegmentDescriptor&, TcpStreamTracker&); - void syn_ack_sent(TcpSegmentDescriptor&, TcpStreamTracker&); - void syn_ack_recv(TcpSegmentDescriptor&, TcpStreamTracker&); - void ack_sent(TcpSegmentDescriptor&, TcpStreamTracker&); - void ack_recv(TcpSegmentDescriptor&, TcpStreamTracker&); - void data_seg_sent(TcpSegmentDescriptor&, TcpStreamTracker&); - void data_seg_recv(TcpSegmentDescriptor&, TcpStreamTracker&); - void fin_sent(TcpSegmentDescriptor&, TcpStreamTracker&); - void fin_recv(TcpSegmentDescriptor&, TcpStreamTracker&); - void rst_sent(TcpSegmentDescriptor&, TcpStreamTracker&); - void rst_recv(TcpSegmentDescriptor&, TcpStreamTracker&); + TcpStateSynSent(TcpStateMachine&, TcpSession&); + virtual ~TcpStateSynSent(void); + + bool syn_sent(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool syn_recv(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool syn_ack_sent(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool syn_ack_recv(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool ack_sent(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool ack_recv(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool data_seg_sent(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool data_seg_recv(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool fin_sent(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool fin_recv(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool rst_sent(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool rst_recv(TcpSegmentDescriptor&, TcpStreamTracker&) override; + +private: + TcpSession& session; }; #endif + diff --git a/src/stream/tcp/tcp_state_time_wait.cc b/src/stream/tcp/tcp_state_time_wait.cc new file mode 100644 index 000000000..5de9ead3b --- /dev/null +++ b/src/stream/tcp/tcp_state_time_wait.cc @@ -0,0 +1,127 @@ +//-------------------------------------------------------------------------- +// Copyright (C) 2015-2015 Cisco and/or its affiliates. All rights reserved. +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License Version 2 as published +// by the Free Software Foundation. You may not use, modify or distribute +// this program under any other version of the GNU General Public License. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +//-------------------------------------------------------------------------- + +// tcp_state_time_wait.cc author davis mcpherson +// Created on: Aug 5, 2015 + +#include +using namespace std; + +#include "tcp_module.h" +#include "tcp_tracker.h" +#include "tcp_session.h" +#include "tcp_normalizer.h" +#include "tcp_state_time_wait.h" + +#ifdef UNIT_TEST +#include "catch/catch.hpp" +#endif + +TcpStateTimeWait::TcpStateTimeWait(TcpStateMachine& tsm, TcpSession& session) : + TcpStateHandler(TcpStreamTracker::TCP_TIME_WAIT, tsm), session(session) +{ +} + +TcpStateTimeWait::~TcpStateTimeWait() +{ +} + +bool TcpStateTimeWait::syn_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateTimeWait::syn_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateTimeWait::syn_ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateTimeWait::syn_ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateTimeWait::ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateTimeWait::ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateTimeWait::data_seg_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateTimeWait::data_seg_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateTimeWait::fin_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateTimeWait::fin_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateTimeWait::rst_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + +bool TcpStateTimeWait::rst_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) +{ + TcpTracker& trk = static_cast< TcpTracker& >( tracker ); + + return default_state_action(tsd, trk, __func__); +} + diff --git a/src/stream/tcp/tcp_state_time_wait.h b/src/stream/tcp/tcp_state_time_wait.h new file mode 100644 index 000000000..bf02fbb2f --- /dev/null +++ b/src/stream/tcp/tcp_state_time_wait.h @@ -0,0 +1,53 @@ +//-------------------------------------------------------------------------- +// Copyright (C) 2015-2015 Cisco and/or its affiliates. All rights reserved. +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License Version 2 as published +// by the Free Software Foundation. You may not use, modify or distribute +// this program under any other version of the GNU General Public License. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +//-------------------------------------------------------------------------- + +// tcp_state_time_wait.h author davis mcpherson +// Created on: Aug 5, 2015 + +#ifndef TCP_STATE_TIME_WAIT_H +#define TCP_STATE_TIME_WAIT_H + +#include "stream/libtcp/tcp_state_handler.h" + +class TcpSession; + +class TcpStateTimeWait : public TcpStateHandler +{ +public: + TcpStateTimeWait(TcpStateMachine&, TcpSession&); + virtual ~TcpStateTimeWait(void); + + bool syn_sent(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool syn_recv(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool syn_ack_sent(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool syn_ack_recv(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool ack_sent(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool ack_recv(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool data_seg_sent(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool data_seg_recv(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool fin_sent(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool fin_recv(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool rst_sent(TcpSegmentDescriptor&, TcpStreamTracker&) override; + bool rst_recv(TcpSegmentDescriptor&, TcpStreamTracker&) override; + +private: + TcpSession& session; +}; + +#endif + diff --git a/src/stream/tcp/tcp_stream_config.cc b/src/stream/tcp/tcp_stream_config.cc new file mode 100644 index 000000000..0ef5392a2 --- /dev/null +++ b/src/stream/tcp/tcp_stream_config.cc @@ -0,0 +1,119 @@ +//-------------------------------------------------------------------------- +// Copyright (C) 2015-2015 Cisco and/or its affiliates. All rights reserved. +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License Version 2 as published +// by the Free Software Foundation. You may not use, modify or distribute +// this program under any other version of the GNU General Public License. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +//-------------------------------------------------------------------------- + +// tcp_stream_config.cc author davis mcpherson +// 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" }; + +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) +{ + TcpStreamConfig::show_config(this); +} + +void TcpStreamConfig::show_config(TcpStreamConfig* config) +{ + LogMessage("Stream TCP Policy config:\n"); + LogMessage(" Reassembly Policy: %s\n", + reassembly_policy_names[ static_cast( config->reassembly_policy ) ]); + LogMessage(" Timeout: %d seconds\n", config->session_timeout); + + if ( config->max_window != 0 ) + LogMessage(" Max TCP Window: %u\n", config->max_window); + + if ( config->overlap_limit ) + LogMessage(" Limit on TCP Overlaps: %d\n", config->overlap_limit); + + if ( config->max_queued_bytes != 0 ) + LogMessage(" Maximum number of bytes to queue per session: %d\n", + config->max_queued_bytes); + + if ( config->max_queued_segs != 0 ) + LogMessage(" Maximum number of segs to queue per session: %d\n", + config->max_queued_segs); + + if ( config->flags ) + { + LogMessage(" Options:\n"); + if (config->flags & STREAM_CONFIG_IGNORE_ANY) + LogMessage(" Ignore Any -> Any Rules: YES\n"); + + if (config->flags & STREAM_CONFIG_NO_ASYNC_REASSEMBLY) + LogMessage(" Don't queue packets on one-sided sessions: YES\n"); + } + + if ( config->hs_timeout < 0 ) + LogMessage(" Require 3-Way Handshake: NO\n"); + else + LogMessage(" Require 3-Way Handshake: after %d seconds\n", config->hs_timeout); +} + +//------------------------------------------------------------------------- +// attribute table foo +//------------------------------------------------------------------------- + +int TcpStreamConfig::verify_config(SnortConfig*) +{ + return 0; +} + diff --git a/src/stream/tcp/tcp_listen_state.h b/src/stream/tcp/tcp_stream_config.h similarity index 56% rename from src/stream/tcp/tcp_listen_state.h rename to src/stream/tcp/tcp_stream_config.h index c0a173e52..5bb466118 100644 --- a/src/stream/tcp/tcp_listen_state.h +++ b/src/stream/tcp/tcp_stream_config.h @@ -16,20 +16,45 @@ // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. //-------------------------------------------------------------------------- -// tcp_listen_state.h author davis mcpherson -// Created on: Jul 30, 2015 +// tcp_stream_config.h author davis mcpherson +// Created on: Oct 22, 2015 -#ifndef TCP_LISTEN_STATE_H -#define TCP_LISTEN_STATE_H +#ifndef TCP_STREAM_CONFIG_H +#define TCP_STREAM_CONFIG_H -#include "stream/libtcp/tcp_state_handler.h" +#include "tcp_defs.h" -class TcpListenState: public TcpStateHandler +class TcpStreamConfig { public: - TcpListenState(); - virtual ~TcpListenState(); + TcpStreamConfig(void); + bool require_3whs(void); + bool midstream_allowed(Packet*); + int verify_config(SnortConfig*); + void show_config(void); + static void show_config(TcpStreamConfig*); + + StreamPolicy policy; + ReassemblyPolicy reassembly_policy; + + uint16_t flags; + uint16_t flush_factor; + + uint32_t session_timeout; + uint32_t max_window; + uint32_t overlap_limit; + + uint32_t max_queued_bytes; + uint32_t max_queued_segs; + + uint32_t max_consec_small_segs; + uint32_t max_consec_small_seg_size; + + int hs_timeout; + int footprint; + unsigned paf_max; }; #endif + diff --git a/src/stream/tcp/tcp_syn_recv_state.cc b/src/stream/tcp/tcp_syn_recv_state.cc deleted file mode 100644 index 3002b8373..000000000 --- a/src/stream/tcp/tcp_syn_recv_state.cc +++ /dev/null @@ -1,97 +0,0 @@ -//-------------------------------------------------------------------------- -// Copyright (C) 2015-2015 Cisco and/or its affiliates. All rights reserved. -// -// This program is free software; you can redistribute it and/or modify it -// under the terms of the GNU General Public License Version 2 as published -// by the Free Software Foundation. You may not use, modify or distribute -// this program under any other version of the GNU General Public License. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// General Public License for more details. -// -// You should have received a copy of the GNU General Public License along -// with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -//-------------------------------------------------------------------------- - -// tcp_syn_sent_state.cc author davis mcpherson -// Created on: Aug 5, 2015 - -#include -using namespace std; - -#include "tcp_syn_recv_state.h" - -TcpSynRecvState::TcpSynRecvState() -{ - // TODO Auto-generated constructor stub - -} - -TcpSynRecvState::~TcpSynRecvState() -{ - // TODO Auto-generated destructor stub -} - -void TcpSynRecvState::syn_sent( TcpSegmentDescriptor &tcp_seg, TcpStreamTracker &tracker ) -{ - default_state_action( &tcp_seg, &tracker, __func__ ); -} - -void TcpSynRecvState::syn_recv(TcpSegmentDescriptor &tcp_seg, TcpStreamTracker &tracker) -{ - default_state_action( &tcp_seg, &tracker, __func__ ); -} - -void TcpSynRecvState::syn_ack_sent(TcpSegmentDescriptor &tcp_seg, TcpStreamTracker &tracker) -{ - default_state_action( &tcp_seg, &tracker, __func__ ); -} - -void TcpSynRecvState::syn_ack_recv(TcpSegmentDescriptor &tcp_seg, TcpStreamTracker &tracker) -{ - default_state_action( &tcp_seg, &tracker, __func__ ); -} - -void TcpSynRecvState::ack_sent(TcpSegmentDescriptor &tcp_seg, TcpStreamTracker &tracker) -{ - default_state_action( &tcp_seg, &tracker, __func__ ); -} - -void TcpSynRecvState::ack_recv(TcpSegmentDescriptor &tcp_seg, TcpStreamTracker &tracker) -{ - default_state_action( &tcp_seg, &tracker, __func__ ); -} - -void TcpSynRecvState::data_seg_sent(TcpSegmentDescriptor &tcp_seg, TcpStreamTracker &tracker) -{ - default_state_action( &tcp_seg, &tracker, __func__ ); -} - -void TcpSynRecvState::data_seg_recv(TcpSegmentDescriptor &tcp_seg, TcpStreamTracker &tracker) -{ - default_state_action( &tcp_seg, &tracker, __func__ ); -} - -void TcpSynRecvState::fin_sent(TcpSegmentDescriptor &tcp_seg, TcpStreamTracker &tracker) -{ - default_state_action( &tcp_seg, &tracker, __func__ ); -} - -void TcpSynRecvState::fin_recv(TcpSegmentDescriptor &tcp_seg, TcpStreamTracker &tracker) -{ - default_state_action( &tcp_seg, &tracker, __func__ ); -} - -void TcpSynRecvState::rst_sent(TcpSegmentDescriptor &tcp_seg, TcpStreamTracker &tracker) -{ - default_state_action( &tcp_seg, &tracker, __func__ ); -} - -void TcpSynRecvState::rst_recv(TcpSegmentDescriptor &tcp_seg, TcpStreamTracker &tracker) -{ - default_state_action( &tcp_seg, &tracker, __func__ ); -} - diff --git a/src/stream/tcp/tcp_syn_sent_state.cc b/src/stream/tcp/tcp_syn_sent_state.cc deleted file mode 100644 index 73de21ae9..000000000 --- a/src/stream/tcp/tcp_syn_sent_state.cc +++ /dev/null @@ -1,104 +0,0 @@ -//-------------------------------------------------------------------------- -// Copyright (C) 2015-2015 Cisco and/or its affiliates. All rights reserved. -// -// This program is free software; you can redistribute it and/or modify it -// under the terms of the GNU General Public License Version 2 as published -// by the Free Software Foundation. You may not use, modify or distribute -// this program under any other version of the GNU General Public License. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// General Public License for more details. -// -// You should have received a copy of the GNU General Public License along -// with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -//-------------------------------------------------------------------------- - -// tcp_syn_sent_state.cc author davis mcpherson -// Created on: Aug 5, 2015 - -#include -using namespace std; - -#include "tcp_syn_sent_state.h" - -#ifdef UNIT_TEST -#include "catch/catch.hpp" -#endif - -TcpSynSentState::TcpSynSentState() -{ - // TODO Auto-generated constructor stub - -} - -TcpSynSentState::~TcpSynSentState() -{ - // TODO Auto-generated destructor stub -} - -void TcpSynSentState::syn_sent( TcpSegmentDescriptor &tcp_seg, TcpStreamTracker &tracker ) -{ - default_state_action( &tcp_seg, &tracker, __func__ ); -} - -void TcpSynSentState::syn_recv(TcpSegmentDescriptor &tcp_seg, TcpStreamTracker &tracker) -{ - default_state_action( &tcp_seg, &tracker, __func__ ); -} - -void TcpSynSentState::syn_ack_sent(TcpSegmentDescriptor &tcp_seg, TcpStreamTracker &tracker) -{ - default_state_action( &tcp_seg, &tracker, __func__ ); -} - -void TcpSynSentState::syn_ack_recv(TcpSegmentDescriptor &tcp_seg, TcpStreamTracker &tracker) -{ - default_state_action( &tcp_seg, &tracker, __func__ ); -} - -void TcpSynSentState::ack_sent(TcpSegmentDescriptor &tcp_seg, TcpStreamTracker &tracker) -{ - default_state_action( &tcp_seg, &tracker, __func__ ); -} - -void TcpSynSentState::ack_recv(TcpSegmentDescriptor &tcp_seg, TcpStreamTracker &tracker) -{ - default_state_action( &tcp_seg, &tracker, __func__ ); -} - -void TcpSynSentState::data_seg_sent(TcpSegmentDescriptor &tcp_seg, TcpStreamTracker &tracker) -{ - default_state_action( &tcp_seg, &tracker, __func__ ); -} - -void TcpSynSentState::data_seg_recv(TcpSegmentDescriptor &tcp_seg, TcpStreamTracker &tracker) -{ - default_state_action( &tcp_seg, &tracker, __func__ ); -} - -void TcpSynSentState::fin_sent(TcpSegmentDescriptor &tcp_seg, TcpStreamTracker &tracker) -{ - default_state_action( &tcp_seg, &tracker, __func__ ); -} - -void TcpSynSentState::fin_recv(TcpSegmentDescriptor &tcp_seg, TcpStreamTracker &tracker) -{ - default_state_action( &tcp_seg, &tracker, __func__ ); -} - -void TcpSynSentState::rst_sent(TcpSegmentDescriptor &tcp_seg, TcpStreamTracker &tracker) -{ - default_state_action( &tcp_seg, &tracker, __func__ ); -} - -void TcpSynSentState::rst_recv(TcpSegmentDescriptor &tcp_seg, TcpStreamTracker &tracker) -{ - default_state_action( &tcp_seg, &tracker, __func__ ); -} - -#ifdef UNIT_TEST - -#endif diff --git a/src/stream/tcp/tcp_tracker.cc b/src/stream/tcp/tcp_tracker.cc new file mode 100644 index 000000000..4c7fb1f38 --- /dev/null +++ b/src/stream/tcp/tcp_tracker.cc @@ -0,0 +1,317 @@ +//-------------------------------------------------------------------------- +// Copyright (C) 2015-2015 Cisco and/or its affiliates. All rights reserved. +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License Version 2 as published +// by the Free Software Foundation. You may not use, modify or distribute +// this program under any other version of the GNU General Public License. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +//-------------------------------------------------------------------------- + +// tcp_tracker.cc author davis mcpherson +// Created on: Dec 1, 2015 + +#include "profiler/profiler_defs.h" +#include "tcp_module.h" +#include "tcp_normalizers.h" +#include "tcp_reassemblers.h" +#include "tcp_tracker.h" + +TcpTracker::TcpTracker(bool client) : + TcpStreamTracker(client), splitter(nullptr), normalizer(nullptr), reassembler(nullptr) +{ + tcp_event = TCP_MAX_EVENTS; + init_tracker( ); +} + +TcpTracker::~TcpTracker(void) +{ + delete splitter; + delete normalizer; + delete reassembler; +} + +void TcpTracker::init_tracker(void) +{ + memset(&s_mgr, 0, sizeof( StateMgr ) ); + s_mgr.state_queue = TcpStreamTracker::TCP_STATE_NONE; + + tcp_state = TcpStreamTracker::TCP_STATE_NONE; + flush_policy = STREAM_FLPOLICY_IGNORE; + 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; + alert_count = 0; + memset(alerts, 0, sizeof( alerts ) ); + + delete splitter; + splitter = nullptr; + delete normalizer; + normalizer = nullptr; + delete reassembler; + reassembler = nullptr; +} + +//------------------------------------------------------------------------- +// flush policy stuff +//------------------------------------------------------------------------- + +void TcpTracker::init_flush_policy(void) +{ + if ( splitter == nullptr ) + flush_policy = STREAM_FLPOLICY_IGNORE; + else if ( !normalizer->is_tcp_ips_enabled() ) + flush_policy = STREAM_FLPOLICY_ON_ACK; + else + flush_policy = STREAM_FLPOLICY_ON_DATA; +} + +void TcpTracker::set_splitter(StreamSplitter* ss) +{ + if ( splitter ) + delete splitter; + + splitter = ss; + + if ( ss ) + paf_setup(&paf_state); + else + flush_policy = STREAM_FLPOLICY_IGNORE; +} + +void TcpTracker::set_splitter(const Flow* flow) +{ + Inspector* ins = flow->gadget; + + if ( !ins ) + ins = flow->clouseau; + + if ( ins ) + set_splitter(ins->get_splitter(!client_tracker) ); + else + set_splitter(new AtomSplitter(!client_tracker) ); +} + +void TcpTracker::init_on_syn_sent(TcpSegmentDescriptor& tsd) +{ + Profile profile(s5TcpNewSessPerfStats); + + tsd.get_flow()->set_session_flags(SSNFLAG_SEEN_CLIENT); + if ( tsd.get_tcph()->are_flags_set(TH_CWR | TH_ECE) ) + tsd.get_flow()->set_session_flags(SSNFLAG_ECN_CLIENT_QUERY); + + 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 ); + + snd_wnd = tsd.get_win(); + ts_last_packet = tsd.get_pkt()->pkth->ts.tv_sec; + + 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); + + cache_mac_address(tsd, FROM_CLIENT); + set_splitter(tsd.get_flow() ); + init_flush_policy( ); + + tcp_state = TcpStreamTracker::TCP_SYN_SENT; +} + +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; + + cache_mac_address(tsd, FROM_CLIENT); + set_splitter(tsd.get_flow() ); + init_flush_policy( ); + + tcp_state = TcpStreamTracker::TCP_LISTEN; +} + +void TcpTracker::init_on_synack_sent(TcpSegmentDescriptor& tsd) +{ + Profile profile(s5TcpNewSessPerfStats); + + DebugMessage(DEBUG_STREAM_STATE, "Creating new session tracker on SYN_ACK!\n"); + + tsd.get_flow()->set_session_flags(SSNFLAG_SEEN_SERVER); + if (tsd.get_tcph()->are_flags_set(TH_CWR | TH_ECE)) + tsd.get_flow()->set_session_flags(SSNFLAG_ECN_SERVER_REPLY); + + iss =tsd.get_seq(); + snd_una = tsd.get_seq() + 1; + snd_nxt = snd_una; + snd_wnd = tsd.get_win(); + + 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; + + 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); + + cache_mac_address(tsd, FROM_SERVER); + set_splitter(tsd.get_flow() ); + init_flush_policy(); + + tcp_state = TcpStreamTracker::TCP_SYN_RECV; +} + +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(); + + cache_mac_address(tsd, FROM_SERVER); + set_splitter(tsd.get_flow() ); + init_flush_policy(); + + tcp_state = TcpStreamTracker::TCP_SYN_SENT; +} + +void TcpTracker::init_on_3whs_ack_sent(TcpSegmentDescriptor& tsd) +{ + Profile profile(s5TcpNewSessPerfStats); + + tsd.get_flow()->set_session_flags(SSNFLAG_SEEN_CLIENT); + + if ( tsd.get_tcph()->are_flags_set(TH_CWR | TH_ECE) ) + tsd.get_flow()->set_session_flags(SSNFLAG_ECN_CLIENT_QUERY); + + iss = tsd.get_seq(); + snd_una = tsd.get_seq() + 1; + snd_nxt = tsd.get_seq() + 1; + snd_wnd = tsd.get_win(); + ts_last_packet = tsd.get_pkt()->pkth->ts.tv_sec; + 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); + + cache_mac_address(tsd, FROM_CLIENT); + set_splitter(tsd.get_flow() ); + init_flush_policy(); + tcp_state = TcpStreamTracker::TCP_ESTABLISHED; +} + +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; + + cache_mac_address(tsd, FROM_CLIENT); + set_splitter(tsd.get_flow() ); + init_flush_policy(); + tcp_state = TcpStreamTracker::TCP_ESTABLISHED; +} + +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() ); + } + else + { + r_win_base = 0; + r_nxt_ack = 0; + } + + ts_last_packet = tsd.get_pkt()->pkth->ts.tv_sec; + 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); + + cache_mac_address(tsd, tsd.get_direction() ); + set_splitter(tsd.get_flow() ); + init_flush_policy(); + tcp_state = TcpStreamTracker::TCP_ESTABLISHED; +} + +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(); + snd_wnd = 0; /* reset later */ + reassembler->set_seglist_base_seq(tsd.get_seq() ); + + cache_mac_address(tsd, tsd.get_direction() ); + set_splitter(tsd.get_flow() ); + init_flush_policy(); + tcp_state = TcpStreamTracker::TCP_ESTABLISHED; +} + +void TcpTracker::print(void) +{ + LogMessage(" + TcpTracker +\n"); + LogMessage(" state: %s\n", tcp_state_names[ tcp_state ]); + LogMessage(" state_queue: %s\n", tcp_state_names[ s_mgr.state_queue ]); + LogMessage(" expected_flags: 0x%X\n", s_mgr.expected_flags); + LogMessage(" transition_seq: 0x%X\n", s_mgr.transition_seq); + LogMessage(" stq_get_seq: %d\n", s_mgr.stq_get_seq); + LogMessage(" iss: 0x%X\n", iss); + LogMessage(" ts_last: %u\n", ts_last); + LogMessage(" wscale: %u\n", wscale); + LogMessage(" mss: 0x%08X\n", mss); + LogMessage(" snd_una: %X\n", snd_una); + LogMessage(" snd_nxt: %X\n", snd_nxt); + LogMessage(" snd_win: %u\n", snd_wnd); + LogMessage(" rcv_nxt: %X\n", rcv_nxt); + LogMessage(" r_win_base: %X\n", r_win_base); +} + diff --git a/src/stream/tcp/tcp_tracker.h b/src/stream/tcp/tcp_tracker.h new file mode 100644 index 000000000..7eb7e8f6a --- /dev/null +++ b/src/stream/tcp/tcp_tracker.h @@ -0,0 +1,119 @@ +//-------------------------------------------------------------------------- +// Copyright (C) 2015-2015 Cisco and/or its affiliates. All rights reserved. +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License Version 2 as published +// by the Free Software Foundation. You may not use, modify or distribute +// this program under any other version of the GNU General Public License. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +//-------------------------------------------------------------------------- + +// tcp_tracker.h author davis mcpherson +// Created on: Dec 1, 2015 + +#ifndef TCP_TRACKER_H_ +#define TCP_TRACKER_H_ + +#include "stream/libtcp/tcp_stream_tracker.h" +#include "stream/paf.h" +#include "tcp_defs.h" + +struct StateMgr +{ + uint8_t sub_state; + enum TcpStreamTracker::TcpStates state_queue; + uint8_t expected_flags; + uint32_t transition_seq; + uint32_t stq_get_seq; +}; + +//------------------------------------------------------------------------- +// extra, extra - read all about it! +// -- u2 is the only output plugin that currently supports extra data +// -- extra data may be captured before or after alerts +// -- extra data may be per packet or persistent (saved on session) +// +// -- per packet extra data is logged iff we alert on the packet +// containing the extra data - u2 drives this +// -- an extra data mask is added to Packet to indicate when per packet +// extra data is available +// +// -- persistent extra data must be logged exactly once for each alert +// regardless of capture/alert ordering - s5 purge_alerts drives this +// -- an extra data mask is added to the session trackers to indicate that +// persistent extra data is available +// +// -- event id and second are added to the session alert trackers so that +// the extra data can be correlated with events +// -- event id and second are not available when check_alerted() +// is called; u2 calls StreamUpdateSessionAlertTcp as events are logged +// to set these fields +//------------------------------------------------------------------------- + +/* Only track a maximum number of alerts per session */ +#define MAX_SESSION_ALERTS 8 +struct StreamAlertInfo +{ + /* For storing alerts that have already been seen on the session */ + uint32_t sid; + uint32_t gid; + uint32_t seq; + // if we log extra data, event_* is used to correlate with alert + uint32_t event_id; + uint32_t event_second; +}; + +class TcpNormalizer; +class TcpReassembler; + +class TcpTracker : public TcpStreamTracker +{ +public: + TcpTracker(bool); + virtual ~TcpTracker(void); + void init_tracker(void); + void print(void); + void init_flush_policy(void); + void set_splitter(StreamSplitter* ss); + void set_splitter(const Flow* flow); + + void init_on_syn_sent(TcpSegmentDescriptor&); + void init_on_syn_recv(TcpSegmentDescriptor&); + void init_on_synack_sent(TcpSegmentDescriptor& tsd); + void init_on_synack_recv(TcpSegmentDescriptor& tsd); + void init_on_3whs_ack_sent(TcpSegmentDescriptor& tsd); + void init_on_3whs_ack_recv(TcpSegmentDescriptor& tsd); + void init_on_data_seg_sent(TcpSegmentDescriptor& tsd); + void init_on_data_seg_recv(TcpSegmentDescriptor& tsd); + + StateMgr s_mgr; /* state tracking goodies */ + + // 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 +