From: Russ Combs (rucombs) Date: Fri, 13 Apr 2018 15:42:18 +0000 (-0400) Subject: Merge pull request #1187 in SNORT/snort3 from stream_perf_optimization to master X-Git-Tag: 3.0.0-245~44 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=3e9b41f960b29f821cdb2be227b786d9e6ffe42d;p=thirdparty%2Fsnort3.git Merge pull request #1187 in SNORT/snort3 from stream_perf_optimization to master Squashed commit of the following: commit aba95f74f79e56d0752ceab71a6da315596d0aad Author: Russ Combs Date: Fri Mar 30 17:09:05 2018 -0400 stream_tcp: refactor tcp normalizer and reassembler to eliminate dynamic heap allocations per flow --- diff --git a/src/stream/libtcp/tcp_state_handler.cc b/src/stream/libtcp/tcp_state_handler.cc index 7392b88a7..a89e9ecfb 100644 --- a/src/stream/libtcp/tcp_state_handler.cc +++ b/src/stream/libtcp/tcp_state_handler.cc @@ -28,7 +28,7 @@ #include #include "main/snort_debug.h" - +#include "tcp_segment_descriptor.h" #include "tcp_state_machine.h" #ifdef UNIT_TEST diff --git a/src/stream/libtcp/tcp_state_handler.h b/src/stream/libtcp/tcp_state_handler.h index fe5380243..6b8d0c8ba 100644 --- a/src/stream/libtcp/tcp_state_handler.h +++ b/src/stream/libtcp/tcp_state_handler.h @@ -23,9 +23,9 @@ #define TCP_STATE_HANDLER_H #include "protocols/tcp.h" -#include "stream/libtcp/tcp_segment_descriptor.h" #include "stream/libtcp/tcp_stream_tracker.h" +class TcpSegmentDescriptor; class TcpStateMachine; class TcpStateHandler diff --git a/src/stream/libtcp/tcp_stream_session.cc b/src/stream/libtcp/tcp_stream_session.cc index 7f07e60f0..df9bc4099 100644 --- a/src/stream/libtcp/tcp_stream_session.cc +++ b/src/stream/libtcp/tcp_stream_session.cc @@ -40,14 +40,12 @@ const char* const flush_policy_names[] = }; #endif +TcpStreamSession::TcpStreamSession(Flow* f) + : Session(f), client(true), server(false) +{ } + TcpStreamSession::~TcpStreamSession() -{ - if (tcp_init) - { - delete client; - delete server; - } -} +{ } void TcpStreamSession::init_new_tcp_session(TcpSegmentDescriptor& tsd) { @@ -96,8 +94,8 @@ void TcpStreamSession::update_session_on_server_packet(TcpSegmentDescriptor& tsd DebugMessage(DEBUG_STREAM_STATE, "Stream: Updating on packet from server\n"); flow->set_session_flags(SSNFLAG_SEEN_SERVER); - talker = server; - listener = client; + talker = &server; + listener = &client; /* If we picked this guy up midstream, finish the initialization */ if ( !( flow->session_state & STREAM_STATE_ESTABLISHED ) @@ -126,8 +124,8 @@ void TcpStreamSession::update_session_on_client_packet(TcpSegmentDescriptor& tsd /* if we got here we had to see the SYN already... */ flow->set_session_flags(SSNFLAG_SEEN_CLIENT); - talker = client; - listener = server; + talker = &client; + listener = &server; if ( !( flow->session_state & STREAM_STATE_ESTABLISHED ) && ( flow->session_state & STREAM_STATE_MIDSTREAM ) ) @@ -148,10 +146,10 @@ uint8_t TcpStreamSession::get_reassembly_direction() { uint8_t dir = SSN_DIR_NONE; - if (server->flush_policy != STREAM_FLPOLICY_IGNORE) + if (server.get_flush_policy() != STREAM_FLPOLICY_IGNORE) dir |= SSN_DIR_FROM_CLIENT; - if (client->flush_policy != STREAM_FLPOLICY_IGNORE) + if (client.get_flush_policy() != STREAM_FLPOLICY_IGNORE) dir |= SSN_DIR_FROM_SERVER; return dir; @@ -161,13 +159,13 @@ bool TcpStreamSession::is_sequenced(uint8_t dir) { if (dir & SSN_DIR_FROM_CLIENT) { - if ( server->get_tf_flags() & ( TF_MISSING_PREV_PKT | TF_PKT_MISSED ) ) + if ( server.get_tf_flags() & ( TF_MISSING_PREV_PKT | TF_PKT_MISSED ) ) return false; } if ( dir & SSN_DIR_FROM_SERVER ) { - if ( client->get_tf_flags() & ( TF_MISSING_PREV_PKT | TF_PKT_MISSED ) ) + if ( client.get_tf_flags() & ( TF_MISSING_PREV_PKT | TF_PKT_MISSED ) ) return false; } @@ -180,22 +178,22 @@ uint8_t TcpStreamSession::missing_in_reassembled(uint8_t dir) { if (dir & SSN_DIR_FROM_CLIENT) { - if ( (server->get_tf_flags() & TF_MISSING_PKT) - && (server->get_tf_flags() & TF_MISSING_PREV_PKT)) + if ( (server.get_tf_flags() & TF_MISSING_PKT) + && (server.get_tf_flags() & TF_MISSING_PREV_PKT)) return SSN_MISSING_BOTH; - else if (server->get_tf_flags() & TF_MISSING_PREV_PKT) + else if (server.get_tf_flags() & TF_MISSING_PREV_PKT) return SSN_MISSING_BEFORE; - else if (server->get_tf_flags() & TF_MISSING_PKT) + else if (server.get_tf_flags() & TF_MISSING_PKT) return SSN_MISSING_AFTER; } else if (dir & SSN_DIR_FROM_SERVER) { - if ((client->get_tf_flags() & TF_MISSING_PKT) - && (client->get_tf_flags() & TF_MISSING_PREV_PKT)) + if ((client.get_tf_flags() & TF_MISSING_PKT) + && (client.get_tf_flags() & TF_MISSING_PREV_PKT)) return SSN_MISSING_BOTH; - else if (client->get_tf_flags() & TF_MISSING_PREV_PKT) + else if (client.get_tf_flags() & TF_MISSING_PREV_PKT) return SSN_MISSING_BEFORE; - else if (client->get_tf_flags() & TF_MISSING_PKT) + else if (client.get_tf_flags() & TF_MISSING_PKT) return SSN_MISSING_AFTER; } @@ -206,13 +204,13 @@ bool TcpStreamSession::are_packets_missing(uint8_t dir) { if (dir & SSN_DIR_FROM_CLIENT) { - if (server->get_tf_flags() & TF_PKT_MISSED) + if (server.get_tf_flags() & TF_PKT_MISSED) return true; } if (dir & SSN_DIR_FROM_SERVER) { - if (client->get_tf_flags() & TF_PKT_MISSED) + if (client.get_tf_flags() & TF_PKT_MISSED) return true; } @@ -223,7 +221,6 @@ void TcpStreamSession::update_direction(char dir, const SfIp* ip, uint16_t port) { SfIp tmpIp; uint16_t tmpPort; - TcpStreamTracker* tracker; if (flow->client_ip.equals(*ip) && (flow->client_port == port)) { @@ -251,7 +248,7 @@ void TcpStreamSession::update_direction(char dir, const SfIp* ip, uint16_t port) flow->server_port = tmpPort; SwapPacketHeaderFoo( ); - tracker = client; + TcpStreamTracker& tracker = client; client = server; server = tracker; } @@ -260,25 +257,20 @@ void TcpStreamSession::update_direction(char dir, const SfIp* ip, uint16_t port) // packet / PDU split because PDU rules won't run on raw packets bool TcpStreamSession::add_alert(Packet* p, uint32_t gid, uint32_t sid) { - TcpStreamTracker* st; + TcpStreamTracker& st = p->ptrs.ip_api.get_src()->equals(flow->client_ip) ? server : client; StreamAlertInfo* ai; - if (p->ptrs.ip_api.get_src()->equals(flow->client_ip)) - st = server; - else - st = client; - - if (st->alert_count >= MAX_SESSION_ALERTS) + if (st.alert_count >= MAX_SESSION_ALERTS) return false; - ai = st->alerts + st->alert_count; + ai = st.alerts + st.alert_count; ai->gid = gid; ai->sid = sid; ai->seq = 0; ai->event_id = 0; ai->event_second = 0; - st->alert_count++; + st.alert_count++; return true; } @@ -289,22 +281,14 @@ bool TcpStreamSession::check_alerted(Packet* p, uint32_t gid, uint32_t sid) if (!(p->packet_flags & PKT_REBUILT_STREAM)) return false; - TcpStreamTracker* st; - - if (p->ptrs.ip_api.get_src()->equals(flow->client_ip)) - st = server; - else - st = client; - - for (int i = 0; i < st->alert_count; i++) + TcpStreamTracker& st = p->ptrs.ip_api.get_src()->equals(flow->client_ip) ? server : client; + for (int i = 0; i < st.alert_count; i++) { /* This is a rebuilt packet and if we've seen this alert before, * return that we have previously alerted on original packet. */ - if (st->alerts[i].gid == gid && st->alerts[i].sid == sid) - { + if (st.alerts[i].gid == gid && st.alerts[i].sid == sid) return true; - } } return false; @@ -313,20 +297,12 @@ bool TcpStreamSession::check_alerted(Packet* p, uint32_t gid, uint32_t sid) int TcpStreamSession::update_alert(Packet* p, uint32_t gid, uint32_t sid, uint32_t event_id, uint32_t event_second) { - TcpStreamTracker* st; - int i; - uint32_t seq_num; + uint32_t seq_num = 0; + TcpStreamTracker& st = p->ptrs.ip_api.get_src()->equals(flow->client_ip) ? server : client; - if (p->ptrs.ip_api.get_src()->equals(flow->client_ip)) - st = server; - else - st = client; - - seq_num = 0; - - for (i = 0; i < st->alert_count; i++) + for (unsigned i = 0; i < st.alert_count; i++) { - StreamAlertInfo* ai = st->alerts + i; + StreamAlertInfo* ai = st.alerts + i; if (ai->gid == gid && ai->sid == sid && SEQ_EQ(ai->seq, seq_num)) { @@ -424,11 +400,8 @@ void TcpStreamSession::reset() bool TcpStreamSession::setup(Packet*) { - // FIXIT-L this it should not be necessary to reset here - reset(); - - client->init_tcp_state(); - server->init_tcp_state(); + client.init_tcp_state(); + server.init_tcp_state(); lws_init = tcp_init = false; generate_3whs_alert = true; pkt_action_mask = ACTION_NOTHING; @@ -444,6 +417,8 @@ bool TcpStreamSession::setup(Packet*) void TcpStreamSession::cleanup(Packet* p) { clear_session(true, true, false, p); + client.normalizer.reset(); + server.reassembler.reset(); } void TcpStreamSession::clear() @@ -451,36 +426,37 @@ void TcpStreamSession::clear() if ( tcp_init ) // this does NOT flush data clear_session( true, false, false ); + TcpHAManager::process_deletion(flow); } void TcpStreamSession::set_splitter(bool to_server, StreamSplitter* ss) { - TcpStreamTracker* trk = ( to_server ) ? server : client; + TcpStreamTracker& trk = ( to_server ) ? server : client; - trk->set_splitter(ss); + trk.set_splitter(ss); } uint16_t TcpStreamSession::get_mss(bool to_server) const { - TcpStreamTracker* trk = (to_server) ? client : server; + const TcpStreamTracker& trk = (to_server) ? client : server; - return trk->get_mss(); + return trk.get_mss(); } uint8_t TcpStreamSession::get_tcp_options_len(bool to_server) const { - TcpStreamTracker* trk = (to_server) ? client : server; + const TcpStreamTracker& trk = (to_server) ? client : server; - return trk->get_tcp_options_len(); + return trk.get_tcp_options_len(); } StreamSplitter* TcpStreamSession::get_splitter(bool to_server) { if ( to_server ) - return server->splitter; + return server.get_splitter(); else - return client->splitter; + return client.get_splitter(); } void TcpStreamSession::start_proxy() @@ -513,9 +489,9 @@ void TcpStreamSession::print() LogMessage(" client port: %d\n", flow->client_port); LogMessage(" flags: 0x%X\n", flow->get_session_flags()); LogMessage("Client Tracker:\n"); - client->print(); + client.print(); LogMessage("Server Tracker:\n"); - server->print(); + server.print(); } diff --git a/src/stream/libtcp/tcp_stream_session.h b/src/stream/libtcp/tcp_stream_session.h index 9bcfd30c5..b106c4df9 100644 --- a/src/stream/libtcp/tcp_stream_session.h +++ b/src/stream/libtcp/tcp_stream_session.h @@ -25,6 +25,7 @@ #include "detection/detection_engine.h" #include "flow/session.h" #include "protocols/ipv6.h" + #include "stream/libtcp/tcp_stream_tracker.h" #include "stream/tcp/tcp_stream_config.h" @@ -38,7 +39,6 @@ extern const char* const flush_policy_names[]; class TcpStreamSession : public Session { public: - TcpStreamSession(snort::Flow* flow) : Session(flow) { } ~TcpStreamSession() override; bool setup(snort::Packet*) override; @@ -130,8 +130,8 @@ public: virtual void handle_data_segment(TcpSegmentDescriptor&) { } virtual bool validate_packet_established_session(TcpSegmentDescriptor&) { return true; } - TcpStreamTracker* client = nullptr; - TcpStreamTracker* server = nullptr; + TcpStreamTracker client; + TcpStreamTracker server; bool lws_init = false; bool tcp_init = false; uint32_t pkt_action_mask = ACTION_NOTHING; @@ -153,6 +153,7 @@ private: uint16_t real_dst_port = 0; protected: + TcpStreamSession(snort::Flow*); virtual void set_os_policy() = 0; TcpStreamTracker* talker = nullptr; diff --git a/src/stream/libtcp/tcp_stream_tracker.cc b/src/stream/libtcp/tcp_stream_tracker.cc index 7a83f488a..47ddc23a0 100644 --- a/src/stream/libtcp/tcp_stream_tracker.cc +++ b/src/stream/libtcp/tcp_stream_tracker.cc @@ -25,9 +25,14 @@ #include "tcp_stream_tracker.h" +#include "log/messages.h" +#include "profiler/profiler_defs.h" #include "protocols/eth.h" #include "stream/stream.h" #include "stream/tcp/tcp_module.h" +#include "stream/tcp/tcp_normalizers.h" +#include "stream/tcp/tcp_reassemblers.h" +#include "stream/tcp/segment_overlap_editor.h" using namespace snort; @@ -51,7 +56,11 @@ const char* tcp_event_names[] = { TcpStreamTracker::TcpStreamTracker(bool client) : client_tracker(client), tcp_state(client ? TCP_STATE_NONE : TCP_LISTEN) +{ } + +TcpStreamTracker::~TcpStreamTracker() { + delete splitter; } TcpStreamTracker::TcpEvent TcpStreamTracker::set_tcp_event(TcpSegmentDescriptor& tsd) @@ -173,3 +182,503 @@ void TcpStreamTracker::cache_mac_address(TcpSegmentDescriptor& tsd, uint8_t dire } } +void TcpStreamTracker::init_tcp_state() +{ + tcp_state = ( client_tracker ) ? + TcpStreamTracker::TCP_STATE_NONE : TcpStreamTracker::TCP_LISTEN; + 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; + tf_flags = 0; + alert_count = 0; + mac_addr_valid = false; + fin_final_seq = 0; + fin_seq_status = TcpStreamTracker::FIN_NOT_SEEN; + fin_seq_set = false; + rst_pkt_sent = false; +} + +//------------------------------------------------------------------------- +// flush policy stuff +//------------------------------------------------------------------------- + +void TcpStreamTracker::init_flush_policy() +{ + if ( splitter == nullptr ) + flush_policy = STREAM_FLPOLICY_IGNORE; + else if ( normalizer.is_tcp_ips_enabled() ) + flush_policy = STREAM_FLPOLICY_ON_DATA; + else + flush_policy = STREAM_FLPOLICY_ON_ACK; +} + +void TcpStreamTracker::set_splitter(StreamSplitter* ss) +{ + if ( splitter ) + delete splitter; + + splitter = ss; + + if ( ss ) + paf_setup(&paf_state); + else + flush_policy = STREAM_FLPOLICY_IGNORE; +} + +void TcpStreamTracker::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 TcpStreamTracker::reset_splitter( ) +{ + if ( splitter ) + splitter->reset(); +} + +void TcpStreamTracker::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_seg_seq(); + snd_una = iss; + snd_nxt = tsd.get_end_seq(); + snd_wnd = tsd.get_seg_wnd(); + + ts_last_packet = tsd.get_pkt()->pkth->ts.tv_sec; + tf_flags |= normalizer.get_tcp_timestamp(tsd, false); + ts_last = tsd.get_ts(); + if (ts_last == 0) + tf_flags |= TF_TSTAMP_ZERO; + tf_flags |= tsd.init_mss(&mss); + tf_flags |= tsd.init_wscale(&wscale); + + cache_mac_address(tsd, FROM_CLIENT); + tcp_state = TcpStreamTracker::TCP_SYN_SENT; + tcpStats.sessions_on_syn++; +} + +void TcpStreamTracker::init_on_syn_recv(TcpSegmentDescriptor& tsd) +{ + Profile profile(s5TcpNewSessPerfStats); + + irs = tsd.get_seg_seq(); + // FIXIT-H can we really set the vars below now? + r_nxt_ack = tsd.get_seg_seq() + 1; + r_win_base = tsd.get_seg_seq() + 1; + reassembler.set_seglist_base_seq(tsd.get_seg_seq() + 1); + + cache_mac_address(tsd, FROM_CLIENT); + tcp_state = TcpStreamTracker::TCP_SYN_RECV; +} + +void TcpStreamTracker::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_seg_seq(); + irs = tsd.get_seg_ack() - 1; + snd_una = tsd.get_seg_seq(); + snd_nxt = tsd.get_end_seq(); + snd_wnd = tsd.get_seg_wnd(); + + r_win_base = tsd.get_seg_ack(); + r_nxt_ack = tsd.get_seg_ack(); + reassembler.set_seglist_base_seq(tsd.get_seg_ack() ); + + ts_last_packet = tsd.get_pkt()->pkth->ts.tv_sec; + tf_flags |= normalizer.get_tcp_timestamp(tsd, false); + ts_last = tsd.get_ts(); + if ( ts_last == 0 ) + tf_flags |= TF_TSTAMP_ZERO; + tf_flags |= tsd.init_mss(&mss); + tf_flags |= tsd.init_wscale(&wscale); + + cache_mac_address(tsd, FROM_SERVER); + tcp_state = TcpStreamTracker::TCP_SYN_RECV; + tcpStats.sessions_on_syn_ack++; +} + +void TcpStreamTracker::init_on_synack_recv(TcpSegmentDescriptor& tsd) +{ + Profile profile(s5TcpNewSessPerfStats); + + iss = tsd.get_seg_ack() - 1; + irs = tsd.get_seg_seq(); + snd_una = tsd.get_seg_ack(); + snd_nxt = snd_una; + + r_nxt_ack = tsd.get_seg_seq() + 1; + r_win_base = tsd.get_seg_seq() + 1; + reassembler.set_seglist_base_seq(tsd.get_seg_seq() + 1); + + cache_mac_address(tsd, FROM_SERVER); + tcp_state = TcpStreamTracker::TCP_ESTABLISHED; +} + +void TcpStreamTracker::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_seg_seq(); + snd_una = tsd.get_seg_seq(); + snd_nxt = snd_una; + snd_wnd = tsd.get_seg_wnd(); + + r_win_base = tsd.get_seg_ack(); + r_nxt_ack = tsd.get_seg_ack(); + + ts_last_packet = tsd.get_pkt()->pkth->ts.tv_sec; + tf_flags |= normalizer.get_tcp_timestamp(tsd, false); + ts_last = tsd.get_ts(); + if (ts_last == 0) + tf_flags |= TF_TSTAMP_ZERO; + tf_flags |= tsd.init_mss(&mss); + tf_flags |= tsd.init_wscale(&wscale); + + cache_mac_address(tsd, FROM_CLIENT); + tcp_state = TcpStreamTracker::TCP_ESTABLISHED; +} + +void TcpStreamTracker::init_on_3whs_ack_recv(TcpSegmentDescriptor& tsd) +{ + Profile profile(s5TcpNewSessPerfStats); + + iss = tsd.get_seg_ack() - 1; + irs = tsd.get_seg_seq(); + snd_una = tsd.get_seg_ack(); + snd_nxt = snd_una; + + r_nxt_ack = tsd.get_seg_seq(); + r_win_base = tsd.get_seg_seq(); + reassembler.set_seglist_base_seq(tsd.get_seg_seq() + 1); + + cache_mac_address(tsd, FROM_CLIENT); + tcp_state = TcpStreamTracker::TCP_ESTABLISHED; + tcpStats.sessions_on_3way++; +} + +void TcpStreamTracker::init_on_data_seg_sent(TcpSegmentDescriptor& tsd) +{ + Profile profile(s5TcpNewSessPerfStats); + + Flow* flow = tsd.get_flow(); + + if ( flow->ssn_state.direction == FROM_CLIENT ) + flow->set_session_flags(SSNFLAG_SEEN_CLIENT); + else + flow->set_session_flags(SSNFLAG_SEEN_SERVER); + + // FIXIT-H should we init these? + iss = tsd.get_seg_seq(); + irs = tsd.get_seg_ack(); + snd_una = tsd.get_seg_seq(); + snd_nxt = snd_una + tsd.get_seg_len(); + snd_wnd = tsd.get_seg_wnd(); + + r_win_base = tsd.get_seg_ack(); + r_nxt_ack = tsd.get_seg_ack(); + reassembler.set_seglist_base_seq(tsd.get_seg_ack()); + + ts_last_packet = tsd.get_pkt()->pkth->ts.tv_sec; + tf_flags |= normalizer.get_tcp_timestamp(tsd, false); + ts_last = tsd.get_ts(); + if (ts_last == 0) + tf_flags |= TF_TSTAMP_ZERO; + tf_flags |= ( tsd.init_mss(&mss) | tsd.init_wscale(&wscale) ); + + cache_mac_address(tsd, tsd.get_direction() ); + tcp_state = TcpStreamTracker::TCP_ESTABLISHED; +} + +void TcpStreamTracker::init_on_data_seg_recv(TcpSegmentDescriptor& tsd) +{ + Profile profile(s5TcpNewSessPerfStats); + + iss = tsd.get_seg_ack(); + irs = tsd.get_seg_seq(); + snd_una = tsd.get_seg_ack(); + snd_nxt = snd_una; + snd_wnd = 0; /* reset later */ + + r_nxt_ack = tsd.get_seg_seq(); + r_win_base = tsd.get_seg_seq(); + reassembler.set_seglist_base_seq(tsd.get_seg_seq()); + + cache_mac_address(tsd, tsd.get_direction() ); + tcp_state = TcpStreamTracker::TCP_ESTABLISHED; + tcpStats.sessions_on_data++; +} + +void TcpStreamTracker::finish_server_init(TcpSegmentDescriptor& tsd) +{ + iss = tsd.get_seg_seq(); + snd_una = tsd.get_seg_seq(); + snd_nxt = tsd.get_end_seq(); + snd_wnd = tsd.get_seg_wnd(); + + // FIXIT-H move this to fin handler for syn_recv state .. + //if ( tcph->is_fin() ) + // server->set_snd_nxt(server->get_snd_nxt() - 1); + + tf_flags |= normalizer.get_tcp_timestamp(tsd, false); + ts_last = tsd.get_ts(); + if ( ts_last != 0 ) + ts_last_packet = tsd.get_pkt()->pkth->ts.tv_sec; + else + tf_flags |= TF_TSTAMP_ZERO; + + tf_flags |= ( tsd.init_mss(&mss) | tsd.init_wscale(&wscale) ); +} + +void TcpStreamTracker::finish_client_init(TcpSegmentDescriptor& tsd) +{ + Flow* flow = tsd.get_flow(); + + r_nxt_ack = tsd.get_end_seq(); + + if ( !( flow->session_state & STREAM_STATE_MIDSTREAM ) ) + { + reassembler.set_seglist_base_seq(tsd.get_seg_seq() + 1); + r_win_base = tsd.get_end_seq(); + } + else + { + reassembler.set_seglist_base_seq(tsd.get_seg_seq() ); + r_win_base = tsd.get_seg_seq(); + } +} + +void TcpStreamTracker::update_tracker_ack_recv(TcpSegmentDescriptor& tsd) +{ + if ( SEQ_GT(tsd.get_seg_ack(), snd_una) ) + { + snd_una = tsd.get_seg_ack(); + if ( snd_nxt < snd_una ) + snd_nxt = snd_una; + } +} + +void TcpStreamTracker::update_tracker_ack_sent(TcpSegmentDescriptor& tsd) +{ + // ** this is how we track the last seq number sent + // as is l_unackd is the "last left" seq recvd + //snd_una = tsd.get_seg_seq(); + + // FIXIT-H add check to validate ack... + + if ( SEQ_GT(tsd.get_end_seq(), snd_nxt) ) + snd_nxt = tsd.get_end_seq(); + + if ( !SEQ_EQ(r_win_base, tsd.get_seg_ack() ) ) + small_seg_count = 0; + + if ( SEQ_GT(tsd.get_seg_ack(), r_win_base) ) + r_win_base = tsd.get_seg_ack(); + + if ( ( fin_seq_status == TcpStreamTracker::FIN_WITH_SEQ_SEEN ) + && SEQ_EQ(r_win_base, fin_final_seq) ) + { + fin_seq_status = TcpStreamTracker::FIN_WITH_SEQ_ACKED; + } + + snd_wnd = tsd.get_seg_wnd(); + reassembler.flush_on_ack_policy(tsd.get_pkt() ); +} + +bool TcpStreamTracker::update_on_3whs_ack(TcpSegmentDescriptor& tsd) +{ + bool good_ack = true; + + if ( is_ack_valid(tsd.get_seg_ack()) ) + { + Flow* flow = tsd.get_flow(); + + irs = tsd.get_seg_seq(); + finish_client_init(tsd); + update_tracker_ack_recv(tsd); + flow->set_session_flags(SSNFLAG_ESTABLISHED); + flow->session_state |= ( STREAM_STATE_ACK | STREAM_STATE_ESTABLISHED ); + tcp_state = TcpStreamTracker::TCP_ESTABLISHED; + } + else + { + DebugFormat(DEBUG_STREAM_STATE, + "Pkt Ack is Out of Bounds (%X, %X, %X) = (snd_una, snd_nxt, cur)\n", + snd_una, snd_nxt, tsd.get_seg_ack()); + inc_tcp_discards(); + normalizer.trim_win_payload(tsd); + good_ack = false; + } + + return good_ack; +} + +bool TcpStreamTracker::update_on_rst_recv(TcpSegmentDescriptor& tsd) +{ + bool good_rst = true; + + normalizer.trim_rst_payload(tsd); + if ( normalizer.validate_rst(tsd) ) + { + Flow* flow = tsd.get_flow(); + + DebugMessage(DEBUG_STREAM_STATE, "Received Valid RST, bailing\n"); + flow->set_session_flags(SSNFLAG_RESET); + if ( normalizer.is_tcp_ips_enabled() ) + tcp_state = TcpStreamTracker::TCP_CLOSED; + } + else + { + DebugMessage(DEBUG_STREAM_STATE, "Received RST with bad sequence number, bailing\n"); + inc_tcp_discards(); + normalizer.packet_dropper(tsd, NORM_TCP_BLOCK); + good_rst = false; + } + + return good_rst; +} + +void TcpStreamTracker::update_on_rst_sent() +{ + tcp_state = TcpStreamTracker::TCP_CLOSED; + rst_pkt_sent = true; +} + +void TcpStreamTracker::flush_data_on_fin_recv(TcpSegmentDescriptor& tsd) +{ + if ( (flush_policy != STREAM_FLPOLICY_ON_ACK) + && (flush_policy != STREAM_FLPOLICY_ON_DATA) + && normalizer.is_tcp_ips_enabled()) + { + tsd.get_pkt()->packet_flags |= PKT_PDU_TAIL; + } + + reassembler.flush_on_data_policy(tsd.get_pkt()); +} + +bool TcpStreamTracker::update_on_fin_recv(TcpSegmentDescriptor& tsd) +{ + if ( SEQ_LT(tsd.get_end_seq(), r_win_base) ) + { + DebugMessage(DEBUG_STREAM_STATE, "FIN inside r_win_base, bailing\n"); + return false; + } + + //-------------------------------------------------- + // FIXIT-L don't bump r_nxt_ack unless FIN is in seq + // because it causes bogus 129:5 cases + // but doing so causes extra gaps + //if ( SEQ_EQ(tsd.end_seq, r_nxt_ack) ) + r_nxt_ack++; + + // set final seq # any packet rx'ed with seq > is bad + if ( !fin_seq_set ) + { + fin_final_seq = tsd.get_end_seq(); + fin_seq_set = true; + if( tsd.get_seg_len() == 0 ) + fin_seq_status = TcpStreamTracker::FIN_WITH_SEQ_SEEN; + } + + return true; +} + +bool TcpStreamTracker::update_on_fin_sent(TcpSegmentDescriptor& tsd) +{ + update_tracker_ack_sent(tsd); + snd_nxt++; + return true; +} + +bool TcpStreamTracker::is_segment_seq_valid(TcpSegmentDescriptor& tsd) +{ + bool valid_seq = true; + + int right_ok; + uint32_t left_seq; + + DebugFormat(DEBUG_STREAM_STATE, + "Checking end_seq (%X) > r_win_base (%X) && seq (%X) < r_nxt_ack(%X)\n", + tsd.get_end_seq(), r_win_base, tsd.get_seg_seq(), + r_nxt_ack + normalizer.get_stream_window(tsd)); + + if ( SEQ_LT(r_nxt_ack, r_win_base) ) + left_seq = r_nxt_ack; + else + left_seq = r_win_base; + + if ( tsd.get_seg_len() ) + right_ok = SEQ_GT(tsd.get_end_seq(), left_seq); + else + right_ok = SEQ_GEQ(tsd.get_end_seq(), left_seq); + + if ( right_ok ) + { + uint32_t win = normalizer.get_stream_window(tsd); + + if ( SEQ_LEQ(tsd.get_seg_seq(), r_win_base + win) ) + { + DebugMessage(DEBUG_STREAM_STATE, "seq is within window!\n"); + } + else + { + DebugMessage(DEBUG_STREAM_STATE, "seq is past the end of the window!\n"); + valid_seq = false; + } + } + else + { + DebugMessage(DEBUG_STREAM_STATE, "end_seq is before win_base\n"); + valid_seq = false; + } + + if ( !valid_seq ) + { + inc_tcp_discards(); + normalizer.trim_win_payload(tsd); + } + + return valid_seq; +} + +void TcpStreamTracker::print() +{ + LogMessage(" + TcpTracker +\n"); + LogMessage(" state: %s\n", tcp_state_names[ tcp_state ]); + 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/libtcp/tcp_stream_tracker.h b/src/stream/libtcp/tcp_stream_tracker.h index 6a96840ba..dc93572e8 100644 --- a/src/stream/libtcp/tcp_stream_tracker.h +++ b/src/stream/libtcp/tcp_stream_tracker.h @@ -22,9 +22,12 @@ #ifndef TCP_STREAM_TRACKER_H #define TCP_STREAM_TRACKER_H -#include "stream/libtcp/tcp_segment_descriptor.h" #include "stream/paf.h" +#include "stream/tcp/segment_overlap_editor.h" #include "stream/tcp/tcp_defs.h" +#include "stream/tcp/tcp_normalizers.h" +#include "stream/tcp/tcp_reassemblers.h" +#include "stream/libtcp/tcp_segment_descriptor.h" /* Only track a maximum number of alerts per session */ #define MAX_SESSION_ALERTS 8 @@ -42,9 +45,9 @@ struct StreamAlertInfo extern const char* tcp_state_names[]; extern const char* tcp_event_names[]; -class TcpNormalizer; class TcpReassembler; class TcpSession; +struct TcpSegmentNode; class TcpStreamTracker { @@ -85,175 +88,109 @@ public: enum FinSeqNumStatus { FIN_NOT_SEEN, FIN_WITH_SEQ_SEEN, FIN_WITH_SEQ_ACKED }; - TcpStreamTracker(bool); - virtual ~TcpStreamTracker() = default; + TcpStreamTracker(bool client); + virtual ~TcpStreamTracker(); bool is_client_tracker() const - { - return client_tracker; - } + { return client_tracker; } bool is_server_tracker() const - { - return !client_tracker; - } + { return !client_tracker; } TcpState get_tcp_state() const - { - return tcp_state; - } + { return tcp_state; } void set_tcp_state(TcpState tcp_state) - { - this->tcp_state = tcp_state; - } + { this->tcp_state = tcp_state; } TcpEvent get_tcp_event() const - { - return tcp_event; - } + { return tcp_event; } TcpEvent set_tcp_event(TcpSegmentDescriptor&); void set_tcp_event(TcpEvent tcp_event) - { - this->tcp_event = tcp_event; - } + { this->tcp_event = tcp_event; } uint32_t get_rcv_nxt() const - { - return rcv_nxt; - } + { return rcv_nxt; } void set_rcv_nxt(uint32_t rcv_nxt) - { - this->rcv_nxt = rcv_nxt; - } + { this->rcv_nxt = rcv_nxt; } uint32_t get_rcv_wnd() const - { - return rcv_wnd; - } + { return rcv_wnd; } void set_rcv_wnd(uint32_t rcv_wnd) - { - this->rcv_wnd = rcv_wnd; - } + { this->rcv_wnd = rcv_wnd; } uint16_t get_rcv_up() const - { - return rcv_up; - } + { return rcv_up; } void set_rcv_up(uint16_t rcv_up) - { - this->rcv_up = rcv_up; - } + { this->rcv_up = rcv_up; } uint32_t get_irs() const - { - return irs; - } + { return irs; } void set_irs(uint32_t irs) - { - this->irs = irs; - } + { this->irs = irs; } uint32_t get_snd_una() const - { - return snd_una; - } + { return snd_una; } void set_snd_una(uint32_t snd_una) - { - this->snd_una = snd_una; - } + { this->snd_una = snd_una; } uint32_t get_snd_nxt() const - { - return snd_nxt; - } + { return snd_nxt; } void set_snd_nxt(uint32_t snd_nxt) - { - this->snd_nxt = snd_nxt; - } + { this->snd_nxt = snd_nxt; } uint16_t get_snd_up() const - { - return snd_up; - } + { return snd_up; } void set_snd_up(uint16_t snd_up) - { - this->snd_up = snd_up; - } + { this->snd_up = snd_up; } uint32_t get_snd_wl1() const - { - return snd_wl1; - } + { return snd_wl1; } void set_snd_wl1(uint32_t snd_wl1) - { - this->snd_wl1 = snd_wl1; - } + { this->snd_wl1 = snd_wl1; } uint32_t get_snd_wl2() const - { - return snd_wl2; - } + { return snd_wl2; } void set_snd_wl2(uint32_t snd_wl2) - { - this->snd_wl2 = snd_wl2; - } + { this->snd_wl2 = snd_wl2; } uint32_t get_snd_wnd() const - { - return snd_wnd; - } + { return snd_wnd; } void set_snd_wnd(uint32_t snd_wnd) - { - this->snd_wnd = snd_wnd; - } + { this->snd_wnd = snd_wnd; } uint32_t get_iss() const - { - return iss; - } + { return iss; } void set_iss(uint32_t iss) - { - this->iss = iss; - } + { this->iss = iss; } uint32_t get_fin_final_seq() const - { - return fin_final_seq; - } + { return fin_final_seq; } void set_fin_final_seq(uint32_t fin_final_seq = 0) - { - this->fin_final_seq = fin_final_seq; - } + { this->fin_final_seq = fin_final_seq; } bool is_fin_seq_set() const - { - return fin_seq_set; - } + { return fin_seq_set; } uint32_t get_ts_last_packet() const - { - return ts_last_packet; - } + { return ts_last_packet; } void set_ts_last_packet(uint32_t ts_last_packet) - { - this->ts_last_packet = ts_last_packet; - } + { this->ts_last_packet = ts_last_packet; } bool is_ack_valid(uint32_t cur) { @@ -267,107 +204,83 @@ public: // ack number must ack syn bool is_rst_valid_in_syn_sent(TcpSegmentDescriptor& tsd) - { - return tsd.get_seg_ack() == snd_una; - } + { return tsd.get_seg_ack() == snd_una; } uint32_t get_ts_last() const - { - return ts_last; - } + { return ts_last; } void set_ts_last(uint32_t ts_last) - { - this->ts_last = ts_last; - } + { this->ts_last = ts_last; } uint16_t get_tf_flags() const - { - return tf_flags; - } + { return tf_flags; } void set_tf_flags(uint16_t flags) - { - this->tf_flags |= flags; - } + { this->tf_flags |= flags; } void clear_tf_flags(uint16_t flags) - { - this->tf_flags &= ~flags; - } + { this->tf_flags &= ~flags; } uint16_t get_wscale() const - { - return wscale; - } + { return wscale; } void set_wscale(uint16_t wscale) - { - this->wscale = wscale; - } + { this->wscale = wscale; } uint16_t get_mss() const - { - return mss; - } + { return mss; } void set_mss(uint16_t mss) - { - this->mss = mss; - } + { this->mss = mss; } uint8_t get_tcp_options_len() const - { - return tcp_options_len; - } + { return tcp_options_len; } void set_tcp_options_len(uint8_t tcp_options_len) - { - this->tcp_options_len = tcp_options_len; - } + { this->tcp_options_len = tcp_options_len; } void cache_mac_address(TcpSegmentDescriptor&, uint8_t direction); bool compare_mac_addresses(const uint8_t eth_addr[]); bool is_rst_pkt_sent() const - { - return rst_pkt_sent; - } + { return rst_pkt_sent; } bool process_inorder_fin() const - { - return inorder_fin; - } - - virtual void init_tcp_state() = 0; - virtual void init_toolbox() = 0; - - virtual void print() = 0; - virtual void init_flush_policy() = 0; - virtual void set_splitter(snort::StreamSplitter* ss) = 0; - virtual void set_splitter(const snort::Flow* flow) = 0; - virtual void reset_splitter( ) = 0; - - virtual void init_on_syn_sent(TcpSegmentDescriptor&) = 0; - virtual void init_on_syn_recv(TcpSegmentDescriptor&) = 0; - virtual void init_on_synack_sent(TcpSegmentDescriptor&) = 0; - virtual void init_on_synack_recv(TcpSegmentDescriptor&) = 0; - virtual void init_on_3whs_ack_sent(TcpSegmentDescriptor&) = 0; - virtual void init_on_3whs_ack_recv(TcpSegmentDescriptor&) = 0; - virtual void init_on_data_seg_sent(TcpSegmentDescriptor&) = 0; - virtual void init_on_data_seg_recv(TcpSegmentDescriptor&) = 0; - virtual void finish_server_init(TcpSegmentDescriptor&) = 0; - virtual void finish_client_init(TcpSegmentDescriptor&) = 0; - - virtual void update_tracker_ack_recv(TcpSegmentDescriptor&) = 0; - virtual void update_tracker_ack_sent(TcpSegmentDescriptor&) = 0; - virtual bool update_on_3whs_ack(TcpSegmentDescriptor&) = 0; - virtual bool update_on_rst_recv(TcpSegmentDescriptor&) = 0; - virtual void update_on_rst_sent() = 0; - virtual bool update_on_fin_recv(TcpSegmentDescriptor&) = 0; - virtual bool update_on_fin_sent(TcpSegmentDescriptor&) = 0; - virtual bool is_segment_seq_valid(TcpSegmentDescriptor&) = 0; - virtual void flush_data_on_fin_recv(TcpSegmentDescriptor&) = 0; + { return inorder_fin; } + + snort::StreamSplitter* get_splitter() + { return splitter; } + + FlushPolicy get_flush_policy() + { return flush_policy; } + + virtual void init_tcp_state(); + virtual void print(); + virtual void init_flush_policy(); + virtual void set_splitter(snort::StreamSplitter* ss); + virtual void set_splitter(const snort::Flow* flow); + virtual void reset_splitter( ); + + virtual void init_on_syn_sent(TcpSegmentDescriptor&); + virtual void init_on_syn_recv(TcpSegmentDescriptor&); + virtual void init_on_synack_sent(TcpSegmentDescriptor&); + virtual void init_on_synack_recv(TcpSegmentDescriptor&); + virtual void init_on_3whs_ack_sent(TcpSegmentDescriptor&); + virtual void init_on_3whs_ack_recv(TcpSegmentDescriptor&); + virtual void init_on_data_seg_sent(TcpSegmentDescriptor&); + virtual void init_on_data_seg_recv(TcpSegmentDescriptor&); + virtual void finish_server_init(TcpSegmentDescriptor&); + virtual void finish_client_init(TcpSegmentDescriptor&); + + virtual void update_tracker_ack_recv(TcpSegmentDescriptor&); + virtual void update_tracker_ack_sent(TcpSegmentDescriptor&); + virtual bool update_on_3whs_ack(TcpSegmentDescriptor&); + virtual bool update_on_rst_recv(TcpSegmentDescriptor&); + virtual void update_on_rst_sent(); + virtual bool update_on_fin_recv(TcpSegmentDescriptor&); + virtual bool update_on_fin_sent(TcpSegmentDescriptor&); + virtual bool is_segment_seq_valid(TcpSegmentDescriptor&); + virtual void flush_data_on_fin_recv(TcpSegmentDescriptor&); bool client_tracker; TcpState tcp_state; @@ -396,10 +309,10 @@ public: uint32_t r_win_base = 0; /* remote side window base sequence number * (i.e. the last ack we got) */ - snort::StreamSplitter* splitter = nullptr; - TcpNormalizer* normalizer = nullptr; - TcpReassembler* reassembler = nullptr; TcpSession* session = nullptr; + TcpNormalizerPolicy normalizer; + TcpReassemblerPolicy reassembler; + snort::StreamSplitter* splitter = nullptr; uint32_t small_seg_count = 0; uint8_t alert_count = 0; diff --git a/src/stream/tcp/CMakeLists.txt b/src/stream/tcp/CMakeLists.txt index 24eeaa1e4..ad4d30b31 100644 --- a/src/stream/tcp/CMakeLists.txt +++ b/src/stream/tcp/CMakeLists.txt @@ -24,8 +24,6 @@ add_library( stream_tcp OBJECT tcp_reassembler.cc tcp_reassemblers.h tcp_reassemblers.cc - tcp_tracker.cc - tcp_tracker.h tcp_session.cc tcp_session.h tcp_state_closed.cc diff --git a/src/stream/tcp/ips_stream_reassemble.cc b/src/stream/tcp/ips_stream_reassemble.cc index f9e51b4ea..1b3fb6d8b 100644 --- a/src/stream/tcp/ips_stream_reassemble.cc +++ b/src/stream/tcp/ips_stream_reassemble.cc @@ -122,13 +122,13 @@ IpsOption::EvalStatus 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); } } @@ -138,13 +138,13 @@ IpsOption::EvalStatus 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)); } } diff --git a/src/stream/tcp/ips_stream_size.cc b/src/stream/tcp/ips_stream_size.cc index 63030d109..96b2d843b 100644 --- a/src/stream/tcp/ips_stream_size.cc +++ b/src/stream/tcp/ips_stream_size.cc @@ -105,26 +105,26 @@ IpsOption::EvalStatus SizeOption::eval(Cursor&, Packet* pkt) uint32_t client_size; uint32_t server_size; - if (tcpssn->client->get_snd_nxt() > tcpssn->client->get_iss()) + if (tcpssn->client.get_snd_nxt() > tcpssn->client.get_iss()) { /* the normal case... */ - client_size = tcpssn->client->get_snd_nxt() - tcpssn->client->get_iss(); + client_size = tcpssn->client.get_snd_nxt() - tcpssn->client.get_iss(); } else { /* the seq num wrapping case... */ - client_size = tcpssn->client->get_iss() - tcpssn->client->get_snd_nxt(); + client_size = tcpssn->client.get_iss() - tcpssn->client.get_snd_nxt(); } - if (tcpssn->server->get_snd_nxt() > tcpssn->server->get_iss()) + if (tcpssn->server.get_snd_nxt() > tcpssn->server.get_iss()) { /* the normal case... */ - server_size = tcpssn->server->get_snd_nxt() - tcpssn->server->get_iss(); + server_size = tcpssn->server.get_snd_nxt() - tcpssn->server.get_iss(); } else { /* the seq num wrapping case... */ - server_size = tcpssn->server->get_iss() - tcpssn->server->get_snd_nxt(); + server_size = tcpssn->server.get_iss() - tcpssn->server.get_snd_nxt(); } switch ( direction ) diff --git a/src/stream/tcp/segment_overlap_editor.cc b/src/stream/tcp/segment_overlap_editor.cc index d4b9b0bbd..43db0bc74 100644 --- a/src/stream/tcp/segment_overlap_editor.cc +++ b/src/stream/tcp/segment_overlap_editor.cc @@ -28,34 +28,93 @@ #include "log/messages.h" #include "tcp_module.h" -#include "tcp_normalizer.h" +#include "tcp_normalizers.h" +#include "tcp_session.h" -bool SegmentOverlapEditor::is_segment_retransmit(bool* full_retransmit) +void SegmentOverlapState::init_sos(TcpSession* ssn, ReassemblyPolicy pol) +{ + + session = ssn; + reassembly_policy = pol; + + seglist.reset(); + + 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; + rdata = nullptr; + + seq = 0; + seq_end = 0; + len = 0; + overlap = 0; + slide = 0; + trunc_len = 0; + rsize = 0; + rseq = 0; + keep_segment = true; + + tcp_ips_data = Normalize_GetMode(NORM_TCP_IPS); +} + +void SegmentOverlapState::init_soe( + TcpSegmentDescriptor& tsd, TcpSegmentNode* left, TcpSegmentNode* right) +{ + this->tsd = &tsd; + this->left = left; + this->right = right; + + seq = tsd.get_seg_seq(); + seq_end = tsd.get_end_seq(); + len = tsd.get_seg_len(); + + overlap = 0; + slide = 0; + trunc_len = 0; + + rdata = tsd.get_pkt()->data; + rsize = tsd.get_seg_len(); + rseq = tsd.get_seg_seq(); + + keep_segment = true; +} + +bool SegmentOverlapEditor::is_segment_retransmit( + TcpReassemblerState& trs, bool* full_retransmit) { // Don't want to count retransmits as overlaps or do anything // else with them. Account for retransmits of multiple PDUs // in one segment. - bool* pb = (rseq == tsd->get_seg_seq()) ? full_retransmit : nullptr; + bool* pb = (trs.sos.rseq == trs.sos.tsd->get_seg_seq()) ? full_retransmit : nullptr; - if ( right->is_retransmit(rdata, rsize, rseq, right->orig_dsize, pb) ) + if ( trs.sos.right->is_retransmit( + trs.sos.rdata, trs.sos.rsize, trs.sos.rseq, trs.sos.right->orig_dsize, pb) ) { if ( !(*full_retransmit) ) { - rdata += right->payload_size; - rsize -= right->payload_size; - rseq += right->payload_size; - seq += right->payload_size; - left = right; - right = right->next; + trs.sos.rdata += trs.sos.right->payload_size; + trs.sos.rsize -= trs.sos.right->payload_size; + trs.sos.rseq += trs.sos.right->payload_size; + trs.sos.seq += trs.sos.right->payload_size; + trs.sos.left = trs.sos.right; + trs.sos.right = trs.sos.right->next; } else - rsize = 0; + trs.sos.rsize = 0; - if ( rsize == 0 ) + if ( trs.sos.rsize == 0 ) { // All data was retransmitted - session->retransmit_process(tsd->get_pkt()); - keep_segment = false; + trs.sos.session->retransmit_process(trs.sos.tsd->get_pkt()); + trs.sos.keep_segment = false; } return true; @@ -64,45 +123,46 @@ bool SegmentOverlapEditor::is_segment_retransmit(bool* full_retransmit) return false; } -int SegmentOverlapEditor::eval_left() +int SegmentOverlapEditor::eval_left(TcpReassemblerState& trs) { int rc = STREAM_INSERT_OK; - if ( left ) - rc = insert_left_overlap(); + if ( trs.sos.left ) + rc = insert_left_overlap(trs); return rc; } -int SegmentOverlapEditor::eval_right() +int SegmentOverlapEditor::eval_right(TcpReassemblerState& trs) { - while ( right && SEQ_LT(right->seq, seq_end) ) + while ( trs.sos.right && SEQ_LT(trs.sos.right->seq, trs.sos.seq_end) ) { - trunc_len = 0; + trs.sos.trunc_len = 0; - assert(SEQ_LEQ(seq, right->seq)); - overlap = ( int )( seq_end - right->seq ); + assert(SEQ_LEQ(trs.sos.seq, trs.sos.right->seq)); + trs.sos.overlap = ( int )( trs.sos.seq_end - trs.sos.right->seq ); DebugFormat(DEBUG_STREAM_STATE, "right overlap(%d): len: %d right->seq: 0x%X seq: 0x%X\n", - overlap, len, right->seq, seq); + trs.sos.overlap, trs.sos.len, trs.sos.right->seq, trs.sos.seq); // Treat sequence number overlap as a retransmission, only check right side since // left side happens rarely - session->retransmit_handle(tsd->get_pkt()); + trs.sos.session->retransmit_handle(trs.sos.tsd->get_pkt()); - if ( overlap < right->payload_size ) + if ( trs.sos.overlap < trs.sos.right->payload_size ) { - if ( right->is_retransmit(rdata, rsize, rseq, right->orig_dsize, nullptr) ) + if ( trs.sos.right->is_retransmit( + trs.sos.rdata, trs.sos.rsize, trs.sos.rseq, trs.sos.right->orig_dsize, nullptr) ) { // All data was retransmitted - session->retransmit_process(tsd->get_pkt()); - keep_segment = false; + trs.sos.session->retransmit_process(trs.sos.tsd->get_pkt()); + trs.sos.keep_segment = false; } else { tcpStats.overlaps++; - overlap_count++; - insert_right_overlap(); + trs.sos.overlap_count++; + insert_right_overlap(trs); } break; @@ -113,7 +173,7 @@ int SegmentOverlapEditor::eval_right() // 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(&full_retransmit) ) + if ( is_segment_retransmit(trs, &full_retransmit) ) { if ( full_retransmit ) break; @@ -121,8 +181,8 @@ int SegmentOverlapEditor::eval_right() } tcpStats.overlaps++; - overlap_count++; - int rc = insert_full_overlap(); + trs.sos.overlap_count++; + int rc = insert_full_overlap(trs); if ( rc != STREAM_INSERT_OK ) return rc; } @@ -131,91 +191,94 @@ int SegmentOverlapEditor::eval_right() return STREAM_INSERT_OK; } -void SegmentOverlapEditor::drop_old_segment() +void SegmentOverlapEditor::drop_old_segment(TcpReassemblerState& trs) { DebugFormat(DEBUG_STREAM_STATE, "full right overlap, dropping old segment at seq %u, size %hu\n", - right->seq, right->payload_size); + trs.sos.right->seq, trs.sos.right->payload_size); - TcpSegmentNode* drop_seg = right; - right = right->next; - delete_reassembly_segment(drop_seg); + TcpSegmentNode* drop_seg = trs.sos.right; + trs.sos.right = trs.sos.right->next; + delete_reassembly_segment(trs, drop_seg); } -int SegmentOverlapEditor::left_overlap_keep_first() +int SegmentOverlapEditor::left_overlap_keep_first(TcpReassemblerState& trs) { - DebugFormat(DEBUG_STREAM_STATE, "left overlap %d\n", overlap); + DebugFormat(DEBUG_STREAM_STATE, "left overlap %d\n", trs.sos.overlap); // NOTE that overlap will always be less than left->size since // seq is always greater than left->seq - assert(SEQ_GT(seq, left->seq)); + assert(SEQ_GT(trs.sos.seq, trs.sos.left->seq)); - len = tsd->get_seg_len(); - overlap = left->seq + left->payload_size - seq; + trs.sos.len = trs.sos.tsd->get_seg_len(); + trs.sos.overlap = trs.sos.left->seq + trs.sos.left->payload_size - trs.sos.seq; - if ( len < overlap ) - overlap = len; + if ( trs.sos.len < trs.sos.overlap ) + trs.sos.overlap = trs.sos.len; - if ( overlap > 0 ) + if ( trs.sos.overlap > 0 ) { tcpStats.overlaps++; - overlap_count++; + trs.sos.overlap_count++; DebugMessage(DEBUG_STREAM_STATE, "left overlap, honoring old data\n"); - if ( SEQ_GT(left->seq + left->payload_size, seq_end) ) + if ( SEQ_GT(trs.sos.left->seq + trs.sos.left->payload_size, trs.sos.seq_end) ) { - if (tcp_ips_data == NORM_MODE_ON) + if (trs.sos.tcp_ips_data == NORM_MODE_ON) { - unsigned offset = tsd->get_seg_seq() - left->seq; - memcpy(const_cast(tsd->get_pkt()->data), left->payload()+offset, tsd->get_seg_len()); - tsd->get_pkt()->packet_flags |= PKT_MODIFIED; + unsigned offset = trs.sos.tsd->get_seg_seq() - trs.sos.left->seq; + memcpy(const_cast(trs.sos.tsd->get_pkt()->data), + trs.sos.left->payload()+offset, trs.sos.tsd->get_seg_len()); + trs.sos.tsd->get_pkt()->packet_flags |= PKT_MODIFIED; } - tcp_norm_stats[PC_TCP_IPS_DATA][tcp_ips_data]++; + tcp_norm_stats[PC_TCP_IPS_DATA][trs.sos.tcp_ips_data]++; } else { - if ( tcp_ips_data == NORM_MODE_ON ) + if ( trs.sos.tcp_ips_data == NORM_MODE_ON ) { - unsigned offset = tsd->get_seg_seq() - left->seq; - unsigned length = left->seq + left->payload_size - tsd->get_seg_seq(); - memcpy(const_cast(tsd->get_pkt()->data), left->payload()+offset, length); - tsd->get_pkt()->packet_flags |= PKT_MODIFIED; + unsigned offset = trs.sos.tsd->get_seg_seq() - trs.sos.left->seq; + unsigned length = trs.sos.left->seq + trs.sos.left->payload_size - + trs.sos.tsd->get_seg_seq(); + memcpy(const_cast(trs.sos.tsd->get_pkt()->data), + trs.sos.left->payload()+offset, length); + trs.sos.tsd->get_pkt()->packet_flags |= PKT_MODIFIED; } - tcp_norm_stats[PC_TCP_IPS_DATA][tcp_ips_data]++; + tcp_norm_stats[PC_TCP_IPS_DATA][trs.sos.tcp_ips_data]++; } - seq += overlap; + trs.sos.seq += trs.sos.overlap; } return STREAM_INSERT_OK; } -int SegmentOverlapEditor::left_overlap_trim_first() +int SegmentOverlapEditor::left_overlap_trim_first(TcpReassemblerState& trs) { - DebugFormat(DEBUG_STREAM_STATE, "left overlap %d\n", overlap); - assert(SEQ_GT(seq, left->seq)); + DebugFormat(DEBUG_STREAM_STATE, "left overlap %d\n", trs.sos.overlap); + assert(SEQ_GT(trs.sos.seq, trs.sos.left->seq)); - len = tsd->get_seg_len(); - overlap = left->seq + left->payload_size - seq; + trs.sos.len = trs.sos.tsd->get_seg_len(); + trs.sos.overlap = trs.sos.left->seq + trs.sos.left->payload_size - trs.sos.seq; - if ( overlap > 0 ) + if ( trs.sos.overlap > 0 ) { tcpStats.overlaps++; - overlap_count++; + trs.sos.overlap_count++; - if ( SEQ_GEQ(left->seq + left->payload_size, seq + len) ) + if ( SEQ_GEQ(trs.sos.left->seq + trs.sos.left->payload_size, trs.sos.seq + trs.sos.len) ) { // existing packet overlaps new on both sides. Drop the new data. DebugMessage(DEBUG_STREAM_STATE, "left overlap, honoring old data\n"); - seq += len; + trs.sos.seq += trs.sos.len; } else { /* Otherwise, trim the old data accordingly */ - left->payload_size -= ( int16_t )overlap; - seg_bytes_logical -= overlap; + trs.sos.left->payload_size -= ( int16_t )trs.sos.overlap; + trs.sos.seg_bytes_logical -= trs.sos.overlap; DebugMessage(DEBUG_STREAM_STATE, "left overlap, honoring new data\n"); } } @@ -223,130 +286,134 @@ int SegmentOverlapEditor::left_overlap_trim_first() return STREAM_INSERT_OK; } -int SegmentOverlapEditor::left_overlap_keep_last() +int SegmentOverlapEditor::left_overlap_keep_last(TcpReassemblerState& trs) { - DebugFormat(DEBUG_STREAM_STATE, "left overlap %d\n", overlap); - assert(SEQ_GT(seq, left->seq)); + DebugFormat(DEBUG_STREAM_STATE, "left overlap %d\n", trs.sos.overlap); + assert(SEQ_GT(trs.sos.seq, trs.sos.left->seq)); - len = tsd->get_seg_len(); - overlap = left->seq + left->payload_size - seq; + trs.sos.len = trs.sos.tsd->get_seg_len(); + trs.sos.overlap = trs.sos.left->seq + trs.sos.left->payload_size - trs.sos.seq; - if ( overlap > 0 ) + if ( trs.sos.overlap > 0 ) { tcpStats.overlaps++; - overlap_count++; + trs.sos.overlap_count++; /* True "Last" policy" */ - if ( SEQ_GT(left->seq + left->payload_size, seq + len) ) + if ( SEQ_GT(trs.sos.left->seq + trs.sos.left->payload_size, trs.sos.seq + trs.sos.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(left, &right); + int rc = dup_reassembly_segment(trs, trs.sos.left, &trs.sos.right); if ( rc != STREAM_INSERT_OK ) return rc; - left->payload_size -= ( int16_t )overlap; + trs.sos.left->payload_size -= ( int16_t )trs.sos.overlap; - right->seq = seq + len; - uint16_t delta = ( int16_t )( right->seq - left->seq ); - right->payload_size -= delta; - right->offset += delta; + trs.sos.right->seq = trs.sos.seq + trs.sos.len; + uint16_t delta = ( int16_t )( trs.sos.right->seq - trs.sos.left->seq ); + trs.sos.right->payload_size -= delta; + trs.sos.right->offset += delta; - seg_bytes_logical -= len; + trs.sos.seg_bytes_logical -= trs.sos.len; } else { - left->payload_size -= (int16_t)overlap; - seg_bytes_logical -= overlap; + trs.sos.left->payload_size -= (int16_t)trs.sos.overlap; + trs.sos.seg_bytes_logical -= trs.sos.overlap; } } return STREAM_INSERT_OK; } -void SegmentOverlapEditor::right_overlap_truncate_existing() +void SegmentOverlapEditor::right_overlap_truncate_existing(TcpReassemblerState& trs) { DebugMessage(DEBUG_STREAM_STATE, "Got partial right overlap\n"); - if ( SEQ_EQ(right->seq, seq) && ( reassembly_policy != ReassemblyPolicy::OS_LAST ) ) + if ( SEQ_EQ(trs.sos.right->seq, trs.sos.seq) && ( trs.sos.reassembly_policy != ReassemblyPolicy::OS_LAST ) ) { - slide = ( right->seq + right->payload_size - seq ); - seq += slide; + trs.sos.slide = ( trs.sos.right->seq + trs.sos.right->payload_size - trs.sos.seq ); + trs.sos.seq += trs.sos.slide; } else { /* partial overlap */ - right->seq += overlap; - right->offset += overlap; - right->payload_size -= (int16_t)overlap; - seg_bytes_logical -= overlap; - total_bytes_queued -= overlap; + trs.sos.right->seq += trs.sos.overlap; + trs.sos.right->offset += trs.sos.overlap; + trs.sos.right->payload_size -= (int16_t)trs.sos.overlap; + trs.sos.seg_bytes_logical -= trs.sos.overlap; + trs.sos.total_bytes_queued -= trs.sos.overlap; } } -void SegmentOverlapEditor::right_overlap_truncate_new() +void SegmentOverlapEditor::right_overlap_truncate_new(TcpReassemblerState& trs) { - if (tcp_ips_data == NORM_MODE_ON) + if (trs.sos.tcp_ips_data == NORM_MODE_ON) { - unsigned offset = right->seq - tsd->get_seg_seq(); - unsigned length = tsd->get_seg_seq() + tsd->get_seg_len() - right->seq; - memcpy(const_cast(tsd->get_pkt()->data) + offset, right->payload(), length); - tsd->get_pkt()->packet_flags |= PKT_MODIFIED; + unsigned offset = trs.sos.right->seq - trs.sos.tsd->get_seg_seq(); + unsigned length = trs.sos.tsd->get_seg_seq() + trs.sos.tsd->get_seg_len() - + trs.sos.right->seq; + memcpy(const_cast(trs.sos.tsd->get_pkt()->data) + offset, + trs.sos.right->payload(), length); + trs.sos.tsd->get_pkt()->packet_flags |= PKT_MODIFIED; } - tcp_norm_stats[PC_TCP_IPS_DATA][tcp_ips_data]++; - trunc_len = overlap; + tcp_norm_stats[PC_TCP_IPS_DATA][trs.sos.tcp_ips_data]++; + trs.sos.trunc_len = trs.sos.overlap; } // REASSEMBLY_POLICY_FIRST: // REASSEMBLY_POLICY_VISTA: -int SegmentOverlapEditor::full_right_overlap_truncate_new() +int SegmentOverlapEditor::full_right_overlap_truncate_new(TcpReassemblerState& trs) { DebugMessage(DEBUG_STREAM_STATE, "Got full right overlap, truncating new\n"); - if ( tcp_ips_data == NORM_MODE_ON ) + if ( trs.sos.tcp_ips_data == NORM_MODE_ON ) { - unsigned offset = right->seq - tsd->get_seg_seq(); - memcpy(const_cast(tsd->get_pkt()->data) + offset, right->payload(), right->payload_size); - tsd->get_pkt()->packet_flags |= PKT_MODIFIED; + unsigned offset = trs.sos.right->seq - trs.sos.tsd->get_seg_seq(); + memcpy(const_cast(trs.sos.tsd->get_pkt()->data) + offset, + trs.sos.right->payload(), trs.sos.right->payload_size); + trs.sos.tsd->get_pkt()->packet_flags |= PKT_MODIFIED; } - tcp_norm_stats[PC_TCP_IPS_DATA][tcp_ips_data]++; + tcp_norm_stats[PC_TCP_IPS_DATA][trs.sos.tcp_ips_data]++; - if ( SEQ_EQ(right->seq, seq) ) + if ( SEQ_EQ(trs.sos.right->seq, trs.sos.seq) ) { /* Overlap is greater than or equal to right->size * slide gets set before insertion */ - seq += right->payload_size; - left = right; - right = right->next; + trs.sos.seq += trs.sos.right->payload_size; + trs.sos.left = trs.sos.right; + trs.sos.right = trs.sos.right->next; /* Adjusted seq is fully overlapped */ - if ( SEQ_EQ(seq, seq_end) ) + if ( SEQ_EQ(trs.sos.seq, trs.sos.seq_end) ) return STREAM_INSERT_OK; } else { /* seq is less than right->seq, trunc length is reset to 0 at beginning of loop */ - trunc_len = overlap; + trs.sos.trunc_len = trs.sos.overlap; /* insert this one, and see if we need to chunk it up Adjust slide so that is correct relative to orig seq */ - slide = seq - tsd->get_seg_seq(); - int rc = add_reassembly_segment(*tsd, len, slide, trunc_len, seq, left); + trs.sos.slide = trs.sos.seq - trs.sos.tsd->get_seg_seq(); + int rc = add_reassembly_segment(trs, *trs.sos.tsd, trs.sos.len, trs.sos.slide, + trs.sos.trunc_len, trs.sos.seq, trs.sos.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 // inserted seq has been truncated to beginning of right and reset trunc length to 0 // since we may fall out of loop if next right is NULL - seq = right->seq + right->payload_size; - left = right; - right = right->next; - trunc_len = 0; + trs.sos.seq = trs.sos.right->seq + trs.sos.right->payload_size; + trs.sos.left = trs.sos.right; + trs.sos.right = trs.sos.right->next; + trs.sos.trunc_len = 0; } return STREAM_INSERT_OK; @@ -356,15 +423,16 @@ int SegmentOverlapEditor::full_right_overlap_truncate_new() // REASSEMBLY_POLICY_WINDOWS2K3: // REASSEMBLY_POLICY_BSD: // REASSEMBLY_POLICY_MACOS: -int SegmentOverlapEditor::full_right_overlap_os1() +int SegmentOverlapEditor::full_right_overlap_os1(TcpReassemblerState& trs) { - if ( SEQ_GEQ(seq_end, right->seq + right->payload_size) && SEQ_LT(seq, right->seq) ) + if ( SEQ_GEQ(trs.sos.seq_end, trs.sos.right->seq + trs.sos.right->payload_size) and + SEQ_LT(trs.sos.seq, trs.sos.right->seq) ) { - drop_old_segment(); + drop_old_segment(trs); } else { - int rc = full_right_overlap_truncate_new(); + int rc = full_right_overlap_truncate_new(trs); if ( rc != STREAM_INSERT_OK ) return rc; } @@ -375,19 +443,21 @@ int SegmentOverlapEditor::full_right_overlap_os1() // REASSEMBLY_POLICY_LINUX: // REASSEMBLY_POLICY_HPUX10: // REASSEMBLY_POLICY_IRIX: -int SegmentOverlapEditor::full_right_overlap_os2() +int SegmentOverlapEditor::full_right_overlap_os2(TcpReassemblerState& trs) { - if ( SEQ_GEQ(seq_end, right->seq + right->payload_size) && SEQ_LT(seq, right->seq) ) + if ( SEQ_GEQ(trs.sos.seq_end, trs.sos.right->seq + trs.sos.right->payload_size) and + SEQ_LT(trs.sos.seq, trs.sos.right->seq) ) { - drop_old_segment(); + drop_old_segment(trs); } - else if ( SEQ_GT(seq_end, right->seq + right->payload_size) && SEQ_EQ(seq, right->seq) ) + else if ( SEQ_GT(trs.sos.seq_end, trs.sos.right->seq + trs.sos.right->payload_size) and + SEQ_EQ(trs.sos.seq, trs.sos.right->seq) ) { - drop_old_segment(); + drop_old_segment(trs); } else { - int rc = full_right_overlap_truncate_new(); + int rc = full_right_overlap_truncate_new(trs); if ( rc != STREAM_INSERT_OK ) return rc; } @@ -397,25 +467,25 @@ int SegmentOverlapEditor::full_right_overlap_os2() // REASSEMBLY_POLICY_HPUX11: // REASSEMBLY_POLICY_SOLARIS: -int SegmentOverlapEditor::full_right_overlap_os3() +int SegmentOverlapEditor::full_right_overlap_os3(TcpReassemblerState& trs) { // If this packet is wholly overlapping and the same size as a previous one and we have not // received the one immediately preceding, 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(trs.sos.right->seq, trs.sos.seq) && (trs.sos.right->payload_size == trs.sos.len) + && (trs.sos.left && !SEQ_EQ(trs.sos.left->seq + trs.sos.left->payload_size, trs.sos.seq)) ) { - right_overlap_truncate_new(); - - rdata += right->payload_size; - rsize -= right->payload_size; - rseq += right->payload_size; - seq += right->payload_size; - left = right; - right = right->next; + right_overlap_truncate_new(trs); + + trs.sos.rdata += trs.sos.right->payload_size; + trs.sos.rsize -= trs.sos.right->payload_size; + trs.sos.rseq += trs.sos.right->payload_size; + trs.sos.seq += trs.sos.right->payload_size; + trs.sos.left = trs.sos.right; + trs.sos.right = trs.sos.right->next; } else { - drop_old_segment(); + drop_old_segment(trs); } return STREAM_INSERT_OK; @@ -423,25 +493,25 @@ int SegmentOverlapEditor::full_right_overlap_os3() // REASSEMBLY_POLICY_OLD_LINUX: // REASSEMBLY_POLICY_LAST: -int SegmentOverlapEditor::full_right_overlap_os4() +int SegmentOverlapEditor::full_right_overlap_os4(TcpReassemblerState& trs) { - drop_old_segment(); + drop_old_segment(trs); return STREAM_INSERT_OK; } -int SegmentOverlapEditor::full_right_overlap_os5() +int SegmentOverlapEditor::full_right_overlap_os5(TcpReassemblerState& trs) { - return full_right_overlap_truncate_new(); + return full_right_overlap_truncate_new(trs); } -void SegmentOverlapEditor::print() +void SegmentOverlapEditor::print(TcpReassemblerState& trs) { - 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); + LogMessage(" seglist_base_seq: %X\n", trs.sos.seglist_base_seq); + LogMessage(" seglist head: %p\n", (void*)trs.sos.seglist.head); + LogMessage(" seglist tail: %p\n", (void*)trs.sos.seglist.tail); + LogMessage(" seglist next: %p\n", (void*)trs.sos.seglist.next); + LogMessage(" seg_count: %d\n", trs.sos.seg_count); + LogMessage(" seg_bytes_total: %d\n", trs.sos.seg_bytes_total); + LogMessage(" seg_bytes_logical: %d\n", trs.sos.seg_bytes_logical); } diff --git a/src/stream/tcp/segment_overlap_editor.h b/src/stream/tcp/segment_overlap_editor.h index 71ab5fe95..22a8f59c1 100644 --- a/src/stream/tcp/segment_overlap_editor.h +++ b/src/stream/tcp/segment_overlap_editor.h @@ -26,90 +26,98 @@ #include "stream/tcp/tcp_segment_node.h" class TcpSession; +class TcpStreamTracker; #define STREAM_INSERT_OK 0 // FIXIT-L replace with bool -class SegmentOverlapEditor +struct SegmentOverlapState { -protected: + TcpSession* session; + TcpSegmentDescriptor* tsd; + TcpSegmentNode* left; + TcpSegmentNode* right; + const uint8_t* rdata; - SegmentOverlapEditor() - { - tcp_ips_data = Normalize_GetMode(NORM_TCP_IPS); - } + TcpSegmentList seglist; + ReassemblyPolicy reassembly_policy; - virtual ~SegmentOverlapEditor() = default; + uint32_t seglist_base_seq; /* seq of first queued segment */ + uint32_t seg_count; /* number of current queued segments */ + uint32_t seg_bytes_total; /* total bytes currently queued */ + uint32_t seg_bytes_logical; /* logical bytes queued (total - overlaps) */ + uint32_t total_bytes_queued; /* total bytes queued (life of session) */ + uint32_t total_segs_queued; /* number of segments queued (life) */ + uint32_t overlap_count; /* overlaps encountered */ + + uint32_t seq; + uint32_t seq_end; + uint32_t rseq; + + int32_t overlap; + int32_t slide; + int32_t trunc_len; + + uint16_t len; + uint16_t rsize; + int8_t tcp_ips_data; + + bool keep_segment; - void init_soe(TcpSegmentDescriptor& tsd, TcpSegmentNode* left, TcpSegmentNode* right) + ~SegmentOverlapState() { - this->tsd = &tsd; - this->left = left; - this->right = right; - seq = tsd.get_seg_seq(); - seq_end = tsd.get_end_seq(); - len = tsd.get_seg_len(); - overlap = 0; - slide = 0; - trunc_len = 0; - rdata = tsd.get_pkt()->data; - rsize = tsd.get_seg_len(); - rseq = tsd.get_seg_seq(); - keep_segment = true; + seglist.reset(); } - int eval_left(); - int eval_right(); - - virtual bool is_segment_retransmit(bool*); - virtual void drop_old_segment(); - - virtual int left_overlap_keep_first(); - virtual int left_overlap_trim_first(); - virtual int left_overlap_keep_last(); - virtual void right_overlap_truncate_existing(); - virtual void right_overlap_truncate_new(); - virtual int full_right_overlap_truncate_new(); - virtual int full_right_overlap_os1(); - virtual int full_right_overlap_os2(); - virtual int full_right_overlap_os3(); - virtual int full_right_overlap_os4(); - virtual int full_right_overlap_os5(); - - virtual int insert_left_overlap() = 0; - virtual void insert_right_overlap() = 0; - virtual int insert_full_overlap() = 0; - virtual int add_reassembly_segment(TcpSegmentDescriptor&, int16_t, uint32_t, uint32_t, - uint32_t, TcpSegmentNode*) = 0; - virtual int dup_reassembly_segment(TcpSegmentNode*, TcpSegmentNode**) = 0; - virtual int delete_reassembly_segment(TcpSegmentNode*) = 0; - virtual void print(); - - TcpSession* session = nullptr; - ReassemblyPolicy reassembly_policy = ReassemblyPolicy::OS_DEFAULT; - NormMode tcp_ips_data; + void init_sos(TcpSession*, ReassemblyPolicy); + void init_soe(TcpSegmentDescriptor& tsd, TcpSegmentNode* left, TcpSegmentNode* right); +}; - TcpSegmentList seglist; - uint32_t seglist_base_seq = 0; /* seq of first queued segment */ - uint32_t seg_count = 0; /* number of current queued segments */ - uint32_t seg_bytes_total = 0; /* total bytes currently queued */ - uint32_t seg_bytes_logical = 0; /* logical bytes queued (total - overlaps) */ - uint32_t total_bytes_queued = 0; /* total bytes queued (life of session) */ - uint32_t total_segs_queued = 0; /* number of segments queued (life) */ - uint32_t overlap_count = 0; /* overlaps encountered */ - - TcpSegmentDescriptor* tsd = nullptr; - TcpSegmentNode* left = nullptr; - TcpSegmentNode* right = nullptr; - const uint8_t* rdata = nullptr; - uint32_t seq = 0; - uint32_t seq_end = 0; - uint16_t len = 0; - int32_t overlap = 0; - int32_t slide = 0; - int32_t trunc_len = 0; - uint16_t rsize = 0; - uint32_t rseq = 0; - bool keep_segment = true; +struct TcpReassemblerState +{ + SegmentOverlapState sos; + TcpStreamTracker* tracker; + uint32_t flush_count; // number of flushed queued segments + uint32_t xtradata_mask; // extra data available to log + bool server_side; + uint8_t ignore_dir; + uint8_t packet_dir; +}; + +class SegmentOverlapEditor +{ +protected: + SegmentOverlapEditor() { } + virtual ~SegmentOverlapEditor() = default; + + int eval_left(TcpReassemblerState&); + int eval_right(TcpReassemblerState&); + + virtual bool is_segment_retransmit(TcpReassemblerState&, bool*); + virtual void drop_old_segment(TcpReassemblerState&); + + virtual int left_overlap_keep_first(TcpReassemblerState&); + virtual int left_overlap_trim_first(TcpReassemblerState&); + virtual int left_overlap_keep_last(TcpReassemblerState&); + virtual void right_overlap_truncate_existing(TcpReassemblerState&); + virtual void right_overlap_truncate_new(TcpReassemblerState&); + virtual int full_right_overlap_truncate_new(TcpReassemblerState&); + virtual int full_right_overlap_os1(TcpReassemblerState&); + virtual int full_right_overlap_os2(TcpReassemblerState&); + virtual int full_right_overlap_os3(TcpReassemblerState&); + virtual int full_right_overlap_os4(TcpReassemblerState&); + virtual int full_right_overlap_os5(TcpReassemblerState&); + + virtual int insert_left_overlap(TcpReassemblerState&) = 0; + virtual void insert_right_overlap(TcpReassemblerState&) = 0; + virtual int insert_full_overlap(TcpReassemblerState&) = 0; + + virtual int add_reassembly_segment( + TcpReassemblerState&, TcpSegmentDescriptor&, int16_t, uint32_t, + uint32_t, uint32_t, TcpSegmentNode*) = 0; + + virtual int dup_reassembly_segment(TcpReassemblerState&, TcpSegmentNode*, TcpSegmentNode**) = 0; + virtual int delete_reassembly_segment(TcpReassemblerState&, TcpSegmentNode*) = 0; + virtual void print(TcpReassemblerState&); }; #endif diff --git a/src/stream/tcp/tcp_debug_trace.h b/src/stream/tcp/tcp_debug_trace.h index 203d810f5..15eaebef2 100644 --- a/src/stream/tcp/tcp_debug_trace.h +++ b/src/stream/tcp/tcp_debug_trace.h @@ -24,7 +24,7 @@ #include "utils/stats.h" -#include "tcp_reassembler.h" +#include "tcp_reassemblers.h" #ifndef REG_TEST #define S5TraceTCP(pkt, flow, tsd, evt) @@ -42,7 +42,8 @@ static const char* const flushxt[] = { "IGN", "FPR", "PRE", "PRO", "PAF" }; static THREAD_LOCAL int s5_trace_enabled = -1; // FIXIT-L should use module trace feature -inline void TraceEvent(const snort::Packet* p, TcpSegmentDescriptor*, uint32_t txd, uint32_t rxd) +inline void TraceEvent( + const snort::Packet* p, TcpSegmentDescriptor*, uint32_t txd, uint32_t rxd) { int i; char flags[7] = "UAPRSF"; @@ -78,7 +79,7 @@ inline void TraceSession(const snort::Flow* lws) lws->ssn_state.session_flags, lws->client_port, lws->server_port); } -inline void TraceState(const TcpStreamTracker* a, const TcpStreamTracker* b, const char* s) +inline void TraceState(TcpStreamTracker* a, TcpStreamTracker* b, const char* s) { uint32_t ua = a->get_snd_una() ? LCL(a, get_snd_una) : 0; uint32_t ns = a->get_snd_nxt() ? LCL(a, get_snd_nxt) : 0; @@ -94,21 +95,22 @@ inline void TraceState(const TcpStreamTracker* a, const TcpStreamTracker* b, con 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()); + 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(); + a->reassembler.trace_segments(); fprintf(stdout, "\n"); } -inline void TraceTCP(const snort::Packet* p, const snort::Flow* lws, TcpSegmentDescriptor* tsd, int event) +inline void TraceTCP( + const snort::Packet* p, const snort::Flow* lws, TcpSegmentDescriptor* tsd, int event) { - const TcpSession* ssn = (TcpSession*)lws->session; - const TcpStreamTracker* srv = ssn ? ssn->server : nullptr; - const TcpStreamTracker* cli = ssn ? ssn->client : nullptr; + TcpSession* ssn = (TcpSession*)lws->session; + TcpStreamTracker* srv = ssn ? &ssn->server : nullptr; + TcpStreamTracker* cli = ssn ? &ssn->client : nullptr; const char* cdir = "?", * sdir = "?"; uint32_t txd = 0, rxd = 0; @@ -141,7 +143,8 @@ inline void TraceTCP(const snort::Packet* p, const snort::Flow* lws, TcpSegmentD } } -inline void S5TraceTCP(const snort::Packet* p, const snort::Flow* lws, TcpSegmentDescriptor* tsd, int event) +inline void S5TraceTCP( + const snort::Packet* p, const snort::Flow* lws, TcpSegmentDescriptor* tsd, int event) { if (!s5_trace_enabled) return; @@ -162,7 +165,6 @@ inline void S5TraceTCP(const snort::Packet* p, const snort::Flow* lws, TcpSegmen TraceTCP(p, lws, tsd, event); } - #endif // REG_TEST #endif diff --git a/src/stream/tcp/tcp_module.h b/src/stream/tcp/tcp_module.h index dcadac0c7..4ec589ff2 100644 --- a/src/stream/tcp/tcp_module.h +++ b/src/stream/tcp/tcp_module.h @@ -85,8 +85,8 @@ struct TcpStats PegCount exceeded_max_segs; PegCount exceeded_max_bytes; PegCount internalEvents; - PegCount s5tcp1; - PegCount s5tcp2; + PegCount client_cleanups; + PegCount server_cleanups; PegCount mem_in_use; PegCount sessions_initializing; PegCount sessions_established; diff --git a/src/stream/tcp/tcp_normalizer.cc b/src/stream/tcp/tcp_normalizer.cc index ee3a9f619..40fb2d83c 100644 --- a/src/stream/tcp/tcp_normalizer.cc +++ b/src/stream/tcp/tcp_normalizer.cc @@ -25,6 +25,9 @@ #include "tcp_normalizer.h" +#include "stream/libtcp/tcp_stream_session.h" +#include "stream/libtcp/tcp_stream_tracker.h" + #include "main/snort_debug.h" #include "packet_io/active.h" @@ -45,20 +48,6 @@ static const PegInfo pegName[] = { CountType::END, nullptr, nullptr } }; -TcpNormalizer::TcpNormalizer(StreamPolicy os_policy, TcpSession* session, - TcpStreamTracker* tracker) : - os_policy(os_policy), session(session), tracker(tracker) -{ - 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); -} - const PegInfo* TcpNormalizer::get_normalization_pegs() { return pegName; @@ -71,6 +60,7 @@ NormPegs TcpNormalizer::get_normalization_counts(unsigned& c) } void TcpNormalizer::trim_payload( + TcpNormalizerState&, TcpSegmentDescriptor& tsd, uint32_t max, NormMode mode, TcpPegCounts peg) { if (mode == NORM_MODE_ON) @@ -85,6 +75,7 @@ void TcpNormalizer::trim_payload( } bool TcpNormalizer::strip_tcp_timestamp( + TcpNormalizerState&, TcpSegmentDescriptor& tsd, const tcp::TcpOption* opt, NormMode mode) { tcp_norm_stats[PC_TCP_TS_NOP][mode]++; @@ -100,9 +91,10 @@ bool TcpNormalizer::strip_tcp_timestamp( return false; } -bool TcpNormalizer::packet_dropper(TcpSegmentDescriptor& tsd, NormFlags f) +bool TcpNormalizer::packet_dropper( + TcpNormalizerState& tns, TcpSegmentDescriptor& tsd, NormFlags f) { - const NormMode mode = (f == NORM_TCP_BLOCK) ? tcp_block : opt_block; + const int8_t mode = (f == NORM_TCP_BLOCK) ? tns.tcp_block : tns.opt_block; tcp_norm_stats[PC_TCP_BLOCK][mode]++; @@ -115,79 +107,87 @@ bool TcpNormalizer::packet_dropper(TcpSegmentDescriptor& tsd, NormFlags f) return false; } -void TcpNormalizer::trim_syn_payload(TcpSegmentDescriptor& tsd, uint32_t max) +void TcpNormalizer::trim_syn_payload( + TcpNormalizerState& tns, TcpSegmentDescriptor& tsd, uint32_t max) { if (tsd.get_seg_len() > max) - trim_payload(tsd, max, trim_syn, PC_TCP_TRIM_SYN); + trim_payload(tns, tsd, max, (NormMode)tns.trim_syn, PC_TCP_TRIM_SYN); } -void TcpNormalizer::trim_rst_payload(TcpSegmentDescriptor& tsd, uint32_t max) +void TcpNormalizer::trim_rst_payload( + TcpNormalizerState& tns, TcpSegmentDescriptor& tsd, uint32_t max) { if (tsd.get_seg_len() > max) - trim_payload(tsd, max, trim_rst, PC_TCP_TRIM_RST); + trim_payload(tns, tsd, max, (NormMode)tns.trim_rst, PC_TCP_TRIM_RST); } -void TcpNormalizer::trim_win_payload(TcpSegmentDescriptor& tsd, uint32_t max) +void TcpNormalizer::trim_win_payload( + TcpNormalizerState& tns, TcpSegmentDescriptor& tsd, uint32_t max) { if (tsd.get_seg_len() > max) - trim_payload(tsd, max, trim_win, PC_TCP_TRIM_WIN); + trim_payload(tns, tsd, max, (NormMode)tns.trim_win, PC_TCP_TRIM_WIN); } -void TcpNormalizer::trim_mss_payload(TcpSegmentDescriptor& tsd, uint32_t max) +void TcpNormalizer::trim_mss_payload( + TcpNormalizerState& tns, TcpSegmentDescriptor& tsd, uint32_t max) { if (tsd.get_seg_len() > max) - trim_payload(tsd, max, trim_mss, PC_TCP_TRIM_MSS); + trim_payload(tns, tsd, max, (NormMode)tns.trim_mss, PC_TCP_TRIM_MSS); } -void TcpNormalizer::ecn_tracker(const tcp::TCPHdr* tcph, bool req3way) +void TcpNormalizer::ecn_tracker( + TcpNormalizerState& tns, const tcp::TCPHdr* tcph, bool req3way) { if ( tcph->is_syn_ack() ) { - if ( !req3way || session->ecn ) - session->ecn = ((tcph->th_flags & (TH_ECE | TH_CWR)) == TH_ECE); + if ( !req3way || tns.session->ecn ) + tns.session->ecn = ((tcph->th_flags & (TH_ECE | TH_CWR)) == TH_ECE); } else if ( tcph->is_syn() ) - session->ecn = tcph->are_flags_set(TH_ECE | TH_CWR); + tns.session->ecn = tcph->are_flags_set(TH_ECE | TH_CWR); } -void TcpNormalizer::ecn_stripper(Packet* p) +void TcpNormalizer::ecn_stripper( + TcpNormalizerState& tns, Packet* p) { - if (!session->ecn && (p->ptrs.tcph->th_flags & (TH_ECE | TH_CWR))) + if (!tns.session->ecn && (p->ptrs.tcph->th_flags & (TH_ECE | TH_CWR))) { - if (strip_ecn == NORM_MODE_ON) + if (tns.strip_ecn == NORM_MODE_ON) { (const_cast(p->ptrs.tcph))->th_flags &= ~(TH_ECE | TH_CWR); p->packet_flags |= PKT_MODIFIED; } - tcp_norm_stats[PC_TCP_ECN_SSN][strip_ecn]++; + tcp_norm_stats[PC_TCP_ECN_SSN][tns.strip_ecn]++; } } // don't use the window if we may have missed scaling // one way zero window is uninitialized // two way zero window is actually closed (regardless of scaling) -uint32_t TcpNormalizer::get_stream_window(TcpSegmentDescriptor& tsd) +uint32_t TcpNormalizer::get_stream_window( + TcpNormalizerState& tns, TcpSegmentDescriptor& tsd) { int32_t window; - if ( tracker->get_snd_wnd() ) + if ( tns.tracker->get_snd_wnd() ) { - if ( !(session->flow->session_state & STREAM_STATE_MIDSTREAM ) ) - return tracker->get_snd_wnd(); + if ( !(tns.session->flow->session_state & STREAM_STATE_MIDSTREAM ) ) + return tns.tracker->get_snd_wnd(); } - else if ( session->flow->two_way_traffic() ) - return tracker->get_snd_wnd(); + else if ( tns.session->flow->two_way_traffic() ) + return tns.tracker->get_snd_wnd(); // ensure the data is in the window - window = tsd.get_end_seq() - tracker->r_win_base; + window = tsd.get_end_seq() - tns.tracker->r_win_base; if ( window < 0 ) window = 0; return (uint32_t)window; } -uint32_t TcpNormalizer::get_tcp_timestamp(TcpSegmentDescriptor& tsd, bool strip) +uint32_t TcpNormalizer::get_tcp_timestamp( + TcpNormalizerState& tns, TcpSegmentDescriptor& tsd, bool strip) { DebugMessage(DEBUG_STREAM_STATE, "Getting timestamp...\n"); @@ -201,7 +201,7 @@ uint32_t TcpNormalizer::get_tcp_timestamp(TcpSegmentDescriptor& tsd, bool strip) bool stripped = false; if (strip) - stripped = strip_tcp_timestamp(tsd, &opt, opt_block); + stripped = strip_tcp_timestamp(tns, tsd, &opt, (NormMode)tns.opt_block); if (!stripped) { @@ -218,15 +218,16 @@ uint32_t TcpNormalizer::get_tcp_timestamp(TcpSegmentDescriptor& tsd, bool strip) return TF_NONE; } -bool TcpNormalizer::validate_rst_seq_geq(TcpSegmentDescriptor& tsd) +bool TcpNormalizer::validate_rst_seq_geq( + TcpNormalizerState& tns, TcpSegmentDescriptor& tsd) { DebugFormat(DEBUG_STREAM_STATE, "Checking end_seq (%X) > r_win_base (%X) && seq (%X) < r_nxt_ack(%X)\n", - tsd.get_end_seq(), tracker->r_win_base, tsd.get_seg_seq(), tracker->r_nxt_ack + - get_stream_window(tsd)); + tsd.get_end_seq(), tns.tracker->r_win_base, tsd.get_seg_seq(), tns.tracker->r_nxt_ack + + get_stream_window(tns, tsd)); // FIXIT-H check for r_win_base == 0 is hack for uninitialized r_win_base, fix this - if ( ( tracker->r_nxt_ack == 0 ) || SEQ_GEQ(tsd.get_seg_seq(), tracker->r_nxt_ack) ) + if ( ( tns.tracker->r_nxt_ack == 0 ) || SEQ_GEQ(tsd.get_seg_seq(), tns.tracker->r_nxt_ack) ) { DebugMessage(DEBUG_STREAM_STATE, "rst is valid seq (>= next seq)!\n"); return true; @@ -236,21 +237,22 @@ bool TcpNormalizer::validate_rst_seq_geq(TcpSegmentDescriptor& tsd) return false; } -bool TcpNormalizer::validate_rst_end_seq_geq(TcpSegmentDescriptor& tsd) +bool TcpNormalizer::validate_rst_end_seq_geq( + TcpNormalizerState& tns, TcpSegmentDescriptor& tsd) { DebugFormat(DEBUG_STREAM_STATE, "Checking end_seq (%X) > r_win_base (%X) && seq (%X) < r_nxt_ack(%X)\n", - tsd.get_end_seq(), tracker->r_win_base, tsd.get_seg_seq(), tracker->r_nxt_ack + - get_stream_window(tsd)); + tsd.get_end_seq(), tns.tracker->r_win_base, tsd.get_seg_seq(), tns.tracker->r_nxt_ack + + get_stream_window(tns, tsd)); // FIXIT-H check for r_win_base == 0 is hack for uninitialized r_win_base, fix this - if ( tracker->r_win_base == 0 ) + if ( tns.tracker->r_win_base == 0 ) return true; - if ( SEQ_GEQ(tsd.get_end_seq(), tracker->r_win_base)) + if ( SEQ_GEQ(tsd.get_end_seq(), tns.tracker->r_win_base)) { // reset must be admitted when window closed - if (SEQ_LEQ(tsd.get_seg_seq(), tracker->r_win_base + get_stream_window(tsd))) + if (SEQ_LEQ(tsd.get_seg_seq(), tns.tracker->r_win_base + get_stream_window(tns, tsd))) { DebugMessage(DEBUG_STREAM_STATE, "rst is valid seq (within window)!\n"); return true; @@ -261,15 +263,16 @@ bool TcpNormalizer::validate_rst_end_seq_geq(TcpSegmentDescriptor& tsd) return false; } -bool TcpNormalizer::validate_rst_seq_eq(TcpSegmentDescriptor& tsd) +bool TcpNormalizer::validate_rst_seq_eq( + TcpNormalizerState& tns, TcpSegmentDescriptor& tsd) { DebugFormat(DEBUG_STREAM_STATE, "Checking end_seq (%X) > r_win_base (%X) && seq (%X) < r_nxt_ack(%X)\n", - tsd.get_end_seq(), tracker->r_win_base, tsd.get_seg_seq(), tracker->r_nxt_ack + - get_stream_window(tsd)); + tsd.get_end_seq(), tns.tracker->r_win_base, tsd.get_seg_seq(), + tns.tracker->r_nxt_ack + get_stream_window(tns, tsd)); // FIXIT-H check for r_nxt_ack == 0 is hack for uninitialized r_nxt_ack, fix this - if ( ( tracker->r_nxt_ack == 0 ) || SEQ_EQ(tsd.get_seg_seq(), tracker->r_nxt_ack) ) + if ( ( tns.tracker->r_nxt_ack == 0 ) || SEQ_EQ(tsd.get_seg_seq(), tns.tracker->r_nxt_ack) ) { DebugMessage(DEBUG_STREAM_STATE, "rst is valid seq (next seq)!\n"); return true; @@ -283,33 +286,35 @@ bool TcpNormalizer::validate_rst_seq_eq(TcpSegmentDescriptor& tsd) // 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(TcpSegmentDescriptor& tsd) +bool TcpNormalizer::validate_rst( + TcpNormalizerState& tns, TcpSegmentDescriptor& tsd) { - return validate_rst_seq_eq(tsd); + return validate_rst_seq_eq(tns, tsd); } -int TcpNormalizer::validate_paws_timestamp(TcpSegmentDescriptor& tsd) +int TcpNormalizer::validate_paws_timestamp( + TcpNormalizerState& tns, TcpSegmentDescriptor& tsd) { - if ( ( (int)( ( tsd.get_ts() - peer_tracker->get_ts_last() ) + paws_ts_fudge ) ) < 0 ) + if ( ( (int)( ( tsd.get_ts() - tns.peer_tracker->get_ts_last() ) + tns.paws_ts_fudge ) ) < 0 ) { DebugMessage(DEBUG_STREAM_STATE, "Packet outside PAWS window, dropping\n"); /* bail, we've got a packet outside the PAWS window! */ //inc_tcp_discards(); - ( ( TcpSession* )tsd.get_flow()->session )->tel.set_tcp_event(EVENT_BAD_TIMESTAMP); - packet_dropper(tsd, NORM_TCP_OPT); + tns.session->tel.set_tcp_event(EVENT_BAD_TIMESTAMP); + packet_dropper(tns, tsd, NORM_TCP_OPT); return ACTION_BAD_PKT; } - else if ( ( peer_tracker->get_ts_last() != 0 ) - && ( ( uint32_t )tsd.get_pkt()->pkth->ts.tv_sec > peer_tracker->get_ts_last_packet() + + else if ( ( tns.peer_tracker->get_ts_last() != 0 ) + && ( ( uint32_t )tsd.get_pkt()->pkth->ts.tv_sec > tns.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 %ld %u...\n", - tsd.get_pkt()->pkth->ts.tv_sec, peer_tracker->get_ts_last_packet() ); + tsd.get_pkt()->pkth->ts.tv_sec, tns.peer_tracker->get_ts_last_packet() ); //inc_tcp_discards(); - ( ( TcpSession* )tsd.get_flow()->session )->tel.set_tcp_event(EVENT_BAD_TIMESTAMP); - packet_dropper(tsd, NORM_TCP_OPT); + tns.session->tel.set_tcp_event(EVENT_BAD_TIMESTAMP); + packet_dropper(tns, tsd, NORM_TCP_OPT); return ACTION_BAD_PKT; } else @@ -319,20 +324,22 @@ int TcpNormalizer::validate_paws_timestamp(TcpSegmentDescriptor& tsd) } } -bool TcpNormalizer::is_paws_ts_checked_required(TcpSegmentDescriptor&) +bool TcpNormalizer::is_paws_ts_checked_required( + TcpNormalizerState&, TcpSegmentDescriptor&) { return true; } -int TcpNormalizer::validate_paws(TcpSegmentDescriptor& tsd) +int TcpNormalizer::validate_paws( + TcpNormalizerState& tns, TcpSegmentDescriptor& tsd) { - tcp_ts_flags = get_tcp_timestamp(tsd, false); - if ( tcp_ts_flags ) + tns.tcp_ts_flags = get_tcp_timestamp(tns, tsd, false); + if ( tns.tcp_ts_flags ) { - bool check_ts = is_paws_ts_checked_required(tsd); + bool check_ts = is_paws_ts_checked_required(tns, tsd); if ( check_ts ) - return validate_paws_timestamp(tsd); + return validate_paws_timestamp(tns, tsd); else return ACTION_NOTHING; } @@ -343,38 +350,39 @@ int TcpNormalizer::validate_paws(TcpSegmentDescriptor& tsd) // with the missing timestamp. Log an alert, but continue to process the packet DebugMessage(DEBUG_STREAM_STATE, "packet no timestamp, had one earlier from this side...ok for now...\n"); - ( ( TcpSession* )tsd.get_flow()->session )->tel.set_tcp_event(EVENT_NO_TIMESTAMP); + tns.session->tel.set_tcp_event(EVENT_NO_TIMESTAMP); /* Ignore the timestamp for this first packet, next one will checked. */ - if ( session->config->policy == StreamPolicy::OS_SOLARIS ) - tracker->clear_tf_flags(TF_TSTAMP); + if ( tns.session->config->policy == StreamPolicy::OS_SOLARIS ) + tns.tracker->clear_tf_flags(TF_TSTAMP); - packet_dropper(tsd, NORM_TCP_OPT); + packet_dropper(tns, tsd, NORM_TCP_OPT); return ACTION_NOTHING; } } -int TcpNormalizer::handle_paws_no_timestamps(TcpSegmentDescriptor& tsd) +int TcpNormalizer::handle_paws_no_timestamps( + TcpNormalizerState& tns, TcpSegmentDescriptor& tsd) { - tcp_ts_flags = get_tcp_timestamp(tsd, true); - if (tcp_ts_flags) + tns.tcp_ts_flags = get_tcp_timestamp(tns, tsd, true); + if (tns.tcp_ts_flags) { - if (!(peer_tracker->get_tf_flags() & TF_TSTAMP)) + if (!(tns.peer_tracker->get_tf_flags() & TF_TSTAMP)) { // SYN skipped, may have missed talker's timestamp , so set it now. if (tsd.get_ts() == 0) - peer_tracker->set_tf_flags(TF_TSTAMP | TF_TSTAMP_ZERO); + tns.peer_tracker->set_tf_flags(TF_TSTAMP | TF_TSTAMP_ZERO); else - peer_tracker->set_tf_flags(TF_TSTAMP); + tns.peer_tracker->set_tf_flags(TF_TSTAMP); } // Only valid to test this if listener is using timestamps. Otherwise, timestamp // in this packet is not used, regardless of its value. - if ( ( paws_drop_zero_ts && ( tsd.get_ts() == 0 ) ) && ( tracker->get_tf_flags() & - TF_TSTAMP ) ) + if ( ( tns.paws_drop_zero_ts && ( tsd.get_ts() == 0 ) ) && + ( tns.tracker->get_tf_flags() & TF_TSTAMP ) ) { DebugMessage(DEBUG_STREAM_STATE, "Packet with 0 timestamp, dropping\n"); - ( ( TcpSession* )tsd.get_flow()->session )->tel.set_tcp_event(EVENT_BAD_TIMESTAMP); + tns.session->tel.set_tcp_event(EVENT_BAD_TIMESTAMP); return ACTION_BAD_PKT; } } @@ -382,7 +390,8 @@ int TcpNormalizer::handle_paws_no_timestamps(TcpSegmentDescriptor& tsd) return ACTION_NOTHING; } -int TcpNormalizer::handle_paws(TcpSegmentDescriptor& tsd) +int TcpNormalizer::handle_paws( + TcpNormalizerState& tns, TcpSegmentDescriptor& tsd) { if ( tsd.get_tcph()->is_rst() ) return ACTION_NOTHING; @@ -396,26 +405,28 @@ int TcpNormalizer::handle_paws(TcpSegmentDescriptor& tsd) } #endif - if ((peer_tracker->get_tf_flags() & TF_TSTAMP) && (tracker->get_tf_flags() & TF_TSTAMP)) + if ((tns.peer_tracker->get_tf_flags() & TF_TSTAMP) && + (tns.tracker->get_tf_flags() & TF_TSTAMP)) { DebugMessage(DEBUG_STREAM_STATE, "Checking timestamps for PAWS\n"); - return validate_paws(tsd); + return validate_paws(tns, tsd); } else if (tsd.get_tcph()->is_syn_only()) { - tcp_ts_flags = get_tcp_timestamp(tsd, false); - if (tcp_ts_flags) - peer_tracker->set_tf_flags(TF_TSTAMP); + tns.tcp_ts_flags = get_tcp_timestamp(tns, tsd, false); + if (tns.tcp_ts_flags) + tns.peer_tracker->set_tf_flags(TF_TSTAMP); return ACTION_NOTHING; } else { - return handle_paws_no_timestamps(tsd); + return handle_paws_no_timestamps(tns, tsd); } } -uint16_t TcpNormalizer::set_urg_offset(const tcp::TCPHdr* tcph, uint16_t dsize) +uint16_t TcpNormalizer::set_urg_offset( + TcpNormalizerState&, const tcp::TCPHdr* tcph, uint16_t dsize) { uint16_t urg_offset = 0; diff --git a/src/stream/tcp/tcp_normalizer.h b/src/stream/tcp/tcp_normalizer.h index 6a186b943..27ea32163 100644 --- a/src/stream/tcp/tcp_normalizer.h +++ b/src/stream/tcp/tcp_normalizer.h @@ -22,9 +22,11 @@ #ifndef TCP_NORMALIZER_H #define TCP_NORMALIZER_H +#include "tcp_defs.h" + +#include "main/thread.h" #include "normalize/normalize.h" #include "protocols/tcp_options.h" -#include "stream/tcp/tcp_session.h" enum TcpPegCounts { @@ -41,127 +43,72 @@ enum TcpPegCounts extern THREAD_LOCAL PegCount tcp_norm_stats[PC_TCP_MAX][NORM_MODE_MAX]; +class TcpStreamSession; +class TcpStreamTracker; +class TcpSegmentDescriptor; + +struct TcpNormalizerState +{ + TcpStreamSession* session = nullptr; + TcpStreamTracker* tracker = nullptr; + TcpStreamTracker* peer_tracker = nullptr; + + StreamPolicy os_policy = StreamPolicy::OS_INVALID; + + int32_t paws_ts_fudge = 0; + int tcp_ts_flags = 0; + + int8_t trim_syn = 0; + int8_t trim_rst = 0; + int8_t trim_win = 0; + int8_t trim_mss = 0; + int8_t strip_ecn = 0; + int8_t tcp_block = 0; + int8_t opt_block = 0; + + bool tcp_ips_enabled = false; + bool paws_drop_zero_ts = false; +}; + class TcpNormalizer { public: - - virtual ~TcpNormalizer( ) = default; - - 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 snort::tcp::TCPHdr*, bool req3way); - virtual void ecn_stripper(snort::Packet*); - virtual uint32_t get_stream_window(TcpSegmentDescriptor&); - virtual uint32_t get_tcp_timestamp(TcpSegmentDescriptor&, bool strip); - virtual int handle_paws(TcpSegmentDescriptor&); - virtual bool validate_rst(TcpSegmentDescriptor&); - virtual int handle_repeated_syn(TcpSegmentDescriptor&) = 0; - virtual uint16_t set_urg_offset(const snort::tcp::TCPHdr* tcph, uint16_t dsize); + using State = TcpNormalizerState; + + virtual ~TcpNormalizer() = default; + + virtual void init(State&) { } + virtual bool packet_dropper(State&, TcpSegmentDescriptor&, NormFlags); + virtual void trim_syn_payload(State&, TcpSegmentDescriptor&, uint32_t max = 0); + virtual void trim_rst_payload(State&, TcpSegmentDescriptor&, uint32_t max = 0); + virtual void trim_win_payload(State&, TcpSegmentDescriptor&, uint32_t max = 0); + virtual void trim_mss_payload(State&, TcpSegmentDescriptor&, uint32_t max = 0); + virtual void ecn_tracker(State&, const snort::tcp::TCPHdr*, bool req3way); + virtual void ecn_stripper(State&, snort::Packet*); + virtual uint32_t get_stream_window(State&, TcpSegmentDescriptor&); + virtual uint32_t get_tcp_timestamp(State&, TcpSegmentDescriptor&, bool strip); + virtual int handle_paws(State&, TcpSegmentDescriptor&); + virtual bool validate_rst(State&, TcpSegmentDescriptor&); + virtual int handle_repeated_syn(State&, TcpSegmentDescriptor&) = 0; + virtual uint16_t set_urg_offset(State&, const snort::tcp::TCPHdr* tcph, uint16_t dsize); static const PegInfo* get_normalization_pegs(); static NormPegs get_normalization_counts(unsigned&); - void set_peer_tracker(TcpStreamTracker* peer_tracker) - { - this->peer_tracker = peer_tracker; - } - - StreamPolicy get_os_policy() const - { - return os_policy; - } - - bool is_paws_drop_zero_ts() const - { - return paws_drop_zero_ts; - } - - int32_t get_paws_ts_fudge() const - { - return paws_ts_fudge; - } - - NormMode get_opt_block() const - { - return opt_block; - } - - NormMode get_strip_ecn() const - { - return strip_ecn; - } - - NormMode get_tcp_block() const - { - return tcp_block; - } - - NormMode get_trim_rst() const - { - return trim_rst; - } - - NormMode get_trim_syn() const - { - return trim_syn; - } - - NormMode get_trim_mss() const - { - return trim_mss; - } - - NormMode get_trim_win() const - { - return trim_win; - } - - bool is_tcp_ips_enabled() const - { - return tcp_ips_enabled; - } - - bool handling_timestamps() const - { - return tcp_ts_flags != TF_NONE; - } - - uint32_t get_timestamp_flags() - { - return tcp_ts_flags; - } - protected: - TcpNormalizer(StreamPolicy, TcpSession*, TcpStreamTracker*); - virtual void trim_payload(TcpSegmentDescriptor&, uint32_t, NormMode, TcpPegCounts); - virtual bool strip_tcp_timestamp(TcpSegmentDescriptor&, const snort::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&); - virtual int handle_paws_no_timestamps(TcpSegmentDescriptor&); - - StreamPolicy os_policy; - TcpSession* session = nullptr; - TcpStreamTracker* tracker = nullptr; - TcpStreamTracker* peer_tracker = nullptr; - bool tcp_ips_enabled; - NormMode trim_syn; - NormMode trim_rst; - NormMode trim_win; - NormMode trim_mss; - NormMode strip_ecn; - NormMode tcp_block; - NormMode opt_block; - int32_t paws_ts_fudge = 0; - bool paws_drop_zero_ts = true; - int tcp_ts_flags = 0; + TcpNormalizer() = default; + + virtual void trim_payload(State&, TcpSegmentDescriptor&, uint32_t, NormMode, TcpPegCounts); + virtual bool strip_tcp_timestamp( + State&, TcpSegmentDescriptor&, const snort::tcp::TcpOption*, NormMode); + virtual bool validate_rst_seq_geq(State&, TcpSegmentDescriptor&); + virtual bool validate_rst_end_seq_geq(State&, TcpSegmentDescriptor&); + virtual bool validate_rst_seq_eq(State&, TcpSegmentDescriptor&); + + virtual int validate_paws_timestamp(State&, TcpSegmentDescriptor&); + virtual bool is_paws_ts_checked_required(State&, TcpSegmentDescriptor&); + virtual int validate_paws(State&, TcpSegmentDescriptor&); + virtual int handle_paws_no_timestamps(State&, TcpSegmentDescriptor&); }; #endif diff --git a/src/stream/tcp/tcp_normalizers.cc b/src/stream/tcp/tcp_normalizers.cc index 4b52552d4..303c52037 100644 --- a/src/stream/tcp/tcp_normalizers.cc +++ b/src/stream/tcp/tcp_normalizers.cc @@ -26,180 +26,166 @@ #include "tcp_normalizers.h" #include "tcp_module.h" +#include "stream/libtcp/tcp_segment_descriptor.h" +#include "stream/libtcp/tcp_stream_session.h" +#include "stream/libtcp/tcp_stream_tracker.h" using namespace snort; class TcpNormalizerFirst : public TcpNormalizer { public: - TcpNormalizerFirst(TcpSession* session, TcpStreamTracker* tracker) : - TcpNormalizer(StreamPolicy::OS_FIRST, session, tracker) - { } + TcpNormalizerFirst() = default; - int handle_repeated_syn(TcpSegmentDescriptor&) override; + int handle_repeated_syn(TcpNormalizerState&, TcpSegmentDescriptor&) override; }; class TcpNormalizerLast : public TcpNormalizer { public: - TcpNormalizerLast(TcpSession* session, TcpStreamTracker* tracker) : - TcpNormalizer(StreamPolicy::OS_LAST, session, tracker) - { } + TcpNormalizerLast() = default; - int handle_repeated_syn(TcpSegmentDescriptor&) override; + int handle_repeated_syn(TcpNormalizerState&, TcpSegmentDescriptor&) override; }; class TcpNormalizerLinux : public TcpNormalizer { public: - TcpNormalizerLinux(TcpSession* session, TcpStreamTracker* tracker) : - TcpNormalizer(StreamPolicy::OS_LINUX, session, tracker) + TcpNormalizerLinux() = default; + + void init(TcpNormalizerState& tns) override { // Linux 2.6 accepts timestamp values that are off by one. so set fudge factor */ - paws_ts_fudge = 1; + tns.paws_ts_fudge = 1; } - 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; + bool validate_rst(TcpNormalizerState&, TcpSegmentDescriptor&) override; + bool is_paws_ts_checked_required(TcpNormalizerState&, TcpSegmentDescriptor&) override; + int handle_repeated_syn(TcpNormalizerState&, TcpSegmentDescriptor&) override; + uint16_t set_urg_offset( + TcpNormalizerState&, const tcp::TCPHdr* tcph, uint16_t dsize) override; }; class TcpNormalizerOldLinux : public TcpNormalizer { public: - TcpNormalizerOldLinux(TcpSession* session, TcpStreamTracker* tracker) : - TcpNormalizer(StreamPolicy::OS_OLD_LINUX, session, tracker) - { - paws_drop_zero_ts = false; - } + TcpNormalizerOldLinux() = default; - 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; + void init(TcpNormalizerState& tns) override + { tns.paws_drop_zero_ts = false; } + + bool validate_rst(TcpNormalizerState&, TcpSegmentDescriptor&) override; + bool is_paws_ts_checked_required(TcpNormalizerState&, TcpSegmentDescriptor&) override; + int handle_repeated_syn(TcpNormalizerState&, TcpSegmentDescriptor&) override; + uint16_t set_urg_offset( + TcpNormalizerState&, const tcp::TCPHdr* tcph, uint16_t dsize) override; }; class TcpNormalizerBSD : public TcpNormalizer { public: - TcpNormalizerBSD(TcpSession* session, TcpStreamTracker* tracker) : - TcpNormalizer(StreamPolicy::OS_BSD, session, tracker) - { } + TcpNormalizerBSD() = default; - bool validate_rst(TcpSegmentDescriptor&) override; - int handle_repeated_syn(TcpSegmentDescriptor&) override; + bool validate_rst(TcpNormalizerState&, TcpSegmentDescriptor&) override; + int handle_repeated_syn(TcpNormalizerState&, TcpSegmentDescriptor&) override; }; class TcpNormalizerMacOS : public TcpNormalizer { public: - TcpNormalizerMacOS(TcpSession* session, TcpStreamTracker* tracker) : - TcpNormalizer(StreamPolicy::OS_MACOS, session, tracker) - { } + TcpNormalizerMacOS() = default; - int handle_repeated_syn(TcpSegmentDescriptor&) override; + int handle_repeated_syn(TcpNormalizerState&, TcpSegmentDescriptor&) override; }; class TcpNormalizerSolaris : public TcpNormalizer { public: - TcpNormalizerSolaris(TcpSession* session, TcpStreamTracker* tracker) : - TcpNormalizer(StreamPolicy::OS_SOLARIS, session, tracker) - { - paws_drop_zero_ts = false; - } + TcpNormalizerSolaris() = default; + + void init(TcpNormalizerState& tns) override + { tns.paws_drop_zero_ts = false; } - bool validate_rst(TcpSegmentDescriptor&) override; - int handle_repeated_syn(TcpSegmentDescriptor&) override; + bool validate_rst(TcpNormalizerState&, TcpSegmentDescriptor&) override; + int handle_repeated_syn(TcpNormalizerState&, TcpSegmentDescriptor&) override; }; class TcpNormalizerIrix : public TcpNormalizer { public: - TcpNormalizerIrix(TcpSession* session, TcpStreamTracker* tracker) : - TcpNormalizer(StreamPolicy::OS_IRIX, session, tracker) - { } + TcpNormalizerIrix() = default; - int handle_repeated_syn(TcpSegmentDescriptor&) override; + int handle_repeated_syn(TcpNormalizerState&, TcpSegmentDescriptor&) override; }; class TcpNormalizerHpux11 : public TcpNormalizer { public: - TcpNormalizerHpux11(TcpSession* session, TcpStreamTracker* tracker) : - TcpNormalizer(StreamPolicy::OS_HPUX11, session, tracker) - { } + TcpNormalizerHpux11() = default; - bool validate_rst(TcpSegmentDescriptor&) override; - bool is_paws_ts_checked_required(TcpSegmentDescriptor&) override; - int handle_repeated_syn(TcpSegmentDescriptor&) override; + bool validate_rst(TcpNormalizerState&, TcpSegmentDescriptor&) override; + bool is_paws_ts_checked_required(TcpNormalizerState&, TcpSegmentDescriptor&) override; + int handle_repeated_syn(TcpNormalizerState&, TcpSegmentDescriptor&) override; }; class TcpNormalizerHpux10 : public TcpNormalizer { public: - TcpNormalizerHpux10(TcpSession* session, TcpStreamTracker* tracker) : - TcpNormalizer(StreamPolicy::OS_HPUX10, session, tracker) - { } + TcpNormalizerHpux10() = default; - int handle_repeated_syn(TcpSegmentDescriptor&) override; + int handle_repeated_syn(TcpNormalizerState&, TcpSegmentDescriptor&) override; }; class TcpNormalizerWindows : public TcpNormalizer { public: - TcpNormalizerWindows(TcpSession* session, TcpStreamTracker* tracker) : - TcpNormalizer(StreamPolicy::OS_WINDOWS, session, tracker) - { - paws_drop_zero_ts = false; - } + TcpNormalizerWindows() = default; - bool is_paws_ts_checked_required(TcpSegmentDescriptor&) override; - int handle_repeated_syn(TcpSegmentDescriptor&) override; + void init(TcpNormalizerState& tns) override + { tns.paws_drop_zero_ts = false; } + + bool is_paws_ts_checked_required(TcpNormalizerState&, TcpSegmentDescriptor&) override; + int handle_repeated_syn(TcpNormalizerState&, TcpSegmentDescriptor&) override; }; class TcpNormalizerWindows2K3 : public TcpNormalizer { public: - TcpNormalizerWindows2K3(TcpSession* session, TcpStreamTracker* tracker) : - TcpNormalizer(StreamPolicy::OS_WINDOWS2K3, session, tracker) - { - paws_drop_zero_ts = false; - } + TcpNormalizerWindows2K3() = default; + + void init(TcpNormalizerState& tns) override + { tns.paws_drop_zero_ts = false; } - bool is_paws_ts_checked_required(TcpSegmentDescriptor&) override; - int handle_repeated_syn(TcpSegmentDescriptor&) override; + bool is_paws_ts_checked_required(TcpNormalizerState&, TcpSegmentDescriptor&) override; + int handle_repeated_syn(TcpNormalizerState&, TcpSegmentDescriptor&) override; }; class TcpNormalizerVista : public TcpNormalizer { public: - TcpNormalizerVista(TcpSession* session, TcpStreamTracker* tracker) : - TcpNormalizer(StreamPolicy::OS_VISTA, session, tracker) - { - paws_drop_zero_ts = false; - } + TcpNormalizerVista() = default; - bool is_paws_ts_checked_required(TcpSegmentDescriptor&) override; - int handle_repeated_syn(TcpSegmentDescriptor&) override; + void init(TcpNormalizerState& tns) override + { tns.paws_drop_zero_ts = false; } + + bool is_paws_ts_checked_required(TcpNormalizerState&, TcpSegmentDescriptor&) override; + int handle_repeated_syn(TcpNormalizerState&, TcpSegmentDescriptor&) override; }; class TcpNormalizerProxy : public TcpNormalizer { public: - TcpNormalizerProxy(TcpSession* session, TcpStreamTracker* tracker) : - TcpNormalizer(StreamPolicy::OS_PROXY, session, tracker) - { } + TcpNormalizerProxy() = default; - bool validate_rst(TcpSegmentDescriptor&) override; - int handle_paws(TcpSegmentDescriptor&) override; - int handle_repeated_syn(TcpSegmentDescriptor&) override; + bool validate_rst(TcpNormalizerState&, TcpSegmentDescriptor&) override; + int handle_paws(TcpNormalizerState&, TcpSegmentDescriptor&) override; + int handle_repeated_syn(TcpNormalizerState&, TcpSegmentDescriptor&) override; }; -static inline int handle_repeated_syn_mswin(TcpStreamTracker* talker, TcpStreamTracker* listener, - TcpSegmentDescriptor& tsd, TcpSession* session) +static inline int handle_repeated_syn_mswin( + TcpStreamTracker* talker, TcpStreamTracker* listener, + TcpSegmentDescriptor& tsd, TcpStreamSession* session) { /* Windows has some strange behavior here. If the sequence of the reset is the * next expected sequence, it Resets. Otherwise it ignores the 2nd SYN. @@ -221,8 +207,8 @@ static inline int handle_repeated_syn_mswin(TcpStreamTracker* talker, TcpStreamT } } -static inline int handle_repeated_syn_bsd(TcpStreamTracker* talker, TcpSegmentDescriptor& tsd, - TcpSession* session) +static inline int handle_repeated_syn_bsd( + TcpStreamTracker* talker, TcpSegmentDescriptor& tsd, TcpStreamSession* session) { /* If its not a retransmission of the actual SYN... RESET */ if (!SEQ_EQ(tsd.get_seg_seq(), talker->get_iss())) @@ -243,8 +229,8 @@ static inline int handle_repeated_syn_bsd(TcpStreamTracker* talker, TcpSegmentDe } // Linux, Win2k3 et al. do not support timestamps if the 3whs used a 0 timestamp. -static inline bool paws_3whs_zero_ts_not_supported(TcpStreamTracker* talker, - TcpStreamTracker* listener) +static inline bool paws_3whs_zero_ts_not_supported( + TcpStreamTracker* talker, TcpStreamTracker* listener) { bool check_ts = true; @@ -259,8 +245,8 @@ static inline bool paws_3whs_zero_ts_not_supported(TcpStreamTracker* talker, } // Older Linux ( <= 2.2 kernel ), Win32 (non 2K3) allow the 3whs to use a 0 timestamp. -static inline bool paws_3whs_zero_ts_supported(TcpStreamTracker* talker, - TcpStreamTracker* listener, TcpSegmentDescriptor& tsd) +static inline bool paws_3whs_zero_ts_supported( + TcpStreamTracker* talker, TcpStreamTracker* listener, TcpSegmentDescriptor& tsd) { bool check_ts = true; @@ -296,67 +282,80 @@ static inline uint16_t set_urg_offset_linux(const tcp::TCPHdr* tcph, uint16_t ds return urg_offset; } -int TcpNormalizerFirst::handle_repeated_syn(TcpSegmentDescriptor& tsd) +int TcpNormalizerFirst::handle_repeated_syn( + TcpNormalizerState& tns, TcpSegmentDescriptor& tsd) { - return handle_repeated_syn_bsd(peer_tracker, tsd, session); + return handle_repeated_syn_bsd(tns.peer_tracker, tsd, tns.session); } -int TcpNormalizerLast::handle_repeated_syn(TcpSegmentDescriptor& tsd) +int TcpNormalizerLast::handle_repeated_syn( + TcpNormalizerState& tns, TcpSegmentDescriptor& tsd) { - return handle_repeated_syn_bsd(peer_tracker, tsd, session); + return handle_repeated_syn_bsd(tns.peer_tracker, tsd, tns.session); } -bool TcpNormalizerLinux::validate_rst(TcpSegmentDescriptor& tsd) +bool TcpNormalizerLinux::validate_rst( + TcpNormalizerState& tns, TcpSegmentDescriptor& tsd) { - return validate_rst_end_seq_geq(tsd); + return validate_rst_end_seq_geq(tns, tsd); } -bool TcpNormalizerLinux::is_paws_ts_checked_required(TcpSegmentDescriptor&) +bool TcpNormalizerLinux::is_paws_ts_checked_required( + TcpNormalizerState& tns, TcpSegmentDescriptor&) { - return paws_3whs_zero_ts_not_supported(peer_tracker, tracker); + return paws_3whs_zero_ts_not_supported(tns.peer_tracker, tns.tracker); } -int TcpNormalizerLinux::handle_repeated_syn(TcpSegmentDescriptor& tsd) +int TcpNormalizerLinux::handle_repeated_syn( + TcpNormalizerState& tns, TcpSegmentDescriptor& tsd) { - return handle_repeated_syn_bsd(peer_tracker, tsd, session); + return handle_repeated_syn_bsd(tns.peer_tracker, tsd, tns.session); } -uint16_t TcpNormalizerLinux::set_urg_offset(const tcp::TCPHdr* tcph, uint16_t dsize) +uint16_t TcpNormalizerLinux::set_urg_offset( + TcpNormalizerState&, const tcp::TCPHdr* tcph, uint16_t dsize) { return set_urg_offset_linux(tcph, dsize); } -bool TcpNormalizerOldLinux::validate_rst(TcpSegmentDescriptor& tsd) +bool TcpNormalizerOldLinux::validate_rst( + TcpNormalizerState& tns, TcpSegmentDescriptor& tsd) { - return validate_rst_end_seq_geq(tsd); + return validate_rst_end_seq_geq(tns, tsd); } -bool TcpNormalizerOldLinux::is_paws_ts_checked_required(TcpSegmentDescriptor& tsd) +bool TcpNormalizerOldLinux::is_paws_ts_checked_required( + TcpNormalizerState& tns, TcpSegmentDescriptor& tsd) { - return paws_3whs_zero_ts_supported(peer_tracker, tracker, tsd); + return paws_3whs_zero_ts_supported(tns.peer_tracker, tns.tracker, tsd); } -int TcpNormalizerOldLinux::handle_repeated_syn(TcpSegmentDescriptor& tsd) +int TcpNormalizerOldLinux::handle_repeated_syn( + TcpNormalizerState& tns, TcpSegmentDescriptor& tsd) { - return handle_repeated_syn_bsd(peer_tracker, tsd, session); + return handle_repeated_syn_bsd(tns.peer_tracker, tsd, tns.session); } -uint16_t TcpNormalizerOldLinux::set_urg_offset(const tcp::TCPHdr* tcph, uint16_t dsize) +uint16_t TcpNormalizerOldLinux::set_urg_offset( + TcpNormalizerState&, const tcp::TCPHdr* tcph, uint16_t dsize) { return set_urg_offset_linux(tcph, dsize); } -bool TcpNormalizerBSD::validate_rst(TcpSegmentDescriptor& tsd) +bool TcpNormalizerBSD::validate_rst( + TcpNormalizerState& tns, TcpSegmentDescriptor& tsd) { - return validate_rst_end_seq_geq(tsd); + return validate_rst_end_seq_geq(tns, tsd); } -int TcpNormalizerBSD::handle_repeated_syn(TcpSegmentDescriptor& tsd) +int TcpNormalizerBSD::handle_repeated_syn( + TcpNormalizerState& tns, TcpSegmentDescriptor& tsd) { - return handle_repeated_syn_bsd(peer_tracker, tsd, session); + return handle_repeated_syn_bsd(tns.peer_tracker, tsd, tns.session); } -int TcpNormalizerMacOS::handle_repeated_syn(TcpSegmentDescriptor&) +int TcpNormalizerMacOS::handle_repeated_syn( + TcpNormalizerState&, TcpSegmentDescriptor&) { /* MACOS ignores a 2nd SYN, regardless of the sequence number. */ DebugMessage(DEBUG_STREAM_STATE, @@ -365,173 +364,182 @@ int TcpNormalizerMacOS::handle_repeated_syn(TcpSegmentDescriptor&) return ACTION_NOTHING; } -bool TcpNormalizerSolaris::validate_rst(TcpSegmentDescriptor& tsd) +bool TcpNormalizerSolaris::validate_rst( + TcpNormalizerState& tns, TcpSegmentDescriptor& tsd) { - return validate_rst_end_seq_geq(tsd); + return validate_rst_end_seq_geq(tns, tsd); } -int TcpNormalizerSolaris::handle_repeated_syn(TcpSegmentDescriptor& tsd) +int TcpNormalizerSolaris::handle_repeated_syn( + TcpNormalizerState& tns, TcpSegmentDescriptor& tsd) { - return handle_repeated_syn_bsd(peer_tracker, tsd, session); + return handle_repeated_syn_bsd(tns.peer_tracker, tsd, tns.session); } -int TcpNormalizerIrix::handle_repeated_syn(TcpSegmentDescriptor& tsd) +int TcpNormalizerIrix::handle_repeated_syn( + TcpNormalizerState& tns, TcpSegmentDescriptor& tsd) { - return handle_repeated_syn_bsd(peer_tracker, tsd, session); + return handle_repeated_syn_bsd(tns.peer_tracker, tsd, tns.session); } -bool TcpNormalizerHpux11::validate_rst(TcpSegmentDescriptor& tsd) +bool TcpNormalizerHpux11::validate_rst( + TcpNormalizerState& tns, TcpSegmentDescriptor& tsd) { - return validate_rst_seq_geq(tsd); + return validate_rst_seq_geq(tns, tsd); } -bool TcpNormalizerHpux11::is_paws_ts_checked_required(TcpSegmentDescriptor& tsd) +bool TcpNormalizerHpux11::is_paws_ts_checked_required( + TcpNormalizerState& tns, TcpSegmentDescriptor& tsd) { /* HPUX 11 ignores timestamps for out of order segments */ - if ((tracker->get_tf_flags() & TF_MISSING_PKT) || !SEQ_EQ(tracker->r_nxt_ack, + if ((tns.tracker->get_tf_flags() & TF_MISSING_PKT) || !SEQ_EQ(tns.tracker->r_nxt_ack, tsd.get_seg_seq())) return false; else return true; } -int TcpNormalizerHpux11::handle_repeated_syn(TcpSegmentDescriptor& tsd) +int TcpNormalizerHpux11::handle_repeated_syn( + TcpNormalizerState& tns, TcpSegmentDescriptor& tsd) { - return handle_repeated_syn_bsd(peer_tracker, tsd, session); + return handle_repeated_syn_bsd(tns.peer_tracker, tsd, tns.session); } -int TcpNormalizerHpux10::handle_repeated_syn(TcpSegmentDescriptor& tsd) +int TcpNormalizerHpux10::handle_repeated_syn( + TcpNormalizerState& tns, TcpSegmentDescriptor& tsd) { - return handle_repeated_syn_bsd(peer_tracker, tsd, session); + return handle_repeated_syn_bsd(tns.peer_tracker, tsd, tns.session); } -bool TcpNormalizerWindows::is_paws_ts_checked_required(TcpSegmentDescriptor& tsd) +bool TcpNormalizerWindows::is_paws_ts_checked_required( + TcpNormalizerState& tns, TcpSegmentDescriptor& tsd) { - return paws_3whs_zero_ts_supported(peer_tracker, tracker, tsd); + return paws_3whs_zero_ts_supported(tns.peer_tracker, tns.tracker, tsd); } -int TcpNormalizerWindows::handle_repeated_syn(TcpSegmentDescriptor& tsd) +int TcpNormalizerWindows::handle_repeated_syn( + TcpNormalizerState& tns, TcpSegmentDescriptor& tsd) { - return handle_repeated_syn_mswin(peer_tracker, tracker, tsd, session); + return handle_repeated_syn_mswin(tns.peer_tracker, tns.tracker, tsd, tns.session); } -int TcpNormalizerWindows2K3::handle_repeated_syn(TcpSegmentDescriptor& tsd) +int TcpNormalizerWindows2K3::handle_repeated_syn( + TcpNormalizerState& tns, TcpSegmentDescriptor& tsd) { - return handle_repeated_syn_mswin(peer_tracker, tracker, tsd, session); + return handle_repeated_syn_mswin(tns.peer_tracker, tns.tracker, tsd, tns.session); } -bool TcpNormalizerWindows2K3::is_paws_ts_checked_required(TcpSegmentDescriptor&) +bool TcpNormalizerWindows2K3::is_paws_ts_checked_required( + TcpNormalizerState& tns, TcpSegmentDescriptor&) { - return paws_3whs_zero_ts_not_supported(peer_tracker, tracker); + return paws_3whs_zero_ts_not_supported(tns.peer_tracker, tns.tracker); } -bool TcpNormalizerVista::is_paws_ts_checked_required(TcpSegmentDescriptor& tsd) +bool TcpNormalizerVista::is_paws_ts_checked_required( + TcpNormalizerState& tns, TcpSegmentDescriptor& tsd) { - return paws_3whs_zero_ts_supported(peer_tracker, tracker, tsd); + return paws_3whs_zero_ts_supported(tns.peer_tracker, tns.tracker, tsd); } -int TcpNormalizerVista::handle_repeated_syn(TcpSegmentDescriptor& tsd) +int TcpNormalizerVista::handle_repeated_syn( + TcpNormalizerState& tns, TcpSegmentDescriptor& tsd) { - return handle_repeated_syn_mswin(peer_tracker, tracker, tsd, session); + return handle_repeated_syn_mswin(tns.peer_tracker, tns.tracker, tsd, tns.session); } -bool TcpNormalizerProxy::validate_rst(TcpSegmentDescriptor& tsd) +bool TcpNormalizerProxy::validate_rst( + TcpNormalizerState& tns, TcpSegmentDescriptor& tsd) { #ifndef DEBUG_MSGS UNUSED(tsd); #endif // FIXIT-L will session->flow ever be null? convert to assert if possible - if ( session->flow ) + if ( tns.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", - tsd.get_end_seq(), tracker->r_win_base, tsd.get_seg_seq(), tracker->r_nxt_ack + - get_stream_window(tsd)); + tsd.get_end_seq(), tns.tracker->r_win_base, tsd.get_seg_seq(), tns.tracker->r_nxt_ack + + get_stream_window(tns, tsd)); } return false; } -int TcpNormalizerProxy::handle_paws(TcpSegmentDescriptor&) +int TcpNormalizerProxy::handle_paws( + TcpNormalizerState&, TcpSegmentDescriptor&) { return ACTION_NOTHING; } -int TcpNormalizerProxy::handle_repeated_syn(TcpSegmentDescriptor&) +int TcpNormalizerProxy::handle_repeated_syn( + TcpNormalizerState&, TcpSegmentDescriptor&) { return ACTION_NOTHING; } -TcpNormalizer* TcpNormalizerFactory::create(TcpSession* session, StreamPolicy os_policy, - TcpStreamTracker* tracker, TcpStreamTracker* peer) +void TcpNormalizerPolicy::init(StreamPolicy os, TcpStreamSession* ssn, TcpStreamTracker* trk, TcpStreamTracker* peer) { - TcpNormalizer* normalizer; + tns.os_policy = os; + tns.session = ssn; + tns.tracker = trk; + tns.peer_tracker = peer; - switch (os_policy) - { - case StreamPolicy::OS_FIRST: - normalizer = new TcpNormalizerFirst(session, tracker); - break; - - case StreamPolicy::OS_LAST: - normalizer = new TcpNormalizerLast(session, tracker); - break; - - case StreamPolicy::OS_LINUX: - normalizer = new TcpNormalizerLinux(session, tracker); - break; - - case StreamPolicy::OS_OLD_LINUX: - normalizer = new TcpNormalizerOldLinux(session, tracker); - break; - - case StreamPolicy::OS_BSD: - normalizer = new TcpNormalizerBSD(session, tracker); - break; - - case StreamPolicy::OS_MACOS: - normalizer = new TcpNormalizerMacOS(session, tracker); - break; - - case StreamPolicy::OS_SOLARIS: - normalizer = new TcpNormalizerSolaris(session, tracker); - break; + tns.paws_ts_fudge = 0; + tns.paws_drop_zero_ts = true; + tns.tcp_ts_flags = 0; - case StreamPolicy::OS_IRIX: - normalizer = new TcpNormalizerIrix(session, tracker); - break; + tns.tcp_ips_enabled = Normalize_IsEnabled(NORM_TCP_IPS); + tns.trim_syn = Normalize_GetMode(NORM_TCP_TRIM_SYN); + tns.trim_rst = Normalize_GetMode(NORM_TCP_TRIM_RST); + tns.trim_win = Normalize_GetMode(NORM_TCP_TRIM_WIN); + tns.trim_mss = Normalize_GetMode(NORM_TCP_TRIM_MSS); + tns.strip_ecn = Normalize_GetMode(NORM_TCP_ECN_STR); + tns.tcp_block = Normalize_GetMode(NORM_TCP_BLOCK); + tns.opt_block = Normalize_GetMode(NORM_TCP_OPT); - case StreamPolicy::OS_HPUX11: - normalizer = new TcpNormalizerHpux11(session, tracker); - break; - - case StreamPolicy::OS_HPUX10: - normalizer = new TcpNormalizerHpux10(session, tracker); - break; - - case StreamPolicy::OS_WINDOWS: - normalizer = new TcpNormalizerWindows(session, tracker); - break; - - case StreamPolicy::OS_WINDOWS2K3: - normalizer = new TcpNormalizerWindows2K3(session, tracker); - break; + norm = TcpNormalizerFactory::create(os); + norm->init(tns); +} - case StreamPolicy::OS_VISTA: - normalizer = new TcpNormalizerVista(session, tracker); - break; +TcpNormalizer* TcpNormalizerFactory::create(StreamPolicy os_policy) +{ + static TcpNormalizerFirst first; + static TcpNormalizerLast last; + static TcpNormalizerLinux linux; + static TcpNormalizerOldLinux old_linux; + static TcpNormalizerBSD bsd; + static TcpNormalizerMacOS mac_os; + static TcpNormalizerSolaris solaris; + static TcpNormalizerIrix irix; + static TcpNormalizerHpux11 hpux11; + static TcpNormalizerHpux10 hpux10; + static TcpNormalizerWindows windows; + static TcpNormalizerWindows2K3 windows_2K3; + static TcpNormalizerVista vista; + static TcpNormalizerProxy proxy; - case StreamPolicy::OS_PROXY: - normalizer = new TcpNormalizerProxy(session, tracker); - break; + TcpNormalizer* normalizer; - default: - normalizer = new TcpNormalizerBSD(session, tracker); - break; + switch (os_policy) + { + case StreamPolicy::OS_FIRST: normalizer = &first; break; + case StreamPolicy::OS_LAST: normalizer = &last; break; + case StreamPolicy::OS_LINUX: normalizer = &linux; break; + case StreamPolicy::OS_OLD_LINUX: normalizer = &old_linux; break; + case StreamPolicy::OS_BSD: normalizer = &bsd; break; + case StreamPolicy::OS_MACOS: normalizer = &mac_os; break; + case StreamPolicy::OS_SOLARIS: normalizer = &solaris; break; + case StreamPolicy::OS_IRIX: normalizer = &irix; break; + case StreamPolicy::OS_HPUX11: normalizer = &hpux11; break; + case StreamPolicy::OS_HPUX10: normalizer = &hpux10; break; + case StreamPolicy::OS_WINDOWS: normalizer = &windows; break; + case StreamPolicy::OS_WINDOWS2K3: normalizer = &windows_2K3; break; + case StreamPolicy::OS_VISTA: normalizer = &vista; break; + case StreamPolicy::OS_PROXY: normalizer = &proxy; break; + default: normalizer = &bsd; break; } - normalizer->set_peer_tracker(peer); return normalizer; } diff --git a/src/stream/tcp/tcp_normalizers.h b/src/stream/tcp/tcp_normalizers.h index 23c51849e..025c47878 100644 --- a/src/stream/tcp/tcp_normalizers.h +++ b/src/stream/tcp/tcp_normalizers.h @@ -24,10 +24,106 @@ #include "stream/tcp/tcp_normalizer.h" +class TcpStreamSession; +class TcpStreamSession; + class TcpNormalizerFactory { public: - static TcpNormalizer* create(TcpSession*, StreamPolicy, TcpStreamTracker*, TcpStreamTracker*); + static TcpNormalizer* create(StreamPolicy); +}; + +class TcpNormalizerPolicy +{ +public: + TcpNormalizerPolicy() = default; + ~TcpNormalizerPolicy() = default; + + void init(StreamPolicy os, TcpStreamSession* ssn, TcpStreamTracker* trk, TcpStreamTracker* peer); + void reset() + { init(StreamPolicy::OS_INVALID, nullptr, nullptr, nullptr); } + + bool packet_dropper(TcpSegmentDescriptor& tsd, NormFlags nflags) + { return norm->packet_dropper(tns, tsd, nflags); } + + void trim_syn_payload(TcpSegmentDescriptor& tsd, uint32_t max = 0) + { norm->trim_syn_payload(tns, tsd, max); } + + void trim_rst_payload(TcpSegmentDescriptor& tsd, uint32_t max = 0) + { norm->trim_rst_payload(tns, tsd, max); } + + void trim_win_payload(TcpSegmentDescriptor& tsd, uint32_t max = 0) + { norm->trim_win_payload(tns, tsd, max); } + + void trim_mss_payload(TcpSegmentDescriptor& tsd, uint32_t max = 0) + { norm->trim_mss_payload(tns, tsd, max); } + + void ecn_tracker(const snort::tcp::TCPHdr* tcph, bool req3way) + { norm->ecn_tracker(tns, tcph, req3way); } + + void ecn_stripper(snort::Packet* p) + { norm->ecn_stripper(tns, p); } + + uint32_t get_stream_window(TcpSegmentDescriptor& tsd) + { return norm->get_stream_window(tns, tsd); } + + uint32_t get_tcp_timestamp(TcpSegmentDescriptor& tsd, bool strip) + { return norm->get_tcp_timestamp(tns, tsd, strip); } + + int handle_paws(TcpSegmentDescriptor& tsd) + { return norm->handle_paws(tns, tsd); } + + bool validate_rst(TcpSegmentDescriptor& tsd) + { return norm->validate_rst(tns, tsd); } + + int handle_repeated_syn(TcpSegmentDescriptor& tsd) + { return norm->handle_repeated_syn(tns, tsd); } + + uint16_t set_urg_offset(const snort::tcp::TCPHdr* tcph, uint16_t dsize) + { return norm->set_urg_offset(tns, tcph, dsize); } + + StreamPolicy get_os_policy() const + { return tns.os_policy; } + + bool is_paws_drop_zero_ts() const + { return tns.paws_drop_zero_ts; } + + int32_t get_paws_ts_fudge() const + { return tns.paws_ts_fudge; } + + int8_t get_opt_block() const + { return tns.opt_block; } + + int8_t get_strip_ecn() const + { return tns.strip_ecn; } + + int8_t get_tcp_block() const + { return tns.tcp_block; } + + int8_t get_trim_rst() const + { return tns.trim_rst; } + + int8_t get_trim_syn() const + { return tns.trim_syn; } + + int8_t get_trim_mss() const + { return tns.trim_mss; } + + int8_t get_trim_win() const + { return tns.trim_win; } + + bool is_tcp_ips_enabled() const + { return tns.tcp_ips_enabled; } + + bool handling_timestamps() const + { return tns.tcp_ts_flags != TF_NONE; } + + uint32_t get_timestamp_flags() + { return tns.tcp_ts_flags; } + +private: + TcpNormalizer* norm = nullptr; + TcpNormalizerState tns; }; #endif diff --git a/src/stream/tcp/tcp_reassembler.cc b/src/stream/tcp/tcp_reassembler.cc index e04581942..fb819fd1f 100644 --- a/src/stream/tcp/tcp_reassembler.cc +++ b/src/stream/tcp/tcp_reassembler.cc @@ -29,44 +29,19 @@ #include "log/log.h" #include "main/snort.h" #include "profiler/profiler.h" -#include "detection/detection_engine.h" #include "protocols/packet_manager.h" #include "time/packet_time.h" #include "tcp_module.h" -#include "tcp_normalizer.h" +#include "tcp_normalizers.h" +#include "tcp_session.h" using namespace snort; -ReassemblyPolicy stream_reassembly_policy_map[] = -{ - ReassemblyPolicy::OS_INVALID, - ReassemblyPolicy::OS_FIRST, - ReassemblyPolicy::OS_LAST, - ReassemblyPolicy::OS_LINUX, - ReassemblyPolicy::OS_OLD_LINUX, - ReassemblyPolicy::OS_BSD, - ReassemblyPolicy::OS_MACOS, - ReassemblyPolicy::OS_SOLARIS, - ReassemblyPolicy::OS_IRIX, - ReassemblyPolicy::OS_HPUX11, - ReassemblyPolicy::OS_HPUX10, - ReassemblyPolicy::OS_WINDOWS, - ReassemblyPolicy::OS_WINDOWS2K3, - ReassemblyPolicy::OS_VISTA, - ReassemblyPolicy::OS_PROXY, - ReassemblyPolicy::OS_DEFAULT -}; - -void TcpReassembler::set_tcp_reassembly_policy(StreamPolicy os_policy) -{ - reassembly_policy = stream_reassembly_policy_map[ static_cast( os_policy ) ]; -} - -void TcpReassembler::trace_segments() +void TcpReassembler::trace_segments(TcpReassemblerState& trs) { - TcpSegmentNode* tsn = seglist.head; - uint32_t sx = tracker->r_win_base; + TcpSegmentNode* tsn = trs.sos.seglist.head; + uint32_t sx = trs.tracker->r_win_base; unsigned segs = 0, bytes = 0; while ( tsn ) @@ -84,28 +59,28 @@ void TcpReassembler::trace_segments() sx = tsn->seq + tsn->payload_size; tsn = tsn->next; } - assert(seg_count == segs); - assert(seg_bytes_logical == bytes); + assert(trs.sos.seg_count == segs); + assert(trs.sos.seg_bytes_logical == bytes); } -bool TcpReassembler::is_segment_pending_flush() +bool TcpReassembler::is_segment_pending_flush(TcpReassemblerState& trs) { - return ( get_pending_segment_count(1) > 0 ); + return ( get_pending_segment_count(trs, 1) > 0 ); } -uint32_t TcpReassembler::get_pending_segment_count(unsigned max) +uint32_t TcpReassembler::get_pending_segment_count(TcpReassemblerState& trs, unsigned max) { - uint32_t n = seg_count - flush_count; + uint32_t n = trs.sos.seg_count - trs.flush_count; TcpSegmentNode* tsn; if ( !n || max == 1 ) return n; n = 0; - tsn = seglist.head; + tsn = trs.sos.seglist.head; while ( tsn ) { - if ( !tsn->buffered && SEQ_LT(tsn->seq, tracker->r_win_base) ) + if ( !tsn->buffered && SEQ_LT(tsn->seq, trs.tracker->r_win_base) ) n++; if ( max && n == max ) @@ -117,20 +92,21 @@ uint32_t TcpReassembler::get_pending_segment_count(unsigned max) return n; } -bool TcpReassembler::flush_data_ready() +bool TcpReassembler::flush_data_ready(TcpReassemblerState& trs) { // needed by stream_reassemble:action disable; can fire on rebuilt // packets, yanking the splitter out from under us :( - if (!tracker->flush_policy or !tracker->splitter) + if (!trs.tracker->flush_policy or !trs.tracker->splitter) return false; - if (tracker->flush_policy == STREAM_FLPOLICY_ON_DATA || tracker->splitter->is_paf()) - return ( is_segment_pending_flush( ) ); + if ( (trs.tracker->flush_policy == STREAM_FLPOLICY_ON_DATA) or + trs.tracker->splitter->is_paf() ) + return ( is_segment_pending_flush(trs) ); - return ( get_pending_segment_count(2) > 1 ); // FIXIT-L return false? + return ( get_pending_segment_count(trs, 2) > 1 ); // FIXIT-L return false? } -int TcpReassembler::delete_reassembly_segment(TcpSegmentNode* tsn) +int TcpReassembler::delete_reassembly_segment(TcpReassemblerState& trs, TcpSegmentNode* tsn) { int ret; assert(tsn); @@ -141,36 +117,37 @@ int TcpReassembler::delete_reassembly_segment(TcpSegmentNode* tsn) if (tsn->prev) tsn->prev->next = tsn->next; else - seglist.head = tsn->next; + trs.sos.seglist.head = tsn->next; if (tsn->next) tsn->next->prev = tsn->prev; else - seglist.tail = tsn->prev; + trs.sos.seglist.tail = tsn->prev; - seg_bytes_logical -= tsn->payload_size; - seg_bytes_total -= tsn->orig_dsize; + trs.sos.seg_bytes_logical -= tsn->payload_size; + trs.sos.seg_bytes_total -= tsn->orig_dsize; ret = tsn->orig_dsize; if (tsn->buffered) { tcpStats.segs_used++; - flush_count--; + trs.flush_count--; } - if (seglist.next == tsn) - seglist.next = nullptr; + if (trs.sos.seglist.next == tsn) + trs.sos.seglist.next = nullptr; tsn->term( ); - seg_count--; + trs.sos.seg_count--; return ret; } -int TcpReassembler::trim_delete_reassembly_segment(TcpSegmentNode* tsn, uint32_t flush_seq) +int TcpReassembler::trim_delete_reassembly_segment( + TcpReassemblerState& trs, TcpSegmentNode* tsn, uint32_t flush_seq) { - if ( paf_active(&tracker->paf_state) && ( ( tsn->seq + tsn->payload_size ) > flush_seq ) ) + if ( paf_active(&trs.tracker->paf_state) && ( ( tsn->seq + tsn->payload_size ) > flush_seq ) ) { uint32_t delta = flush_seq - tsn->seq; @@ -181,27 +158,29 @@ int TcpReassembler::trim_delete_reassembly_segment(TcpSegmentNode* tsn, uint32_t tsn->seq = flush_seq; tsn->payload_size -= (uint16_t)delta; - seg_bytes_logical -= delta; + trs.sos.seg_bytes_logical -= delta; return 0; } } - return delete_reassembly_segment(tsn); + return delete_reassembly_segment(trs, tsn); } -void TcpReassembler::queue_reassembly_segment(TcpSegmentNode* prev, TcpSegmentNode* tsn) +void TcpReassembler::queue_reassembly_segment( + TcpReassemblerState& trs, TcpSegmentNode* prev, TcpSegmentNode* tsn) { - seglist.insert(prev, tsn); - seg_count++; - seg_bytes_total += tsn->orig_dsize; - total_segs_queued++; + trs.sos.seglist.insert(prev, tsn); + trs.sos.seg_count++; + trs.sos.seg_bytes_total += tsn->orig_dsize; + trs.sos.total_segs_queued++; tcpStats.segs_queued++; } -bool TcpReassembler::is_segment_fasttrack(TcpSegmentNode* tail, TcpSegmentDescriptor& tsd) +bool TcpReassembler::is_segment_fasttrack( + TcpReassemblerState&, TcpSegmentNode* tail, TcpSegmentDescriptor& tsd) { - DebugFormat(DEBUG_STREAM_STATE, "Checking seq for fast track: %X > %X\n", tsd.get_seg_seq(), - tail->seq + tail->payload_size); + DebugFormat(DEBUG_STREAM_STATE, "Checking seq for fast track: %X > %X\n", + tsd.get_seg_seq(), tail->seq + tail->payload_size); if ( SEQ_EQ(tsd.get_seg_seq(), tail->seq + tail->payload_size) ) return true; @@ -209,9 +188,9 @@ bool TcpReassembler::is_segment_fasttrack(TcpSegmentNode* tail, TcpSegmentDescri return false; } -int TcpReassembler::add_reassembly_segment(TcpSegmentDescriptor& tsd, int16_t len, uint32_t slide, - uint32_t trunc_len, - uint32_t seq, TcpSegmentNode* left) +int TcpReassembler::add_reassembly_segment( + TcpReassemblerState& trs, TcpSegmentDescriptor& tsd, int16_t len, uint32_t slide, + uint32_t trunc_len, uint32_t seq, TcpSegmentNode* left) { TcpSegmentNode* tsn = nullptr; int32_t newSize = len - slide - trunc_len; @@ -226,7 +205,7 @@ int TcpReassembler::add_reassembly_segment(TcpSegmentDescriptor& tsd, int16_t le "(len: %hd slide: %u trunc: %u)\n", len, slide, trunc_len); inc_tcp_discards(); - tracker->normalizer->trim_win_payload(tsd); + trs.tracker->normalizer.trim_win_payload(tsd); return STREAM_INSERT_OK; } @@ -241,23 +220,27 @@ int TcpReassembler::add_reassembly_segment(TcpSegmentDescriptor& tsd, int16_t le // FIXIT-M the urgent ptr handling is broken... urg_offset is set here but currently // not actually referenced anywhere else. In 2.9.7 the FlushStream function did reference // this field but that code has been lost... urg ptr handling needs to be reviewed and fixed - tsn->urg_offset = tracker->normalizer->set_urg_offset(tsd.get_tcph(), tsd.get_seg_len() ); - queue_reassembly_segment(left, tsn); - seg_bytes_logical += tsn->payload_size; - total_bytes_queued += tsn->payload_size; + tsn->urg_offset = trs.tracker->normalizer.set_urg_offset(tsd.get_tcph(), tsd.get_seg_len() ); + + queue_reassembly_segment(trs, left, tsn); + + trs.sos.seg_bytes_logical += tsn->payload_size; + trs.sos.total_bytes_queued += tsn->payload_size; tsd.get_pkt()->packet_flags |= PKT_STREAM_INSERT; DebugFormat(DEBUG_STREAM_STATE, "added %hu bytes on segment list @ seq: 0x%X, total %u, %u segments queued\n", - tsn->payload_size, tsn->seq, seg_bytes_logical, get_pending_segment_count(0)); + tsn->payload_size, tsn->seq, trs.sos.seg_bytes_logical, + get_pending_segment_count(trs, 0)); #ifdef SEG_TEST - CheckSegments(tracker); + CheckSegments(trs.tracker); #endif return STREAM_INSERT_OK; } -int TcpReassembler::dup_reassembly_segment(TcpSegmentNode* left, TcpSegmentNode** retSeg) +int TcpReassembler::dup_reassembly_segment( + TcpReassemblerState& trs, TcpSegmentNode* left, TcpSegmentNode** retSeg) { TcpSegmentNode* tsn = TcpSegmentNode::init(*left); tcpStats.segs_split++; @@ -266,32 +249,33 @@ int TcpReassembler::dup_reassembly_segment(TcpSegmentNode* left, TcpSegmentNode* tsn->payload_size = left->payload_size; tsn->seq = left->seq; - queue_reassembly_segment(left, tsn); + queue_reassembly_segment(trs, left, tsn); DebugFormat(DEBUG_STREAM_STATE, "added %hu bytes on segment list @ seq: 0x%X, total %u, %u segments queued\n", - tsn->payload_size, tsn->seq, seg_bytes_logical, get_pending_segment_count(0)); + tsn->payload_size, tsn->seq, trs.sos.seg_bytes_logical, + get_pending_segment_count(trs, 0)); *retSeg = tsn; return STREAM_INSERT_OK; } -int TcpReassembler::purge_alerts(Flow* flow) +int TcpReassembler::purge_alerts(TcpReassemblerState& trs, Flow* flow) { - for (int i = 0; i < tracker->alert_count; i++) + for (int i = 0; i < trs.tracker->alert_count; i++) { - StreamAlertInfo* ai = tracker->alerts + i; - Stream::log_extra_data(flow, xtradata_mask, ai->event_id, ai->event_second); + StreamAlertInfo* ai = trs.tracker->alerts + i; + Stream::log_extra_data(flow, trs.xtradata_mask, ai->event_id, ai->event_second); } - tracker->alert_count = 0; + trs.tracker->alert_count = 0; return 0; } -int TcpReassembler::purge_to_seq(uint32_t flush_seq) +int TcpReassembler::purge_to_seq(TcpReassemblerState& trs, uint32_t flush_seq) { - assert(seglist.head != nullptr); - TcpSegmentNode* tsn = seglist.head; + assert(trs.sos.seglist.head != nullptr); + TcpSegmentNode* tsn = trs.sos.seglist.head; TcpSegmentNode* dump_me = nullptr; int purged_bytes = 0; uint32_t last_ts = 0; @@ -310,26 +294,26 @@ int TcpReassembler::purge_to_seq(uint32_t flush_seq) if (dump_me->ts > last_ts) last_ts = dump_me->ts; - purged_bytes += trim_delete_reassembly_segment(dump_me, flush_seq); + purged_bytes += trim_delete_reassembly_segment(trs, dump_me, flush_seq); } else break; } - if ( SEQ_LT(seglist_base_seq, flush_seq) ) + if ( SEQ_LT(trs.sos.seglist_base_seq, flush_seq) ) { // FIXIT-M these lines are out of code coverage. Is this even possible? DebugFormat(DEBUG_STREAM_STATE, "setting seglist_base_seq to 0x%X\n", flush_seq); - seglist_base_seq = flush_seq; + trs.sos.seglist_base_seq = flush_seq; } - if ( SEQ_LT(tracker->r_nxt_ack, flush_seq) ) - tracker->r_nxt_ack = flush_seq; + if ( SEQ_LT(trs.tracker->r_nxt_ack, flush_seq) ) + trs.tracker->r_nxt_ack = flush_seq; - purge_alerts(session->flow); + purge_alerts(trs, trs.sos.session->flow); - if ( seglist.head == nullptr ) - seglist.tail = nullptr; + if ( trs.sos.seglist.head == nullptr ) + trs.sos.seglist.tail = nullptr; /* Update the "last" time stamp seen from the other side * to be the most recent timestamp (largest) that was removed @@ -349,17 +333,17 @@ int TcpReassembler::purge_to_seq(uint32_t flush_seq) if ( !last_ts ) return purged_bytes; - if ( !server_side ) + if ( !trs.server_side ) { - int32_t delta = last_ts - session->server->get_ts_last(); + int32_t delta = last_ts - trs.sos.session->server.get_ts_last(); if ( delta > 0 ) - session->server->set_ts_last(last_ts); + trs.sos.session->server.set_ts_last(last_ts); } else { - int32_t delta = last_ts - session->client->get_ts_last(); + int32_t delta = last_ts - trs.sos.session->client.get_ts_last(); if ( delta > 0 ) - session->client->set_ts_last(last_ts); + trs.sos.session->client.set_ts_last(last_ts); } return purged_bytes; @@ -371,44 +355,45 @@ int TcpReassembler::purge_to_seq(uint32_t flush_seq) // 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() +int TcpReassembler::purge_flushed_ackd(TcpReassemblerState& trs) { - TcpSegmentNode* tsn = seglist.head; + TcpSegmentNode* tsn = trs.sos.seglist.head; uint32_t seq; - if (!seglist.head) + if (!trs.sos.seglist.head) return 0; - seq = seglist.head->seq; + seq = trs.sos.seglist.head->seq; while ( tsn && tsn->buffered ) { uint32_t end = tsn->seq + tsn->payload_size; - if ( SEQ_GT(end, tracker->r_win_base) ) + if ( SEQ_GT(end, trs.tracker->r_win_base) ) { - seq = tracker->r_win_base; + seq = trs.tracker->r_win_base; break; } seq = end; tsn = tsn->next; } - if ( seq != seglist.head->seq ) - return purge_to_seq(seq); + if ( seq != trs.sos.seglist.head->seq ) + return purge_to_seq(trs, seq); return 0; } -void TcpReassembler::show_rebuilt_packet(Packet* pkt) +void TcpReassembler::show_rebuilt_packet(TcpReassemblerState& trs, Packet* pkt) { - if ( session->config->flags & STREAM_CONFIG_SHOW_PACKETS ) + if ( trs.sos.session->config->flags & STREAM_CONFIG_SHOW_PACKETS ) { LogFlow(pkt); LogNetData(pkt->data, pkt->dsize, pkt); } } -uint32_t TcpReassembler::get_flush_data_len(TcpSegmentNode* tsn, uint32_t to_seq, unsigned max) +uint32_t TcpReassembler::get_flush_data_len( + TcpReassemblerState& trs, TcpSegmentNode* tsn, uint32_t to_seq, unsigned max) { unsigned int flushSize = tsn->payload_size; @@ -416,29 +401,31 @@ uint32_t TcpReassembler::get_flush_data_len(TcpSegmentNode* tsn, uint32_t to_seq flushSize = max; // copy only to flush point - if ( paf_active(&tracker->paf_state) && SEQ_GT(tsn->seq + flushSize, to_seq) ) + if ( paf_active(&trs.tracker->paf_state) && SEQ_GT(tsn->seq + flushSize, to_seq) ) flushSize = to_seq - tsn->seq; return flushSize; } -// flush the client seglist up to the most recently acked segment -int TcpReassembler::flush_data_segments(Packet* p, uint32_t total, Packet* pdu) +// flush the client trs.sos.seglist up to the most recently acked segment +int TcpReassembler::flush_data_segments( + TcpReassemblerState& trs, Packet* p, uint32_t total, Packet* pdu) { uint32_t bytes_flushed = 0; uint32_t segs = 0; uint32_t flags = PKT_PDU_HEAD; - DEBUG_WRAP(uint32_t bytes_queued = seg_bytes_logical; ); + DEBUG_WRAP(uint32_t bytes_queued = trs.sos.seg_bytes_logical; ); - assert(seglist.next); + assert(trs.sos.seglist.next); Profile profile(s5TcpBuildPacketPerfStats); - uint32_t to_seq = seglist.next->seq + total; + uint32_t to_seq = trs.sos.seglist.next->seq + total; - while ( SEQ_LT(seglist.next->seq, to_seq) ) + while ( SEQ_LT(trs.sos.seglist.next->seq, to_seq) ) { - TcpSegmentNode* tsn = seglist.next, * sr = nullptr; - unsigned bytes_to_copy = get_flush_data_len(tsn, to_seq, tracker->splitter->max(p->flow)); + TcpSegmentNode* tsn = trs.sos.seglist.next, * sr = nullptr; + unsigned bytes_to_copy = get_flush_data_len( + trs, tsn, to_seq, trs.tracker->splitter->max(p->flow)); unsigned bytes_copied = 0; assert(bytes_to_copy); @@ -447,12 +434,12 @@ int TcpReassembler::flush_data_segments(Packet* p, uint32_t total, Packet* pdu) if ( !tsn->next or (bytes_to_copy < tsn->payload_size) or SEQ_EQ(tsn->seq + bytes_to_copy, to_seq) or (bytes_flushed + tsn->payload_size + tsn->next->payload_size > - tracker->splitter->get_max_pdu()) ) + trs.tracker->splitter->get_max_pdu()) ) { flags |= PKT_PDU_TAIL; } - const StreamBuffer sb = tracker->splitter->reassemble( - session->flow, total, bytes_flushed, tsn->payload(), + const StreamBuffer sb = trs.tracker->splitter->reassemble( + trs.sos.session->flow, total, bytes_flushed, tsn->payload(), bytes_to_copy, flags, bytes_copied); flags = 0; @@ -469,7 +456,7 @@ int TcpReassembler::flush_data_segments(Packet* p, uint32_t total, Packet* pdu) bytes_flushed += bytes_to_copy; if ( bytes_to_copy < tsn->payload_size - && dup_reassembly_segment(tsn, &sr) == STREAM_INSERT_OK ) + && dup_reassembly_segment(trs, tsn, &sr) == STREAM_INSERT_OK ) { tsn->payload_size = bytes_to_copy; sr->seq += bytes_to_copy; @@ -477,10 +464,10 @@ int TcpReassembler::flush_data_segments(Packet* p, uint32_t total, Packet* pdu) sr->offset += bytes_to_copy; } tsn->buffered = true; - flush_count++; + trs.flush_count++; segs++; - seglist.next = tsn->next; + trs.sos.seglist.next = tsn->next; if ( SEQ_EQ(tsn->seq + bytes_to_copy, to_seq) ) break; @@ -493,16 +480,19 @@ int TcpReassembler::flush_data_segments(Packet* p, uint32_t total, Packet* pdu) || (!tsn->next && (tsn->seq + tsn->payload_size < to_seq)))) { // FIXIT-L this is suboptimal - better to exclude fin from to_seq - if ( !tracker->is_fin_seq_set() or SEQ_LEQ(to_seq, tracker->get_fin_final_seq()) ) - tracker->set_tf_flags(TF_MISSING_PKT); - + if ( !trs.tracker->is_fin_seq_set() or + SEQ_LEQ(to_seq, trs.tracker->get_fin_final_seq()) ) + { + trs.tracker->set_tf_flags(TF_MISSING_PKT); + } break; } - if ( sb.data || !seglist.next ) + if ( sb.data || !trs.sos.seglist.next ) break; - if ( bytes_flushed + seglist.next->payload_size > tracker->splitter->get_max_pdu() ) + if ( bytes_flushed + trs.sos.seglist.next->payload_size > + trs.tracker->splitter->get_max_pdu() ) break; } @@ -515,7 +505,8 @@ int TcpReassembler::flush_data_segments(Packet* p, uint32_t total, Packet* pdu) } // FIXIT-L consolidate encode format, update, and this into new function? -void TcpReassembler::prep_pdu(Flow* flow, Packet* p, uint32_t pkt_flags, Packet* pdu) +void TcpReassembler::prep_pdu( + TcpReassemblerState&, Flow* flow, Packet* p, uint32_t pkt_flags, Packet* pdu) { pdu->ptrs.set_pkt_type(PktType::PDU); pdu->proto_bits |= PROTO_BIT__TCP; @@ -565,27 +556,29 @@ void TcpReassembler::prep_pdu(Flow* flow, Packet* p, uint32_t pkt_flags, Packet* } } -Packet* TcpReassembler::initialize_pdu(Packet* p, uint32_t pkt_flags, struct timeval tv) +Packet* TcpReassembler::initialize_pdu( + TcpReassemblerState& trs, Packet* p, uint32_t pkt_flags, struct timeval tv) { - DetectionEngine::onload(session->flow); + DetectionEngine::onload(trs.sos.session->flow); Packet* pdu = DetectionEngine::set_next_packet(); EncodeFlags enc_flags = 0; DAQ_PktHdr_t pkth; - session->GetPacketHeaderFoo(&pkth, pkt_flags); + trs.sos.session->GetPacketHeaderFoo(&pkth, pkt_flags); PacketManager::format_tcp(enc_flags, p, pdu, PSEUDO_PKT_TCP, &pkth, pkth.opaque); - prep_pdu(session->flow, p, pkt_flags, pdu); + prep_pdu(trs, trs.sos.session->flow, p, pkt_flags, pdu); (const_cast(pdu->pkth))->ts = tv; pdu->dsize = 0; pdu->data = nullptr; return pdu; } -int TcpReassembler::_flush_to_seq(uint32_t bytes, Packet* p, uint32_t pkt_flags) +int TcpReassembler::_flush_to_seq( + TcpReassemblerState& trs, uint32_t bytes, Packet* p, uint32_t pkt_flags) { Profile profile(s5TcpFlushPerfStats); - DetectionEngine::onload(session->flow); + DetectionEngine::onload(trs.sos.session->flow); Packet* pdu = DetectionEngine::set_next_packet(); if ( !p ) @@ -599,12 +592,12 @@ int TcpReassembler::_flush_to_seq(uint32_t bytes, Packet* p, uint32_t pkt_flags) DebugFormat(DEBUG_STREAM_STATE, "Attempting to flush %u bytes\n", bytes); uint32_t bytes_processed = 0; - uint32_t stop_seq = seglist.next->seq + bytes; + uint32_t stop_seq = trs.sos.seglist.next->seq + bytes; - while ( seglist.next and SEQ_LT(seglist.next->seq, stop_seq) ) + while ( trs.sos.seglist.next and SEQ_LT(trs.sos.seglist.next->seq, stop_seq) ) { - seglist_base_seq = seglist.next->seq; - uint32_t footprint = stop_seq - seglist_base_seq; + trs.sos.seglist_base_seq = trs.sos.seglist.next->seq; + uint32_t footprint = stop_seq - trs.sos.seglist_base_seq; if ( footprint == 0 ) return bytes_processed; @@ -613,16 +606,17 @@ int TcpReassembler::_flush_to_seq(uint32_t bytes, Packet* p, uint32_t pkt_flags) /* this is as much as we can pack into a stream buffer */ footprint = pdu->max_dsize; - if ( tracker->splitter->is_paf() and ( tracker->get_tf_flags() & TF_MISSING_PREV_PKT ) ) - fallback(); + if ( trs.tracker->splitter->is_paf() and + ( trs.tracker->get_tf_flags() & TF_MISSING_PREV_PKT ) ) + fallback(trs); - Packet* pdu = initialize_pdu(p, pkt_flags, seglist.next->tv); - int32_t flushed_bytes = flush_data_segments(p, footprint, pdu); + Packet* pdu = initialize_pdu(trs, p, pkt_flags, trs.sos.seglist.next->tv); + int32_t flushed_bytes = flush_data_segments(trs, p, footprint, pdu); if ( flushed_bytes == 0 ) break; /* No more data... bail */ bytes_processed += flushed_bytes; - seglist_base_seq += flushed_bytes; + trs.sos.seglist_base_seq += flushed_bytes; if ( pdu->dsize ) { @@ -632,7 +626,7 @@ int TcpReassembler::_flush_to_seq(uint32_t bytes, Packet* p, uint32_t pkt_flags) pdu->packet_flags |= ( PKT_REBUILT_STREAM | PKT_STREAM_EST ); pdu->set_snort_protocol_id(p->get_snort_protocol_id()); - show_rebuilt_packet(pdu); + show_rebuilt_packet(trs, pdu); tcpStats.rebuilt_packets++; tcpStats.rebuilt_bytes += flushed_bytes; @@ -644,24 +638,25 @@ int TcpReassembler::_flush_to_seq(uint32_t bytes, Packet* p, uint32_t pkt_flags) tcpStats.rebuilt_buffers++; // FIXIT-L this is not accurate } - DebugFormat(DEBUG_STREAM_STATE, "setting seglist_base_seq to 0x%X\n", seglist_base_seq); + DebugFormat(DEBUG_STREAM_STATE, "setting trs.sos.seglist_base_seq to 0x%X\n", + trs.sos.seglist_base_seq); - // FIXIT-L must check because above may clear session - if ( tracker->splitter ) - tracker->splitter->update(); + // FIXIT-L must check because above may clear trs.sos.session + if ( trs.tracker->splitter ) + trs.tracker->splitter->update(); // FIXIT-L abort should be by PAF callback only since recovery may be possible - if ( tracker->get_tf_flags() & TF_MISSING_PKT ) + if ( trs.tracker->get_tf_flags() & TF_MISSING_PKT ) { - tracker->set_tf_flags(TF_MISSING_PREV_PKT | TF_PKT_MISSED); - tracker->clear_tf_flags(TF_MISSING_PKT); + trs.tracker->set_tf_flags(TF_MISSING_PREV_PKT | TF_PKT_MISSED); + trs.tracker->clear_tf_flags(TF_MISSING_PKT); tcpStats.gaps++; } else - tracker->clear_tf_flags(TF_MISSING_PREV_PKT); + trs.tracker->clear_tf_flags(TF_MISSING_PREV_PKT); // check here instead of in while to allow single segment flushes - if ( !flush_data_ready() ) + if ( !flush_data_ready(trs) ) break; } @@ -669,89 +664,92 @@ int TcpReassembler::_flush_to_seq(uint32_t bytes, Packet* p, uint32_t pkt_flags) } // flush a seglist up to the given point, generate a pseudopacket, and fire it thru the system. -int TcpReassembler::flush_to_seq(uint32_t bytes, Packet* p, uint32_t pkt_flags) +int TcpReassembler::flush_to_seq( + TcpReassemblerState& trs, uint32_t bytes, Packet* p, uint32_t pkt_flags) { - if ( !bytes || !seglist.next ) + if ( !bytes || !trs.sos.seglist.next ) { - DebugFormat(DEBUG_STREAM_STATE, "bailing: no bytes: %u or empty seglist: %p\n", - bytes, (void*)seglist.next); + DebugFormat(DEBUG_STREAM_STATE, "bailing: no bytes: %u or empty trs.sos.seglist: %p\n", + bytes, (void*)trs.sos.seglist.next); return 0; } - if ( !flush_data_ready() and !(tracker->get_tf_flags() & TF_FORCE_FLUSH) and - !tracker->splitter->is_paf() ) + if ( !flush_data_ready(trs) and !(trs.tracker->get_tf_flags() & TF_FORCE_FLUSH) and + !trs.tracker->splitter->is_paf() ) { - DebugMessage(DEBUG_STREAM_STATE, "only 1 packet in seglist no need to flush\n"); + DebugMessage(DEBUG_STREAM_STATE, "only 1 packet in trs.sos.seglist no need to flush\n"); return 0; } - tracker->clear_tf_flags(TF_MISSING_PKT | TF_MISSING_PREV_PKT); + trs.tracker->clear_tf_flags(TF_MISSING_PKT | TF_MISSING_PREV_PKT); /* This will set this flag on the first reassembly * if reassembly for this direction was set midstream */ - if ( SEQ_LT(seglist_base_seq, seglist.next->seq) ) + if ( SEQ_LT(trs.sos.seglist_base_seq, trs.sos.seglist.next->seq) ) { - uint32_t missed = seglist.next->seq - seglist_base_seq; + uint32_t missed = trs.sos.seglist.next->seq - trs.sos.seglist_base_seq; if ( missed <= bytes ) bytes -= missed; - tracker->set_tf_flags(TF_MISSING_PREV_PKT | TF_PKT_MISSED); + trs.tracker->set_tf_flags(TF_MISSING_PREV_PKT | TF_PKT_MISSED); tcpStats.gaps++; - seglist_base_seq = seglist.next->seq; + trs.sos.seglist_base_seq = trs.sos.seglist.next->seq; if ( !bytes ) return 0; } - return _flush_to_seq(bytes, p, pkt_flags); + return _flush_to_seq(trs, bytes, p, pkt_flags); } // flush a seglist up to the given point, generate a pseudopacket, and fire it thru the system. -int TcpReassembler::do_zero_byte_flush(Packet* p, uint32_t pkt_flags) +int TcpReassembler::do_zero_byte_flush(TcpReassemblerState& trs, Packet* p, uint32_t pkt_flags) { unsigned bytes_copied = 0; - const StreamBuffer sb = tracker->splitter->reassemble(session->flow, 0, 0, nullptr, 0, - (PKT_PDU_HEAD | PKT_PDU_TAIL), bytes_copied); + const StreamBuffer sb = trs.tracker->splitter->reassemble( + trs.sos.session->flow, 0, 0, nullptr, 0, (PKT_PDU_HEAD | PKT_PDU_TAIL), bytes_copied); if ( sb.data ) { - Packet* pdu = initialize_pdu(p, pkt_flags, p->pkth->ts); + Packet* pdu = initialize_pdu(trs, p, pkt_flags, p->pkth->ts); /* setup the pseudopacket payload */ pdu->data = sb.data; pdu->dsize = sb.length; - pdu->packet_flags |= ( PKT_REBUILT_STREAM | PKT_STREAM_EST | PKT_PDU_HEAD | PKT_PDU_TAIL ); + pdu->packet_flags |= (PKT_REBUILT_STREAM | PKT_STREAM_EST | PKT_PDU_HEAD | PKT_PDU_TAIL); pdu->set_snort_protocol_id(p->get_snort_protocol_id()); - flush_count++; + trs.flush_count++; - show_rebuilt_packet(pdu); + show_rebuilt_packet(trs, pdu); ProfileExclude profile_exclude(s5TcpFlushPerfStats); Snort::inspect(pdu); - if ( tracker->splitter ) - tracker->splitter->update(); + + if ( trs.tracker->splitter ) + trs.tracker->splitter->update(); } return bytes_copied; } -// get the footprint for the current seglist, the difference +// get the footprint for the current trs.sos.seglist, the difference // between our base sequence and the last ack'd sequence we received -uint32_t TcpReassembler::get_q_footprint() +uint32_t TcpReassembler::get_q_footprint(TcpReassemblerState& trs) { int32_t footprint = 0, sequenced = 0; - if ( !tracker ) + if ( !trs.tracker ) return 0; - seglist.next = seglist.head; - footprint = tracker->r_win_base - seglist_base_seq; - if( footprint ) + trs.sos.seglist.next = trs.sos.seglist.head; + footprint = trs.tracker->r_win_base - trs.sos.seglist_base_seq; + + if ( footprint ) { - sequenced = get_q_sequenced(); - if( tracker->fin_seq_status == TcpStreamTracker::FIN_WITH_SEQ_ACKED ) + sequenced = get_q_sequenced(trs); + if ( trs.tracker->fin_seq_status == TcpStreamTracker::FIN_WITH_SEQ_ACKED ) --footprint; } @@ -759,15 +757,16 @@ uint32_t TcpReassembler::get_q_footprint() } // FIXIT-P get_q_sequenced() performance could possibly be -// boosted by tracking sequenced bytes as seglist is updated +// boosted by tracking sequenced bytes as trs.sos.seglist is updated // to avoid the while loop, etc. below. -uint32_t TcpReassembler::get_q_sequenced() +uint32_t TcpReassembler::get_q_sequenced(TcpReassemblerState& trs) { - TcpSegmentNode* tsn = tracker ? seglist.head : nullptr; + TcpSegmentNode* tsn = trs.tracker ? trs.sos.seglist.head : nullptr; TcpSegmentNode* base = nullptr; - if ( !tsn || ( session->flow->two_way_traffic() && SEQ_LT(tracker->r_win_base, tsn->seq) ) ) + if ( !tsn || ( trs.sos.session->flow->two_way_traffic() && + SEQ_LT(trs.tracker->r_win_base, tsn->seq) ) ) return 0; while ( tsn->next && ( tsn->next->seq == tsn->seq + tsn->payload_size ) ) @@ -781,10 +780,11 @@ uint32_t TcpReassembler::get_q_sequenced() base = tsn; int32_t len = 0; + if ( base ) { - seglist.next = base; - seglist_base_seq = base->seq; + trs.sos.seglist.next = base; + trs.sos.seglist_base_seq = base->seq; len = tsn->seq + tsn->payload_size - base->seq; } @@ -794,35 +794,43 @@ uint32_t TcpReassembler::get_q_sequenced() // FIXIT-L flush_stream() calls should be replaced with calls to // CheckFlushPolicyOn*() with the exception that for the *OnAck() case, // any available ackd data must be flushed in both directions. -int TcpReassembler::flush_stream(Packet* p, uint32_t dir, bool final_flush) +int TcpReassembler::flush_stream( + TcpReassemblerState& trs, Packet* p, uint32_t dir, bool final_flush) { // this is not always redundant; stream_reassemble rule option causes trouble - if ( !tracker->flush_policy or !tracker->splitter ) + if ( !trs.tracker->flush_policy or !trs.tracker->splitter ) return 0; uint32_t bytes; - if ( tracker->normalizer->is_tcp_ips_enabled() ) - bytes = get_q_sequenced( ); + if ( trs.tracker->normalizer.is_tcp_ips_enabled() ) + bytes = get_q_sequenced(trs); else - bytes = get_q_footprint( ); + bytes = get_q_footprint(trs); if ( bytes ) - return flush_to_seq(bytes, p, dir); - else if( final_flush ) - return do_zero_byte_flush(p, dir); + return flush_to_seq(trs, bytes, p, dir); + + if ( final_flush ) + return do_zero_byte_flush(trs, p, dir); return 0; } -void TcpReassembler::final_flush(Packet* p, uint32_t dir) +void TcpReassembler::final_flush(TcpReassemblerState& trs, Packet* p, uint32_t dir) { - tracker->set_tf_flags(TF_FORCE_FLUSH); + trs.tracker->set_tf_flags(TF_FORCE_FLUSH); - if ( flush_stream(p, dir, true) ) - purge_flushed_ackd( ); + if ( flush_stream(trs, p, dir, true) ) + { + if ( trs.server_side ) + tcpStats.server_cleanups++; + else + tcpStats.client_cleanups++; - tracker->clear_tf_flags(TF_FORCE_FLUSH); + purge_flushed_ackd(trs); + } + trs.tracker->clear_tf_flags(TF_FORCE_FLUSH); } static Packet* set_packet(Flow* flow, uint32_t flags, bool c2s) @@ -854,30 +862,26 @@ static Packet* set_packet(Flow* flow, uint32_t flags, bool c2s) return p; } -void TcpReassembler::flush_queued_segments(Flow* flow, bool clear, Packet* p) +void TcpReassembler::flush_queued_segments( + TcpReassemblerState& trs, Flow* flow, bool clear, Packet* p) { if ( !p ) { // this packet is required if we call finish and/or final_flush - p = set_packet(flow, packet_dir, server_side); - - if ( server_side ) - tcpStats.s5tcp2++; - else - tcpStats.s5tcp1++; + p = set_packet(flow, trs.packet_dir, trs.server_side); } - bool pending = clear and paf_initialized(&tracker->paf_state) - and (!tracker->splitter or tracker->splitter->finish(flow) ); + bool pending = clear and paf_initialized(&trs.tracker->paf_state) + and (!trs.tracker->splitter or trs.tracker->splitter->finish(flow) ); - if ( pending and !(flow->ssn_state.ignore_direction & ignore_dir) ) + if ( pending and !(flow->ssn_state.ignore_direction & trs.ignore_dir) ) { - final_flush(p, packet_dir); + final_flush(trs, p, trs.packet_dir); } } // this is for post-ack flushing -uint32_t TcpReassembler::get_reverse_packet_dir(const Packet* p) +uint32_t TcpReassembler::get_reverse_packet_dir(TcpReassemblerState&, const Packet* p) { /* Remember, one side's packets are stored in the * other side's queue. So when talker ACKs data, @@ -890,17 +894,19 @@ uint32_t TcpReassembler::get_reverse_packet_dir(const Packet* p) */ if ( p->is_from_server() ) return PKT_FROM_CLIENT; - else if ( p->is_from_client() ) + + if ( p->is_from_client() ) return PKT_FROM_SERVER; return 0; } -uint32_t TcpReassembler::get_forward_packet_dir(const Packet* p) +uint32_t TcpReassembler::get_forward_packet_dir(TcpReassemblerState&, const Packet* p) { if ( p->is_from_server() ) return PKT_FROM_SERVER; - else if ( p->is_from_client() ) + + if ( p->is_from_client() ) return PKT_FROM_CLIENT; return 0; @@ -909,16 +915,16 @@ uint32_t TcpReassembler::get_forward_packet_dir(const Packet* p) // see flush_pdu_ackd() for details // the key difference is that we operate on forward moving data // because we don't wait until it is acknowledged -int32_t TcpReassembler::flush_pdu_ips(uint32_t* flags) +int32_t TcpReassembler::flush_pdu_ips(TcpReassemblerState& trs, uint32_t* flags) { Profile profile(s5TcpPAFPerfStats); - DetectionEngine::onload(session->flow); + DetectionEngine::onload(trs.sos.session->flow); uint32_t total = 0, avail; TcpSegmentNode* tsn; - avail = get_q_sequenced( ); - tsn = seglist.next; + avail = get_q_sequenced(trs); + tsn = trs.sos.seglist.next; // * must stop if gap (checked in paf_check) while ( tsn && *flags && ( total < avail ) ) @@ -926,25 +932,26 @@ int32_t TcpReassembler::flush_pdu_ips(uint32_t* flags) int32_t flush_pt; uint32_t size = tsn->payload_size; uint32_t end = tsn->seq + tsn->payload_size; - uint32_t pos = paf_position(&tracker->paf_state); + uint32_t pos = paf_position(&trs.tracker->paf_state); total += size; - if ( paf_initialized(&tracker->paf_state) && SEQ_LEQ(end, pos) ) + if ( paf_initialized(&trs.tracker->paf_state) && SEQ_LEQ(end, pos) ) { tsn = tsn->next; continue; } - flush_pt = paf_check(tracker->splitter, &tracker->paf_state, session->flow, + flush_pt = paf_check( + trs.tracker->splitter, &trs.tracker->paf_state, trs.sos.session->flow, tsn->payload(), size, total, tsn->seq, flags); if (flush_pt >= 0) { // see flush_pdu_ackd() - if ( !tracker->splitter->is_paf() && avail > (unsigned)flush_pt ) + if ( !trs.tracker->splitter->is_paf() && avail > (unsigned)flush_pt ) { - paf_jump(&tracker->paf_state, avail - (unsigned)flush_pt); + paf_jump(&trs.tracker->paf_state, avail - (unsigned)flush_pt); return avail; } return flush_pt; @@ -955,20 +962,21 @@ int32_t TcpReassembler::flush_pdu_ips(uint32_t* flags) return -1; } -void TcpReassembler::fallback() +void TcpReassembler::fallback(TcpReassemblerState& trs) { - bool c2s = tracker->splitter->to_server(); + bool c2s = trs.tracker->splitter->to_server(); - delete tracker->splitter; - tracker->splitter = new AtomSplitter(c2s, session->config->paf_max); - tracker->paf_state.paf = StreamSplitter::SEARCH; + delete trs.tracker->splitter; + trs.tracker->splitter = new AtomSplitter(c2s, trs.sos.session->config->paf_max); + trs.tracker->paf_state.paf = StreamSplitter::SEARCH; - session->flow->set_session_flags( c2s ? SSNFLAG_ABORT_CLIENT : SSNFLAG_ABORT_SERVER ); + trs.sos.session->flow->set_session_flags( + c2s ? SSNFLAG_ABORT_CLIENT : SSNFLAG_ABORT_SERVER ); } -// iterate over seglist and scan all new acked bytes +// iterate over trs.sos.seglist and scan all new acked bytes // - new means not yet scanned -// - must use seglist data (not packet) since this packet may plug a +// - must use trs.sos.seglist data (not packet) since this packet may plug a // hole and enable paf scanning of following segments // - if we reach a flush point // - return bytes to flush if data available (must be acked) @@ -981,36 +989,38 @@ void TcpReassembler::fallback() // - if we partially scan a segment we must save state so we // know where we left off and can resume scanning the remainder -int32_t TcpReassembler::flush_pdu_ackd(uint32_t* flags) +int32_t TcpReassembler::flush_pdu_ackd(TcpReassemblerState& trs, uint32_t* flags) { Profile profile(s5TcpPAFPerfStats); - DetectionEngine::onload(session->flow); + DetectionEngine::onload(trs.sos.session->flow); uint32_t total = 0; - TcpSegmentNode* tsn = SEQ_LT(seglist_base_seq, tracker->r_win_base) ? seglist.head : nullptr; + TcpSegmentNode* tsn = + SEQ_LT(trs.sos.seglist_base_seq, trs.tracker->r_win_base) ? trs.sos.seglist.head : nullptr; // must stop if not acked // must use adjusted size of tsn if not fully acked // must stop if gap (checked in paf_check) - while (tsn && *flags && SEQ_LT(tsn->seq, tracker->r_win_base)) + while (tsn && *flags && SEQ_LT(tsn->seq, trs.tracker->r_win_base)) { int32_t flush_pt; uint32_t size = tsn->payload_size; uint32_t end = tsn->seq + tsn->payload_size; - uint32_t pos = paf_position(&tracker->paf_state); + uint32_t pos = paf_position(&trs.tracker->paf_state); - if ( paf_initialized(&tracker->paf_state) && SEQ_LEQ(end, pos) ) + if ( paf_initialized(&trs.tracker->paf_state) && SEQ_LEQ(end, pos) ) { total += size; tsn = tsn->next; continue; } - if ( SEQ_GT(end, tracker->r_win_base)) - size = tracker->r_win_base - tsn->seq; + if ( SEQ_GT(end, trs.tracker->r_win_base)) + size = trs.tracker->r_win_base - tsn->seq; total += size; - flush_pt = paf_check(tracker->splitter, &tracker->paf_state, session->flow, + flush_pt = paf_check( + trs.tracker->splitter, &trs.tracker->paf_state, trs.sos.session->flow, tsn->payload(), size, total, tsn->seq, flags); if ( flush_pt >= 0 ) @@ -1020,13 +1030,14 @@ int32_t TcpReassembler::flush_pdu_ackd(uint32_t* flags) // instead of creating more, but smaller, packets // FIXIT-L just flush to end of segment to avoid splitting // instead of all avail? - if ( !tracker->splitter->is_paf() ) + if ( !trs.tracker->splitter->is_paf() ) { // get_q_footprint() w/o side effects - int32_t avail = tracker->r_win_base - seglist_base_seq; + int32_t avail = trs.tracker->r_win_base - trs.sos.seglist_base_seq; + if ( avail > flush_pt ) { - paf_jump(&tracker->paf_state, avail - flush_pt); + paf_jump(&trs.tracker->paf_state, avail - flush_pt); return avail; } } @@ -1038,15 +1049,15 @@ int32_t TcpReassembler::flush_pdu_ackd(uint32_t* flags) return -1; } -int TcpReassembler::flush_on_data_policy(Packet* p) +int TcpReassembler::flush_on_data_policy(TcpReassemblerState& trs, Packet* p) { uint32_t flushed = 0; DebugMessage(DEBUG_STREAM_STATE, "In CheckFlushPolicyOnData\n"); DebugFormat(DEBUG_STREAM_STATE, "Listener flush policy: %s\n", - flush_policy_names[ tracker->flush_policy ]); + flush_policy_names[ trs.tracker->flush_policy ]); - switch ( tracker->flush_policy ) + switch ( trs.tracker->flush_policy ) { case STREAM_FLPOLICY_IGNORE: DebugMessage(DEBUG_STREAM_STATE, "STREAM_FLPOLICY_IGNORE\n"); @@ -1057,25 +1068,25 @@ int TcpReassembler::flush_on_data_policy(Packet* p) case STREAM_FLPOLICY_ON_DATA: { - uint32_t flags = get_forward_packet_dir(p); - int32_t flush_amt = flush_pdu_ips(&flags); + uint32_t flags = get_forward_packet_dir(trs, p); + int32_t flush_amt = flush_pdu_ips(trs, &flags); uint32_t this_flush; while ( flush_amt >= 0 ) { if ( !flush_amt ) - flush_amt = seglist.next->seq - seglist_base_seq; + flush_amt = trs.sos.seglist.next->seq - trs.sos.seglist_base_seq; #if 0 // FIXIT-P can't do this with new HI - copy is inevitable // if this payload is exactly one pdu, don't // actually flush, just use the raw packet - if ( listener->seglist.next && - ( tsd.seq == listener->seglist.next->seq ) && - ( flush_amt == listener->seglist.next->payload_size ) && + if ( listener->trs.sos.seglist.next && + ( tsd.seq == listener->trs.sos.seglist.next->seq ) && + ( flush_amt == listener->trs.sos.seglist.next->payload_size ) && ( flush_amt == p->dsize ) ) { this_flush = flush_amt; - listener->seglist.next->buffered = true; + listener->trs.sos.seglist.next->buffered = true; listener->flush_count++; p->packet_flags |= PKT_PDU_FULL; ShowRebuiltPacket(p); @@ -1083,7 +1094,7 @@ int TcpReassembler::flush_on_data_policy(Packet* p) else #endif { - this_flush = flush_to_seq(flush_amt, p, flags); + this_flush = flush_to_seq(trs, flush_amt, p, flags); } // if we didn't flush as expected, bail // (we can flush less than max dsize) @@ -1091,14 +1102,14 @@ int TcpReassembler::flush_on_data_policy(Packet* p) break; flushed += this_flush; - flags = get_forward_packet_dir(p); - flush_amt = flush_pdu_ips(&flags); + flags = get_forward_packet_dir(trs, p); + flush_amt = flush_pdu_ips(trs, &flags); } - if ( !flags && tracker->splitter->is_paf() ) + if ( !flags && trs.tracker->splitter->is_paf() ) { - fallback( ); - return flush_on_data_policy(p); + fallback(trs); + return flush_on_data_policy(trs, p); } } break; @@ -1106,15 +1117,15 @@ int TcpReassembler::flush_on_data_policy(Packet* p) return flushed; } -int TcpReassembler::flush_on_ack_policy(Packet* p) +int TcpReassembler::flush_on_ack_policy(TcpReassemblerState& trs, Packet* p) { uint32_t flushed = 0; DebugMessage(DEBUG_STREAM_STATE, "In CheckFlushPolicyOnAck\n"); DebugFormat(DEBUG_STREAM_STATE, "Talker flush policy: %s\n", - flush_policy_names[ tracker->flush_policy ]); + flush_policy_names[ trs.tracker->flush_policy ]); - switch (tracker->flush_policy) + switch (trs.tracker->flush_policy) { case STREAM_FLPOLICY_IGNORE: DebugMessage(DEBUG_STREAM_STATE, "STREAM_FLPOLICY_IGNORE\n"); @@ -1122,61 +1133,62 @@ int TcpReassembler::flush_on_ack_policy(Packet* p) case STREAM_FLPOLICY_ON_ACK: { - uint32_t flags = get_reverse_packet_dir(p); - int32_t flush_amt = flush_pdu_ackd(&flags); + uint32_t flags = get_reverse_packet_dir(trs, p); + int32_t flush_amt = flush_pdu_ackd(trs, &flags); while (flush_amt >= 0) { if (!flush_amt) - flush_amt = seglist.next->seq - seglist_base_seq; + flush_amt = trs.sos.seglist.next->seq - trs.sos.seglist_base_seq; - seglist.next = seglist.head; - seglist_base_seq = seglist.head->seq; + trs.sos.seglist.next = trs.sos.seglist.head; + trs.sos.seglist_base_seq = trs.sos.seglist.head->seq; // for consistency with other cases, should return total // but that breaks flushing pipelined pdus - flushed = flush_to_seq(flush_amt, p, flags); + flushed = flush_to_seq(trs, flush_amt, p, flags); // ideally we would purge just once after this loop // but that throws off base - if ( flushed and seglist.head ) - purge_to_seq(seglist.head->seq + flushed); + if ( flushed and trs.sos.seglist.head ) + purge_to_seq(trs, trs.sos.seglist.head->seq + flushed); // if we didn't flush as expected, bail // (we can flush less than max dsize) if (!flushed) break; - flags = get_reverse_packet_dir(p); - flush_amt = flush_pdu_ackd(&flags); + flags = get_reverse_packet_dir(trs, p); + flush_amt = flush_pdu_ackd(trs, &flags); } - if (!flags && tracker->splitter->is_paf()) + if (!flags && trs.tracker->splitter->is_paf()) { - fallback( ); - return flush_on_ack_policy(p); + fallback(trs); + return flush_on_ack_policy(trs, p); } } break; case STREAM_FLPOLICY_ON_DATA: - purge_flushed_ackd( ); + purge_flushed_ackd(trs); break; } return flushed; } -void TcpReassembler::purge_segment_list() +void TcpReassembler::purge_segment_list(TcpReassemblerState& trs) { - seglist.clear( ); - seg_count = 0; - flush_count = 0; - seg_bytes_total = 0; - seg_bytes_logical = 0; + trs.sos.seglist.reset(); + trs.sos.seg_count = 0; + trs.sos.seg_bytes_total = 0; + trs.sos.seg_bytes_logical = 0; + trs.flush_count = 0; } -void TcpReassembler::insert_segment_in_empty_seglist(TcpSegmentDescriptor& tsd) +void TcpReassembler::insert_segment_in_empty_seglist( + TcpReassemblerState& trs, TcpSegmentDescriptor& tsd) { const tcp::TCPHdr* tcph = tsd.get_tcph(); @@ -1186,10 +1198,11 @@ void TcpReassembler::insert_segment_in_empty_seglist(TcpSegmentDescriptor& tsd) if ( tcph->is_syn() ) seq++; - if ( SEQ_GT(tracker->r_win_base, seq) ) + if ( SEQ_GT(trs.tracker->r_win_base, seq) ) { DebugMessage(DEBUG_STREAM_STATE, "segment overlaps ack'd data...\n"); - overlap = tracker->r_win_base - tsd.get_seg_seq(); + overlap = trs.tracker->r_win_base - tsd.get_seg_seq(); + if ( overlap >= tsd.get_seg_len() ) { DebugMessage(DEBUG_STREAM_STATE, "full overlap on ack'd data, dropping segment\n"); @@ -1197,59 +1210,66 @@ void TcpReassembler::insert_segment_in_empty_seglist(TcpSegmentDescriptor& tsd) } } - // BLOCK add new block to seglist containing data - add_reassembly_segment(tsd, tsd.get_seg_len(), overlap, 0, tsd.get_seg_seq() + overlap, nullptr); + // BLOCK add new block to trs.sos.seglist containing data + add_reassembly_segment( + trs, tsd, tsd.get_seg_len(), overlap, 0, tsd.get_seg_seq() + overlap, nullptr); DebugFormat(DEBUG_STREAM_STATE, - "Attached new queue to seglist, %u bytes queued, base_seq 0x%X\n", - tsd.get_seg_len() - overlap, seglist_base_seq); + "Attached new queue to trs.sos.seglist, %u bytes queued, base_seq 0x%X\n", + tsd.get_seg_len() - overlap, trs.sos.seglist_base_seq); } -void TcpReassembler::init_overlap_editor(TcpSegmentDescriptor& tsd) +void TcpReassembler::init_overlap_editor( + TcpReassemblerState& trs, TcpSegmentDescriptor& tsd) { TcpSegmentNode* left = nullptr; TcpSegmentNode* right = nullptr; TcpSegmentNode* tsn = nullptr; + int32_t dist_head; int32_t dist_tail; + DEBUG_WRAP( TcpSegmentNode *lastptr = nullptr; - uint32_t base_seq = seglist_base_seq; + uint32_t base_seq = trs.sos.seglist_base_seq; int last = 0; - ); + ); - if ( seglist.head && seglist.tail ) + if ( trs.sos.seglist.head && trs.sos.seglist.tail ) { - if ( SEQ_GT(tsd.get_seg_seq(), seglist.head->seq) ) - dist_head = tsd.get_seg_seq() - seglist.head->seq; + if ( SEQ_GT(tsd.get_seg_seq(), trs.sos.seglist.head->seq) ) + dist_head = tsd.get_seg_seq() - trs.sos.seglist.head->seq; else - dist_head = seglist.head->seq - tsd.get_seg_seq(); + dist_head = trs.sos.seglist.head->seq - tsd.get_seg_seq(); - if ( SEQ_GT(tsd.get_seg_seq(), seglist.tail->seq) ) - dist_tail = tsd.get_seg_seq() - seglist.tail->seq; + if ( SEQ_GT(tsd.get_seg_seq(), trs.sos.seglist.tail->seq) ) + dist_tail = tsd.get_seg_seq() - trs.sos.seglist.tail->seq; else - dist_tail = seglist.tail->seq - tsd.get_seg_seq(); + dist_tail = trs.sos.seglist.tail->seq - tsd.get_seg_seq(); } else dist_head = dist_tail = 0; if ( SEQ_LEQ(dist_head, dist_tail) ) { - for ( tsn = seglist.head; tsn; tsn = tsn->next ) + for ( tsn = trs.sos.seglist.head; tsn; tsn = tsn->next ) { DEBUG_WRAP( DebugFormat(DEBUG_STREAM_STATE, "tsn: %p seq: 0x%X size: %hu delta: %u\n", - (void*) tsn, tsn->seq, tsn->payload_size, ( tsn->seq - base_seq ) - last); + (void*) tsn, tsn->seq, tsn->payload_size, ( tsn->seq - base_seq ) - last); + last = tsn->seq - base_seq; lastptr = tsn; DebugFormat(DEBUG_STREAM_STATE, " lastptr: %p tsn->next: %p tsn->prev: %p\n", - (void*) lastptr, (void*) tsn->next, (void*) tsn->prev); - ); + (void*) lastptr, (void*) tsn->next, (void*) tsn->prev); + ); right = tsn; + if ( SEQ_GEQ(right->seq, tsd.get_seg_seq() ) ) break; + left = right; } @@ -1258,21 +1278,24 @@ void TcpReassembler::init_overlap_editor(TcpSegmentDescriptor& tsd) } else { - for ( tsn = seglist.tail; tsn; tsn = tsn->prev ) + for ( tsn = trs.sos.seglist.tail; tsn; tsn = tsn->prev ) { DEBUG_WRAP( DebugFormat(DEBUG_STREAM_STATE, "tsn: %p seq: 0x%X size: %hu delta: %u\n", - (void*) tsn, tsn->seq, tsn->payload_size, ( tsn->seq - base_seq ) - last); + (void*) tsn, tsn->seq, tsn->payload_size, ( tsn->seq - base_seq ) - last); + last = tsn->seq - base_seq; lastptr = tsn; DebugFormat(DEBUG_STREAM_STATE, " lastptr: %p tsn->next: %p tsn->prev: %p\n", - (void*) lastptr, (void*) tsn->next, (void*) tsn->prev); - ); + (void*) lastptr, (void*) tsn->next, (void*) tsn->prev); + ); left = tsn; + if ( SEQ_LT(left->seq, tsd.get_seg_seq() ) ) break; + right = left; } @@ -1282,53 +1305,60 @@ void TcpReassembler::init_overlap_editor(TcpSegmentDescriptor& tsd) DebugMessage(DEBUG_STREAM_STATE, "!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+\n"); DebugMessage(DEBUG_STREAM_STATE, "!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+\n"); + DebugFormat(DEBUG_STREAM_STATE, "left: %p:0x%X right: %p:0x%X\n", (void*) left, left ? left->seq : 0, (void*) right, right ? right->seq : 0); - init_soe(tsd, left, right); + trs.sos.init_soe(tsd, left, right); } -int TcpReassembler::insert_segment_in_seglist(TcpSegmentDescriptor& tsd) +int TcpReassembler::insert_segment_in_seglist( + TcpReassemblerState& trs, TcpSegmentDescriptor& tsd) { int rc = STREAM_INSERT_OK; DebugFormat(DEBUG_STREAM_STATE, "Queuing %u bytes on stream!\nbase_seq: %X seq: %X seq_end: %X\n", - tsd.get_end_seq() - tsd.get_seg_seq(), seglist_base_seq, tsd.get_seg_seq(), + tsd.get_end_seq() - tsd.get_seg_seq(), trs.sos.seglist_base_seq, tsd.get_seg_seq(), tsd.get_end_seq()); - DebugFormat(DEBUG_STREAM_STATE, "%u segments on seglist\n", get_pending_segment_count(0)); + DebugFormat(DEBUG_STREAM_STATE, "%u segments on trs.sos.seglist\n", + get_pending_segment_count(trs, 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, tsd) ) + if ( trs.sos.seglist.tail && is_segment_fasttrack(trs, trs.sos.seglist.tail, tsd) ) { /* segment fit cleanly at the end of the segment list */ - TcpSegmentNode* left = seglist.tail; + TcpSegmentNode* left = trs.sos.seglist.tail; DebugFormat(DEBUG_STREAM_STATE, "Fast tracking segment! (tail_seq %X size %d)\n", - seglist.tail->seq, seglist.tail->payload_size); + trs.sos.seglist.tail->seq, trs.sos.seglist.tail->payload_size); // BLOCK add to existing block and/or allocate new block - rc = add_reassembly_segment(tsd, tsd.get_seg_len(), 0, 0, tsd.get_seg_seq(), left); + rc = add_reassembly_segment(trs, tsd, tsd.get_seg_len(), 0, 0, tsd.get_seg_seq(), left); return rc; } - init_overlap_editor(tsd); - rc = eval_left(); + init_overlap_editor(trs, tsd); + rc = eval_left(trs); + if ( rc != STREAM_INSERT_OK ) return rc; - rc = eval_right( ); + rc = eval_right(trs); + if ( rc != STREAM_INSERT_OK ) return rc; - if ( keep_segment ) + if ( trs.sos.keep_segment ) { /* Adjust slide so that is correct relative to orig seq */ - slide = seq - tsd.get_seg_seq(); - rc = add_reassembly_segment(tsd, len, slide, trunc_len, seq, left); + trs.sos.slide = trs.sos.seq - tsd.get_seg_seq(); + rc = add_reassembly_segment( + trs, tsd, trs.sos.len, trs.sos.slide, trs.sos.trunc_len, trs.sos.seq, trs.sos.left); } else { @@ -1339,39 +1369,40 @@ int TcpReassembler::insert_segment_in_seglist(TcpSegmentDescriptor& tsd) return rc; } -int TcpReassembler::queue_packet_for_reassembly(TcpSegmentDescriptor& tsd) +int TcpReassembler::queue_packet_for_reassembly( + TcpReassemblerState& trs, TcpSegmentDescriptor& tsd) { Profile profile(s5TcpInsertPerfStats); int rc = STREAM_INSERT_OK; - if ( seg_count == 0 ) + if ( trs.sos.seg_count == 0 ) { - insert_segment_in_empty_seglist(tsd); + insert_segment_in_empty_seglist(trs, tsd); return STREAM_INSERT_OK; } - if ( SEQ_GT(tracker->r_win_base, tsd.get_seg_seq() ) ) + if ( SEQ_GT(trs.tracker->r_win_base, tsd.get_seg_seq() ) ) { - int32_t offset = tracker->r_win_base - tsd.get_seg_seq(); + int32_t offset = trs.tracker->r_win_base - tsd.get_seg_seq(); if ( offset < tsd.get_seg_len() ) { tsd.slide_segment_in_rcv_window(offset); - rc = insert_segment_in_seglist(tsd); + rc = insert_segment_in_seglist(trs, tsd); tsd.slide_segment_in_rcv_window(-offset); } } else - rc = insert_segment_in_seglist(tsd); + rc = insert_segment_in_seglist(trs, tsd); return rc; } #ifdef SEG_TEST -static void CheckSegments(const TcpStreamTracker* a) +static void CheckSegments(const TcpStreamtrs.tracker* a) { - TcpSegmentNode* tsn = a->seglist.head; + TcpSegmentNode* tsn = a->trs.sos.seglist.head; uint32_t sx = tsn ? tsn->seq : 0; while ( tsn ) @@ -1385,6 +1416,5 @@ static void CheckSegments(const TcpStreamTracker* a) tsn = tsn->next; } } - #endif diff --git a/src/stream/tcp/tcp_reassembler.h b/src/stream/tcp/tcp_reassembler.h index 28661bee7..8a9ffcf54 100644 --- a/src/stream/tcp/tcp_reassembler.h +++ b/src/stream/tcp/tcp_reassembler.h @@ -31,137 +31,65 @@ class TcpStreamTracker; class TcpReassembler : public SegmentOverlapEditor { public: - - virtual int queue_packet_for_reassembly(TcpSegmentDescriptor&); - virtual void purge_segment_list(); - virtual int flush_stream(snort::Packet* p, uint32_t dir, bool final_flush = false); - virtual int purge_flushed_ackd(); - virtual void flush_queued_segments(snort::Flow* flow, bool clear, snort::Packet* p = nullptr); - virtual bool is_segment_pending_flush(); - virtual int flush_on_data_policy(snort::Packet*); - virtual int flush_on_ack_policy(snort::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); - } - - uint32_t get_seglist_base_seq() const - { - return seglist_base_seq; - } - - void set_xtradata_mask(uint32_t xtradata_mask) - { - this->xtradata_mask = xtradata_mask; - } - - uint32_t get_xtradata_mask() const - { - return xtradata_mask; - } - - uint32_t get_seg_count() const - { - return seg_count; - } - - uint32_t get_seg_bytes_total() const - { - return seg_bytes_total; - } - - uint32_t get_overlap_count() const - { - return overlap_count; - } - - void set_overlap_count(uint32_t overlap_count) - { - this->overlap_count = overlap_count; - } - - uint32_t get_flush_count() const - { - return flush_count; - } - - uint32_t get_seg_bytes_logical() const - { - return seg_bytes_logical; - } - - ReassemblyPolicy get_reassembly_policy() const - { - return reassembly_policy; - } - - void trace_segments(); + virtual int queue_packet_for_reassembly(TcpReassemblerState&, TcpSegmentDescriptor&); + virtual void purge_segment_list(TcpReassemblerState&); + virtual int purge_flushed_ackd(TcpReassemblerState&); + virtual int flush_stream( + TcpReassemblerState&, snort::Packet* p, uint32_t dir, bool final_flush = false); + virtual void flush_queued_segments( + TcpReassemblerState&, snort::Flow* flow, bool clear, snort::Packet* p = nullptr); + virtual bool is_segment_pending_flush(TcpReassemblerState&); + virtual int flush_on_data_policy(TcpReassemblerState&, snort::Packet*); + virtual int flush_on_ack_policy(TcpReassemblerState&, snort::Packet*); + virtual void trace_segments(TcpReassemblerState&); protected: - TcpReassembler(TcpSession* session, TcpStreamTracker* tracker, - StreamPolicy os_policy, bool server) : server_side(server), tracker(tracker) - { - this->session = session; - set_tcp_reassembly_policy(os_policy); - - if ( server_side ) - { - ignore_dir = SSN_DIR_FROM_CLIENT; - packet_dir = PKT_FROM_CLIENT; - } - else - { - ignore_dir = SSN_DIR_FROM_SERVER; - packet_dir = PKT_FROM_SERVER; - } - - seglist.head = nullptr; - seglist.tail = nullptr; - seglist.next = nullptr; - } - - int add_reassembly_segment(TcpSegmentDescriptor&, int16_t len, uint32_t slide, uint32_t trunc, - uint32_t seq, TcpSegmentNode* left) override; - int dup_reassembly_segment(TcpSegmentNode* left, TcpSegmentNode** retSeg) override; - int delete_reassembly_segment(TcpSegmentNode*) 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(); - int trim_delete_reassembly_segment(TcpSegmentNode*, uint32_t flush_seq); - void queue_reassembly_segment(TcpSegmentNode* prev, TcpSegmentNode*); - void init_overlap_editor(TcpSegmentDescriptor&); - bool is_segment_fasttrack(TcpSegmentNode* tail, TcpSegmentDescriptor&); - int purge_alerts(snort::Flow*); - void show_rebuilt_packet(snort::Packet*); - uint32_t get_flush_data_len(TcpSegmentNode*, uint32_t to_seq, unsigned max); - int flush_data_segments(snort::Packet*, uint32_t total, snort::Packet* pdu); - void prep_pdu(snort::Flow*, snort::Packet*, uint32_t pkt_flags, snort::Packet* pdu); - snort::Packet* initialize_pdu(snort::Packet* p, uint32_t pkt_flags, struct timeval tv); - int _flush_to_seq(uint32_t bytes, snort::Packet*, uint32_t pkt_flags); - int flush_to_seq(uint32_t bytes, snort::Packet*, uint32_t pkt_flags); - int do_zero_byte_flush(snort::Packet* p, uint32_t pkt_flags); - uint32_t get_q_footprint(); - uint32_t get_q_sequenced(); - void final_flush(snort::Packet*, uint32_t dir); - uint32_t get_reverse_packet_dir(const snort::Packet*); - uint32_t get_forward_packet_dir(const snort::Packet*); - int32_t flush_pdu_ips(uint32_t*); - void fallback(); - int32_t flush_pdu_ackd(uint32_t* flags); - int purge_to_seq(uint32_t flush_seq); - - bool server_side; - TcpStreamTracker* tracker; - uint8_t ignore_dir; - uint8_t packet_dir; - uint32_t flush_count = 0; /* number of flushed queued segments */ - uint32_t xtradata_mask = 0; /* extra data available to log */ + TcpReassembler() = default; + + int add_reassembly_segment( + TcpReassemblerState&, TcpSegmentDescriptor&, int16_t len, uint32_t slide, + uint32_t trunc, uint32_t seq, TcpSegmentNode* left) override; + + int dup_reassembly_segment( + TcpReassemblerState&, TcpSegmentNode* left, TcpSegmentNode** retSeg) override; + + int delete_reassembly_segment(TcpReassemblerState&, TcpSegmentNode*) override; + + virtual void insert_segment_in_empty_seglist(TcpReassemblerState&, TcpSegmentDescriptor&); + virtual int insert_segment_in_seglist(TcpReassemblerState&, TcpSegmentDescriptor&); + + virtual uint32_t get_pending_segment_count(TcpReassemblerState&, unsigned max); + + bool flush_data_ready(TcpReassemblerState&); + int trim_delete_reassembly_segment(TcpReassemblerState&, TcpSegmentNode*, uint32_t flush_seq); + void queue_reassembly_segment(TcpReassemblerState&, TcpSegmentNode* prev, TcpSegmentNode*); + void init_overlap_editor(TcpReassemblerState&, TcpSegmentDescriptor&); + bool is_segment_fasttrack(TcpReassemblerState&, TcpSegmentNode* tail, TcpSegmentDescriptor&); + int purge_alerts(TcpReassemblerState&, snort::Flow*); + void show_rebuilt_packet(TcpReassemblerState&, snort::Packet*); + + uint32_t get_flush_data_len( + TcpReassemblerState&, TcpSegmentNode*, uint32_t to_seq, unsigned max); + int flush_data_segments( + TcpReassemblerState&, snort::Packet*, uint32_t total, snort::Packet* pdu); + void prep_pdu( + TcpReassemblerState&, snort::Flow*, snort::Packet*, uint32_t pkt_flags, + snort::Packet* pdu); + snort::Packet* initialize_pdu( + TcpReassemblerState&, snort::Packet* p, uint32_t pkt_flags, struct timeval tv); + + int _flush_to_seq(TcpReassemblerState&, uint32_t bytes, snort::Packet*, uint32_t pkt_flags); + int flush_to_seq(TcpReassemblerState&, uint32_t bytes, snort::Packet*, uint32_t pkt_flags); + int do_zero_byte_flush(TcpReassemblerState&, snort::Packet* p, uint32_t pkt_flags); + uint32_t get_q_footprint(TcpReassemblerState&); + uint32_t get_q_sequenced(TcpReassemblerState&); + void final_flush(TcpReassemblerState&, snort::Packet*, uint32_t dir); + uint32_t get_reverse_packet_dir(TcpReassemblerState&, const snort::Packet*); + uint32_t get_forward_packet_dir(TcpReassemblerState&, const snort::Packet*); + int32_t flush_pdu_ips(TcpReassemblerState&, uint32_t*); + void fallback(TcpReassemblerState&); + int32_t flush_pdu_ackd(TcpReassemblerState&, uint32_t* flags); + int purge_to_seq(TcpReassemblerState&, uint32_t flush_seq); }; #endif diff --git a/src/stream/tcp/tcp_reassemblers.cc b/src/stream/tcp/tcp_reassemblers.cc index e54761e84..91b6b3ba9 100644 --- a/src/stream/tcp/tcp_reassemblers.cc +++ b/src/stream/tcp/tcp_reassemblers.cc @@ -24,401 +24,320 @@ #endif #include "tcp_reassemblers.h" +#include "stream/libtcp/tcp_stream_tracker.h" class TcpReassemblerFirst : public TcpReassembler { public: - TcpReassemblerFirst(TcpSession* session, TcpStreamTracker* tracker, bool server) : - TcpReassembler(session, tracker, StreamPolicy::OS_FIRST, server) - { } + TcpReassemblerFirst() = default; private: - int insert_left_overlap() override - { - return left_overlap_keep_first( ); - } + int insert_left_overlap(TcpReassemblerState& trs) override + { return left_overlap_keep_first(trs); } - void insert_right_overlap() override - { - right_overlap_truncate_new( ); - } + void insert_right_overlap(TcpReassemblerState& trs) override + { right_overlap_truncate_new(trs); } - int insert_full_overlap() override - { - return full_right_overlap_os5( ); - } + int insert_full_overlap(TcpReassemblerState& trs) override + { return full_right_overlap_os5(trs); } }; class TcpReassemblerLast : public TcpReassembler { public: - TcpReassemblerLast(TcpSession* session, TcpStreamTracker* tracker, bool server) : - TcpReassembler(session, tracker, StreamPolicy::OS_LAST, server) - { } + TcpReassemblerLast() = default; private: - int insert_left_overlap() override - { - return left_overlap_keep_last( ); - } + int insert_left_overlap(TcpReassemblerState& trs) override + { return left_overlap_keep_last(trs); } - void insert_right_overlap() override - { - right_overlap_truncate_existing( ); - } + void insert_right_overlap(TcpReassemblerState& trs) override + { right_overlap_truncate_existing(trs); } - int insert_full_overlap() override - { - return full_right_overlap_os4( ); - } + int insert_full_overlap(TcpReassemblerState& trs) override + { return full_right_overlap_os4(trs); } }; class TcpReassemblerLinux : public TcpReassembler { public: - TcpReassemblerLinux(TcpSession* session, TcpStreamTracker* tracker, bool server) : - TcpReassembler(session, tracker, StreamPolicy::OS_LINUX, server) - { } + TcpReassemblerLinux() = default; private: - int insert_left_overlap() override - { - return left_overlap_keep_first( ); - } + int insert_left_overlap(TcpReassemblerState& trs) override + { return left_overlap_keep_first(trs); } - void insert_right_overlap() override - { - right_overlap_truncate_existing( ); - } + void insert_right_overlap(TcpReassemblerState& trs) override + { right_overlap_truncate_existing(trs); } - int insert_full_overlap() override - { - return full_right_overlap_os2( ); - } + int insert_full_overlap(TcpReassemblerState& trs) override + { return full_right_overlap_os2(trs); } }; class TcpReassemblerOldLinux : public TcpReassembler { public: - TcpReassemblerOldLinux(TcpSession* session, TcpStreamTracker* tracker, bool server) : - TcpReassembler(session, tracker, StreamPolicy::OS_OLD_LINUX, server) - { } + TcpReassemblerOldLinux() = default; private: - int insert_left_overlap() override - { - return left_overlap_keep_first( ); - } + int insert_left_overlap(TcpReassemblerState& trs) override + { return left_overlap_keep_first(trs); } - void insert_right_overlap() override - { - right_overlap_truncate_existing( ); - } + void insert_right_overlap(TcpReassemblerState& trs) override + { right_overlap_truncate_existing(trs); } - int insert_full_overlap() override - { - return full_right_overlap_os4( ); - } + int insert_full_overlap(TcpReassemblerState& trs) override + { return full_right_overlap_os4(trs); } }; class TcpReassemblerBSD : public TcpReassembler { public: - TcpReassemblerBSD(TcpSession* session, TcpStreamTracker* tracker, bool server) : - TcpReassembler(session, tracker, StreamPolicy::OS_BSD, server) - { } + TcpReassemblerBSD() = default; private: - int insert_left_overlap() override - { - return left_overlap_keep_first( ); - } + int insert_left_overlap(TcpReassemblerState& trs) override + { return left_overlap_keep_first(trs); } - void insert_right_overlap() override - { - right_overlap_truncate_existing( ); - } + void insert_right_overlap(TcpReassemblerState& trs) override + { right_overlap_truncate_existing(trs); } - int insert_full_overlap() override - { - return full_right_overlap_os1( ); - } + int insert_full_overlap(TcpReassemblerState& trs) override + { return full_right_overlap_os1(trs); } }; class TcpReassemblerMacOS : public TcpReassembler { public: - TcpReassemblerMacOS(TcpSession* session, TcpStreamTracker* tracker, bool server) : - TcpReassembler(session, tracker, StreamPolicy::OS_MACOS, server) - { } + TcpReassemblerMacOS() = default; private: - int insert_left_overlap() override - { - return left_overlap_keep_first( ); - } + int insert_left_overlap(TcpReassemblerState& trs) override + { return left_overlap_keep_first(trs); } - void insert_right_overlap() override - { - right_overlap_truncate_existing( ); - } + void insert_right_overlap(TcpReassemblerState& trs) override + { right_overlap_truncate_existing(trs); } - int insert_full_overlap() override - { - return full_right_overlap_os1( ); - } + int insert_full_overlap(TcpReassemblerState& trs) override + { return full_right_overlap_os1(trs); } }; class TcpReassemblerSolaris : public TcpReassembler { public: - TcpReassemblerSolaris(TcpSession* session, TcpStreamTracker* tracker, bool server) : - TcpReassembler(session, tracker, StreamPolicy::OS_SOLARIS, server) - { } + TcpReassemblerSolaris() = default; private: - int insert_left_overlap() override - { - return left_overlap_trim_first( ); - } + int insert_left_overlap(TcpReassemblerState& trs) override + { return left_overlap_trim_first(trs); } - void insert_right_overlap() override - { - right_overlap_truncate_new( ); - } + void insert_right_overlap(TcpReassemblerState& trs) override + { right_overlap_truncate_new(trs); } - int insert_full_overlap() override - { - return full_right_overlap_os3( ); - } + int insert_full_overlap(TcpReassemblerState& trs) override + { return full_right_overlap_os3(trs); } }; class TcpReassemblerIrix : public TcpReassembler { public: - TcpReassemblerIrix(TcpSession* session, TcpStreamTracker* tracker, bool server) : - TcpReassembler(session, tracker, StreamPolicy::OS_IRIX, server) - { } + TcpReassemblerIrix() = default; private: - int insert_left_overlap() override - { - return left_overlap_keep_first( ); - } + int insert_left_overlap(TcpReassemblerState& trs) override + { return left_overlap_keep_first(trs); } - void insert_right_overlap() override - { - right_overlap_truncate_existing( ); - } + void insert_right_overlap(TcpReassemblerState& trs) override + { right_overlap_truncate_existing(trs); } - int insert_full_overlap() override - { - return full_right_overlap_os2( ); - } + int insert_full_overlap(TcpReassemblerState& trs) override + { return full_right_overlap_os2(trs); } }; class TcpReassemblerHpux11 : public TcpReassembler { public: - TcpReassemblerHpux11(TcpSession* session, TcpStreamTracker* tracker, bool server) : - TcpReassembler(session, tracker, StreamPolicy::OS_HPUX11, server) - { } + TcpReassemblerHpux11() = default; private: - int insert_left_overlap() override - { - return left_overlap_trim_first( ); - } + int insert_left_overlap(TcpReassemblerState& trs) override + { return left_overlap_trim_first(trs); } - void insert_right_overlap() override - { - right_overlap_truncate_new( ); - } + void insert_right_overlap(TcpReassemblerState& trs) override + { right_overlap_truncate_new(trs); } - int insert_full_overlap() override - { - return full_right_overlap_os3( ); - } + int insert_full_overlap(TcpReassemblerState& trs) override + { return full_right_overlap_os3(trs); } }; class TcpReassemblerHpux10 : public TcpReassembler { public: - TcpReassemblerHpux10(TcpSession* session, TcpStreamTracker* tracker, bool server) : - TcpReassembler(session, tracker, StreamPolicy::OS_HPUX10, server) - { } + TcpReassemblerHpux10() = default; private: - int insert_left_overlap() override - { - return left_overlap_keep_first( ); - } + int insert_left_overlap(TcpReassemblerState& trs) override + { return left_overlap_keep_first(trs); } - void insert_right_overlap() override - { - right_overlap_truncate_existing( ); - } + void insert_right_overlap(TcpReassemblerState& trs) override + { right_overlap_truncate_existing(trs); } - int insert_full_overlap() override - { - return full_right_overlap_os2( ); - } + int insert_full_overlap(TcpReassemblerState& trs) override + { return full_right_overlap_os2(trs); } }; class TcpReassemblerWindows : public TcpReassembler { public: - TcpReassemblerWindows(TcpSession* session, TcpStreamTracker* tracker, bool server) : - TcpReassembler(session, tracker, StreamPolicy::OS_WINDOWS, server) - { } + TcpReassemblerWindows() = default; private: - int insert_left_overlap() override - { - return left_overlap_keep_first( ); - } + int insert_left_overlap(TcpReassemblerState& trs) override + { return left_overlap_keep_first(trs); } - void insert_right_overlap() override - { - right_overlap_truncate_existing( ); - } + void insert_right_overlap(TcpReassemblerState& trs) override + { right_overlap_truncate_existing(trs); } - int insert_full_overlap() override - { - return full_right_overlap_os1( ); - } + int insert_full_overlap(TcpReassemblerState& trs) override + { return full_right_overlap_os1(trs); } }; class TcpReassemblerWindows2K3 : public TcpReassembler { public: - TcpReassemblerWindows2K3(TcpSession* session, TcpStreamTracker* tracker, bool server) : - TcpReassembler(session, tracker, StreamPolicy::OS_WINDOWS2K3, server) - { } + TcpReassemblerWindows2K3() = default; private: - int insert_left_overlap() override - { - return left_overlap_keep_first( ); - } + int insert_left_overlap(TcpReassemblerState& trs) override + { return left_overlap_keep_first(trs); } - void insert_right_overlap() override - { - right_overlap_truncate_existing( ); - } + void insert_right_overlap(TcpReassemblerState& trs) override + { right_overlap_truncate_existing(trs); } - int insert_full_overlap() override - { - return full_right_overlap_os1( ); - } + int insert_full_overlap(TcpReassemblerState& trs) override + { return full_right_overlap_os1(trs); } }; class TcpReassemblerVista : public TcpReassembler { public: - TcpReassemblerVista(TcpSession* session, TcpStreamTracker* tracker, bool server) : - TcpReassembler(session, tracker, StreamPolicy::OS_VISTA, server) - { } + TcpReassemblerVista() = default; private: - int insert_left_overlap() override - { - return left_overlap_keep_first( ); - } + int insert_left_overlap(TcpReassemblerState& trs) override + { return left_overlap_keep_first(trs); } - void insert_right_overlap() override - { - right_overlap_truncate_new( ); - } + void insert_right_overlap(TcpReassemblerState& trs) override + { right_overlap_truncate_new(trs); } - int insert_full_overlap() override - { - return full_right_overlap_os5 ( ); - } + int insert_full_overlap(TcpReassemblerState& trs) override + { return full_right_overlap_os5 (trs); } }; class TcpReassemblerProxy : public TcpReassemblerFirst { public: - TcpReassemblerProxy(TcpSession* session, TcpStreamTracker* tracker, bool server) : - TcpReassemblerFirst(session, tracker, server) - { - tcp_ips_data = NORM_MODE_TEST; - } + TcpReassemblerProxy() = default; private: - int insert_left_overlap() override - { - return left_overlap_keep_first( ); - } + int insert_left_overlap(TcpReassemblerState& trs) override + { return left_overlap_keep_first(trs); } - void insert_right_overlap() override - { - right_overlap_truncate_new( ); - } + void insert_right_overlap(TcpReassemblerState& trs) override + { right_overlap_truncate_new(trs); } - int insert_full_overlap() override - { - return full_right_overlap_os5( ); - } + int insert_full_overlap(TcpReassemblerState& trs) override + { return full_right_overlap_os5(trs); } }; -TcpReassembler* TcpReassemblerFactory::create(TcpSession* session, TcpStreamTracker* tracker, - StreamPolicy os_policy, bool server) +static ReassemblyPolicy stream_reassembly_policy_map[] = { - NormMode tcp_ips_data = Normalize_GetMode(NORM_TCP_IPS); + ReassemblyPolicy::OS_INVALID, + ReassemblyPolicy::OS_FIRST, + ReassemblyPolicy::OS_LAST, + ReassemblyPolicy::OS_LINUX, + ReassemblyPolicy::OS_OLD_LINUX, + ReassemblyPolicy::OS_BSD, + ReassemblyPolicy::OS_MACOS, + ReassemblyPolicy::OS_SOLARIS, + ReassemblyPolicy::OS_IRIX, + ReassemblyPolicy::OS_HPUX11, + ReassemblyPolicy::OS_HPUX10, + ReassemblyPolicy::OS_WINDOWS, + ReassemblyPolicy::OS_WINDOWS2K3, + ReassemblyPolicy::OS_VISTA, + ReassemblyPolicy::OS_PROXY, + ReassemblyPolicy::OS_DEFAULT +}; - if (tcp_ips_data == NORM_MODE_ON) - return new TcpReassemblerFirst(session, tracker, server); +void TcpReassemblerPolicy::init(TcpSession* ssn, TcpStreamTracker* trk, StreamPolicy pol, bool server) +{ + trs.sos.init_sos(ssn, stream_reassembly_policy_map[ static_cast(pol) ]); + trs.server_side = server; + trs.tracker = trk; + + if ( trs.server_side ) + { + trs.ignore_dir = SSN_DIR_FROM_CLIENT; + trs.packet_dir = PKT_FROM_CLIENT; + } else { - switch (os_policy) - { - case StreamPolicy::OS_FIRST: - return new TcpReassemblerFirst(session, tracker, server); - - case StreamPolicy::OS_LAST: - return new TcpReassemblerLast(session, tracker, server); - - case StreamPolicy::OS_LINUX: - return new TcpReassemblerLinux(session, tracker, server); - - case StreamPolicy::OS_OLD_LINUX: - return new TcpReassemblerOldLinux(session, tracker, server); - - case StreamPolicy::OS_BSD: - return new TcpReassemblerBSD(session, tracker, server); - - case StreamPolicy::OS_MACOS: - return new TcpReassemblerMacOS(session, tracker, server); - - case StreamPolicy::OS_SOLARIS: - return new TcpReassemblerSolaris(session, tracker, server); - - case StreamPolicy::OS_IRIX: - return new TcpReassemblerIrix(session, tracker, server); - - case StreamPolicy::OS_HPUX11: - return new TcpReassemblerHpux11(session, tracker, server); - - case StreamPolicy::OS_HPUX10: - return new TcpReassemblerHpux10(session, tracker, server); + trs.ignore_dir = SSN_DIR_FROM_SERVER; + trs.packet_dir = PKT_FROM_SERVER; + } - case StreamPolicy::OS_WINDOWS: - return new TcpReassemblerWindows(session, tracker, server); + trs.flush_count = 0; + trs.xtradata_mask = 0; - case StreamPolicy::OS_WINDOWS2K3: - return new TcpReassemblerWindows2K3(session, tracker, server); + reassembler = TcpReassemblerFactory::create(pol); +} - case StreamPolicy::OS_VISTA: - return new TcpReassemblerVista(session, tracker, server); +void TcpReassemblerPolicy::reset() +{ + init(nullptr, nullptr, StreamPolicy::OS_INVALID, false); +} - case StreamPolicy::OS_PROXY: - return new TcpReassemblerProxy(session, tracker, server); +TcpReassembler* TcpReassemblerFactory::create(StreamPolicy os_policy) +{ + static TcpReassemblerFirst first; + static TcpReassemblerLast last; + static TcpReassemblerLinux linux; + static TcpReassemblerOldLinux old_linux; + static TcpReassemblerBSD bsd; + static TcpReassemblerMacOS mac_os; + static TcpReassemblerSolaris solaris; + static TcpReassemblerIrix irix; + static TcpReassemblerHpux11 hpux11; + static TcpReassemblerHpux10 hpux10; + static TcpReassemblerWindows windows; + static TcpReassemblerWindows2K3 windows_2K3; + static TcpReassemblerVista vista; + static TcpReassemblerProxy proxy; - default: - return new TcpReassemblerBSD(session, tracker, server); - } - } + NormMode tcp_ips_data = Normalize_GetMode(NORM_TCP_IPS); + StreamPolicy actual = (tcp_ips_data == NORM_MODE_ON) ? StreamPolicy::OS_FIRST : os_policy; + TcpReassembler* reassembler; + + switch (actual) + { + case StreamPolicy::OS_FIRST: reassembler = &first; break; + case StreamPolicy::OS_LAST: reassembler = &last; break; + case StreamPolicy::OS_LINUX: reassembler = &linux; break; + case StreamPolicy::OS_OLD_LINUX: reassembler = &old_linux; break; + case StreamPolicy::OS_BSD: reassembler = &bsd; break; + case StreamPolicy::OS_MACOS: reassembler = &mac_os; break; + case StreamPolicy::OS_SOLARIS: reassembler = &solaris; break; + case StreamPolicy::OS_IRIX: reassembler = &irix; break; + case StreamPolicy::OS_HPUX11: reassembler = &hpux11; break; + case StreamPolicy::OS_HPUX10: reassembler = &hpux10; break; + case StreamPolicy::OS_WINDOWS: reassembler = &windows; break; + case StreamPolicy::OS_WINDOWS2K3: reassembler = &windows_2K3; break; + case StreamPolicy::OS_VISTA: reassembler = &vista; break; + case StreamPolicy::OS_PROXY: reassembler = &proxy; break; + default: reassembler = &bsd; break; + } + + return reassembler; } diff --git a/src/stream/tcp/tcp_reassemblers.h b/src/stream/tcp/tcp_reassemblers.h index e9b1674ac..affa5ba98 100644 --- a/src/stream/tcp/tcp_reassemblers.h +++ b/src/stream/tcp/tcp_reassemblers.h @@ -22,14 +22,90 @@ #ifndef TCP_REASSEMBLERS_H #define TCP_REASSEMBLERS_H -#include "stream/tcp/tcp_reassembler.h" +#include "tcp_reassembler.h" class TcpReassemblerFactory { public: - static TcpReassembler* create(TcpSession* session, TcpStreamTracker* tracker, - StreamPolicy os_policy, bool server); + static TcpReassembler* create(StreamPolicy); }; +class TcpReassemblerPolicy + +{ +public: + TcpReassemblerPolicy() = default; + ~TcpReassemblerPolicy() = default; + + void init(TcpSession* ssn, TcpStreamTracker* trk, StreamPolicy pol, bool server); + void reset(); + + int queue_packet_for_reassembly(TcpSegmentDescriptor& tsd) + { return reassembler->queue_packet_for_reassembly(trs, tsd); } + + void purge_segment_list() + { reassembler->purge_segment_list(trs); } + + int purge_flushed_ackd() + { return reassembler->purge_flushed_ackd(trs); } + + int flush_stream(snort::Packet* p, uint32_t dir, bool final_flush = false) + { return reassembler->flush_stream(trs, p, dir, final_flush); } + + void flush_queued_segments(snort::Flow* flow, bool clear, snort::Packet* p = nullptr) + { reassembler->flush_queued_segments(trs, flow, clear, p); } + + bool is_segment_pending_flush() + { return reassembler->is_segment_pending_flush(trs); } + + int flush_on_data_policy(snort::Packet* p) + { return reassembler->flush_on_data_policy(trs, p); } + + int flush_on_ack_policy(snort::Packet* p) + { return reassembler->flush_on_ack_policy(trs, p); } + + void trace_segments() + { reassembler->trace_segments(trs); } + + void set_seglist_base_seq(uint32_t seglist_base_seq) + { trs.sos.seglist_base_seq = seglist_base_seq; } + + uint32_t get_seglist_base_seq() const + { return trs.sos.seglist_base_seq; } + + void set_xtradata_mask(uint32_t xtradata_mask) + { trs.xtradata_mask = xtradata_mask; } + + uint32_t get_xtradata_mask() const + { return trs.xtradata_mask; } + + uint32_t get_seg_count() const + { return trs.sos.seg_count; } + + uint32_t get_seg_bytes_total() const + { return trs.sos.seg_bytes_total; } + + uint32_t get_overlap_count() const + { return trs.sos.overlap_count; } + + void set_overlap_count(uint32_t overlap_count) + { trs.sos.overlap_count = overlap_count; } + + uint32_t get_flush_count() const + { return trs.flush_count; } + + uint32_t get_seg_bytes_logical() const + { return trs.sos.seg_bytes_logical; } + + ReassemblyPolicy get_reassembly_policy() const + { return trs.sos.reassembly_policy; } + + void set_norm_mode_test() + { trs.sos.tcp_ips_data = NORM_MODE_TEST; } + +private: + TcpReassembler* reassembler = nullptr; + TcpReassemblerState trs; +}; #endif diff --git a/src/stream/tcp/tcp_segment_node.cc b/src/stream/tcp/tcp_segment_node.cc index d8649f690..47b19bb0a 100644 --- a/src/stream/tcp/tcp_segment_node.cc +++ b/src/stream/tcp/tcp_segment_node.cc @@ -27,6 +27,7 @@ #include "utils/util.h" +#include "segment_overlap_editor.h" #include "tcp_module.h" // FIXIT-P this is going to set each member 2X; once here and once in init @@ -46,9 +47,9 @@ TcpSegmentNode* TcpSegmentNode::init(TcpSegmentDescriptor& tsd) return init(tsd.get_pkt()->pkth->ts, tsd.get_pkt()->data, tsd.get_seg_len() ); } -TcpSegmentNode* TcpSegmentNode::init(TcpSegmentNode& tsn) +TcpSegmentNode* TcpSegmentNode::init(TcpSegmentNode& tns) { - return init(tsn.tv, tsn.payload(), tsn.payload_size); + return init(tns.tv, tns.payload(), tns.payload_size); } TcpSegmentNode* TcpSegmentNode::init(const struct timeval& tv, const uint8_t* data, unsigned dsize) diff --git a/src/stream/tcp/tcp_segment_node.h b/src/stream/tcp/tcp_segment_node.h index 157581751..8092ab87d 100644 --- a/src/stream/tcp/tcp_segment_node.h +++ b/src/stream/tcp/tcp_segment_node.h @@ -16,7 +16,7 @@ // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. //-------------------------------------------------------------------------- -// tcp_segment.h author davis mcpherson +// tcp_segment_node.h author davis mcpherson // Created on: Sep 21, 2015 #ifndef TCP_SEGMENT_H @@ -26,6 +26,8 @@ #include "stream/libtcp/tcp_segment_descriptor.h" #include "stream/tcp/tcp_defs.h" +class TcpSegmentDescriptor; + //----------------------------------------------------------------- // we make a lot of TcpSegments so it is organized by member // size/alignment requirements to minimize unused space @@ -37,7 +39,7 @@ struct TcpSegmentNode TcpSegmentNode(); static TcpSegmentNode* init(TcpSegmentDescriptor& tsd); - static TcpSegmentNode* init(TcpSegmentNode& tsn); + static TcpSegmentNode* init(TcpSegmentNode& tns); static TcpSegmentNode* init(const struct timeval&, const uint8_t*, unsigned); void term(); @@ -66,32 +68,10 @@ struct TcpSegmentNode class TcpSegmentList { public: - TcpSegmentList() : - head(nullptr), tail(nullptr), next(nullptr), count(0) - { - } - - ~TcpSegmentList() - { - 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. - TcpSegmentNode* next; - - uint32_t count; - - uint32_t clear() + uint32_t reset() { int i = 0; - DebugMessage(DEBUG_STREAM_STATE, "Clearing segment list.\n"); while ( head ) { i++; @@ -102,7 +82,6 @@ public: head = tail = next = nullptr; count = 0; - DebugFormat(DEBUG_STREAM_STATE, "Dropped %d segments\n", i); return i; } @@ -113,6 +92,7 @@ public: ss->next = prev->next; ss->prev = prev; prev->next = ss; + if ( ss->next ) ss->next->prev = ss; else @@ -121,6 +101,7 @@ public: else { ss->next = head; + if ( ss->next ) ss->next->prev = ss; else @@ -145,6 +126,16 @@ public: count--; } + + TcpSegmentNode* head = nullptr; + TcpSegmentNode* tail = nullptr; + + // 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. + TcpSegmentNode* next = nullptr; + uint32_t count = 0; }; #endif diff --git a/src/stream/tcp/tcp_session.cc b/src/stream/tcp/tcp_session.cc index b849e85f1..5b5898881 100644 --- a/src/stream/tcp/tcp_session.cc +++ b/src/stream/tcp/tcp_session.cc @@ -69,21 +69,20 @@ static THREAD_LOCAL const char* t_name = nullptr; static THREAD_LOCAL const char* l_name = nullptr; #endif -TcpSession::TcpSession(Flow* flow) : TcpStreamSession(flow) +TcpSession::TcpSession(Flow* flow) + : TcpStreamSession(flow) { tsm = TcpStreamStateMachine::get_instance(); - client = new TcpTracker(true, this); - server = new TcpTracker(false, this); splitter_init = false; + + client.session = this; + server.session = this; } TcpSession::~TcpSession() { if (tcp_init) clear_session(true, false, false); - - delete client; - delete server; } bool TcpSession::setup(Packet* p) @@ -91,9 +90,6 @@ bool TcpSession::setup(Packet* p) TcpStreamSession::setup(p); splitter_init = false; - client->init_toolbox(); - server->init_toolbox(); - SESSION_STATS_ADD(tcpStats); return true; } @@ -111,21 +107,21 @@ void TcpSession::restart(Packet* p) if (p->is_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); } //------------------------------------------------------------------------- @@ -146,18 +142,15 @@ void TcpSession::clear_session(bool free_flow_data, bool flush_segments, bool re assert(!p or p->flow == flow); DetectionEngine::onload(flow); - if ( client->reassembler ) - { - if ( flush_segments ) - client->reassembler->flush_queued_segments(flow, true, p); - client->reassembler->purge_segment_list(); - } - - if ( server->reassembler ) + if ( tcp_init ) { if ( flush_segments ) - server->reassembler->flush_queued_segments(flow, true, p); - server->reassembler->purge_segment_list(); + { + client.reassembler.flush_queued_segments(flow, true, p); + server.reassembler.flush_queued_segments(flow, true, p); + } + client.reassembler.purge_segment_list(); + server.reassembler.purge_segment_list(); } if ( tcp_init ) @@ -172,15 +165,15 @@ void TcpSession::clear_session(bool free_flow_data, bool flush_segments, bool re if ( restart ) { flow->restart(free_flow_data); - paf_reset(&client->paf_state); - paf_reset(&server->paf_state); + paf_reset(&client.paf_state); + paf_reset(&server.paf_state); } else { flow->clear(free_flow_data); - paf_clear(&client->paf_state); - paf_clear(&server->paf_state); + paf_clear(&client.paf_state); + paf_clear(&server.paf_state); } set_splitter(true, nullptr); @@ -307,7 +300,7 @@ bool TcpSession::flow_exceeds_config_thresholds(TcpSegmentDescriptor& tsd) } if ( config->max_queued_bytes - && ( listener->reassembler->get_seg_bytes_total() > config->max_queued_bytes ) ) + && ( listener->reassembler.get_seg_bytes_total() > config->max_queued_bytes ) ) { tcpStats.exceeded_max_bytes++; // FIXIT-H add one alert per flow per above @@ -315,7 +308,7 @@ bool TcpSession::flow_exceeds_config_thresholds(TcpSegmentDescriptor& tsd) } if ( config->max_queued_segs - && ( listener->reassembler->get_seg_count() + 1 > config->max_queued_segs ) ) + && ( listener->reassembler.get_seg_count() + 1 > config->max_queued_segs ) ) { tcpStats.exceeded_max_segs++; // FIXIT-H add one alert per flow per above @@ -339,14 +332,14 @@ void TcpSession::process_tcp_stream(TcpSegmentDescriptor& tsd) return; DebugMessage(DEBUG_STREAM_STATE, "queuing segment\n"); - listener->reassembler->queue_packet_for_reassembly(tsd); + listener->reassembler.queue_packet_for_reassembly(tsd); // Alert if overlap limit exceeded if ( ( config->overlap_limit ) - && ( listener->reassembler->get_overlap_count() > config->overlap_limit ) ) + && ( listener->reassembler.get_overlap_count() > config->overlap_limit ) ) { tel.set_tcp_event(EVENT_EXCESSIVE_OVERLAP); - listener->reassembler->set_overlap_count(0); + listener->reassembler.set_overlap_count(0); } } @@ -371,26 +364,25 @@ int TcpSession::process_tcp_data(TcpSegmentDescriptor& tsd) if ( tcph->is_syn() ) { - if (listener->normalizer->get_os_policy() == StreamPolicy::OS_MACOS) + if (listener->normalizer.get_os_policy() == StreamPolicy::OS_MACOS) seq++; else { DebugMessage(DEBUG_STREAM_STATE, "Bailing, data on SYN, not MAC Policy!\n"); - listener->normalizer->trim_syn_payload(tsd); + listener->normalizer.trim_syn_payload(tsd); return STREAM_UNALIGNED; - } - } + } } /* we're aligned, so that's nice anyway */ if (seq == listener->r_nxt_ack) { /* check if we're in the window */ if (config->policy != StreamPolicy::OS_PROXY - and listener->normalizer->get_stream_window(tsd) == 0) + 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(tsd); + listener->normalizer.trim_win_payload(tsd); return STREAM_UNALIGNED; } @@ -422,10 +414,10 @@ int TcpSession::process_tcp_data(TcpSegmentDescriptor& tsd) /* check if we're in the window */ if (config->policy != StreamPolicy::OS_PROXY - and listener->normalizer->get_stream_window(tsd) == 0) + 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(tsd); + listener->normalizer.trim_win_payload(tsd); return STREAM_UNALIGNED; } @@ -458,20 +450,15 @@ void TcpSession::set_os_policy() { StreamPolicy client_os_policy = flow->ssn_policy ? static_cast( flow->ssn_policy ) : config->policy; + StreamPolicy server_os_policy = flow->ssn_policy ? static_cast( flow->ssn_policy ) : config->policy; - if ( client->normalizer == nullptr ) - client->normalizer = TcpNormalizerFactory::create(this, client_os_policy, client, server); - - if ( server->normalizer == nullptr ) - server->normalizer = TcpNormalizerFactory::create(this, server_os_policy, server, client); + client.normalizer.init(client_os_policy, this, &client, &server); + server.normalizer.init(server_os_policy, this, &server, &client); - 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); + client.reassembler.init(this, &client, client_os_policy, false); + server.reassembler.init(this, &server, server_os_policy, true); } // FIXIT-H this is no longer called (but should be) @@ -480,7 +467,7 @@ void TcpSession::swap_trackers() uint32_t session_flags = flow->get_session_flags( ); if ( ( session_flags & SSNFLAG_CLIENT_SWAP ) && !( session_flags & SSNFLAG_CLIENT_SWAPPED ) ) { - TcpStreamTracker* trk = client; + TcpStreamTracker& trk = client; client = server; server = trk; @@ -513,24 +500,24 @@ void TcpSession::swap_trackers() void TcpSession::NewTcpSessionOnSyn(TcpSegmentDescriptor& tsd) { - server->init_on_syn_recv(tsd); - client->init_on_syn_sent(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); + server.init_on_synack_sent(tsd); + client.init_on_synack_recv(tsd); init_new_tcp_session(tsd); tcpStats.sessions_on_syn_ack++; } void TcpSession::update_timestamp_tracking(TcpSegmentDescriptor& tsd) { - talker->set_tf_flags(listener->normalizer->get_timestamp_flags()); - if (listener->normalizer->handling_timestamps() + talker->set_tf_flags(listener->normalizer.get_timestamp_flags()); + if (listener->normalizer.handling_timestamps() && SEQ_EQ(listener->r_nxt_ack, tsd.get_seg_seq())) { talker->set_ts_last_packet(tsd.get_pkt()->pkth->ts.tv_sec); @@ -561,8 +548,8 @@ bool TcpSession::handle_syn_on_reset_session(TcpSegmentDescriptor& tsd) // one function can ever perform a normalization. /* Got SYN/RST. We're done. */ - listener->normalizer->trim_syn_payload(tsd); - listener->normalizer->trim_rst_payload(tsd); + listener->normalizer.trim_syn_payload(tsd); + listener->normalizer.trim_rst_payload(tsd); pkt_action_mask |= ACTION_RST; return false; } @@ -573,9 +560,9 @@ bool TcpSession::handle_syn_on_reset_session(TcpSegmentDescriptor& tsd) flow->set_ttl(tsd.get_pkt(), true); NewTcpSessionOnSyn(tsd); tcpStats.resyns++; - listener = server; - talker = client; - listener->normalizer->ecn_tracker( tcph, config->require_3whs() ); + listener = &server; + talker = &client; + listener->normalizer.ecn_tracker(tcph, config->require_3whs()); flow->update_session_flags(SSNFLAG_SEEN_CLIENT); } else if (tcph->is_syn_ack()) @@ -589,9 +576,9 @@ bool TcpSession::handle_syn_on_reset_session(TcpSegmentDescriptor& tsd) tcpStats.resyns++; } - listener = client; - talker = server; - listener->normalizer->ecn_tracker( tcph, config->require_3whs() ); + listener = &client; + talker = &server; + listener->normalizer.ecn_tracker(tcph, config->require_3whs()); flow->update_session_flags(SSNFLAG_SEEN_SERVER); } } @@ -625,13 +612,13 @@ void TcpSession::update_ignored_session(TcpSegmentDescriptor& tsd) void TcpSession::handle_data_on_syn(TcpSegmentDescriptor& tsd) { /* MacOS accepts data on SYN, so don't alert if policy is MACOS */ - if (talker->normalizer->get_os_policy() == StreamPolicy::OS_MACOS) + if (talker->normalizer.get_os_policy() == StreamPolicy::OS_MACOS) { handle_data_segment(tsd); } else { - listener->normalizer->trim_syn_payload(tsd); + listener->normalizer.trim_syn_payload(tsd); DebugMessage(DEBUG_STREAM_STATE, "Got data on SYN packet, not processing it\n"); tel.set_tcp_event(EVENT_DATA_ON_SYN); pkt_action_mask |= ACTION_BAD_PKT; @@ -660,7 +647,7 @@ void TcpSession::update_paws_timestamps(TcpSegmentDescriptor& tsd) DebugFormat(DEBUG_STREAM_STATE, "PAWS update tsd.seq %u > listener->r_win_base %u\n", tsd.get_seg_seq(), listener->r_win_base); - if ( listener->normalizer->handling_timestamps() + if ( listener->normalizer.handling_timestamps() && SEQ_EQ(listener->r_win_base, tsd.get_seg_seq() ) ) { if ( ( (int32_t)(tsd.get_ts() - talker->get_ts_last() ) >= 0 ) @@ -730,7 +717,7 @@ bool TcpSession::check_for_window_slam(TcpSegmentDescriptor& tsd) /* got a window too large, alert! */ tel.set_tcp_event(EVENT_WINDOW_TOO_LARGE); inc_tcp_discards(); - listener->normalizer->packet_dropper(tsd, NORM_TCP_BLOCK); + listener->normalizer.packet_dropper(tsd, NORM_TCP_BLOCK); pkt_action_mask |= ACTION_BAD_PKT; return true; } @@ -745,7 +732,7 @@ bool TcpSession::check_for_window_slam(TcpSegmentDescriptor& tsd) tel.set_tcp_event(EVENT_WINDOW_SLAM); inc_tcp_discards(); - if (listener->normalizer->packet_dropper(tsd, NORM_TCP_BLOCK)) + if (listener->normalizer.packet_dropper(tsd, NORM_TCP_BLOCK)) { pkt_action_mask |= ACTION_BAD_PKT; return true; @@ -757,7 +744,7 @@ bool TcpSession::check_for_window_slam(TcpSegmentDescriptor& tsd) void TcpSession::mark_packet_for_drop(TcpSegmentDescriptor& tsd) { - listener->normalizer->packet_dropper(tsd, NORM_TCP_BLOCK); + listener->normalizer.packet_dropper(tsd, NORM_TCP_BLOCK); set_pkt_action_flag(ACTION_BAD_PKT); } @@ -774,9 +761,9 @@ void TcpSession::handle_data_segment(TcpSegmentDescriptor& tsd) { uint8_t tcp_options_len = tsd.get_tcph()->options_len(); if (tsd.is_packet_from_server()) - server->set_tcp_options_len(tcp_options_len); + server.set_tcp_options_len(tcp_options_len); else - client->set_tcp_options_len(tcp_options_len); + client.set_tcp_options_len(tcp_options_len); // FIXIT-M move this to normalizer base class, handle OS_PROXY in derived class if (config->policy != StreamPolicy::OS_PROXY) @@ -794,13 +781,13 @@ void TcpSession::handle_data_segment(TcpSegmentDescriptor& tsd) TcpStreamTracker* st = listener; // trim to fit in window and mss as needed - st->normalizer->trim_win_payload(tsd, (st->r_win_base + st->get_snd_wnd() - - st->r_nxt_ack)); + st->normalizer.trim_win_payload( + tsd, (st->r_win_base + st->get_snd_wnd() - st->r_nxt_ack)); if (st->get_mss()) - st->normalizer->trim_mss_payload(tsd, st->get_mss()); + st->normalizer.trim_mss_payload(tsd, st->get_mss()); - st->normalizer->ecn_stripper(tsd.get_pkt()); + st->normalizer.ecn_stripper(tsd.get_pkt()); } } @@ -816,11 +803,11 @@ void TcpSession::handle_data_segment(TcpSegmentDescriptor& tsd) else { tel.set_tcp_event(EVENT_DATA_WITHOUT_FLAGS); - listener->normalizer->packet_dropper(tsd, NORM_TCP_BLOCK); + listener->normalizer.packet_dropper(tsd, NORM_TCP_BLOCK); } } - listener->reassembler->flush_on_data_policy(tsd.get_pkt()); + listener->reassembler.flush_on_data_policy(tsd.get_pkt()); } TcpStreamTracker::TcpState TcpSession::get_talker_state() @@ -838,14 +825,14 @@ void TcpSession::check_for_repeated_syn(TcpSegmentDescriptor& tsd) uint32_t action = ACTION_NOTHING; if ( !SEQ_EQ(tsd.get_seg_seq(), talker->get_iss()) and - listener->normalizer->packet_dropper(tsd, NORM_TCP_BLOCK) ) + listener->normalizer.packet_dropper(tsd, NORM_TCP_BLOCK) ) { action = ACTION_BAD_PKT; } else if ( talker->get_tcp_state() >= TcpStreamTracker::TCP_ESTABLISHED and talker->get_tcp_state() < TcpStreamTracker::TCP_CLOSED ) { - action = listener->normalizer->handle_repeated_syn(tsd); + action = listener->normalizer.handle_repeated_syn(tsd); } if (action != ACTION_NOTHING) { @@ -860,7 +847,7 @@ void TcpSession::flush_server(Packet* p) if ( !tcp_init ) return; - server->set_tf_flags(TF_FORCE_FLUSH); + server.set_tf_flags(TF_FORCE_FLUSH); // If rebuilt packet, don't flush now because we'll overwrite the packet being processed. if ( p->packet_flags & PKT_REBUILT_STREAM ) @@ -870,10 +857,10 @@ void TcpSession::flush_server(Packet* p) } // Need to convert the addresses to network order - if ( server->reassembler->flush_stream(p, PKT_FROM_SERVER) ) - server->reassembler->purge_flushed_ackd( ); + if ( server.reassembler.flush_stream(p, PKT_FROM_SERVER) ) + server.reassembler.purge_flushed_ackd(); - server->clear_tf_flags(TF_FORCE_FLUSH); + server.clear_tf_flags(TF_FORCE_FLUSH); } void TcpSession::flush_client(Packet* p) @@ -881,7 +868,7 @@ void TcpSession::flush_client(Packet* p) if ( !tcp_init ) return; - client->set_tf_flags(TF_FORCE_FLUSH); + client.set_tf_flags(TF_FORCE_FLUSH); // If rebuilt packet, don't flush now because we'll overwrite the packet being processed. if ( p->packet_flags & PKT_REBUILT_STREAM ) @@ -890,25 +877,25 @@ void TcpSession::flush_client(Packet* p) return; } - if ( client->reassembler->flush_stream(p, PKT_FROM_CLIENT) ) - client->reassembler->purge_flushed_ackd( ); + if ( client.reassembler.flush_stream(p, PKT_FROM_CLIENT) ) + client.reassembler.purge_flushed_ackd(); - client->clear_tf_flags(TF_FORCE_FLUSH); + client.clear_tf_flags(TF_FORCE_FLUSH); } void TcpSession::flush_tracker( - TcpStreamTracker* tracker, Packet* p, uint32_t dir, bool final_flush) + TcpStreamTracker& tracker, Packet* p, uint32_t dir, bool final_flush) { - if ( final_flush && ( !tracker->splitter || !tracker->splitter->finish(flow) ) ) + if ( final_flush && ( !tracker.splitter || !tracker.splitter->finish(flow) ) ) return; DebugFormat(DEBUG_STREAM_STATE, "Flushing tracker on packet from %s\n", (dir == PKT_FROM_CLIENT) ? "client" : "server"); - tracker->set_tf_flags(TF_FORCE_FLUSH); - if ( tracker->reassembler->flush_stream(p, dir) ) - tracker->reassembler->purge_flushed_ackd( ); + tracker.set_tf_flags(TF_FORCE_FLUSH); + if ( tracker.reassembler.flush_stream(p, dir) ) + tracker.reassembler.purge_flushed_ackd(); - tracker->clear_tf_flags(TF_FORCE_FLUSH); + tracker.clear_tf_flags(TF_FORCE_FLUSH); } void TcpSession::flush_listener(Packet* p, bool final_flush) @@ -931,14 +918,8 @@ void TcpSession::flush_talker(Packet* p, bool final_flush) void TcpSession::set_extra_data(Packet* p, uint32_t xid) { - TcpStreamTracker* st; - - if (p->ptrs.ip_api.get_src()->equals(flow->client_ip)) - st = server; - else - st = client; - - st->reassembler->set_xtradata_mask(st->reassembler->get_xtradata_mask() | BIT(xid) ); + TcpStreamTracker& st = p->ptrs.ip_api.get_src()->equals(flow->client_ip) ? server : client; + st.reassembler.set_xtradata_mask(st.reassembler.get_xtradata_mask() | BIT(xid)); } static inline void set_window_scale(TcpStreamTracker& talker, TcpStreamTracker& listener, @@ -996,8 +977,8 @@ bool TcpSession::is_flow_handling_packets(Packet* p) // harmonize this with that and the checks above if ( Stream::expected_flow(flow, p) ) { - server->flush_policy = STREAM_FLPOLICY_IGNORE; - client->flush_policy = STREAM_FLPOLICY_IGNORE; + server.flush_policy = STREAM_FLPOLICY_IGNORE; + client.flush_policy = STREAM_FLPOLICY_IGNORE; flow_ready = false; } @@ -1035,11 +1016,11 @@ bool TcpSession::do_packet_analysis_pre_checks(Packet* p, TcpSegmentDescriptor& if ( !splitter_init and tsd.get_seg_len() > 0 ) { - client->set_splitter(tsd.get_flow()); - server->set_splitter(tsd.get_flow()); + client.set_splitter(tsd.get_flow()); + server.set_splitter(tsd.get_flow()); - client->init_flush_policy(); - server->init_flush_policy(); + client.init_flush_policy(); + server.init_flush_policy(); splitter_init = true; } @@ -1072,7 +1053,7 @@ bool TcpSession::do_packet_analysis_pre_checks(Packet* p, TcpSegmentDescriptor& bool TcpSession::validate_packet_established_session(TcpSegmentDescriptor& tsd) { - pkt_action_mask |= listener->normalizer->handle_paws(tsd); + pkt_action_mask |= listener->normalizer.handle_paws(tsd); if ( pkt_action_mask & ACTION_BAD_PKT ) return false; @@ -1153,14 +1134,14 @@ int TcpSession::process(Packet* p) void TcpSession::flush() { - 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() ) ) { // FIXIT-L flush_queued_segments is basically a noop when the 'clear' parameter // is passed in as false... review what happens in 2.9.x probably related // to ssl encryption support - 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); } } diff --git a/src/stream/tcp/tcp_session.h b/src/stream/tcp/tcp_session.h index 874a3e23d..bf43f5b0a 100644 --- a/src/stream/tcp/tcp_session.h +++ b/src/stream/tcp/tcp_session.h @@ -20,12 +20,18 @@ #ifndef TCP_SESSION_H #define TCP_SESSION_H -#include "stream/libtcp/tcp_stream_session.h" #include "stream/libtcp/tcp_state_machine.h" -#include "stream/tcp/tcp_tracker.h" +#include "stream/libtcp/tcp_stream_session.h" +#include "stream/libtcp/tcp_stream_tracker.h" +namespace snort +{ +class Flow; +struct Packet; +} class TcpEventLogger; + class TcpSession : public TcpStreamSession { public: @@ -42,11 +48,8 @@ public: void flush_server(snort::Packet*) override; void flush_talker(snort::Packet*, bool final_flush = false) override; void flush_listener(snort::Packet*, bool final_flush = false) override; - void clear_session(bool free_flow_data, bool flush_segments, bool restart, snort::Packet* p = nullptr) override; - void set_extra_data(snort::Packet*, uint32_t /*flag*/) override; - void update_perf_base_state(char new_state) override; TcpStreamTracker::TcpState get_talker_state() override; TcpStreamTracker::TcpState get_listener_state() override; @@ -61,7 +64,6 @@ public: bool check_for_window_slam(TcpSegmentDescriptor& tsd) override; void mark_packet_for_drop(TcpSegmentDescriptor&) override; void handle_data_segment(TcpSegmentDescriptor&) override; - bool validate_packet_established_session(TcpSegmentDescriptor&) override; private: @@ -79,8 +81,9 @@ private: void cleanup_session_if_expired(snort::Packet*); bool do_packet_analysis_pre_checks(snort::Packet*, TcpSegmentDescriptor&); void do_packet_analysis_post_checks(snort::Packet*); - void flush_tracker(TcpStreamTracker*, snort::Packet*, uint32_t dir, bool final_flush); + void flush_tracker(TcpStreamTracker&, snort::Packet*, uint32_t dir, bool final_flush); +private: TcpStateMachine* tsm; bool splitter_init; }; diff --git a/src/stream/tcp/tcp_state_close_wait.cc b/src/stream/tcp/tcp_state_close_wait.cc index 9a871c8ad..79b31a5f2 100644 --- a/src/stream/tcp/tcp_state_close_wait.cc +++ b/src/stream/tcp/tcp_state_close_wait.cc @@ -27,7 +27,7 @@ #include "main/snort_debug.h" -#include "tcp_normalizer.h" +#include "tcp_normalizers.h" #include "tcp_session.h" #ifdef UNIT_TEST @@ -43,7 +43,7 @@ TcpStateCloseWait::TcpStateCloseWait(TcpStateMachine& tsm) : bool TcpStateCloseWait::syn_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) { - trk.normalizer->ecn_tracker(tsd.get_tcph(), trk.session->config->require_3whs() ); + trk.normalizer.ecn_tracker(tsd.get_tcph(), trk.session->config->require_3whs() ); if ( tsd.get_seg_len() ) trk.session->handle_data_on_syn(tsd); @@ -98,7 +98,7 @@ bool TcpStateCloseWait::fin_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tr { DebugMessage(DEBUG_STREAM_STATE, "FIN beyond previous, ignoring\n"); trk.session->tel.set_tcp_event(EVENT_BAD_FIN); - trk.normalizer->packet_dropper(tsd, NORM_TCP_BLOCK); + trk.normalizer.packet_dropper(tsd, NORM_TCP_BLOCK); trk.session->set_pkt_action_flag(ACTION_BAD_PKT); } else diff --git a/src/stream/tcp/tcp_state_closed.cc b/src/stream/tcp/tcp_state_closed.cc index d4e670a90..8cf517a19 100644 --- a/src/stream/tcp/tcp_state_closed.cc +++ b/src/stream/tcp/tcp_state_closed.cc @@ -164,8 +164,8 @@ TEST_CASE("TCP State Closed", "[tcp_closed_state][stream_tcp]") 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->normalizer = TcpNormalizerFactory::create(StreamPolicy::OS_LINUX, session, ctrk, strk); + strk->normalizer = TcpNormalizerFactory::create(StreamPolicy::OS_LINUX, session, strk, ctrk); ctrk->reassembler = TcpReassemblerFactory::create(session, ctrk, StreamPolicy::OS_LINUX, false); strk->reassembler = TcpReassemblerFactory::create(session, strk, StreamPolicy::OS_LINUX, true); diff --git a/src/stream/tcp/tcp_state_closing.cc b/src/stream/tcp/tcp_state_closing.cc index 6229c922b..46506aefe 100644 --- a/src/stream/tcp/tcp_state_closing.cc +++ b/src/stream/tcp/tcp_state_closing.cc @@ -27,7 +27,7 @@ #include "main/snort_debug.h" -#include "tcp_normalizer.h" +#include "tcp_normalizers.h" #include "tcp_session.h" #ifdef UNIT_TEST @@ -49,7 +49,7 @@ bool TcpStateClosing::syn_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) bool TcpStateClosing::syn_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) { - trk.normalizer->ecn_tracker(tsd.get_tcph(), trk.session->config->require_3whs() ); + trk.normalizer.ecn_tracker(tsd.get_tcph(), trk.session->config->require_3whs()); if ( tsd.get_seg_len() ) trk.session->handle_data_on_syn(tsd); return true; @@ -98,7 +98,7 @@ bool TcpStateClosing::fin_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) { DebugMessage(DEBUG_STREAM_STATE, "FIN beyond previous, ignoring\n"); trk.session->tel.set_tcp_event(EVENT_BAD_FIN); - trk.normalizer->packet_dropper(tsd, NORM_TCP_BLOCK); + trk.normalizer.packet_dropper(tsd, NORM_TCP_BLOCK); trk.session->set_pkt_action_flag(ACTION_BAD_PKT); } diff --git a/src/stream/tcp/tcp_state_established.cc b/src/stream/tcp/tcp_state_established.cc index 2898155b6..27185ccd7 100644 --- a/src/stream/tcp/tcp_state_established.cc +++ b/src/stream/tcp/tcp_state_established.cc @@ -25,7 +25,7 @@ #include "tcp_state_established.h" -#include "tcp_normalizer.h" +#include "tcp_normalizers.h" #include "tcp_session.h" TcpStateEstablished::TcpStateEstablished(TcpStateMachine& tsm) : @@ -42,7 +42,7 @@ bool TcpStateEstablished::syn_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& bool TcpStateEstablished::syn_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) { trk.session->check_for_repeated_syn(tsd); - trk.normalizer->ecn_tracker(tsd.get_tcph(), trk.session->config->require_3whs() ); + trk.normalizer.ecn_tracker(tsd.get_tcph(), trk.session->config->require_3whs()); return true; } @@ -59,7 +59,7 @@ bool TcpStateEstablished::syn_ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTrack } if ( trk.is_server_tracker() ) - trk.normalizer->ecn_tracker(tsd.get_tcph(), trk.session->config->require_3whs() ); + trk.normalizer.ecn_tracker(tsd.get_tcph(), trk.session->config->require_3whs() ); return true; } @@ -91,16 +91,13 @@ bool TcpStateEstablished::data_seg_recv(TcpSegmentDescriptor& tsd, TcpStreamTrac bool TcpStateEstablished::fin_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) { - TcpStreamTracker* listener = nullptr; + TcpStreamTracker& listener = + tsd.get_pkt()->is_from_client() ? trk.session->server : trk.session->client; - if ( tsd.get_pkt()->is_from_client() ) - listener = trk.session->server; - else - listener = trk.session->client; trk.update_on_fin_sent(tsd); - if ( SEQ_EQ(tsd.get_end_seq(), (listener->r_nxt_ack + tsd.get_seg_len())) || - listener->process_inorder_fin() || !listener->is_segment_seq_valid(tsd) ) + if ( SEQ_EQ(tsd.get_end_seq(), (listener.r_nxt_ack + tsd.get_seg_len())) || + listener.process_inorder_fin() || !listener.is_segment_seq_valid(tsd) ) { trk.session->eof_handle(tsd.get_pkt()); trk.set_tcp_state(TcpStreamTracker::TCP_FIN_WAIT1); diff --git a/src/stream/tcp/tcp_state_fin_wait1.cc b/src/stream/tcp/tcp_state_fin_wait1.cc index 1ef5b52a9..bae4b73f6 100644 --- a/src/stream/tcp/tcp_state_fin_wait1.cc +++ b/src/stream/tcp/tcp_state_fin_wait1.cc @@ -27,7 +27,7 @@ #include "main/snort_debug.h" -#include "tcp_normalizer.h" +#include "tcp_normalizers.h" #include "tcp_module.h" #include "tcp_session.h" @@ -46,7 +46,7 @@ bool TcpStateFinWait1::syn_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk bool TcpStateFinWait1::syn_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) { - trk.normalizer->ecn_tracker(tsd.get_tcph(), trk.session->config->require_3whs() ); + trk.normalizer.ecn_tracker(tsd.get_tcph(), trk.session->config->require_3whs()); if ( tsd.get_seg_len() ) trk.session->handle_data_on_syn(tsd); return true; @@ -147,13 +147,13 @@ bool TcpStateFinWait1::check_for_window_slam(TcpSegmentDescriptor& tsd, TcpStrea if ( SEQ_EQ(tsd.get_seg_ack(), trk.get_snd_nxt() ) ) { - if ( (trk.normalizer->get_os_policy() == StreamPolicy::OS_WINDOWS) + if ( (trk.normalizer.get_os_policy() == StreamPolicy::OS_WINDOWS) && (tsd.get_seg_wnd() == 0)) { trk.session->tel.set_tcp_event(EVENT_WINDOW_SLAM); inc_tcp_discards(); - if (trk.normalizer->packet_dropper(tsd, NORM_TCP_BLOCK)) + if (trk.normalizer.packet_dropper(tsd, NORM_TCP_BLOCK)) { trk.session->set_pkt_action_flag(ACTION_BAD_PKT); return false; diff --git a/src/stream/tcp/tcp_state_fin_wait2.cc b/src/stream/tcp/tcp_state_fin_wait2.cc index 9672a2259..5706426fc 100644 --- a/src/stream/tcp/tcp_state_fin_wait2.cc +++ b/src/stream/tcp/tcp_state_fin_wait2.cc @@ -25,7 +25,7 @@ #include "tcp_state_fin_wait2.h" -#include "tcp_normalizer.h" +#include "tcp_normalizers.h" #include "tcp_session.h" using namespace std; @@ -43,7 +43,7 @@ bool TcpStateFinWait2::syn_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk bool TcpStateFinWait2::syn_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) { - trk.normalizer->ecn_tracker(tsd.get_tcph(), trk.session->config->require_3whs() ); + trk.normalizer.ecn_tracker(tsd.get_tcph(), trk.session->config->require_3whs()); if ( tsd.get_seg_len() ) trk.session->handle_data_on_syn(tsd); return true; @@ -66,7 +66,7 @@ bool TcpStateFinWait2::ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk { if ( SEQ_GT(tsd.get_seg_ack(), trk.get_snd_nxt() ) ) { - trk.normalizer->packet_dropper(tsd, NORM_TCP_BLOCK); + trk.normalizer.packet_dropper(tsd, NORM_TCP_BLOCK); trk.session->tel.set_tcp_event(EVENT_BAD_ACK); trk.session->set_pkt_action_flag(ACTION_BAD_PKT); } @@ -88,7 +88,7 @@ bool TcpStateFinWait2::data_seg_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker { if ( SEQ_GT(tsd.get_seg_ack(), trk.get_snd_nxt() ) ) { - trk.normalizer->packet_dropper(tsd, NORM_TCP_BLOCK); + trk.normalizer.packet_dropper(tsd, NORM_TCP_BLOCK); trk.session->tel.set_tcp_event(EVENT_BAD_ACK); trk.session->set_pkt_action_flag(ACTION_BAD_PKT); } diff --git a/src/stream/tcp/tcp_state_last_ack.cc b/src/stream/tcp/tcp_state_last_ack.cc index 924c35299..97547ff3b 100644 --- a/src/stream/tcp/tcp_state_last_ack.cc +++ b/src/stream/tcp/tcp_state_last_ack.cc @@ -25,7 +25,7 @@ #include "tcp_state_last_ack.h" -#include "tcp_normalizer.h" +#include "tcp_normalizers.h" #include "tcp_session.h" using namespace std; @@ -43,7 +43,7 @@ bool TcpStateLastAck::syn_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) bool TcpStateLastAck::syn_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) { - trk.normalizer->ecn_tracker(tsd.get_tcph(), trk.session->config->require_3whs() ); + trk.normalizer.ecn_tracker(tsd.get_tcph(), trk.session->config->require_3whs()); if ( tsd.get_seg_len() ) trk.session->handle_data_on_syn(tsd); return true; diff --git a/src/stream/tcp/tcp_state_listen.cc b/src/stream/tcp/tcp_state_listen.cc index c5bf0229f..d6c58aa76 100644 --- a/src/stream/tcp/tcp_state_listen.cc +++ b/src/stream/tcp/tcp_state_listen.cc @@ -25,7 +25,7 @@ #include "tcp_state_listen.h" -#include "tcp_normalizer.h" +#include "tcp_normalizers.h" #include "tcp_session.h" using namespace snort; @@ -49,8 +49,8 @@ bool TcpStateListen::syn_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) bool TcpStateListen::syn_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) { trk.init_on_syn_recv(tsd); - trk.normalizer->ecn_tracker(tsd.get_tcph(), trk.session->config->require_3whs() ); - trk.session->set_pkt_action_flag(trk.normalizer->handle_paws(tsd) ); + trk.normalizer.ecn_tracker(tsd.get_tcph(), trk.session->config->require_3whs()); + trk.session->set_pkt_action_flag(trk.normalizer.handle_paws(tsd) ); if ( tsd.get_seg_len() > 0 ) trk.session->handle_data_on_syn(tsd); return true; @@ -64,7 +64,7 @@ bool TcpStateListen::syn_ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& t if ( trk.session->config->midstream_allowed(tsd.get_pkt() ) ) { trk.init_on_synack_sent(tsd); - trk.normalizer->ecn_tracker(tsd.get_tcph(), trk.session->config->require_3whs() ); + trk.normalizer.ecn_tracker(tsd.get_tcph(), trk.session->config->require_3whs()); trk.session->init_new_tcp_session(tsd); } else if ( trk.session->config->require_3whs() ) @@ -125,7 +125,8 @@ bool TcpStateListen::ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) 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.session->config->require_3whs() ); + trk.normalizer.ecn_tracker( + tsd.get_tcph(), trk.session->config->require_3whs()); } } else if ( trk.session->config->require_3whs() ) @@ -168,7 +169,7 @@ bool TcpStateListen::data_seg_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& flow->session_state |= STREAM_STATE_MIDSTREAM; flow->set_session_flags(SSNFLAG_MIDSTREAM); trk.init_on_data_seg_recv(tsd); - trk.normalizer->ecn_tracker(tsd.get_tcph(), trk.session->config->require_3whs() ); + trk.normalizer.ecn_tracker(tsd.get_tcph(), trk.session->config->require_3whs()); trk.session->handle_data_segment(tsd); } else if ( trk.session->config->require_3whs() ) @@ -207,7 +208,7 @@ bool TcpStateListen::fin_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) bool TcpStateListen::rst_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) { - trk.normalizer->trim_rst_payload(tsd); + trk.normalizer.trim_rst_payload(tsd); return true; } diff --git a/src/stream/tcp/tcp_state_none.cc b/src/stream/tcp/tcp_state_none.cc index a17884b5e..382933a20 100644 --- a/src/stream/tcp/tcp_state_none.cc +++ b/src/stream/tcp/tcp_state_none.cc @@ -25,7 +25,7 @@ #include "tcp_state_none.h" -#include "tcp_normalizer.h" +#include "tcp_normalizers.h" #include "tcp_session.h" using namespace snort; @@ -62,7 +62,7 @@ bool TcpStateNone::syn_ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk flow->session_state |= ( STREAM_STATE_SYN | STREAM_STATE_SYN_ACK ); trk.init_on_synack_sent(tsd); trk.session->init_new_tcp_session(tsd); - trk.normalizer->ecn_tracker(tsd.get_tcph(), trk.session->config->require_3whs() ); + trk.normalizer.ecn_tracker(tsd.get_tcph(), trk.session->config->require_3whs()); } else if ( trk.session->config->require_3whs() ) { @@ -77,7 +77,7 @@ bool TcpStateNone::syn_ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk if ( trk.session->config->midstream_allowed(tsd.get_pkt() ) ) { trk.init_on_synack_recv(tsd); - trk.normalizer->ecn_tracker(tsd.get_tcph(), trk.session->config->require_3whs() ); + trk.normalizer.ecn_tracker(tsd.get_tcph(), trk.session->config->require_3whs()); if ( tsd.get_seg_len() > 0 ) trk.session->handle_data_segment(tsd); } @@ -122,7 +122,8 @@ bool TcpStateNone::ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) 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.session->config->require_3whs() ); + trk.normalizer.ecn_tracker( + tsd.get_tcph(), trk.session->config->require_3whs()); } } else if ( trk.session->config->require_3whs() ) @@ -166,7 +167,7 @@ bool TcpStateNone::data_seg_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tr flow->set_session_flags(SSNFLAG_MIDSTREAM); trk.init_on_data_seg_recv(tsd); - trk.normalizer->ecn_tracker(tsd.get_tcph(), trk.session->config->require_3whs() ); + trk.normalizer.ecn_tracker(tsd.get_tcph(), trk.session->config->require_3whs()); trk.session->handle_data_segment(tsd); } else if ( trk.session->config->require_3whs() ) @@ -243,8 +244,9 @@ TEST_CASE("TCP State None", "[tcp_none_state][stream_tcp]") 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->normalizer = TcpNormalizerFactory::create(StreamPolicy::OS_LINUX, session, ctrk, strk); + strk->normalizer = TcpNormalizerFactory::create(StreamPolicy::OS_LINUX, session, strk, ctrk); ctrk->reassembler = TcpReassemblerFactory::create(session, ctrk, StreamPolicy::OS_LINUX, false); strk->reassembler = TcpReassemblerFactory::create(session, strk, StreamPolicy::OS_LINUX, true); diff --git a/src/stream/tcp/tcp_state_syn_recv.cc b/src/stream/tcp/tcp_state_syn_recv.cc index 30a9ed355..289d3cdac 100644 --- a/src/stream/tcp/tcp_state_syn_recv.cc +++ b/src/stream/tcp/tcp_state_syn_recv.cc @@ -26,7 +26,7 @@ #include "tcp_state_syn_recv.h" #include "tcp_module.h" -#include "tcp_normalizer.h" +#include "tcp_normalizers.h" #include "tcp_session.h" using namespace snort; @@ -42,7 +42,7 @@ bool TcpStateSynRecv::syn_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) Flow* flow = tsd.get_flow(); trk.finish_server_init(tsd); - trk.normalizer->ecn_tracker(tsd.get_tcph(), trk.session->config->require_3whs() ); + trk.normalizer.ecn_tracker(tsd.get_tcph(), trk.session->config->require_3whs()); trk.session->update_timestamp_tracking(tsd); if ( tsd.get_tcph()->are_flags_set(TH_ECE) && ( flow->get_session_flags() & SSNFLAG_ECN_CLIENT_QUERY ) ) @@ -69,7 +69,7 @@ bool TcpStateSynRecv::syn_ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& // FIXIT-H verify ack being sent is valid... trk.finish_server_init(tsd); - trk.normalizer->ecn_tracker(tsd.get_tcph(), trk.session->config->require_3whs() ); + trk.normalizer.ecn_tracker(tsd.get_tcph(), trk.session->config->require_3whs()); flow->session_state |= STREAM_STATE_SYN_ACK; return true; } @@ -81,7 +81,7 @@ bool TcpStateSynRecv::syn_ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& Flow* flow = tsd.get_flow(); trk.update_tracker_ack_recv(tsd); - trk.normalizer->ecn_tracker(tsd.get_tcph(), trk.session->config->require_3whs() ); + trk.normalizer.ecn_tracker(tsd.get_tcph(), trk.session->config->require_3whs()); flow->set_session_flags(SSNFLAG_ESTABLISHED); flow->session_state |= ( STREAM_STATE_ACK | STREAM_STATE_ESTABLISHED ); trk.session->update_perf_base_state(TcpStreamTracker::TCP_ESTABLISHED); @@ -108,7 +108,7 @@ bool TcpStateSynRecv::ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) Flow* flow = tsd.get_flow(); trk.update_tracker_ack_recv(tsd); - trk.session->set_pkt_action_flag(trk.normalizer->handle_paws(tsd) ); + trk.session->set_pkt_action_flag(trk.normalizer.handle_paws(tsd)); tsd.get_pkt()->packet_flags |= PKT_STREAM_TWH; flow->set_session_flags(SSNFLAG_ESTABLISHED); flow->session_state |= ( STREAM_STATE_ACK | STREAM_STATE_ESTABLISHED ); @@ -128,7 +128,7 @@ bool TcpStateSynRecv::data_seg_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& { trk.update_tracker_ack_recv(tsd); tsd.get_pkt()->packet_flags |= PKT_STREAM_TWH; - trk.session->set_pkt_action_flag(trk.normalizer->handle_paws(tsd) ); + trk.session->set_pkt_action_flag(trk.normalizer.handle_paws(tsd)); trk.session->update_perf_base_state(TcpStreamTracker::TCP_ESTABLISHED); trk.set_tcp_state(TcpStreamTracker::TCP_ESTABLISHED); } @@ -144,7 +144,7 @@ bool TcpStateSynRecv::fin_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) Flow* flow = tsd.get_flow(); trk.update_tracker_ack_recv(tsd); - trk.session->set_pkt_action_flag(trk.normalizer->handle_paws(tsd) ); + trk.session->set_pkt_action_flag(trk.normalizer.handle_paws(tsd)); flow->session_state |= STREAM_STATE_ACK; if ( tsd.get_seg_len() > 0 ) { @@ -163,20 +163,20 @@ bool TcpStateSynRecv::fin_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) bool TcpStateSynRecv::rst_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) { - trk.normalizer->trim_rst_payload(tsd); - if ( trk.normalizer->validate_rst(tsd) ) + trk.normalizer.trim_rst_payload(tsd); + if ( trk.normalizer.validate_rst(tsd) ) { Flow* flow = tsd.get_flow(); flow->set_session_flags(SSNFLAG_RESET); - if ( trk.normalizer->is_tcp_ips_enabled() ) + if ( trk.normalizer.is_tcp_ips_enabled() ) tcp_state = TcpStreamTracker::TCP_LISTEN; } else { DebugMessage(DEBUG_STREAM_STATE, "Received RST with bad sequence number\n"); inc_tcp_discards(); - trk.normalizer->packet_dropper(tsd, NORM_TCP_BLOCK); + trk.normalizer.packet_dropper(tsd, NORM_TCP_BLOCK); trk.session->tel.set_tcp_event(EVENT_BAD_RST); } diff --git a/src/stream/tcp/tcp_state_time_wait.cc b/src/stream/tcp/tcp_state_time_wait.cc index b7c66b502..1abf966b0 100644 --- a/src/stream/tcp/tcp_state_time_wait.cc +++ b/src/stream/tcp/tcp_state_time_wait.cc @@ -27,7 +27,7 @@ #include "main/snort_debug.h" -#include "tcp_normalizer.h" +#include "tcp_normalizers.h" #include "tcp_session.h" using namespace std; @@ -45,7 +45,7 @@ bool TcpStateTimeWait::syn_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk bool TcpStateTimeWait::syn_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) { - trk.normalizer->ecn_tracker(tsd.get_tcph(), trk.session->config->require_3whs() ); + trk.normalizer.ecn_tracker(tsd.get_tcph(), trk.session->config->require_3whs()); if ( tsd.get_seg_len() ) trk.session->handle_data_on_syn(tsd); @@ -73,7 +73,7 @@ bool TcpStateTimeWait::fin_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk { DebugMessage(DEBUG_STREAM_STATE, "FIN beyond previous, ignoring\n"); trk.session->tel.set_tcp_event(EVENT_BAD_FIN); - trk.normalizer->packet_dropper(tsd, NORM_TCP_BLOCK); + trk.normalizer.packet_dropper(tsd, NORM_TCP_BLOCK); trk.session->set_pkt_action_flag(ACTION_BAD_PKT); } else if ( tsd.get_seg_len() > 0 ) diff --git a/src/stream/tcp/tcp_stream_state_machine.h b/src/stream/tcp/tcp_stream_state_machine.h index 45752852f..8bd98b2ab 100644 --- a/src/stream/tcp/tcp_stream_state_machine.h +++ b/src/stream/tcp/tcp_stream_state_machine.h @@ -35,7 +35,6 @@ public: private: TcpStreamStateMachine(); - void initialize_tsm(); }; #endif diff --git a/src/stream/tcp/tcp_tracker.cc b/src/stream/tcp/tcp_tracker.cc deleted file mode 100644 index 4ba33c972..000000000 --- a/src/stream/tcp/tcp_tracker.cc +++ /dev/null @@ -1,606 +0,0 @@ -//-------------------------------------------------------------------------- -// Copyright (C) 2015-2018 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 - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "tcp_tracker.h" - -#include "log/messages.h" -#include "profiler/profiler_defs.h" - -#include "tcp_module.h" -#include "tcp_normalizer.h" -#include "tcp_reassembler.h" - -using namespace snort; - -TcpTracker::TcpTracker(bool client, TcpSession* ssn) : - TcpStreamTracker(client) -{ - session = ssn; -} - -TcpTracker::~TcpTracker() -{ - delete splitter; - delete normalizer; - delete reassembler; -} - -void TcpTracker::init_tcp_state( ) -{ - tcp_state = ( client_tracker ) ? - TcpStreamTracker::TCP_STATE_NONE : TcpStreamTracker::TCP_LISTEN; - 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; - tf_flags = 0; - alert_count = 0; - mac_addr_valid = false; - fin_final_seq = 0; - fin_seq_status = TcpStreamTracker::FIN_NOT_SEEN; - fin_seq_set = false; - rst_pkt_sent = false; -} - -void TcpTracker::init_toolbox() -{ - delete splitter; - splitter = nullptr; - delete normalizer; - normalizer = nullptr; - delete reassembler; - reassembler = nullptr; -} - -//------------------------------------------------------------------------- -// flush policy stuff -//------------------------------------------------------------------------- - -void TcpTracker::init_flush_policy() -{ - if ( splitter == nullptr ) - flush_policy = STREAM_FLPOLICY_IGNORE; - else if ( normalizer->is_tcp_ips_enabled() ) - flush_policy = STREAM_FLPOLICY_ON_DATA; - else - flush_policy = STREAM_FLPOLICY_ON_ACK; -} - -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::reset_splitter( ) -{ - if ( splitter ) - splitter->reset(); -} - -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_seg_seq(); - snd_una = iss; - snd_nxt = tsd.get_end_seq(); - snd_wnd = tsd.get_seg_wnd(); - - ts_last_packet = tsd.get_pkt()->pkth->ts.tv_sec; - tf_flags |= normalizer->get_tcp_timestamp(tsd, false); - ts_last = tsd.get_ts(); - if (ts_last == 0) - tf_flags |= TF_TSTAMP_ZERO; - tf_flags |= tsd.init_mss(&mss); - tf_flags |= tsd.init_wscale(&wscale); - - cache_mac_address(tsd, FROM_CLIENT); - tcp_state = TcpStreamTracker::TCP_SYN_SENT; - tcpStats.sessions_on_syn++; -} - -void TcpTracker::init_on_syn_recv(TcpSegmentDescriptor& tsd) -{ - Profile profile(s5TcpNewSessPerfStats); - - irs = tsd.get_seg_seq(); - // FIXIT-H can we really set the vars below now? - r_nxt_ack = tsd.get_seg_seq() + 1; - r_win_base = tsd.get_seg_seq() + 1; - reassembler->set_seglist_base_seq(tsd.get_seg_seq() + 1); - - cache_mac_address(tsd, FROM_CLIENT); - tcp_state = TcpStreamTracker::TCP_SYN_RECV; -} - -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_seg_seq(); - irs = tsd.get_seg_ack() - 1; - snd_una = tsd.get_seg_seq(); - snd_nxt = tsd.get_end_seq(); - snd_wnd = tsd.get_seg_wnd(); - - r_win_base = tsd.get_seg_ack(); - r_nxt_ack = tsd.get_seg_ack(); - reassembler->set_seglist_base_seq(tsd.get_seg_ack() ); - - ts_last_packet = tsd.get_pkt()->pkth->ts.tv_sec; - tf_flags |= normalizer->get_tcp_timestamp(tsd, false); - ts_last = tsd.get_ts(); - if ( ts_last == 0 ) - tf_flags |= TF_TSTAMP_ZERO; - tf_flags |= tsd.init_mss(&mss); - tf_flags |= tsd.init_wscale(&wscale); - - cache_mac_address(tsd, FROM_SERVER); - tcp_state = TcpStreamTracker::TCP_SYN_RECV; - tcpStats.sessions_on_syn_ack++; -} - -void TcpTracker::init_on_synack_recv(TcpSegmentDescriptor& tsd) -{ - Profile profile(s5TcpNewSessPerfStats); - - iss = tsd.get_seg_ack() - 1; - irs = tsd.get_seg_seq(); - snd_una = tsd.get_seg_ack(); - snd_nxt = snd_una; - - r_nxt_ack = tsd.get_seg_seq() + 1; - r_win_base = tsd.get_seg_seq() + 1; - reassembler->set_seglist_base_seq(tsd.get_seg_seq() + 1); - - cache_mac_address(tsd, FROM_SERVER); - tcp_state = TcpStreamTracker::TCP_ESTABLISHED; -} - -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_seg_seq(); - snd_una = tsd.get_seg_seq(); - snd_nxt = snd_una; - snd_wnd = tsd.get_seg_wnd(); - - r_win_base = tsd.get_seg_ack(); - r_nxt_ack = tsd.get_seg_ack(); - - ts_last_packet = tsd.get_pkt()->pkth->ts.tv_sec; - tf_flags |= normalizer->get_tcp_timestamp(tsd, false); - ts_last = tsd.get_ts(); - if (ts_last == 0) - tf_flags |= TF_TSTAMP_ZERO; - tf_flags |= tsd.init_mss(&mss); - tf_flags |= tsd.init_wscale(&wscale); - - cache_mac_address(tsd, FROM_CLIENT); - tcp_state = TcpStreamTracker::TCP_ESTABLISHED; -} - -void TcpTracker::init_on_3whs_ack_recv(TcpSegmentDescriptor& tsd) -{ - Profile profile(s5TcpNewSessPerfStats); - - iss = tsd.get_seg_ack() - 1; - irs = tsd.get_seg_seq(); - snd_una = tsd.get_seg_ack(); - snd_nxt = snd_una; - - r_nxt_ack = tsd.get_seg_seq(); - r_win_base = tsd.get_seg_seq(); - reassembler->set_seglist_base_seq(tsd.get_seg_seq() + 1); - - cache_mac_address(tsd, FROM_CLIENT); - tcp_state = TcpStreamTracker::TCP_ESTABLISHED; - tcpStats.sessions_on_3way++; -} - -void TcpTracker::init_on_data_seg_sent(TcpSegmentDescriptor& tsd) -{ - Profile profile(s5TcpNewSessPerfStats); - - Flow* flow = tsd.get_flow(); - - if ( flow->ssn_state.direction == FROM_CLIENT ) - flow->set_session_flags(SSNFLAG_SEEN_CLIENT); - else - flow->set_session_flags(SSNFLAG_SEEN_SERVER); - - // FIXIT-H should we init these? - iss = tsd.get_seg_seq(); - irs = tsd.get_seg_ack(); - snd_una = tsd.get_seg_seq(); - snd_nxt = snd_una + tsd.get_seg_len(); - snd_wnd = tsd.get_seg_wnd(); - - r_win_base = tsd.get_seg_ack(); - r_nxt_ack = tsd.get_seg_ack(); - reassembler->set_seglist_base_seq(tsd.get_seg_ack()); - - ts_last_packet = tsd.get_pkt()->pkth->ts.tv_sec; - tf_flags |= normalizer->get_tcp_timestamp(tsd, false); - ts_last = tsd.get_ts(); - if (ts_last == 0) - tf_flags |= TF_TSTAMP_ZERO; - tf_flags |= ( tsd.init_mss(&mss) | tsd.init_wscale(&wscale) ); - - cache_mac_address(tsd, tsd.get_direction() ); - tcp_state = TcpStreamTracker::TCP_ESTABLISHED; -} - -void TcpTracker::init_on_data_seg_recv(TcpSegmentDescriptor& tsd) -{ - Profile profile(s5TcpNewSessPerfStats); - - iss = tsd.get_seg_ack(); - irs = tsd.get_seg_seq(); - snd_una = tsd.get_seg_ack(); - snd_nxt = snd_una; - snd_wnd = 0; /* reset later */ - - r_nxt_ack = tsd.get_seg_seq(); - r_win_base = tsd.get_seg_seq(); - reassembler->set_seglist_base_seq(tsd.get_seg_seq()); - - cache_mac_address(tsd, tsd.get_direction() ); - tcp_state = TcpStreamTracker::TCP_ESTABLISHED; - tcpStats.sessions_on_data++; -} - -void TcpTracker::finish_server_init(TcpSegmentDescriptor& tsd) -{ - iss = tsd.get_seg_seq(); - snd_una = tsd.get_seg_seq(); - snd_nxt = tsd.get_end_seq(); - snd_wnd = tsd.get_seg_wnd(); - - // FIXIT-H move this to fin handler for syn_recv state .. - //if ( tcph->is_fin() ) - // server->set_snd_nxt(server->get_snd_nxt() - 1); - - tf_flags |= normalizer->get_tcp_timestamp(tsd, false); - ts_last = tsd.get_ts(); - if ( ts_last != 0 ) - ts_last_packet = tsd.get_pkt()->pkth->ts.tv_sec; - else - tf_flags |= TF_TSTAMP_ZERO; - - tf_flags |= ( tsd.init_mss(&mss) | tsd.init_wscale(&wscale) ); -} - -void TcpTracker::finish_client_init(TcpSegmentDescriptor& tsd) -{ - Flow* flow = tsd.get_flow(); - - r_nxt_ack = tsd.get_end_seq(); - - if ( !( flow->session_state & STREAM_STATE_MIDSTREAM ) ) - { - reassembler->set_seglist_base_seq(tsd.get_seg_seq() + 1); - r_win_base = tsd.get_end_seq(); - } - else - { - reassembler->set_seglist_base_seq(tsd.get_seg_seq() ); - r_win_base = tsd.get_seg_seq(); - } -} - -void TcpTracker::update_tracker_ack_recv(TcpSegmentDescriptor& tsd) -{ - if ( SEQ_GT(tsd.get_seg_ack(), snd_una) ) - { - snd_una = tsd.get_seg_ack(); - if ( snd_nxt < snd_una ) - snd_nxt = snd_una; - } -} - -void TcpTracker::update_tracker_ack_sent(TcpSegmentDescriptor& tsd) -{ - // ** this is how we track the last seq number sent - // as is l_unackd is the "last left" seq recvd - //snd_una = tsd.get_seg_seq(); - - // FIXIT-H add check to validate ack... - - if ( SEQ_GT(tsd.get_end_seq(), snd_nxt) ) - snd_nxt = tsd.get_end_seq(); - - if ( !SEQ_EQ(r_win_base, tsd.get_seg_ack() ) ) - small_seg_count = 0; - -#ifdef S5_PEDANTIC - if ( SEQ_GT(tsd.get_seg_ack(), r_win_base) && - SEQ_LEQ(tsd.get_seg_ack(), r_nxt_ack) ) -#else - if ( SEQ_GT(tsd.get_seg_ack(), r_win_base) ) -#endif - r_win_base = tsd.get_seg_ack(); - - if ( ( fin_seq_status == TcpStreamTracker::FIN_WITH_SEQ_SEEN ) - && SEQ_EQ(r_win_base, fin_final_seq) ) - { - fin_seq_status = TcpStreamTracker::FIN_WITH_SEQ_ACKED; - } - - snd_wnd = tsd.get_seg_wnd(); - reassembler->flush_on_ack_policy(tsd.get_pkt() ); -} - -bool TcpTracker::update_on_3whs_ack(TcpSegmentDescriptor& tsd) -{ - bool good_ack = true; - - if ( is_ack_valid(tsd.get_seg_ack()) ) - { - Flow* flow = tsd.get_flow(); - - irs = tsd.get_seg_seq(); - finish_client_init(tsd); - update_tracker_ack_recv(tsd); - flow->set_session_flags(SSNFLAG_ESTABLISHED); - flow->session_state |= ( STREAM_STATE_ACK | STREAM_STATE_ESTABLISHED ); - tcp_state = TcpStreamTracker::TCP_ESTABLISHED; - } - else - { - DebugFormat(DEBUG_STREAM_STATE, - "Pkt Ack is Out of Bounds (%X, %X, %X) = (snd_una, snd_nxt, cur)\n", - snd_una, snd_nxt, tsd.get_seg_ack()); - inc_tcp_discards(); - normalizer->trim_win_payload(tsd); - good_ack = false; - } - - return good_ack; -} - -bool TcpTracker::update_on_rst_recv(TcpSegmentDescriptor& tsd) -{ - bool good_rst = true; - - normalizer->trim_rst_payload(tsd); - if ( normalizer->validate_rst(tsd) ) - { - Flow* flow = tsd.get_flow(); - - DebugMessage(DEBUG_STREAM_STATE, "Received Valid RST, bailing\n"); - flow->set_session_flags(SSNFLAG_RESET); - if ( normalizer->is_tcp_ips_enabled() ) - tcp_state = TcpStreamTracker::TCP_CLOSED; - } - else - { - DebugMessage(DEBUG_STREAM_STATE, "Received RST with bad sequence number, bailing\n"); - inc_tcp_discards(); - normalizer->packet_dropper(tsd, NORM_TCP_BLOCK); - good_rst = false; - } - - return good_rst; -} - -void TcpTracker::update_on_rst_sent() -{ - tcp_state = TcpStreamTracker::TCP_CLOSED; - rst_pkt_sent = true; -} - -void TcpTracker::flush_data_on_fin_recv(TcpSegmentDescriptor& tsd) -{ - if ( (flush_policy != STREAM_FLPOLICY_ON_ACK) - && (flush_policy != STREAM_FLPOLICY_ON_DATA) - && normalizer->is_tcp_ips_enabled()) - { - tsd.get_pkt()->packet_flags |= PKT_PDU_TAIL; - } - - reassembler->flush_on_data_policy(tsd.get_pkt()); -} - -bool TcpTracker::update_on_fin_recv(TcpSegmentDescriptor& tsd) -{ - if ( SEQ_LT(tsd.get_end_seq(), r_win_base) ) - { - DebugMessage(DEBUG_STREAM_STATE, "FIN inside r_win_base, bailing\n"); - return false; - } - - //-------------------------------------------------- - // FIXIT-L don't bump r_nxt_ack unless FIN is in seq - // because it causes bogus 129:5 cases - // but doing so causes extra gaps - //if ( SEQ_EQ(tsd.end_seq, r_nxt_ack) ) - r_nxt_ack++; - - // set final seq # any packet rx'ed with seq > is bad - if ( !fin_seq_set ) - { - fin_final_seq = tsd.get_end_seq(); - fin_seq_set = true; - if( tsd.get_seg_len() == 0 ) - fin_seq_status = TcpStreamTracker::FIN_WITH_SEQ_SEEN; - } - - return true; -} - -bool TcpTracker::update_on_fin_sent(TcpSegmentDescriptor& tsd) -{ - update_tracker_ack_sent(tsd); - snd_nxt++; - return true; -} - -#ifdef S5_PEDANTIC -// From RFC 793: -// -// Segment Receive Test -// Length Window -// ------- ------- ------------------------------------------- -// -// 0 0 SEG.SEQ = RCV.NXT -// -// 0 >0 RCV.NXT =< SEG.SEQ < RCV.NXT+RCV.WND -// -// >0 0 not acceptable -// -// >0 >0 RCV.NXT =< SEG.SEQ < RCV.NXT+RCV.WND -// or RCV.NXT =< SEG.SEQ+SEG.LEN-1 < RCV.NXT+RCV.WND -// -bool ValidSeq(const Packet* p, Flow* flow, TcpTracker* st, TcpSegmentDescriptor& tsd) -{ - uint32_t win = normalizer->get_stream_window(flow, st, tsd); - - if ( !p->dsize ) - { - if ( !win ) - { - return ( tsd.get_seg_seq() == r_win_base ); - } - return SEQ_LEQ(r_win_base, tsd.get_seg_seq()) && - SEQ_LT(tsd.get_seg_seq(), r_win_base+win); - } - if ( !win ) - return 0; - - if ( SEQ_LEQ(r_win_base, tsd.get_seg_seq()) && - SEQ_LT(tsd.get_seg_seq(), r_win_base+win) ) - return 1; - - return SEQ_LEQ(r_win_base, tsd.get_end_seq()) && - SEQ_LT(tsd.get_end_seq(), r_win_base+win); -} - -#endif - -bool TcpTracker::is_segment_seq_valid(TcpSegmentDescriptor& tsd) -{ - bool valid_seq = true; - - int right_ok; - uint32_t left_seq; - - DebugFormat(DEBUG_STREAM_STATE, - "Checking end_seq (%X) > r_win_base (%X) && seq (%X) < r_nxt_ack(%X)\n", - tsd.get_end_seq(), r_win_base, tsd.get_seg_seq(), - r_nxt_ack + normalizer->get_stream_window(tsd)); - - if ( SEQ_LT(r_nxt_ack, r_win_base) ) - left_seq = r_nxt_ack; - else - left_seq = r_win_base; - - if ( tsd.get_seg_len() ) - right_ok = SEQ_GT(tsd.get_end_seq(), left_seq); - else - right_ok = SEQ_GEQ(tsd.get_end_seq(), left_seq); - - if ( right_ok ) - { - uint32_t win = normalizer->get_stream_window(tsd); - - if ( SEQ_LEQ(tsd.get_seg_seq(), r_win_base + win) ) - { - DebugMessage(DEBUG_STREAM_STATE, "seq is within window!\n"); - } - else - { - DebugMessage(DEBUG_STREAM_STATE, "seq is past the end of the window!\n"); - valid_seq = false; - } - } - else - { - DebugMessage(DEBUG_STREAM_STATE, "end_seq is before win_base\n"); - valid_seq = false; - } - - if ( !valid_seq ) - { - inc_tcp_discards(); - normalizer->trim_win_payload(tsd); - } - - return valid_seq; -} - -void TcpTracker::print() -{ - LogMessage(" + TcpTracker +\n"); - LogMessage(" state: %s\n", tcp_state_names[ tcp_state ]); - 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 deleted file mode 100644 index ed39cc9a4..000000000 --- a/src/stream/tcp/tcp_tracker.h +++ /dev/null @@ -1,88 +0,0 @@ -//-------------------------------------------------------------------------- -// Copyright (C) 2015-2018 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" - -//------------------------------------------------------------------------- -// 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 -//------------------------------------------------------------------------- - -class TcpTracker : public TcpStreamTracker -{ -public: - TcpTracker(bool, class TcpSession*); - ~TcpTracker() override; - - void init_tcp_state() override; - void print() override; - void init_flush_policy() override; - void set_splitter(snort::StreamSplitter* ss) override; - void set_splitter(const snort::Flow* flow) override; - void reset_splitter( ) override; - - void init_on_syn_sent(TcpSegmentDescriptor&) override; - void init_on_syn_recv(TcpSegmentDescriptor&) override; - void init_on_synack_sent(TcpSegmentDescriptor&) override; - void init_on_synack_recv(TcpSegmentDescriptor&) override; - void init_on_3whs_ack_sent(TcpSegmentDescriptor&) override; - void init_on_3whs_ack_recv(TcpSegmentDescriptor&) override; - void init_on_data_seg_sent(TcpSegmentDescriptor&) override; - void init_on_data_seg_recv(TcpSegmentDescriptor&) override; - void finish_server_init(TcpSegmentDescriptor&) override; - void finish_client_init(TcpSegmentDescriptor&) override; - - void update_tracker_ack_recv(TcpSegmentDescriptor&) override; - void update_tracker_ack_sent(TcpSegmentDescriptor&) override; - bool update_on_3whs_ack(TcpSegmentDescriptor&) override; - bool update_on_rst_recv(TcpSegmentDescriptor&) override; - void update_on_rst_sent() override; - bool update_on_fin_recv(TcpSegmentDescriptor&) override; - bool update_on_fin_sent(TcpSegmentDescriptor&) override; - bool is_segment_seq_valid(TcpSegmentDescriptor&) override; - void flush_data_on_fin_recv(TcpSegmentDescriptor&) override; - - void init_toolbox() override; -}; - -#endif - diff --git a/src/stream/tcp/test/tcp_normalizer_test.cc b/src/stream/tcp/test/tcp_normalizer_test.cc index 2abbd45dc..9fc4aba9a 100644 --- a/src/stream/tcp/test/tcp_normalizer_test.cc +++ b/src/stream/tcp/test/tcp_normalizer_test.cc @@ -122,14 +122,14 @@ TEST(tcp_normalizers, os_policy) StreamPolicy os_policy; Flow* flow = new FlowMock; TcpSession* session = new TcpSessionMock( flow ); + TcpNormalizerState tns; for( os_policy = StreamPolicy::OS_FIRST; os_policy <= StreamPolicy::OS_PROXY; ++os_policy ) { - TcpNormalizer* normalizer = TcpNormalizerFactory::create( session, os_policy, - session->client, session->server ); - CHECK( normalizer->get_os_policy() == os_policy ); + TcpNormalizer* normalizer = TcpNormalizerFactory::create( + tns, os_policy, session, session->client, session->server); - delete normalizer; + CHECK( normalizer.get_os_policy(tns) == os_policy ); } delete flow; @@ -141,24 +141,23 @@ TEST(tcp_normalizers, paws_fudge_config) StreamPolicy os_policy; Flow* flow = new FlowMock; TcpSession* session = new TcpSessionMock( flow ); + TcpNormalizerState tns; for( os_policy = StreamPolicy::OS_FIRST; os_policy <= StreamPolicy::OS_PROXY; ++os_policy ) { - TcpNormalizer* normalizer = TcpNormalizerFactory::create( session, os_policy, - session->client, session->server ); + TcpNormalizer* normalizer = TcpNormalizerFactory::create( + tns, os_policy, session, session->client, session->server); switch ( os_policy ) { case StreamPolicy::OS_LINUX: - CHECK( normalizer->get_paws_ts_fudge() == 1 ); + CHECK( normalizer.get_paws_ts_fudge(tns) == 1 ); break; default: - CHECK( normalizer->get_paws_ts_fudge() == 0 ); + CHECK( normalizer.get_paws_ts_fudge(tns) == 0 ); break; } - - delete normalizer; } delete flow; @@ -170,11 +169,12 @@ TEST(tcp_normalizers, paws_drop_zero_ts_config) StreamPolicy os_policy; Flow* flow = new FlowMock; TcpSession* session = new TcpSessionMock( flow ); + TcpNormalizerState tns; for( os_policy = StreamPolicy::OS_FIRST; os_policy <= StreamPolicy::OS_PROXY; ++os_policy ) { - TcpNormalizer* normalizer = TcpNormalizerFactory::create( session, os_policy, - session->client, session->server ); + TcpNormalizer* normalizer = TcpNormalizerFactory::create( + tns, os_policy, session, session->client, session->server ); switch ( os_policy ) { @@ -183,15 +183,13 @@ TEST(tcp_normalizers, paws_drop_zero_ts_config) case StreamPolicy::OS_WINDOWS: case StreamPolicy::OS_WINDOWS2K3: case StreamPolicy::OS_VISTA: - CHECK( !normalizer->is_paws_drop_zero_ts() ); + CHECK( !normalizer.is_paws_drop_zero_ts(tns) ); break; default: - CHECK( normalizer->is_paws_drop_zero_ts() ); + CHECK( normalizer.is_paws_drop_zero_ts(tns) ); break; } - - delete normalizer; } delete flow; @@ -207,36 +205,35 @@ TEST(tcp_normalizers, norm_options_enabled) norm_enabled = true; for( os_policy = StreamPolicy::OS_FIRST; os_policy <= StreamPolicy::OS_PROXY; ++os_policy ) { - TcpNormalizer* normalizer = TcpNormalizerFactory::create( session, os_policy, - session->client, session->server ); - - CHECK( normalizer->get_opt_block() == NORM_MODE_ON ); - CHECK( normalizer->get_strip_ecn() == NORM_MODE_ON ); - CHECK( normalizer->get_tcp_block() == NORM_MODE_ON ); - CHECK( normalizer->get_trim_syn() == NORM_MODE_ON ); - CHECK( normalizer->get_trim_rst() == NORM_MODE_ON ); - CHECK( normalizer->get_trim_mss() == NORM_MODE_ON ); - CHECK( normalizer->get_trim_win() == NORM_MODE_ON ); - CHECK( normalizer->is_tcp_ips_enabled() ); - - delete normalizer; + TcpNormalizerState tns; + TcpNormalizer* normalizer = TcpNormalizerFactory::create( + tns, os_policy, session, session->client, session->server); + + CHECK( normalizer.get_opt_block(tns) == NORM_MODE_ON ); + CHECK( normalizer.get_strip_ecn(tns) == NORM_MODE_ON ); + CHECK( normalizer.get_tcp_block(tns) == NORM_MODE_ON ); + CHECK( normalizer.get_trim_syn(tns) == NORM_MODE_ON ); + CHECK( normalizer.get_trim_rst(tns) == NORM_MODE_ON ); + CHECK( normalizer.get_trim_mss(tns) == NORM_MODE_ON ); + CHECK( normalizer.get_trim_win(tns) == NORM_MODE_ON ); + CHECK( normalizer.is_tcp_ips_enabled(tns) ); } norm_enabled = false; for( os_policy = StreamPolicy::OS_FIRST; os_policy <= StreamPolicy::OS_PROXY; ++os_policy ) { - TcpNormalizer* normalizer = TcpNormalizerFactory::create( session, os_policy, - session->client, session->server ); - - CHECK( normalizer->get_opt_block() == NORM_MODE_TEST ); - CHECK( normalizer->get_strip_ecn() == NORM_MODE_TEST ); - CHECK( normalizer->get_tcp_block() == NORM_MODE_TEST ); - CHECK( normalizer->get_trim_syn() == NORM_MODE_TEST ); - CHECK( normalizer->get_trim_rst() == NORM_MODE_TEST ); - CHECK( normalizer->get_trim_mss() == NORM_MODE_TEST ); - CHECK( normalizer->get_trim_win() == NORM_MODE_TEST ); - CHECK( !normalizer->is_tcp_ips_enabled() ); - delete normalizer; + TcpNormalizerState tns; + TcpNormalizer* normalizer = TcpNormalizerFactory::create( + tns, os_policy, session, session->client, session->server); + + CHECK( normalizer.get_opt_block(tns) == NORM_MODE_TEST ); + CHECK( normalizer.get_strip_ecn(tns) == NORM_MODE_TEST ); + CHECK( normalizer.get_tcp_block(tns) == NORM_MODE_TEST ); + CHECK( normalizer.get_trim_syn(tns) == NORM_MODE_TEST ); + CHECK( normalizer.get_trim_rst(tns) == NORM_MODE_TEST ); + CHECK( normalizer.get_trim_mss(tns) == NORM_MODE_TEST ); + CHECK( normalizer.get_trim_win(tns) == NORM_MODE_TEST ); + CHECK( !normalizer.is_tcp_ips_enabled(tns) ); } delete flow;