listener.set_tcp_event(tsd);
tcp_state_handlers[ tcp_state ]->eval(tsd, listener);
tcp_state_handlers[ tcp_state ]->do_post_sm_packet_actions(tsd, listener);
- if( listener.process_inorder_fin() )
- {
- //FIN is in order or we need to process FIN from state_queue
- tcp_state_handlers[ tcp_state ]->eval(tsd, listener);
- tcp_state = talker.get_tcp_state( );
- tcp_state_handlers[ tcp_state ]->eval(tsd, talker);
- tcp_state_handlers[ tcp_state ]->do_post_sm_packet_actions(tsd, listener);
- listener.inorder_fin = false;
- }
return true;
}
flush_policy = STREAM_FLPOLICY_IGNORE;
memset(&paf_state, 0, sizeof(paf_state));
snd_una = snd_nxt = snd_wnd = 0;
- r_nxt_ack = r_win_base = iss = ts_last = ts_last_packet = 0;
+ rcv_nxt = r_win_base = iss = ts_last = ts_last_packet = 0;
small_seg_count = wscale = mss = 0;
tf_flags = 0;
alert_count = 0;
irs = tsd.get_seg_seq();
// FIXIT-H can we really set the vars below now?
- r_nxt_ack = tsd.get_seg_seq() + 1;
+ rcv_nxt = tsd.get_seg_seq() + 1;
r_win_base = tsd.get_seg_seq() + 1;
reassembler.set_seglist_base_seq(tsd.get_seg_seq() + 1);
snd_wnd = tsd.get_seg_wnd();
r_win_base = tsd.get_seg_ack();
- r_nxt_ack = tsd.get_seg_ack();
+ rcv_nxt = tsd.get_seg_ack();
reassembler.set_seglist_base_seq(tsd.get_seg_ack() );
ts_last_packet = tsd.get_pkt()->pkth->ts.tv_sec;
snd_una = tsd.get_seg_ack();
snd_nxt = snd_una;
- r_nxt_ack = tsd.get_seg_seq() + 1;
+ rcv_nxt = tsd.get_seg_seq() + 1;
r_win_base = tsd.get_seg_seq() + 1;
reassembler.set_seglist_base_seq(tsd.get_seg_seq() + 1);
snd_wnd = tsd.get_seg_wnd();
r_win_base = tsd.get_seg_ack();
- r_nxt_ack = tsd.get_seg_ack();
+ rcv_nxt = tsd.get_seg_ack();
ts_last_packet = tsd.get_pkt()->pkth->ts.tv_sec;
tf_flags |= normalizer.get_tcp_timestamp(tsd, false);
snd_una = tsd.get_seg_ack();
snd_nxt = snd_una;
- r_nxt_ack = tsd.get_seg_seq();
+ rcv_nxt = tsd.get_seg_seq();
r_win_base = tsd.get_seg_seq();
reassembler.set_seglist_base_seq(tsd.get_seg_seq() + 1);
snd_wnd = tsd.get_seg_wnd();
r_win_base = tsd.get_seg_ack();
- r_nxt_ack = tsd.get_seg_ack();
+ rcv_nxt = tsd.get_seg_ack();
reassembler.set_seglist_base_seq(tsd.get_seg_ack());
ts_last_packet = tsd.get_pkt()->pkth->ts.tv_sec;
snd_nxt = snd_una;
snd_wnd = 0; /* reset later */
- r_nxt_ack = tsd.get_seg_seq();
+ rcv_nxt = tsd.get_seg_seq();
r_win_base = tsd.get_seg_seq();
reassembler.set_seglist_base_seq(tsd.get_seg_seq());
{
Flow* flow = tsd.get_flow();
- r_nxt_ack = tsd.get_end_seq();
+ rcv_nxt = tsd.get_end_seq();
if ( !( flow->session_state & STREAM_STATE_MIDSTREAM ) )
{
bool TcpStreamTracker::update_on_fin_recv(TcpSegmentDescriptor& tsd)
{
if ( SEQ_LT(tsd.get_end_seq(), r_win_base) )
- {
return false;
- }
//--------------------------------------------------
- // FIXIT-L don't bump r_nxt_ack unless FIN is in seq
+ // FIXIT-L don't bump rcv_nxt unless FIN is in seq
// because it causes bogus 129:5 cases
// but doing so causes extra gaps
- //if ( SEQ_EQ(tsd.end_seq, r_nxt_ack) )
- r_nxt_ack++;
+ if ( SEQ_EQ(tsd.get_end_seq(), rcv_nxt) )
+ rcv_nxt++;
+ else
+ fin_seq_adjust = 1;
// set final seq # any packet rx'ed with seq > is bad
if ( !fin_seq_set )
int right_ok;
uint32_t left_seq;
- if ( SEQ_LT(r_nxt_ack, r_win_base) )
- left_seq = r_nxt_ack;
+ if ( SEQ_LT(rcv_nxt, r_win_base) )
+ left_seq = rcv_nxt;
else
left_seq = r_win_base;
{ this->iss = iss; }
uint32_t get_fin_final_seq() const
- { return fin_final_seq; }
+ { return fin_final_seq + fin_seq_adjust; }
- void set_fin_final_seq(uint32_t fin_final_seq = 0)
- { this->fin_final_seq = fin_final_seq; }
+ uint32_t get_fin_seq_adjust()
+ { return fin_seq_adjust; }
bool is_fin_seq_set() const
{ return fin_seq_set; }
bool is_rst_pkt_sent() const
{ return rst_pkt_sent; }
- bool process_inorder_fin() const
- { return inorder_fin; }
-
snort::StreamSplitter* get_splitter()
{ return splitter; }
uint32_t irs = 0; // IRS - initial receive sequence number
bool rst_pkt_sent = false;
- bool inorder_fin = false;
// FIXIT-L make these non-public
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) */
uint8_t mac_addr[6] = { };
bool mac_addr_valid = false;
uint32_t fin_final_seq = 0;
+ uint32_t fin_seq_adjust = 0;
bool fin_seq_set = false; // FIXIT-M should be obviated by tcp state
uint8_t tcp_options_len = 0;
fprintf(stdout,
" %s ST=%s UA=%-4u NS=%-4u LW=%-5u RN=%-4u RW=%-4u ISS=%-4u IRS=%-4u ",
s, statext[a->get_tcp_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());
+ RMT(a, rcv_nxt, b), RMT(a, r_win_base, b), a->get_iss(), a->get_irs());
fprintf(stdout, "\n");
unsigned paf = (a->splitter and a->splitter->is_paf()) ? 2 : 0;
const PegInfo tcp_pegs[] =
{
SESSION_PEGS("tcp"),
+ { CountType::SUM, "instantiated", "new sessions instantiated" },
+ { CountType::SUM, "setups", "session initializations" },
+ { CountType::SUM, "restarts", "sessions restarted" },
{ CountType::SUM, "resyns", "SYN received on established session" },
{ CountType::SUM, "discards", "tcp packets discarded" },
{ CountType::SUM, "events", "events generated" },
struct TcpStats
{
SESSION_STATS;
+ PegCount instantiated;
+ PegCount setups;
+ PegCount restarts;
PegCount resyns;
PegCount discards;
PegCount events;
bool TcpNormalizer::validate_rst_seq_geq(
TcpNormalizerState& tns, TcpSegmentDescriptor& tsd)
{
- // FIXIT-H check for r_win_base == 0 is hack for uninitialized r_win_base, fix this
- if ( ( tns.tracker->r_nxt_ack == 0 ) || SEQ_GEQ(tsd.get_seg_seq(), tns.tracker->r_nxt_ack) )
- {
+ // FIXIT-H check for rcv_nxt == 0 is hack for uninitialized rcv_nxt, fix this
+ if ( ( tns.tracker->rcv_nxt == 0 ) || SEQ_GEQ(tsd.get_seg_seq(), tns.tracker->rcv_nxt) )
return true;
- }
return false;
}
{
// reset must be admitted when window closed
if (SEQ_LEQ(tsd.get_seg_seq(), tns.tracker->r_win_base + get_stream_window(tns, tsd)))
- {
return true;
- }
}
return false;
bool TcpNormalizer::validate_rst_seq_eq(
TcpNormalizerState& tns, TcpSegmentDescriptor& tsd)
{
- // FIXIT-H check for r_nxt_ack == 0 is hack for uninitialized r_nxt_ack, fix this
- if ( ( tns.tracker->r_nxt_ack == 0 ) || SEQ_EQ(tsd.get_seg_seq(), tns.tracker->r_nxt_ack) )
- {
+ uint32_t expected_seq = tns.tracker->rcv_nxt + tns.tracker->get_fin_seq_adjust();
+
+ // FIXIT-H check for rcv_nxt == 0 is hack for uninitialized rcv_nxt, fix this
+ if ( ( tns.tracker->rcv_nxt == 0 ) || SEQ_EQ(tsd.get_seg_seq(), expected_seq) )
return true;
- }
return false;
}
return ACTION_BAD_PKT;
}
else
- {
return ACTION_NOTHING;
- }
}
bool TcpNormalizer::is_paws_ts_checked_required(
/* Windows has some strange behavior here. If the sequence of the reset is the
* next expected sequence, it Resets. Otherwise it ignores the 2nd SYN.
*/
- if (SEQ_EQ(tsd.get_seg_seq(), listener->r_nxt_ack))
+ if (SEQ_EQ(tsd.get_seg_seq(), listener->rcv_nxt))
{
session->flow->set_session_flags(SSNFLAG_RESET);
talker->set_tcp_state(TcpStreamTracker::TCP_CLOSED);
if ( talker->get_tf_flags() & TF_TSTAMP_ZERO )
{
talker->clear_tf_flags(TF_TSTAMP_ZERO);
- if ( SEQ_EQ(listener->r_nxt_ack, tsd.get_seg_seq() ) )
+ if ( SEQ_EQ(listener->rcv_nxt, tsd.get_seg_seq() ) )
{
// Ignore timestamp for this first packet, save to check on next
talker->set_ts_last(tsd.get_ts() );
TcpNormalizerState& tns, TcpSegmentDescriptor& tsd)
{
/* HPUX 11 ignores timestamps for out of order segments */
- if ((tns.tracker->get_tf_flags() & TF_MISSING_PKT) || !SEQ_EQ(tns.tracker->r_nxt_ack,
+ if ((tns.tracker->get_tf_flags() & TF_MISSING_PKT) || !SEQ_EQ(tns.tracker->rcv_nxt,
tsd.get_seg_seq()))
return false;
else
trs.sos.seglist_base_seq = flush_seq;
}
- if ( SEQ_LT(trs.tracker->r_nxt_ack, flush_seq) )
- trs.tracker->r_nxt_ack = flush_seq;
+ if ( SEQ_LT(trs.tracker->rcv_nxt, flush_seq) )
+ trs.tracker->rcv_nxt = flush_seq;
purge_alerts(trs, trs.sos.session->flow);
overlap = trs.tracker->r_win_base - tsd.get_seg_seq();
if ( overlap >= tsd.get_seg_len() )
- {
return;
- }
}
// BLOCK add new block to trs.sos.seglist containing data
client.session = this;
server.session = this;
+ tcpStats.instantiated++;
}
TcpSession::~TcpSession()
splitter_init = false;
SESSION_STATS_ADD(tcpStats);
+ tcpStats.setups++;
return true;
}
if (p->ptrs.tcph->is_ack())
talker->reassembler.flush_on_ack_policy(p);
+
+ tcpStats.restarts++;
}
//-------------------------------------------------------------------------
void TcpSession::clear_session(bool free_flow_data, bool flush_segments, bool restart, Packet* p)
{
+ assert(!p or p->flow == flow);
if ( !tcp_init )
+ {
+ if ( lws_init )
+ tcpStats.no_pickups++;
return;
+ }
+
+ lws_init = false;
+ tcp_init = false;
+ tcpStats.released++;
- assert(!p or p->flow == flow);
DetectionEngine::onload(flow);
- if ( tcp_init )
+ if ( flush_segments )
{
- if ( flush_segments )
- {
- client.reassembler.flush_queued_segments(flow, true, p);
- server.reassembler.flush_queued_segments(flow, true, p);
- }
- client.reassembler.purge_segment_list();
- server.reassembler.purge_segment_list();
+ client.reassembler.flush_queued_segments(flow, true, p);
+ server.reassembler.flush_queued_segments(flow, true, p);
}
-
- if ( tcp_init )
- tcpStats.released++;
- else if ( lws_init )
- tcpStats.no_pickups++;
- else
- return;
+ client.reassembler.purge_segment_list();
+ server.reassembler.purge_segment_list();
update_perf_base_state(TcpStreamTracker::TCP_CLOSED);
set_splitter(false, nullptr);
tel.log_internal_event(SESSION_EVENT_CLEAR);
-
- lws_init = false;
- tcp_init = false;
}
void TcpSession::update_perf_base_state(char newState)
}
}
-void TcpSession::check_fin_transition_status(TcpSegmentDescriptor& tsd)
-{
- if((tsd.get_seg_len() != 0) &&
- SEQ_EQ(listener->get_fin_final_seq(), listener->r_nxt_ack))
- {
- listener->set_tcp_event(TcpStreamTracker::TCP_FIN_RECV_EVENT);
- talker->set_tcp_event(TcpStreamTracker::TCP_FIN_SENT_EVENT);
- listener->inorder_fin = true;
- }
-}
-
-
int TcpSession::process_tcp_data(TcpSegmentDescriptor& tsd)
{
DeepProfile profile(s5TcpDataPerfStats);
{
if (listener->normalizer.get_os_policy() == StreamPolicy::OS_MACOS)
seq++;
-
else
{
listener->normalizer.trim_syn_payload(tsd);
return STREAM_UNALIGNED;
- } }
+ }
+ }
/* we're aligned, so that's nice anyway */
- if (seq == listener->r_nxt_ack)
+ if (seq == listener->rcv_nxt)
{
/* check if we're in the window */
if (config->policy != StreamPolicy::OS_PROXY
/* move the ack boundary up, this is the only way we'll accept data */
// FIXIT-L for ips, must move all the way to first hole or right end
- listener->r_nxt_ack = tsd.get_end_seq();
+ listener->rcv_nxt = tsd.get_end_seq();
if (tsd.get_seg_len() != 0)
{
if ((listener->get_tcp_state() == TcpStreamTracker::TCP_ESTABLISHED)
&& (listener->flush_policy == STREAM_FLPOLICY_IGNORE))
{
- if (SEQ_GT(tsd.get_end_seq(), listener->r_nxt_ack))
+ if (SEQ_GT(tsd.get_end_seq(), listener->rcv_nxt))
{
// set next ack so we are within the window going forward on this side.
// FIXIT-L for ips, must move all the way to first hole or right end
- listener->r_nxt_ack = tsd.get_end_seq();
+ listener->rcv_nxt = tsd.get_end_seq();
}
}
{
if (!( flow->get_session_flags() & SSNFLAG_STREAM_ORDER_BAD))
{
- if (!SEQ_LEQ((tsd.get_seg_seq() + tsd.get_seg_len()), listener->r_nxt_ack))
+ if (!SEQ_LEQ((tsd.get_seg_seq() + tsd.get_seg_len()), listener->rcv_nxt))
flow->set_session_flags(SSNFLAG_STREAM_ORDER_BAD);
}
process_tcp_stream(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()))
+ && SEQ_EQ(listener->rcv_nxt, tsd.get_seg_seq()))
{
talker->set_ts_last_packet(tsd.get_pkt()->pkth->ts.tv_sec);
talker->set_ts_last(tsd.get_ts());
// 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));
+ tsd, (st->r_win_base + st->get_snd_wnd() - st->rcv_nxt));
if (st->get_mss())
st->normalizer.trim_mss_payload(tsd, st->get_mss());
or (config->policy == StreamPolicy::OS_PROXY))
{
process_tcp_data(tsd);
- //Check if all segments are received. Process FIN transition
- check_fin_transition_status(tsd);
}
else
{
private:
void set_os_policy() override;
bool flow_exceeds_config_thresholds(TcpSegmentDescriptor&);
- void check_fin_transition_status(TcpSegmentDescriptor&);
void process_tcp_stream(TcpSegmentDescriptor&);
int process_tcp_data(TcpSegmentDescriptor&);
void swap_trackers();
bool TcpStateCloseWait::fin_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk)
{
snort::Flow* flow = tsd.get_flow();
- if( trk.process_inorder_fin() )
- {
- trk.update_on_fin_recv(tsd);
- return true;
- }
trk.update_tracker_ack_recv(tsd);
bool TcpStateClosing::ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk)
{
trk.update_tracker_ack_recv(tsd);
- if ( SEQ_GEQ(tsd.get_end_seq(), trk.r_nxt_ack) )
+ if ( SEQ_GEQ(tsd.get_end_seq(), trk.rcv_nxt) )
trk.set_tcp_state(TcpStreamTracker::TCP_TIME_WAIT);
return true;
}
bool TcpStateClosing::data_seg_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk)
{
trk.update_tracker_ack_recv(tsd);
- if ( SEQ_GEQ(tsd.get_end_seq(), trk.r_nxt_ack) )
+ if ( SEQ_GEQ(tsd.get_end_seq(), trk.rcv_nxt) )
trk.set_tcp_state(TcpStreamTracker::TCP_TIME_WAIT);
return true;
}
bool TcpStateEstablished::fin_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk)
{
- TcpStreamTracker& listener =
- tsd.get_pkt()->is_from_client() ? trk.session->server : trk.session->client;
-
trk.update_on_fin_sent(tsd);
+ trk.session->eof_handle(tsd.get_pkt());
+ trk.set_tcp_state(TcpStreamTracker::TCP_FIN_WAIT1);
- if ( SEQ_EQ(tsd.get_end_seq(), (listener.r_nxt_ack + tsd.get_seg_len())) ||
- listener.process_inorder_fin() || !listener.is_segment_seq_valid(tsd) )
- {
- trk.session->eof_handle(tsd.get_pkt());
- trk.set_tcp_state(TcpStreamTracker::TCP_FIN_WAIT1);
- }
return true;
}
trk.session->handle_data_segment(tsd);
trk.flush_data_on_fin_recv(tsd);
}
- if( (tsd.get_end_seq() == trk.r_nxt_ack) || !trk.is_segment_seq_valid(tsd) )
- {
- if ( trk.update_on_fin_recv(tsd) )
- {
- trk.session->update_perf_base_state(TcpStreamTracker::TCP_CLOSING);
- trk.set_tcp_state(TcpStreamTracker::TCP_CLOSE_WAIT);
- }
- }
- else
+
+ if ( trk.update_on_fin_recv(tsd) )
{
- //Out of Order FIN received
- if ( !trk.is_fin_seq_set() )
- trk.set_fin_final_seq( tsd.get_seg_seq() );
+ trk.session->update_perf_base_state(TcpStreamTracker::TCP_CLOSING);
+ trk.set_tcp_state(TcpStreamTracker::TCP_CLOSE_WAIT);
}
+
return true;
}
trk.session->update_timestamp_tracking(tsd);
trk.session->update_perf_base_state(TcpStreamTracker::TCP_ESTABLISHED);
trk.set_tcp_state(TcpStreamTracker::TCP_ESTABLISHED);
- trk.r_nxt_ack = tsd.get_seg_ack();
return true;
}