From: Juweria Ali Imran (jaliimra) Date: Thu, 7 Mar 2024 14:22:19 +0000 (+0000) Subject: Pull request #4235: stream_tcp: add reasons for drops due to trims X-Git-Tag: 3.1.82.0~2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e6407d4e824e870ad68ecb47617ccc397df27081;p=thirdparty%2Fsnort3.git Pull request #4235: stream_tcp: add reasons for drops due to trims Merge in SNORT/snort3 from ~JALIIMRA/snort3:drop_reason to master Squashed commit of the following: commit fb9c9dc56abfd72ddc898814680be4f356d71ee8 Author: Juweria Ali Imran Date: Thu Feb 1 03:54:41 2024 -0500 stream_tcp: add reasons for drops due to trims --- diff --git a/src/stream/tcp/tcp_normalizer.cc b/src/stream/tcp/tcp_normalizer.cc index 586925ab4..7a72fa281 100644 --- a/src/stream/tcp/tcp_normalizer.cc +++ b/src/stream/tcp/tcp_normalizer.cc @@ -49,11 +49,13 @@ TcpNormalizer::NormStatus TcpNormalizer::apply_normalizations( if ( !tns.tracker->is_segment_seq_valid(tsd) ) { tcpStats.invalid_seq_num++; + log_drop_reason(tns, tsd, false, "normalizer", "Normalizer: Sequence number is invalid\n"); trim_win_payload(tns, tsd); 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)); @@ -65,11 +67,14 @@ TcpNormalizer::NormStatus TcpNormalizer::apply_normalizations( if ( stream_is_inorder ) { + bool inline_mode = tsd.is_nap_policy_inline(); + if ( get_stream_window(tns, tsd) == 0 ) { if ( !data_inside_window(tns, tsd) ) { - trim_win_payload(tns, tsd, 0, tsd.is_nap_policy_inline()); + log_drop_reason(tns, tsd, inline_mode, "normalizer", "Normalizer: Data is outside the TCP Window\n"); + trim_win_payload(tns, tsd, 0, inline_mode); return NORM_TRIMMED; } @@ -77,20 +82,26 @@ TcpNormalizer::NormStatus TcpNormalizer::apply_normalizations( { tcpStats.zero_win_probes++; set_zwp_seq(tns, seq); - trim_win_payload(tns, tsd, MAX_ZERO_WIN_PROBE_LEN, tsd.is_nap_policy_inline()); + log_drop_reason(tns, tsd, inline_mode, "normalizer", + "Normalizer: Maximum Zero Window Probe length supported at a time is 1 byte\n"); + trim_win_payload(tns, tsd, MAX_ZERO_WIN_PROBE_LEN, inline_mode); } } } else if ( get_stream_window(tns, tsd) == 0 ) { + bool inline_mode = tsd.is_nap_policy_inline(); + if ( SEQ_EQ(seq, get_zwp_seq(tns)) ) { tcpStats.zero_win_probes++; - trim_win_payload(tns, tsd, MAX_ZERO_WIN_PROBE_LEN, tsd.is_nap_policy_inline()); + trim_win_payload(tns, tsd, MAX_ZERO_WIN_PROBE_LEN, inline_mode); + log_drop_reason(tns, tsd, inline_mode, "normalizer", "Normalizer: Maximum Zero Window Probe length supported at a time is 1 byte\n"); return NORM_TRIMMED; } - trim_win_payload(tns, tsd, 0, tsd.is_nap_policy_inline()); + log_drop_reason(tns, tsd, inline_mode, "normalizer", "Normalizer: Received data during a Zero Window that is not a Zero Window Probe\n"); + trim_win_payload(tns, tsd, 0, inline_mode); return NORM_TRIMMED; } @@ -169,30 +180,58 @@ bool TcpNormalizer::packet_dropper( bool TcpNormalizer::trim_syn_payload( TcpNormalizerState& tns, TcpSegmentDescriptor& tsd, uint32_t max) { - if (tsd.get_len() > max) + uint32_t len = tsd.get_len(); + + if (len > max) + { + if ( PacketTracer::is_active() && (NormMode)tns.trim_syn == NORM_MODE_ON ) + PacketTracer::log("Normalizer: Trimming payload of SYN packet with length (%u) to a maximum value of %u\n", len, max); + return trim_payload(tns, tsd, max, (NormMode)tns.trim_syn, PC_TCP_TRIM_SYN); + } return false; } void TcpNormalizer::trim_rst_payload( TcpNormalizerState& tns, TcpSegmentDescriptor& tsd, uint32_t max) { - if (tsd.get_len() > max) + uint32_t len = tsd.get_len(); + + if (len > max) + { + if ( PacketTracer::is_active() && (NormMode)tns.trim_rst == NORM_MODE_ON ) + PacketTracer::log("Normalizer: Trimming payload of RST packet with length (%u) to a maximum value of %u\n", len, max); + trim_payload(tns, tsd, max, (NormMode)tns.trim_rst, PC_TCP_TRIM_RST); + } } void TcpNormalizer::trim_win_payload( TcpNormalizerState& tns, TcpSegmentDescriptor& tsd, uint32_t max, bool force) { - if (tsd.get_len() > max) + uint32_t len = tsd.get_len(); + + if (len > max) + { + if ( PacketTracer::is_active() && (force || (NormMode)tns.trim_win == NORM_MODE_ON) ) + PacketTracer::log("Normalizer: Trimming payload with length (%u) to a maximum value of %u\n", len, max); + trim_payload(tns, tsd, max, (NormMode)tns.trim_win, PC_TCP_TRIM_WIN, force); + } } void TcpNormalizer::trim_mss_payload( TcpNormalizerState& tns, TcpSegmentDescriptor& tsd, uint32_t max) { - if (tsd.get_len() > max) + uint32_t len = tsd.get_len(); + + if (len > max) + { + if ( PacketTracer::is_active() && (NormMode)tns.trim_mss == NORM_MODE_ON ) + PacketTracer::log("Normalizer: Trimming payload with length (%u) to fit MSS size (%u)\n", len, max); + trim_payload(tns, tsd, max, (NormMode)tns.trim_mss, PC_TCP_TRIM_MSS); + } } void TcpNormalizer::ecn_tracker( @@ -476,6 +515,16 @@ void TcpNormalizer::set_zwp_seq( tns.zwp_seq = seq; } +void TcpNormalizer::log_drop_reason(TcpNormalizerState& tns, const TcpSegmentDescriptor& tsd, bool force, const char *issuer, const std::string& log) +{ + if ( force || (NormMode)tns.trim_win == NORM_MODE_ON ) + { + tsd.get_pkt()->active->set_drop_reason(issuer); + if (PacketTracer::is_active()) + PacketTracer::log("%s", log.c_str()); + } +} + uint16_t TcpNormalizer::set_urg_offset( TcpNormalizerState&, const tcp::TCPHdr* tcph, uint16_t dsize) { diff --git a/src/stream/tcp/tcp_normalizer.h b/src/stream/tcp/tcp_normalizer.h index 10b119af9..68e6a75ac 100644 --- a/src/stream/tcp/tcp_normalizer.h +++ b/src/stream/tcp/tcp_normalizer.h @@ -87,6 +87,7 @@ public: virtual int handle_repeated_syn(State&, TcpSegmentDescriptor&) = 0; 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); static void reset_stats(); diff --git a/src/stream/tcp/tcp_normalizers.h b/src/stream/tcp/tcp_normalizers.h index 2715100d0..eaa3190de 100644 --- a/src/stream/tcp/tcp_normalizers.h +++ b/src/stream/tcp/tcp_normalizers.h @@ -101,6 +101,9 @@ public: void set_zwp_seq(uint32_t seq) { 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); } + uint16_t set_urg_offset(const snort::tcp::TCPHdr* tcph, uint16_t dsize) { return norm->set_urg_offset(tns, tcph, dsize); } diff --git a/src/stream/tcp/tcp_reassembler.cc b/src/stream/tcp/tcp_reassembler.cc index 1c1d2a498..f0fdd58b1 100644 --- a/src/stream/tcp/tcp_reassembler.cc +++ b/src/stream/tcp/tcp_reassembler.cc @@ -952,6 +952,9 @@ void TcpReassembler::fallback(TcpStreamTracker& tracker, bool server_side) bool TcpReassembler::segment_within_seglist_window(TcpReassemblerState& trs, TcpSegmentDescriptor& tsd) { + if ( !trs.sos.seglist.head ) + return true; + uint32_t start, end = (trs.sos.seglist.tail->i_seq + trs.sos.seglist.tail->i_len); if ( SEQ_LT(trs.sos.seglist_base_seq, trs.sos.seglist.head->i_seq) ) diff --git a/src/stream/tcp/tcp_session.cc b/src/stream/tcp/tcp_session.cc index b1773731b..0d9bc074a 100644 --- a/src/stream/tcp/tcp_session.cc +++ b/src/stream/tcp/tcp_session.cc @@ -358,10 +358,11 @@ bool TcpSession::flow_exceeds_config_thresholds(TcpSegmentDescriptor& tsd) if ( inline_mode || listener->normalizer.get_trim_win() == NORM_MODE_ON) { - tsd.get_pkt()->active->set_drop_reason("stream"); tel.set_tcp_event(EVENT_MAX_QUEUED_BYTES_EXCEEDED); - if (PacketTracer::is_active()) - PacketTracer::log("Stream: Flow exceeded the configured max byte threshold (%u)\n", tcp_config->max_queued_bytes); + listener->normalizer.log_drop_reason(tsd, inline_mode, "stream", + "Stream: Flow exceeded the configured max byte threshold (" + std::to_string(tcp_config->max_queued_bytes) + + "). You may want to adjust the 'max_bytes' parameter in the NAP policy" + " to a higher value, or '0' for unlimited.\n"); } listener->normalizer.trim_win_payload(tsd, space_left, inline_mode); @@ -394,10 +395,11 @@ bool TcpSession::flow_exceeds_config_thresholds(TcpSegmentDescriptor& tsd) if ( inline_mode || listener->normalizer.get_trim_win() == NORM_MODE_ON) { - tsd.get_pkt()->active->set_drop_reason("stream"); tel.set_tcp_event(EVENT_MAX_QUEUED_SEGS_EXCEEDED); - if (PacketTracer::is_active()) - PacketTracer::log("Stream: Flow exceeded the configured max segment threshold (%u)\n", tcp_config->max_queued_segs); + listener->normalizer.log_drop_reason(tsd, inline_mode, "stream", + "Stream: Flow exceeded the configured max segment threshold (" + std::to_string(tcp_config->max_queued_segs) + + "). You may want to adjust the 'max_segments' parameter in the NAP policy" + " to a higher value, or '0' for unlimited.\n"); } listener->normalizer.trim_win_payload(tsd, 0, inline_mode); @@ -751,7 +753,6 @@ bool TcpSession::check_for_window_slam(TcpSegmentDescriptor& tsd) void TcpSession::mark_packet_for_drop(TcpSegmentDescriptor& tsd) { - tsd.get_listener()->normalizer.packet_dropper(tsd, NORM_TCP_BLOCK); set_pkt_action_flag(ACTION_BAD_PKT); }