From: Russ Combs (rucombs) Date: Thu, 17 Sep 2020 17:50:55 +0000 (+0000) Subject: Merge pull request #2426 in SNORT/snort3 from ~DAVMCPHE/snort3:stream_tcp_fixits... X-Git-Tag: 3.0.3-1~18 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=8961411bd8097a9637c8b56ddd446ae4a37a6a81;p=thirdparty%2Fsnort3.git Merge pull request #2426 in SNORT/snort3 from ~DAVMCPHE/snort3:stream_tcp_fixits to master Squashed commit of the following: commit 13038c9f32725d9286103fca639511b3d236378d Author: davis mcpherson Date: Wed Sep 16 16:55:38 2020 -0400 stream_tcp: refactor tcp handling of no flags to drop packet before any processing, don't generate event commit 3e19864b0c21b1a08295e8d0c935cfb29d216d91 Author: davis mcpherson Date: Mon Sep 14 09:22:40 2020 -0400 stream_tcp: updates to resolve PR review comments commit 0d05172e8d97fc8c98105ec7636a258e9a1d7f8a Author: davis mcpherson Date: Wed Sep 9 10:05:01 2020 -0400 stream_tcp: merge the setup methods of the TcpStreamSession and TcpSession classes into a single method in TcpSession commit df18ba9cdd09abe0400ae41820d2f1d4ca688068 Author: davis mcpherson Date: Wed Aug 26 09:33:15 2020 -0400 stream_tcp: add PegCount for tcp packets received with an invalid ack commit ac9f49387302084104403c3c0a490741bd00fe92 Author: davis mcpherson Date: Wed Aug 26 09:14:27 2020 -0400 stream_tcp: delete unused packet action flags, set action flags via its setter commit bd0cf57e31549ec2fc9eb82cf4f3d276e0bd8db9 Author: davis mcpherson Date: Wed Aug 26 08:09:31 2020 -0400 stream_tcp: delete redundant calls to flush data when FIN is received commit 3280c0ba1d11d045459483d741ab8b81031ca070 Author: davis mcpherson Date: Thu Aug 13 10:34:15 2020 -0400 stream_tcp: handle bad tcp packets consistently when normalizing in ips mode commit 3058628b9d04b8e513c92e63ee20265fb76f3f97 Author: davis mcpherson Date: Tue Aug 11 16:04:18 2020 -0400 stream_tcp: add an assert to catch tcp state/event combination that should not occur commit 0f383f759e850602e17e12ea6fd78f35b31a81c0 Author: davis mcpherson Date: Tue Aug 11 15:55:40 2020 -0400 stream_tcp: remove FIXIT-H to add ack validation, the ack is already validated when processed on the listener side commit 7570270137e4ee288ab892a81305dc2cc4671849 Author: davis mcpherson Date: Tue Aug 11 15:43:52 2020 -0400 stream_tcp: implement helper function to return true if the TCP packet is a data segment, false otherwise commit acd13bf5378f9f80c4d757ef710c4d104d77d714 Author: davis mcpherson Date: Tue Aug 11 15:21:46 2020 -0400 stream_tcp: this FIXIT-H has been removed because by definition an Ack Sent event in TcpStateNone means the SYN-ACK was not seen, so no way to do the check suggested commit b4ebcb37e6c2045b0f78bd4e12f1d2b3eb337353 Author: davis mcpherson Date: Mon Aug 10 10:02:02 2020 -0400 stream_tcp: arrange TCP tracker member vars to optimize storage requirements, add helper functions to access private splitter functions stream_tcp: refactor tracker and reassembler classes to improve encapsulation and move member variables to appropriate class commit ce9d8536c14011dc4dc33f43d33259a76c0f6e9d Author: davis mcpherson Date: Tue Jul 21 13:31:28 2020 -0400 stream_tcp: fix issues with stream_tcp handling of the TCP MSS option --- diff --git a/src/stream/tcp/held_packet_queue.cc b/src/stream/tcp/held_packet_queue.cc index 889a3f25e..1b4d6dcc9 100644 --- a/src/stream/tcp/held_packet_queue.cc +++ b/src/stream/tcp/held_packet_queue.cc @@ -43,8 +43,7 @@ void HeldPacket::adjust_expiration(const timeval& delta, bool up) HeldPacket::HeldPacket(DAQ_Msg_h msg, uint32_t seq, const timeval& exp, TcpStreamTracker& trk) : daq_msg(msg), seq_num(seq), expiration(exp), tracker(trk), expired(false) -{ -} +{ } HeldPacketQueue::iter_t HeldPacketQueue::append(DAQ_Msg_h msg, uint32_t seq, TcpStreamTracker& trk) @@ -69,7 +68,6 @@ bool HeldPacketQueue::execute(const timeval& cur_time, int max_remove) auto held_packet = q.begin(); if ( held_packet->has_expired(cur_time) ) { - assert(held_packet == held_packet->get_tracker().held_packet); held_packet->get_tracker().perform_partial_flush(); tcpStats.held_packet_timeouts++; } diff --git a/src/stream/tcp/ips_stream_reassemble.cc b/src/stream/tcp/ips_stream_reassemble.cc index 64d9c4ecb..e491cd437 100644 --- a/src/stream/tcp/ips_stream_reassemble.cc +++ b/src/stream/tcp/ips_stream_reassemble.cc @@ -117,13 +117,13 @@ IpsOption::EvalStatus ReassembleOption::eval(Cursor&, Packet* pkt) { if ( srod.direction & SSN_DIR_FROM_SERVER ) { - tcpssn->server.flush_policy = STREAM_FLPOLICY_IGNORE; + tcpssn->server.set_flush_policy(STREAM_FLPOLICY_IGNORE); Stream::set_splitter(lwssn, true); } if ( srod.direction & SSN_DIR_FROM_CLIENT ) { - tcpssn->client.flush_policy = STREAM_FLPOLICY_IGNORE; + tcpssn->client.set_flush_policy(STREAM_FLPOLICY_IGNORE); Stream::set_splitter(lwssn, false); } } @@ -133,13 +133,13 @@ IpsOption::EvalStatus ReassembleOption::eval(Cursor&, Packet* pkt) // FIXIT-M PAF need to check for ips / on-data if ( srod.direction & SSN_DIR_FROM_SERVER ) { - tcpssn->server.flush_policy = STREAM_FLPOLICY_ON_ACK; + tcpssn->server.set_flush_policy(STREAM_FLPOLICY_ON_ACK); Stream::set_splitter(lwssn, true, new AtomSplitter(true)); } if ( srod.direction & SSN_DIR_FROM_CLIENT ) { - tcpssn->client.flush_policy = STREAM_FLPOLICY_ON_ACK; + tcpssn->client.set_flush_policy(STREAM_FLPOLICY_ON_ACK); Stream::set_splitter(lwssn, false, new AtomSplitter(false)); } } @@ -319,7 +319,7 @@ TEST_CASE("IPS Stream Reassemble", "[ips_stream_reassemble][stream_tcp]") StreamSplitter* ss = Stream::get_splitter(flow, true); CHECK( ( ss != nullptr ) ); CHECK( ( !ss->is_paf() ) ); - CHECK( ( ( ( TcpSession* )pkt->flow->session)->server.flush_policy + CHECK( ( ( ( TcpSession* )pkt->flow->session)->server.get_flush_policy() == STREAM_FLPOLICY_IGNORE ) ); } #endif diff --git a/src/stream/tcp/segment_overlap_editor.h b/src/stream/tcp/segment_overlap_editor.h index 116151ebd..ee7f0688c 100644 --- a/src/stream/tcp/segment_overlap_editor.h +++ b/src/stream/tcp/segment_overlap_editor.h @@ -23,6 +23,7 @@ #define SEGMENT_OVERLAP_EDITOR_H #include "normalize/normalize.h" +#include "stream/paf.h" #include "tcp_segment_node.h" class TcpSession; @@ -37,8 +38,6 @@ struct SegmentOverlapState const uint8_t* rdata; TcpSegmentList seglist; - StreamPolicy reassembly_policy; - 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 */ @@ -58,6 +57,7 @@ struct SegmentOverlapState uint16_t len; uint16_t rsize; int8_t tcp_ips_data; + StreamPolicy reassembly_policy; bool keep_segment; @@ -68,15 +68,31 @@ struct SegmentOverlapState void init_soe(TcpSegmentDescriptor& tsd, TcpSegmentNode* left, TcpSegmentNode* right); }; +/* Only track a maximum number of alerts per session */ +#define MAX_SESSION_ALERTS 8 +struct StreamAlertInfo +{ + /* For storing alerts that have already been seen on the session */ + uint32_t gid; + uint32_t sid; + uint32_t seq; + // if we log extra data, event_* is used to correlate with alert + uint32_t event_id; + uint32_t event_second; +}; + struct TcpReassemblerState { SegmentOverlapState sos; TcpStreamTracker* tracker; uint32_t flush_count; // number of flushed queued segments uint32_t xtradata_mask; // extra data available to log - bool server_side; + StreamAlertInfo alerts[MAX_SESSION_ALERTS]; + uint8_t alert_count = 0; uint8_t ignore_dir; uint8_t packet_dir; + bool server_side; + PAF_State paf_state; }; class SegmentOverlapEditor diff --git a/src/stream/tcp/stream_tcp.cc b/src/stream/tcp/stream_tcp.cc index 59a5894f6..563ca56dd 100644 --- a/src/stream/tcp/stream_tcp.cc +++ b/src/stream/tcp/stream_tcp.cc @@ -141,8 +141,8 @@ static const InspectApi tcp_api = 0, API_RESERVED, API_OPTIONS, - MOD_NAME, - MOD_HELP, + STREAM_TCP_MOD_NAME, + STREAM_TCP_MOD_HELP, mod_ctor, mod_dtor }, diff --git a/src/stream/tcp/tcp_debug_trace.h b/src/stream/tcp/tcp_debug_trace.h index bc8253825..21c2a6b65 100644 --- a/src/stream/tcp/tcp_debug_trace.h +++ b/src/stream/tcp/tcp_debug_trace.h @@ -89,11 +89,11 @@ inline void TraceState(TcpStreamTracker& a, TcpStreamTracker& b, const char* s) 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; - unsigned fpt = a.flush_policy ? 192 : 0; + unsigned paf = ( a.is_splitter_paf() ) ? 2 : 0; + unsigned fpt = a.get_flush_policy() ? 192 : 0; fprintf(stdout, " FP=%s:%-4u SC=%-4u FL=%-4u SL=%-5u BS=%-4u", - flushxt[a.flush_policy + paf], fpt, + flushxt[a.get_flush_policy() + paf], fpt, a.reassembler.get_seg_count(), a.reassembler.get_flush_count(), a.reassembler.get_seg_bytes_logical(), a.reassembler.get_seglist_base_seq() - b.get_iss()); diff --git a/src/stream/tcp/tcp_defs.h b/src/stream/tcp/tcp_defs.h index 23af99b07..9193079d5 100644 --- a/src/stream/tcp/tcp_defs.h +++ b/src/stream/tcp/tcp_defs.h @@ -31,18 +31,10 @@ struct Packet; /* actions */ #define ACTION_NOTHING 0x00000000 -#define ACTION_FLUSH_SENDER_STREAM 0x00000001 -#define ACTION_FLUSH_RECEIVER_STREAM 0x00000002 -#define ACTION_DROP_SESSION 0x00000004 -#define ACTION_ACK_SENDER_DATA 0x00000008 -#define ACTION_ACK_RECEIVER_DATA 0x00000010 -#define ACTION_SET_SSN 0x00000040 -#define ACTION_COMPLETE_TWH 0x00000080 -#define ACTION_RST 0x00000100 -#define ACTION_BAD_SEQ 0x00000200 -#define ACTION_BAD_PKT 0x00000400 -#define ACTION_LWSSN_CLOSED 0x00000800 -#define ACTION_DISABLE_INSPECTION 0x00001000 +#define ACTION_RST 0x00000001 +#define ACTION_BAD_PKT 0x00000002 +#define ACTION_LWSSN_CLOSED 0x00000004 +#define ACTION_DISABLE_INSPECTION 0x00000008 #define TF_NONE 0x0000 #define TF_WSCALE 0x0001 diff --git a/src/stream/tcp/tcp_event_logger.h b/src/stream/tcp/tcp_event_logger.h index af8ac2f58..9c086962f 100644 --- a/src/stream/tcp/tcp_event_logger.h +++ b/src/stream/tcp/tcp_event_logger.h @@ -52,16 +52,11 @@ public: TcpEventLogger() = default; void clear_tcp_events() - { - tcp_events = 0; - } + { tcp_events = 0; } void set_tcp_event(int eventcode) - { - tcp_events |= eventcode; - } + { tcp_events |= eventcode; } - void set_tcp_internal_syn_event(); void log_tcp_events(); void log_internal_event(uint32_t eventSid); diff --git a/src/stream/tcp/tcp_module.cc b/src/stream/tcp/tcp_module.cc index 3cc1bac50..cfc771269 100644 --- a/src/stream/tcp/tcp_module.cc +++ b/src/stream/tcp/tcp_module.cc @@ -44,6 +44,10 @@ const PegInfo tcp_pegs[] = { CountType::SUM, "restarts", "sessions restarted" }, { CountType::SUM, "resyns", "SYN received on established session" }, { CountType::SUM, "discards", "tcp packets discarded" }, + { CountType::SUM, "discards_skipped", "tcp packet discards skipped due to normalization disabled" }, + { CountType::SUM, "invalid_seq_num", "tcp packets received with an invalid sequence number" }, + { CountType::SUM, "invalid_ack", "tcp packets received with an invalid ack number" }, + { CountType::SUM, "no_flags_set", "tcp packets received with no TCP flags set" }, { CountType::SUM, "events", "events generated" }, { CountType::SUM, "ignored", "tcp packets ignored" }, { CountType::SUM, "untracked", "tcp packets not tracked" }, @@ -64,6 +68,7 @@ const PegInfo tcp_pegs[] = "number of times the maximum queued segment limit was reached" }, { CountType::SUM, "exceeded_max_bytes", "number of times the maximum queued byte limit was reached" }, + { CountType::SUM, "payload_fully_trimmed", "segments with no data after trimming" }, { CountType::SUM, "internal_events", "135:X events generated" }, { CountType::SUM, "client_cleanups", "number of times data from server was flushed when session released" }, @@ -229,7 +234,7 @@ static const RuleMap stream_tcp_rules[] = }; StreamTcpModule::StreamTcpModule() : - Module(MOD_NAME, MOD_HELP, s_params) + Module(STREAM_TCP_MOD_NAME, STREAM_TCP_MOD_HELP, s_params) { config = nullptr; } @@ -243,7 +248,7 @@ ProfileStats* StreamTcpModule::get_profile( switch ( index ) { case 0: - name = MOD_NAME; + name = STREAM_TCP_MOD_NAME; parent = nullptr; return &s5TcpPerfStats; diff --git a/src/stream/tcp/tcp_module.h b/src/stream/tcp/tcp_module.h index c87706e1c..f651e3bb6 100644 --- a/src/stream/tcp/tcp_module.h +++ b/src/stream/tcp/tcp_module.h @@ -52,7 +52,6 @@ extern const PegInfo tcp_pegs[]; extern THREAD_LOCAL snort::ProfileStats s5TcpPerfStats; -extern THREAD_LOCAL snort::ProfileStats streamSizePerfStats; struct TcpStats { @@ -62,6 +61,10 @@ struct TcpStats PegCount restarts; PegCount resyns; PegCount discards; + PegCount discards_skipped; + PegCount invalid_seq_num; + PegCount invalid_ack; + PegCount no_flags_set; PegCount events; PegCount ignored; PegCount no_pickups; @@ -80,6 +83,7 @@ struct TcpStats PegCount gaps; PegCount exceeded_max_segs; PegCount exceeded_max_bytes; + PegCount payload_fully_trimmed; PegCount internalEvents; PegCount client_cleanups; PegCount server_cleanups; @@ -108,17 +112,12 @@ struct TcpStats extern THREAD_LOCAL struct TcpStats tcpStats; -inline void inc_tcp_discards() -{ - tcpStats.discards++; -} - //------------------------------------------------------------------------- // stream_tcp module //------------------------------------------------------------------------- -#define MOD_NAME "stream_tcp" -#define MOD_HELP "stream inspector for TCP flow tracking and stream normalization and reassembly" +#define STREAM_TCP_MOD_NAME "stream_tcp" +#define STREAM_TCP_MOD_HELP "stream inspector for TCP flow tracking and stream normalization and reassembly" namespace snort { diff --git a/src/stream/tcp/tcp_normalizer.cc b/src/stream/tcp/tcp_normalizer.cc index a269441fc..1d848d4ad 100644 --- a/src/stream/tcp/tcp_normalizer.cc +++ b/src/stream/tcp/tcp_normalizer.cc @@ -25,6 +25,7 @@ #include "tcp_normalizer.h" +#include "tcp_module.h" #include "tcp_stream_session.h" #include "tcp_stream_tracker.h" @@ -57,8 +58,7 @@ NormPegs TcpNormalizer::get_normalization_counts(unsigned& c) } void TcpNormalizer::trim_payload( - TcpNormalizerState&, - TcpSegmentDescriptor& tsd, uint32_t max, NormMode mode, TcpPegCounts peg) + TcpNormalizerState&, TcpSegmentDescriptor& tsd, uint32_t max, NormMode mode, TcpPegCounts peg) { if (mode == NORM_MODE_ON) { @@ -72,8 +72,7 @@ void TcpNormalizer::trim_payload( } bool TcpNormalizer::strip_tcp_timestamp( - TcpNormalizerState&, - TcpSegmentDescriptor& tsd, const tcp::TcpOption* opt, NormMode mode) + TcpNormalizerState&, TcpSegmentDescriptor& tsd, const tcp::TcpOption* opt, NormMode mode) { tcp_norm_stats[PC_TCP_TS_NOP][mode]++; @@ -98,9 +97,11 @@ bool TcpNormalizer::packet_dropper( if (mode == NORM_MODE_ON) { tsd.drop_packet(); + tcpStats.discards++; return true; } + tcpStats.discards_skipped++; return false; } @@ -282,7 +283,6 @@ int TcpNormalizer::validate_paws_timestamp( else { /* bail, we've got a packet outside the PAWS window! */ - //inc_tcp_discards(); tns.session->tel.set_tcp_event(EVENT_BAD_TIMESTAMP); packet_dropper(tns, tsd, NORM_TCP_OPT); return ACTION_BAD_PKT; @@ -293,7 +293,6 @@ int TcpNormalizer::validate_paws_timestamp( PAWS_24DAYS ) ) { /* this packet is from way too far into the future */ - //inc_tcp_discards(); tns.session->tel.set_tcp_event(EVENT_BAD_TIMESTAMP); packet_dropper(tns, tsd, NORM_TCP_OPT); return ACTION_BAD_PKT; @@ -358,6 +357,7 @@ int TcpNormalizer::handle_paws_no_timestamps( ( tns.tracker->get_tf_flags() & TF_TSTAMP ) ) { tns.session->tel.set_tcp_event(EVENT_BAD_TIMESTAMP); + packet_dropper(tns, tsd, NORM_TCP_BLOCK); return ACTION_BAD_PKT; } } diff --git a/src/stream/tcp/tcp_normalizers.cc b/src/stream/tcp/tcp_normalizers.cc index e6515712c..5303ba192 100644 --- a/src/stream/tcp/tcp_normalizers.cc +++ b/src/stream/tcp/tcp_normalizers.cc @@ -193,10 +193,7 @@ static inline int handle_repeated_syn_mswin( return ACTION_RST; } else - { - inc_tcp_discards(); return ACTION_NOTHING; - } } static inline int handle_repeated_syn_bsd( @@ -210,10 +207,7 @@ static inline int handle_repeated_syn_bsd( return ACTION_RST; } else - { - inc_tcp_discards(); return ACTION_NOTHING; - } } // Linux, Win2k3 et al. do not support timestamps if the 3whs used a 0 timestamp. @@ -337,7 +331,6 @@ int TcpNormalizerMacOS::handle_repeated_syn( TcpNormalizerState&, TcpSegmentDescriptor&) { /* MACOS ignores a 2nd SYN, regardless of the sequence number. */ - inc_tcp_discards(); return ACTION_NOTHING; } diff --git a/src/stream/tcp/tcp_reassembler.cc b/src/stream/tcp/tcp_reassembler.cc index e85dace90..222089b49 100644 --- a/src/stream/tcp/tcp_reassembler.cc +++ b/src/stream/tcp/tcp_reassembler.cc @@ -123,11 +123,10 @@ bool TcpReassembler::flush_data_ready(TcpReassemblerState& trs) { // needed by stream_reassemble:action disable; can fire on rebuilt // packets, yanking the splitter out from under us :( - if (!trs.tracker->flush_policy or !trs.tracker->splitter) + if ( !trs.tracker->is_reassembly_enabled() ) return false; - if ( (trs.tracker->flush_policy == STREAM_FLPOLICY_ON_DATA) or - trs.tracker->splitter->is_paf() ) + if ( (trs.tracker->get_flush_policy() == STREAM_FLPOLICY_ON_DATA) or trs.tracker->is_splitter_paf() ) return ( is_segment_pending_flush(trs) ); return ( get_pending_segment_count(trs, 2) > 1 ); // FIXIT-L return false? @@ -205,10 +204,10 @@ void TcpReassembler::add_reassembly_segment( const int32_t new_size = len - slide - trunc_len; assert(new_size >= 0); + // if trimming will delete all data, don't insert this segment in the queue if ( new_size <= 0 ) { - // Zero size data because of trimming. Don't insert it. - inc_tcp_discards(); + tcpStats.payload_fully_trimmed++; trs.tracker->normalizer.trim_win_payload(tsd); return; } @@ -248,17 +247,69 @@ void TcpReassembler::dup_reassembly_segment( *retSeg = tsn; } +bool TcpReassembler::add_alert(TcpReassemblerState& trs, uint32_t gid, uint32_t sid) +{ + if ( trs.alert_count >= MAX_SESSION_ALERTS) + return false; + + StreamAlertInfo* ai = trs.alerts + trs.alert_count; + ai->gid = gid; + ai->sid = sid; + ai->seq = 0; + ai->event_id = 0; + ai->event_second = 0; + + trs.alert_count++; + + return true; +} + +bool TcpReassembler::check_alerted(TcpReassemblerState& trs, uint32_t gid, uint32_t sid) +{ + for (int i = 0; i < trs.alert_count; i++) + { + /* This is a rebuilt packet and if we've seen this alert before, + * return that we have previously alerted on original packet. + */ + if (trs.alerts[i].gid == gid && trs.alerts[i].sid == sid) + return true; + } + + return false; +} + +int TcpReassembler::update_alert(TcpReassemblerState& trs, uint32_t gid, uint32_t sid, + uint32_t event_id, uint32_t event_second) +{ + // FIXIT-M comparison of seq_num is wrong, compare value is always 0, should be seq_num of wire packet + uint32_t seq_num = 0; + + for (unsigned i = 0; i < trs.alert_count; i++) + { + StreamAlertInfo* ai = &trs.alerts[i]; + + if (ai->gid == gid && ai->sid == sid && SEQ_EQ(ai->seq, seq_num)) + { + ai->event_id = event_id; + ai->event_second = event_second; + return 0; + } + } + + return -1; +} + void TcpReassembler::purge_alerts(TcpReassemblerState& trs) { Flow* flow = trs.sos.session->flow; - for (int i = 0; i < trs.tracker->alert_count; i++) + for (int i = 0; i < trs.alert_count; i++) { - StreamAlertInfo* ai = trs.tracker->alerts + i; + StreamAlertInfo* ai = trs.alerts + i; Stream::log_extra_data(flow, trs.xtradata_mask, ai->event_id, ai->event_second); } if ( !flow->is_suspended() ) - trs.tracker->alert_count = 0; + trs.alert_count = 0; } void TcpReassembler::purge_to_seq(TcpReassemblerState& trs, uint32_t flush_seq) @@ -377,7 +428,7 @@ uint32_t TcpReassembler::get_flush_data_len( unsigned int flush_len = ( tsn->c_len <= max ) ? tsn->c_len : max; // copy only to flush point - if ( paf_active(&trs.tracker->paf_state) && SEQ_GT(tsn->c_seq + flush_len, to_seq) ) + if ( paf_active(&trs.paf_state) && SEQ_GT(tsn->c_seq + flush_len, to_seq) ) flush_len = to_seq - tsn->c_seq; return flush_len; @@ -397,16 +448,16 @@ int TcpReassembler::flush_data_segments( TcpSegmentNode* tsn = trs.sos.seglist.cur_rseg; unsigned bytes_copied = 0; unsigned bytes_to_copy = get_flush_data_len( - trs, tsn, to_seq, trs.tracker->splitter->max(p->flow)); + trs, tsn, to_seq, trs.tracker->get_splitter()->max(p->flow)); assert(bytes_to_copy); if ( !tsn->next or (bytes_to_copy < tsn->c_len) or SEQ_EQ(tsn->c_seq + bytes_to_copy, to_seq) or - (total_flushed + tsn->c_len > trs.tracker->splitter->get_max_pdu()) ) + (total_flushed + tsn->c_len > trs.tracker->get_splitter()->get_max_pdu()) ) { flags |= PKT_PDU_TAIL; } - const StreamBuffer sb = trs.tracker->splitter->reassemble( + const StreamBuffer sb = trs.tracker->get_splitter()->reassemble( trs.sos.session->flow, total, total_flushed, tsn->payload(), bytes_to_copy, flags, bytes_copied); @@ -546,8 +597,8 @@ int TcpReassembler::_flush_to_seq( if ( footprint > Packet::max_dsize ) // max stream buffer size footprint = Packet::max_dsize; - if ( trs.tracker->splitter->is_paf() and - ( trs.tracker->get_tf_flags() & TF_MISSING_PREV_PKT ) ) + if ( trs.tracker->is_splitter_paf() + and ( trs.tracker->get_tf_flags() & TF_MISSING_PREV_PKT ) ) fallback(*trs.tracker, trs.server_side); Packet* pdu = initialize_pdu(trs, p, pkt_flags, trs.sos.seglist.cur_rseg->tv); @@ -583,8 +634,8 @@ int TcpReassembler::_flush_to_seq( } // FIXIT-L must check because above may clear trs.sos.session - if ( trs.tracker->splitter ) - trs.tracker->splitter->update(); + if ( trs.tracker->get_splitter() ) + trs.tracker->get_splitter()->update(); // FIXIT-L abort should be by PAF callback only since recovery may be possible if ( trs.tracker->get_tf_flags() & TF_MISSING_PKT ) @@ -612,7 +663,7 @@ int TcpReassembler::flush_to_seq( return 0; if ( !flush_data_ready(trs) and !(trs.tracker->get_tf_flags() & TF_FORCE_FLUSH) and - !trs.tracker->splitter->is_paf() ) + !trs.tracker->is_splitter_paf() ) return 0; trs.tracker->clear_tf_flags(TF_MISSING_PKT | TF_MISSING_PREV_PKT); @@ -643,7 +694,7 @@ int TcpReassembler::do_zero_byte_flush(TcpReassemblerState& trs, Packet* p, uint { unsigned bytes_copied = 0; - const StreamBuffer sb = trs.tracker->splitter->reassemble( + const StreamBuffer sb = trs.tracker->get_splitter()->reassemble( trs.sos.session->flow, 0, 0, nullptr, 0, (PKT_PDU_HEAD | PKT_PDU_TAIL), bytes_copied); if ( sb.data ) @@ -658,8 +709,8 @@ int TcpReassembler::do_zero_byte_flush(TcpReassemblerState& trs, Packet* p, uint show_rebuilt_packet(trs, pdu); Analyzer::get_local_analyzer()->inspect_rebuilt(pdu); - if ( trs.tracker->splitter ) - trs.tracker->splitter->update(); + if ( trs.tracker->get_splitter() ) + trs.tracker->get_splitter()->update(); } return bytes_copied; @@ -706,7 +757,7 @@ uint32_t TcpReassembler::get_q_sequenced(TcpReassemblerState& trs) trs.sos.seglist.cur_rseg = tsn; } uint32_t len = 0; - const uint32_t limit = trs.tracker->splitter->get_max_pdu(); + const uint32_t limit = trs.tracker->get_splitter()->get_max_pdu(); while ( len < limit and next_no_gap(*tsn) ) { @@ -757,7 +808,7 @@ int TcpReassembler::flush_stream( TcpReassemblerState& trs, Packet* p, uint32_t dir, bool final_flush) { // this is not always redundant; stream_reassemble rule option causes trouble - if ( !trs.tracker->flush_policy or !trs.tracker->splitter ) + if ( !trs.tracker->is_reassembly_enabled() ) return 0; uint32_t bytes; @@ -849,8 +900,8 @@ void TcpReassembler::flush_queued_segments( p = set_packet(flow, trs.packet_dir, trs.server_side); } - bool pending = clear and paf_initialized(&trs.tracker->paf_state) - and (!trs.tracker->splitter or trs.tracker->splitter->finish(flow) ); + bool pending = clear and paf_initialized(&trs.paf_state) + and (!trs.tracker->get_splitter() or trs.tracker->get_splitter()->finish(flow) ); if ( pending and !(flow->ssn_state.ignore_direction & trs.ignore_dir) ) final_flush(trs, p, trs.packet_dir); @@ -904,7 +955,7 @@ int32_t TcpReassembler::flush_pdu_ips(TcpReassemblerState& trs, uint32_t* flags, if ( !tsn ) tsn = trs.sos.seglist.cur_rseg; - else if ( paf_initialized(&trs.tracker->paf_state) ) + else if ( paf_initialized(&trs.paf_state) ) { assert(trs.sos.seglist.cur_rseg); total = tsn->c_seq - trs.sos.seglist.cur_rseg->c_seq; @@ -915,9 +966,9 @@ int32_t TcpReassembler::flush_pdu_ips(TcpReassemblerState& trs, uint32_t* flags, total += tsn->c_len; uint32_t end = tsn->c_seq + tsn->c_len; - uint32_t pos = paf_position(&trs.tracker->paf_state); + uint32_t pos = paf_position(&trs.paf_state); - if ( paf_initialized(&trs.tracker->paf_state) && SEQ_LEQ(end, pos) ) + if ( paf_initialized(&trs.paf_state) && SEQ_LEQ(end, pos) ) { if ( !next_no_gap(*tsn) ) return -1; @@ -927,7 +978,7 @@ int32_t TcpReassembler::flush_pdu_ips(TcpReassemblerState& trs, uint32_t* flags, } int32_t flush_pt = paf_check( - trs.tracker->splitter, &trs.tracker->paf_state, p, tsn->payload(), + trs.tracker->get_splitter(), &trs.paf_state, p, tsn->payload(), tsn->c_len, total, tsn->c_seq, flags); if (flush_pt >= 0) @@ -954,9 +1005,8 @@ static inline bool both_splitters_aborted(Flow* flow) static inline void fallback(TcpStreamTracker& trk, bool server_side, uint16_t max) { - delete trk.splitter; - trk.splitter = new AtomSplitter(!server_side, max); - trk.paf_state.paf = StreamSplitter::START; + trk.set_splitter(new AtomSplitter(!server_side, max)); + trk.reassembler.reset_paf(); tcpStats.partial_fallbacks++; } @@ -1008,9 +1058,9 @@ int32_t TcpReassembler::flush_pdu_ackd(TcpReassemblerState& trs, uint32_t* flags { uint32_t size = tsn->c_len; uint32_t end = tsn->c_seq + tsn->c_len; - uint32_t pos = paf_position(&trs.tracker->paf_state); + uint32_t pos = paf_position(&trs.paf_state); - if ( paf_initialized(&trs.tracker->paf_state) && SEQ_LEQ(end, pos) ) + if ( paf_initialized(&trs.paf_state) && SEQ_LEQ(end, pos) ) { total += size; tsn = tsn->next; @@ -1023,7 +1073,7 @@ int32_t TcpReassembler::flush_pdu_ackd(TcpReassemblerState& trs, uint32_t* flags total += size; int32_t flush_pt = paf_check( - trs.tracker->splitter, &trs.tracker->paf_state, p, tsn->payload(), + trs.tracker->get_splitter(), &trs.paf_state, p, tsn->payload(), size, total, tsn->c_seq, flags); if ( flush_pt >= 0 ) @@ -1039,14 +1089,14 @@ int32_t TcpReassembler::flush_pdu_ackd(TcpReassemblerState& trs, uint32_t* flags // instead of creating more, but smaller, packets // FIXIT-L just flush to end of segment to avoid splitting // instead of all avail? - if ( !trs.tracker->splitter->is_paf() ) + if ( !trs.tracker->is_splitter_paf() ) { // get_q_footprint() w/o side effects int32_t avail = trs.tracker->r_win_base - trs.sos.seglist_base_seq; if ( avail > flush_pt ) { - paf_jump(&trs.tracker->paf_state, avail - flush_pt); + paf_jump(&trs.paf_state, avail - flush_pt); return avail; } } @@ -1062,7 +1112,7 @@ int TcpReassembler::flush_on_data_policy(TcpReassemblerState& trs, Packet* p) uint32_t flushed = 0; last_pdu = nullptr; - switch ( trs.tracker->flush_policy ) + switch ( trs.tracker->get_flush_policy() ) { case STREAM_FLPOLICY_IGNORE: return 0; @@ -1089,7 +1139,7 @@ int TcpReassembler::flush_on_data_policy(TcpReassemblerState& trs, Packet* p) flush_amt = flush_pdu_ips(trs, &flags, p); } - if ( !flags && trs.tracker->splitter->is_paf() ) + if ( !flags && trs.tracker->is_splitter_paf() ) { fallback(*trs.tracker, trs.server_side); return flush_on_data_policy(trs, p); @@ -1101,7 +1151,7 @@ int TcpReassembler::flush_on_data_policy(TcpReassemblerState& trs, Packet* p) if ( trs.tracker->is_retransmit_of_held_packet(p) ) flushed = perform_partial_flush(trs, p, flushed); - // FIXIT-H a drop rule will yoink the seglist out from under us + // FIXIT-M a drop rule will yoink the seglist out from under us // because apply_delayed_action is only deferred to end of context // this is causing stability issues if ( flushed and trs.sos.seg_count and @@ -1123,7 +1173,7 @@ int TcpReassembler::flush_on_ack_policy(TcpReassemblerState& trs, Packet* p) uint32_t flushed = 0; last_pdu = nullptr; - switch (trs.tracker->flush_policy) + switch ( trs.tracker->get_flush_policy() ) { case STREAM_FLPOLICY_IGNORE: return 0; @@ -1138,8 +1188,8 @@ int TcpReassembler::flush_on_ack_policy(TcpReassemblerState& trs, Packet* p) if ( !flush_amt ) flush_amt = trs.sos.seglist.cur_rseg->c_seq - trs.sos.seglist_base_seq; - if ( trs.tracker->paf_state.paf == StreamSplitter::ABORT ) - trs.tracker->splitter->finish(p->flow); + if ( trs.paf_state.paf == StreamSplitter::ABORT ) + trs.tracker->get_splitter()->finish(p->flow); // for consistency with other cases, should return total // but that breaks flushing pipelined pdus @@ -1156,8 +1206,7 @@ int TcpReassembler::flush_on_ack_policy(TcpReassemblerState& trs, Packet* p) break; // bail if nothing flushed } - if ( (trs.tracker->paf_state.paf == StreamSplitter::ABORT) && - (trs.tracker->splitter && trs.tracker->splitter->is_paf()) ) + if ( (trs.paf_state.paf == StreamSplitter::ABORT) && trs.tracker->is_splitter_paf() ) { fallback(*trs.tracker, trs.server_side); return flush_on_ack_policy(trs, p); @@ -1345,10 +1394,10 @@ uint32_t TcpReassembler::perform_partial_flush(TcpReassemblerState& trs, Flow* f // are not null. uint32_t TcpReassembler::perform_partial_flush(TcpReassemblerState& trs, Packet* p, uint32_t flushed) { - if ( trs.tracker->splitter->init_partial_flush(p->flow) ) + if ( trs.tracker->get_splitter()->init_partial_flush(p->flow) ) { flushed += flush_stream(trs, p, trs.packet_dir, false); - paf_jump(&trs.tracker->paf_state, flushed); + paf_jump(&trs.paf_state, flushed); tcpStats.partial_flushes++; tcpStats.partial_flush_bytes += flushed; if ( trs.sos.seg_count ) diff --git a/src/stream/tcp/tcp_reassembler.h b/src/stream/tcp/tcp_reassembler.h index ba8fd5111..ea609984c 100644 --- a/src/stream/tcp/tcp_reassembler.h +++ b/src/stream/tcp/tcp_reassembler.h @@ -39,6 +39,10 @@ public: virtual int flush_on_data_policy(TcpReassemblerState&, snort::Packet*); virtual int flush_on_ack_policy(TcpReassemblerState&, snort::Packet*); virtual void trace_segments(TcpReassemblerState&); + virtual bool add_alert(TcpReassemblerState&, uint32_t gid, uint32_t sid); + virtual bool check_alerted(TcpReassemblerState&, uint32_t gid, uint32_t sid); + virtual int update_alert(TcpReassemblerState&, uint32_t gid, uint32_t sid, + uint32_t event_id, uint32_t event_second); virtual void purge_alerts(TcpReassemblerState&); uint32_t perform_partial_flush(TcpReassemblerState&, snort::Flow*); diff --git a/src/stream/tcp/tcp_reassemblers.h b/src/stream/tcp/tcp_reassemblers.h index c7cad8915..928a8da53 100644 --- a/src/stream/tcp/tcp_reassemblers.h +++ b/src/stream/tcp/tcp_reassemblers.h @@ -49,6 +49,15 @@ public: void queue_packet_for_reassembly(TcpSegmentDescriptor& tsd) { reassembler->queue_packet_for_reassembly(trs, tsd); } + bool add_alert(uint32_t gid, uint32_t sid) + { return reassembler->add_alert(trs, gid, sid); } + + bool check_alerted(uint32_t gid, uint32_t sid) + { return reassembler->check_alerted(trs, gid, sid); } + + int update_alert(uint32_t gid, uint32_t sid, uint32_t event_id, uint32_t event_second) + { return reassembler->update_alert(trs, gid, sid, event_id, event_second); } + void purge_alerts() { reassembler->purge_alerts(trs); } @@ -118,6 +127,15 @@ public: uint32_t perform_partial_flush(snort::Flow* flow) { return reassembler->perform_partial_flush(trs, flow); } + void reset_paf() + { paf_reset(&trs.paf_state); } + + void clear_paf() + { paf_clear(&trs.paf_state); } + + void setup_paf() + { paf_setup(&trs.paf_state); } + private: TcpReassembler* reassembler = nullptr; TcpReassemblerState trs; diff --git a/src/stream/tcp/tcp_segment_descriptor.h b/src/stream/tcp/tcp_segment_descriptor.h index dd665649e..222558bbb 100644 --- a/src/stream/tcp/tcp_segment_descriptor.h +++ b/src/stream/tcp/tcp_segment_descriptor.h @@ -114,6 +114,9 @@ public: pkt->dsize = seg_len; } + bool is_data_segment() const + { return pkt->dsize > 0; } + void update_len(int32_t offset) { assert(!meta_ack_packet); diff --git a/src/stream/tcp/tcp_session.cc b/src/stream/tcp/tcp_session.cc index a109d7532..3fe36e117 100644 --- a/src/stream/tcp/tcp_session.cc +++ b/src/stream/tcp/tcp_session.cc @@ -96,11 +96,21 @@ TcpSession::~TcpSession() memory::MemoryCap::update_deallocations(sizeof(*this)); } -bool TcpSession::setup(Packet* p) +bool TcpSession::setup(Packet*) { - TcpStreamSession::setup(p); + client.init_tcp_state(); + server.init_tcp_state(); + lws_init = tcp_init = false; + generate_3whs_alert = true; + cleaning = false; splitter_init = false; + pkt_action_mask = ACTION_NOTHING; + ecn = 0; + ingress_index = egress_index = 0; + ingress_group = egress_group = 0; + daq_flags = address_space_id = 0; + tcp_config = get_tcp_cfg(flow->ssn_server); flow->set_default_session_timeout(tcp_config->session_timeout, false); set_os_policy(); @@ -194,15 +204,14 @@ void TcpSession::clear_session(bool free_flow_data, bool flush_segments, bool re if ( restart ) { flow->restart(free_flow_data); - paf_reset(&client.paf_state); - paf_reset(&server.paf_state); - + client.reassembler.reset_paf(); + server.reassembler.reset_paf(); } else { flow->clear(free_flow_data); - paf_clear(&client.paf_state); - paf_clear(&server.paf_state); + client.reassembler.clear_paf(); + server.reassembler.clear_paf(); } set_splitter(true, nullptr); @@ -300,7 +309,7 @@ bool TcpSession::flow_exceeds_config_thresholds(const TcpSegmentDescriptor& tsd) { TcpStreamTracker* listener = tsd.get_listener(); - if ( listener->flush_policy == STREAM_FLPOLICY_IGNORE ) + if ( listener->get_flush_policy() == STREAM_FLPOLICY_IGNORE ) return true; // FIXIT-M any discards must be counted and in many cases alerted as well @@ -372,6 +381,7 @@ void TcpSession::update_stream_order(const TcpSegmentDescriptor& tsd, bool align else listener->order = 1; break; + case 1: if ( aligned ) { @@ -379,6 +389,7 @@ void TcpSession::update_stream_order(const TcpSegmentDescriptor& tsd, bool align listener->order = 2; } break; + default: if ( aligned ) tsd.set_packet_flags(PKT_STREAM_ORDER_OK); @@ -413,8 +424,8 @@ int TcpSession::process_tcp_data(TcpSegmentDescriptor& tsd) if (seq == listener->rcv_nxt) { /* check if we're in the window */ - if (tcp_config->policy != StreamPolicy::OS_PROXY - and listener->normalizer.get_stream_window(tsd) == 0) + if ( tcp_config->policy != StreamPolicy::OS_PROXY + and listener->normalizer.get_stream_window(tsd) == 0 ) { listener->normalizer.trim_win_payload(tsd); return STREAM_UNALIGNED; @@ -424,7 +435,7 @@ int TcpSession::process_tcp_data(TcpSegmentDescriptor& tsd) // FIXIT-L for ips, must move all the way to first hole or right end listener->rcv_nxt = tsd.get_end_seq(); - if (tsd.get_len() != 0) + if ( tsd.is_data_segment() ) { update_stream_order(tsd, true); process_tcp_stream(tsd); @@ -440,13 +451,13 @@ int TcpSession::process_tcp_data(TcpSegmentDescriptor& tsd) // some cases. /* check if we're in the window */ - if (tcp_config->policy != StreamPolicy::OS_PROXY - and listener->normalizer.get_stream_window(tsd) == 0) + if ( tcp_config->policy != StreamPolicy::OS_PROXY + and listener->normalizer.get_stream_window(tsd) == 0 ) { listener->normalizer.trim_win_payload(tsd); return STREAM_UNALIGNED; } - if (tsd.get_len() != 0) + if ( tsd.is_data_segment() ) { update_stream_order(tsd, false); process_tcp_stream(tsd); @@ -567,7 +578,7 @@ bool TcpSession::handle_syn_on_reset_session(TcpSegmentDescriptor& tsd) /* Got SYN/RST. We're done. */ listener->normalizer.trim_syn_payload(tsd); listener->normalizer.trim_rst_payload(tsd); - pkt_action_mask |= ACTION_RST; + set_pkt_action_flag(ACTION_RST); return false; } else if ( tcph->is_syn_only() ) @@ -625,7 +636,7 @@ void TcpSession::update_ignored_session(TcpSegmentDescriptor& tsd) } tsd.set_packet_flags(PKT_IGNORE); - pkt_action_mask |= ACTION_DISABLE_INSPECTION; + set_pkt_action_flag(ACTION_DISABLE_INSPECTION); tcpStats.ignored++; } } @@ -642,7 +653,7 @@ void TcpSession::handle_data_on_syn(TcpSegmentDescriptor& tsd) { listener->normalizer.trim_syn_payload(tsd); tel.set_tcp_event(EVENT_DATA_ON_SYN); - pkt_action_mask |= ACTION_BAD_PKT; + set_pkt_action_flag(ACTION_BAD_PKT); } } @@ -729,9 +740,8 @@ bool TcpSession::check_for_window_slam(TcpSegmentDescriptor& tsd) { /* 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; + set_pkt_action_flag(ACTION_BAD_PKT); return true; } else if ( tsd.is_packet_from_client() && (tsd.get_wnd() <= SLAM_MAX) @@ -741,13 +751,9 @@ bool TcpSession::check_for_window_slam(TcpSegmentDescriptor& tsd) { /* 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 true; - } + listener->normalizer.packet_dropper(tsd, NORM_TCP_BLOCK); + set_pkt_action_flag(ACTION_BAD_PKT); + return true; } return false; @@ -776,43 +782,30 @@ void TcpSession::handle_data_segment(TcpSegmentDescriptor& tsd) // FIXIT-M move this to normalizer base class, handle OS_PROXY in derived class if ( tcp_config->policy != StreamPolicy::OS_PROXY ) { - /* check for valid sequence/retrans */ + // drop packet if sequence num is invalid if ( !listener->is_segment_seq_valid(tsd) ) + { + tcpStats.invalid_seq_num++; + listener->normalizer.trim_win_payload(tsd); return; + } // these normalizations can't be done if we missed setup. and // window is zero in one direction until we've seen both sides. if ( !(flow->get_session_flags() & SSNFLAG_MIDSTREAM) && flow->two_way_traffic() ) { - // sender of syn w/mss limits payloads from peer since we store mss on - // sender side, use listener mss same reasoning for window size - TcpStreamTracker* st = listener; + // trim to fit in listener's window and mss + listener->normalizer.trim_win_payload + (tsd, (listener->r_win_base + listener->get_snd_wnd() - listener->rcv_nxt)); - // trim to fit in window and mss as needed - st->normalizer.trim_win_payload( - tsd, (st->r_win_base + st->get_snd_wnd() - st->rcv_nxt)); + if ( listener->get_mss() ) + listener->normalizer.trim_mss_payload(tsd, listener->get_mss()); - // FIXIT-H: MSS is not set on client so packets sent to client are not trimmed - // use case? - if ( st->get_mss() ) - st->normalizer.trim_mss_payload(tsd, st->get_mss()); - - st->normalizer.ecn_stripper(tsd); + listener->normalizer.ecn_stripper(tsd); } } - // 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 ( (tsd.get_tcph()->th_flags != 0) or (tcp_config->policy == StreamPolicy::OS_LINUX) - or (tcp_config->policy == StreamPolicy::OS_PROXY) ) - { - process_tcp_data(tsd); - } - else - { - tel.set_tcp_event(EVENT_DATA_WITHOUT_FLAGS); - listener->normalizer.packet_dropper(tsd, NORM_TCP_BLOCK); - } + process_tcp_data(tsd); } listener->reassembler.flush_on_data_policy(tsd.get_pkt()); @@ -837,7 +830,7 @@ void TcpSession::check_for_repeated_syn(TcpSegmentDescriptor& tsd) if ( !SEQ_EQ(tsd.get_seq(), talker->get_iss()) and listener->normalizer.packet_dropper(tsd, NORM_TCP_BLOCK) ) { - action = ACTION_BAD_PKT; + set_pkt_action_flag(ACTION_BAD_PKT); } else if ( talker->get_tcp_state() >= TcpStreamTracker::TCP_ESTABLISHED and talker->get_tcp_state() < TcpStreamTracker::TCP_CLOSED ) @@ -890,7 +883,7 @@ void TcpSession::flush_client(Packet* p) void TcpSession::flush_tracker( TcpStreamTracker& tracker, Packet* p, uint32_t dir, bool final_flush) { - if ( final_flush && (!tracker.splitter || !tracker.splitter->finish(flow)) ) + if ( final_flush && (!tracker.get_splitter() || !tracker.get_splitter()->finish(flow)) ) return; tracker.set_tf_flags(TF_FORCE_FLUSH); @@ -937,11 +930,11 @@ static inline void set_window_scale(TcpSegmentDescriptor& tsd) void TcpSession::check_events_and_actions(const TcpSegmentDescriptor& tsd) { + tel.log_tcp_events(); + if ( tsd.is_meta_ack_packet() ) return; - tel.log_tcp_events(); - Packet* p = tsd.get_pkt(); if ( !(pkt_action_mask & ACTION_LWSSN_CLOSED) ) { @@ -971,8 +964,8 @@ bool TcpSession::ignore_this_packet(Packet* p) if ( flow->ssn_state.ignore_direction != SSN_DIR_NONE ) { - server.flush_policy = STREAM_FLPOLICY_IGNORE; - client.flush_policy = STREAM_FLPOLICY_IGNORE; + server.set_flush_policy(STREAM_FLPOLICY_IGNORE); + client.set_flush_policy(STREAM_FLPOLICY_IGNORE); return true; } @@ -1005,7 +998,7 @@ void TcpSession::precheck(Packet* p) void TcpSession::init_tcp_packet_analysis(TcpSegmentDescriptor& tsd) { - if ( !splitter_init and tsd.get_len() > 0 ) + if ( !splitter_init and tsd.is_data_segment() ) { if ( !(tcp_config->flags & STREAM_CONFIG_NO_REASSEMBLY) ) { @@ -1054,32 +1047,23 @@ bool TcpSession::validate_packet_established_session(TcpSegmentDescriptor& tsd) if ( tsd.is_policy_inline() ) if ( tsd.get_tcph()->is_ack() && !listener->is_ack_valid(tsd.get_ack()) ) - pkt_action_mask |= ACTION_BAD_PKT; + { + listener->normalizer.packet_dropper(tsd, NORM_TCP_BLOCK); + set_pkt_action_flag(ACTION_BAD_PKT); + } if ( !tsd.is_meta_ack_packet() ) - pkt_action_mask |= listener->normalizer.handle_paws(tsd); + set_pkt_action_flag(listener->normalizer.handle_paws(tsd)); return ( pkt_action_mask & ACTION_BAD_PKT ) ? false : true; } int TcpSession::process_tcp_packet(TcpSegmentDescriptor& tsd) { - if ( tsm->eval(tsd) ) - { - check_events_and_actions(tsd); - S5TraceTCP(tsd); - } - else - { - if ( pkt_action_mask & ACTION_BAD_PKT ) - { - inc_tcp_discards(); - check_events_and_actions(tsd); - } + tsm->eval(tsd); + check_events_and_actions(tsd); - tel.log_tcp_events(); - S5TraceTCP(tsd); - } + S5TraceTCP(tsd); return ACTION_NOTHING; } diff --git a/src/stream/tcp/tcp_state_close_wait.cc b/src/stream/tcp/tcp_state_close_wait.cc index acc7fb239..f36e1cade 100644 --- a/src/stream/tcp/tcp_state_close_wait.cc +++ b/src/stream/tcp/tcp_state_close_wait.cc @@ -32,14 +32,13 @@ using namespace snort; TcpStateCloseWait::TcpStateCloseWait(TcpStateMachine& tsm) : TcpStateHandler(TcpStreamTracker::TCP_CLOSE_WAIT, tsm) -{ -} +{ } bool TcpStateCloseWait::syn_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) { trk.normalizer.ecn_tracker(tsd.get_tcph(), trk.session->tcp_config->require_3whs() ); - if ( tsd.get_len() ) + if ( tsd.is_data_segment() ) trk.session->handle_data_on_syn(tsd); return true; @@ -93,9 +92,10 @@ bool TcpStateCloseWait::fin_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tr { if ( !flow->two_way_traffic() ) trk.set_tf_flags(TF_FORCE_FLUSH); - if ( tsd.get_len() > 0 ) + if ( tsd.is_data_segment() ) trk.session->handle_data_segment(tsd); } + return true; } @@ -108,10 +108,7 @@ bool TcpStateCloseWait::rst_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& tr trk.session->set_pkt_action_flag(ACTION_RST); tsd.get_flow()->session_state |= STREAM_STATE_CLOSED; } - else - { - trk.session->tel.set_tcp_event(EVENT_BAD_RST); - } + return true; } diff --git a/src/stream/tcp/tcp_state_closed.cc b/src/stream/tcp/tcp_state_closed.cc index 575e69e82..9633c7f25 100644 --- a/src/stream/tcp/tcp_state_closed.cc +++ b/src/stream/tcp/tcp_state_closed.cc @@ -35,8 +35,7 @@ using namespace snort; TcpStateClosed::TcpStateClosed(TcpStateMachine& tsm) : TcpStateHandler(TcpStreamTracker::TCP_CLOSED, tsm) -{ -} +{ } bool TcpStateClosed::syn_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) { @@ -99,7 +98,7 @@ bool TcpStateClosed::fin_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) { trk.update_tracker_ack_recv(tsd); - if( tsd.get_len() > 0 ) + if( tsd.is_data_segment() ) { if ( trk.is_rst_pkt_sent() ) trk.session->tel.set_tcp_event(EVENT_DATA_AFTER_RESET); @@ -117,10 +116,7 @@ bool TcpStateClosed::rst_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) trk.session->update_perf_base_state(TcpStreamTracker::TCP_CLOSING); trk.session->set_pkt_action_flag(ACTION_RST); } - else - { - trk.session->tel.set_tcp_event(EVENT_BAD_RST); - } + return true; } diff --git a/src/stream/tcp/tcp_state_closing.cc b/src/stream/tcp/tcp_state_closing.cc index 22c5b3ee7..ebd677151 100644 --- a/src/stream/tcp/tcp_state_closing.cc +++ b/src/stream/tcp/tcp_state_closing.cc @@ -32,8 +32,7 @@ using namespace snort; TcpStateClosing::TcpStateClosing(TcpStateMachine& tsm) : TcpStateHandler(TcpStreamTracker::TCP_CLOSING, tsm) -{ -} +{ } bool TcpStateClosing::syn_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) { @@ -44,7 +43,7 @@ bool TcpStateClosing::syn_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) bool TcpStateClosing::syn_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) { trk.normalizer.ecn_tracker(tsd.get_tcph(), trk.session->tcp_config->require_3whs()); - if ( tsd.get_len() ) + if ( tsd.is_data_segment() ) trk.session->handle_data_on_syn(tsd); return true; } @@ -112,10 +111,7 @@ bool TcpStateClosing::rst_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) trk.session->set_pkt_action_flag(ACTION_RST); tsd.get_flow()->session_state |= STREAM_STATE_CLOSED; } - else - { - trk.session->tel.set_tcp_event(EVENT_BAD_RST); - } + return true; } diff --git a/src/stream/tcp/tcp_state_established.cc b/src/stream/tcp/tcp_state_established.cc index a6f4e5e77..3333787c8 100644 --- a/src/stream/tcp/tcp_state_established.cc +++ b/src/stream/tcp/tcp_state_established.cc @@ -30,8 +30,7 @@ TcpStateEstablished::TcpStateEstablished(TcpStateMachine& tsm) : TcpStateHandler(TcpStreamTracker::TCP_ESTABLISHED, tsm) -{ -} +{ } bool TcpStateEstablished::syn_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) { @@ -104,11 +103,8 @@ bool TcpStateEstablished::fin_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& bool TcpStateEstablished::fin_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) { trk.update_tracker_ack_recv(tsd); - if ( tsd.get_len() > 0 ) - { + if ( tsd.is_data_segment() ) trk.session->handle_data_segment(tsd); - trk.flush_data_on_fin_recv(tsd); - } if ( trk.update_on_fin_recv(tsd) ) { @@ -127,13 +123,9 @@ bool TcpStateEstablished::rst_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk.session->update_perf_base_state(TcpStreamTracker::TCP_CLOSING); trk.session->set_pkt_action_flag(ACTION_RST); } - else - { - trk.session->tel.set_tcp_event(EVENT_BAD_RST); - } // FIXIT-L might be good to create alert specific to RST with data - if ( tsd.get_len() > 0 ) + if ( tsd.is_data_segment() ) trk.session->tel.set_tcp_event(EVENT_DATA_AFTER_RST_RCVD); return true; diff --git a/src/stream/tcp/tcp_state_fin_wait1.cc b/src/stream/tcp/tcp_state_fin_wait1.cc index 2656058ad..43e72b933 100644 --- a/src/stream/tcp/tcp_state_fin_wait1.cc +++ b/src/stream/tcp/tcp_state_fin_wait1.cc @@ -33,8 +33,7 @@ using namespace snort; TcpStateFinWait1::TcpStateFinWait1(TcpStateMachine& tsm) : TcpStateHandler(TcpStreamTracker::TCP_FIN_WAIT1, tsm) -{ -} +{ } bool TcpStateFinWait1::syn_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) { @@ -45,14 +44,14 @@ bool TcpStateFinWait1::syn_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk bool TcpStateFinWait1::syn_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) { trk.normalizer.ecn_tracker(tsd.get_tcph(), trk.session->tcp_config->require_3whs()); - if ( tsd.get_len() ) + if ( tsd.is_data_segment() ) trk.session->handle_data_on_syn(tsd); return true; } bool TcpStateFinWait1::syn_ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) { - if ( tsd.get_len() ) + if ( tsd.is_data_segment() ) trk.session->handle_data_on_syn(tsd); return true; } @@ -81,7 +80,7 @@ bool TcpStateFinWait1::data_seg_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker trk.update_tracker_ack_recv(tsd); if ( check_for_window_slam(tsd, trk) ) { - if ( tsd.get_len() > 0 ) + if ( tsd.is_data_segment() ) trk.session->handle_data_segment(tsd); } return true; @@ -103,7 +102,7 @@ bool TcpStateFinWait1::fin_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk bool is_ack_valid = false; if ( check_for_window_slam(tsd, trk, &is_ack_valid) ) { - if ( tsd.get_len() > 0 ) + if ( tsd.is_data_segment() ) trk.session->handle_data_segment(tsd); if ( !flow->two_way_traffic() ) @@ -127,13 +126,9 @@ bool TcpStateFinWait1::rst_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk trk.session->set_pkt_action_flag(ACTION_RST); tsd.get_flow()->session_state |= STREAM_STATE_CLOSED; } - else - { - trk.session->tel.set_tcp_event(EVENT_BAD_RST); - } // FIXIT-L might be good to create alert specific to RST with data - if ( tsd.get_len() > 0 ) + if ( tsd.is_data_segment() ) trk.session->tel.set_tcp_event(EVENT_DATA_AFTER_RST_RCVD); return true; } @@ -146,13 +141,9 @@ bool TcpStateFinWait1::check_for_window_slam(TcpSegmentDescriptor& tsd, TcpStrea && (tsd.get_wnd() == 0)) { trk.session->tel.set_tcp_event(EVENT_WINDOW_SLAM); - inc_tcp_discards(); - - if (trk.normalizer.packet_dropper(tsd, NORM_TCP_BLOCK)) - { - trk.session->set_pkt_action_flag(ACTION_BAD_PKT); - return false; - } + trk.normalizer.packet_dropper(tsd, NORM_TCP_BLOCK); + trk.session->set_pkt_action_flag(ACTION_BAD_PKT); + return false; } trk.set_tcp_state(TcpStreamTracker::TCP_FIN_WAIT2); diff --git a/src/stream/tcp/tcp_state_fin_wait2.cc b/src/stream/tcp/tcp_state_fin_wait2.cc index f314f147c..81df9352f 100644 --- a/src/stream/tcp/tcp_state_fin_wait2.cc +++ b/src/stream/tcp/tcp_state_fin_wait2.cc @@ -32,8 +32,7 @@ using namespace snort; TcpStateFinWait2::TcpStateFinWait2(TcpStateMachine& tsm) : TcpStateHandler(TcpStreamTracker::TCP_FIN_WAIT2, tsm) -{ -} +{ } bool TcpStateFinWait2::syn_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) { @@ -44,14 +43,14 @@ bool TcpStateFinWait2::syn_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk bool TcpStateFinWait2::syn_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) { trk.normalizer.ecn_tracker(tsd.get_tcph(), trk.session->tcp_config->require_3whs()); - if ( tsd.get_len() ) + if ( tsd.is_data_segment() ) trk.session->handle_data_on_syn(tsd); return true; } bool TcpStateFinWait2::syn_ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) { - if ( tsd.get_len() ) + if ( tsd.is_data_segment() ) trk.session->handle_data_on_syn(tsd); return true; } @@ -72,6 +71,7 @@ bool TcpStateFinWait2::ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk } else trk.update_tracker_ack_recv(tsd); + return true; } @@ -95,9 +95,10 @@ bool TcpStateFinWait2::data_seg_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker else { trk.update_tracker_ack_recv(tsd); - if ( tsd.get_len() > 0 ) + if ( tsd.is_data_segment() ) trk.session->handle_data_segment(tsd); } + return true; } @@ -108,7 +109,7 @@ bool TcpStateFinWait2::fin_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk trk.update_tracker_ack_recv(tsd); if ( trk.update_on_fin_recv(tsd) ) { - if ( tsd.get_len() > 0 ) + if ( tsd.is_data_segment() ) trk.session->handle_data_segment(tsd); if ( !flow->two_way_traffic() ) @@ -128,10 +129,7 @@ bool TcpStateFinWait2::rst_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk trk.session->set_pkt_action_flag(ACTION_RST); tsd.get_flow()->session_state |= STREAM_STATE_CLOSED; } - else - { - trk.session->tel.set_tcp_event(EVENT_BAD_RST); - } + return true; } diff --git a/src/stream/tcp/tcp_state_handler.cc b/src/stream/tcp/tcp_state_handler.cc index d0e83344b..dbf50a8cd 100644 --- a/src/stream/tcp/tcp_state_handler.cc +++ b/src/stream/tcp/tcp_state_handler.cc @@ -36,19 +36,13 @@ using namespace std; TcpStateHandler::TcpStateHandler(TcpStreamTracker::TcpState state, TcpStateMachine& tsm) -{ - tsm.register_state_handler(state, *this); -} +{ tsm.register_state_handler(state, *this); } bool TcpStateHandler::do_pre_sm_packet_actions(TcpSegmentDescriptor&, TcpStreamTracker&) -{ - return true; -} +{ return true; } bool TcpStateHandler::do_post_sm_packet_actions(TcpSegmentDescriptor&, TcpStreamTracker&) -{ - return true; -} +{ return true; } bool TcpStateHandler::eval(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) { @@ -90,6 +84,9 @@ bool TcpStateHandler::eval(TcpSegmentDescriptor& tsd, TcpStreamTracker& tracker) case TcpStreamTracker::TCP_RST_RECV_EVENT: return rst_recv(tsd, tracker); + case TcpStreamTracker::TCP_NO_FLAGS_EVENT: + return no_flags(tsd, tracker); + default: break; } diff --git a/src/stream/tcp/tcp_state_handler.h b/src/stream/tcp/tcp_state_handler.h index b7e014f7f..a53fd2597 100644 --- a/src/stream/tcp/tcp_state_handler.h +++ b/src/stream/tcp/tcp_state_handler.h @@ -53,6 +53,11 @@ protected: virtual bool fin_recv(TcpSegmentDescriptor&, TcpStreamTracker&) { return true; } virtual bool rst_sent(TcpSegmentDescriptor&, TcpStreamTracker&) { return true; } virtual bool rst_recv(TcpSegmentDescriptor&, TcpStreamTracker&) { return true; } + virtual bool no_flags(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) + { + trk.normalizer.packet_dropper(tsd, NORM_TCP_BLOCK); + return false; + } }; #endif diff --git a/src/stream/tcp/tcp_state_last_ack.cc b/src/stream/tcp/tcp_state_last_ack.cc index c779edcec..f1f01ddb5 100644 --- a/src/stream/tcp/tcp_state_last_ack.cc +++ b/src/stream/tcp/tcp_state_last_ack.cc @@ -32,8 +32,7 @@ using namespace snort; TcpStateLastAck::TcpStateLastAck(TcpStateMachine& tsm) : TcpStateHandler(TcpStreamTracker::TCP_LAST_ACK, tsm) -{ -} +{ } bool TcpStateLastAck::syn_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) { @@ -44,7 +43,7 @@ bool TcpStateLastAck::syn_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) bool TcpStateLastAck::syn_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) { trk.normalizer.ecn_tracker(tsd.get_tcph(), trk.session->tcp_config->require_3whs()); - if ( tsd.get_len() ) + if ( tsd.is_data_segment() ) trk.session->handle_data_on_syn(tsd); return true; } @@ -104,13 +103,9 @@ bool TcpStateLastAck::rst_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) trk.session->update_perf_base_state(TcpStreamTracker::TCP_CLOSING); trk.session->set_pkt_action_flag(ACTION_RST); } - else - { - trk.session->tel.set_tcp_event(EVENT_BAD_RST); - } // FIXIT-L might be good to create alert specific to RST with data - if ( tsd.get_len() > 0 ) + if ( tsd.is_data_segment() ) trk.session->tel.set_tcp_event(EVENT_DATA_AFTER_RST_RCVD); return true; } diff --git a/src/stream/tcp/tcp_state_listen.cc b/src/stream/tcp/tcp_state_listen.cc index afdb7dc89..dfd52b483 100644 --- a/src/stream/tcp/tcp_state_listen.cc +++ b/src/stream/tcp/tcp_state_listen.cc @@ -37,7 +37,7 @@ TcpStateListen::TcpStateListen(TcpStateMachine& tsm) : bool TcpStateListen::syn_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) { - if ( trk.session->tcp_config->require_3whs() || tsd.has_wscale() || ( tsd.get_len() > 0 ) ) + if ( trk.session->tcp_config->require_3whs() || tsd.has_wscale() || ( tsd.is_data_segment() ) ) { if ( tsd.is_packet_from_server() ) trk.session->tel.set_tcp_event(EVENT_4WHS); @@ -50,7 +50,7 @@ bool TcpStateListen::syn_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) trk.init_on_syn_recv(tsd); trk.normalizer.ecn_tracker(tsd.get_tcph(), trk.session->tcp_config->require_3whs()); trk.session->set_pkt_action_flag(trk.normalizer.handle_paws(tsd) ); - if ( tsd.get_len() > 0 ) + if ( tsd.is_data_segment() ) trk.session->handle_data_on_syn(tsd); return true; } @@ -79,7 +79,7 @@ bool TcpStateListen::syn_ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& t if ( !trk.session->tcp_config->require_3whs() or trk.session->is_midstream_allowed(tsd) ) { trk.init_on_synack_recv(tsd); - if ( tsd.get_len() > 0 ) + if ( tsd.is_data_segment() ) trk.session->handle_data_segment(tsd); } else if ( trk.session->tcp_config->require_3whs() ) @@ -93,7 +93,7 @@ bool TcpStateListen::syn_ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& t bool TcpStateListen::ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) { if ( trk.session->tcp_config->midstream_allowed(tsd.get_pkt()) - && (tsd.has_wscale() || (tsd.get_len() > 0 )) ) + && (tsd.has_wscale() || (tsd.is_data_segment() )) ) { Flow* flow = tsd.get_flow(); flow->session_state |= ( STREAM_STATE_ACK | STREAM_STATE_SYN_ACK | @@ -113,7 +113,7 @@ bool TcpStateListen::ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) bool TcpStateListen::ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) { - if ( trk.session->is_midstream_allowed(tsd) && (tsd.has_wscale() || (tsd.get_len() > 0 )) ) + if ( trk.session->is_midstream_allowed(tsd) && (tsd.has_wscale() || (tsd.is_data_segment() )) ) { Flow* flow = tsd.get_flow(); diff --git a/src/stream/tcp/tcp_state_none.cc b/src/stream/tcp/tcp_state_none.cc index 55ae09809..fa27ecf69 100644 --- a/src/stream/tcp/tcp_state_none.cc +++ b/src/stream/tcp/tcp_state_none.cc @@ -32,8 +32,7 @@ using namespace snort; TcpStateNone::TcpStateNone(TcpStateMachine& tsm) : TcpStateHandler(TcpStreamTracker::TCP_STATE_NONE, tsm) -{ -} +{ } bool TcpStateNone::syn_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) { @@ -48,7 +47,6 @@ bool TcpStateNone::syn_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) bool TcpStateNone::syn_recv(TcpSegmentDescriptor&, TcpStreamTracker&) { - // FIXIT-H syn received on undefined client, figure this out and do the right thing return true; } @@ -77,7 +75,7 @@ bool TcpStateNone::syn_ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk { trk.init_on_synack_recv(tsd); trk.normalizer.ecn_tracker(tsd.get_tcph(), trk.session->tcp_config->require_3whs()); - if ( tsd.get_len() > 0 ) + if ( tsd.is_data_segment() ) trk.session->handle_data_segment(tsd); } else if ( trk.session->tcp_config->require_3whs() ) @@ -90,12 +88,10 @@ bool TcpStateNone::syn_ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk bool TcpStateNone::ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) { - if ( trk.session->is_midstream_allowed(tsd) && (tsd.has_wscale() || (tsd.get_len() > 0)) ) + if ( trk.session->is_midstream_allowed(tsd) && (tsd.has_wscale() || (tsd.is_data_segment())) ) { Flow* flow = tsd.get_flow(); - // FIXIT-H 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); @@ -112,7 +108,7 @@ bool TcpStateNone::ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) bool TcpStateNone::ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) { - if ( trk.session->is_midstream_allowed(tsd) && (tsd.has_wscale() || (tsd.get_len() > 0)) ) + if ( trk.session->is_midstream_allowed(tsd) && (tsd.has_wscale() || (tsd.is_data_segment())) ) { Flow* flow = tsd.get_flow(); @@ -228,10 +224,7 @@ bool TcpStateNone::rst_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) trk.session->update_perf_base_state(TcpStreamTracker::TCP_CLOSING); trk.session->set_pkt_action_flag(ACTION_RST); } - else - { - trk.session->tel.set_tcp_event(EVENT_BAD_RST); - } + return true; } diff --git a/src/stream/tcp/tcp_state_syn_recv.cc b/src/stream/tcp/tcp_state_syn_recv.cc index 1084ea9e9..2e6a19e84 100644 --- a/src/stream/tcp/tcp_state_syn_recv.cc +++ b/src/stream/tcp/tcp_state_syn_recv.cc @@ -57,7 +57,7 @@ bool TcpStateSynRecv::syn_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) bool TcpStateSynRecv::syn_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) { - if ( tsd.get_len() ) + if ( tsd.is_data_segment() ) trk.session->handle_data_on_syn(tsd); return true; } @@ -66,8 +66,6 @@ bool TcpStateSynRecv::syn_ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& { Flow* flow = tsd.get_flow(); - // FIXIT-H verify ack being sent is valid... - // norm/drop + discard trk.finish_server_init(tsd); trk.normalizer.ecn_tracker(tsd.get_tcph(), trk.session->tcp_config->require_3whs()); flow->session_state |= STREAM_STATE_SYN_ACK; @@ -86,7 +84,7 @@ bool TcpStateSynRecv::syn_ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& flow->session_state |= ( STREAM_STATE_ACK | STREAM_STATE_ESTABLISHED ); trk.session->update_perf_base_state(TcpStreamTracker::TCP_ESTABLISHED); trk.set_tcp_state(TcpStreamTracker::TCP_ESTABLISHED); - if ( tsd.get_len() ) + if ( tsd.is_data_segment() ) trk.session->handle_data_on_syn(tsd); } return true; @@ -114,7 +112,7 @@ bool TcpStateSynRecv::ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) flow->session_state |= ( STREAM_STATE_ACK | STREAM_STATE_ESTABLISHED ); trk.session->update_perf_base_state(TcpStreamTracker::TCP_ESTABLISHED); trk.set_tcp_state(TcpStreamTracker::TCP_ESTABLISHED); - if ( tsd.get_len() > 0 ) + if ( tsd.is_data_segment() ) trk.session->handle_data_segment(tsd); else trk.session->check_for_window_slam(tsd); @@ -140,7 +138,7 @@ bool TcpStateSynRecv::data_seg_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk.session->update_perf_base_state(TcpStreamTracker::TCP_ESTABLISHED); trk.set_tcp_state(TcpStreamTracker::TCP_ESTABLISHED); } - if ( tsd.get_len() > 0 ) + if ( tsd.is_data_segment() ) trk.session->handle_data_segment(tsd); return true; } @@ -154,11 +152,8 @@ bool TcpStateSynRecv::fin_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) trk.update_tracker_ack_recv(tsd); trk.session->set_pkt_action_flag(trk.normalizer.handle_paws(tsd)); flow->session_state |= STREAM_STATE_ACK; - if ( tsd.get_len() > 0 ) - { + if ( tsd.is_data_segment() ) trk.session->handle_data_segment(tsd); - trk.flush_data_on_fin_recv(tsd); - } if ( trk.update_on_fin_recv(tsd) ) { @@ -179,13 +174,13 @@ bool TcpStateSynRecv::rst_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) } else { - inc_tcp_discards(); trk.session->tel.set_tcp_event(EVENT_BAD_RST); trk.normalizer.packet_dropper(tsd, NORM_TCP_BLOCK); + trk.session->set_pkt_action_flag(ACTION_BAD_PKT); } // FIXIT-L might be good to create alert specific to RST with data - if ( tsd.get_len() > 0 ) + if ( tsd.is_data_segment() ) trk.session->tel.set_tcp_event(EVENT_DATA_AFTER_RST_RCVD); return true; } diff --git a/src/stream/tcp/tcp_state_syn_sent.cc b/src/stream/tcp/tcp_state_syn_sent.cc index c8e8c69f0..deb555d99 100644 --- a/src/stream/tcp/tcp_state_syn_sent.cc +++ b/src/stream/tcp/tcp_state_syn_sent.cc @@ -31,8 +31,7 @@ using namespace snort; TcpStateSynSent::TcpStateSynSent(TcpStateMachine& tsm) : TcpStateHandler(TcpStreamTracker::TCP_SYN_SENT, tsm) -{ -} +{ } bool TcpStateSynSent::syn_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) { @@ -43,7 +42,7 @@ bool TcpStateSynSent::syn_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) bool TcpStateSynSent::syn_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) { trk.finish_client_init(tsd); - if ( tsd.get_len() ) + if ( tsd.is_data_segment() ) trk.session->handle_data_on_syn(tsd); trk.set_tcp_state(TcpStreamTracker::TCP_SYN_RECV); return true; @@ -54,11 +53,12 @@ bool TcpStateSynSent::syn_ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& if ( trk.update_on_3whs_ack(tsd) ) { trk.session->update_timestamp_tracking(tsd); - if ( tsd.get_len() ) + if ( tsd.is_data_segment() ) trk.session->handle_data_on_syn(tsd); } else trk.session->set_pkt_action_flag(ACTION_BAD_PKT); + return true; } @@ -66,8 +66,6 @@ bool TcpStateSynSent::ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) { Flow* flow = tsd.get_flow(); - // FIXIT-H verify ack being sent is valid... - // norm/drop + discard trk.update_tracker_ack_sent(tsd); flow->set_session_flags(SSNFLAG_ESTABLISHED); flow->session_state |= ( STREAM_STATE_ACK | STREAM_STATE_ESTABLISHED ); @@ -79,7 +77,7 @@ bool TcpStateSynSent::ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) bool TcpStateSynSent::ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) { - if ( tsd.get_len() > 0 ) + if ( tsd.is_data_segment() ) trk.session->handle_data_segment(tsd); return true; } @@ -88,8 +86,6 @@ bool TcpStateSynSent::data_seg_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& { Flow* flow = tsd.get_flow(); - // FIXIT-H verify ack being sent is valid... - // norm/drop + discard trk.update_tracker_ack_sent(tsd); flow->set_session_flags(SSNFLAG_ESTABLISHED); flow->session_state |= ( STREAM_STATE_ACK | STREAM_STATE_ESTABLISHED ); @@ -107,7 +103,7 @@ bool TcpStateSynSent::data_seg_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& bool TcpStateSynSent::fin_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) { - if ( tsd.get_len() > 0 ) + if ( tsd.is_data_segment() ) trk.session->handle_data_segment(tsd); return true; } @@ -122,13 +118,9 @@ bool TcpStateSynSent::rst_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) trk.session->set_pkt_action_flag(ACTION_RST); tsd.get_flow()->session_state |= STREAM_STATE_CLOSED; } - else - { - trk.session->tel.set_tcp_event(EVENT_BAD_RST); - } // FIXIT-L might be good to create alert specific to RST with data - if ( tsd.get_len() > 0 ) + if ( tsd.is_data_segment() ) trk.session->tel.set_tcp_event(EVENT_DATA_AFTER_RST_RCVD); return true; } diff --git a/src/stream/tcp/tcp_state_time_wait.cc b/src/stream/tcp/tcp_state_time_wait.cc index 9c4351809..6c17227e0 100644 --- a/src/stream/tcp/tcp_state_time_wait.cc +++ b/src/stream/tcp/tcp_state_time_wait.cc @@ -44,7 +44,7 @@ bool TcpStateTimeWait::syn_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk bool TcpStateTimeWait::syn_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk) { trk.normalizer.ecn_tracker(tsd.get_tcph(), trk.session->tcp_config->require_3whs()); - if ( tsd.get_len() ) + if ( tsd.is_data_segment() ) trk.session->handle_data_on_syn(tsd); return true; @@ -73,7 +73,7 @@ bool TcpStateTimeWait::fin_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk trk.normalizer.packet_dropper(tsd, NORM_TCP_BLOCK); trk.session->set_pkt_action_flag(ACTION_BAD_PKT); } - else if ( tsd.get_len() > 0 ) + else if ( tsd.is_data_segment() ) trk.session->handle_data_segment(tsd); return true; @@ -87,14 +87,8 @@ bool TcpStateTimeWait::rst_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk trk.session->update_perf_base_state(TcpStreamTracker::TCP_CLOSING); trk.session->set_pkt_action_flag(ACTION_RST); } - else - { - trk.session->tel.set_tcp_event(EVENT_BAD_RST); - } - // FIXIT-L might be good to create alert specific to RST with data - // FIXIT-L refactoring required? seen this in many places - if ( tsd.get_len() > 0 ) + if ( tsd.is_data_segment() ) trk.session->tel.set_tcp_event(EVENT_DATA_AFTER_RST_RCVD); return true; diff --git a/src/stream/tcp/tcp_stream_session.cc b/src/stream/tcp/tcp_stream_session.cc index 33ba85267..383b846bf 100644 --- a/src/stream/tcp/tcp_stream_session.cc +++ b/src/stream/tcp/tcp_stream_session.cc @@ -58,7 +58,7 @@ void TcpStreamSession::init_new_tcp_session(TcpSegmentDescriptor& tsd) void TcpStreamSession::update_session_on_syn_ack() { /* If session is already marked as established */ - if ( !( flow->session_state & STREAM_STATE_ESTABLISHED ) ) + if ( !(flow->session_state & STREAM_STATE_ESTABLISHED) ) { /* SYN-ACK from server */ if (flow->session_state != STREAM_STATE_NONE) @@ -72,7 +72,7 @@ void TcpStreamSession::update_session_on_syn_ack() void TcpStreamSession::update_session_on_ack() { /* If session is already marked as established */ - if ( !( flow->session_state & STREAM_STATE_ESTABLISHED ) ) + if ( !(flow->session_state & STREAM_STATE_ESTABLISHED) ) { if ( flow->session_state & STREAM_STATE_SYN_ACK ) { @@ -89,14 +89,14 @@ void TcpStreamSession::update_session_on_server_packet(TcpSegmentDescriptor& tsd tsd.set_listener(client); /* If we picked this guy up midstream, finish the initialization */ - if ( !( flow->session_state & STREAM_STATE_ESTABLISHED ) - && ( flow->session_state & STREAM_STATE_MIDSTREAM ) ) + if ( !(flow->session_state & STREAM_STATE_ESTABLISHED) + && (flow->session_state & STREAM_STATE_MIDSTREAM) ) { - if (tsd.get_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 ( flow->get_session_flags() & SSNFLAG_SEEN_CLIENT ) { // should TCP state go to established too? flow->session_state |= STREAM_STATE_ESTABLISHED; @@ -120,14 +120,14 @@ void TcpStreamSession::update_session_on_client_packet(TcpSegmentDescriptor& tsd && ( flow->session_state & STREAM_STATE_MIDSTREAM ) ) { /* Midstream and seen server. */ - if (flow->get_session_flags() & SSNFLAG_SEEN_SERVER) + if ( flow->get_session_flags() & SSNFLAG_SEEN_SERVER ) { flow->session_state |= STREAM_STATE_ESTABLISHED; flow->set_session_flags(SSNFLAG_ESTABLISHED); } } - if (!flow->inner_client_ttl && !tsd.is_meta_ack_packet() ) + if ( !flow->inner_client_ttl && !tsd.is_meta_ack_packet() ) flow->set_ttl(tsd.get_pkt(), true); } @@ -148,8 +148,8 @@ void TcpStreamSession::disable_reassembly(Flow* f) client.reassembler.purge_segment_list(); server.reassembler.purge_segment_list(); - client.flush_policy = STREAM_FLPOLICY_IGNORE; - server.flush_policy = STREAM_FLPOLICY_IGNORE; + client.set_flush_policy(STREAM_FLPOLICY_IGNORE); + server.set_flush_policy(STREAM_FLPOLICY_IGNORE); client.finalize_held_packet(f); server.finalize_held_packet(f); @@ -159,10 +159,10 @@ uint8_t TcpStreamSession::get_reassembly_direction() { uint8_t dir = SSN_DIR_NONE; - if (server.get_flush_policy() != STREAM_FLPOLICY_IGNORE) + if ( server.get_flush_policy() != STREAM_FLPOLICY_IGNORE ) dir |= SSN_DIR_FROM_CLIENT; - if (client.get_flush_policy() != STREAM_FLPOLICY_IGNORE) + if ( client.get_flush_policy() != STREAM_FLPOLICY_IGNORE ) dir |= SSN_DIR_FROM_SERVER; return dir; @@ -170,7 +170,7 @@ uint8_t TcpStreamSession::get_reassembly_direction() bool TcpStreamSession::is_sequenced(uint8_t dir) { - if (dir & SSN_DIR_FROM_CLIENT) + if ( dir & SSN_DIR_FROM_CLIENT ) { if ( server.get_tf_flags() & ( TF_MISSING_PREV_PKT | TF_PKT_MISSED ) ) return false; @@ -189,24 +189,24 @@ bool TcpStreamSession::is_sequenced(uint8_t dir) * packet if reassembly for this direction was set mid-session */ uint8_t TcpStreamSession::missing_in_reassembled(uint8_t dir) { - if (dir & SSN_DIR_FROM_CLIENT) + if ( dir & SSN_DIR_FROM_CLIENT ) { if ( (server.get_tf_flags() & TF_MISSING_PKT) - && (server.get_tf_flags() & TF_MISSING_PREV_PKT)) + && (server.get_tf_flags() & TF_MISSING_PREV_PKT) ) return SSN_MISSING_BOTH; - else if (server.get_tf_flags() & TF_MISSING_PREV_PKT) + else if ( server.get_tf_flags() & TF_MISSING_PREV_PKT ) return SSN_MISSING_BEFORE; - else if (server.get_tf_flags() & TF_MISSING_PKT) + else if ( server.get_tf_flags() & TF_MISSING_PKT ) return SSN_MISSING_AFTER; } - else if (dir & SSN_DIR_FROM_SERVER) + else if ( dir & SSN_DIR_FROM_SERVER ) { - if ((client.get_tf_flags() & TF_MISSING_PKT) - && (client.get_tf_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.get_tf_flags() & TF_MISSING_PREV_PKT) + else if ( client.get_tf_flags() & TF_MISSING_PREV_PKT ) return SSN_MISSING_BEFORE; - else if (client.get_tf_flags() & TF_MISSING_PKT) + else if ( client.get_tf_flags() & TF_MISSING_PKT ) return SSN_MISSING_AFTER; } @@ -215,15 +215,15 @@ uint8_t TcpStreamSession::missing_in_reassembled(uint8_t dir) bool TcpStreamSession::are_packets_missing(uint8_t dir) { - if (dir & SSN_DIR_FROM_CLIENT) + if ( dir & SSN_DIR_FROM_CLIENT ) { - if (server.get_tf_flags() & TF_PKT_MISSED) + if ( server.get_tf_flags() & TF_PKT_MISSED ) return true; } - if (dir & SSN_DIR_FROM_SERVER) + if ( dir & SSN_DIR_FROM_SERVER ) { - if (client.get_tf_flags() & TF_PKT_MISSED) + if ( client.get_tf_flags() & TF_PKT_MISSED ) return true; } @@ -232,62 +232,31 @@ bool TcpStreamSession::are_packets_missing(uint8_t dir) bool TcpStreamSession::add_alert(Packet* p, uint32_t gid, uint32_t sid) { - TcpStreamTracker& st = p->ptrs.ip_api.get_src()->equals(flow->client_ip) ? server : client; - StreamAlertInfo* ai; - - if (st.alert_count >= MAX_SESSION_ALERTS) - return false; - - ai = st.alerts + st.alert_count; - ai->gid = gid; - ai->sid = sid; - ai->seq = 0; - ai->event_id = 0; - ai->event_second = 0; - - st.alert_count++; + TcpReassemblerPolicy& trp = p->ptrs.ip_api.get_src()->equals(flow->client_ip) ? + server.reassembler : client.reassembler; - return true; + return trp.add_alert(gid, sid); } bool TcpStreamSession::check_alerted(Packet* p, uint32_t gid, uint32_t sid) { - /* If this is not a rebuilt packet, no need to check further */ - if (!(p->packet_flags & PKT_REBUILT_STREAM)) + // only check alerts on rebuilt packets + if ( !(p->packet_flags & PKT_REBUILT_STREAM) ) return false; - const TcpStreamTracker& st = p->ptrs.ip_api.get_src()->equals(flow->client_ip) ? server : client; - for (int i = 0; i < st.alert_count; i++) - { - /* This is a rebuilt packet and if we've seen this alert before, - * return that we have previously alerted on original packet. - */ - if (st.alerts[i].gid == gid && st.alerts[i].sid == sid) - return true; - } + TcpReassemblerPolicy& trp = p->ptrs.ip_api.get_src()->equals(flow->client_ip) ? + server.reassembler : client.reassembler; - return false; + return trp.check_alerted(gid, sid); } int TcpStreamSession::update_alert(Packet* p, uint32_t gid, uint32_t sid, uint32_t event_id, uint32_t event_second) { - uint32_t seq_num = 0; - TcpStreamTracker& st = p->ptrs.ip_api.get_src()->equals(flow->client_ip) ? server : client; - - for (unsigned i = 0; i < st.alert_count; i++) - { - StreamAlertInfo* ai = &st.alerts[i]; + TcpReassemblerPolicy& trp = p->ptrs.ip_api.get_src()->equals(flow->client_ip) ? + server.reassembler : client.reassembler; - if (ai->gid == gid && ai->sid == sid && SEQ_EQ(ai->seq, seq_num)) - { - ai->event_id = event_id; - ai->event_second = event_second; - return 0; - } - } - - return -1; + return trp.update_alert(gid, sid, event_id, event_second); } bool TcpStreamSession::set_packet_action_to_hold(Packet* p) @@ -350,27 +319,10 @@ void TcpStreamSession::get_packet_header_foo(DAQ_PktHdr_t* pkth, uint32_t dir) void TcpStreamSession::reset() { - if (tcp_init) + if ( tcp_init ) clear_session(true, false, false ); } -bool TcpStreamSession::setup(Packet*) -{ - client.init_tcp_state(); - server.init_tcp_state(); - lws_init = tcp_init = false; - generate_3whs_alert = true; - cleaning = false; - pkt_action_mask = ACTION_NOTHING; - ecn = 0; - ingress_index = egress_index = 0; - ingress_group = egress_group = 0; - daq_flags = address_space_id = 0; - tcp_config = nullptr; - - return true; -} - void TcpStreamSession::cleanup(Packet* p) { if ( cleaning ) @@ -388,7 +340,6 @@ void TcpStreamSession::cleanup(Packet* p) void TcpStreamSession::clear() { if ( tcp_init ) - // this does NOT flush data clear_session( true, false, false ); TcpHAManager::process_deletion(*flow); @@ -424,7 +375,5 @@ StreamSplitter* TcpStreamSession::get_splitter(bool to_server) } void TcpStreamSession::start_proxy() -{ - tcp_config->policy = StreamPolicy::OS_PROXY; -} +{ tcp_config->policy = StreamPolicy::OS_PROXY; } diff --git a/src/stream/tcp/tcp_stream_session.h b/src/stream/tcp/tcp_stream_session.h index 7c1fbeecb..b9aa98ccd 100644 --- a/src/stream/tcp/tcp_stream_session.h +++ b/src/stream/tcp/tcp_stream_session.h @@ -37,24 +37,23 @@ class TcpStreamSession : public Session public: ~TcpStreamSession() override; - bool setup(snort::Packet*) override; void clear() override; void cleanup(snort::Packet* = nullptr) override; void set_splitter(bool, snort::StreamSplitter*) override; snort::StreamSplitter* get_splitter(bool) override; - bool is_sequenced(uint8_t /*dir*/) override; - bool are_packets_missing(uint8_t /*dir*/) override; + bool is_sequenced(uint8_t dir) override; + bool are_packets_missing(uint8_t dir) override; void disable_reassembly(snort::Flow*) override; uint8_t get_reassembly_direction() override; - uint8_t missing_in_reassembled(uint8_t /*dir*/) override; + uint8_t missing_in_reassembled(uint8_t dir) override; bool add_alert(snort::Packet*, uint32_t gid, uint32_t sid) override; bool check_alerted(snort::Packet*, uint32_t gid, uint32_t sid) override; - int update_alert(snort::Packet*, uint32_t /*gid*/, uint32_t /*sid*/, - uint32_t /*event_id*/, uint32_t /*event_second*/) override; + int update_alert(snort::Packet*, uint32_t gid, uint32_t sid, + uint32_t event_id, uint32_t event_second) override; bool set_packet_action_to_hold(snort::Packet*) override; @@ -68,17 +67,12 @@ public: void get_packet_header_foo(DAQ_PktHdr_t*, uint32_t dir); void set_no_ack(bool); bool no_ack_mode_enabled() { return no_ack; } - virtual void update_perf_base_state(char) = 0; virtual void clear_session( bool free_flow_data, bool flush_segments, bool restart, snort::Packet* p = nullptr) = 0; - virtual void flush() = 0; - virtual TcpStreamTracker::TcpState get_talker_state(TcpSegmentDescriptor&) = 0; - virtual TcpStreamTracker::TcpState get_listener_state(TcpSegmentDescriptor&) = 0; - TcpStreamTracker::TcpState get_peer_state(TcpStreamTracker* me) { return me == &client ? server.get_tcp_state() : client.get_tcp_state(); } @@ -127,10 +121,10 @@ public: bool generate_3whs_alert = true; TcpStreamConfig* tcp_config = nullptr; TcpEventLogger tel; + bool cleaning = false; private: bool no_ack = false; - bool cleaning = false; protected: TcpStreamSession(snort::Flow*); diff --git a/src/stream/tcp/tcp_stream_tracker.cc b/src/stream/tcp/tcp_stream_tracker.cc index 93740df2c..12bc51e1e 100644 --- a/src/stream/tcp/tcp_stream_tracker.cc +++ b/src/stream/tcp/tcp_stream_tracker.cc @@ -34,7 +34,6 @@ #include "held_packet_queue.h" #include "segment_overlap_editor.h" -#include "tcp_module.h" #include "tcp_normalizers.h" #include "tcp_reassemblers.h" #include "tcp_session.h" @@ -95,16 +94,17 @@ TcpStreamTracker::TcpEvent TcpStreamTracker::set_tcp_event(const TcpSegmentDescr tcp_event = TCP_FIN_SENT_EVENT; else if ( tcph->is_ack() || tcph->is_psh() ) { - if ( tsd.get_len() > 0 ) + if ( tsd.is_data_segment() ) tcp_event = TCP_DATA_SEG_SENT_EVENT; else tcp_event = TCP_ACK_SENT_EVENT; } - else if ( tsd.get_len() > 0 ) // FIXIT-H no flags set, how do we handle this? - // discard; drop if normalizing - tcp_event = TCP_DATA_SEG_SENT_EVENT; else - tcp_event = TCP_ACK_SENT_EVENT; + { + // count no flags set on the talker side... + tcpStats.no_flags_set++; + tcp_event = TCP_NO_FLAGS_EVENT; + } } else { @@ -138,16 +138,15 @@ TcpStreamTracker::TcpEvent TcpStreamTracker::set_tcp_event(const TcpSegmentDescr } else if ( tcph->is_ack() || tcph->is_psh() ) { - if ( tsd.get_len() > 0 ) + if ( tsd.is_data_segment() ) tcp_event = TCP_DATA_SEG_RECV_EVENT; else tcp_event = TCP_ACK_RECV_EVENT; } - else if ( tsd.get_len() > 0 ) // FIXIT-H no flags set, how do we handle this? - // discard; drop if normalizing - tcp_event = TCP_DATA_SEG_RECV_EVENT; else - tcp_event = TCP_ACK_RECV_EVENT; + { + tcp_event = TCP_NO_FLAGS_EVENT; + } } return tcp_event; @@ -203,13 +202,14 @@ void TcpStreamTracker::init_tcp_state() { tcp_state = ( client_tracker ) ? TcpStreamTracker::TCP_STATE_NONE : TcpStreamTracker::TCP_LISTEN; - flush_policy = STREAM_FLPOLICY_IGNORE; - paf_setup(&paf_state); + snd_una = snd_nxt = snd_wnd = 0; - rcv_nxt = r_win_base = iss = ts_last = ts_last_packet = 0; - small_seg_count = wscale = mss = 0; + rcv_nxt = r_win_base = iss = 0; + ts_last = ts_last_packet = 0; + small_seg_count = 0; + wscale = 0; + mss = 0; tf_flags = 0; - alert_count = 0; mac_addr_valid = false; fin_final_seq = 0; fin_seq_status = TcpStreamTracker::FIN_NOT_SEEN; @@ -217,6 +217,8 @@ void TcpStreamTracker::init_tcp_state() rst_pkt_sent = false; order = 0; held_packet = null_iterator; + flush_policy = STREAM_FLPOLICY_IGNORE; + reassembler.setup_paf(); } //------------------------------------------------------------------------- @@ -225,7 +227,7 @@ void TcpStreamTracker::init_tcp_state() void TcpStreamTracker::init_flush_policy() { - if ( splitter == nullptr ) + if ( !splitter ) flush_policy = STREAM_FLPOLICY_IGNORE; else if ( normalizer.is_tcp_ips_enabled() ) flush_policy = STREAM_FLPOLICY_ON_DATA; @@ -244,7 +246,7 @@ void TcpStreamTracker::set_splitter(StreamSplitter* ss) flush_policy = STREAM_FLPOLICY_IGNORE; else { - paf_setup(&paf_state); + reassembler.setup_paf(); reassembler.reset_paf_segment(); } } @@ -362,7 +364,6 @@ void TcpStreamTracker::init_on_3whs_ack_sent(TcpSegmentDescriptor& tsd) ts_last = tsd.get_timestamp(); if (ts_last == 0) tf_flags |= TF_TSTAMP_ZERO; - tf_flags |= tsd.init_mss(&mss); tf_flags |= tsd.init_wscale(&wscale); cache_mac_address(tsd, FROM_CLIENT); @@ -409,7 +410,7 @@ void TcpStreamTracker::init_on_data_seg_sent(TcpSegmentDescriptor& tsd) ts_last = tsd.get_timestamp(); if (ts_last == 0) tf_flags |= TF_TSTAMP_ZERO; - tf_flags |= ( tsd.init_mss(&mss) | tsd.init_wscale(&wscale) ); + tf_flags |= tsd.init_wscale(&wscale); cache_mac_address(tsd, tsd.get_direction() ); tcp_state = TcpStreamTracker::TCP_ESTABLISHED; @@ -495,13 +496,6 @@ void TcpStreamTracker::update_tracker_no_ack_sent(TcpSegmentDescriptor& tsd) void TcpStreamTracker::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-H add check to validate ack... - // norm/drop + discard - if ( SEQ_GT(tsd.get_end_seq(), snd_nxt) ) snd_nxt = tsd.get_end_seq(); @@ -520,9 +514,9 @@ void TcpStreamTracker::update_tracker_ack_sent(TcpSegmentDescriptor& tsd) bool TcpStreamTracker::update_on_3whs_ack(TcpSegmentDescriptor& tsd) { - bool good_ack = true; + bool good_ack = is_ack_valid(tsd.get_ack()); - if ( is_ack_valid(tsd.get_ack()) ) + if ( good_ack ) { Flow* flow = tsd.get_flow(); @@ -533,22 +527,15 @@ bool TcpStreamTracker::update_on_3whs_ack(TcpSegmentDescriptor& tsd) flow->session_state |= ( STREAM_STATE_ACK | STREAM_STATE_ESTABLISHED ); tcp_state = TcpStreamTracker::TCP_ESTABLISHED; } - else - { - inc_tcp_discards(); - normalizer.trim_win_payload(tsd); - good_ack = false; - } return good_ack; } bool TcpStreamTracker::update_on_rst_recv(TcpSegmentDescriptor& tsd) { - bool good_rst = true; - normalizer.trim_rst_payload(tsd); - if ( normalizer.validate_rst(tsd) ) + bool good_rst = normalizer.validate_rst(tsd); + if ( good_rst ) { Flow* flow = tsd.get_flow(); @@ -558,9 +545,9 @@ bool TcpStreamTracker::update_on_rst_recv(TcpSegmentDescriptor& tsd) } else { - inc_tcp_discards(); + session->tel.set_tcp_event(EVENT_BAD_RST); normalizer.packet_dropper(tsd, NORM_TCP_BLOCK); - good_rst = false; + session->set_pkt_action_flag(ACTION_BAD_PKT); } return good_rst; @@ -572,18 +559,6 @@ void TcpStreamTracker::update_on_rst_sent() rst_pkt_sent = true; } -void TcpStreamTracker::flush_data_on_fin_recv(TcpSegmentDescriptor& tsd) -{ - if ( (flush_policy != STREAM_FLPOLICY_ON_ACK) - && (flush_policy != STREAM_FLPOLICY_ON_DATA) - && normalizer.is_tcp_ips_enabled()) - { - tsd.set_packet_flags(PKT_PDU_TAIL); - } - - reassembler.flush_on_data_policy(tsd.get_pkt()); -} - bool TcpStreamTracker::update_on_fin_recv(TcpSegmentDescriptor& tsd) { if ( SEQ_LT(tsd.get_end_seq(), r_win_base) ) @@ -629,7 +604,7 @@ bool TcpStreamTracker::is_segment_seq_valid(TcpSegmentDescriptor& tsd) else left_seq = r_win_base; - if ( tsd.get_len() ) + if ( tsd.is_data_segment() ) right_ok = SEQ_GT(tsd.get_end_seq(), left_seq); else right_ok = SEQ_GEQ(tsd.get_end_seq(), left_seq); @@ -639,24 +614,12 @@ bool TcpStreamTracker::is_segment_seq_valid(TcpSegmentDescriptor& tsd) uint32_t win = normalizer.get_stream_window(tsd); if ( SEQ_LEQ(tsd.get_seq(), r_win_base + win) ) - { return true; - } else - { valid_seq = false; - } } else - { valid_seq = false; - } - - if ( !valid_seq ) - { - inc_tcp_discards(); - normalizer.trim_win_payload(tsd); - } return valid_seq; } diff --git a/src/stream/tcp/tcp_stream_tracker.h b/src/stream/tcp/tcp_stream_tracker.h index 4435bdc00..490c5650f 100644 --- a/src/stream/tcp/tcp_stream_tracker.h +++ b/src/stream/tcp/tcp_stream_tracker.h @@ -28,23 +28,11 @@ #include "segment_overlap_editor.h" #include "tcp_defs.h" +#include "tcp_module.h" #include "tcp_normalizers.h" #include "tcp_reassemblers.h" #include "tcp_segment_descriptor.h" -/* Only track a maximum number of alerts per session */ -#define MAX_SESSION_ALERTS 8 -struct StreamAlertInfo -{ - /* For storing alerts that have already been seen on the session */ - uint32_t sid; - uint32_t gid; - uint32_t seq; - // if we log extra data, event_* is used to correlate with alert - uint32_t event_id; - uint32_t event_second; -}; - extern const char* tcp_state_names[]; extern const char* tcp_event_names[]; @@ -91,6 +79,7 @@ public: TCP_FIN_RECV_EVENT, TCP_RST_SENT_EVENT, TCP_RST_RECV_EVENT, + TCP_NO_FLAGS_EVENT, TCP_MAX_EVENTS }; @@ -202,11 +191,14 @@ public: bool is_ack_valid(uint32_t cur) { - // If we haven't seen anything, ie, low & high are 0, return true if ( ( snd_una == 0 ) && ( snd_nxt == 0 ) ) return true; - return ( SEQ_GEQ(cur, snd_una) && SEQ_LEQ(cur, snd_nxt) ); + bool valid = SEQ_GEQ(cur, snd_una) && SEQ_LEQ(cur, snd_nxt); + if ( !valid ) + tcpStats.invalid_ack++; + + return valid; } // ack number must ack syn @@ -252,18 +244,26 @@ public: bool is_rst_pkt_sent() const { return rst_pkt_sent; } - snort::StreamSplitter* get_splitter() - { return splitter; } + void set_flush_policy(FlushPolicy policy) + { flush_policy = policy; } FlushPolicy get_flush_policy() { return flush_policy; } virtual void init_tcp_state(); virtual void init_flush_policy(); - virtual void set_splitter(snort::StreamSplitter* ss); virtual void set_splitter(const snort::Flow* flow); + snort::StreamSplitter* get_splitter() + { return splitter; } + + bool is_splitter_paf() const + { return splitter && splitter->is_paf(); } + + bool is_reassembly_enabled() const + { return ( splitter and (flush_policy != STREAM_FLPOLICY_IGNORE) ); } + virtual void init_on_syn_sent(TcpSegmentDescriptor&); virtual void init_on_syn_recv(TcpSegmentDescriptor&); virtual void init_on_synack_sent(TcpSegmentDescriptor&); @@ -285,7 +285,6 @@ public: virtual bool update_on_fin_recv(TcpSegmentDescriptor&); virtual bool update_on_fin_sent(TcpSegmentDescriptor&); virtual bool is_segment_seq_valid(TcpSegmentDescriptor&); - virtual void flush_data_on_fin_recv(TcpSegmentDescriptor&); bool set_held_packet(snort::Packet*); bool is_retransmit_of_held_packet(snort::Packet*); void finalize_held_packet(snort::Packet*); @@ -327,48 +326,30 @@ public: public: TcpNormalizerPolicy normalizer; TcpReassemblerPolicy reassembler; - - StreamAlertInfo alerts[MAX_SESSION_ALERTS]; - - // 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 - TcpSession* session = nullptr; - snort::StreamSplitter* splitter = nullptr; - - FlushPolicy flush_policy = STREAM_FLPOLICY_IGNORE; uint32_t r_win_base = 0; // remote side window base sequence number (the last ack we got) uint32_t small_seg_count = 0; - - uint16_t wscale = 0; /* window scale setting */ - uint16_t mss = 0; /* max segment size */ - - uint8_t alert_count = 0; uint8_t order = 0; - FinSeqNumStatus fin_seq_status = TcpStreamTracker::FIN_NOT_SEEN; - std::list::iterator held_packet; protected: - // FIXIT-H reorganize per-flow structs to minimize padding + static const std::list::iterator null_iterator; + std::list::iterator held_packet; + snort::StreamSplitter* splitter = nullptr; uint32_t ts_last_packet = 0; - uint32_t ts_last = 0; /* last timestamp (for PAWS) */ - + uint32_t ts_last = 0; // last timestamp (for PAWS) uint32_t fin_final_seq = 0; uint32_t fin_seq_adjust = 0; - + uint16_t mss = 0; // max segment size + uint16_t wscale = 0; // window scale setting uint16_t tf_flags = 0; - uint8_t mac_addr[6] = { }; uint8_t tcp_options_len = 0; + FlushPolicy flush_policy = STREAM_FLPOLICY_IGNORE; bool mac_addr_valid = false; bool fin_seq_set = false; // FIXIT-M should be obviated by tcp state - - static const std::list::iterator null_iterator; }; // <--- note -- the 'state' parameter must be a reference