#define SLAM_MAX 4
#define MAX_ZERO_WIN_PROBE_LEN 1
+#define MAX_KEEP_ALIVE_PROBE_LEN 1
// target-based policy types - changes to this enum require changes to stream.h::TCP_POLICIES
enum StreamPolicy : uint8_t
{ CountType::MAX, "max_bytes", "maximum number of bytes queued in any flow" },
{ CountType::SUM, "zero_len_tcp_opt", "number of zero length tcp options" },
{ CountType::SUM, "zero_win_probes", "number of tcp zero window probes" },
+ { CountType::SUM, "keep_alive_probes", "number of tcp keep-alive probes" },
{ 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" },
PegCount max_bytes;
PegCount zero_len_tcp_opt;
PegCount zero_win_probes;
+ PegCount keep_alive_probes;
PegCount proxy_mode_flows;
PegCount full_retransmits;
PegCount flush_on_asymmetric_flow;
// drop packet if sequence num is invalid
if ( !tns.tracker->is_segment_seq_valid(tsd) )
{
+ if ( is_keep_alive_probe(tns, tsd) )
+ return NORM_BAD_SEQ;
+
bool inline_mode = tsd.is_nap_policy_inline();
tcpStats.invalid_seq_num++;
log_drop_reason(tns, tsd, inline_mode, "stream", "Normalizer: Sequence number is invalid\n");
}
}
+bool TcpNormalizer::is_keep_alive_probe(TcpNormalizerState& tns, const TcpSegmentDescriptor& tsd)
+{
+ if ( (tns.tracker->r_win_base - tsd.get_seq()) == MAX_KEEP_ALIVE_PROBE_LEN
+ and tsd.get_len() <= MAX_KEEP_ALIVE_PROBE_LEN and
+ !(tsd.get_tcph()->th_flags & (TH_SYN|TH_FIN|TH_RST)) )
+ {
+ tcpStats.keep_alive_probes++;
+ return true;
+ }
+
+ return false;
+}
+
uint16_t TcpNormalizer::set_urg_offset(
TcpNormalizerState&, const tcp::TCPHdr* tcph, uint16_t dsize)
{
virtual uint16_t set_urg_offset(State&, const snort::tcp::TCPHdr* tcph, uint16_t dsize);
virtual void set_zwp_seq(State&, uint32_t seq);
virtual void log_drop_reason(State&, const TcpSegmentDescriptor&, bool inline_mode, const char *issuer, const std::string& log);
+ virtual bool is_keep_alive_probe(State&, const TcpSegmentDescriptor&);
static void reset_stats();
{ return norm->set_zwp_seq(tns, seq); }
void log_drop_reason(const TcpSegmentDescriptor& tsd, bool inline_mode, const char *issuer, const std::string& log)
- { return norm->log_drop_reason(tns, tsd , inline_mode, issuer, log); }
+ { return norm->log_drop_reason(tns, tsd, inline_mode, issuer, log); }
+
+ bool is_keep_alive_probe(const TcpSegmentDescriptor& tsd)
+ { return norm->is_keep_alive_probe(tns, tsd); }
uint16_t set_urg_offset(const snort::tcp::TCPHdr* tcph, uint16_t dsize)
{ return norm->set_urg_offset(tns, tcph, dsize); }
if ( SEQ_LT(snd_nxt, snd_una) )
snd_nxt = snd_una;
}
- if ( !tsd.get_len() and snd_wnd == 0
- and SEQ_LT(tsd.get_seq(), r_win_base) )
- tcpStats.zero_win_probes++;
+ if ( !tsd.get_len() and SEQ_LT(tsd.get_seq(), r_win_base) )
+ {
+ if ( snd_wnd == 0 )
+ tcpStats.zero_win_probes++;
+ else if ( (r_win_base - tsd.get_seq()) == MAX_KEEP_ALIVE_PROBE_LEN
+ and !(tsd.get_tcph()->th_flags & (TH_SYN|TH_FIN|TH_RST)) )
+ tcpStats.keep_alive_probes++;
+ }
}
// In no-ack policy, data is implicitly acked immediately.