#include <iostream>
#include "main/snort_debug.h"
-
+#include "tcp_segment_descriptor.h"
#include "tcp_state_machine.h"
#ifdef UNIT_TEST
#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
};
#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)
{
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 )
/* 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 ) )
{
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;
{
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;
}
{
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;
}
{
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;
}
{
SfIp tmpIp;
uint16_t tmpPort;
- TcpStreamTracker* tracker;
if (flow->client_ip.equals(*ip) && (flow->client_port == port))
{
flow->server_port = tmpPort;
SwapPacketHeaderFoo( );
- tracker = client;
+ TcpStreamTracker& tracker = client;
client = server;
server = tracker;
}
// 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;
}
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;
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))
{
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;
void TcpStreamSession::cleanup(Packet* p)
{
clear_session(true, true, false, p);
+ client.normalizer.reset();
+ server.reassembler.reset();
}
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()
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();
}
#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"
class TcpStreamSession : public Session
{
public:
- TcpStreamSession(snort::Flow* flow) : Session(flow) { }
~TcpStreamSession() override;
bool setup(snort::Packet*) override;
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;
uint16_t real_dst_port = 0;
protected:
+ TcpStreamSession(snort::Flow*);
virtual void set_os_policy() = 0;
TcpStreamTracker* talker = nullptr;
#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;
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)
}
}
+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);
+}
+
#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
extern const char* tcp_state_names[];
extern const char* tcp_event_names[];
-class TcpNormalizer;
class TcpReassembler;
class TcpSession;
+struct TcpSegmentNode;
class TcpStreamTracker
{
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)
{
// 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;
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;
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
{
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);
}
}
// 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));
}
}
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 )
#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;
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;
// 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;
}
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;
}
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<uint8_t*>(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<uint8_t*>(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<uint8_t*>(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<uint8_t*>(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");
}
}
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<uint8_t*>(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<uint8_t*>(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<uint8_t*>(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<uint8_t*>(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;
// 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;
}
// 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;
}
// 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;
// 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);
}
#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
#include "utils/stats.h"
-#include "tcp_reassembler.h"
+#include "tcp_reassemblers.h"
#ifndef REG_TEST
#define S5TraceTCP(pkt, flow, tsd, evt)
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";
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;
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;
}
}
-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;
TraceTCP(p, lws, tsd, event);
}
-
#endif // REG_TEST
#endif
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;
#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"
{ 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;
}
void TcpNormalizer::trim_payload(
+ TcpNormalizerState&,
TcpSegmentDescriptor& tsd, uint32_t max, NormMode mode, TcpPegCounts peg)
{
if (mode == NORM_MODE_ON)
}
bool TcpNormalizer::strip_tcp_timestamp(
+ TcpNormalizerState&,
TcpSegmentDescriptor& tsd, const tcp::TcpOption* opt, NormMode mode)
{
tcp_norm_stats[PC_TCP_TS_NOP][mode]++;
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]++;
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<tcp::TCPHdr*>(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");
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)
{
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;
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;
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;
// 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
}
}
-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;
}
// 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;
}
}
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;
}
#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;
#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
{
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
#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.
}
}
-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()))
}
// 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;
}
// 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;
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,
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;
}
#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
#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<int>( 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 )
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 )
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);
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;
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;
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;
"(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;
}
// 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++;
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;
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
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;
// 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;
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);
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;
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;
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;
|| (!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;
}
}
// 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;
}
}
-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<DAQ_PktHdr_t*>(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 )
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;
/* 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 )
{
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;
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;
}
}
// 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;
}
}
// 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 ) )
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;
}
// 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)
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,
*/
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;
// 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 ) )
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;
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)
// - 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 )
// 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;
}
}
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");
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);
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)
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;
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");
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();
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");
}
}
- // 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;
}
}
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;
}
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
{
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 )
tsn = tsn->next;
}
}
-
#endif
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
#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<int>(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;
}
#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
#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
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)
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//--------------------------------------------------------------------------
-// tcp_segment.h author davis mcpherson <davmcphe@@cisco.com>
+// tcp_segment_node.h author davis mcpherson <davmcphe@@cisco.com>
// Created on: Sep 21, 2015
#ifndef TCP_SEGMENT_H
#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
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();
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++;
head = tail = next = nullptr;
count = 0;
- DebugFormat(DEBUG_STREAM_STATE, "Dropped %d segments\n", i);
return i;
}
ss->next = prev->next;
ss->prev = prev;
prev->next = ss;
+
if ( ss->next )
ss->next->prev = ss;
else
else
{
ss->next = head;
+
if ( ss->next )
ss->next->prev = ss;
else
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
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)
TcpStreamSession::setup(p);
splitter_init = false;
- client->init_toolbox();
- server->init_toolbox();
-
SESSION_STATS_ADD(tcpStats);
return true;
}
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);
}
//-------------------------------------------------------------------------
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 )
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);
}
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
}
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
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);
}
}
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;
}
/* 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;
}
{
StreamPolicy client_os_policy = flow->ssn_policy ?
static_cast<StreamPolicy>( flow->ssn_policy ) : config->policy;
+
StreamPolicy server_os_policy = flow->ssn_policy ?
static_cast<StreamPolicy>( 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)
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;
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);
// 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;
}
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())
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);
}
}
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;
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 )
/* 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;
}
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;
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);
}
{
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)
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());
}
}
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()
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)
{
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 )
}
// 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)
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 )
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)
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,
// 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;
}
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;
}
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;
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);
}
}
#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:
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;
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:
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;
};
#include "main/snort_debug.h"
-#include "tcp_normalizer.h"
+#include "tcp_normalizers.h"
#include "tcp_session.h"
#ifdef UNIT_TEST
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);
{
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
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);
#include "main/snort_debug.h"
-#include "tcp_normalizer.h"
+#include "tcp_normalizers.h"
#include "tcp_session.h"
#ifdef UNIT_TEST
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;
{
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);
}
#include "tcp_state_established.h"
-#include "tcp_normalizer.h"
+#include "tcp_normalizers.h"
#include "tcp_session.h"
TcpStateEstablished::TcpStateEstablished(TcpStateMachine& tsm) :
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;
}
}
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;
}
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);
#include "main/snort_debug.h"
-#include "tcp_normalizer.h"
+#include "tcp_normalizers.h"
#include "tcp_module.h"
#include "tcp_session.h"
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;
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;
#include "tcp_state_fin_wait2.h"
-#include "tcp_normalizer.h"
+#include "tcp_normalizers.h"
#include "tcp_session.h"
using namespace std;
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;
{
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);
}
{
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);
}
#include "tcp_state_last_ack.h"
-#include "tcp_normalizer.h"
+#include "tcp_normalizers.h"
#include "tcp_session.h"
using namespace std;
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;
#include "tcp_state_listen.h"
-#include "tcp_normalizer.h"
+#include "tcp_normalizers.h"
#include "tcp_session.h"
using namespace snort;
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;
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() )
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() )
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() )
bool TcpStateListen::rst_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk)
{
- trk.normalizer->trim_rst_payload(tsd);
+ trk.normalizer.trim_rst_payload(tsd);
return true;
}
#include "tcp_state_none.h"
-#include "tcp_normalizer.h"
+#include "tcp_normalizers.h"
#include "tcp_session.h"
using namespace snort;
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() )
{
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);
}
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() )
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() )
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);
#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;
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 ) )
// 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;
}
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);
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 );
{
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);
}
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 )
{
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);
}
#include "main/snort_debug.h"
-#include "tcp_normalizer.h"
+#include "tcp_normalizers.h"
#include "tcp_session.h"
using namespace std;
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);
{
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 )
private:
TcpStreamStateMachine();
- void initialize_tsm();
};
#endif
+++ /dev/null
-//--------------------------------------------------------------------------
-// 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 <davmcphe@@cisco.com>
-// 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);
-}
-
+++ /dev/null
-//--------------------------------------------------------------------------
-// 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 <davmcphe@@cisco.com>
-// 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
-
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;
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;
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_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;
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;