static const uint32_t max_dsize = IP_MAXPACKET;
/* Boolean functions - general information about this packet */
+ inline bool is_eth() const
+ { return proto_bits & PROTO_BIT__ETH; }
+
inline bool has_ip() const
{ return ptrs.ip_api.is_ip(); }
static inline void SetExtraData(Packet* p, const uint32_t xid)
{ p->xtradata_mask |= BIT(xid); }
-static inline uint16_t EXTRACT_16BITS(const uint8_t* const p)
+static inline uint16_t extract_16bits(const uint8_t* const p)
{ return ntohs(*(uint16_t*)(p)); }
#ifdef WORDS_MUSTALIGN
#ifdef __GNUC__
/* force word-aligned ntohl parameter */
-static inline uint32_t EXTRACT_32BITS(const uint8_t* p)
+static inline uint32_t extract_32bits(const uint8_t* p)
{
uint32_t tmp;
memmove(&tmp, p, sizeof(uint32_t));
#else
/* allows unaligned ntohl parameter - dies w/SIGBUS on SPARCs */
-static inline uint32_t EXTRACT_32BITS(const uint8_t* p)
+static inline uint32_t extract_32bits(const uint8_t* p)
{ return ntohl(*(uint32_t*)p); }
#endif
using namespace tcp;
-TcpSegmentDescriptor::TcpSegmentDescriptor(Flow* flow, Packet* pkt, TcpEventLogger* tel) :
+TcpSegmentDescriptor::TcpSegmentDescriptor(Flow* flow, Packet* pkt, TcpEventLogger& tel) :
flow(flow), pkt(pkt)
{
tcph = pkt->ptrs.tcph;
- src_port = ntohs(tcph->th_sport);
- dst_port = ntohs(tcph->th_dport);
- seq = ntohl(pkt->ptrs.tcph->th_seq);
- ack = ntohl(pkt->ptrs.tcph->th_ack);
- win = ntohs(pkt->ptrs.tcph->th_win);
- end_seq = seq + (uint32_t)pkt->dsize;
+ src_port = tcph->src_port();
+ dst_port = tcph->dst_port();
+ seg_seq = tcph->seq();
+ seg_ack = tcph->ack();
+ seg_wnd = tcph->win();
+ end_seq = seg_seq + (uint32_t)pkt->dsize;
ts = 0;
// don't bump end_seq for fin here we will bump if/when fin is processed
{
end_seq++;
if ( !tcph->is_ack() )
- tel->set_tcp_internal_syn_event( );
+ tel.set_tcp_internal_syn_event( );
}
#ifdef DEBUG_STREAM_EX
{
if ( opt.code == TcpOptCode::MAXSEG )
{
- *value = EXTRACT_16BITS(opt.data);
+ *value = extract_16bits(opt.data);
DebugFormat(DEBUG_STREAM_STATE, "Found MSS %u\n", *value);
return TF_MSS;
}
TcpOptIterator iter(tcph, pkt);
- // using const because non-const is not supported
for (const TcpOption& opt : iter)
{
if (opt.code == TcpOptCode::WSCALE)
*value = (uint16_t)opt.data[0];
DebugFormat(DEBUG_STREAM_STATE, "Found wscale %d\n", *value);
- /* If scale specified in option is larger than 14,
- * use 14 because of limitation in the math of
- * shifting a 32bit value (max scaled window is 2^30th).
- *
- * See RFC 1323 for details.
- */
+ // If scale specified in option is larger than 14, use 14 because of limitation
+ // in the math of shifting a 32bit value (max scaled window is 2^30th).
+ // See RFC 1323 for details.
if (*value > 14)
*value = 14;
return TF_NONE;
}
-uint32_t TcpSegmentDescriptor::has_wscale(void)
+bool TcpSegmentDescriptor::has_wscale(void)
{
uint16_t wscale;
DebugMessage(DEBUG_STREAM_STATE, "Checking for wscale...\n");
- return init_wscale(&wscale);
+ return ( init_wscale(&wscale) & TF_WSCALE ) != TF_NONE;
}
void TcpSegmentDescriptor::print_tsd(void)
{
LogMessage("Tcp Segment Descriptor:\n");
- LogMessage(" seq: 0x%08X\n", seq);
- LogMessage(" ack: 0x%08X\n", ack);
- LogMessage(" win: %d\n", win);
+ LogMessage(" seq: 0x%08X\n", seg_seq);
+ LogMessage(" ack: 0x%08X\n", seg_ack);
+ LogMessage(" win: %d\n", seg_wnd);
LogMessage(" end: 0x%08X\n", end_seq);
}
class TcpSegmentDescriptor
{
public:
- TcpSegmentDescriptor(Flow*, Packet*, TcpEventLogger*);
+ TcpSegmentDescriptor(Flow*, Packet*, TcpEventLogger&);
virtual ~TcpSegmentDescriptor();
uint32_t init_mss(uint16_t* value);
uint32_t init_wscale(uint16_t* value);
- uint32_t has_wscale(void);
+ bool has_wscale(void);
Flow* get_flow() const
{
return tcph;
}
- void set_seq(uint32_t seq)
+ void set_seg_seq(uint32_t seq)
{
- this->seq = seq;
+ this->seg_seq = seq;
}
- uint32_t get_seq() const
+ void update_seg_seq(int32_t offset)
{
- return seq;
+ seg_seq += offset;
}
- uint32_t get_ack() const
+ uint32_t get_seg_seq() const
{
- return ack;
+ return seg_seq;
+ }
+
+ uint32_t get_seg_ack() const
+ {
+ return seg_ack;
}
void set_end_seq(uint32_t end_seq)
return ts;
}
- void set_win(uint32_t win)
+ void scale_seg_wnd(uint16_t wscale)
{
- this->win = win;
+ this->seg_wnd <<= wscale;
}
- uint32_t get_win() const
+ uint32_t get_seg_wnd() const
{
- return win;
+ return seg_wnd;
}
uint16_t get_dst_port() const
return flow->ssn_state.direction;
}
- uint32_t get_data_len() const
+ uint16_t get_seg_len() const
{
return pkt->dsize;
}
+ void set_seg_len(uint16_t seg_len)
+ {
+ pkt->dsize = seg_len;
+ }
+
+ void update_seg_len(int32_t offset)
+ {
+ pkt->dsize += offset;
+ }
+
+ bool is_packet_from_server(void)
+ {
+ return pkt->packet_flags & PKT_FROM_SERVER;
+ }
+
+ void slide_segment_in_rcv_window(int32_t offset)
+ {
+ seg_seq += offset;
+ pkt->data += offset;
+ pkt->dsize -= offset;
+ }
+
void print_tsd(void);
private:
const tcp::TCPHdr* tcph;
uint16_t src_port;
uint16_t dst_port;
- uint32_t seq;
- uint32_t ack;
- uint32_t win;
+ uint32_t seg_seq;
+ uint32_t seg_ack;
+ uint32_t seg_wnd;
uint32_t end_seq;
uint32_t ts;
};
#include "stream_tcp_unit_test.h"
#endif
-TcpStateHandler::TcpStateHandler(TcpStreamTracker::TcpStates state, TcpStateMachine& tsm) :
- tsm(&tsm), tcp_state(state), tcp_event(TcpStreamTracker::TCP_MAX_EVENTS)
+TcpStateHandler::TcpStateHandler(TcpStreamTracker::TcpState state, TcpStateMachine& tsm) :
+ tsm(&tsm), tcp_state(state)
{
tsm.register_state_handler(state, *this);
}
TcpStateHandler::TcpStateHandler(void) :
- tsm(nullptr), tcp_state(TcpStreamTracker::TCP_CLOSED),
- tcp_event(TcpStreamTracker::TCP_MAX_EVENTS)
+ tsm(nullptr), tcp_state(TcpStreamTracker::TCP_CLOSED)
{
}
// TODO Auto-generated destructor stub
}
+void TcpStateHandler::do_pre_sm_packet_actions(TcpSegmentDescriptor& tsd)
+{
+ UNUSED(tsd);
+}
+
+void TcpStateHandler::do_post_sm_packet_actions(TcpSegmentDescriptor& tsd)
+{
+ UNUSED(tsd);
+}
+
bool TcpStateHandler::eval(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
bool handled = false;
+ do_pre_sm_packet_actions(tsd);
+
switch ( tcp_event = tracker.get_tcp_event() )
{
case TcpStreamTracker::TCP_SYN_SENT_EVENT:
break;
}
+ do_post_sm_packet_actions(tsd);
return handled;
}
-bool TcpStateHandler::default_state_action(
- TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker, const char* func_name)
+bool TcpStateHandler::default_state_action(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
#ifdef DEBUG_MSGS
- DebugFormat(DEBUG_STREAM_STATE, "Default Implementation of: %s tsd: %p tracker: %p\n",
- func_name, &tsd, &tracker);
+ DebugFormat(DEBUG_STREAM_STATE, "tsd: %p tracker: %p state: %u event: %u\n",
+ &tsd, &tracker, tracker.get_tcp_state(), tracker.get_tcp_event() );
#else
UNUSED(tsd);
- UNUSED(func_name);
+ UNUSED(tracker)
#endif
- tcp_event = tracker.get_tcp_event();
- return false;
+ return true;
}
bool TcpStateHandler::syn_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- return default_state_action(tsd, tracker, __func__);
+ return default_state_action(tsd, tracker);
}
bool TcpStateHandler::syn_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- return default_state_action(tsd, tracker, __func__);
+ return default_state_action(tsd, tracker);
}
bool TcpStateHandler::syn_ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- return default_state_action(tsd, tracker, __func__);
+ return default_state_action(tsd, tracker);
}
bool TcpStateHandler::syn_ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- return default_state_action(tsd, tracker, __func__);
+ return default_state_action(tsd, tracker);
}
bool TcpStateHandler::ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- return default_state_action(tsd, tracker, __func__);
+ return default_state_action(tsd, tracker);
}
bool TcpStateHandler::ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- return default_state_action(tsd, tracker, __func__);
+ return default_state_action(tsd, tracker);
}
bool TcpStateHandler::data_seg_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- return default_state_action(tsd, tracker, __func__);
+ return default_state_action(tsd, tracker);
}
bool TcpStateHandler::data_seg_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- return default_state_action(tsd, tracker, __func__);
+ return default_state_action(tsd, tracker);
}
bool TcpStateHandler::fin_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- return default_state_action(tsd, tracker, __func__);
+ return default_state_action(tsd, tracker);
}
bool TcpStateHandler::fin_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- return default_state_action(tsd, tracker, __func__);
+ return default_state_action(tsd, tracker);
}
bool TcpStateHandler::rst_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- return default_state_action(tsd, tracker, __func__);
+ return default_state_action(tsd, tracker);
}
bool TcpStateHandler::rst_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- return default_state_action(tsd, tracker, __func__);
+ return default_state_action(tsd, tracker);
}
#ifdef UNIT_TEST
TcpStateHandler* tsh = new TcpStateHandler;
TcpStreamTracker* client_tracker = new TcpStreamTracker(true);
TcpStreamTracker* server_tracker = new TcpStreamTracker(false);
- TcpEventLogger* tel = new TcpEventLogger;
+ TcpEventLogger tel;
GIVEN("a SYN Packet")
{
class TcpStateHandler
{
public:
- TcpStateHandler(TcpStreamTracker::TcpStates, TcpStateMachine&);
+ TcpStateHandler(TcpStreamTracker::TcpState, TcpStateMachine&);
TcpStateHandler(void);
virtual ~TcpStateHandler();
virtual bool eval(TcpSegmentDescriptor&, TcpStreamTracker&);
- TcpStreamTracker::TcpEvents get_tcp_event() const
+ TcpStreamTracker::TcpEvent get_tcp_event() const
{
return tcp_event;
}
- TcpStreamTracker::TcpStates get_tcp_state() const
+ TcpStreamTracker::TcpState get_tcp_state() const
{
return tcp_state;
}
- void set_tcp_state(TcpStreamTracker::TcpStates tcp_state)
- {
- this->tcp_state = tcp_state;
- }
-
- void set_tcp_event(TcpStreamTracker::TcpEvents tcp_event)
+ void set_tcp_event(TcpStreamTracker::TcpEvent tcp_event)
{
this->tcp_event = tcp_event;
}
}
protected:
+ virtual void do_pre_sm_packet_actions(TcpSegmentDescriptor&);
+ virtual void do_post_sm_packet_actions(TcpSegmentDescriptor&);
+
virtual bool syn_sent(TcpSegmentDescriptor&, TcpStreamTracker&);
virtual bool syn_recv(TcpSegmentDescriptor&, TcpStreamTracker&);
virtual bool syn_ack_sent(TcpSegmentDescriptor&, TcpStreamTracker&);
virtual bool rst_sent(TcpSegmentDescriptor&, TcpStreamTracker&);
virtual bool rst_recv(TcpSegmentDescriptor&, TcpStreamTracker&);
- bool default_state_action(TcpSegmentDescriptor&, TcpStreamTracker&, const char*);
+ bool default_state_action(TcpSegmentDescriptor&, TcpStreamTracker&);
const TcpStateMachine* tsm;
- TcpStreamTracker::TcpStates tcp_state;
- TcpStreamTracker::TcpEvents tcp_event;
+ TcpStreamTracker::TcpState tcp_state;
+ TcpStreamTracker::TcpEvent tcp_event = TcpStreamTracker::TCP_MAX_EVENTS;
};
#endif
TcpStateMachine::TcpStateMachine(void)
{
+ TcpStreamTracker::TcpState s;
// register a default handler for each state...
- for ( TcpStreamTracker::TcpStates state = TcpStreamTracker::TCP_LISTEN; state <
- TcpStreamTracker::TCP_MAX_STATES; state++ )
+ for ( s = TcpStreamTracker::TCP_LISTEN; s < TcpStreamTracker::TCP_MAX_STATES; s++ )
{
- tcp_state_handlers[ state ] = nullptr;
- new TcpStateHandler(state, *this);
+ tcp_state_handlers[ s ] = nullptr;
+ new TcpStateHandler(s, *this);
}
}
// TODO Auto-generated destructor stub
}
-void TcpStateMachine::register_state_handler(TcpStreamTracker::TcpStates state,
+void TcpStateMachine::register_state_handler(TcpStreamTracker::TcpState state,
TcpStateHandler& handler)
{
if ( tcp_state_handlers[ state ] != nullptr )
TcpStateMachine(void);
virtual ~TcpStateMachine(void);
- virtual void register_state_handler(TcpStreamTracker::TcpStates, TcpStateHandler&);
+ virtual void register_state_handler(TcpStreamTracker::TcpState, TcpStateHandler&);
virtual bool eval(TcpSegmentDescriptor&, TcpStreamTracker&);
private:
"TCP_RST_RECV_EVENT" };
TcpStreamTracker::TcpStreamTracker(bool client) :
- client_tracker(client), require_3whs(false), snd_una(0), snd_nxt(0), snd_wnd(0), snd_up(0),
- snd_wl1(0), snd_wl2(0), iss(0), rcv_nxt(0), rcv_wnd(0), rcv_up(0), irs(0),
- ts_last_packet(0), ts_last(0), wscale(0), mss(0), flags(0)
+ client_tracker(client), tcp_state(client ? TCP_STATE_NONE : TCP_LISTEN)
{
- memset(mac_addr, '0', sizeof(mac_addr));
- tcp_state = TCP_STATE_NONE;
- tcp_event = TCP_MAX_EVENTS;
}
TcpStreamTracker::~TcpStreamTracker()
// TODO Auto-generated destructor stub
}
-void TcpStreamTracker::set_tcp_event(TcpSegmentDescriptor& tsd)
+TcpStreamTracker::TcpEvent TcpStreamTracker::set_tcp_event(TcpSegmentDescriptor& tsd)
{
bool talker;
const tcp::TCPHdr* tcph = tsd.get_tcph();
if ( talker )
{
+ // talker events
if ( tcph->is_syn_only() )
tcp_event = TCP_SYN_SENT_EVENT;
else if ( tcph->is_syn_ack() )
tcp_event = TCP_SYN_ACK_SENT_EVENT;
+ else if ( tcph->is_rst() )
+ tcp_event = TCP_RST_SENT_EVENT;
+ else if ( tcph->is_fin( ) )
+ tcp_event = TCP_FIN_SENT_EVENT;
else if ( tcph->is_ack() || tcph->is_psh() )
{
- if ( tsd.get_data_len() > 0 )
+ if ( tsd.get_seg_len() > 0 )
tcp_event = TCP_DATA_SEG_SENT_EVENT;
else
tcp_event = TCP_ACK_SENT_EVENT;
}
- else if ( tcph->is_rst() )
- tcp_event = TCP_RST_SENT_EVENT;
- else if ( tcph->is_fin( ) )
- tcp_event = TCP_FIN_SENT_EVENT;
// else if( tsd.get_data_len() > 0 ) // FIXIT - No flags set, how do we handle this?
// tcp_event = TCP_DATA_SEG_SENT_EVENT;
else
tcp_event = TCP_ACK_SENT_EVENT;
}
- else // server is listening events
+ else
{
+ // listener events
if ( tcph->is_syn_only() )
tcp_event = TCP_SYN_RECV_EVENT;
else if ( tcph->is_syn_ack() )
tcp_event = TCP_SYN_ACK_RECV_EVENT;
+ else if ( tcph->is_rst() )
+ tcp_event = TCP_RST_RECV_EVENT;
+ else if ( tcph->is_fin( ) )
+ tcp_event = TCP_FIN_RECV_EVENT;
else if ( tcph->is_ack() || tcph->is_psh() )
{
- if ( tsd.get_data_len() > 0 )
+ if ( tsd.get_seg_len() > 0 )
tcp_event = TCP_DATA_SEG_RECV_EVENT;
else
tcp_event = TCP_ACK_RECV_EVENT;
}
- else if ( tcph->is_rst() )
- tcp_event = TCP_RST_RECV_EVENT;
- else if ( tcph->is_fin( ) )
- tcp_event = TCP_FIN_RECV_EVENT;
-// else if( tsd.get_data_len() > 0 ) // FIXIT - No flags set, how do we handle this?
+// else if( tsd.get_data_len() > 0 ) // FIXIT - No flags set, how do we handle this?
// tcp_event = TCP_DATA_SEG_RECV_EVENT;
else
tcp_event = TCP_ACK_RECV_EVENT;
}
+
+ return tcp_event;
}
// Use a for loop and byte comparison, which has proven to be faster on pipelined architectures
// there is no guarantee of memory alignment (and thus performance issues similar to memcmp).
bool TcpStreamTracker::compare_mac_addresses(const uint8_t eth_addr[])
{
+ if ( !mac_addr_valid )
+ return true;
+
for ( int i = 0; i < 6; ++i )
if ( mac_addr[i] != eth_addr[i] )
return false;
int i;
/* Not Ethernet based, nothing to do */
- if ( !( tsd.get_pkt()->proto_bits & PROTO_BIT__ETH ) )
- return;
-
- // if flag is set, guaranteed to have an eth layer
- const eth::EtherHdr* eh = layer::get_eth_layer(tsd.get_pkt() );
-
- if ( direction == FROM_CLIENT )
+ if ( tsd.get_pkt()->is_eth() )
{
- if ( client_tracker )
- for ( i = 0; i < 6; i++ )
- mac_addr[i] = eh->ether_src[i];
- else
- for ( i = 0; i < 6; i++ )
- mac_addr[i] = eh->ether_dst[i];
- }
- else
- {
- if ( client_tracker )
- for ( i = 0; i < 6; i++ )
- mac_addr[i] = eh->ether_dst[i];
+ // if flag is set, guaranteed to have an eth layer
+ const eth::EtherHdr* eh = layer::get_eth_layer(tsd.get_pkt() );
+
+ if ( direction == FROM_CLIENT )
+ {
+ if ( client_tracker )
+ for ( i = 0; i < 6; i++ )
+ mac_addr[i] = eh->ether_src[i];
+ else
+ for ( i = 0; i < 6; i++ )
+ mac_addr[i] = eh->ether_dst[i];
+ }
else
- for ( i = 0; i < 6; i++ )
- mac_addr[i] = eh->ether_src[i];
+ {
+ if ( client_tracker )
+ for ( i = 0; i < 6; i++ )
+ mac_addr[i] = eh->ether_dst[i];
+ else
+ for ( i = 0; i < 6; i++ )
+ mac_addr[i] = eh->ether_src[i];
+ }
+
+ mac_addr_valid = true;
}
+
+ mac_addr_valid = true;
}
class TcpStreamTracker
{
public:
- enum TcpStates
+ enum TcpState
{
TCP_LISTEN,
TCP_SYN_SENT,
TCP_MAX_STATES
};
- enum TcpEvents
+ enum TcpEvent
{
TCP_SYN_SENT_EVENT,
TCP_SYN_RECV_EVENT,
return client_tracker;
}
- bool is_3whs_required() const
+ bool is_server_tracker() const
{
- return require_3whs;
+ return !client_tracker;
}
- void set_require_3whs(bool require3_whs)
- {
- this->require_3whs = require3_whs;
- }
-
- TcpStates get_tcp_state() const
+ TcpState get_tcp_state() const
{
return tcp_state;
}
- void set_tcp_state(TcpStates tcp_state)
+ void set_tcp_state(TcpState tcp_state)
{
this->tcp_state = tcp_state;
}
- TcpEvents get_tcp_event() const
+ TcpEvent get_tcp_event() const
{
return tcp_event;
}
- void set_tcp_event(TcpSegmentDescriptor& tsd);
+ TcpEvent set_tcp_event(TcpSegmentDescriptor& tsd);
- void set_tcp_event(TcpEvents tcp_event)
+ void set_tcp_event(TcpEvent tcp_event)
{
this->tcp_event = tcp_event;
}
bool is_ack_valid(uint32_t cur)
{
+ // FIXIT - do we need this check? we've alwasy seen something by the time
+ // we get here
/* If we haven't seen anything, ie, low & high are 0, return true */
if ( ( snd_una == 0 ) && ( snd_una == snd_nxt ) )
return 1;
// ack number must ack syn
bool is_rst_valid_in_syn_sent(TcpSegmentDescriptor& tsd)
{
- return tsd.get_ack() == snd_una;
+ return tsd.get_seg_ack() == snd_una;
+ }
+
+ uint32_t get_ts_last() const
+ {
+ return ts_last;
+ }
+
+ void set_ts_last(uint32_t ts_last)
+ {
+ this->ts_last = ts_last;
+ }
+
+ uint8_t get_tf_flags() const
+ {
+ return tf_flags;
+ }
+
+ void set_tf_flags(uint16_t flags)
+ {
+ this->tf_flags |= flags;
+ }
+
+ void clear_tf_flags(uint16_t flags)
+ {
+ this->tf_flags &= ~flags;
+ }
+
+ uint16_t get_wscale() const
+ {
+ return wscale;
+ }
+
+ void set_wscale(uint16_t wscale)
+ {
+ this->wscale = wscale;
+ }
+
+ uint16_t get_mss() const
+ {
+ return mss;
+ }
+
+ void set_mss(uint16_t mss)
+ {
+ this->mss = mss;
}
void cache_mac_address(TcpSegmentDescriptor& tsd, uint8_t direction);
protected:
bool client_tracker;
- bool require_3whs;
+ TcpState tcp_state;
+ TcpEvent tcp_event = TCP_MAX_EVENTS;
+ bool require_3whs = false;
+
+ uint32_t snd_una = 0; // SND.UNA - send unacknowledged
+ uint32_t snd_nxt = 0; // SND.NXT - send next
+ uint32_t snd_wnd = 0; // SND.WND - send window
+ uint16_t snd_up = 0; // SND.UP - send urgent pointer
+ uint32_t snd_wl1 = 0; // SND.WL1 - segment sequence number used for last window update
+ uint32_t snd_wl2 = 0; // SND.WL2 - segment acknowledgment number used for last window update
+ uint32_t iss = 0; // ISS - initial send sequence number
- uint32_t snd_una; // SND.UNA - send unacknowledged
- uint32_t snd_nxt; // SND.NXT - send next
- uint32_t snd_wnd; // SND.WND - send window
- uint16_t snd_up; // SND.UP - send urgent pointer
- uint32_t snd_wl1; // SND.WL1 - segment sequence number used for last window update
- uint32_t snd_wl2; // SND.WL2 - segment acknowledgment number used for last window update
- uint32_t iss; // ISS - initial send sequence number
+ uint32_t rcv_nxt = 0; // RCV.NXT - receive next
+ uint32_t rcv_wnd = 0; // RCV.WND - receive window
+ uint16_t rcv_up = 0; // RCV.UP - receive urgent pointer
+ uint32_t irs = 0; // IRS - initial receive sequence number
- uint32_t rcv_nxt; // RCV.NXT - receive next
- uint32_t rcv_wnd; // RCV.WND - receive window
- uint16_t rcv_up; // RCV.UP - receive urgent pointer
- uint32_t irs; // IRS - initial receive sequence number
+// FIXIT - make these non-public
- uint32_t ts_last_packet; // timestamp of last packet we got
+public:
+ uint32_t r_nxt_ack = 0; /* next expected ack from remote side */
+ uint32_t r_win_base = 0; /* remote side window base sequence number
+ * (i.e. the last ack we got) */
+
+protected:
+ uint32_t ts_last_packet = 0;
+ uint32_t ts_last = 0; /* last timestamp (for PAWS) */
+ uint16_t tf_flags = 0;
- // FIXIT - make this protected
+ uint8_t mac_addr[6] = {};
+ bool mac_addr_valid = false;
+
+ // FIXIT - make this protected...
public:
- uint32_t ts_last; /* last timestamp (for PAWS) */
uint16_t wscale; /* window scale setting */
uint16_t mss; /* max segment size */
-
- uint8_t mac_addr[6];
- uint8_t flags; /* bitmap flags (TF_xxx) */
-
-protected:
- TcpStates tcp_state;
- TcpEvents tcp_event;
};
-inline TcpStreamTracker::TcpStates& operator++(TcpStreamTracker::TcpStates& state, int) // <---
- // note --
- // must be
- // a reference
+// <--- note -- the 'state' parameter must be a reference
+inline TcpStreamTracker::TcpState& operator++(TcpStreamTracker::TcpState& state, int)
{
const int i = static_cast<int>(state);
- state = static_cast<TcpStreamTracker::TcpStates>((i + 1) % ( TcpStreamTracker::TCP_MAX_EVENTS +
+ state = static_cast<TcpStreamTracker::TcpState>((i + 1) % ( TcpStreamTracker::TCP_MAX_EVENTS +
1 ) );
return state;
}
{
DebugFormat(DEBUG_STREAM_STATE, "bad segment: overlap with invalid sequence number"
"(seq: %X seq_end: %X overlap: %lu\n", seq, seq_end, overlap);
- session->tel->EventBadSegment();
+ session->tel.EventBadSegment();
inc_tcp_discards();
return STREAM_INSERT_ANOMALY;
}
DebugFormat(DEBUG_STREAM_STATE, "left overlap %d\n", overlap);
- len = tsd->get_pkt()->dsize;
+ len = tsd->get_seg_len();
overlap = left->seq + left->payload_size - seq;
if ( overlap > 0 )
{
overlap_count++;
DebugMessage(DEBUG_STREAM_STATE, "left overlap, honoring old data\n");
- if ( SEQ_LT(left->seq, tsd->get_seq() ) && SEQ_GT(left->seq + left->payload_size,
- tsd->get_seq() + tsd->get_pkt()->dsize) )
+ if ( SEQ_LT(left->seq, tsd->get_seg_seq() ) && SEQ_GT(left->seq + left->payload_size,
+ tsd->get_seg_seq() + tsd->get_seg_len() ) )
{
if (tcp_ips_data == NORM_MODE_ON)
{
- unsigned offset = tsd->get_seq() - left->seq;
+ unsigned offset = tsd->get_seg_seq() - left->seq;
memcpy( ( uint8_t* )tsd->get_pkt()->data, left->payload + offset,
- tsd->get_pkt()->dsize);
+ tsd->get_seg_len() );
tsd->get_pkt()->packet_flags |= PKT_MODIFIED;
}
tcp_norm_stats[PC_TCP_IPS_DATA][tcp_ips_data]++;
}
- else if ( SEQ_LT(left->seq, tsd->get_seq() ) )
+ else if ( SEQ_LT(left->seq, tsd->get_seg_seq() ) )
{
if ( tcp_ips_data == NORM_MODE_ON )
{
- unsigned offset = tsd->get_seq() - left->seq;
- unsigned length = left->seq + left->payload_size - tsd->get_seq();
+ unsigned offset = tsd->get_seg_seq() - left->seq;
+ unsigned length = left->seq + left->payload_size - tsd->get_seg_seq();
memcpy( ( uint8_t* )tsd->get_pkt()->data, left->payload + offset, length);
tsd->get_pkt()->packet_flags |= PKT_MODIFIED;
}
DebugFormat(DEBUG_STREAM_STATE, "left overlap %d\n", overlap);
- len = tsd->get_pkt()->dsize;
+ len = tsd->get_seg_len();
overlap = left->seq + left->payload_size - seq;
if ( overlap > 0 )
{
DebugFormat(DEBUG_STREAM_STATE, "left overlap %d\n", overlap);
- len = tsd->get_pkt()->dsize;
+ len = tsd->get_seg_len();
overlap = left->seq + left->payload_size - seq;
if ( overlap > 0 )
{
{
if (tcp_ips_data == NORM_MODE_ON)
{
- unsigned offset = right->seq - tsd->get_seq();
- unsigned length = tsd->get_seq() + tsd->get_pkt()->dsize - right->seq;
+ unsigned offset = right->seq - tsd->get_seg_seq();
+ unsigned length = tsd->get_seg_seq() + tsd->get_seg_len() - right->seq;
memcpy( ( uint8_t* )tsd->get_pkt()->data + offset, right->payload, length);
tsd->get_pkt()->packet_flags |= PKT_MODIFIED;
}
if ( tcp_ips_data == NORM_MODE_ON )
{
- unsigned offset = right->seq - tsd->get_seq();
+ unsigned offset = right->seq - tsd->get_seg_seq();
memcpy( ( uint8_t* )tsd->get_pkt()->data + offset, right->payload, right->payload_size);
tsd->get_pkt()->packet_flags |= PKT_MODIFIED;
}
/* insert this one, and see if we need to chunk it up
Adjust slide so that is correct relative to orig seq */
- slide = seq - tsd->get_seq();
+ slide = seq - tsd->get_seg_seq();
int rc = add_reassembly_segment(*tsd, len, slide, trunc_len, seq, left);
if ( rc != STREAM_INSERT_OK )
return rc;
protected:
SegmentOverlapEditor(void)
- : session(nullptr), reassembly_policy(ReassemblyPolicy::OS_DEFAULT), seglist_base_seq(0),
- seg_count(0), seg_bytes_total(0), seg_bytes_logical(0), total_bytes_queued(0),
- total_segs_queued(0), overlap_count(0),
- tsd(nullptr), left(nullptr), right(nullptr), seq(0), seq_end(0),
- len(0), overlap(0), slide(0), trunc_len(0), rdata(nullptr),
- rsize(0), rseq(0), keep_segment(true)
{
tcp_ips_data = Normalize_GetMode(NORM_TCP_IPS);
}
this->tsd = &tsd;
this->left = left;
this->right = right;
- seq = tsd.get_seq();
+ seq = tsd.get_seg_seq();
seq_end = tsd.get_end_seq();
- len = tsd.get_data_len();
+ len = tsd.get_seg_len();
overlap = 0;
slide = 0;
trunc_len = 0;
rdata = tsd.get_pkt()->data;
- rsize = tsd.get_data_len();
- rseq = tsd.get_seq();
+ rsize = tsd.get_seg_len();
+ rseq = tsd.get_seg_seq();
keep_segment = true;
}
virtual int insert_left_overlap(void) = 0;
virtual void insert_right_overlap(void) = 0;
virtual int insert_full_overlap(void) = 0;
- virtual int add_reassembly_segment(TcpSegmentDescriptor&, int16_t len, uint32_t slide, uint32_t
- trunc,
- uint32_t seq, TcpSegmentNode*) = 0;
- virtual int dup_reassembly_segment(Packet* p, TcpSegmentNode* left, TcpSegmentNode** retSeg) =
- 0;
- virtual int delete_reassembly_segment(TcpSegmentNode* seg) = 0;
-
+ virtual int add_reassembly_segment(TcpSegmentDescriptor&, int16_t, uint32_t, uint32_t, uint32_t, TcpSegmentNode*) = 0;
+ virtual int dup_reassembly_segment(Packet*, TcpSegmentNode*, TcpSegmentNode**) = 0;
+ virtual int delete_reassembly_segment(TcpSegmentNode*) = 0;
virtual void print(void);
- TcpSession* session;
- ReassemblyPolicy reassembly_policy;
+ TcpSession* session = nullptr;
+ ReassemblyPolicy reassembly_policy = ReassemblyPolicy::OS_DEFAULT;
NormMode tcp_ips_data;
TcpSegmentList seglist;
- uint32_t seglist_base_seq; /* seq of first queued segment */
- uint32_t seg_count; /* number of current queued segments */
- uint32_t seg_bytes_total; /* total bytes currently queued */
- uint32_t seg_bytes_logical; /* logical bytes queued (total - overlaps) */
- uint32_t total_bytes_queued; /* total bytes queued (life of session) */
- uint32_t total_segs_queued; /* number of segments queued (life) */
- uint32_t overlap_count; /* overlaps encountered */
-
- TcpSegmentDescriptor* tsd;
- TcpSegmentNode* left;
- TcpSegmentNode* right;
- uint32_t seq;
- uint32_t seq_end;
- uint16_t len;
- int32_t overlap;
- int32_t slide;
- int32_t trunc_len;
- const uint8_t* rdata;
- uint16_t rsize;
- uint32_t rseq;
- bool keep_segment;
+ uint32_t seglist_base_seq = 0; /* seq of first queued segment */
+ uint32_t seg_count = 0; /* number of current queued segments */
+ uint32_t seg_bytes_total = 0; /* total bytes currently queued */
+ uint32_t seg_bytes_logical = 0; /* logical bytes queued (total - overlaps) */
+ uint32_t total_bytes_queued = 0; /* total bytes queued (life of session) */
+ uint32_t total_segs_queued = 0; /* number of segments queued (life) */
+ uint32_t overlap_count = 0; /* overlaps encountered */
+
+ TcpSegmentDescriptor* tsd = nullptr;
+ TcpSegmentNode* left = nullptr;
+ TcpSegmentNode* right = nullptr;
+ const uint8_t* rdata = nullptr;
+ uint32_t seq = 0;
+ uint32_t seq_end = 0;
+ uint16_t len = 0;
+ int32_t overlap = 0;
+ int32_t slide = 0;
+ int32_t trunc_len = 0;
+ uint16_t rsize = 0;
+ uint32_t rseq = 0;
+ bool keep_segment = true;
};
#endif
// force relative ack to zero if not conveyed
if (flags[1] != 'A')
- rxd = ntohl(h->th_ack);
+ rxd = h->ack(); // FIXIT - SYN's seen with ack > 0 and ACK flag not set...
if (p->packet_flags & PKT_STREAM_ORDER_OK)
order = " (ins)";
else if (p->packet_flags & PKT_STREAM_ORDER_BAD)
order = " (oos)";
+ uint32_t rseq = ( txd ) ? h->seq() - txd : h->seq();
+ uint32_t rack = ( rxd ) ? h->ack() - rxd : h->ack();
fprintf(stdout, "\n" FMTu64("-3") " %s=0x%02x Seq=%-4u Ack=%-4u Win=%-4u Len=%-4u%s\n",
//"\n" FMTu64("-3") " %s=0x%02x Seq=%-4u Ack=%-4u Win=%-4u Len=%-4u End=%-4u%s\n",
- pc.total_from_daq, flags, h->th_flags, ntohl(h->th_seq) - txd, ntohl(h->th_ack) - rxd,
- ntohs(h->th_win), p->dsize, order);
+ pc.total_from_daq, flags, h->th_flags, rseq, rack, h->win(), p->dsize, order);
}
static inline void TraceSession(const Flow* lws)
static inline void TraceState(const TcpTracker* a, const TcpTracker* b, const char* s)
{
- uint32_t why = a->get_snd_nxt() ? LCL(a, get_snd_nxt) : 0;
+ uint32_t ua = a->get_snd_una() ? LCL(a, get_snd_una) : 0;
+ uint32_t ns = a->get_snd_nxt() ? LCL(a, get_snd_nxt) : 0;
- fprintf(stdout, " %s ST=%s:%02x UA=%-4u NS=%-4u LW=%-5u RN=%-4u RW=%-4u ", s,
- statext[a->get_tcp_state()], a->s_mgr.sub_state, LCL(a, get_snd_una), why,
- a->get_snd_wnd( ), RMT(a, r_nxt_ack, b), RMT(a, r_win_base, b));
+ fprintf(stdout,
+ " %s ST=%s:%02x UA=%-4u NS=%-4u LW=%-5u RN=%-4u RW=%-4u ISS=%-4u IRS=%-4u ",
+ s, statext[a->get_tcp_state()], a->s_mgr.sub_state, ua, ns, a->get_snd_wnd( ),
+ RMT(a, r_nxt_ack, b), RMT(a, r_win_base, b), a->get_iss(), a->get_irs());
if ( a->s_mgr.state_queue != TcpStreamTracker::TCP_STATE_NONE )
fprintf(stdout, "QS=%s QC=0x%02x QA=%-4u", statext[a->s_mgr.state_queue],
sdir = "SRV>";
cdir = "CLI<";
- if (ssn->tcp_init)
- {
- txd = srv->get_iss();
- rxd = cli->get_iss();
- }
+ txd = srv->get_iss();
+ rxd = srv->get_irs();
}
else if (p->packet_flags & PKT_FROM_CLIENT)
{
sdir = "SRV<";
cdir = "CLI>";
- if (ssn->tcp_init)
- {
- txd = cli->get_iss();
- rxd = srv->get_iss();
- }
+ txd = cli->get_iss();
+ rxd = cli->get_irs();
}
TraceEvent(p, tsd, txd, rxd);
- if (!ssn->tcp_init)
- return;
-
if (lws && ssn->lws_init)
TraceSession(lws);
#include "main/snort_debug.h"
#include "protocols/packet.h"
-#if 0
-/* TCP states */
-#define TCP_STATE_NONE 0
-#define TCP_STATE_LISTEN 1
-#define TCP_STATE_SYN_RCVD 2
-#define TCP_STATE_SYN_SENT 3
-#define TCP_STATE_ESTABLISHED 4
-#define TCP_STATE_CLOSE_WAIT 5
-#define TCP_STATE_LAST_ACK 6
-#define TCP_STATE_FIN_WAIT_1 7
-#define TCP_STATE_CLOSING 8
-#define TCP_STATE_FIN_WAIT_2 9
-#define TCP_STATE_TIME_WAIT 10
-#define TCP_STATE_CLOSED 11
-#endif
-
/* actions */
#define ACTION_NOTHING 0x00000000
#define ACTION_FLUSH_SENDER_STREAM 0x00000001
#define PAWS_WINDOW 60
#define PAWS_24DAYS 2073600 /* 24 days in seconds */
+#define SUB_STATE_NONE 0x00
#define SUB_SYN_SENT 0x01
#define SUB_ACK_SENT 0x02
#define SUB_SETUP_OK 0x03
STREAM_FLPOLICY_ON_DATA, /* protocol aware ips */
};
-#if 0
-struct TcpDataBlock
-{
- Packet* pkt;
- uint32_t seq;
- uint32_t ack;
- uint32_t win;
- uint32_t end_seq;
- uint32_t ts;
-};
-#endif
//#define DEBUG_STREAM_EX
#ifdef DEBUG_STREAM_EX
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//--------------------------------------------------------------------------
-// tcp_events.cc author davis mcpherson <davmcphe@@cisco.com>
+// tcp_event_logger.cc author davis mcpherson <davmcphe@@cisco.com>
// Created on: Jul 30, 2015
#include "main/snort_config.h"
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//--------------------------------------------------------------------------
-// tcp_events.h author davis mcpherson <davmcphe@@cisco.com>
+// tcp_event_logger.h author davis mcpherson <davmcphe@@cisco.com>
// Created on: Jul 30, 2015
#ifndef TCP_EVENT_LOGGER_H
}
TcpNormalizer::TcpNormalizer(StreamPolicy os_policy, TcpSession* session, TcpTracker* tracker) :
- os_policy(os_policy), session(session), tracker(tracker),
- peer_tracker(nullptr)
+ os_policy(os_policy), session(session), tracker(tracker)
{
tcp_ips_enabled = Normalize_IsEnabled(NORM_TCP_IPS);
trim_syn = Normalize_GetMode(NORM_TCP_TRIM_SYN);
strip_ecn = Normalize_GetMode(NORM_TCP_ECN_STR);
tcp_block = Normalize_GetMode(NORM_TCP_BLOCK);
opt_block = Normalize_GetMode(NORM_TCP_OPT);
-
- paws_ts_fudge = 0;
- paws_drop_zero_ts = true;
}
const PegInfo* TcpNormalizer::get_normalization_pegs()
{
if (mode == NORM_MODE_ON)
{
- uint16_t fat = tsd.get_pkt()->dsize - max;
- tsd.get_pkt()->dsize = max;
+ uint16_t fat = tsd.get_seg_len() - max;
+ tsd.set_seg_len(max);
tsd.get_pkt()->packet_flags |= (PKT_MODIFIED | PKT_RESIZED);
tsd.set_end_seq(tsd.get_end_seq() - fat);
}
tcp::TcpOptIterator iter(tsd.get_tcph(), tsd.get_pkt() );
// using const because non-const is not supported
- for (const tcp::TcpOption& opt : iter)
+ for ( const tcp::TcpOption& opt : iter )
{
- if (opt.code == tcp::TcpOptCode::TIMESTAMP)
+ if ( opt.code == tcp::TcpOptCode::TIMESTAMP )
{
bool stripped = false;
if (!stripped)
{
- tsd.set_ts(EXTRACT_32BITS(opt.data) );
+ tsd.set_ts(extract_32bits(opt.data) );
DebugFormat(DEBUG_STREAM_STATE, "Found timestamp %lu\n", tsd.get_ts());
return TF_TSTAMP;
}
{
DebugFormat(DEBUG_STREAM_STATE,
"Checking end_seq (%X) > r_win_base (%X) && seq (%X) < r_nxt_ack(%X)\n",
- tsd.get_end_seq(), tracker->r_win_base, tsd.get_seq(), tracker->r_nxt_ack +
+ tsd.get_end_seq(), tracker->r_win_base, tsd.get_seg_seq(), tracker->r_nxt_ack +
get_stream_window(tsd));
- if (SEQ_GEQ(tsd.get_seq(), tracker->r_nxt_ack))
+ if ( ( tracker->r_nxt_ack == 0 ) || SEQ_GEQ(tsd.get_seg_seq(), tracker->r_nxt_ack) )
{
DebugMessage(DEBUG_STREAM_STATE, "rst is valid seq (>= next seq)!\n");
return true;
{
DebugFormat(DEBUG_STREAM_STATE,
"Checking end_seq (%X) > r_win_base (%X) && seq (%X) < r_nxt_ack(%X)\n",
- tsd.get_end_seq(), tracker->r_win_base, tsd.get_seq(), tracker->r_nxt_ack +
+ tsd.get_end_seq(), tracker->r_win_base, tsd.get_seg_seq(), tracker->r_nxt_ack +
get_stream_window(tsd));
- if (SEQ_GEQ(tsd.get_end_seq(), tracker->r_win_base))
+ // FIXIT - check for r_win_base == 0 is hack for uninitialized r_win_base, fix this
+ if ( tracker->r_win_base == 0 )
+ return true;
+
+ if ( SEQ_GEQ(tsd.get_end_seq(), tracker->r_win_base))
{
// reset must be admitted when window closed
- if (SEQ_LEQ(tsd.get_seq(), tracker->r_win_base + get_stream_window(tsd)))
+ if (SEQ_LEQ(tsd.get_seg_seq(), tracker->r_win_base + get_stream_window(tsd)))
{
DebugMessage(DEBUG_STREAM_STATE, "rst is valid seq (within window)!\n");
return true;
{
DebugFormat(DEBUG_STREAM_STATE,
"Checking end_seq (%X) > r_win_base (%X) && seq (%X) < r_nxt_ack(%X)\n",
- tsd.get_end_seq(), tracker->r_win_base, tsd.get_seq(), tracker->r_nxt_ack +
+ tsd.get_end_seq(), tracker->r_win_base, tsd.get_seg_seq(), tracker->r_nxt_ack +
get_stream_window(tsd));
- if (SEQ_EQ(tsd.get_seq(), tracker->r_nxt_ack))
+ // FIXIT - check for r_nxt_ack == 0 is hack for uninitialized r_nxt_ack, fix this
+ if ( ( tracker->r_nxt_ack == 0 ) || SEQ_EQ(tsd.get_seg_seq(), tracker->r_nxt_ack) )
{
DebugMessage(DEBUG_STREAM_STATE, "rst is valid seq (next seq)!\n");
return true;
int TcpNormalizer::validate_paws_timestamp(TcpSegmentDescriptor& tsd)
{
- if ( ( (int)( ( tsd.get_ts() - peer_tracker->ts_last ) + paws_ts_fudge ) ) < 0 )
+ if ( ( (int)( ( tsd.get_ts() - peer_tracker->get_ts_last() ) + paws_ts_fudge ) ) < 0 )
{
DebugMessage(DEBUG_STREAM_STATE, "Packet outside PAWS window, dropping\n");
/* bail, we've got a packet outside the PAWS window! */
//inc_tcp_discards();
- ( ( TcpSession* )tsd.get_flow()->session )->tel->set_tcp_event(EVENT_BAD_TIMESTAMP);
+ ( ( TcpSession* )tsd.get_flow()->session )->tel.set_tcp_event(EVENT_BAD_TIMESTAMP);
packet_dropper(tsd, NORM_TCP_OPT);
return ACTION_BAD_PKT;
}
- else if ( ( peer_tracker->ts_last != 0 )
+ else if ( ( peer_tracker->get_ts_last() != 0 )
&& ( ( uint32_t )tsd.get_pkt()->pkth->ts.tv_sec > peer_tracker->get_ts_last_packet() +
PAWS_24DAYS ) )
{
"packet PAWS timestamp way too far ahead of last packet %d %d...\n",
tsd.get_pkt()->pkth->ts.tv_sec, peer_tracker->get_ts_last_packet() );
//inc_tcp_discards();
- ( ( TcpSession* )tsd.get_flow()->session )->tel->set_tcp_event(EVENT_BAD_TIMESTAMP);
+ ( ( TcpSession* )tsd.get_flow()->session )->tel.set_tcp_event(EVENT_BAD_TIMESTAMP);
packet_dropper(tsd, NORM_TCP_OPT);
return ACTION_BAD_PKT;
}
return true;
}
-int TcpNormalizer::validate_paws(TcpSegmentDescriptor& tsd, int* got_ts)
+int TcpNormalizer::validate_paws(TcpSegmentDescriptor& tsd)
{
- *got_ts = get_tcp_timestamp(tsd, false);
- if ( *got_ts )
+ tcp_ts_flags = get_tcp_timestamp(tsd, false);
+ if ( tcp_ts_flags )
{
bool check_ts = is_paws_ts_checked_required(tsd);
// with the missing timestamp. Log an alert, but continue to process the packet
DebugMessage(DEBUG_STREAM_STATE,
"packet no timestamp, had one earlier from this side...ok for now...\n");
- ( ( TcpSession* )tsd.get_flow()->session )->tel->set_tcp_event(EVENT_NO_TIMESTAMP);
+ ( ( TcpSession* )tsd.get_flow()->session )->tel.set_tcp_event(EVENT_NO_TIMESTAMP);
/* Ignore the timestamp for this first packet, next one will checked. */
if ( session->config->policy == StreamPolicy::OS_SOLARIS )
- tracker->flags &= ~TF_TSTAMP;
+ tracker->clear_tf_flags(TF_TSTAMP);
packet_dropper(tsd, NORM_TCP_OPT);
return ACTION_NOTHING;
}
}
-int TcpNormalizer::handle_paws_no_timestamps(TcpSegmentDescriptor& tsd, int* got_ts)
+int TcpNormalizer::handle_paws_no_timestamps(TcpSegmentDescriptor& tsd)
{
// if we are not handling timestamps, and this isn't a syn (only), and we have seen a
// valid 3way setup, then we strip (nop) the timestamp option. this includes the cases
int strip = ( SetupOK(peer_tracker) && SetupOK(tracker) );
DebugMessage(DEBUG_STREAM_STATE, "listener not doing timestamps...\n");
- *got_ts = get_tcp_timestamp(tsd, strip);
- if (*got_ts)
+ tcp_ts_flags = get_tcp_timestamp(tsd, strip);
+ if (tcp_ts_flags)
{
- if (!(peer_tracker->flags & TF_TSTAMP))
+ if (!(peer_tracker->get_tf_flags() & TF_TSTAMP))
{
// SYN skipped, may have missed talker's timestamp , so set it now.
- peer_tracker->flags |= TF_TSTAMP;
if (tsd.get_ts() == 0)
- peer_tracker->flags |= TF_TSTAMP_ZERO;
+ peer_tracker->set_tf_flags(TF_TSTAMP | TF_TSTAMP_ZERO);
+ else
+ peer_tracker->set_tf_flags(TF_TSTAMP);
}
// Only valid to test this if listener is using timestamps. Otherwise, timestamp
// in this packet is not used, regardless of its value.
- if ( ( paws_drop_zero_ts && ( tsd.get_ts() == 0 ) ) && ( tracker->flags & TF_TSTAMP ) )
+ if ( ( paws_drop_zero_ts && ( tsd.get_ts() == 0 ) ) && ( tracker->get_tf_flags() &
+ TF_TSTAMP ) )
{
DebugMessage(DEBUG_STREAM_STATE, "Packet with 0 timestamp, dropping\n");
- ( ( TcpSession* )tsd.get_flow()->session )->tel->set_tcp_event(EVENT_BAD_TIMESTAMP);
+ ( ( TcpSession* )tsd.get_flow()->session )->tel.set_tcp_event(EVENT_BAD_TIMESTAMP);
return ACTION_BAD_PKT;
}
}
return ACTION_NOTHING;
}
-int TcpNormalizer::handle_paws(TcpSegmentDescriptor& tsd, int* got_ts)
+int TcpNormalizer::handle_paws(TcpSegmentDescriptor& tsd)
{
if ( tsd.get_tcph()->is_rst() )
return ACTION_NOTHING;
}
#endif
- if ((peer_tracker->flags & TF_TSTAMP) && (tracker->flags & TF_TSTAMP))
+ if ((peer_tracker->get_tf_flags() & TF_TSTAMP) && (tracker->get_tf_flags() & TF_TSTAMP))
{
DebugMessage(DEBUG_STREAM_STATE, "Checking timestamps for PAWS\n");
- return validate_paws(tsd, got_ts);
+ return validate_paws(tsd);
}
else if (tsd.get_tcph()->is_syn_only())
{
- *got_ts = get_tcp_timestamp(tsd, 0);
- if (*got_ts)
- peer_tracker->flags |= TF_TSTAMP;
+ tcp_ts_flags = get_tcp_timestamp(tsd, 0);
+ if (tcp_ts_flags)
+ peer_tracker->set_tf_flags(TF_TSTAMP);
return ACTION_NOTHING;
}
else
{
- return handle_paws_no_timestamps(tsd, got_ts);
+ return handle_paws_no_timestamps(tsd);
}
}
virtual void ecn_stripper(Packet*);
virtual uint32_t get_stream_window(TcpSegmentDescriptor&);
virtual uint32_t get_tcp_timestamp(TcpSegmentDescriptor&, bool strip);
- virtual int handle_paws(TcpSegmentDescriptor&, int*);
+ virtual int handle_paws(TcpSegmentDescriptor&);
virtual bool validate_rst(TcpSegmentDescriptor&);
virtual int handle_repeated_syn(TcpSegmentDescriptor&) = 0;
virtual uint16_t set_urg_offset(const tcp::TCPHdr* tcph, uint16_t dsize);
return tcp_ips_enabled;
}
+ bool handling_timestamps(void) const
+ {
+ return tcp_ts_flags != TF_NONE;
+ }
+
+ uint32_t get_timestamp_flags(void)
+ {
+ return tcp_ts_flags;
+ }
+
protected:
TcpNormalizer(StreamPolicy, TcpSession*, TcpTracker*);
virtual void trim_payload(TcpSegmentDescriptor&, uint32_t, NormMode, TcpPegCounts);
virtual int validate_paws_timestamp(TcpSegmentDescriptor&);
virtual bool is_paws_ts_checked_required(TcpSegmentDescriptor&);
- virtual int validate_paws(TcpSegmentDescriptor&, int*);
- virtual int handle_paws_no_timestamps(TcpSegmentDescriptor&, int*);
+ virtual int validate_paws(TcpSegmentDescriptor&);
+ virtual int handle_paws_no_timestamps(TcpSegmentDescriptor&);
StreamPolicy os_policy;
- TcpSession* session;
- TcpTracker* tracker;
- TcpTracker* peer_tracker;
+ TcpSession* session = nullptr;
+ TcpTracker* tracker = nullptr;
+ TcpTracker* peer_tracker = nullptr;
bool tcp_ips_enabled;
NormMode trim_syn;
NormMode trim_rst;
NormMode strip_ecn;
NormMode tcp_block;
NormMode opt_block;
- int32_t paws_ts_fudge;
- bool paws_drop_zero_ts;
+ int32_t paws_ts_fudge = 0;
+ bool paws_drop_zero_ts = true;
+ int tcp_ts_flags = 0;
};
#endif
{ }
bool validate_rst(TcpSegmentDescriptor&) override;
- int handle_paws(TcpSegmentDescriptor&, int*) override;
+ int handle_paws(TcpSegmentDescriptor&) override;
int handle_repeated_syn(TcpSegmentDescriptor&) override;
};
/* Windows has some strange behaviour here. If the sequence of the reset is the
* next expected sequence, it Resets. Otherwise it ignores the 2nd SYN.
*/
- if (SEQ_EQ(tsd.get_seq(), listener->r_nxt_ack))
+ if (SEQ_EQ(tsd.get_seg_seq(), listener->r_nxt_ack))
{
DebugMessage(DEBUG_STREAM_STATE,
"Got syn on established windows ssn, which causes Reset, bailing\n");
TcpSession* session)
{
/* If its not a retransmission of the actual SYN... RESET */
- if (!SEQ_EQ(tsd.get_seq(), talker->get_iss()))
+ if (!SEQ_EQ(tsd.get_seg_seq(), talker->get_iss()))
{
DebugMessage(DEBUG_STREAM_STATE,
"Got syn on established ssn, which causes Reset, bailing\n");
{
bool check_ts = true;
- if (talker->flags & TF_TSTAMP_ZERO)
+ if (talker->get_tf_flags() & TF_TSTAMP_ZERO)
{
- talker->flags &= ~TF_TSTAMP;
- listener->flags &= ~TF_TSTAMP;
+ talker->clear_tf_flags(TF_TSTAMP);
+ listener->clear_tf_flags(TF_TSTAMP);
check_ts = false;
}
{
bool check_ts = true;
- if ( talker->flags & TF_TSTAMP_ZERO )
+ if ( talker->get_tf_flags() & TF_TSTAMP_ZERO )
{
- talker->flags &= ~TF_TSTAMP_ZERO;
- if ( SEQ_EQ(listener->r_nxt_ack, tsd.get_seq() ) )
+ talker->clear_tf_flags(TF_TSTAMP_ZERO);
+ if ( SEQ_EQ(listener->r_nxt_ack, tsd.get_seg_seq() ) )
{
// Ignore timestamp for this first packet, save to check on next
- talker->ts_last = tsd.get_ts();
+ talker->set_ts_last(tsd.get_ts() );
check_ts = false;
}
}
bool TcpNormalizerHpux11::is_paws_ts_checked_required(TcpSegmentDescriptor& tsd)
{
/* HPUX 11 ignores timestamps for out of order segments */
- if ((tracker->flags & TF_MISSING_PKT) || !SEQ_EQ(tracker->r_nxt_ack, tsd.get_seq()))
+ if ((tracker->get_tf_flags() & TF_MISSING_PKT) || !SEQ_EQ(tracker->r_nxt_ack,
+ tsd.get_seg_seq()))
return false;
else
return true;
{
DebugFormat(DEBUG_STREAM_STATE,
"Proxy Normalizer - Not Valid\n end_seq (%X) > r_win_base (%X) && seq (%X) < r_nxt_ack(%X)\n",
- tsd.get_end_seq(), tracker->r_win_base, tsd.get_seq(), tracker->r_nxt_ack +
+ tsd.get_end_seq(), tracker->r_win_base, tsd.get_seg_seq(), tracker->r_nxt_ack +
get_stream_window(tsd));
}
return false;
}
-int TcpNormalizerProxy::handle_paws(TcpSegmentDescriptor&, int*)
+int TcpNormalizerProxy::handle_paws(TcpSegmentDescriptor&)
{
return ACTION_NOTHING;
}
bool TcpReassembler::is_segment_fasttrack(TcpSegmentNode* tail, TcpSegmentDescriptor& tsd)
{
- DebugFormat(DEBUG_STREAM_STATE, "Checking seq for fast track: %X > %X\n", tsd.get_seq(),
+ DebugFormat(DEBUG_STREAM_STATE, "Checking seq for fast track: %X > %X\n", tsd.get_seg_seq(),
tail->seq + tail->payload_size);
- if ( SEQ_EQ(tsd.get_seq(), tail->seq + tail->payload_size) )
+ if ( SEQ_EQ(tsd.get_seg_seq(), tail->seq + tail->payload_size) )
return true;
return false;
}
// FIXIT-L don't allocate overlapped part
- tsn = TcpSegmentNode::init(tsd.get_pkt()->pkth->ts, tsd.get_pkt()->data, tsd.get_pkt()->dsize);
+ tsn = TcpSegmentNode::init(tsd);
if ( !tsn )
return STREAM_INSERT_FAILED;
else if ( TcpSegmentNode::needs_pruning() )
// FIXIT - The urgent ptr handling is broken... urg_offset is set here but currently
// not actually referenced anywhere else. In 2.9.7 the FlushStream function did reference
// this field but that code has been lost... urg ptr handling needs to be reviewed and fixed
- tsn->urg_offset = tracker->normalizer->set_urg_offset(tsd.get_tcph(), tsd.get_pkt()->dsize);
+ tsn->urg_offset = tracker->normalizer->set_urg_offset(tsd.get_tcph(), tsd.get_seg_len() );
queue_reassembly_segment(left, tsn);
seg_bytes_logical += tsn->payload_size;
total_bytes_queued += tsn->payload_size;
int TcpReassembler::dup_reassembly_segment(Packet* p, TcpSegmentNode* left,
TcpSegmentNode** retSeg)
{
- TcpSegmentNode* tsn = TcpSegmentNode::init(left->tv, left->payload, left->payload_size);
+ TcpSegmentNode* tsn = TcpSegmentNode::init(*left);
if ( !tsn )
return STREAM_INSERT_FAILED;
if ( TcpSegmentNode::needs_pruning() )
if ( !server_side )
{
- int32_t delta = last_ts - session->server->ts_last;
+ int32_t delta = last_ts - session->server->get_ts_last();
if ( delta > 0 )
- session->server->ts_last = last_ts;
+ session->server->set_ts_last(last_ts);
}
else
{
- int32_t delta = last_ts - session->client->ts_last;
+ int32_t delta = last_ts - session->client->get_ts_last();
if ( delta > 0 )
- session->client->ts_last = last_ts;
+ session->client->set_ts_last(last_ts);
}
return purged_bytes;
void TcpReassembler::show_rebuilt_packet(Packet* pkt)
{
- if ( ( session->config->flags & STREAM_CONFIG_SHOW_PACKETS )
- || ( session->config->flags & STREAM_CONFIG_SHOW_PACKETS ) )
+ if ( session->config->flags & STREAM_CONFIG_SHOW_PACKETS )
{
LogFlow(pkt);
LogNetData(pkt->data, pkt->dsize, pkt);
// FIXIT-L FIN may be in toSeq causing bogus gap counts.
if (((tsn->next && (tsn->seq + tsn->payload_size != tsn->next->seq))
|| (!tsn->next && (tsn->seq + tsn->payload_size < toSeq)))
- && !(tracker->flags & TF_FIRST_PKT_MISSING))
+ && !(tracker->get_tf_flags() & TF_FIRST_PKT_MISSING))
{
if ( tsn->next )
seglist.next = tsn->next;
- tracker->flags |= TF_MISSING_PKT;
+ tracker->set_tf_flags(TF_MISSING_PKT);
break;
}
seglist.next = tsn->next;
const uint8_t* s5_pkt_end = s5_pkt->data + s5_pkt->max_dsize;
flushed_bytes = flush_data_segments(p, stop_seq, ( uint8_t* )s5_pkt->data, s5_pkt_end);
- if ( !flushed_bytes )
+ if ( flushed_bytes == 0 )
break; /* No more data... bail */
- else if ( !s5_pkt->dsize )
- {
- tcpStats.rebuilt_buffers++;
- bytes_processed += flushed_bytes;
- }
- else
- {
- s5_pkt->packet_flags |= ( PKT_REBUILT_STREAM | PKT_STREAM_EST );
-
- if ( ( p->packet_flags & PKT_PDU_TAIL ) )
- s5_pkt->packet_flags |= PKT_PDU_TAIL;
+ bytes_processed += flushed_bytes;
+ seglist_base_seq += flushed_bytes;
- tcpStats.rebuilt_packets++;
- bytes_processed += flushed_bytes;
+ if ( s5_pkt->dsize )
+ {
+ if ( p->packet_flags & PKT_PDU_TAIL )
+ s5_pkt->packet_flags |= ( PKT_REBUILT_STREAM | PKT_STREAM_EST | PKT_PDU_TAIL );
+ else
+ s5_pkt->packet_flags |= ( PKT_REBUILT_STREAM | PKT_STREAM_EST );
// FIXIT - this came with merge should it be here?
//s5_pkt->application_protocol_ordinal =
tcpStats.rebuilt_packets++;
tcpStats.rebuilt_bytes += flushed_bytes;
- {
- ProfileExclude profile_exclude(s5TcpFlushPerfStats);
- Snort::detect_rebuilt_packet(s5_pkt);
- }
+ ProfileExclude profile_exclude(s5TcpFlushPerfStats);
+ Snort::detect_rebuilt_packet(s5_pkt);
+ }
+ else
+ {
+ tcpStats.rebuilt_buffers++;
+ tcpStats.rebuilt_buffers++;
}
-
- seglist_base_seq += flushed_bytes;
DebugFormat(DEBUG_STREAM_STATE, "setting seglist_base_seq to 0x%X\n", seglist_base_seq);
if ( tracker->splitter )
tracker->splitter->update();
- // TBD abort should be by PAF callback only since
- // recovery may be possible in some cases
- if ( tracker->flags & TF_MISSING_PKT )
+ // FIXIT - abort should be by PAF callback only since recovery may be
+ // possible in some cases
+ if ( tracker->get_tf_flags() & TF_MISSING_PKT )
{
- tracker->flags |= TF_MISSING_PREV_PKT;
- tracker->flags |= TF_PKT_MISSED;
- tracker->flags &= ~TF_MISSING_PKT;
+ tracker->set_tf_flags(TF_MISSING_PREV_PKT | TF_PKT_MISSED);
+ tracker->clear_tf_flags(TF_MISSING_PKT);
tcpStats.gaps++;
}
else
- {
- tracker->flags &= ~TF_MISSING_PREV_PKT;
- }
+ tracker->clear_tf_flags(TF_MISSING_PREV_PKT);
}
while ( seglist.next and flush_data_ready( ) );
return 0;
}
- if ( !flush_data_ready( ) && !( tracker->flags & TF_FORCE_FLUSH ) )
+ if ( !flush_data_ready( ) && !( tracker->get_tf_flags() & TF_FORCE_FLUSH ) )
{
DebugMessage(DEBUG_STREAM_STATE, "only 1 packet in seglist no need to flush\n");
return 0;
}
- tracker->flags &= ~TF_MISSING_PKT;
- tracker->flags &= ~TF_MISSING_PREV_PKT;
+ tracker->clear_tf_flags(TF_MISSING_PKT | TF_MISSING_PREV_PKT);
/* This will set this flag on the first reassembly
* if reassembly for this direction was set midstream */
if ( SEQ_LT(seglist_base_seq, seglist.next->seq)
- && !( tracker->flags & TF_FIRST_PKT_MISSING ) )
+ && !( tracker->get_tf_flags() & TF_FIRST_PKT_MISSING ) )
{
uint32_t missed = seglist.next->seq - seglist_base_seq;
if ( missed <= bytes )
bytes -= missed;
- tracker->flags |= TF_MISSING_PREV_PKT;
- tracker->flags |= TF_PKT_MISSED;
+ tracker->set_tf_flags(TF_MISSING_PREV_PKT | TF_PKT_MISSED);
tcpStats.gaps++;
seglist_base_seq = seglist.next->seq;
return 0;
}
- tracker->flags &= ~TF_FIRST_PKT_MISSING;
+ tracker->clear_tf_flags(TF_FIRST_PKT_MISSING);
return _flush_to_seq(bytes, p, pkt_flags);
}
tmp_pcap_hdr->ts.tv_usec = seglist.head->tv.tv_usec;
}
- tracker->flags |= TF_FORCE_FLUSH;
+ tracker->set_tf_flags(TF_FORCE_FLUSH);
if ( flush_stream(p, dir) )
purge_flushed_ackd( );
- tracker->flags &= ~TF_FORCE_FLUSH;
+ tracker->clear_tf_flags(TF_FORCE_FLUSH);
}
void TcpReassembler::flush_queued_segments(Flow* flow, bool clear, Packet* p)
const tcp::TCPHdr* tcph = tsd.get_tcph();
uint32_t overlap = 0;
- uint32_t seq = tsd.get_seq();
+ uint32_t seq = tsd.get_seg_seq();
if ( tcph->is_syn() )
seq++;
if ( SEQ_GT(tracker->r_win_base, seq) )
{
DebugMessage(DEBUG_STREAM_STATE, "segment overlaps ack'd data...\n");
- overlap = tracker->r_win_base - tsd.get_seq();
- if ( overlap >= tsd.get_pkt()->dsize )
+ overlap = tracker->r_win_base - tsd.get_seg_seq();
+ if ( overlap >= tsd.get_seg_len() )
{
DebugMessage(DEBUG_STREAM_STATE, "full overlap on ack'd data, dropping segment\n");
return;
}
// BLOCK add new block to seglist containing data
- add_reassembly_segment(tsd, tsd.get_pkt()->dsize, overlap, 0, tsd.get_seq() + overlap, NULL);
+ add_reassembly_segment(tsd, tsd.get_seg_len(), overlap, 0, tsd.get_seg_seq() + overlap, NULL);
DebugFormat(DEBUG_STREAM_STATE,
"Attached new queue to seglist, %d bytes queued, base_seq 0x%X\n",
- tsd.get_pkt()->dsize - overlap, seglist_base_seq);
+ tsd.get_seg_len() - overlap, seglist_base_seq);
}
void TcpReassembler::init_overlap_editor(TcpSegmentDescriptor& tsd)
if ( seglist.head && seglist.tail )
{
- if ( SEQ_GT(tsd.get_seq(), seglist.head->seq) )
- dist_head = tsd.get_seq() - seglist.head->seq;
+ if ( SEQ_GT(tsd.get_seg_seq(), seglist.head->seq) )
+ dist_head = tsd.get_seg_seq() - seglist.head->seq;
else
- dist_head = seglist.head->seq - tsd.get_seq();
+ dist_head = seglist.head->seq - tsd.get_seg_seq();
- if ( SEQ_GT(tsd.get_seq(), seglist.tail->seq) )
- dist_tail = tsd.get_seq() - seglist.tail->seq;
+ if ( SEQ_GT(tsd.get_seg_seq(), seglist.tail->seq) )
+ dist_tail = tsd.get_seg_seq() - seglist.tail->seq;
else
- dist_tail = seglist.tail->seq - tsd.get_seq();
+ dist_tail = seglist.tail->seq - tsd.get_seg_seq();
}
else
dist_head = dist_tail = 0;
);
right = tsn;
- if ( SEQ_GEQ(right->seq, tsd.get_seq() ) )
+ if ( SEQ_GEQ(right->seq, tsd.get_seg_seq() ) )
break;
left = right;
}
);
left = tsn;
- if ( SEQ_LT(left->seq, tsd.get_seq() ) )
+ if ( SEQ_LT(left->seq, tsd.get_seg_seq() ) )
break;
right = left;
}
DebugFormat(DEBUG_STREAM_STATE,
"Queuing %d bytes on stream!\nbase_seq: %X seq: %X seq_end: %X\n",
- tsd.get_end_seq() - tsd.get_seq(), seglist_base_seq, tsd.get_seq(), tsd.get_end_seq());
+ tsd.get_end_seq() - tsd.get_seg_seq(), seglist_base_seq, tsd.get_seg_seq(),
+ tsd.get_end_seq());
DebugFormat(DEBUG_STREAM_STATE, "%d segments on seglist\n", get_pending_segment_count(0));
DebugMessage(DEBUG_STREAM_STATE, "!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+\n");
seglist.tail->seq, seglist.tail->payload_size);
// BLOCK add to existing block and/or allocate new block
- rc = add_reassembly_segment(tsd, tsd.get_pkt()->dsize, 0, 0, tsd.get_seq(), left);
+ rc = add_reassembly_segment(tsd, tsd.get_seg_len(), 0, 0, tsd.get_seg_seq(), left);
return rc;
}
if ( keep_segment )
{
/* Adjust slide so that is correct relative to orig seq */
- slide = seq - tsd.get_seq();
+ slide = seq - tsd.get_seg_seq();
rc = add_reassembly_segment(tsd, len, slide, trunc_len, seq, left);
}
else
return STREAM_INSERT_OK;
}
- if ( SEQ_GT(tracker->r_win_base, tsd.get_seq() ) )
+ if ( SEQ_GT(tracker->r_win_base, tsd.get_seg_seq() ) )
{
- uint32_t offset = tracker->r_win_base - tsd.get_seq();
+ int32_t offset = tracker->r_win_base - tsd.get_seg_seq();
- if ( offset < tsd.get_pkt()->dsize )
+ if ( offset < tsd.get_seg_len() )
{
- tsd.set_seq(tsd.get_seq() + offset);
- tsd.get_pkt()->data += offset;
- tsd.get_pkt()->dsize -= (uint16_t)offset;
-
+ tsd.slide_segment_in_rcv_window(offset);
rc = insert_segment_in_seglist(tsd);
-
- tsd.get_pkt()->dsize += (uint16_t)offset;
- tsd.get_pkt()->data -= offset;
- tsd.set_seq(tsd.get_seq() - offset);
+ tsd.slide_segment_in_rcv_window(-offset);
}
}
else
void trace_segments(void);
protected:
- bool server_side;
- TcpTracker* tracker;
- uint8_t ignore_dir;
- uint8_t packet_dir;
- uint32_t flush_count; /* number of flushed queued segments */
- uint32_t xtradata_mask; /* extra data available to log */
-
TcpReassembler(TcpSession* session, TcpTracker* tracker, StreamPolicy os_policy, bool server) :
- server_side(server), tracker(tracker), flush_count(0), xtradata_mask(0)
+ server_side(server), tracker(tracker)
{
this->session = session;
set_tcp_reassembly_policy(os_policy);
void fallback(void);
uint32_t flush_pdu_ackd(uint32_t* flags);
int purge_to_seq(uint32_t flush_seq);
+
+ bool server_side;
+ TcpTracker* tracker;
+ uint8_t ignore_dir;
+ uint8_t packet_dir;
+ uint32_t flush_count = 0; /* number of flushed queued segments */
+ uint32_t xtradata_mask = 0; /* extra data available to log */
};
#endif
//-------------------------------------------------------------------------
// TcpSegment stuff
//-------------------------------------------------------------------------
+TcpSegmentNode* TcpSegmentNode::init(TcpSegmentDescriptor& tsd)
+{
+ return init(tsd.get_pkt()->pkth->ts, tsd.get_pkt()->data, tsd.get_seg_len() );
+}
+
+TcpSegmentNode* TcpSegmentNode::init(TcpSegmentNode& tsn)
+{
+ return init(tsn.tv, tsn.payload, tsn.payload_size);
+}
TcpSegmentNode* TcpSegmentNode::init(const struct timeval& tv, const uint8_t* data, unsigned dsize)
{
#include "protocols/packet.h"
#include "flow/memcap.h"
+#include "stream/libtcp/tcp_segment_descriptor.h"
+
extern THREAD_LOCAL Memcap* tcp_memcap;
//-----------------------------------------------------------------
TcpSegmentNode();
virtual ~TcpSegmentNode();
+ static TcpSegmentNode* init(TcpSegmentDescriptor& tsd);
+ static TcpSegmentNode* init(TcpSegmentNode& tsn);
static TcpSegmentNode* init(const struct timeval&, const uint8_t*, unsigned);
static bool needs_pruning(void)
{
};
#endif
+DEBUG_WRAP(const char* t = NULL; const char* l = NULL; )
+
+TcpSession::TcpSession(Flow* flow) :
+ Session(flow), client(new TcpTracker(true)), server(new TcpTracker(false))
+{
+ // initialize stream tracker state machine...
+ new TcpStateNone(tsm, *this);
+ new TcpStateClosed(tsm, *this);
+ new TcpStateListen(tsm, *this);
+ new TcpStateSynSent(tsm, *this);
+ new TcpStateSynRecv(tsm, *this);
+ new TcpStateEstablished(tsm, *this);
+ new TcpStateFinWait1(tsm, *this);
+ new TcpStateFinWait2(tsm, *this);
+ new TcpStateClosing(tsm, *this);
+ new TcpStateCloseWait(tsm, *this);
+ new TcpStateLastAck(tsm, *this);
+ new TcpStateTimeWait(tsm, *this);
+}
+
+TcpSession::~TcpSession(void)
+{
+ if (tcp_init)
+ {
+ clear_session(1);
+
+ delete client;
+ delete server;
+ }
+}
+
+void TcpSession::reset(void)
+{
+ if (tcp_init)
+ clear_session(2);
+}
+
+bool TcpSession::setup(Packet*)
+{
+ // FIXIT-L this it should not be necessary to reset here
+ reset();
+
+ client->init_tracker( );
+ server->init_tracker( );
+ lws_init = tcp_init = false;
+ no_3whs = false;
+ pkt_action_mask = ACTION_NOTHING;
+ ecn = 0;
+ ingress_index = egress_index = 0;
+ ingress_group = egress_group = 0;
+ daq_flags = address_space_id = 0;
+
+ tcpStats.sessions++;
+ return true;
+}
+
+void TcpSession::cleanup(void)
+{
+ // this flushes data and then calls TcpSessionClear()
+ cleanup_session(1);
+}
+
+void TcpSession::clear(void)
+{
+ if ( tcp_init )
+ // this does NOT flush data
+ clear_session(1);
+}
+
+void TcpSession::restart(Packet* p)
+{
+ // sanity check since this is called externally
+ assert(p->ptrs.tcph);
+
+ TcpTracker* talker, * listener;
+
+ if (p->packet_flags & PKT_FROM_SERVER)
+ {
+ talker = server;
+ listener = client;
+ }
+ else
+ {
+ talker = client;
+ listener = server;
+ }
+
+ // FIXIT-H on data / on ack must be based on flush policy
+ if (p->dsize > 0)
+ listener->reassembler->flush_on_data_policy(p);
+
+ if (p->ptrs.tcph->is_ack())
+ talker->reassembler->flush_on_ack_policy(p);
+}
+
+void TcpSession::print(void)
+{
+ char buf[64];
+
+ LogMessage("TcpSession:\n");
+ sfip_ntop(&flow->server_ip, buf, sizeof(buf));
+ LogMessage(" server IP: %s\n", buf);
+ sfip_ntop(&flow->client_ip, buf, sizeof(buf));
+ LogMessage(" client IP: %s\n", buf);
+ LogMessage(" server port: %d\n", flow->server_port);
+ LogMessage(" client port: %d\n", flow->client_port);
+ LogMessage(" flags: 0x%X\n", flow->get_session_flags());
+ LogMessage("Client Tracker:\n");
+ client->print();
+ LogMessage("Server Tracker:\n");
+ server->print();
+}
+
+void TcpSession::set_splitter(bool to_server, StreamSplitter* ss)
+{
+ TcpTracker* trk = ( to_server ) ? server : client;
+
+ trk->set_splitter(ss);
+}
+
+StreamSplitter* TcpSession::get_splitter(bool to_server)
+{
+ if ( to_server )
+ return server->splitter;
+ else
+ return client->splitter;
+}
+
void TcpSession::update_perf_base_state(char newState)
{
uint32_t session_flags = flow->get_session_flags();
return event_code;
}
-#ifdef S5_PEDANTIC
-// From RFC 793:
-//
-// Segment Receive Test
-// Length Window
-// ------- ------- -------------------------------------------
-//
-// 0 0 SEG.SEQ = RCV.NXT
-//
-// 0 >0 RCV.NXT =< SEG.SEQ < RCV.NXT+RCV.WND
-//
-// >0 0 not acceptable
-//
-// >0 >0 RCV.NXT =< SEG.SEQ < RCV.NXT+RCV.WND
-// or RCV.NXT =< SEG.SEQ+SEG.LEN-1 < RCV.NXT+RCV.WND
-//
-static inline int ValidSeq(const Packet* p, Flow* flow, TcpTracker* st, TcpSegmentDescriptor& tsd)
-{
- uint32_t win = st->normalizer->get_stream_window(flow, st, tsd);
-
- if ( !p->dsize )
- {
- if ( !win )
- {
- return ( tsd.get_seq() == st->r_win_base );
- }
- return SEQ_LEQ(st->r_win_base, tsd.get_seq()) &&
- SEQ_LT(tsd.get_seq(), st->r_win_base+win);
- }
- if ( !win )
- return 0;
-
- if ( SEQ_LEQ(st->r_win_base, tsd.get_seq()) &&
- SEQ_LT(tsd.get_seq(), st->r_win_base+win) )
- return 1;
-
- return SEQ_LEQ(st->r_win_base, tsd.get_end_seq()) &&
- SEQ_LT(tsd.get_end_seq(), st->r_win_base+win);
-}
-
-#else
-static inline int ValidSeq(TcpTracker* st, TcpSegmentDescriptor& tsd)
-{
- int right_ok;
- uint32_t left_seq;
-
- DebugFormat(DEBUG_STREAM_STATE,
- "Checking end_seq (%X) > r_win_base (%X) && seq (%X) < r_nxt_ack(%X)\n",
- tsd.get_end_seq(), st->r_win_base, tsd.get_seq(), st->r_nxt_ack +
- st->normalizer->get_stream_window(tsd));
-
- if ( SEQ_LT(st->r_nxt_ack, st->r_win_base) )
- left_seq = st->r_nxt_ack;
- else
- left_seq = st->r_win_base;
-
- if ( tsd.get_pkt()->dsize )
- right_ok = SEQ_GT(tsd.get_end_seq(), left_seq);
- else
- right_ok = SEQ_GEQ(tsd.get_end_seq(), left_seq);
-
- if ( right_ok )
- {
- uint32_t win = st->normalizer->get_stream_window(tsd);
-
- if ( SEQ_LEQ(tsd.get_seq(), st->r_win_base + win) )
- {
- DebugMessage(DEBUG_STREAM_STATE, "seq is within window!\n");
- return 1;
- }
- else
- {
- DebugMessage(DEBUG_STREAM_STATE, "seq is past the end of the window!\n");
- }
- }
- else
- {
- DebugMessage(DEBUG_STREAM_STATE, "end_seq is before win_base\n");
- }
- return 0;
-}
-
-#endif
-
-static inline void UpdateSsn(TcpTracker* rcv, TcpTracker* snd, TcpSegmentDescriptor& tsd)
-{
-#if 0
- // FIXIT-L these checks are a hack to avoid off by one normalization
- // due to FIN ... if last segment filled a hole, r_nxt_ack is not at
- // end of data, FIN is ignored so sequence isn't bumped, and this
- // forces seq-- on ACK of FIN. :(
- if ( rcv->get_tcp_state() == TcpStreamTracker::TCP_ESTABLISHED &&
- rcv->s_mgr.state_queue == TcpStreamTracker::TCP_STATE_NONE &&
- Normalize_IsEnabled(NORM_TCP_IPS) )
- {
- // walk the seglist until a gap or tsd.ack whichever is first
- // if a gap exists prior to ack, move ack back to start of gap
- TcpSegment* seg = snd->seglist;
-
- // FIXIT-L must check ack oob with empty seglist
- // FIXIT-L add lower gap bound to tracker for efficiency?
- while ( seg )
- {
- uint32_t seq = seg->seq + seg->size;
- if ( SEQ_LEQ(tsd.get_ack(), seq) )
- break;
-
- seg = seg->next;
-
- if ( !seg || seg->seq > seq )
- {
- // normalize here
- tsd.set_ack(seq);
- tcph->th_ack = htonl(seq);
- p->packet_flags |= PKT_MODIFIED;
- break;
- }
- }
- }
-#endif
- // ** if we don't see a segment, we can't track seq at ** below
- // so we update the seq by the ack if it is beyond next expected
- if ( SEQ_GT(tsd.get_ack(), rcv->get_snd_una() ) )
- rcv->set_snd_una(tsd.get_ack() );
-
- // ** this is how we track the last seq number sent
- // as is l_unackd is the "last left" seq recvd
- snd->set_snd_una(tsd.get_seq() );
-
- if ( SEQ_GT(tsd.get_end_seq(), snd->get_snd_nxt() ) )
- snd->set_snd_nxt(tsd.get_end_seq() );
-
- if ( !SEQ_EQ(snd->r_win_base, tsd.get_ack() ) )
- {
- snd->small_seg_count = 0;
- }
-#ifdef S5_PEDANTIC
- if ( SEQ_GT(tsd.get_ack(), snd->r_win_base) &&
- SEQ_LEQ(tsd.get_ack(), snd->r_nxt_ack) )
-#else
- if ( SEQ_GT(tsd.get_ack(), snd->r_win_base) )
-#endif
- snd->r_win_base = tsd.get_ack();
-
- snd->set_snd_wnd(tsd.get_win() );
-}
-
void TcpSession::clear_session(int freeApplicationData)
{
// update stats
flow->clear(freeApplicationData);
// generate event for rate filtering
- tel->EventInternal(INTERNAL_EVENT_SESSION_DEL);
+ tel.EventInternal(INTERNAL_EVENT_SESSION_DEL);
DebugFormat(DEBUG_STREAM_STATE, "After cleaning, %lu bytes in use\n", tcp_memcap->used());
clear_session(freeApplicationData);
}
-#if 0
-static inline int IsWellFormed(Packet* p, TcpTracker* ts)
-{
- return ( !ts->mss || (p->dsize <= ts->mss) );
-}
-
-#endif
-
-void TcpSession::FinishServerInit(TcpSegmentDescriptor& tsd)
-{
- const tcp::TCPHdr* tcph = tsd.get_tcph();
-
- server->set_snd_wnd(tsd.get_win() );
- server->set_snd_una(tsd.get_seq() + 1);
- server->set_snd_nxt(server->get_snd_una() );
- server->set_iss(tsd.get_seq() );
-
- client->r_nxt_ack = tsd.get_end_seq();
-
- if ( tcph->is_fin() )
- server->set_snd_nxt(server->get_snd_nxt() - 1);
-
- if ( !( flow->session_state & STREAM_STATE_MIDSTREAM ) )
- {
- server->set_tcp_state(TcpStreamTracker::TCP_SYN_RECV);
- client->reassembler->set_seglist_base_seq(server->get_snd_una() );
- client->r_win_base = tsd.get_end_seq();
- }
- else
- {
- client->reassembler->set_seglist_base_seq(tsd.get_seq() );
- client->r_win_base = tsd.get_seq();
- }
-
- server->flags |= server->normalizer->get_tcp_timestamp(tsd, false);
- server->ts_last = tsd.get_ts();
- if (server->ts_last == 0)
- server->flags |= TF_TSTAMP_ZERO;
- else
- server->set_ts_last_packet(tsd.get_pkt()->pkth->ts.tv_sec);
-
- server->flags |= tsd.init_mss(&server->mss);
- server->flags |= tsd.init_wscale(&server->wscale);
-
-#ifdef DEBUG_STREAM_EX
- PrintTcpSession(ssn);
-#endif
-}
-
void TcpSession::EndOfFileHandle(Packet* p)
{
flow->call_handlers(p, true);
if ( ( config->flags & STREAM_CONFIG_NO_ASYNC_REASSEMBLY ) && !flow->two_way_traffic() )
return true;
- if ( config->max_consec_small_segs && ( tsd.get_pkt()->dsize <
+ if ( config->max_consec_small_segs && ( tsd.get_seg_len() <
config->max_consec_small_seg_size ) )
{
rcv->small_seg_count++;
{
/* Above threshold, log it... in this TCP policy,
* action controlled by preprocessor rule. */
- tel->EventMaxSmallSegsExceeded();
+ tel.EventMaxSmallSegsExceeded();
/* Reset counter, so we're not too noisy */
rcv->small_seg_count = 0;
}
void TcpSession::process_tcp_stream(TcpTracker* rcv, TcpSegmentDescriptor& tsd)
{
DebugFormat(DEBUG_STREAM_STATE, "In ProcessTcpStream(), %d bytes to queue\n",
- tsd.get_pkt()->dsize);
+ tsd.get_seg_len());
if (tsd.get_pkt()->packet_flags & PKT_IGNORE)
return;
if ( ( config->overlap_limit )
&& ( rcv->reassembler->get_overlap_count() > config->overlap_limit ) )
{
- tel->EventExcessiveOverlap();
+ tel.EventExcessiveOverlap();
rcv->reassembler->set_overlap_count(0);
}
}
Profile profile(s5TcpDataPerfStats);
const tcp::TCPHdr* tcph = tsd.get_tcph();
- uint32_t seq = tsd.get_seq();
+ uint32_t seq = tsd.get_seg_seq();
if ( tcph->is_syn() )
{
if ( listener->s_mgr.state_queue == TcpStreamTracker::TCP_STATE_NONE )
listener->r_nxt_ack = tsd.get_end_seq();
- if (tsd.get_pkt()->dsize != 0)
+ if (tsd.get_seg_len() != 0)
{
if (!( flow->get_session_flags() & SSNFLAG_STREAM_ORDER_BAD))
tsd.get_pkt()->packet_flags |= PKT_STREAM_ORDER_OK;
// some cases.
DebugFormat(DEBUG_STREAM_STATE,
"out of order segment (tsd.seq: 0x%X l->r_nxt_ack: 0x%X!\n",
- tsd.get_seq(), listener->r_nxt_ack);
+ tsd.get_seg_seq(), listener->r_nxt_ack);
if (listener->s_mgr.state_queue == TcpStreamTracker::TCP_STATE_NONE)
{
}
}
- if (tsd.get_pkt()->dsize != 0)
+ if (tsd.get_seg_len() != 0)
{
if (!( flow->get_session_flags() & SSNFLAG_STREAM_ORDER_BAD))
{
- if (!SEQ_LEQ((tsd.get_seq() + tsd.get_pkt()->dsize), listener->r_nxt_ack))
+ if (!SEQ_LEQ((tsd.get_seg_seq() + tsd.get_seg_len()), listener->r_nxt_ack))
flow->set_session_flags(SSNFLAG_STREAM_ORDER_BAD);
}
process_tcp_stream(listener, tsd);
flow->set_expire(tsd.get_pkt(), config->session_timeout);
update_perf_base_state(TcpStreamTracker::TCP_SYN_SENT);
- tel->EventInternal(INTERNAL_EVENT_SESSION_ADD);
+ tel.EventInternal(INTERNAL_EVENT_SESSION_ADD);
- //assert( !tcp_init );
tcp_init = true;
- new_ssn = true;
+ lws_init = true;
// FIXIT - this state is bogus... move to tracker init...
tcpStats.created++;
tcpStats.sessions_on_syn_ack++;
}
-void TcpSession::update_session_state(const tcp::TCPHdr* tcph, TcpSegmentDescriptor& tsd)
+void TcpSession::update_timestamp_tracking(TcpSegmentDescriptor& tsd)
+{
+ talker->set_tf_flags(listener->normalizer->get_timestamp_flags());
+ if (listener->normalizer->handling_timestamps()
+ && SEQ_EQ(listener->r_nxt_ack, tsd.get_seg_seq()))
+ {
+ talker->set_ts_last_packet(tsd.get_pkt()->pkth->ts.tv_sec);
+ talker->set_ts_last(tsd.get_ts());
+ }
+}
+
+void TcpSession::update_session_on_syn_ack(void)
{
/* If session is already marked as established */
- if (!(flow->session_state & STREAM_STATE_ESTABLISHED)
- && (!require_3whs || config->midstream_allowed(tsd.get_pkt())))
+ if ( !( flow->session_state & STREAM_STATE_ESTABLISHED ) )
{
- /* If not requiring 3-way Handshake...
- TCP session created on TH_SYN above, or maybe on SYN-ACK, or anything else
- Need to update Lightweight session state */
- if (tcph->is_syn_ack())
+ /* SYN-ACK from server */
+ if (flow->session_state != STREAM_STATE_NONE)
{
- /* SYN-ACK from server */
- if (flow->session_state != STREAM_STATE_NONE)
- {
- flow->session_state |= STREAM_STATE_SYN_ACK;
- update_perf_base_state(TcpStreamTracker::TCP_ESTABLISHED);
- }
+ flow->session_state |= STREAM_STATE_SYN_ACK;
+ update_perf_base_state(TcpStreamTracker::TCP_ESTABLISHED);
}
- else if (tcph->is_ack() && (flow->session_state & STREAM_STATE_SYN_ACK))
+ }
+}
+
+void TcpSession::update_session_on_ack(void)
+{
+ /* If session is already marked as established */
+ if ( !( flow->session_state & STREAM_STATE_ESTABLISHED ) )
+ {
+ if ( flow->session_state & STREAM_STATE_SYN_ACK )
{
flow->session_state |= STREAM_STATE_ACK | STREAM_STATE_ESTABLISHED;
update_perf_base_state(TcpStreamTracker::TCP_ESTABLISHED);
}
}
-void TcpSession::update_session_on_server_packet(const tcp::TCPHdr* tcph,
- TcpSegmentDescriptor& tsd)
+void TcpSession::update_session_on_server_packet(TcpSegmentDescriptor& tsd)
{
DebugMessage(DEBUG_STREAM_STATE, "Stream: Updating on packet from server\n");
flow->set_session_flags(SSNFLAG_SEEN_SERVER);
+ talker = server;
+ listener = client;
- if (tcp_init)
- {
- talker = server;
- listener = client;
- }
-
- if ( talker and (talker->get_tcp_state() == TcpStreamTracker::TCP_LISTEN)
- and tcph->is_syn_only() )
- {
- tel->set_tcp_event(EVENT_4WHS);
- }
/* If we picked this guy up midstream, finish the initialization */
- if ((flow->session_state & STREAM_STATE_MIDSTREAM) && !(flow->session_state &
- STREAM_STATE_ESTABLISHED))
+ if ( !( flow->session_state & STREAM_STATE_ESTABLISHED )
+ && ( flow->session_state & STREAM_STATE_MIDSTREAM ) )
{
- FinishServerInit(tsd);
- if (tcph->are_flags_set(TH_ECE) && (flow->get_session_flags() & SSNFLAG_ECN_CLIENT_QUERY))
+ if (tsd.get_tcph()->are_flags_set(TH_ECE)
+ && (flow->get_session_flags() & SSNFLAG_ECN_CLIENT_QUERY))
flow->set_session_flags(SSNFLAG_ECN_SERVER_REPLY);
if (flow->get_session_flags() & SSNFLAG_SEEN_CLIENT)
/* if we got here we had to see the SYN already... */
flow->set_session_flags(SSNFLAG_SEEN_CLIENT);
- if (tcp_init)
- {
- talker = client;
- listener = server;
- }
+ talker = client;
+ listener = server;
- if ((flow->session_state & STREAM_STATE_MIDSTREAM)
- && !(flow->session_state & STREAM_STATE_ESTABLISHED))
+ if ( !( flow->session_state & STREAM_STATE_ESTABLISHED )
+ && ( flow->session_state & STREAM_STATE_MIDSTREAM ) )
{
/* Midstream and seen server. */
if (flow->get_session_flags() & SSNFLAG_SEEN_SERVER)
flow->set_ttl(tsd.get_pkt(), true);
}
-bool TcpSession::handle_syn_on_reset_session(const tcp::TCPHdr* tcph, TcpSegmentDescriptor& tsd)
+bool TcpSession::handle_syn_on_reset_session(TcpSegmentDescriptor& tsd)
{
- if ( !tcp_init || ( listener->get_tcp_state() == TcpStreamTracker::TCP_CLOSED )
- || ( talker->get_tcp_state() == TcpStreamTracker::TCP_CLOSED ) )
+ const tcp::TCPHdr* tcph = tsd.get_tcph();
+ if ( tcph->is_syn() &&
+ ( ( listener->get_tcp_state() == TcpStreamTracker::TCP_CLOSED )
+ || ( talker->get_tcp_state() == TcpStreamTracker::TCP_CLOSED ) ) )
{
/* Listener previously issued a reset Talker is re-SYN-ing */
// FIXIT-L this leads to bogus 129:20
tcpStats.resyns++;
listener = server;
talker = client;
- listener->normalizer->ecn_tracker( (tcp::TCPHdr*)tcph, require_3whs);
+ listener->normalizer->ecn_tracker( (tcp::TCPHdr*)tcph, config->require_3whs() );
flow->update_session_flags(SSNFLAG_SEEN_CLIENT);
}
else if (tcph->is_syn_ack())
listener = client;
talker = server;
- listener->normalizer->ecn_tracker( (tcp::TCPHdr*)tcph, require_3whs);
+ listener->normalizer->ecn_tracker( (tcp::TCPHdr*)tcph, config->require_3whs() );
flow->update_session_flags(SSNFLAG_SEEN_SERVER);
}
}
// s5_ignored_session() may be disabling detection too soon if we really want to flush
if (stream.ignored_session(flow, tsd.get_pkt()))
{
- if (talker && (talker->flags & TF_FORCE_FLUSH))
+ if ( talker && ( talker->get_tf_flags() & TF_FORCE_FLUSH ) )
{
- flush_talker(tsd.get_pkt());
- talker->flags &= ~TF_FORCE_FLUSH;
+ flush_talker(tsd.get_pkt() );
+ talker->clear_tf_flags(TF_FORCE_FLUSH);
}
- if (listener && (listener->flags & TF_FORCE_FLUSH))
+
+ if ( listener && ( listener->get_tf_flags() & TF_FORCE_FLUSH ) )
{
- flush_listener(tsd.get_pkt());
- listener->flags &= ~TF_FORCE_FLUSH;
+ flush_listener(tsd.get_pkt() );
+ listener->clear_tf_flags(TF_FORCE_FLUSH);
}
+
tsd.get_pkt()->packet_flags |= PKT_IGNORE;
pkt_action_mask |= ACTION_DISABLE_INSPECTION;
}
}
-void TcpSession::handle_data_on_syn(const tcp::TCPHdr* tcph, TcpSegmentDescriptor& tsd)
+void TcpSession::handle_data_on_syn(TcpSegmentDescriptor& tsd)
{
- /* Handle data on SYN */
- if ((tsd.get_pkt()->dsize) && tcph->is_syn())
+ /* MacOS accepts data on SYN, so don't alert if policy is MACOS */
+ if (talker->normalizer->get_os_policy() != StreamPolicy::OS_MACOS)
{
- /* MacOS accepts data on SYN, so don't alert if policy is MACOS */
- if (talker->normalizer->get_os_policy() != StreamPolicy::OS_MACOS)
- {
- // remove data on SYN
- listener->normalizer->trim_syn_payload(tsd);
+ // remove data on SYN
+ listener->normalizer->trim_syn_payload(tsd);
- if (Normalize_GetMode(NORM_TCP_TRIM_SYN) == NORM_MODE_OFF)
- {
- DebugMessage(DEBUG_STREAM_STATE, "Got data on SYN packet, not processing it\n");
- //EventDataOnSyn(config);
- tel->set_tcp_event(EVENT_DATA_ON_SYN);
- pkt_action_mask |= ACTION_BAD_PKT;
- }
+ if (Normalize_GetMode(NORM_TCP_TRIM_SYN) == NORM_MODE_OFF)
+ {
+ DebugMessage(DEBUG_STREAM_STATE, "Got data on SYN packet, not processing it\n");
+ tel.set_tcp_event(EVENT_DATA_ON_SYN);
+ pkt_action_mask |= ACTION_BAD_PKT;
}
}
}
-void TcpSession::process_tcp_packet(TcpSegmentDescriptor& tsd)
+void TcpSession::update_session_on_rst(TcpSegmentDescriptor& tsd, bool flush)
{
- Profile profile(s5TcpStatePerfStats);
+ if ( flush )
+ {
+ flush_listener(tsd.get_pkt());
+ flush_talker(tsd.get_pkt());
+ set_splitter(true, nullptr);
+ set_splitter(false, nullptr);
+ flow->free_application_data();
+ }
- int got_ts = 0;
- talker = nullptr;
- listener = nullptr;
- const tcp::TCPHdr* tcph = tsd.get_tcph();
+ talker->update_on_rst_sent( );
+}
- DEBUG_WRAP(const char* t = NULL; const char* l = NULL; );
+void TcpSession::update_paws_timestamps(TcpSegmentDescriptor& tsd)
+{
+ // update PAWS timestamps
+ DebugFormat(DEBUG_STREAM_STATE, "PAWS update tsd.seq %lu > listener->r_win_base %lu\n",
+ tsd.get_seg_seq(), listener->r_win_base);
- /* If session is already marked as established */
- update_session_state(tcph, tsd);
-
- if ( tcph->is_syn() )
- server->normalizer->ecn_tracker( (tcp::TCPHdr*)tcph, config->require_3whs() );
-
- if ( tsd.get_pkt()->packet_flags & PKT_FROM_SERVER )
+ if ( listener->normalizer->handling_timestamps()
+ && SEQ_EQ(listener->r_win_base, tsd.get_seg_seq() ) )
{
- update_session_on_server_packet(tcph, tsd);
- DEBUG_WRAP(t = "Server"; l = "Client");
+ if ( ( (int32_t)(tsd.get_ts() - talker->get_ts_last() ) >= 0 )
+ ||
+ ( ( uint32_t )tsd.get_pkt()->pkth->ts.tv_sec >=
+ talker->get_ts_last_packet() + PAWS_24DAYS ) )
+ {
+ DebugMessage(DEBUG_STREAM_STATE, "updating timestamps...\n");
+ talker->set_ts_last(tsd.get_ts());
+ talker->set_ts_last_packet(tsd.get_pkt()->pkth->ts.tv_sec);
+ }
}
else
{
- update_session_on_client_packet(tsd);
- DEBUG_WRAP(t = "Server"; l = "Client");
+ DebugMessage(DEBUG_STREAM_STATE, "not updating timestamps...\n");
}
+}
- //check for SYN on reset session
- if ( ( flow->get_session_flags() & SSNFLAG_RESET ) && tcph->is_syn() )
- if ( !handle_syn_on_reset_session(tcph, tsd) )
- return;
-
- update_ignored_session(tsd);
-
- handle_data_on_syn(tcph, tsd);
-
- if (!tcp_init)
- return;
-
- DebugFormat(DEBUG_STREAM_STATE, " %s [talker] state: %s\n", t,
- tcp_state_names[talker->get_tcp_state()]);
- DebugFormat(DEBUG_STREAM_STATE, " %s state: %s(%d)\n", l,
- tcp_state_names[listener->get_tcp_state()], listener->get_tcp_state());
-
- // may find better placement to eliminate redundant flag checks
- if ( tcph->is_syn() )
- talker->s_mgr.sub_state |= SUB_SYN_SENT;
- if ( tcph->is_ack() )
- talker->s_mgr.sub_state |= SUB_ACK_SENT;
-
- // process SYN ACK on unestablished sessions
- if ( ( TcpStreamTracker::TCP_SYN_SENT == listener->get_tcp_state() ) &&
- ( TcpStreamTracker::TCP_LISTEN == talker->get_tcp_state() ) )
+void TcpSession::check_for_session_hijack(TcpSegmentDescriptor& tsd)
+{
+ #ifdef DAQ_PKT_FLAG_PRE_ROUTING
+ if (!(tsd.get_pkt()->pkth->flags & DAQ_PKT_FLAG_PRE_ROUTING))
+#endif
{
- if ( tcph->is_ack() )
- {
- // make sure we've got a valid segment
- if (!listener->is_ack_valid(tsd.get_ack() ) )
- {
- DebugFormat(DEBUG_STREAM_STATE,
- "Pkt Ack is Out of Bounds (%X, %X, %X) = (snd_una, snd_nxt, cur)\n",
- listener->get_snd_una(), listener->get_snd_nxt(), tsd.get_ack());
- inc_tcp_discards();
- listener->normalizer->trim_win_payload(tsd);
- pkt_action_mask |= ACTION_BAD_PKT;
- return;
- }
- }
-
- talker->flags |= talker->normalizer->get_tcp_timestamp(tsd, false);
- if (tsd.get_ts() == 0)
- talker->flags |= TF_TSTAMP_ZERO;
-
- // catch resets sent by server
- if ( tcph->is_rst() )
- {
- DebugMessage(DEBUG_STREAM_STATE, "got RST\n");
-
- listener->normalizer->trim_rst_payload(tsd);
-
- // Reset is valid when in SYN_SENT if the ack field ACKs the SYN.
- if ( listener->is_rst_valid_in_syn_sent(tsd) )
- {
- DebugMessage(DEBUG_STREAM_STATE, "got RST, closing talker\n");
- /* Reset is valid */
- /* Mark session as reset... Leave it around so that any
- * additional data sent from one side or the other isn't
- * processed (and is dropped in inline mode).
- */
- flow->set_session_flags(SSNFLAG_RESET);
- talker->set_tcp_state(TcpStreamTracker::TCP_CLOSED);
- update_perf_base_state(TcpStreamTracker::TCP_CLOSING);
- /* Leave listener open, data may be in transit */
- pkt_action_mask |= ACTION_RST;
- return;
- }
- /* Reset not valid. */
- DebugMessage(DEBUG_STREAM_STATE, "bad sequence number, bailing\n");
- inc_tcp_discards();
- tel->set_tcp_event(EVENT_BAD_RST);
- listener->normalizer->packet_dropper(tsd, NORM_TCP_BLOCK);
- return;
- }
-
- // finish up server init
- if ( tcph->is_syn() )
- {
- FinishServerInit(tsd);
- if (talker->flags & TF_TSTAMP)
- {
- talker->set_ts_last_packet(tsd.get_pkt()->pkth->ts.tv_sec);
- talker->ts_last = tsd.get_ts();
- }
+ tel.set_tcp_event(is_mac_address_valid(talker, listener, tsd.get_pkt()));
+ }
+}
- DebugMessage(DEBUG_STREAM_STATE, "Finish server init got called!\n");
- }
- else
- {
- DebugMessage(DEBUG_STREAM_STATE, "Finish server init didn't get called!\n");
- }
+void TcpSession::handle_fin_recv_in_fw1(TcpSegmentDescriptor& tsd)
+{
+ Flow* flow = tsd.get_flow();
- if ( tcph->are_flags_set(TH_ECE) &&
- ( flow->get_session_flags() & SSNFLAG_ECN_CLIENT_QUERY ) )
- flow->set_session_flags(SSNFLAG_ECN_SERVER_REPLY);
+ DebugMessage(DEBUG_STREAM_STATE, "seq ok, setting state!\n");
- // explicitly set the state
- listener->set_tcp_state(TcpStreamTracker::TCP_SYN_SENT);
- DebugMessage(DEBUG_STREAM_STATE, "Accepted SYN ACK\n");
- return;
+ if ( talker->s_mgr.state_queue == TcpStreamTracker::TCP_STATE_NONE )
+ {
+ talker->set_tcp_state(TcpStreamTracker::TCP_LAST_ACK);
+ EndOfFileHandle(tsd.get_pkt() );
}
- /*
- * scale the window. Only if BOTH client and server specified
- * wscale option as part of 3-way handshake.
- * This is per RFC 1323.
- */
- if ((talker->flags & TF_WSCALE) && (listener->flags & TF_WSCALE))
- tsd.set_win(tsd.get_win() << talker->wscale);
-
- /* Check for session hijacking -- compare mac address to the ones
- * that were recorded at session startup. */
-#ifdef DAQ_PKT_FLAG_PRE_ROUTING
- if (!(tsd.get_pkt()->pkth->flags & DAQ_PKT_FLAG_PRE_ROUTING))
-#endif
+ if ( flow->get_session_flags() & SSNFLAG_MIDSTREAM )
{
- tel->set_tcp_event(is_mac_address_valid (talker, listener, tsd.get_pkt() ) );
+ // FIXIT-L this should be handled below in fin section
+ // but midstream sessions fail the seq test
+ listener->s_mgr.state_queue = TcpStreamTracker::TCP_TIME_WAIT;
+ listener->s_mgr.transition_seq = tsd.get_end_seq();
+ listener->s_mgr.expected_flags = TH_ACK;
}
+}
- pkt_action_mask |= listener->normalizer->handle_paws(tsd, &got_ts);
-
- // check RST validity
+#if 0
+// process SYN ACK on unestablished sessions
+if ( ( listener->get_tcp_state() != TcpStreamTracker::TCP_ESTABLISHED &&
+ TcpStreamTracker::TCP_SYN_ACK_RECV_EVENT == listener->get_tcp_event() ) &&
+ ( TcpStreamTracker::TCP_SYN_ACK_SENT_EVENT == talker->get_tcp_event() ) )
+{
+ // catch resets sent by server
if ( tcph->is_rst() )
{
+ DebugMessage(DEBUG_STREAM_STATE, "got RST\n");
+
listener->normalizer->trim_rst_payload(tsd);
- if (listener->normalizer->validate_rst(tsd))
+ // Reset is valid when in SYN_SENT if the ack field ACKs the SYN.
+ if ( listener->is_rst_valid_in_syn_sent(tsd) )
{
- DebugMessage(DEBUG_STREAM_STATE, "Got RST, bailing\n");
-
- if (listener->get_tcp_state() == TcpStreamTracker::TCP_FIN_WAIT1
- || listener->get_tcp_state() == TcpStreamTracker::TCP_FIN_WAIT2
- || listener->get_tcp_state() == TcpStreamTracker::TCP_CLOSE_WAIT
- || listener->get_tcp_state() == TcpStreamTracker::TCP_CLOSING)
- {
- flush_talker(tsd.get_pkt());
- flush_listener(tsd.get_pkt());
- set_splitter(true, nullptr);
- set_splitter(false, nullptr);
- flow->free_application_data();
- }
-
+ DebugMessage(DEBUG_STREAM_STATE, "got RST, closing talker\n");
+ /* Reset is valid */
+ /* Mark session as reset... Leave it around so that any
+ * additional data sent from one side or the other isn't
+ * processed (and is dropped in inline mode).
+ */
flow->set_session_flags(SSNFLAG_RESET);
talker->set_tcp_state(TcpStreamTracker::TCP_CLOSED);
- talker->s_mgr.sub_state |= SUB_RST_SENT;
update_perf_base_state(TcpStreamTracker::TCP_CLOSING);
-
- if ( listener->normalizer->is_tcp_ips_enabled() )
- listener->set_tcp_state(TcpStreamTracker::TCP_CLOSED);
-
- /* else for ids: leave listener open, data may be in transit */
+ /* Leave listener open, data may be in transit */
pkt_action_mask |= ACTION_RST;
return;
}
/* Reset not valid. */
DebugMessage(DEBUG_STREAM_STATE, "bad sequence number, bailing\n");
inc_tcp_discards();
- tel->set_tcp_event(EVENT_BAD_RST);
+ tel.set_tcp_event(EVENT_BAD_RST);
listener->normalizer->packet_dropper(tsd, NORM_TCP_BLOCK);
return;
}
- else
- {
- /* check for valid seqeuence/retrans */
- if (config->policy != StreamPolicy::OS_PROXY
- and (listener->get_tcp_state() >= TcpStreamTracker::TCP_ESTABLISHED)
- and !ValidSeq(listener, tsd))
- {
- DebugMessage(DEBUG_STREAM_STATE, "bad sequence number, bailing\n");
- inc_tcp_discards();
- listener->normalizer->trim_win_payload(tsd);
- return;
- }
- }
-
- if ( pkt_action_mask & ACTION_BAD_PKT )
- {
- DebugMessage(DEBUG_STREAM_STATE, "bad timestamp, bailing\n");
- inc_tcp_discards();
- return;
- }
-
- // update PAWS timestamps
- DebugFormat(DEBUG_STREAM_STATE, "PAWS update tsd.seq %lu > listener->r_win_base %lu\n",
- tsd.get_seq(), listener->r_win_base);
- if (got_ts && SEQ_EQ(listener->r_win_base, tsd.get_seq()))
- {
- if ( ( int32_t )( tsd.get_ts() - talker->ts_last ) >= 0 ||
- (uint32_t)tsd.get_pkt()->pkth->ts.tv_sec >= talker->get_ts_last_packet() + PAWS_24DAYS)
- {
- DebugMessage(DEBUG_STREAM_STATE, "updating timestamps...\n");
- talker->ts_last = tsd.get_ts();
- talker->set_ts_last_packet(tsd.get_pkt()->pkth->ts.tv_sec);
- }
- }
- else
- {
- DebugMessage(DEBUG_STREAM_STATE, "not updating timestamps...\n");
- }
-
- // check for repeat SYNs
- if ( !new_ssn && tcph->is_syn_only() )
- {
- int action;
- if (!SEQ_EQ(tsd.get_seq(), talker->get_iss()) &&
- listener->normalizer->packet_dropper(tsd, NORM_TCP_BLOCK))
- action = ACTION_BAD_PKT;
- else if (talker->get_tcp_state() >= TcpStreamTracker::TCP_ESTABLISHED)
- action = listener->normalizer->handle_repeated_syn(tsd);
- else
- action = ACTION_NOTHING;
-
- if (action != ACTION_NOTHING)
- {
- /* got a bad SYN on the session, alert! */
- tel->set_tcp_event(EVENT_SYN_ON_EST);
- pkt_action_mask |= action;
- return;
- }
- }
-
- // Check that the window is within the limits
- if (config->policy != StreamPolicy::OS_PROXY)
- {
- if (config->max_window && (tsd.get_win() > config->max_window))
- {
- DebugMessage(DEBUG_STREAM_STATE,
- "Got window that was beyond the allowed policy value, bailing\n");
- /* got a window too large, alert! */
- tel->set_tcp_event(EVENT_WINDOW_TOO_LARGE);
- inc_tcp_discards();
- listener->normalizer->packet_dropper(tsd, NORM_TCP_BLOCK);
- pkt_action_mask |= ACTION_BAD_PKT;
- return;
- }
- else if ((tsd.get_pkt()->packet_flags & PKT_FROM_CLIENT) && (tsd.get_win() <= SLAM_MAX)
- && (tsd.get_ack() == listener->get_iss() + 1)
- && !( tcph->is_fin() | tcph->is_rst() )
- && !(flow->get_session_flags() & SSNFLAG_MIDSTREAM))
- {
- DebugMessage(DEBUG_STREAM_STATE, "Window slammed shut!\n");
- /* got a window slam alert! */
- tel->set_tcp_event(EVENT_WINDOW_SLAM);
- inc_tcp_discards();
-
- if (listener->normalizer->packet_dropper(tsd, NORM_TCP_BLOCK))
- {
- pkt_action_mask |= ACTION_BAD_PKT;
- return;
- }
- }
- }
-
- if (talker->s_mgr.state_queue != TcpStreamTracker::TCP_STATE_NONE)
- {
- DebugFormat(DEBUG_STREAM_STATE,
- "Found queued state transition on ack 0x%X, current 0x%X!\n",
- talker->s_mgr.transition_seq, tsd.get_ack());
-
- if (tsd.get_ack() == talker->s_mgr.transition_seq)
- {
- DebugMessage(DEBUG_STREAM_STATE, "accepting transition!\n");
- talker->set_tcp_state(talker->s_mgr.state_queue);
- talker->s_mgr.state_queue = TcpStreamTracker::TCP_STATE_NONE;
- }
- }
-
- // process ACK flags
- if ( tcph->is_ack() )
- {
- DebugMessage(DEBUG_STREAM_STATE, "Got an ACK...\n");
- DebugFormat(DEBUG_STREAM_STATE, " %s [listener] state: %s\n", l,
- tcp_state_names[listener->get_tcp_state()]);
-
- switch ( listener->get_tcp_state() )
- {
- case TcpStreamTracker::TCP_SYN_SENT:
- break;
-
- case TcpStreamTracker::TCP_SYN_RECV:
- DebugMessage(DEBUG_STREAM_STATE, "listener state is SYN_SENT...\n");
- if ( listener->is_ack_valid(tsd.get_ack() ) )
- {
- UpdateSsn(listener, talker, tsd);
- flow->set_session_flags(SSNFLAG_ESTABLISHED);
- flow->session_state |= STREAM_STATE_ESTABLISHED;
- listener->set_tcp_state(TcpStreamTracker::TCP_ESTABLISHED);
- talker->set_tcp_state(TcpStreamTracker::TCP_ESTABLISHED);
- update_perf_base_state(TcpStreamTracker::TCP_ESTABLISHED);
- /* Indicate this packet completes 3-way handshake */
- tsd.get_pkt()->packet_flags |= PKT_STREAM_TWH;
- }
-
- talker->flags |= got_ts;
- if (got_ts && SEQ_EQ(listener->r_nxt_ack, tsd.get_seq()))
- {
- talker->set_ts_last_packet(tsd.get_pkt()->pkth->ts.tv_sec);
- talker->ts_last = tsd.get_ts();
- }
-
- break;
-
- case TcpStreamTracker::TCP_ESTABLISHED:
- case TcpStreamTracker::TCP_CLOSE_WAIT:
- UpdateSsn(listener, talker, tsd);
- break;
-
- case TcpStreamTracker::TCP_FIN_WAIT1:
- UpdateSsn(listener, talker, tsd);
-
- DebugFormat(DEBUG_STREAM_STATE, "tsd.ack %X >= talker->r_nxt_ack %X\n", tsd.get_ack(),
- talker->r_nxt_ack);
-
- if ( SEQ_EQ(tsd.get_ack(), listener->get_snd_nxt() ) )
- {
- if ((listener->normalizer->get_os_policy() == StreamPolicy::OS_WINDOWS) &&
- (tsd.get_win() == 0))
- {
- tel->set_tcp_event(EVENT_WINDOW_SLAM);
- inc_tcp_discards();
-
- if (listener->normalizer->packet_dropper(tsd, NORM_TCP_BLOCK))
- {
- pkt_action_mask |= ACTION_BAD_PKT;
- return;
- }
- }
-
- listener->set_tcp_state(TcpStreamTracker::TCP_FIN_WAIT2);
-
- if ( tcph->is_fin() )
- {
- DebugMessage(DEBUG_STREAM_STATE, "seq ok, setting state!\n");
-
- if ( talker->s_mgr.state_queue == TcpStreamTracker::TCP_STATE_NONE )
- {
- talker->set_tcp_state(TcpStreamTracker::TCP_LAST_ACK);
- EndOfFileHandle(tsd.get_pkt() );
- }
- if ( flow->get_session_flags() & SSNFLAG_MIDSTREAM )
- {
- // FIXIT-L this should be handled below in fin section
- // but midstream sessions fail the seq test
- listener->s_mgr.state_queue = TcpStreamTracker::TCP_TIME_WAIT;
- listener->s_mgr.transition_seq = tsd.get_end_seq();
- listener->s_mgr.expected_flags = TH_ACK;
- }
- }
- else if ( listener->s_mgr.state_queue == TcpStreamTracker::TCP_CLOSING )
- {
- listener->s_mgr.state_queue = TcpStreamTracker::TCP_TIME_WAIT;
- listener->s_mgr.transition_seq = tsd.get_end_seq();
- listener->s_mgr.expected_flags = TH_ACK;
- }
- }
- else
- {
- DebugMessage(DEBUG_STREAM_STATE, "bad ack!\n");
- }
- break;
-
- case TcpStreamTracker::TCP_FIN_WAIT2:
- UpdateSsn(listener, talker, tsd);
- if ( SEQ_GT(tsd.get_ack(), listener->get_snd_nxt() ) )
- {
- tel->set_tcp_event(EVENT_BAD_ACK);
- listener->normalizer->packet_dropper(tsd, NORM_TCP_BLOCK);
- pkt_action_mask |= ACTION_BAD_PKT;
- return;
- }
- break;
-
- case TcpStreamTracker::TCP_CLOSING:
- UpdateSsn(listener, talker, tsd);
- if (SEQ_GEQ(tsd.get_end_seq(), listener->r_nxt_ack))
- listener->set_tcp_state(TcpStreamTracker::TCP_TIME_WAIT);
- break;
-
- case TcpStreamTracker::TCP_LAST_ACK:
- UpdateSsn(listener, talker, tsd);
-
- if ( SEQ_EQ(tsd.get_ack(), listener->get_snd_nxt() ) )
- listener->set_tcp_state(TcpStreamTracker::TCP_CLOSED);
- break;
-
- default:
- // FIXIT-L safe to ignore when inline?
- break;
- }
- talker->reassembler->flush_on_ack_policy(tsd.get_pkt() );
- }
+ // explicitly set the state
+ //listener->set_tcp_state( TcpStreamTracker::TCP_SYN_SENT );
+ DebugMessage(DEBUG_STREAM_STATE, "Accepted SYN ACK\n");
+ return;
+}
+#endif
+void TcpSession::handle_data_segment(TcpSegmentDescriptor& tsd)
+{
// handle data in the segment
- if (tsd.get_pkt()->dsize)
+ if (tsd.get_seg_len())
{
DebugFormat(DEBUG_STREAM_STATE, " %s state: %s(%d) getting data\n",
l, tcp_state_names[listener->get_tcp_state()], listener->get_tcp_state());
// FIN means only that sender is done talking, other side may continue yapping.
- if ( TcpStreamTracker::TCP_FIN_WAIT2 == talker->get_tcp_state() ||
- TcpStreamTracker::TCP_TIME_WAIT == talker->get_tcp_state() )
+ if (TcpStreamTracker::TCP_FIN_WAIT2 == talker->get_tcp_state()
+ || TcpStreamTracker::TCP_TIME_WAIT == talker->get_tcp_state())
{
// data on a segment when we're not accepting data any more alert!
- //EventDataOnClosed(talker->config);
- tel->set_tcp_event(EVENT_DATA_ON_CLOSED);
+ tel.set_tcp_event(EVENT_DATA_ON_CLOSED);
pkt_action_mask |= ACTION_BAD_PKT;
listener->normalizer->packet_dropper(tsd, NORM_TCP_BLOCK);
}
- else if ( TcpStreamTracker::TCP_CLOSED == talker->get_tcp_state() )
+ else if (TcpStreamTracker::TCP_CLOSED == talker->get_tcp_state())
{
// data on a segment when we're not accepting data any more alert!
if (flow->get_session_flags() & SSNFLAG_RESET)
{
//EventDataAfterReset(listener->config);
if (talker->s_mgr.sub_state & SUB_RST_SENT)
- tel->set_tcp_event(EVENT_DATA_AFTER_RESET);
+ tel.set_tcp_event(EVENT_DATA_AFTER_RESET);
else
- tel->set_tcp_event(EVENT_DATA_AFTER_RST_RCVD);
+ tel.set_tcp_event(EVENT_DATA_AFTER_RST_RCVD);
}
else
{
- //EventDataOnClosed(listener->config);
- tel->set_tcp_event(EVENT_DATA_ON_CLOSED);
+ tel.set_tcp_event(EVENT_DATA_ON_CLOSED);
}
pkt_action_mask |= ACTION_BAD_PKT;
listener->normalizer->packet_dropper(tsd, NORM_TCP_BLOCK);
flush_policy_names[talker->flush_policy],
flush_policy_names[listener->flush_policy]);
+ // FIXIT - move this to normalizer base class, handle OS_PROXY in derived class
if (config->policy != StreamPolicy::OS_PROXY)
{
// these normalizations can't be done if we missed setup. and
TcpTracker* st = listener;
// trim to fit in window and mss as needed
- st->normalizer->trim_win_payload(tsd, ( st->r_win_base + st->get_snd_wnd() -
- st->r_nxt_ack) );
+ st->normalizer->trim_win_payload(tsd, (st->r_win_base + st->get_snd_wnd() -
+ st->r_nxt_ack));
- if (st->mss)
- st->normalizer->trim_mss_payload(tsd, st->mss);
+ if (st->get_mss())
+ st->normalizer->trim_mss_payload(tsd, st->get_mss());
- st->normalizer->ecn_stripper(tsd.get_pkt() );
+ st->normalizer->ecn_stripper(tsd.get_pkt());
}
}
+
// dunno if this is RFC but fragroute testing expects it for the record,
// I've seen FTP data sessions that send data packets with no tcp flags set
- if ((tcph->th_flags != 0)
- or (config->policy == StreamPolicy::OS_LINUX)
+ if ((tsd.get_tcph()->th_flags != 0)or (config->policy == StreamPolicy::OS_LINUX)
or (config->policy == StreamPolicy::OS_PROXY))
{
process_tcp_data(listener, tsd);
}
else
{
- tel->set_tcp_event(EVENT_DATA_WITHOUT_FLAGS);
+ tel.set_tcp_event(EVENT_DATA_WITHOUT_FLAGS);
listener->normalizer->packet_dropper(tsd, NORM_TCP_BLOCK);
}
}
- listener->reassembler->flush_on_data_policy(tsd.get_pkt() );
+ listener->reassembler->flush_on_data_policy(tsd.get_pkt());
}
+}
- if ( tcph->is_fin() )
- {
- DebugMessage(DEBUG_STREAM_STATE, "Got a FIN...\n");
- DebugFormat(DEBUG_STREAM_STATE, " %s state: %s(%d)\n", l,
- tcp_state_names[talker->get_tcp_state()], talker->get_tcp_state());
- DebugFormat(DEBUG_STREAM_STATE, "checking ack (0x%X) vs nxt_ack (0x%X)\n",
- tsd.get_end_seq(), listener->r_win_base);
+bool TcpSession::handle_fin_recv(TcpSegmentDescriptor& tsd)
+{
+ if ( !tsd.get_tcph()->is_fin() )
+ return true;
- if ( SEQ_LT(tsd.get_end_seq(), listener->r_win_base) )
- {
- DebugMessage(DEBUG_STREAM_STATE, "FIN inside r_win_base, bailing\n");
- goto dupfin;
- }
- else
+ DebugMessage(DEBUG_STREAM_STATE, "Got a FIN...\n");
+ DebugFormat(DEBUG_STREAM_STATE, " %s state: %s(%d)\n", l,
+ tcp_state_names[talker->get_tcp_state()], talker->get_tcp_state());
+ DebugFormat(DEBUG_STREAM_STATE, "checking ack (0x%X) vs nxt_ack (0x%X)\n",
+ tsd.get_end_seq(), listener->r_win_base);
+
+ if ( SEQ_LT(tsd.get_end_seq(), listener->r_win_base) )
+ {
+ DebugMessage(DEBUG_STREAM_STATE, "FIN inside r_win_base, bailing\n");
+ return true;
+ }
+ else
+ {
+ // need substate since we don't change state immediately
+ if ( (talker->get_tcp_state() >= TcpStreamTracker::TCP_ESTABLISHED )
+ && !( talker->s_mgr.sub_state & SUB_FIN_SENT ) )
{
- // need substate since we don't change state immediately
- if ( (talker->get_tcp_state() >= TcpStreamTracker::TCP_ESTABLISHED )
- && !( talker->s_mgr.sub_state & SUB_FIN_SENT ) )
- {
- talker->set_snd_nxt(talker->get_snd_nxt() + 1);
+ talker->set_snd_nxt(talker->get_snd_nxt() + 1);
- //--------------------------------------------------
- // FIXIT-L don't bump r_nxt_ack unless FIN is in seq
- // because it causes bogus 129:5 cases
- // but doing so causes extra gaps
- //if ( SEQ_EQ(tsd.end_seq, listener->r_nxt_ack) )
- listener->r_nxt_ack++;
- //--------------------------------------------------
+ //--------------------------------------------------
+ // FIXIT-L don't bump r_nxt_ack unless FIN is in seq
+ // because it causes bogus 129:5 cases
+ // but doing so causes extra gaps
+ //if ( SEQ_EQ(tsd.end_seq, listener->r_nxt_ack) )
+ listener->r_nxt_ack++;
+ //--------------------------------------------------
- talker->s_mgr.sub_state |= SUB_FIN_SENT;
+ talker->s_mgr.sub_state |= SUB_FIN_SENT;
- if ( ( listener->flush_policy != STREAM_FLPOLICY_ON_ACK )
- && ( listener->flush_policy != STREAM_FLPOLICY_ON_DATA )
- && listener->normalizer->is_tcp_ips_enabled() )
- {
- tsd.get_pkt()->packet_flags |= PKT_PDU_TAIL;
- }
- }
- switch (talker->get_tcp_state())
+ if ( ( listener->flush_policy != STREAM_FLPOLICY_ON_ACK )
+ && ( listener->flush_policy != STREAM_FLPOLICY_ON_DATA )
+ && listener->normalizer->is_tcp_ips_enabled() )
{
- case TcpStreamTracker::TCP_SYN_RECV:
- case TcpStreamTracker::TCP_ESTABLISHED:
- if ( talker->s_mgr.state_queue == TcpStreamTracker::TCP_CLOSE_WAIT )
- talker->s_mgr.state_queue = TcpStreamTracker::TCP_CLOSING;
-
- talker->set_tcp_state(TcpStreamTracker::TCP_FIN_WAIT1);
- EndOfFileHandle(tsd.get_pkt() );
+ tsd.get_pkt()->packet_flags |= PKT_PDU_TAIL;
+ }
+ }
+ switch (talker->get_tcp_state())
+ {
+ case TcpStreamTracker::TCP_SYN_RECV:
+ case TcpStreamTracker::TCP_ESTABLISHED:
+ if ( talker->s_mgr.state_queue == TcpStreamTracker::TCP_CLOSE_WAIT )
+ talker->s_mgr.state_queue = TcpStreamTracker::TCP_CLOSING;
- if ( !tsd.get_pkt()->dsize )
- listener->reassembler->flush_on_data_policy(tsd.get_pkt() );
+ talker->set_tcp_state(TcpStreamTracker::TCP_FIN_WAIT1);
+ EndOfFileHandle(tsd.get_pkt() );
- update_perf_base_state(TcpStreamTracker::TCP_CLOSING);
- break;
+ if ( !tsd.get_seg_len() )
+ listener->reassembler->flush_on_data_policy(tsd.get_pkt() );
- case TcpStreamTracker::TCP_CLOSE_WAIT:
- talker->set_tcp_state(TcpStreamTracker::TCP_LAST_ACK);
- break;
+ update_perf_base_state(TcpStreamTracker::TCP_CLOSING);
+ break;
- case TcpStreamTracker::TCP_FIN_WAIT1:
- if (!tsd.get_pkt()->dsize)
- retransmit_handle(tsd.get_pkt() );
- break;
+ case TcpStreamTracker::TCP_CLOSE_WAIT:
+ talker->set_tcp_state(TcpStreamTracker::TCP_LAST_ACK);
+ break;
- default:
- /* all other states stay where they are */
- break;
- }
+ case TcpStreamTracker::TCP_FIN_WAIT1:
+ if (!tsd.get_seg_len())
+ retransmit_handle(tsd.get_pkt() );
+ break;
- if ((talker->get_tcp_state() == TcpStreamTracker::TCP_FIN_WAIT1) ||
- (talker->get_tcp_state() == TcpStreamTracker::TCP_LAST_ACK))
- {
- uint32_t end_seq = (flow->get_session_flags() & SSNFLAG_MIDSTREAM)
- ? tsd.get_end_seq() - 1 : tsd.get_end_seq();
+ default:
+ /* all other states stay where they are */
+ break;
+ }
- if ((listener->s_mgr.expected_flags == TH_ACK) && SEQ_GEQ(end_seq,
- listener->s_mgr.transition_seq))
- {
- DebugMessage(DEBUG_STREAM_STATE, "FIN beyond previous, ignoring\n");
- tel->set_tcp_event(EVENT_BAD_FIN);
- listener->normalizer->packet_dropper(tsd, NORM_TCP_BLOCK);
- pkt_action_mask |= ACTION_BAD_PKT;
- return;
- }
- }
+ if ((talker->get_tcp_state() == TcpStreamTracker::TCP_FIN_WAIT1) ||
+ (talker->get_tcp_state() == TcpStreamTracker::TCP_LAST_ACK))
+ {
+ uint32_t end_seq = (flow->get_session_flags() & SSNFLAG_MIDSTREAM)
+ ? tsd.get_end_seq() - 1 : tsd.get_end_seq();
- switch ( listener->get_tcp_state() )
+ if ((listener->s_mgr.expected_flags == TH_ACK) && SEQ_GEQ(end_seq,
+ listener->s_mgr.transition_seq))
{
- case TcpStreamTracker::TCP_ESTABLISHED:
- listener->s_mgr.state_queue = TcpStreamTracker::TCP_CLOSE_WAIT;
- listener->s_mgr.transition_seq = tsd.get_end_seq() + 1;
- listener->s_mgr.expected_flags = TH_ACK;
- break;
-
- case TcpStreamTracker::TCP_FIN_WAIT1:
- listener->s_mgr.state_queue = TcpStreamTracker::TCP_CLOSING;
- listener->s_mgr.transition_seq = tsd.get_end_seq() + 1;
- listener->s_mgr.expected_flags = TH_ACK;
- break;
-
- case TcpStreamTracker::TCP_FIN_WAIT2:
- listener->s_mgr.state_queue = TcpStreamTracker::TCP_TIME_WAIT;
- listener->s_mgr.transition_seq = tsd.get_end_seq() + 1;
- listener->s_mgr.expected_flags = TH_ACK;
- break;
-
- default:
- // FIXIT - put this here quickly to make compiler happy, what should
- // be done when not in one of the 3 states above?
- DebugMessage(DEBUG_STREAM_STATE, "No Action In This State\n");
- break;
+ DebugMessage(DEBUG_STREAM_STATE, "FIN beyond previous, ignoring\n");
+ tel.set_tcp_event(EVENT_BAD_FIN);
+ listener->normalizer->packet_dropper(tsd, NORM_TCP_BLOCK);
+ pkt_action_mask |= ACTION_BAD_PKT;
+ return false;
}
}
+
+ switch ( listener->get_tcp_state() )
+ {
+ case TcpStreamTracker::TCP_ESTABLISHED:
+ listener->s_mgr.state_queue = TcpStreamTracker::TCP_CLOSE_WAIT;
+ listener->s_mgr.transition_seq = tsd.get_end_seq() + 1;
+ listener->s_mgr.expected_flags = TH_ACK;
+ break;
+
+ case TcpStreamTracker::TCP_FIN_WAIT1:
+ listener->s_mgr.state_queue = TcpStreamTracker::TCP_CLOSING;
+ listener->s_mgr.transition_seq = tsd.get_end_seq() + 1;
+ listener->s_mgr.expected_flags = TH_ACK;
+ break;
+
+ case TcpStreamTracker::TCP_FIN_WAIT2:
+ listener->s_mgr.state_queue = TcpStreamTracker::TCP_TIME_WAIT;
+ listener->s_mgr.transition_seq = tsd.get_end_seq() + 1;
+ listener->s_mgr.expected_flags = TH_ACK;
+ break;
+
+ default:
+ // FIXIT - put this here quickly to make compiler happy, what should
+ // be done when not in one of the 3 states above?
+ DebugMessage(DEBUG_STREAM_STATE, "No Action In This State\n");
+ break;
+ }
}
-dupfin:
+ return true;
+}
+void TcpSession::finalize_tcp_packet_processing(TcpSegmentDescriptor& tsd)
+{
DebugFormat(DEBUG_STREAM_STATE, " %s [talker] state: %s\n", t,
tcp_state_names[talker->get_tcp_state()]);
DebugFormat(DEBUG_STREAM_STATE, " %s state: %s(%d)\n", l,
// handle TIME_WAIT timer stuff
if (!flow->two_way_traffic() &&
- (talker->get_tcp_state() >= TcpStreamTracker::TCP_FIN_WAIT1 || listener->get_tcp_state() >=
- TcpStreamTracker::TCP_FIN_WAIT1))
+ (talker->get_tcp_state() >= TcpStreamTracker::TCP_FIN_WAIT1
+ || listener->get_tcp_state() >= TcpStreamTracker::TCP_FIN_WAIT1))
{
- if (tcph->is_fin() && tcph->is_ack())
+ if (tsd.get_tcph()->is_fin() && tsd.get_tcph()->is_ack())
{
if (talker->get_tcp_state() >= TcpStreamTracker::TCP_FIN_WAIT1)
talker->set_tcp_state(TcpStreamTracker::TCP_CLOSED);
if (listener->get_tcp_state() >= TcpStreamTracker::TCP_FIN_WAIT1)
listener->set_tcp_state(TcpStreamTracker::TCP_CLOSED);
- listener->flags |= TF_FORCE_FLUSH;
+ listener->set_tf_flags(TF_FORCE_FLUSH);
}
}
talker->get_tcp_state() == TcpStreamTracker::TCP_CLOSED)
|| (listener->get_tcp_state() == TcpStreamTracker::TCP_TIME_WAIT &&
talker->get_tcp_state() == TcpStreamTracker::TCP_TIME_WAIT)
- || (!flow->two_way_traffic() && (talker->get_tcp_state() == TcpStreamTracker::TCP_CLOSED ||
+ || (!flow->two_way_traffic() &&
+ (talker->get_tcp_state() == TcpStreamTracker::TCP_CLOSED
+ ||
listener->get_tcp_state() == TcpStreamTracker::TCP_CLOSED)))
{
// The last ACK is a part of the session. Delete the session after processing is complete.
else if ( listener->get_tcp_state() == TcpStreamTracker::TCP_CLOSED
&& talker->get_tcp_state() == TcpStreamTracker::TCP_SYN_SENT )
{
- if ( tcph->is_syn_only() )
+ if ( tsd.get_tcph()->is_syn_only() )
flow->set_expire(tsd.get_pkt(), config->session_timeout);
}
}
-//-------------------------------------------------------------------------
-// TcpSession methods
-//-------------------------------------------------------------------------
-
-TcpSession::TcpSession(Flow* flow) :
- Session(flow), config(nullptr), client(new TcpTracker(true) ),
- server(new TcpTracker(false) ), ecn(0), ingress_index(0),
- ingress_group(0), egress_index(0), egress_group(0), daq_flags(0), address_space_id(0),
- pkt_action_mask(ACTION_NOTHING), require_3whs(true), no_3whs(false)
+void TcpSession::process_tcp_packet(TcpSegmentDescriptor& tsd)
{
- lws_init = tcp_init = false;
- new_ssn = false;
+ Profile profile(s5TcpStatePerfStats);
+ const tcp::TCPHdr* tcph = tsd.get_tcph();
- tel = new TcpEventLogger;
+ check_for_session_hijack(tsd);
- // initialize stream tracker state machine...
- new TcpStateNone(tsm, *this);
- new TcpStateClosed(tsm, *this);
- new TcpStateListen(tsm, *this);
- new TcpStateSynSent(tsm, *this);
- new TcpStateSynRecv(tsm, *this);
- new TcpStateEstablished(tsm, *this);
- new TcpStateFinWait1(tsm, *this);
- new TcpStateFinWait2(tsm, *this);
- new TcpStateClosing(tsm, *this);
- new TcpStateCloseWait(tsm, *this);
- new TcpStateLastAck(tsm, *this);
- new TcpStateTimeWait(tsm, *this);
-}
+ /* check for valid seqeuence/retrans */
+ if ( ( config->policy != StreamPolicy::OS_PROXY )
+ && !listener->is_segment_seq_valid(tsd) )
+ return;
-TcpSession::~TcpSession(void)
-{
- if (tcp_init)
+ if ( pkt_action_mask & ACTION_BAD_PKT )
{
- clear_session(1);
-
- delete client;
- delete server;
+ DebugMessage(DEBUG_STREAM_STATE, "bad timestamp, bailing\n");
+ inc_tcp_discards();
+ return;
}
- delete tel;
-}
-
-void TcpSession::reset(void)
-{
- if (tcp_init)
- clear_session(2);
-}
-
-bool TcpSession::setup(Packet*)
-{
- // FIXIT-L this it should not be necessary to reset here
- reset();
-
- client->init_tracker( );
- server->init_tracker( );
- lws_init = tcp_init = false;
- no_3whs = false;
- pkt_action_mask = ACTION_NOTHING;
- ecn = 0;
- ingress_index = egress_index = 0;
- ingress_group = egress_group = 0;
- daq_flags = address_space_id = 0;
-
- SESSION_STATS_ADD(tcpStats);
- return true;
-}
+ update_paws_timestamps(tsd);
-void TcpSession::cleanup(void)
-{
- // this flushes data and then calls TcpSessionClear()
- cleanup_session(1);
-}
-
-void TcpSession::clear(void)
-{
- if ( tcp_init )
- // this does NOT flush data
- clear_session(true);
-}
-
-void TcpSession::restart(Packet* p)
-{
- // sanity check since this is called externally
- assert(p->ptrs.tcph);
-
- TcpTracker* talker, * listener;
-
- if (p->packet_flags & PKT_FROM_SERVER)
- {
- talker = server;
- listener = client;
- }
- else
+ // check for repeat SYNs
+ if ( tcph->is_syn_only() )
{
- talker = client;
- listener = server;
- }
+ int action;
+ if (!SEQ_EQ(tsd.get_seg_seq(), talker->get_iss())
+ && listener->normalizer->packet_dropper(tsd, NORM_TCP_BLOCK))
+ action = ACTION_BAD_PKT;
+ else if (talker->get_tcp_state() >= TcpStreamTracker::TCP_ESTABLISHED)
+ action = listener->normalizer->handle_repeated_syn(tsd);
+ else
+ action = ACTION_NOTHING;
- // FIXIT-H on data / on ack must be based on flush policy
- if (p->dsize > 0)
- listener->reassembler->flush_on_data_policy(p);
+ if (action != ACTION_NOTHING)
+ {
+ /* got a bad SYN on the session, alert! */
+ tel.set_tcp_event(EVENT_SYN_ON_EST);
+ pkt_action_mask |= action;
+ return;
+ }
+ }
- if (p->ptrs.tcph->is_ack())
- talker->reassembler->flush_on_ack_policy(p);
-}
+ // Check that the window is within the limits
+ if ( config->policy != StreamPolicy::OS_PROXY )
+ {
+ if ( config->max_window && (tsd.get_seg_wnd() > config->max_window ) )
+ {
+ DebugMessage(DEBUG_STREAM_STATE,
+ "Got window that was beyond the allowed policy value, bailing\n");
+ /* got a window too large, alert! */
+ tel.set_tcp_event(EVENT_WINDOW_TOO_LARGE);
+ inc_tcp_discards();
+ listener->normalizer->packet_dropper(tsd, NORM_TCP_BLOCK);
+ pkt_action_mask |= ACTION_BAD_PKT;
+ return;
+ }
+ else if ((tsd.get_pkt()->packet_flags & PKT_FROM_CLIENT)
+ && (tsd.get_seg_wnd() <= SLAM_MAX)
+ && (tsd.get_seg_ack() == listener->get_iss() + 1)
+ && !( tcph->is_fin() | tcph->is_rst() )
+ && !(flow->get_session_flags() & SSNFLAG_MIDSTREAM))
+ {
+ DebugMessage(DEBUG_STREAM_STATE, "Window slammed shut!\n");
+ /* got a window slam alert! */
+ tel.set_tcp_event(EVENT_WINDOW_SLAM);
+ inc_tcp_discards();
-void TcpSession::print(void)
-{
- char buf[64];
+ if (listener->normalizer->packet_dropper(tsd, NORM_TCP_BLOCK))
+ {
+ pkt_action_mask |= ACTION_BAD_PKT;
+ return;
+ }
+ }
+ }
- LogMessage("TcpSession:\n");
- sfip_ntop(&flow->server_ip, buf, sizeof(buf));
- LogMessage(" server IP: %s\n", buf);
- sfip_ntop(&flow->client_ip, buf, sizeof(buf));
- LogMessage(" client IP: %s\n", buf);
- LogMessage(" server port: %d\n", flow->server_port);
- LogMessage(" client port: %d\n", flow->client_port);
- LogMessage(" flags: 0x%X\n", flow->get_session_flags());
- LogMessage("Client Tracker:\n");
- client->print();
- LogMessage("Server Tracker:\n");
- server->print();
-}
+ if (talker->s_mgr.state_queue != TcpStreamTracker::TCP_STATE_NONE)
+ {
+ DebugFormat(DEBUG_STREAM_STATE,
+ "Found queued state transition on ack 0x%X, current 0x%X!\n",
+ talker->s_mgr.transition_seq, tsd.get_seg_ack());
-void TcpSession::set_splitter(bool to_server, StreamSplitter* ss)
-{
- TcpTracker* trk = ( to_server ) ? server : client;
+ if (tsd.get_seg_ack() == talker->s_mgr.transition_seq)
+ {
+ DebugMessage(DEBUG_STREAM_STATE, "accepting transition!\n");
+ talker->set_tcp_state(talker->s_mgr.state_queue);
+ talker->s_mgr.state_queue = TcpStreamTracker::TCP_STATE_NONE;
+ }
+ }
- trk->set_splitter(ss);
-}
+ // handle data in the segment
+ handle_data_segment(tsd);
-StreamSplitter* TcpSession::get_splitter(bool to_server)
-{
- if ( to_server )
- return server->splitter;
- else
- return client->splitter;
+ if ( handle_fin_recv(tsd) )
+ finalize_tcp_packet_processing(tsd);
}
void TcpSession::flush_server(Packet* p)
{
- server->flags |= TF_FORCE_FLUSH;
+ server->set_tf_flags(TF_FORCE_FLUSH);
// If rebuilt packet, don't flush now because we'll overwrite the packet being processed.
if ( p->packet_flags & PKT_REBUILT_STREAM )
if ( server->reassembler->flush_stream(p, PKT_FROM_SERVER) )
server->reassembler->purge_flushed_ackd( );
- server->flags &= ~TF_FORCE_FLUSH;
+ server->clear_tf_flags(TF_FORCE_FLUSH);
}
void TcpSession::flush_client(Packet* p)
{
- client->flags |= TF_FORCE_FLUSH;
+ client->set_tf_flags(TF_FORCE_FLUSH);
// If rebuilt packet, don't flush now because we'll overwrite the packet being processed.
if ( p->packet_flags & PKT_REBUILT_STREAM )
if ( client->reassembler->flush_stream(p, PKT_FROM_CLIENT) )
client->reassembler->purge_flushed_ackd( );
- client->flags &= ~TF_FORCE_FLUSH;
+ client->clear_tf_flags(TF_FORCE_FLUSH);
}
void TcpSession::flush_listener(Packet* p)
if ( dir != 0 )
{
- listener->flags |= TF_FORCE_FLUSH;
+ listener->set_tf_flags(TF_FORCE_FLUSH);
if ( listener->reassembler->flush_stream(p, dir) )
listener->reassembler->purge_flushed_ackd( );
- listener->flags &= ~TF_FORCE_FLUSH;
+ listener->clear_tf_flags(TF_FORCE_FLUSH);
}
}
if (dir != 0)
{
- talker->flags |= TF_FORCE_FLUSH;
+ talker->set_tf_flags(TF_FORCE_FLUSH);
if ( talker->reassembler->flush_stream(p, dir) )
talker->reassembler->purge_flushed_ackd( );
- talker->flags &= ~TF_FORCE_FLUSH;
+ talker->clear_tf_flags(TF_FORCE_FLUSH);
}
}
{
if (dir & SSN_DIR_FROM_CLIENT)
{
- if (server->flags & (TF_MISSING_PREV_PKT | TF_MISSING_PKT))
+ if ( server->get_tf_flags() & ( TF_MISSING_PREV_PKT | TF_MISSING_PKT ) )
return false;
}
- if (dir & SSN_DIR_FROM_SERVER)
+ if ( dir & SSN_DIR_FROM_SERVER )
{
- if (client->flags & (TF_MISSING_PREV_PKT | TF_MISSING_PKT))
+ if ( client->get_tf_flags() & ( TF_MISSING_PREV_PKT | TF_MISSING_PKT ) )
return false;
}
{
if (dir & SSN_DIR_FROM_CLIENT)
{
- if ((server->flags & TF_MISSING_PKT)
- && (server->flags & TF_MISSING_PREV_PKT))
+ if ( (server->get_tf_flags() & TF_MISSING_PKT)
+ && (server->get_tf_flags() & TF_MISSING_PREV_PKT))
return SSN_MISSING_BOTH;
- else if (server->flags & TF_MISSING_PREV_PKT)
+ else if (server->get_tf_flags() & TF_MISSING_PREV_PKT)
return SSN_MISSING_BEFORE;
- else if (server->flags & TF_MISSING_PKT)
+ else if (server->get_tf_flags() & TF_MISSING_PKT)
return SSN_MISSING_AFTER;
}
else if (dir & SSN_DIR_FROM_SERVER)
{
- if ((client->flags & TF_MISSING_PKT)
- && (client->flags & TF_MISSING_PREV_PKT))
+ if ((client->get_tf_flags() & TF_MISSING_PKT)
+ && (client->get_tf_flags() & TF_MISSING_PREV_PKT))
return SSN_MISSING_BOTH;
- else if (client->flags & TF_MISSING_PREV_PKT)
+ else if (client->get_tf_flags() & TF_MISSING_PREV_PKT)
return SSN_MISSING_BEFORE;
- else if (client->flags & TF_MISSING_PKT)
+ else if (client->get_tf_flags() & TF_MISSING_PKT)
return SSN_MISSING_AFTER;
}
{
if (dir & SSN_DIR_FROM_CLIENT)
{
- if (server->flags & TF_PKT_MISSED)
+ if (server->get_tf_flags() & TF_PKT_MISSED)
return true;
}
if (dir & SSN_DIR_FROM_SERVER)
{
- if (client->flags & TF_PKT_MISSED)
+ if (client->get_tf_flags() & TF_PKT_MISSED)
return true;
}
}
}
+static inline void set_window_scale(TcpTracker& talker, TcpTracker& listener,
+ TcpSegmentDescriptor& tsd)
+{
+ // scale the window. Only if BOTH client and server specified wscale option as part
+ // of 3-way handshake. This is per RFC 1323.
+ if ( ( talker.get_tf_flags() & TF_WSCALE ) && ( listener.get_tf_flags() & TF_WSCALE ) )
+ tsd.scale_seg_wnd(talker.get_wscale() );
+}
+
/*
* Main entry point for TCP
*/
DebugFormat((DEBUG_STREAM|DEBUG_STREAM_STATE),
"Got TCP Packet 0x%X:%d -> 0x%X:%d %s\nseq: 0x%X ack:0x%X dsize: %u\n",
p->ptrs.ip_api.get_src(), p->ptrs.sp, p->ptrs.ip_api.get_dst(), p->ptrs.dp, flagbuf,
- ntohl(p->ptrs.tcph->th_seq), ntohl(p->ptrs.tcph->th_ack), p->dsize);
+ p->ptrs.tcph->seq(), p->ptrs.tcph->ack(), p->dsize);
);
// FIXIT-L can't get here without protocol being set to TCP, is this really needed??
}
TcpSegmentDescriptor tsd(flow, p, tel);
- if (!lws_init)
- {
- // FIXIT - should only do ths once...
- if (config == nullptr )
- {
- config = get_tcp_cfg(flow->ssn_server);
- require_3whs = config->require_3whs();
- client->set_require_3whs(require_3whs);
- server->set_require_3whs(require_3whs);
- }
- set_os_policy( );
-
- // FIXIT most of this now looks out of place or redundant
- if ( require_3whs )
- {
- if (p->ptrs.tcph->is_syn_only())
- {
- /* SYN only */
- flow->session_state = STREAM_STATE_SYN;
- }
- else
- {
- // If we're within the "startup" window, try to handle
- // this packet as midstream pickup -- allows for
- // connections that already existed before snort started.
- if (config->midstream_allowed(p))
- goto midstream_pickup_allowed;
-
- // Do nothing with this packet since we require a 3-way ;)
- DEBUG_WRAP(
- DebugMessage(DEBUG_STREAM_STATE,
- "Stream: Requiring 3-way Handshake, but failed to retrieve session"
- " object for non SYN packet.\n");
- );
- if ( !p->ptrs.tcph->is_syn_only() && !p->ptrs.tcph->is_rst() && !no_3whs )
- {
- tel->EventNo3whs();
- no_3whs = true;
- }
-#ifdef REG_TEST
- S5TraceTCP(p, flow, &tsd, 1);
-#endif
- return 0;
- }
- }
- else
- {
-midstream_pickup_allowed:
- if ( !p->ptrs.tcph->is_syn_ack()
- && !p->dsize
- && !(tsd.has_wscale() & TF_WSCALE) )
- {
-#ifdef REG_TEST
- S5TraceTCP(p, flow, &tsd, 1);
-#endif
- return 0;
- }
+ if (config == nullptr )
+ config = get_tcp_cfg(flow->ssn_server);
- if (p->ptrs.tcph->is_syn())
- flow->session_state |= STREAM_STATE_SYN;
- }
- lws_init = true;
- }
+ set_os_policy( );
// Check if the session is expired. Should be done before we do something with
// the packet...Insert a packet, or handle state change SYN, FIN, RST, etc.
}
// FIXIT - need to do something here to handle check for need to swap trackers
- new_ssn = false;
- if ( tsm.eval(tsd, *server) )
- tsm.eval(tsd, *client);
-
// FIXIT - this should change once tcp sm fully implemented
pkt_action_mask = ACTION_NOTHING;
- tel->clear_tcp_events();
+ tel.clear_tcp_events();
+
+ // process thru state machine...talker first
+ if ( p->packet_flags & PKT_FROM_CLIENT )
+ {
+ update_session_on_client_packet(tsd);
+ DEBUG_WRAP(t = "Server"; l = "Client");
+ }
+ else
+ {
+ update_session_on_server_packet(tsd);
+ DEBUG_WRAP(t = "Server"; l = "Client");
+ }
+
+ DebugFormat(DEBUG_STREAM_STATE, " %s [talker] state: %s\n", t,
+ tcp_state_names[talker->get_tcp_state()]);
+ DebugFormat(DEBUG_STREAM_STATE, " %s state: %s(%d)\n", l,
+ tcp_state_names[listener->get_tcp_state()], listener->get_tcp_state());
+
+ update_ignored_session(tsd);
+ // FIXIT - temp hack...move this to state handlers...
+ if ( listener->get_tcp_state() >= TcpStreamTracker::TCP_ESTABLISHED )
+ pkt_action_mask |= listener->normalizer->handle_paws(tsd);
+ set_window_scale(*talker, *listener, tsd);
+
+ if ( ( flow->get_session_flags() & SSNFLAG_RESET )
+ && !handle_syn_on_reset_session(tsd) )
+ return false;
+
+ if ( tsm.eval(tsd, *talker) )
+ tsm.eval(tsd, *listener);
+ else
+ {
+ S5TraceTCP(p, flow, &tsd, 1);
+ return 0;
+ }
- if ( tcp_init || tsd.get_pkt()->dsize)
+ if ( tcp_init || tsd.get_seg_len())
process_tcp_packet(tsd);
// FIXIT - end
- tel->log_tcp_events();
+ tel.log_tcp_events();
DebugMessage(DEBUG_STREAM_STATE,
"Finished Stream TCP cleanly!\n---------------------------------------------------\n");
void set_splitter(bool, StreamSplitter*) override;
StreamSplitter* get_splitter(bool) override;
- void init_new_tcp_session(TcpSegmentDescriptor& tsd);
- void update_session_state(const tcp::TCPHdr* tcph, TcpSegmentDescriptor& tsd);
-
void update_direction(char dir, const sfip_t*, uint16_t port) override;
bool add_alert(Packet*, uint32_t gid, uint32_t sid) override;
static void set_memcap(class Memcap&);
static void sinit(void);
static void sterm(void);
- void update_session_on_server_packet(const tcp::TCPHdr* tcph, TcpSegmentDescriptor& tsd);
- void update_session_on_client_packet(TcpSegmentDescriptor& tsd);
- bool handle_syn_on_reset_session(const tcp::TCPHdr* tcph, TcpSegmentDescriptor& tsd);
- void update_ignored_session(TcpSegmentDescriptor& tsd);
- TcpEventLogger* tel;
- TcpStreamConfig* config;
- TcpTracker* client;
- TcpTracker* server;
- uint8_t ecn;
- bool lws_init;
- bool tcp_init;
+ void init_new_tcp_session(TcpSegmentDescriptor&);
+ void update_timestamp_tracking(TcpSegmentDescriptor&);
+ void update_session_on_syn_ack(void);
+ void update_session_on_ack(void);
+ void update_session_on_server_packet(TcpSegmentDescriptor&);
+ void update_session_on_client_packet(TcpSegmentDescriptor&);
+ void update_session_on_rst(TcpSegmentDescriptor&, bool);
+ bool handle_syn_on_reset_session(TcpSegmentDescriptor&);
+ void handle_data_on_syn(TcpSegmentDescriptor&);
+ void handle_fin_recv_in_fw1(TcpSegmentDescriptor&);
+ bool handle_fin_recv(TcpSegmentDescriptor&);
+ void finalize_tcp_packet_processing(TcpSegmentDescriptor&);
+
+ void update_ignored_session(TcpSegmentDescriptor&);
+
+ void generate_no_3whs_event(void)
+ {
+ if ( !no_3whs )
+ {
+ tel.EventNo3whs();
+ no_3whs = true;
+ }
+ }
- int32_t ingress_index; /* Index of the inbound interface. */
- int32_t ingress_group; /* Index of the inbound group. */
- int32_t egress_index; /* Index of the outbound interface. */
- int32_t egress_group; /* Index of the outbound group. */
- uint32_t daq_flags; /* Flags for the packet (DAQ_PKT_FLAG_*) */
- uint16_t address_space_id;
+ void set_pkt_action_flag(uint32_t flag)
+ {
+ pkt_action_mask |= flag;
+ }
- uint32_t pkt_action_mask;
- bool require_3whs;
- bool no_3whs;
+ void update_paws_timestamps(TcpSegmentDescriptor&);
+ void check_for_session_hijack(TcpSegmentDescriptor&);
+ void handle_data_segment(TcpSegmentDescriptor&);
- // FIXIT - deprecate this once tcp state machine is fully implemented
- bool new_ssn;
+ TcpTracker* client;
+ TcpTracker* server;
+ TcpEventLogger tel;
+ TcpStreamConfig* config = nullptr;
+ bool lws_init = false;
+ bool tcp_init = false;
+ uint8_t ecn = 0;
+ int32_t ingress_index = 0;
+ int32_t ingress_group = 0;
+ int32_t egress_index = 0;
+ int32_t egress_group = 0;
+ uint32_t daq_flags = 0;
+ uint16_t address_space_id = 0;
+ uint32_t pkt_action_mask = ACTION_NOTHING;
private:
void EndOfFileHandle(Packet* p);
- bool flow_exceeds_config_thresholds(TcpTracker* rcv, TcpSegmentDescriptor& tsd);
- void process_tcp_stream(TcpTracker* rcv, TcpSegmentDescriptor& tsd);
- int process_tcp_data(TcpTracker* listener, TcpSegmentDescriptor& tsd);
+ bool flow_exceeds_config_thresholds(TcpTracker*, TcpSegmentDescriptor&);
+ void process_tcp_stream(TcpTracker*, TcpSegmentDescriptor&);
+ int process_tcp_data(TcpTracker*, TcpSegmentDescriptor&);
void process_tcp_packet(TcpSegmentDescriptor&);
- void FinishServerInit(TcpSegmentDescriptor& tsd);
+ void FinishServerInit(TcpSegmentDescriptor&);
void swap_trackers(void);
void NewTcpSessionOnSyn(TcpSegmentDescriptor&);
void clear_session(int freeApplicationData);
int process_dis(Packet*);
- void handle_data_on_syn(const tcp::TCPHdr* tcph, TcpSegmentDescriptor& tsd);
+ void update_on_3whs_complete(TcpSegmentDescriptor&);
- TcpTracker* talker;
- TcpTracker* listener;
+ bool no_3whs = false;
+ TcpTracker* talker = nullptr;
+ TcpTracker* listener = nullptr;
TcpStateMachine tsm;
};
#include "catch/catch.hpp"
#endif
-TcpStateCloseWait::TcpStateCloseWait(TcpStateMachine& tsm, TcpSession& session) :
- TcpStateHandler(TcpStreamTracker::TCP_CLOSE_WAIT, tsm), session(session)
+TcpStateCloseWait::TcpStateCloseWait(TcpStateMachine& tsm, TcpSession& ssn) :
+ TcpStateHandler(TcpStreamTracker::TCP_CLOSE_WAIT, tsm), session(ssn)
{
}
bool TcpStateCloseWait::syn_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
- return default_state_action(tsd, trk, __func__);
+ trk.s_mgr.sub_state |= SUB_SYN_SENT;
+
+ return default_state_action(tsd, trk);
}
bool TcpStateCloseWait::syn_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
+
+ trk.normalizer->ecn_tracker(tsd.get_tcph(), session.config->require_3whs() );
+
+ if ( tsd.get_seg_len() )
+ session.handle_data_on_syn(tsd);
- return default_state_action(tsd, trk, __func__);
+ return default_state_action(tsd, trk);
}
bool TcpStateCloseWait::syn_ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
- return default_state_action(tsd, trk, __func__);
+ trk.s_mgr.sub_state |= ( SUB_SYN_SENT | SUB_ACK_SENT );
+
+ return default_state_action(tsd, trk);
}
bool TcpStateCloseWait::syn_ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
- return default_state_action(tsd, trk, __func__);
+ return default_state_action(tsd, trk);
}
bool TcpStateCloseWait::ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
+
+ trk.update_tracker_ack_sent(tsd);
- return default_state_action(tsd, trk, __func__);
+ return default_state_action(tsd, trk);
}
bool TcpStateCloseWait::ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
+
+ trk.update_tracker_ack_recv(tsd);
- return default_state_action(tsd, trk, __func__);
+ return default_state_action(tsd, trk);
}
bool TcpStateCloseWait::data_seg_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
- return default_state_action(tsd, trk, __func__);
+ trk.update_tracker_ack_sent(tsd);
+
+ return default_state_action(tsd, trk);
}
bool TcpStateCloseWait::data_seg_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
+
+ trk.update_tracker_ack_recv(tsd);
- return default_state_action(tsd, trk, __func__);
+ return default_state_action(tsd, trk);
}
bool TcpStateCloseWait::fin_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
+
+ trk.update_tracker_ack_sent(tsd);
- return default_state_action(tsd, trk, __func__);
+ return default_state_action(tsd, trk);
}
bool TcpStateCloseWait::fin_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
- return default_state_action(tsd, trk, __func__);
+ trk.update_tracker_ack_recv(tsd);
+
+ return default_state_action(tsd, trk);
}
bool TcpStateCloseWait::rst_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
- return default_state_action(tsd, trk, __func__);
+ return default_state_action(tsd, trk);
}
bool TcpStateCloseWait::rst_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
-
- return default_state_action(tsd, trk, __func__);
+ auto& trk = static_cast< TcpTracker& >( tracker );
+
+ if ( trk.update_on_rst_recv(tsd) )
+ {
+ session.update_session_on_rst(tsd, true);
+ session.update_perf_base_state(TcpStreamTracker::TCP_CLOSING);
+ session.set_pkt_action_flag(ACTION_RST);
+ }
+ else
+ {
+ session.tel.set_tcp_event(EVENT_BAD_RST);
+ }
+
+ return default_state_action(tsd, trk);
}
#include "tcp_module.h"
#include "tcp_tracker.h"
#include "tcp_session.h"
+#include "tcp_normalizer.h"
#include "tcp_state_closed.h"
#ifdef UNIT_TEST
bool TcpStateClosed::syn_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- return default_state_action(tsd, tracker, __func__);
+ auto& trk = static_cast< TcpTracker& >( tracker );
+ Flow* flow = tsd.get_flow();
+
+ trk.s_mgr.sub_state |= SUB_SYN_SENT;
+
+ return default_state_action(tsd, tracker);
}
bool TcpStateClosed::syn_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- return default_state_action(tsd, tracker, __func__);
+ auto& trk = static_cast< TcpTracker& >( tracker );
+
+ trk.normalizer->ecn_tracker(tsd.get_tcph(), session.config->require_3whs() );
+ if ( tsd.get_seg_len() )
+ session.handle_data_on_syn(tsd);
+
+ return default_state_action(tsd, tracker);
}
bool TcpStateClosed::syn_ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- return default_state_action(tsd, tracker, __func__);
+ auto& trk = static_cast< TcpTracker& >( tracker );
+
+ trk.s_mgr.sub_state |= ( SUB_SYN_SENT | SUB_ACK_SENT );
+
+ return default_state_action(tsd, tracker);
}
bool TcpStateClosed::syn_ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- return default_state_action(tsd, tracker, __func__);
+ auto& trk = static_cast< TcpTracker& >( tracker );
+
+ return default_state_action(tsd, tracker);
}
bool TcpStateClosed::ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- return default_state_action(tsd, tracker, __func__);
+ auto& trk = static_cast< TcpTracker& >( tracker );
+
+ trk.update_tracker_ack_sent(tsd);
+
+ return default_state_action(tsd, tracker);
}
bool TcpStateClosed::ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- return default_state_action(tsd, tracker, __func__);
+ auto& trk = static_cast< TcpTracker& >( tracker );
+
+ trk.update_tracker_ack_recv(tsd);
+
+ return default_state_action(tsd, tracker);
}
bool TcpStateClosed::data_seg_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- return default_state_action(tsd, tracker, __func__);
+ auto& trk = static_cast< TcpTracker& >( tracker );
+
+ trk.update_tracker_ack_sent(tsd);
+
+ return default_state_action(tsd, tracker);
}
bool TcpStateClosed::data_seg_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- return default_state_action(tsd, tracker, __func__);
+ auto& trk = static_cast< TcpTracker& >( tracker );
+
+ trk.update_tracker_ack_recv(tsd);
+
+ return default_state_action(tsd, tracker);
}
bool TcpStateClosed::fin_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- return default_state_action(tsd, tracker, __func__);
+ auto& trk = static_cast< TcpTracker& >( tracker );
+
+ trk.update_tracker_ack_sent(tsd);
+
+ return default_state_action(tsd, tracker);
}
bool TcpStateClosed::fin_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- return default_state_action(tsd, tracker, __func__);
+ auto& trk = static_cast< TcpTracker& >( tracker );
+
+ trk.update_tracker_ack_recv(tsd);
+
+ return default_state_action(tsd, tracker);
}
bool TcpStateClosed::rst_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- return default_state_action(tsd, tracker, __func__);
+ auto& trk = static_cast< TcpTracker& >( tracker );
+
+ return default_state_action(tsd, tracker);
}
bool TcpStateClosed::rst_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- return default_state_action(tsd, tracker, __func__);
+ auto& trk = static_cast< TcpTracker& >( tracker );
+
+ if ( trk.update_on_rst_recv(tsd) )
+ {
+ session.update_session_on_rst(tsd, false);
+ session.update_perf_base_state(TcpStreamTracker::TCP_CLOSING);
+ session.set_pkt_action_flag(ACTION_RST);
+ }
+ else
+ {
+ session.tel.set_tcp_event(EVENT_BAD_RST);
+ }
+
+ return default_state_action(tsd, tracker);
}
#ifdef FOO // FIXIT - UNIT_TEST need work!!
#include "catch/catch.hpp"
#endif
-TcpStateClosing::TcpStateClosing(TcpStateMachine& tsm, TcpSession& session) :
- TcpStateHandler(TcpStreamTracker::TCP_CLOSING, tsm), session(session)
+TcpStateClosing::TcpStateClosing(TcpStateMachine& tsm, TcpSession& ssn) :
+ TcpStateHandler(TcpStreamTracker::TCP_CLOSING, tsm), session(ssn)
{
}
bool TcpStateClosing::syn_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
- return default_state_action(tsd, trk, __func__);
+ trk.s_mgr.sub_state |= SUB_SYN_SENT;
+
+ return default_state_action(tsd, trk);
}
bool TcpStateClosing::syn_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
+
+ trk.normalizer->ecn_tracker(tsd.get_tcph(), session.config->require_3whs() );
+ if ( tsd.get_seg_len() )
+ session.handle_data_on_syn(tsd);
- return default_state_action(tsd, trk, __func__);
+ return default_state_action(tsd, trk);
}
bool TcpStateClosing::syn_ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
+
+ trk.s_mgr.sub_state |= ( SUB_SYN_SENT | SUB_ACK_SENT );
- return default_state_action(tsd, trk, __func__);
+ return default_state_action(tsd, trk);
}
bool TcpStateClosing::syn_ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
- return default_state_action(tsd, trk, __func__);
+ return default_state_action(tsd, trk);
}
bool TcpStateClosing::ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
- return default_state_action(tsd, trk, __func__);
+ trk.update_tracker_ack_sent(tsd);
+
+ return default_state_action(tsd, trk);
}
bool TcpStateClosing::ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
+
+ trk.update_tracker_ack_recv(tsd);
+ if ( SEQ_GEQ(tsd.get_end_seq(), trk.r_nxt_ack) )
+ trk.set_tcp_state(TcpStreamTracker::TCP_TIME_WAIT);
- return default_state_action(tsd, trk, __func__);
+ return default_state_action(tsd, trk);
}
bool TcpStateClosing::data_seg_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
- return default_state_action(tsd, trk, __func__);
+ trk.update_tracker_ack_sent(tsd);
+
+ return default_state_action(tsd, trk);
}
bool TcpStateClosing::data_seg_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
+
+ trk.update_tracker_ack_recv(tsd);
+ if ( SEQ_GEQ(tsd.get_end_seq(), trk.r_nxt_ack) )
+ trk.set_tcp_state(TcpStreamTracker::TCP_TIME_WAIT);
- return default_state_action(tsd, trk, __func__);
+ return default_state_action(tsd, trk);
}
bool TcpStateClosing::fin_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
+
+ trk.update_tracker_ack_sent(tsd);
- return default_state_action(tsd, trk, __func__);
+ return default_state_action(tsd, trk);
}
bool TcpStateClosing::fin_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
- return default_state_action(tsd, trk, __func__);
+ trk.update_tracker_ack_recv(tsd);
+ if ( SEQ_GEQ(tsd.get_end_seq(), trk.r_nxt_ack) )
+ trk.set_tcp_state(TcpStreamTracker::TCP_TIME_WAIT);
+
+ return default_state_action(tsd, trk);
}
bool TcpStateClosing::rst_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
- return default_state_action(tsd, trk, __func__);
+ return default_state_action(tsd, trk);
}
bool TcpStateClosing::rst_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
-
- return default_state_action(tsd, trk, __func__);
+ auto& trk = static_cast< TcpTracker& >( tracker );
+
+ if ( trk.update_on_rst_recv(tsd) )
+ {
+ session.update_session_on_rst(tsd, true);
+ session.update_perf_base_state(TcpStreamTracker::TCP_CLOSING);
+ session.set_pkt_action_flag(ACTION_RST);
+ }
+ else
+ {
+ session.tel.set_tcp_event(EVENT_BAD_RST);
+ }
+
+ return default_state_action(tsd, trk);
}
#include "tcp_normalizer.h"
#include "tcp_state_established.h"
-TcpStateEstablished::TcpStateEstablished(TcpStateMachine& tsm, TcpSession& session) :
- TcpStateHandler(TcpStreamTracker::TCP_ESTABLISHED, tsm), session(session)
+TcpStateEstablished::TcpStateEstablished(TcpStateMachine& tsm, TcpSession& ssn) :
+ TcpStateHandler(TcpStreamTracker::TCP_ESTABLISHED, tsm), session(ssn)
{
}
bool TcpStateEstablished::syn_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
- return default_state_action(tsd, trk, __func__);
+ trk.s_mgr.sub_state |= SUB_SYN_SENT;
+
+ return default_state_action(tsd, trk);
}
bool TcpStateEstablished::syn_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
- return default_state_action(tsd, trk, __func__);
+ trk.normalizer->ecn_tracker(tsd.get_tcph(), session.config->require_3whs() );
+ return default_state_action(tsd, trk);
}
bool TcpStateEstablished::syn_ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
+
+ if ( session.config->midstream_allowed(tsd.get_pkt()) )
+ {
+ session.update_session_on_syn_ack( );
+ }
+
+ if ( trk.is_server_tracker() )
+ trk.normalizer->ecn_tracker(tsd.get_tcph(), session.config->require_3whs() );
- return default_state_action(tsd, trk, __func__);
+ return default_state_action(tsd, trk);
}
bool TcpStateEstablished::syn_ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
- return default_state_action(tsd, trk, __func__);
+ return default_state_action(tsd, trk);
}
bool TcpStateEstablished::ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
- return default_state_action(tsd, trk, __func__);
+ trk.update_tracker_ack_sent(tsd);
+
+ return default_state_action(tsd, trk);
}
bool TcpStateEstablished::ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
+
+ trk.update_tracker_ack_recv(tsd);
- return default_state_action(tsd, trk, __func__);
+ return default_state_action(tsd, trk);
}
bool TcpStateEstablished::data_seg_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
- return default_state_action(tsd, trk, __func__);
+ trk.update_tracker_ack_sent(tsd);
+
+ return default_state_action(tsd, trk);
}
bool TcpStateEstablished::data_seg_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
+
+ trk.update_tracker_ack_recv(tsd);
- return default_state_action(tsd, trk, __func__);
+ return default_state_action(tsd, trk);
}
bool TcpStateEstablished::fin_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
+
+ trk.update_tracker_ack_sent(tsd);
- return default_state_action(tsd, trk, __func__);
+ return default_state_action(tsd, trk);
}
bool TcpStateEstablished::fin_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
- return default_state_action(tsd, trk, __func__);
+ trk.update_tracker_ack_recv(tsd);
+
+ return default_state_action(tsd, trk);
}
bool TcpStateEstablished::rst_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
- return default_state_action(tsd, trk, __func__);
+ return default_state_action(tsd, trk);
}
bool TcpStateEstablished::rst_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
-
- return default_state_action(tsd, trk, __func__);
+ auto& trk = static_cast< TcpTracker& >( tracker );
+
+ if ( trk.update_on_rst_recv(tsd) )
+ {
+ session.update_session_on_rst(tsd, false);
+ session.update_perf_base_state(TcpStreamTracker::TCP_CLOSING);
+ session.set_pkt_action_flag(ACTION_RST);
+ }
+ else
+ {
+ session.tel.set_tcp_event(EVENT_BAD_RST);
+ }
+
+ return default_state_action(tsd, trk);
}
bool TcpStateFinWait1::syn_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
- return default_state_action(tsd, trk, __func__);
+ trk.s_mgr.sub_state |= SUB_SYN_SENT;
+
+ return default_state_action(tsd, trk);
}
bool TcpStateFinWait1::syn_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
+
+ trk.normalizer->ecn_tracker(tsd.get_tcph(), session.config->require_3whs() );
+ if ( tsd.get_seg_len() )
+ session.handle_data_on_syn(tsd);
- return default_state_action(tsd, trk, __func__);
+ return default_state_action(tsd, trk);
}
bool TcpStateFinWait1::syn_ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
+
+ trk.s_mgr.sub_state |= ( SUB_SYN_SENT | SUB_ACK_SENT );
- return default_state_action(tsd, trk, __func__);
+ return default_state_action(tsd, trk);
}
bool TcpStateFinWait1::syn_ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
- return default_state_action(tsd, trk, __func__);
+ return default_state_action(tsd, trk);
}
bool TcpStateFinWait1::ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
- return default_state_action(tsd, trk, __func__);
+ trk.update_tracker_ack_sent(tsd);
+
+ return default_state_action(tsd, trk);
}
bool TcpStateFinWait1::ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
+
+ trk.update_tracker_ack_recv(tsd);
+ check_for_window_slam(tsd, trk);
- return default_state_action(tsd, trk, __func__);
+ return default_state_action(tsd, trk);
}
bool TcpStateFinWait1::data_seg_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
+
+ trk.update_tracker_ack_sent(tsd);
- return default_state_action(tsd, trk, __func__);
+ return default_state_action(tsd, trk);
}
bool TcpStateFinWait1::data_seg_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
- return default_state_action(tsd, trk, __func__);
+ trk.update_tracker_ack_recv(tsd);
+ check_for_window_slam(tsd, trk);
+
+ return default_state_action(tsd, trk);
}
bool TcpStateFinWait1::fin_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
+
+ trk.update_tracker_ack_sent(tsd);
- return default_state_action(tsd, trk, __func__);
+ return default_state_action(tsd, trk);
}
bool TcpStateFinWait1::fin_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
+
+ trk.update_tracker_ack_recv(tsd);
- return default_state_action(tsd, trk, __func__);
+ if ( check_for_window_slam(tsd, trk) )
+ session.handle_fin_recv_in_fw1(tsd);
+
+ return default_state_action(tsd, trk);
}
bool TcpStateFinWait1::rst_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
- return default_state_action(tsd, trk, __func__);
+ return default_state_action(tsd, trk);
}
bool TcpStateFinWait1::rst_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
+
+ if ( trk.update_on_rst_recv(tsd) )
+ {
+ session.update_session_on_rst(tsd, true);
+ session.update_perf_base_state(TcpStreamTracker::TCP_CLOSING);
+ session.set_pkt_action_flag(ACTION_RST);
+ }
+ else
+ {
+ session.tel.set_tcp_event(EVENT_BAD_RST);
+ }
+
+ return default_state_action(tsd, trk);
+}
- return default_state_action(tsd, trk, __func__);
+bool TcpStateFinWait1::check_for_window_slam(TcpSegmentDescriptor& tsd, TcpTracker& trk)
+{
+ DebugFormat(DEBUG_STREAM_STATE, "tsd.ack %X >= listener->snd_nxt %X\n",
+ tsd.get_seg_ack(), trk.get_snd_nxt());
+
+ if ( SEQ_EQ(tsd.get_seg_ack(), trk.get_snd_nxt() ) )
+ {
+ if ( (trk.normalizer->get_os_policy() == StreamPolicy::OS_WINDOWS)
+ && (tsd.get_seg_wnd() == 0))
+ {
+ session.tel.set_tcp_event(EVENT_WINDOW_SLAM);
+ inc_tcp_discards();
+
+ if (trk.normalizer->packet_dropper(tsd, NORM_TCP_BLOCK))
+ {
+ session.set_pkt_action_flag(ACTION_BAD_PKT);
+ return false;
+ }
+ }
+
+ trk.set_tcp_state(TcpStreamTracker::TCP_FIN_WAIT2);
+
+ if ( trk.s_mgr.state_queue == TcpStreamTracker::TCP_CLOSING )
+ {
+ trk.s_mgr.state_queue = TcpStreamTracker::TCP_TIME_WAIT;
+ trk.s_mgr.transition_seq = tsd.get_end_seq();
+ trk.s_mgr.expected_flags = TH_ACK;
+ }
+ }
+
+ return true;
}
bool rst_recv(TcpSegmentDescriptor&, TcpStreamTracker&) override;
private:
+ bool check_for_window_slam(TcpSegmentDescriptor& tsd, TcpTracker& trk);
+
TcpSession& session;
};
#include "catch/catch.hpp"
#endif
-TcpStateFinWait2::TcpStateFinWait2(TcpStateMachine& tsm, TcpSession& session) :
- TcpStateHandler(TcpStreamTracker::TCP_FIN_WAIT2, tsm), session(session)
+TcpStateFinWait2::TcpStateFinWait2(TcpStateMachine& tsm, TcpSession& ssn) :
+ TcpStateHandler(TcpStreamTracker::TCP_FIN_WAIT2, tsm), session(ssn)
{
}
bool TcpStateFinWait2::syn_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
- return default_state_action(tsd, trk, __func__);
+ trk.s_mgr.sub_state |= SUB_SYN_SENT;
+
+ return default_state_action(tsd, trk);
}
bool TcpStateFinWait2::syn_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
+
+ trk.normalizer->ecn_tracker(tsd.get_tcph(), session.config->require_3whs() );
+ if ( tsd.get_seg_len() )
+ session.handle_data_on_syn(tsd);
- return default_state_action(tsd, trk, __func__);
+ return default_state_action(tsd, trk);
}
bool TcpStateFinWait2::syn_ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
- return default_state_action(tsd, trk, __func__);
+ trk.s_mgr.sub_state |= ( SUB_SYN_SENT | SUB_ACK_SENT );
+
+ return default_state_action(tsd, trk);
}
bool TcpStateFinWait2::syn_ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
- return default_state_action(tsd, trk, __func__);
+ return default_state_action(tsd, trk);
}
bool TcpStateFinWait2::ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
+
+ trk.update_tracker_ack_sent(tsd);
- return default_state_action(tsd, trk, __func__);
+ return default_state_action(tsd, trk);
}
bool TcpStateFinWait2::ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
-
- return default_state_action(tsd, trk, __func__);
+ auto& trk = static_cast< TcpTracker& >( tracker );
+
+ if ( SEQ_GT(tsd.get_seg_ack(), trk.get_snd_nxt() ) )
+ {
+ trk.normalizer->packet_dropper(tsd, NORM_TCP_BLOCK);
+ session.tel.set_tcp_event(EVENT_BAD_ACK);
+ session.set_pkt_action_flag(ACTION_BAD_PKT);
+ }
+ else
+ trk.update_tracker_ack_recv(tsd);
+
+ return default_state_action(tsd, trk);
}
bool TcpStateFinWait2::data_seg_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
+
+ trk.update_tracker_ack_sent(tsd);
- return default_state_action(tsd, trk, __func__);
+ return default_state_action(tsd, trk);
}
bool TcpStateFinWait2::data_seg_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
- return default_state_action(tsd, trk, __func__);
+ return default_state_action(tsd, trk);
}
bool TcpStateFinWait2::fin_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
- return default_state_action(tsd, trk, __func__);
+ return default_state_action(tsd, trk);
}
bool TcpStateFinWait2::fin_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
- return default_state_action(tsd, trk, __func__);
+ return default_state_action(tsd, trk);
}
bool TcpStateFinWait2::rst_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
- return default_state_action(tsd, trk, __func__);
+ return default_state_action(tsd, trk);
}
bool TcpStateFinWait2::rst_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
-
- return default_state_action(tsd, trk, __func__);
+ auto& trk = static_cast< TcpTracker& >( tracker );
+
+ if ( trk.update_on_rst_recv(tsd) )
+ {
+ session.update_session_on_rst(tsd, true);
+ session.update_perf_base_state(TcpStreamTracker::TCP_CLOSING);
+ session.set_pkt_action_flag(ACTION_RST);
+ }
+ else
+ {
+ session.tel.set_tcp_event(EVENT_BAD_RST);
+ }
+
+ return default_state_action(tsd, trk);
}
#include "catch/catch.hpp"
#endif
-TcpStateLastAck::TcpStateLastAck(TcpStateMachine& tsm, TcpSession& session) :
- TcpStateHandler(TcpStreamTracker::TCP_LAST_ACK, tsm), session(session)
+TcpStateLastAck::TcpStateLastAck(TcpStateMachine& tsm, TcpSession& ssn) :
+ TcpStateHandler(TcpStreamTracker::TCP_LAST_ACK, tsm), session(ssn)
{
}
bool TcpStateLastAck::syn_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
- return default_state_action(tsd, trk, __func__);
+ trk.s_mgr.sub_state |= SUB_SYN_SENT;
+
+ return default_state_action(tsd, trk);
}
bool TcpStateLastAck::syn_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
+
+ trk.normalizer->ecn_tracker(tsd.get_tcph(), session.config->require_3whs() );
+ if ( tsd.get_seg_len() )
+ session.handle_data_on_syn(tsd);
- return default_state_action(tsd, trk, __func__);
+ return default_state_action(tsd, trk);
}
bool TcpStateLastAck::syn_ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
+
+ trk.s_mgr.sub_state |= ( SUB_SYN_SENT | SUB_ACK_SENT );
- return default_state_action(tsd, trk, __func__);
+ return default_state_action(tsd, trk);
}
bool TcpStateLastAck::syn_ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
- return default_state_action(tsd, trk, __func__);
+ return default_state_action(tsd, trk);
}
bool TcpStateLastAck::ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
- return default_state_action(tsd, trk, __func__);
+ trk.update_tracker_ack_sent(tsd);
+
+ return default_state_action(tsd, trk);
}
bool TcpStateLastAck::ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
+
+ trk.update_tracker_ack_recv(tsd);
+ if ( SEQ_EQ(tsd.get_seg_ack(), trk.get_snd_nxt() ) )
+ trk.set_tcp_state(TcpStreamTracker::TCP_CLOSED);
- return default_state_action(tsd, trk, __func__);
+ return default_state_action(tsd, trk);
}
bool TcpStateLastAck::data_seg_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
- return default_state_action(tsd, trk, __func__);
+ trk.update_tracker_ack_sent(tsd);
+
+ return default_state_action(tsd, trk);
}
bool TcpStateLastAck::data_seg_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
+
+ trk.update_tracker_ack_recv(tsd);
+ if ( SEQ_EQ(tsd.get_seg_ack(), trk.get_snd_nxt() ) )
+ trk.set_tcp_state(TcpStreamTracker::TCP_CLOSED);
- return default_state_action(tsd, trk, __func__);
+ return default_state_action(tsd, trk);
}
bool TcpStateLastAck::fin_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
+
+ trk.update_tracker_ack_sent(tsd);
- return default_state_action(tsd, trk, __func__);
+ return default_state_action(tsd, trk);
}
bool TcpStateLastAck::fin_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
- return default_state_action(tsd, trk, __func__);
+ trk.update_tracker_ack_recv(tsd);
+ if ( SEQ_EQ(tsd.get_seg_ack(), trk.get_snd_nxt() ) )
+ trk.set_tcp_state(TcpStreamTracker::TCP_CLOSED);
+
+ return default_state_action(tsd, trk);
}
bool TcpStateLastAck::rst_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
- return default_state_action(tsd, trk, __func__);
+ return default_state_action(tsd, trk);
}
bool TcpStateLastAck::rst_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
-
- return default_state_action(tsd, trk, __func__);
+ auto& trk = static_cast< TcpTracker& >( tracker );
+
+ if ( trk.update_on_rst_recv(tsd) )
+ {
+ session.update_session_on_rst(tsd, false);
+ session.update_perf_base_state(TcpStreamTracker::TCP_CLOSING);
+ session.set_pkt_action_flag(ACTION_RST);
+ }
+ else
+ {
+ session.tel.set_tcp_event(EVENT_BAD_RST);
+ }
+
+ return default_state_action(tsd, trk);
}
bool TcpStateListen::syn_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
- return default_state_action(tsd, trk, __func__);
+ if ( session.config->require_3whs() || tsd.has_wscale() || ( tsd.get_seg_len() > 0 ) )
+ {
+ // FIXIT - do we need this check? only server goes into Listen state...
+ if ( tsd.get_pkt()->packet_flags & PKT_FROM_SERVER )
+ session.tel.set_tcp_event(EVENT_4WHS);
+ }
+
+ trk.s_mgr.sub_state |= SUB_SYN_SENT;
+
+ return default_state_action(tsd, trk);
}
bool TcpStateListen::syn_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
+
+ if ( true || session.config->require_3whs() || tsd.has_wscale() || ( tsd.get_seg_len() > 0 ) )
+ {
+ trk.init_on_syn_recv(tsd);
+ trk.normalizer->ecn_tracker(tsd.get_tcph(), session.config->require_3whs() );
+ if ( tsd.get_seg_len() )
+ session.handle_data_on_syn(tsd);
+ }
- return default_state_action(tsd, trk, __func__);
+ return default_state_action(tsd, trk);
}
bool TcpStateListen::syn_ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ Flow* flow = tsd.get_flow();
+ auto& trk = static_cast< TcpTracker& >( tracker );
- return default_state_action(tsd, trk, __func__);
+ flow->session_state |= ( STREAM_STATE_SYN | STREAM_STATE_SYN_ACK );
+
+ if ( session.config->midstream_allowed(tsd.get_pkt() ) )
+ {
+ trk.init_on_synack_sent(tsd);
+ trk.normalizer->ecn_tracker(tsd.get_tcph(), session.config->require_3whs() );
+ session.init_new_tcp_session(tsd);
+ }
+ else if ( session.config->require_3whs() )
+ {
+ session.generate_no_3whs_event();
+ return false;
+ }
+
+ return default_state_action(tsd, trk);
}
bool TcpStateListen::syn_ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
+
+ if ( !session.config->require_3whs() || session.config->midstream_allowed(tsd.get_pkt() ) )
+ {
+ trk.init_on_synack_recv(tsd);
+ }
+ else if ( session.config->require_3whs() )
+ {
+ session.generate_no_3whs_event();
+ return false;
+ }
- return default_state_action(tsd, trk, __func__);
+ return default_state_action(tsd, trk);
}
bool TcpStateListen::ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
- return default_state_action(tsd, trk, __func__);
+ if ( session.config->midstream_allowed(tsd.get_pkt() ) && ( tsd.has_wscale() ||
+ ( tsd.get_seg_len() > 0 ) ) )
+ {
+ Flow* flow = tsd.get_flow();
+
+ /* FIXIT: do we need to verify the ACK field is >= the seq of the SYN-ACK?
+ 3-way Handshake complete, create TCP session */
+ flow->session_state |= ( STREAM_STATE_ACK | STREAM_STATE_SYN_ACK |
+ STREAM_STATE_ESTABLISHED );
+ trk.init_on_3whs_ack_sent(tsd);
+ session.init_new_tcp_session(tsd);
+ session.update_perf_base_state(TcpStreamTracker::TCP_ESTABLISHED);
+ tcpStats.sessions_on_3way++;
+ }
+ else if ( session.config->require_3whs() )
+ {
+ session.generate_no_3whs_event();
+ return false;
+ }
+
+ return default_state_action(tsd, trk);
}
bool TcpStateListen::ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
+
+ if ( session.config->midstream_allowed(tsd.get_pkt() ) && ( tsd.has_wscale() ||
+ ( tsd.get_seg_len() > 0 ) ) )
+ {
+ Flow* flow = tsd.get_flow();
- return default_state_action(tsd, trk, __func__);
+ if ( !tsd.get_tcph()->is_rst() && ( flow->session_state & STREAM_STATE_SYN_ACK ) )
+ {
+ trk.init_on_3whs_ack_recv(tsd);
+ trk.normalizer->ecn_tracker(tsd.get_tcph(), session.config->require_3whs() );
+ }
+ }
+ else if ( session.config->require_3whs() )
+ {
+ session.generate_no_3whs_event();
+ return false;
+ }
+
+ return default_state_action(tsd, trk);
}
bool TcpStateListen::data_seg_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
+
+ if ( session.config->midstream_allowed(tsd.get_pkt() ) )
+ {
+ Flow* flow = tsd.get_flow();
- return default_state_action(tsd, trk, __func__);
+ flow->session_state |= STREAM_STATE_MIDSTREAM;
+ flow->set_session_flags(SSNFLAG_MIDSTREAM);
+
+ trk.init_on_data_seg_sent(tsd);
+ session.init_new_tcp_session(tsd);
+
+ if ( flow->session_state & STREAM_STATE_ESTABLISHED )
+ session.update_perf_base_state(TcpStreamTracker::TCP_ESTABLISHED);
+
+ tcpStats.sessions_on_data++;
+ }
+ else if ( session.config->require_3whs() )
+ {
+ session.generate_no_3whs_event();
+ return false;
+ }
+
+ return default_state_action(tsd, trk);
}
bool TcpStateListen::data_seg_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
+
+ if ( session.config->midstream_allowed(tsd.get_pkt() ) )
+ {
+ Flow* flow = tsd.get_flow();
- return default_state_action(tsd, trk, __func__);
+ flow->session_state |= STREAM_STATE_MIDSTREAM;
+ flow->set_session_flags(SSNFLAG_MIDSTREAM);
+ trk.init_on_data_seg_recv(tsd);
+ trk.normalizer->ecn_tracker(tsd.get_tcph(), session.config->require_3whs() );
+ }
+ else if ( session.config->require_3whs() )
+ {
+ session.generate_no_3whs_event();
+ return false;
+ }
+
+ return default_state_action(tsd, trk);
}
bool TcpStateListen::fin_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
+
+ if ( session.config->midstream_allowed(tsd.get_pkt() ) )
+ {
+ }
+ else if ( session.config->require_3whs() )
+ {
+ session.generate_no_3whs_event();
+ return false;
+ }
- return default_state_action(tsd, trk, __func__);
+ return default_state_action(tsd, trk);
}
bool TcpStateListen::fin_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
+
+ if ( session.config->midstream_allowed(tsd.get_pkt() ) )
+ {
+ // FIXIT - handle this
+ }
+ else if ( session.config->require_3whs() )
+ {
+ session.generate_no_3whs_event();
+ return false;
+ }
- return default_state_action(tsd, trk, __func__);
+ return default_state_action(tsd, trk);
}
bool TcpStateListen::rst_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
- return default_state_action(tsd, trk, __func__);
+ if ( session.config->midstream_allowed(tsd.get_pkt() ) )
+ {
+ }
+
+ return default_state_action(tsd, trk);
}
bool TcpStateListen::rst_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
+
+ if ( session.config->midstream_allowed(tsd.get_pkt() ) )
+ {
+ // FIXIT - handle this
+ }
- return default_state_action(tsd, trk, __func__);
+ return default_state_action(tsd, trk);
}
#include "stream/libtcp/stream_tcp_unit_test.h"
#endif
-TcpStateNone::TcpStateNone(TcpStateMachine& tsm, TcpSession& session) :
- TcpStateHandler(TcpStreamTracker::TCP_STATE_NONE, tsm), session(session)
+TcpStateNone::TcpStateNone(TcpStateMachine& tsm, TcpSession& ssn) :
+ TcpStateHandler(TcpStreamTracker::TCP_STATE_NONE, tsm), session(ssn)
{
}
bool TcpStateNone::syn_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
Flow* flow = tsd.get_flow();
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
flow->ssn_state.direction = FROM_CLIENT;
- flow->session_state |= STREAM_STATE_SYN;
- if ( trk.is_3whs_required() || ( tsd.has_wscale() & TF_WSCALE ) ||
- ( tsd.get_pkt()->dsize > 0 ) )
- {
- trk.init_on_syn_sent(tsd);
- session.init_new_tcp_session(tsd);
- tcpStats.sessions_on_syn++;
- }
+ flow->session_state |= STREAM_STATE_SYN;
+ trk.init_on_syn_sent(tsd);
+ session.init_new_tcp_session(tsd);
- return true;
+ return default_state_action(tsd, trk);
}
bool TcpStateNone::syn_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
-
- if ( trk.is_3whs_required() || ( tsd.has_wscale() & TF_WSCALE ) ||
- ( tsd.get_pkt()->dsize > 0 ) )
- {
- trk.init_on_syn_recv(tsd);
- trk.normalizer->ecn_tracker(tsd.get_tcph(), trk.is_3whs_required() );
- }
+ auto& trk = static_cast< TcpTracker& >( tracker );
- return true;
+ // FIXIT - syn received on undefined client, figure this out and do the right thing
+ return default_state_action(tsd, trk);
}
bool TcpStateNone::syn_ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
Flow* flow = tsd.get_flow();
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
- /* SYN-ACK from server */
- if ( ( flow->session_state == STREAM_STATE_NONE)
- || ( flow->get_session_flags() & SSNFLAG_RESET ) )
- {
- DebugMessage(DEBUG_STREAM_STATE,
- "Stream SYN|ACK PACKET, set session directioon to FROM_SERVER.\n");
- flow->ssn_state.direction = FROM_SERVER;
- }
-
- flow->session_state |= STREAM_STATE_SYN_ACK;
-
- if ( !trk.is_3whs_required() || session.config->midstream_allowed(tsd.get_pkt()) )
+ if ( !session.config->require_3whs() || session.config->midstream_allowed(tsd.get_pkt() ) )
{
+ flow->session_state |= ( STREAM_STATE_SYN | STREAM_STATE_SYN_ACK );
trk.init_on_synack_sent(tsd);
session.init_new_tcp_session(tsd);
- tcpStats.sessions_on_syn_ack++;
+ trk.normalizer->ecn_tracker(tsd.get_tcph(), session.config->require_3whs() );
+ }
+ else if ( session.config->require_3whs() )
+ {
+ session.generate_no_3whs_event();
+ return false;
}
- return true;
+ return default_state_action(tsd, trk);
}
bool TcpStateNone::syn_ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
- if ( !trk.is_3whs_required() || session.config->midstream_allowed(tsd.get_pkt()) )
+ if ( session.config->midstream_allowed(tsd.get_pkt() ) )
{
trk.init_on_synack_recv(tsd);
+ trk.normalizer->ecn_tracker(tsd.get_tcph(), session.config->require_3whs() );
+ }
+ else if ( session.config->require_3whs() )
+ {
+ session.generate_no_3whs_event();
+ return false;
}
- trk.normalizer->ecn_tracker(tsd.get_tcph(), trk.is_3whs_required() );
-
- return true;
+ return default_state_action(tsd, trk);
}
bool TcpStateNone::ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- Flow* flow = tsd.get_flow();
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
- if ( !tsd.get_tcph()->is_rst() && ( flow->session_state & STREAM_STATE_SYN_ACK ) )
+ if ( session.config->midstream_allowed(tsd.get_pkt() ) && ( tsd.has_wscale() ||
+ ( tsd.get_seg_len() > 0 ) ) )
{
+ Flow* flow = tsd.get_flow();
+
/* FIXIT: do we need to verify the ACK field is >= the seq of the SYN-ACK?
3-way Handshake complete, create TCP session */
- flow->session_state |= ( STREAM_STATE_ACK | STREAM_STATE_ESTABLISHED );
+ flow->session_state |= ( STREAM_STATE_ACK | STREAM_STATE_SYN_ACK |
+ STREAM_STATE_ESTABLISHED );
trk.init_on_3whs_ack_sent(tsd);
session.init_new_tcp_session(tsd);
session.update_perf_base_state(TcpStreamTracker::TCP_ESTABLISHED);
tcpStats.sessions_on_3way++;
}
+ else if ( session.config->require_3whs() )
+ {
+ session.generate_no_3whs_event();
+ return false;
+ }
- return true;
+ return default_state_action(tsd, trk);
}
bool TcpStateNone::ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- Flow* flow = tsd.get_flow();
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
+
+ if ( session.config->midstream_allowed(tsd.get_pkt() ) && ( tsd.has_wscale() ||
+ ( tsd.get_seg_len() > 0 ) ) )
+ {
+ Flow* flow = tsd.get_flow();
- if ( !tsd.get_tcph()->is_rst() && ( flow->session_state & STREAM_STATE_SYN_ACK ) )
+ if ( !tsd.get_tcph()->is_rst() && ( flow->session_state & STREAM_STATE_SYN_ACK ) )
+ {
+ trk.init_on_3whs_ack_recv(tsd);
+ trk.normalizer->ecn_tracker(tsd.get_tcph(), session.config->require_3whs() );
+ }
+ }
+ else if ( session.config->require_3whs() )
{
- trk.init_on_3whs_ack_recv(tsd);
- trk.normalizer->ecn_tracker(tsd.get_tcph(), trk.is_3whs_required() );
+ session.generate_no_3whs_event();
+ return false;
}
- return true;
+ return default_state_action(tsd, trk);
}
bool TcpStateNone::data_seg_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
- // FIXIT - are these necessary (see checks in TcpSession::process, but should get rid of those
- if ( !trk.is_3whs_required() || session.config->midstream_allowed(tsd.get_pkt()) )
+ if ( session.config->midstream_allowed(tsd.get_pkt() ) )
{
Flow* flow = tsd.get_flow();
flow->session_state |= STREAM_STATE_MIDSTREAM;
flow->set_session_flags(SSNFLAG_MIDSTREAM);
- if (tsd.get_pkt()->ptrs.sp > tsd.get_pkt()->ptrs.dp)
- {
- flow->ssn_state.direction = FROM_CLIENT;
- flow->set_session_flags(SSNFLAG_SEEN_CLIENT);
- }
- else
- {
- flow->ssn_state.direction = FROM_SERVER;
- flow->set_session_flags(SSNFLAG_SEEN_SERVER);
- }
-
trk.init_on_data_seg_sent(tsd);
session.init_new_tcp_session(tsd);
tcpStats.sessions_on_data++;
}
+ else if ( session.config->require_3whs() )
+ {
+ session.generate_no_3whs_event();
+ return false;
+ }
- return true;
+ return default_state_action(tsd, trk);
}
bool TcpStateNone::data_seg_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
- if ( !trk.is_3whs_required() || session.config->midstream_allowed(tsd.get_pkt()) )
+ if ( session.config->midstream_allowed(tsd.get_pkt() ) )
{
Flow* flow = tsd.get_flow();
flow->session_state |= STREAM_STATE_MIDSTREAM;
flow->set_session_flags(SSNFLAG_MIDSTREAM);
- if (tsd.get_pkt()->ptrs.sp > tsd.get_pkt()->ptrs.dp)
- {
- flow->ssn_state.direction = FROM_CLIENT;
- flow->set_session_flags(SSNFLAG_SEEN_CLIENT);
- }
- else
- {
- flow->ssn_state.direction = FROM_SERVER;
- flow->set_session_flags(SSNFLAG_SEEN_SERVER);
- }
-
trk.init_on_data_seg_recv(tsd);
- trk.normalizer->ecn_tracker(tsd.get_tcph(), trk.is_3whs_required() );
+ trk.normalizer->ecn_tracker(tsd.get_tcph(), session.config->require_3whs() );
+ }
+ else if ( session.config->require_3whs() )
+ {
+ session.generate_no_3whs_event();
+ return false;
}
- return true;
+ return default_state_action(tsd, trk);
}
bool TcpStateNone::fin_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
- return default_state_action(tsd, trk, __func__);
+ if ( session.config->midstream_allowed(tsd.get_pkt() ) )
+ {
+ // FIXIT - handle this
+ }
+ else if ( session.config->require_3whs() )
+ {
+ session.generate_no_3whs_event();
+ return false;
+ }
+
+ return default_state_action(tsd, trk);
}
bool TcpStateNone::fin_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
- return default_state_action(tsd, trk, __func__);
+ if ( session.config->midstream_allowed(tsd.get_pkt() ) )
+ {
+ // FIXIT - handle this
+ }
+ else if ( session.config->require_3whs() )
+ {
+ session.generate_no_3whs_event();
+ return false;
+ }
+
+ return default_state_action(tsd, trk);
}
bool TcpStateNone::rst_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
+
+ if ( session.config->midstream_allowed(tsd.get_pkt() ) )
+ {
+ // FIXIT - handle this
+ }
- return default_state_action(tsd, trk, __func__);
+ return default_state_action(tsd, trk);
}
bool TcpStateNone::rst_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
+
+ if ( session.config->midstream_allowed(tsd.get_pkt() ) )
+ {
+ // FIXIT - handle this
+ }
- return default_state_action(tsd, trk, __func__);
+ return default_state_action(tsd, trk);
}
#ifdef FOO // FIXIT - UNIT_TEST need work!!
#include "tcp_normalizer.h"
#include "tcp_state_syn_recv.h"
-TcpStateSynRecv::TcpStateSynRecv(TcpStateMachine& tsm, TcpSession& session) :
- TcpStateHandler(TcpStreamTracker::TCP_SYN_RECV, tsm), session(session)
+TcpStateSynRecv::TcpStateSynRecv(TcpStateMachine& tsm, TcpSession& ssn) :
+ TcpStateHandler(TcpStreamTracker::TCP_SYN_RECV, tsm), session(ssn)
{
}
bool TcpStateSynRecv::syn_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ Flow* flow = tsd.get_flow();
+ auto& trk = static_cast< TcpTracker& >( tracker );
- return default_state_action(tsd, trk, __func__);
+ trk.finish_server_init(tsd);
+ trk.normalizer->ecn_tracker(tsd.get_tcph(), session.config->require_3whs() );
+ session.update_timestamp_tracking(tsd);
+ if ( tsd.get_tcph()->are_flags_set(TH_ECE) &&
+ ( flow->get_session_flags() & SSNFLAG_ECN_CLIENT_QUERY ) )
+ flow->set_session_flags(SSNFLAG_ECN_SERVER_REPLY);
+
+ if ( tsd.get_pkt()->packet_flags & PKT_FROM_SERVER )
+ {
+ flow->set_session_flags(SSNFLAG_SEEN_SERVER);
+ session.tel.set_tcp_event(EVENT_4WHS);
+ }
+
+ trk.s_mgr.sub_state |= SUB_SYN_SENT;
+
+ return default_state_action(tsd, trk);
}
bool TcpStateSynRecv::syn_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
+
+ if ( tsd.get_seg_len() )
+ session.handle_data_on_syn(tsd);
- return default_state_action(tsd, trk, __func__);
+ return default_state_action(tsd, trk);
}
bool TcpStateSynRecv::syn_ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ Flow* flow = tsd.get_flow();
+ auto& trk = static_cast< TcpTracker& >( tracker );
- return default_state_action(tsd, trk, __func__);
+ // FIXIT - verify ack being sent is valid...
+ trk.finish_server_init(tsd);
+ trk.normalizer->ecn_tracker(tsd.get_tcph(), session.config->require_3whs() );
+ flow->session_state |= STREAM_STATE_SYN_ACK;
+
+ trk.s_mgr.sub_state |= ( SUB_SYN_SENT | SUB_ACK_SENT );
+
+ return default_state_action(tsd, trk);
}
bool TcpStateSynRecv::syn_ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
+
+ if ( trk.is_ack_valid(tsd.get_seg_ack() ) )
+ {
+ Flow* flow = tsd.get_flow();
+
+ trk.update_tracker_ack_recv(tsd);
+ trk.normalizer->ecn_tracker(tsd.get_tcph(), session.config->require_3whs() );
+ flow->set_session_flags(SSNFLAG_ESTABLISHED);
+ flow->session_state |= ( STREAM_STATE_ACK | STREAM_STATE_ESTABLISHED );
+ session.update_perf_base_state(TcpStreamTracker::TCP_ESTABLISHED);
+ trk.set_tcp_state(TcpStreamTracker::TCP_ESTABLISHED);
+ }
- return default_state_action(tsd, trk, __func__);
+ return default_state_action(tsd, trk);
}
bool TcpStateSynRecv::ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
- return default_state_action(tsd, trk, __func__);
+ if ( session.config->midstream_allowed(tsd.get_pkt()) )
+ {
+ session.update_session_on_ack( );
+ }
+ trk.s_mgr.sub_state |= SUB_ACK_SENT;
+
+ return default_state_action(tsd, trk);
}
bool TcpStateSynRecv::ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
+
+ if ( trk.is_ack_valid(tsd.get_seg_ack() ) )
+ {
+ trk.update_tracker_ack_recv(tsd);
+ tsd.get_pkt()->packet_flags |= PKT_STREAM_TWH;
+ session.update_perf_base_state(TcpStreamTracker::TCP_ESTABLISHED);
+ trk.set_tcp_state(TcpStreamTracker::TCP_ESTABLISHED);
+ }
- return default_state_action(tsd, trk, __func__);
+ return default_state_action(tsd, trk);
}
bool TcpStateSynRecv::data_seg_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
- return default_state_action(tsd, trk, __func__);
+ trk.s_mgr.sub_state |= SUB_ACK_SENT;
+
+ return default_state_action(tsd, trk);
}
bool TcpStateSynRecv::data_seg_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
+
+ if ( trk.is_ack_valid(tsd.get_seg_ack() ) )
+ {
+ trk.update_tracker_ack_recv(tsd);
+ tsd.get_pkt()->packet_flags |= PKT_STREAM_TWH;
+ session.update_perf_base_state(TcpStreamTracker::TCP_ESTABLISHED);
+ trk.set_tcp_state(TcpStreamTracker::TCP_ESTABLISHED);
+ }
- return default_state_action(tsd, trk, __func__);
+ return default_state_action(tsd, trk);
}
bool TcpStateSynRecv::fin_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
- return default_state_action(tsd, trk, __func__);
+ trk.s_mgr.sub_state |= SUB_ACK_SENT;
+
+ return default_state_action(tsd, trk);
}
bool TcpStateSynRecv::fin_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
-
- return default_state_action(tsd, trk, __func__);
+ auto& trk = static_cast< TcpTracker& >( tracker );
+ if ( tsd.get_tcph()->is_ack() )
+ {
+ Flow* flow = tsd.get_flow();
+ flow->session_state |= STREAM_STATE_ACK;
+ trk.update_tracker_ack_recv(tsd);
+ trk.set_tcp_state(TcpStreamTracker::TCP_CLOSE_WAIT);
+ }
+
+ return default_state_action(tsd, trk);
}
bool TcpStateSynRecv::rst_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
- return default_state_action(tsd, trk, __func__);
+ return default_state_action(tsd, trk);
}
bool TcpStateSynRecv::rst_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
-
- return default_state_action(tsd, trk, __func__);
+ auto& trk = static_cast< TcpTracker& >( tracker );
+
+ if ( trk.update_on_rst_recv(tsd) )
+ {
+ session.update_session_on_rst(tsd, false);
+ session.update_perf_base_state(TcpStreamTracker::TCP_CLOSING);
+ session.set_pkt_action_flag(ACTION_RST);
+ }
+ else
+ {
+ session.tel.set_tcp_event(EVENT_BAD_RST);
+ }
+
+ return default_state_action(tsd, trk);
}
#include "catch/catch.hpp"
#endif
-TcpStateSynSent::TcpStateSynSent(TcpStateMachine& tsm, TcpSession& session) :
- TcpStateHandler(TcpStreamTracker::TCP_SYN_SENT, tsm), session(session)
+TcpStateSynSent::TcpStateSynSent(TcpStateMachine& tsm, TcpSession& ssn) :
+ TcpStateHandler(TcpStreamTracker::TCP_SYN_SENT, tsm), session(ssn)
{
}
bool TcpStateSynSent::syn_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
- return default_state_action(tsd, trk, __func__);
+ trk.s_mgr.sub_state |= SUB_SYN_SENT;
+
+ return default_state_action(tsd, trk);
}
bool TcpStateSynSent::syn_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
+
+ trk.finish_client_init(tsd);
+ if ( tsd.get_seg_len() )
+ session.handle_data_on_syn(tsd);
+ trk.set_tcp_state(TcpStreamTracker::TCP_SYN_RECV);
- return default_state_action(tsd, trk, __func__);
+ return default_state_action(tsd, trk);
}
bool TcpStateSynSent::syn_ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
- return default_state_action(tsd, trk, __func__);
+ trk.s_mgr.sub_state |= ( SUB_SYN_SENT | SUB_ACK_SENT );
+
+ return default_state_action(tsd, trk);
}
bool TcpStateSynSent::syn_ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
-
- return default_state_action(tsd, trk, __func__);
+ auto& trk = static_cast< TcpTracker& >( tracker );
+
+ if ( trk.update_on_3whs_ack(tsd) )
+ {
+ session.update_timestamp_tracking(tsd);
+ if ( tsd.get_seg_len() )
+ session.handle_data_on_syn(tsd);
+ }
+ else
+ session.set_pkt_action_flag(ACTION_BAD_PKT);
+
+ return default_state_action(tsd, trk);
}
bool TcpStateSynSent::ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
-
- return default_state_action(tsd, trk, __func__);
+ Flow* flow = tsd.get_flow();
+ auto& trk = static_cast< TcpTracker& >( tracker );
+
+ // FIXIT - verify ack being sent is valid...
+ trk.update_tracker_ack_sent(tsd);
+ flow->set_session_flags(SSNFLAG_ESTABLISHED);
+ flow->session_state |= ( STREAM_STATE_ACK | STREAM_STATE_ESTABLISHED );
+ session.update_timestamp_tracking(tsd);
+ session.update_perf_base_state(TcpStreamTracker::TCP_ESTABLISHED);
+ trk.set_tcp_state(TcpStreamTracker::TCP_ESTABLISHED);
+
+ return default_state_action(tsd, trk);
}
bool TcpStateSynSent::ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
- return default_state_action(tsd, trk, __func__);
+ return default_state_action(tsd, trk);
}
bool TcpStateSynSent::data_seg_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
-
- return default_state_action(tsd, trk, __func__);
+ Flow* flow = tsd.get_flow();
+ auto& trk = static_cast< TcpTracker& >( tracker );
+
+ // FIXIT - verify ack being sent is valid...
+ trk.update_tracker_ack_sent(tsd);
+ flow->set_session_flags(SSNFLAG_ESTABLISHED);
+ flow->session_state |= ( STREAM_STATE_ACK | STREAM_STATE_ESTABLISHED );
+ session.update_timestamp_tracking(tsd);
+ session.update_perf_base_state(TcpStreamTracker::TCP_ESTABLISHED);
+ trk.set_tcp_state(TcpStreamTracker::TCP_ESTABLISHED);
+
+ return default_state_action(tsd, trk);
}
bool TcpStateSynSent::data_seg_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
- return default_state_action(tsd, trk, __func__);
+ return default_state_action(tsd, trk);
}
bool TcpStateSynSent::fin_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
- return default_state_action(tsd, trk, __func__);
+ return default_state_action(tsd, trk);
}
bool TcpStateSynSent::fin_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
- return default_state_action(tsd, trk, __func__);
+ return default_state_action(tsd, trk);
}
bool TcpStateSynSent::rst_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
- return default_state_action(tsd, trk, __func__);
+ return default_state_action(tsd, trk);
}
bool TcpStateSynSent::rst_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
-
- return default_state_action(tsd, trk, __func__);
+ auto& trk = static_cast< TcpTracker& >( tracker );
+
+ if ( trk.update_on_rst_recv(tsd) )
+ {
+ session.update_session_on_rst(tsd, false);
+ session.update_perf_base_state(TcpStreamTracker::TCP_CLOSING);
+ session.set_pkt_action_flag(ACTION_RST);
+ }
+ else
+ {
+ session.tel.set_tcp_event(EVENT_BAD_RST);
+ }
+
+ return default_state_action(tsd, trk);
}
#include "catch/catch.hpp"
#endif
-TcpStateTimeWait::TcpStateTimeWait(TcpStateMachine& tsm, TcpSession& session) :
- TcpStateHandler(TcpStreamTracker::TCP_TIME_WAIT, tsm), session(session)
+TcpStateTimeWait::TcpStateTimeWait(TcpStateMachine& tsm, TcpSession& ssn) :
+ TcpStateHandler(TcpStreamTracker::TCP_TIME_WAIT, tsm), session(ssn)
{
}
bool TcpStateTimeWait::syn_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
- return default_state_action(tsd, trk, __func__);
+ trk.s_mgr.sub_state |= SUB_SYN_SENT;
+
+ return default_state_action(tsd, trk);
}
bool TcpStateTimeWait::syn_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
+
+ trk.normalizer->ecn_tracker(tsd.get_tcph(), session.config->require_3whs() );
+ if ( tsd.get_seg_len() )
+ session.handle_data_on_syn(tsd);
- return default_state_action(tsd, trk, __func__);
+ return true;
}
bool TcpStateTimeWait::syn_ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
- return default_state_action(tsd, trk, __func__);
+ trk.s_mgr.sub_state |= ( SUB_SYN_SENT | SUB_ACK_SENT );
+
+ return default_state_action(tsd, trk);
}
bool TcpStateTimeWait::syn_ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
- return default_state_action(tsd, trk, __func__);
+ return default_state_action(tsd, trk);
}
bool TcpStateTimeWait::ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
- return default_state_action(tsd, trk, __func__);
+ return default_state_action(tsd, trk);
}
bool TcpStateTimeWait::ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
- return default_state_action(tsd, trk, __func__);
+ return default_state_action(tsd, trk);
}
bool TcpStateTimeWait::data_seg_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
- return default_state_action(tsd, trk, __func__);
+ return default_state_action(tsd, trk);
}
bool TcpStateTimeWait::data_seg_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
- return default_state_action(tsd, trk, __func__);
+ return default_state_action(tsd, trk);
}
bool TcpStateTimeWait::fin_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
- return default_state_action(tsd, trk, __func__);
+ return default_state_action(tsd, trk);
}
bool TcpStateTimeWait::fin_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
- return default_state_action(tsd, trk, __func__);
+ return default_state_action(tsd, trk);
}
bool TcpStateTimeWait::rst_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
+ auto& trk = static_cast< TcpTracker& >( tracker );
- return default_state_action(tsd, trk, __func__);
+ return default_state_action(tsd, trk);
}
bool TcpStateTimeWait::rst_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker)
{
- TcpTracker& trk = static_cast< TcpTracker& >( tracker );
-
- return default_state_action(tsd, trk, __func__);
+ auto& trk = static_cast< TcpTracker& >( tracker );
+
+ if ( trk.update_on_rst_recv(tsd) )
+ {
+ session.update_session_on_rst(tsd, false);
+ session.update_perf_base_state(TcpStreamTracker::TCP_CLOSING);
+ session.set_pkt_action_flag(ACTION_RST);
+ }
+ else
+ {
+ session.tel.set_tcp_event(EVENT_BAD_RST);
+ }
+
+ return default_state_action(tsd, trk);
}
// Created on: Oct 22, 2015
#include "main/snort_config.h"
-#include "time/packet_time.h"
-#include "stream/stream.h"
#include "tcp_stream_config.h"
-static const char* const reassembly_policy_names[] = { "no policy", "first",
- "last", "linux", "old_linux", "bsd",
- "macos", "solaris", "irix",
- "hpux11", "hpux10", "windows", "win_2003",
- "vista", "proxy" };
+static const char* const reassembly_policy_names[] =
+{ "no policy", "first", "last", "linux", "old_linux", "bsd", "macos", "solaris", "irix",
+ "hpux11", "hpux10", "windows", "win_2003", "vista", "proxy" };
TcpStreamConfig::TcpStreamConfig(void)
{
- policy = StreamPolicy::OS_DEFAULT;
- reassembly_policy = ReassemblyPolicy::OS_DEFAULT;
-
- flags = 0;
- flush_factor = 0;
-
- session_timeout = STREAM_DEFAULT_SSN_TIMEOUT;
- max_window = 0;
- overlap_limit = 0;
-
- max_queued_bytes = STREAM_DEFAULT_MAX_QUEUED_BYTES;
- max_queued_segs = STREAM_DEFAULT_MAX_QUEUED_SEGS;
-
- max_consec_small_segs = STREAM_DEFAULT_CONSEC_SMALL_SEGS;
- max_consec_small_seg_size = STREAM_DEFAULT_MAX_SMALL_SEG_SIZE;
-
- hs_timeout = -1;
- footprint = 0;
- paf_max = 16384;
-}
-
-bool TcpStreamConfig::require_3whs(void)
-{
- return hs_timeout >= 0;
-}
-
-bool TcpStreamConfig::midstream_allowed(Packet* p)
-{
- if ( ( hs_timeout < 0 ) || ( p->pkth->ts.tv_sec - packet_first_time() < hs_timeout ) )
- return true;
-
- return false;
}
void TcpStreamConfig::show_config(void)
#ifndef TCP_STREAM_CONFIG_H
#define TCP_STREAM_CONFIG_H
+#include "time/packet_time.h"
+#include "stream/stream.h"
+
#include "tcp_defs.h"
class TcpStreamConfig
public:
TcpStreamConfig(void);
- bool require_3whs(void);
- bool midstream_allowed(Packet*);
+ bool require_3whs(void)
+ {
+ return hs_timeout >= 0;
+ }
+
+ bool midstream_allowed(Packet* p)
+ {
+ if ( ( hs_timeout < 0 ) || ( p->pkth->ts.tv_sec - packet_first_time() < hs_timeout ) )
+ return true;
+
+ return false;
+ }
+
int verify_config(SnortConfig*);
void show_config(void);
static void show_config(TcpStreamConfig*);
- StreamPolicy policy;
- ReassemblyPolicy reassembly_policy;
+ StreamPolicy policy = StreamPolicy::OS_DEFAULT;
+ ReassemblyPolicy reassembly_policy = ReassemblyPolicy::OS_DEFAULT;
- uint16_t flags;
- uint16_t flush_factor;
+ uint16_t flags = 0;
+ uint16_t flush_factor = 0;
- uint32_t session_timeout;
- uint32_t max_window;
- uint32_t overlap_limit;
+ uint32_t session_timeout = STREAM_DEFAULT_SSN_TIMEOUT;
+ uint32_t max_window = 0;
+ uint32_t overlap_limit = 0;
- uint32_t max_queued_bytes;
- uint32_t max_queued_segs;
+ uint32_t max_queued_bytes = STREAM_DEFAULT_MAX_QUEUED_BYTES;
+ uint32_t max_queued_segs = STREAM_DEFAULT_MAX_QUEUED_SEGS;
- uint32_t max_consec_small_segs;
- uint32_t max_consec_small_seg_size;
+ uint32_t max_consec_small_segs = STREAM_DEFAULT_CONSEC_SMALL_SEGS;
+ uint32_t max_consec_small_seg_size = STREAM_DEFAULT_MAX_SMALL_SEG_SIZE;
- int hs_timeout;
- int footprint;
- unsigned paf_max;
+ int hs_timeout = -1;
+ int footprint = 0;
+ uint32_t paf_max = 16384;
};
#endif
#include "tcp_tracker.h"
TcpTracker::TcpTracker(bool client) :
- TcpStreamTracker(client), splitter(nullptr), normalizer(nullptr), reassembler(nullptr)
+ TcpStreamTracker(client)
{
- tcp_event = TCP_MAX_EVENTS;
- init_tracker( );
}
TcpTracker::~TcpTracker(void)
void TcpTracker::init_tracker(void)
{
- memset(&s_mgr, 0, sizeof( StateMgr ) );
+ memset(&s_mgr, 0, sizeof(s_mgr));
s_mgr.state_queue = TcpStreamTracker::TCP_STATE_NONE;
-
- tcp_state = TcpStreamTracker::TCP_STATE_NONE;
+ tcp_state = ( client_tracker ) ?
+ TcpStreamTracker::TCP_STATE_NONE : TcpStreamTracker::TCP_LISTEN;
flush_policy = STREAM_FLPOLICY_IGNORE;
- memset(&paf_state, 0, sizeof( PAF_State ) );
+ memset(&paf_state, 0, sizeof(paf_state));
snd_una = snd_nxt = snd_wnd = 0;
r_nxt_ack = r_win_base = iss = ts_last = ts_last_packet = 0;
small_seg_count = wscale = mss = 0;
- memset(mac_addr, 0, 6);
- flags = 0;
+ tf_flags = 0;
alert_count = 0;
- memset(alerts, 0, sizeof( alerts ) );
+ memset(&alerts, 0, sizeof(alerts));
+ memset(&mac_addr, 0, sizeof(mac_addr));
delete splitter;
splitter = nullptr;
if ( tsd.get_tcph()->are_flags_set(TH_CWR | TH_ECE) )
tsd.get_flow()->set_session_flags(SSNFLAG_ECN_CLIENT_QUERY);
- iss = tsd.get_seq();
- snd_una = tsd.get_seq() + 1;
- if ( tsd.get_seq() == tsd.get_end_seq() )
- snd_nxt = snd_una;
- else
- snd_nxt = snd_una + ( tsd.get_end_seq() - tsd.get_seq() - 1 );
+ iss = tsd.get_seg_seq();
+ snd_una = iss;
+ snd_nxt = tsd.get_end_seq();
+ snd_wnd = tsd.get_seg_wnd();
- snd_wnd = tsd.get_win();
ts_last_packet = tsd.get_pkt()->pkth->ts.tv_sec;
-
- flags |= normalizer->get_tcp_timestamp(tsd, false);
+ tf_flags |= normalizer->get_tcp_timestamp(tsd, false);
ts_last = tsd.get_ts();
if (ts_last == 0)
- flags |= TF_TSTAMP_ZERO;
- flags |= tsd.init_mss(&mss);
- flags |= tsd.init_wscale(&wscale);
+ tf_flags |= TF_TSTAMP_ZERO;
+ tf_flags |= tsd.init_mss(&mss);
+ tf_flags |= tsd.init_wscale(&wscale);
+ s_mgr.sub_state |= SUB_SYN_SENT;
cache_mac_address(tsd, FROM_CLIENT);
set_splitter(tsd.get_flow() );
init_flush_policy( );
+ tcpStats.sessions_on_syn++;
tcp_state = TcpStreamTracker::TCP_SYN_SENT;
}
{
Profile profile(s5TcpNewSessPerfStats);
- reassembler->set_seglist_base_seq(tsd.get_seq() + 1);
- r_nxt_ack = tsd.get_seq() + 1;
- r_win_base = tsd.get_seq() + 1;
+ irs = tsd.get_seg_seq();
+ // FIXIT - can we really set the vars below now?
+ r_nxt_ack = tsd.get_seg_seq() + 1;
+ r_win_base = tsd.get_seg_seq() + 1;
+ reassembler->set_seglist_base_seq(tsd.get_seg_seq() + 1);
cache_mac_address(tsd, FROM_CLIENT);
set_splitter(tsd.get_flow() );
init_flush_policy( );
- tcp_state = TcpStreamTracker::TCP_LISTEN;
+ tcp_state = TcpStreamTracker::TCP_SYN_RECV;
}
void TcpTracker::init_on_synack_sent(TcpSegmentDescriptor& tsd)
if (tsd.get_tcph()->are_flags_set(TH_CWR | TH_ECE))
tsd.get_flow()->set_session_flags(SSNFLAG_ECN_SERVER_REPLY);
- iss =tsd.get_seq();
- snd_una = tsd.get_seq() + 1;
- snd_nxt = snd_una;
- snd_wnd = tsd.get_win();
+ iss = tsd.get_seg_seq();
+ irs = tsd.get_seg_ack() - 1;
+ snd_una = tsd.get_seg_seq();
+ snd_nxt = tsd.get_end_seq();
+ snd_wnd = tsd.get_seg_wnd();
- reassembler->set_seglist_base_seq(tsd.get_ack() );
- r_win_base = tsd.get_ack();
- r_nxt_ack = tsd.get_ack();
- ts_last_packet = tsd.get_pkt()->pkth->ts.tv_sec;
+ r_win_base = tsd.get_seg_ack();
+ r_nxt_ack = tsd.get_seg_ack();
+ reassembler->set_seglist_base_seq(tsd.get_seg_ack() );
- flags |= normalizer->get_tcp_timestamp(tsd, false);
+ ts_last_packet = tsd.get_pkt()->pkth->ts.tv_sec;
+ tf_flags |= normalizer->get_tcp_timestamp(tsd, false);
ts_last = tsd.get_ts();
if ( ts_last == 0 )
- flags |= TF_TSTAMP_ZERO;
- flags |= tsd.init_mss(&mss);
- flags |= tsd.init_wscale(&wscale);
+ tf_flags |= TF_TSTAMP_ZERO;
+ tf_flags |= tsd.init_mss(&mss);
+ tf_flags |= tsd.init_wscale(&wscale);
+ s_mgr.sub_state |= ( SUB_SYN_SENT | SUB_ACK_SENT );
cache_mac_address(tsd, FROM_SERVER);
set_splitter(tsd.get_flow() );
init_flush_policy();
+ tcpStats.sessions_on_syn_ack++;
tcp_state = TcpStreamTracker::TCP_SYN_RECV;
}
{
Profile profile(s5TcpNewSessPerfStats);
- reassembler->set_seglist_base_seq(tsd.get_seq() + 1);
- iss = tsd.get_ack() - 1;
- r_nxt_ack = tsd.get_seq() + 1;
- r_win_base = tsd.get_seq() + 1;
- snd_nxt = tsd.get_ack();
+ iss = tsd.get_seg_ack() - 1;
+ irs = tsd.get_seg_seq();
+ snd_una = tsd.get_seg_ack();
+ snd_nxt = snd_una;
+
+ r_nxt_ack = tsd.get_seg_seq() + 1;
+ r_win_base = tsd.get_seg_seq() + 1;
+ reassembler->set_seglist_base_seq(tsd.get_seg_seq() + 1);
cache_mac_address(tsd, FROM_SERVER);
set_splitter(tsd.get_flow() );
if ( tsd.get_tcph()->are_flags_set(TH_CWR | TH_ECE) )
tsd.get_flow()->set_session_flags(SSNFLAG_ECN_CLIENT_QUERY);
- iss = tsd.get_seq();
- snd_una = tsd.get_seq() + 1;
- snd_nxt = tsd.get_seq() + 1;
- snd_wnd = tsd.get_win();
+ iss = tsd.get_seg_seq();
+ snd_una = tsd.get_seg_seq();
+ snd_nxt = snd_una;
+ snd_wnd = tsd.get_seg_wnd();
+
+ r_win_base = tsd.get_seg_ack();
+ r_nxt_ack = tsd.get_seg_ack();
+
ts_last_packet = tsd.get_pkt()->pkth->ts.tv_sec;
- flags |= normalizer->get_tcp_timestamp(tsd, false);
+ tf_flags |= normalizer->get_tcp_timestamp(tsd, false);
ts_last = tsd.get_ts();
if (ts_last == 0)
- flags |= TF_TSTAMP_ZERO;
- flags |= tsd.init_mss(&mss);
- flags |= tsd.init_wscale(&wscale);
+ tf_flags |= TF_TSTAMP_ZERO;
+ tf_flags |= tsd.init_mss(&mss);
+ tf_flags |= tsd.init_wscale(&wscale);
+ s_mgr.sub_state |= SUB_ACK_SENT;
cache_mac_address(tsd, FROM_CLIENT);
set_splitter(tsd.get_flow() );
{
Profile profile(s5TcpNewSessPerfStats);
- reassembler->set_seglist_base_seq(tsd.get_seq() + 1);
- r_nxt_ack = tsd.get_seq() + 1;
- r_win_base = tsd.get_seq() + 1;
+ iss = tsd.get_seg_ack() - 1;
+ irs = tsd.get_seg_seq();
+ snd_una = tsd.get_seg_ack();
+ snd_nxt = snd_una;
+
+ r_nxt_ack = tsd.get_seg_seq();
+ r_win_base = tsd.get_seg_seq();
+ reassembler->set_seglist_base_seq(tsd.get_seg_seq() + 1);
cache_mac_address(tsd, FROM_CLIENT);
set_splitter(tsd.get_flow() );
{
Profile profile(s5TcpNewSessPerfStats);
- iss = tsd.get_seq();
- snd_una = tsd.get_seq();
- snd_nxt = tsd.get_seq();
- snd_wnd = tsd.get_win();
- if ( tsd.get_direction() == FROM_SERVER )
- {
- r_win_base = tsd.get_ack();
- r_nxt_ack = tsd.get_ack();
- reassembler->set_seglist_base_seq(tsd.get_ack() );
- }
+ Flow* flow = tsd.get_flow();
+
+ if ( flow->ssn_state.direction == FROM_CLIENT )
+ flow->set_session_flags(SSNFLAG_SEEN_CLIENT);
else
- {
- r_win_base = 0;
- r_nxt_ack = 0;
- }
+ flow->set_session_flags(SSNFLAG_SEEN_SERVER);
+
+ // FIXIT - should we init these?
+ iss = tsd.get_seg_seq();
+ irs = tsd.get_seg_ack();
+ snd_una = tsd.get_seg_seq();
+ snd_nxt = snd_una + tsd.get_seg_len();
+ snd_wnd = tsd.get_seg_wnd();
+
+ r_win_base = tsd.get_seg_ack();
+ r_nxt_ack = tsd.get_seg_ack();
+ reassembler->set_seglist_base_seq(tsd.get_seg_ack() );
ts_last_packet = tsd.get_pkt()->pkth->ts.tv_sec;
- flags |= normalizer->get_tcp_timestamp(tsd, 0);
+ tf_flags |= normalizer->get_tcp_timestamp(tsd, 0);
ts_last = tsd.get_ts();
if (ts_last == 0)
- flags |= TF_TSTAMP_ZERO;
- flags |= tsd.init_mss(&mss);
- flags |= tsd.init_wscale(&wscale);
+ tf_flags |= TF_TSTAMP_ZERO;
+ tf_flags |= ( tsd.init_mss(&mss) | tsd.init_wscale(&wscale) );
+ s_mgr.sub_state |= SUB_ACK_SENT;
cache_mac_address(tsd, tsd.get_direction() );
set_splitter(tsd.get_flow() );
{
Profile profile(s5TcpNewSessPerfStats);
- if ( tsd.get_direction() == FROM_SERVER )
- iss = tsd.get_ack() - 1;
- else
- snd_una = tsd.get_ack() - 1;
-
- r_nxt_ack = tsd.get_seq();
- r_win_base = tsd.get_seq();
+ // FIXIT - should we init these?
+ iss = tsd.get_seg_ack();
+ irs = tsd.get_seg_seq();
+ snd_una = tsd.get_seg_ack();
+ snd_nxt = snd_una;
snd_wnd = 0; /* reset later */
- reassembler->set_seglist_base_seq(tsd.get_seq() );
+
+ r_nxt_ack = tsd.get_seg_seq();
+ r_win_base = tsd.get_seg_seq();
+ reassembler->set_seglist_base_seq(tsd.get_seg_seq() );
cache_mac_address(tsd, tsd.get_direction() );
set_splitter(tsd.get_flow() );
tcp_state = TcpStreamTracker::TCP_ESTABLISHED;
}
+void TcpTracker::finish_server_init(TcpSegmentDescriptor& tsd)
+{
+ iss = tsd.get_seg_seq();
+ snd_una = tsd.get_seg_seq();
+ snd_nxt = tsd.get_end_seq();
+ snd_wnd = tsd.get_seg_wnd();
+
+ // FIXIT - move this to fin handler for syn_recv state ..
+ //if ( tcph->is_fin() )
+ // server->set_snd_nxt(server->get_snd_nxt() - 1);
+
+ tf_flags |= normalizer->get_tcp_timestamp(tsd, false);
+ ts_last = tsd.get_ts();
+ if ( ts_last != 0 )
+ ts_last_packet = tsd.get_pkt()->pkth->ts.tv_sec;
+ else
+ tf_flags |= TF_TSTAMP_ZERO;
+
+ tf_flags |= ( tsd.init_mss(&mss) | tsd.init_wscale(&wscale) );
+}
+
+void TcpTracker::finish_client_init(TcpSegmentDescriptor& tsd)
+{
+ Flow* flow = tsd.get_flow();
+
+ r_nxt_ack = tsd.get_end_seq();
+
+ if ( !( flow->session_state & STREAM_STATE_MIDSTREAM ) )
+ {
+ reassembler->set_seglist_base_seq(tsd.get_seg_seq() + 1);
+ r_win_base = tsd.get_end_seq();
+ }
+ else
+ {
+ reassembler->set_seglist_base_seq(tsd.get_seg_seq() );
+ r_win_base = tsd.get_seg_seq();
+ }
+}
+
+void TcpTracker::update_tracker_ack_recv(TcpSegmentDescriptor& tsd)
+{
+ if ( SEQ_GT(tsd.get_seg_ack(), snd_una) )
+ {
+ snd_una = tsd.get_seg_ack();
+ if ( snd_nxt < snd_una )
+ snd_nxt = snd_una + 1;
+ }
+}
+
+void TcpTracker::update_tracker_ack_sent(TcpSegmentDescriptor& tsd)
+{
+ // ** this is how we track the last seq number sent
+ // as is l_unackd is the "last left" seq recvd
+ //snd_una = tsd.get_seg_seq();
+
+ // FIXIT - add check to validate ack...
+
+ if ( SEQ_GT(tsd.get_end_seq(), snd_nxt) )
+ snd_nxt = tsd.get_end_seq();
+
+ if ( !SEQ_EQ(r_win_base, tsd.get_seg_ack() ) )
+ small_seg_count = 0;
+
+#ifdef S5_PEDANTIC
+ if ( SEQ_GT(tsd.get_seg_ack(), r_win_base) &&
+ SEQ_LEQ(tsd.get_seg_ack(), r_nxt_ack) )
+#else
+ if ( SEQ_GT(tsd.get_seg_ack(), r_win_base) )
+#endif
+ r_win_base = tsd.get_seg_ack();
+
+ snd_wnd = tsd.get_seg_wnd();
+
+ s_mgr.sub_state |= SUB_ACK_SENT;
+
+ reassembler->flush_on_ack_policy(tsd.get_pkt() );
+}
+
+bool TcpTracker::update_on_3whs_ack(TcpSegmentDescriptor& tsd)
+{
+ bool good_ack = true;
+
+ if ( is_ack_valid(tsd.get_seg_ack()) )
+ {
+ Flow* flow = tsd.get_flow();
+
+ irs = tsd.get_seg_seq();
+ finish_client_init(tsd);
+ update_tracker_ack_recv(tsd);
+ flow->set_session_flags(SSNFLAG_ESTABLISHED);
+ flow->session_state |= ( STREAM_STATE_ACK | STREAM_STATE_ESTABLISHED );
+
+ /* Indicate this packet completes 3-way handshake */
+ tsd.get_pkt()->packet_flags |= PKT_STREAM_TWH;
+ tcp_state = TcpStreamTracker::TCP_ESTABLISHED;
+ }
+ else
+ {
+ DebugFormat(DEBUG_STREAM_STATE,
+ "Pkt Ack is Out of Bounds (%X, %X, %X) = (snd_una, snd_nxt, cur)\n",
+ snd_una, snd_nxt, tsd.get_seg_ack());
+ inc_tcp_discards();
+ normalizer->trim_win_payload(tsd);
+ good_ack = false;
+ }
+
+ return good_ack;
+}
+
+bool TcpTracker::update_on_rst_recv(TcpSegmentDescriptor& tsd)
+{
+ bool good_rst = true;
+
+ normalizer->trim_rst_payload(tsd);
+ if ( normalizer->validate_rst(tsd) )
+ {
+ Flow* flow = tsd.get_flow();
+
+ DebugMessage(DEBUG_STREAM_STATE, "Received Valid RST, bailing\n");
+ flow->set_session_flags(SSNFLAG_RESET);
+ if ( normalizer->is_tcp_ips_enabled() )
+ tcp_state = TcpStreamTracker::TCP_CLOSED;
+ }
+ else
+ {
+ DebugMessage(DEBUG_STREAM_STATE, "Received RST with bad sequence number, bailing\n");
+ inc_tcp_discards();
+ normalizer->packet_dropper(tsd, NORM_TCP_BLOCK);
+ good_rst = false;
+ }
+
+ return good_rst;
+}
+
+void TcpTracker::update_on_rst_sent(void)
+{
+ tcp_state = TcpStreamTracker::TCP_CLOSED;
+ s_mgr.sub_state |= SUB_RST_SENT;
+}
+
+#ifdef S5_PEDANTIC
+// From RFC 793:
+//
+// Segment Receive Test
+// Length Window
+// ------- ------- -------------------------------------------
+//
+// 0 0 SEG.SEQ = RCV.NXT
+//
+// 0 >0 RCV.NXT =< SEG.SEQ < RCV.NXT+RCV.WND
+//
+// >0 0 not acceptable
+//
+// >0 >0 RCV.NXT =< SEG.SEQ < RCV.NXT+RCV.WND
+// or RCV.NXT =< SEG.SEQ+SEG.LEN-1 < RCV.NXT+RCV.WND
+//
+bool ValidSeq(const Packet* p, Flow* flow, TcpTracker* st, TcpSegmentDescriptor& tsd)
+{
+ uint32_t win = normalizer->get_stream_window(flow, st, tsd);
+
+ if ( !p->dsize )
+ {
+ if ( !win )
+ {
+ return ( tsd.get_seg_seq() == r_win_base );
+ }
+ return SEQ_LEQ(r_win_base, tsd.get_seg_seq()) &&
+ SEQ_LT(tsd.get_seg_seq(), r_win_base+win);
+ }
+ if ( !win )
+ return 0;
+
+ if ( SEQ_LEQ(r_win_base, tsd.get_seg_seq()) &&
+ SEQ_LT(tsd.get_seg_seq(), r_win_base+win) )
+ return 1;
+
+ return SEQ_LEQ(r_win_base, tsd.get_end_seq()) &&
+ SEQ_LT(tsd.get_end_seq(), r_win_base+win);
+}
+
+#endif
+
+bool TcpTracker::is_segment_seq_valid(TcpSegmentDescriptor& tsd)
+{
+ bool valid_seq = true;
+
+ /* check for valid seqeuence/retrans */
+ if ( tcp_state >= TcpStreamTracker::TCP_ESTABLISHED )
+ {
+ //and
+ //and !ValidSeq(listener, tsd))
+ int right_ok;
+ uint32_t left_seq;
+
+ DebugFormat(DEBUG_STREAM_STATE,
+ "Checking end_seq (%X) > r_win_base (%X) && seq (%X) < r_nxt_ack(%X)\n",
+ tsd.get_end_seq(), r_win_base, tsd.get_seg_seq(), r_nxt_ack +
+ normalizer->get_stream_window(tsd));
+
+ if ( SEQ_LT(r_nxt_ack, r_win_base) )
+ left_seq = r_nxt_ack;
+ else
+ left_seq = r_win_base;
+
+ if ( tsd.get_seg_len() )
+ right_ok = SEQ_GT(tsd.get_end_seq(), left_seq);
+ else
+ right_ok = SEQ_GEQ(tsd.get_end_seq(), left_seq);
+
+ if ( right_ok )
+ {
+ uint32_t win = normalizer->get_stream_window(tsd);
+
+ if ( SEQ_LEQ(tsd.get_seg_seq(), r_win_base + win) )
+ {
+ DebugMessage(DEBUG_STREAM_STATE, "seq is within window!\n");
+ }
+ else
+ {
+ DebugMessage(DEBUG_STREAM_STATE, "seq is past the end of the window!\n");
+ valid_seq = false;
+ }
+ }
+ else
+ {
+ DebugMessage(DEBUG_STREAM_STATE, "end_seq is before win_base\n");
+ valid_seq = false;
+ }
+ }
+
+ if ( !valid_seq )
+ {
+ inc_tcp_discards();
+ normalizer->trim_win_payload(tsd);
+ }
+
+ return valid_seq;
+}
+
void TcpTracker::print(void)
{
LogMessage(" + TcpTracker +\n");
struct StateMgr
{
uint8_t sub_state;
- enum TcpStreamTracker::TcpStates state_queue;
+ enum TcpStreamTracker::TcpState state_queue;
uint8_t expected_flags;
uint32_t transition_seq;
uint32_t stq_get_seq;
public:
TcpTracker(bool);
virtual ~TcpTracker(void);
+
void init_tracker(void);
void print(void);
void init_flush_policy(void);
void init_on_3whs_ack_recv(TcpSegmentDescriptor& tsd);
void init_on_data_seg_sent(TcpSegmentDescriptor& tsd);
void init_on_data_seg_recv(TcpSegmentDescriptor& tsd);
-
+ void finish_server_init(TcpSegmentDescriptor& tsd);
+ void finish_client_init(TcpSegmentDescriptor& tsd);
+
+ void update_tracker_ack_recv(TcpSegmentDescriptor& tsd);
+ void update_tracker_ack_sent(TcpSegmentDescriptor& tsd);
+ bool update_on_3whs_ack(TcpSegmentDescriptor& tsd);
+ bool update_on_rst_recv(TcpSegmentDescriptor& tsd);
+ void update_on_rst_sent(void);
+
+ bool is_segment_seq_valid(TcpSegmentDescriptor& tsd);
+
+ StreamSplitter* splitter = nullptr;
+ TcpNormalizer* normalizer = nullptr;
+ TcpReassembler* reassembler = nullptr;
+ uint32_t small_seg_count = 0;
+ uint8_t alert_count = 0;
+ StreamAlertInfo alerts[MAX_SESSION_ALERTS];
StateMgr s_mgr; /* state tracking goodies */
-
+ FlushPolicy flush_policy = STREAM_FLPOLICY_IGNORE;
// this is intended to be private to paf but is included
// directly to avoid the need for allocation; do not directly
// manipulate within this module.
PAF_State paf_state; // for tracking protocol aware flushing
- FlushPolicy flush_policy;
- StreamSplitter* splitter;
- TcpNormalizer* normalizer;
- TcpReassembler* reassembler;
-
- uint32_t r_nxt_ack; /* next expected ack from remote side */
- uint32_t r_win_base; /* remote side window base sequence number
- * (i.e. the last ack we got) */
-
- uint32_t small_seg_count;
-
- uint8_t alert_count; /* number alerts stored (up to MAX_SESSION_ALERTS) */
- StreamAlertInfo alerts[MAX_SESSION_ALERTS]; /* history of alerts */
};
#endif