// sequence must match enum StreamPolicy defines in tcp_defs.h
#define TCP_POLICIES \
"first | last | linux | old_linux | bsd | macos | solaris | irix | " \
- "hpux11 | hpux10 | windows | win_2003 | vista | proxy"
+ "hpux11 | hpux10 | windows | win_2003 | vista | proxy | asymmetric"
struct AlertInfo
{
OS_WINDOWS2K3,
OS_VISTA,
OS_PROXY,
+ MISSED_3WHS,
OS_END_OF_LIST,
OS_DEFAULT = OS_BSD
};
{ CountType::SUM, "proxy_mode_flows", "number of flows set to proxy normalization policy" },
{ CountType::SUM, "full_retransmits", "number of fully retransmitted segments" },
{ CountType::SUM, "flush_on_asymmetric_flow", "number of flushes on asymmetric flows" },
+ { CountType::SUM, "asymmetric_flows", "number of completed flows having one-way traffic only" },
{ CountType::END, nullptr, nullptr }
};
else
config->flags |= STREAM_CONFIG_NO_ASYNC_REASSEMBLY;
}
+
else if ( v.is("require_3whs") )
{
config->hs_timeout = v.get_int32();
}
+
else if ( v.is("show_rebuilt_packets") )
{
if ( v.get_bool() )
else
config->flags &= ~STREAM_CONFIG_SHOW_PACKETS;
}
+
else if ( v.is("track_only") )
{
if ( v.get_bool() )
PegCount proxy_mode_flows;
PegCount full_retransmits;
PegCount flush_on_asymmetric_flow;
+ PegCount asymmetric_flows;
};
extern THREAD_LOCAL struct TcpStats tcpStats;
TcpNormalizer::NormStatus TcpNormalizer::apply_normalizations(
TcpNormalizerState& tns, TcpSegmentDescriptor& tsd, uint32_t seq, bool stream_is_inorder)
{
- // if this is a midstream pickup then skip normalizations
- if ( Stream::is_midstream(tsd.get_flow()) )
- return NORM_OK;
-
- // these normalizations can't be done if we missed setup. and
- // window is zero in one direction until we've seen both sides.
- if ( tsd.get_flow()->two_way_traffic() )
+ // drop packet if sequence num is invalid
+ if ( !tns.tracker->is_segment_seq_valid(tsd) )
{
- // drop packet if sequence num is invalid
- if ( !tns.tracker->is_segment_seq_valid(tsd) )
- {
- bool inline_mode = tsd.is_nap_policy_inline();
- tcpStats.invalid_seq_num++;
- log_drop_reason(tns, tsd, inline_mode, "normalizer", "Normalizer: Sequence number is invalid\n");
- trim_win_payload(tns, tsd, 0, inline_mode);
- return NORM_BAD_SEQ;
- }
+ bool inline_mode = tsd.is_nap_policy_inline();
+ tcpStats.invalid_seq_num++;
+ log_drop_reason(tns, tsd, inline_mode, "normalizer", "Normalizer: Sequence number is invalid\n");
+ trim_win_payload(tns, tsd, 0, inline_mode);
+ return NORM_BAD_SEQ;
+ }
- // trim to fit in listener's window and mss
- log_drop_reason(tns, tsd, false, "normalizer", "Normalizer: Trimming payload to fit window size\n");
- trim_win_payload(tns, tsd,
- (tns.tracker->r_win_base + tns.tracker->get_snd_wnd() - tns.tracker->rcv_nxt));
+ // trim to fit in listener's window and mss
+ log_drop_reason(tns, tsd, false, "normalizer", "Normalizer: Trimming payload to fit window size\n");
+ trim_win_payload(tns, tsd,
+ (tns.tracker->r_win_base + tns.tracker->get_snd_wnd() - tns.tracker->rcv_nxt));
- if ( tns.tracker->get_mss() )
- trim_mss_payload(tns, tsd, tns.tracker->get_mss());
+ if ( tns.tracker->get_mss() )
+ trim_mss_payload(tns, tsd, tns.tracker->get_mss());
- ecn_stripper(tns, tsd);
- }
+ ecn_stripper(tns, tsd);
if ( stream_is_inorder )
{
virtual ~TcpNormalizer() = default;
virtual void init(State&) { }
+ virtual void init(TcpNormalizer*) { }
virtual NormStatus apply_normalizations(
State&, TcpSegmentDescriptor&, uint32_t seq, bool stream_is_inorder);
virtual int handle_paws_no_timestamps(State&, TcpSegmentDescriptor&);
std::string my_name;
+ TcpNormalizer* prev_norm = nullptr;
};
#endif
int handle_repeated_syn(TcpNormalizerState&, TcpSegmentDescriptor&) override;
};
+// Normalizations applied or excluded for midstream and one-way asymmetric flows are common
+class TcpNormalizerMissed3whs : public TcpNormalizer
+{
+public:
+ TcpNormalizerMissed3whs()
+ { my_name = "Missed3whs"; }
+
+ void init(TcpNormalizer* prev) override
+ { prev_norm = prev; }
+
+ TcpNormalizer::NormStatus apply_normalizations(
+ TcpNormalizerState&, TcpSegmentDescriptor&, uint32_t seq, bool stream_is_inorder) override;
+ bool validate_rst(TcpNormalizerState&, TcpSegmentDescriptor&) override;
+ int handle_paws(TcpNormalizerState&, TcpSegmentDescriptor&) override;
+ int handle_repeated_syn(TcpNormalizerState&, TcpSegmentDescriptor&) override;
+};
static inline int handle_repeated_syn_mswin(
TcpStreamTracker* talker, TcpStreamTracker* listener,
return ACTION_NOTHING;
}
+TcpNormalizer::NormStatus TcpNormalizerMissed3whs::apply_normalizations(
+ TcpNormalizerState&, TcpSegmentDescriptor&, uint32_t, bool)
+{
+ // when a flow is Midstream/Asymmetric, not all packet normalizations are possible
+ return NORM_OK;
+}
+
+bool TcpNormalizerMissed3whs::validate_rst(
+ TcpNormalizerState& tns, TcpSegmentDescriptor& tsd)
+{
+ if ( tns.session->flow->two_way_traffic() )
+ return prev_norm->validate_rst(tns, tsd);
+
+ if ( !prev_norm->get_name().compare("OS_Hpux11") )
+ return validate_rst_seq_geq(tns, tsd);
+
+ return true;
+}
+
+int TcpNormalizerMissed3whs::handle_paws(
+ TcpNormalizerState& tns, TcpSegmentDescriptor& tsd)
+{
+ return ACTION_NOTHING;
+}
+
+int TcpNormalizerMissed3whs::handle_repeated_syn(
+ TcpNormalizerState& tns, TcpSegmentDescriptor& tsd)
+{
+ return prev_norm->handle_repeated_syn(tns, tsd);
+}
+
void TcpNormalizerPolicy::init(StreamPolicy os, TcpStreamSession* ssn, TcpStreamTracker* trk, TcpStreamTracker* peer)
{
+ TcpNormalizer* prev_norm = nullptr;
+ if ( os == StreamPolicy::MISSED_3WHS and os != tns.os_policy )
+ prev_norm = TcpNormalizerFactory::get_instance(tns.os_policy);
+
tns.os_policy = os;
tns.session = ssn;
tns.tracker = trk;
tns.opt_block = Normalize_GetMode(NORM_TCP_OPT);
norm = TcpNormalizerFactory::get_instance(os);
- norm->init(tns);
+
+ if ( prev_norm )
+ norm->init(prev_norm);
+ else
+ norm->init(tns);
}
TcpNormalizer* TcpNormalizerFactory::normalizers[StreamPolicy::OS_END_OF_LIST];
normalizers[StreamPolicy::OS_WINDOWS2K3] = new TcpNormalizerWindows2K3;
normalizers[StreamPolicy::OS_VISTA] = new TcpNormalizerVista;
normalizers[StreamPolicy::OS_PROXY] = new TcpNormalizerProxy;
+ normalizers[StreamPolicy::MISSED_3WHS] = new TcpNormalizerMissed3whs;
}
void TcpNormalizerFactory::term()
{
- for ( auto sp = StreamPolicy::OS_FIRST; sp <= StreamPolicy::OS_PROXY; sp++ )
+ for ( auto sp = StreamPolicy::OS_FIRST; sp < StreamPolicy::OS_END_OF_LIST; sp++ )
delete normalizers[sp];
}
TcpNormalizer* TcpNormalizerFactory::get_instance(StreamPolicy sp)
{
- assert( sp <= StreamPolicy::OS_PROXY );
+ assert( sp < StreamPolicy::OS_END_OF_LIST );
return normalizers[sp];
}
tcp_init = false;
tcpStats.released++;
+ if ( !flow->two_way_traffic() and free_flow_data )
+ tcpStats.asymmetric_flows++;
+
if ( flush_segments )
{
client.reassembler.flush_queued_segments(flow, true, p);
DataBus::publish(intrinsic_pub_id, IntrinsicEventIds::FLOW_STATE_CHANGE, nullptr, flow);
}
+void TcpSession::check_flow_missed_3whs()
+{
+ if ( flow->two_way_traffic() )
+ return;
+
+ if ( PacketTracer::is_active() )
+ PacketTracer::log("Stream TCP did not see the complete 3-Way Handshake. "
+ "Not all normalizations will be in effect\n");
+
+ client.normalizer.init(StreamPolicy::MISSED_3WHS, this, &client, &server);
+ server.normalizer.init(StreamPolicy::MISSED_3WHS, this, &server, &client);
+}
+
void TcpSession::update_stream_order(const TcpSegmentDescriptor& tsd, bool aligned)
{
TcpStreamTracker* listener = tsd.get_listener();
bool TcpSession::check_for_window_slam(TcpSegmentDescriptor& tsd)
{
+ if (Stream::is_midstream(tsd.get_flow()) or !flow->two_way_traffic())
+ return false;
+
TcpStreamTracker* listener = tsd.get_listener();
if ( tcp_config->max_window && (tsd.get_wnd() > tcp_config->max_window) )
}
else if ( tsd.is_packet_from_client() && (tsd.get_wnd() <= SLAM_MAX)
&& (tsd.get_ack() == listener->get_iss() + 1)
- && !(tsd.get_tcph()->is_fin() || tsd.get_tcph()->is_rst())
- && !(flow->get_session_flags() & SSNFLAG_MIDSTREAM))
+ && !(tsd.get_tcph()->is_fin() || tsd.get_tcph()->is_rst()))
{
/* got a window slam alert! */
tel.set_tcp_event(EVENT_WINDOW_SLAM);
client.init_flush_policy();
server.init_flush_policy();
+ if ( tsd.is_packet_from_client() ) // Important if the 3-way handshake's ACK contains data
+ flow->set_session_flags(SSNFLAG_SEEN_CLIENT);
+ else
+ flow->set_session_flags(SSNFLAG_SEEN_SERVER);
+
+ check_flow_missed_3whs();
+
set_no_ack(tcp_config->no_ack);
}
bool filter_packet_for_reassembly(TcpSegmentDescriptor&, TcpStreamTracker*);
void check_small_segment_threshold(const TcpSegmentDescriptor&, TcpStreamTracker*);
int32_t kickstart_asymmetric_flow(const TcpSegmentDescriptor&, TcpStreamTracker*);
+ void check_flow_missed_3whs();
private:
TcpStateMachine* tsm;
#include "tcp_state_listen.h"
+#include "packet_tracer/packet_tracer.h"
#include "pub_sub/stream_event_ids.h"
#include "stream/stream.h"
if ( trk.session->is_midstream_allowed(tsd) )
{
Flow* flow = tsd.get_flow();
-
flow->session_state |= STREAM_STATE_MIDSTREAM;
+
if ( !Stream::is_midstream(flow) )
{
+ TcpStreamTracker* listener = tsd.get_listener();
+ TcpStreamTracker* talker = tsd.get_talker();
+
+ trk.normalizer.init(StreamPolicy::MISSED_3WHS, trk.session, listener, talker);
+ trk.normalizer.init(StreamPolicy::MISSED_3WHS, trk.session, talker, listener);
flow->set_session_flags(SSNFLAG_MIDSTREAM);
+
+ if ( PacketTracer::is_active() )
+ PacketTracer::log("Stream TCP did not see the complete 3-Way Handshake. "
+ "Not all normalizations will be in effect\n");
+
DataBus::publish(Stream::get_pub_id(), StreamEventIds::TCP_MIDSTREAM, tsd.get_pkt());
}
#include "tcp_state_none.h"
+#include "packet_tracer/packet_tracer.h"
#include "pub_sub/stream_event_ids.h"
#include "stream/stream.h"
{
Flow* flow = tsd.get_flow();
flow->session_state |= STREAM_STATE_MIDSTREAM;
+
if ( !Stream::is_midstream(flow) )
{
+ TcpStreamTracker* listener = tsd.get_listener();
+ TcpStreamTracker* talker = tsd.get_talker();
+
+ trk.normalizer.init(StreamPolicy::MISSED_3WHS, trk.session, listener, talker);
+ trk.normalizer.init(StreamPolicy::MISSED_3WHS, trk.session, talker, listener);
flow->set_session_flags(SSNFLAG_MIDSTREAM);
+
+ if ( PacketTracer::is_active() )
+ PacketTracer::log("Stream TCP did not see the complete 3-Way Handshake. "
+ "Not all normalizations will be in effect\n");
+
DataBus::publish(Stream::get_pub_id(), StreamEventIds::TCP_MIDSTREAM, tsd.get_pkt());
}