From: Russ Combs (rucombs) Date: Fri, 15 May 2020 21:40:47 +0000 (+0000) Subject: Merge pull request #2189 in SNORT/snort3 from ~DAVMCPHE/snort3:fallback to master X-Git-Tag: 3.0.1-4~6 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=9ac36fc03aa705b7b6ec070db758fa931d168f48;p=thirdparty%2Fsnort3.git Merge pull request #2189 in SNORT/snort3 from ~DAVMCPHE/snort3:fallback to master Squashed commit of the following: commit 0031d861c9c23b1a08e27a77d10d8ee68f4f7fb4 Author: davis mcpherson Date: Fri May 1 13:23:54 2020 -0400 dce_rpc: code style cleanups commit 5a9614634d99202a0202494b6021116edea1d7e4 Author: davis mcpherson Date: Wed Apr 29 11:24:49 2020 -0400 dce_rpc: generate alert when dce splitter aborts due to invalid fragment length commit 75e56ee0f0a6e875c13de32963b58f15e3c43c7f Author: davis mcpherson Date: Fri May 8 17:16:47 2020 -0400 stream_tcp: call splitter->finish() before reassemble() when flushing when PAF aborts due to gap in queued data commit 39336beb1c4421ebb2124a2beb20ae1c8a5ae9b1 Author: russ Date: Tue Apr 21 14:20:50 2020 -0400 stream_tcp: clear gadget from Flow object once fallback has happened in both directions stream_tcp: when paf aborts due to gap in data set splitter state to ABORT stream_tcp: only clear gadget after both splitters have aborted loggers: when logging alert only use inspector buffers and name when the inspector's paf splitter is assigned for the direction of the alert" --- diff --git a/src/log/log_text.cc b/src/log/log_text.cc index 0c72dbc44..cbab0915a 100644 --- a/src/log/log_text.cc +++ b/src/log/log_text.cc @@ -1160,7 +1160,8 @@ static void obfuscate(Packet* p, const uint8_t* data, int& ip_ob_start, int& ip_ } void LogNetData( - TextLog* log, const uint8_t* data, const int len, Packet* p, const char* buf_name) + TextLog* log, const uint8_t* data, const int len, Packet* p, const char* buf_name, + const char* ins_name) { if ( !len ) return; @@ -1177,7 +1178,9 @@ void LogNetData( const HexAsciiLayout& hal = SnortConfig::get_conf()->output_wide_hex() ? hal_wide : hal_std; const char* hdr_off = SnortConfig::verbose_byte_dump() ? hal.offset_hdr : ""; - const char* ins_name = p->flow and p->flow->gadget ? p->flow->gadget->get_name() : "snort"; + + if ( !ins_name ) + ins_name = p->flow and p->flow->gadget ? p->flow->gadget->get_name() : "snort"; TextLog_Print(log, "\n%s.%s[%u]:\n", ins_name, buf_name, len); TextLog_Print(log, "%s%s\n", hdr_off, hal.separator); diff --git a/src/log/log_text.h b/src/log/log_text.h index d924501ec..6a887640a 100644 --- a/src/log/log_text.h +++ b/src/log/log_text.h @@ -43,7 +43,8 @@ SO_PUBLIC void LogPayload(TextLog*, Packet*); SO_PUBLIC bool LogAppID(TextLog*, Packet*); SO_PUBLIC void LogNetData( - TextLog*, const uint8_t* data, const int len, Packet*, const char* buf_name = nullptr); + TextLog*, const uint8_t* data, const int len, Packet*, const char* buf_name = nullptr, + const char* ins_name = nullptr); SO_PUBLIC void Log2ndHeader(TextLog*, Packet*); SO_PUBLIC void LogTCPHeader(TextLog*, Packet*); diff --git a/src/loggers/alert_fast.cc b/src/loggers/alert_fast.cc index 7ffd70ee6..7f1a43837 100644 --- a/src/loggers/alert_fast.cc +++ b/src/loggers/alert_fast.cc @@ -42,6 +42,8 @@ #include "detection/detection_engine.h" #include "detection/signature.h" #include "events/event.h" +#include "flow/flow.h" +#include "flow/session.h" #include "framework/logger.h" #include "framework/module.h" #include "log/log_text.h" @@ -52,6 +54,7 @@ #include "packet_io/active.h" #include "packet_io/sfdaq.h" #include "service_inspectors/http_inspect/http_enum.h" +#include "stream/stream_splitter.h" using namespace snort; using namespace std; @@ -255,7 +258,18 @@ void FastLogger::log_data(Packet* p, const Event& event) bool log_pkt = true; TextLog_NewLine(fast_log); - Inspector* gadget = p->flow ? p->flow->gadget : nullptr; + const char* ins_name = "snort"; + Inspector* gadget = nullptr; + if ( p->flow and p->flow->session ) + { + snort::StreamSplitter* ss = p->flow->session->get_splitter(p->is_from_client()); + if ( ss and ss->is_paf() ) + { + gadget = p->flow->gadget; + if ( gadget ) + ins_name = gadget->get_name(); + } + } const char** buffers = gadget ? gadget->get_api()->buffers : nullptr; if ( buffers ) @@ -269,7 +283,7 @@ void FastLogger::log_data(Packet* p, const Event& event) { if ( gadget->get_buf(id, p, buf) ) - LogNetData(fast_log, buf.data, buf.len, p, buffers[id-1]); + LogNetData(fast_log, buf.data, buf.len, p, buffers[id-1], ins_name); log_pkt = rsp; } @@ -279,13 +293,13 @@ void FastLogger::log_data(Packet* p, const Event& event) InspectionBuffer buf; if ( gadget->get_buf(InspectionBuffer::IBT_KEY, p, buf) ) - LogNetData(fast_log, buf.data, buf.len, p); + LogNetData(fast_log, buf.data, buf.len, p, nullptr, ins_name); if ( gadget->get_buf(InspectionBuffer::IBT_HEADER, p, buf) ) - LogNetData(fast_log, buf.data, buf.len, p); + LogNetData(fast_log, buf.data, buf.len, p, nullptr, ins_name); if ( gadget->get_buf(InspectionBuffer::IBT_BODY, p, buf) ) - LogNetData(fast_log, buf.data, buf.len, p); + LogNetData(fast_log, buf.data, buf.len, p, nullptr, ins_name); } if (p->has_ip()) LogIPPkt(fast_log, p); @@ -298,10 +312,10 @@ void FastLogger::log_data(Packet* p, const Event& event) for ( const auto& b : *p->obfuscator ) buf.replace(b.offset, b.length, b.length, p->obfuscator->get_mask_char()); - LogNetData(fast_log, (const uint8_t*)buf.c_str(), p->dsize, p); + LogNetData(fast_log, (const uint8_t*)buf.c_str(), p->dsize, p, nullptr, ins_name); } else if ( log_pkt ) - LogNetData(fast_log, p->data, p->dsize, p); + LogNetData(fast_log, p->data, p->dsize, p, nullptr, ins_name); DataBuffer& buf = DetectionEngine::get_alt_buffer(p); diff --git a/src/service_inspectors/dce_rpc/dce_tcp_paf.cc b/src/service_inspectors/dce_rpc/dce_tcp_paf.cc index 374816ef3..fea8cb9a3 100644 --- a/src/service_inspectors/dce_rpc/dce_tcp_paf.cc +++ b/src/service_inspectors/dce_rpc/dce_tcp_paf.cc @@ -25,6 +25,7 @@ #include "dce_tcp_paf.h" +#include "dce_common.h" #include "dce_tcp.h" using namespace snort; @@ -43,75 +44,70 @@ using namespace snort; static StreamSplitter::Status dce2_tcp_paf(DCE2_PafTcpData* ds, Flow* flow, const uint8_t* data, uint32_t len, uint32_t flags, uint32_t* fp) { - uint32_t n = 0; - int start_state; - StreamSplitter::Status ps = StreamSplitter::SEARCH; - uint32_t tmp_fp = 0; DCE2_TcpSsnData* sd = get_dce2_tcp_session_data(flow); - - int num_requests = 0; - if ( dce2_paf_abort((DCE2_SsnData*)sd) ) - { return StreamSplitter::ABORT; - } - if (sd == nullptr) + if ( !sd ) { bool autodetected = false; - if (len >= sizeof(DceRpcCoHdr)) + if ( len >= sizeof(DceRpcCoHdr) ) { const DceRpcCoHdr* co_hdr = (const DceRpcCoHdr*)data; - if ((DceRpcCoVersMaj(co_hdr) == DCERPC_PROTO_MAJOR_VERS__5) + if ( (DceRpcCoVersMaj(co_hdr) == DCERPC_PROTO_MAJOR_VERS__5) && (DceRpcCoVersMin(co_hdr) == DCERPC_PROTO_MINOR_VERS__0) && (((flags & PKT_FROM_CLIENT) && DceRpcCoPduType(co_hdr) == DCERPC_PDU_TYPE__BIND) || ((flags & PKT_FROM_SERVER) && DceRpcCoPduType(co_hdr) == DCERPC_PDU_TYPE__BIND_ACK)) - && (DceRpcCoFragLen(co_hdr) >= sizeof(DceRpcCoHdr))) + && (DceRpcCoFragLen(co_hdr) >= sizeof(DceRpcCoHdr)) ) { autodetected = true; } } - else if ((*data == DCERPC_PROTO_MAJOR_VERS__5) && (flags & PKT_FROM_CLIENT)) + else if ( (*data == DCERPC_PROTO_MAJOR_VERS__5) && (flags & PKT_FROM_CLIENT) ) { autodetected = true; } - if (!autodetected) - { + if ( !autodetected ) return StreamSplitter::ABORT; - } } - start_state = (uint8_t)ds->paf_state; - - while (n < len) + int start_state = (uint8_t)ds->paf_state; + int num_requests = 0; + uint32_t tmp_fp = 0; + uint32_t n = 0; + while ( n < len ) { - switch (ds->paf_state) + switch ( ds->paf_state ) { case DCE2_PAF_TCP_STATES__4: // Get byte order ds->byte_order = DceRpcByteOrder(data[n]); ds->paf_state = (DCE2_PafTcpStates)(((int)ds->paf_state) + 1); break; + case DCE2_PAF_TCP_STATES__8: - if (ds->byte_order == DCERPC_BO_FLAG__LITTLE_ENDIAN) + if ( ds->byte_order == DCERPC_BO_FLAG__LITTLE_ENDIAN ) ds->frag_len = data[n]; else ds->frag_len = data[n] << 8; ds->paf_state = (DCE2_PafTcpStates)(((int)ds->paf_state) + 1); break; + case DCE2_PAF_TCP_STATES__9: - if (ds->byte_order == DCERPC_BO_FLAG__LITTLE_ENDIAN) + if ( ds->byte_order == DCERPC_BO_FLAG__LITTLE_ENDIAN ) ds->frag_len |= data[n] << 8; else ds->frag_len |= data[n]; /* If we get a bad frag length abort */ - if (ds->frag_len < sizeof(DceRpcCoHdr)) + if ( ds->frag_len < sizeof(DceRpcCoHdr) ) { - return StreamSplitter::ABORT; + if ( sd ) + dce_alert(GID_DCE2, DCE2_CO_FRAG_LEN_LT_HDR, (dce2CommonStats*)&dce2_tcp_stats, *(DCE2_SsnData*)sd); + return StreamSplitter::ABORT; } /* Increment n here so we can continue */ @@ -119,11 +115,12 @@ static StreamSplitter::Status dce2_tcp_paf(DCE2_PafTcpData* ds, Flow* flow, cons num_requests++; /* Might have multiple PDUs in one segment. If the last PDU is partial, * flush just before it */ - if ((num_requests == 1) || (n <= len)) + if ( (num_requests == 1) || (n <= len) ) tmp_fp += ds->frag_len; ds->paf_state = DCE2_PAF_TCP_STATES__0; continue; // we incremented n already + default: ds->paf_state = (DCE2_PafTcpStates)(((int)ds->paf_state) + 1); break; @@ -132,13 +129,13 @@ static StreamSplitter::Status dce2_tcp_paf(DCE2_PafTcpData* ds, Flow* flow, cons n++; } - if (tmp_fp != 0) + if ( tmp_fp != 0 ) { *fp = tmp_fp - start_state; return StreamSplitter::FLUSH; } - return ps; + return StreamSplitter::SEARCH; } Dce2TcpSplitter::Dce2TcpSplitter(bool c2s) : StreamSplitter(c2s) diff --git a/src/stream/paf.cc b/src/stream/paf.cc index a78be030a..c6f0d3a17 100644 --- a/src/stream/paf.cc +++ b/src/stream/paf.cc @@ -134,7 +134,6 @@ static bool paf_callback ( const uint8_t* data, uint32_t len, uint32_t flags) { ps->fpt = 0; - ps->paf = ss->scan(pkt, data, len, flags, &ps->fpt); if ( ps->paf == StreamSplitter::ABORT ) @@ -143,7 +142,6 @@ static bool paf_callback ( if ( ps->paf != StreamSplitter::SEARCH ) { ps->fpt += px.idx; - if ( ps->fpt <= px.len ) { px.idx = ps->fpt; @@ -164,9 +162,8 @@ static inline bool paf_eval ( { case StreamSplitter::SEARCH: if ( px.len > px.idx ) - { return paf_callback(ss, ps, px, pkt, data, len, flags); - } + return false; case StreamSplitter::FLUSH: @@ -202,6 +199,7 @@ static inline bool paf_eval ( uint32_t delta = ps->fpt - px.idx; if ( delta > len ) return false; + data += delta; len -= delta; } @@ -270,9 +268,11 @@ int32_t paf_check ( { ps->fpt = 0; px.ft = FT_MAX; + ps->paf = StreamSplitter::ABORT; return paf_flush(ps, px, flags); } *flags = 0; + ps->paf = StreamSplitter::ABORT; return -1; } else if ( SEQ_LEQ(seq + len, ps->seq) ) @@ -285,8 +285,8 @@ int32_t paf_check ( data += shift; len -= shift; } - ps->seq += len; + ps->seq += len; px.idx = total - len; // if 'total' is greater than the maximum paf_max AND 'total' is greater @@ -306,9 +306,7 @@ int32_t paf_check ( len = len + px.len - total; } else - { px.len = total; - } do { @@ -323,6 +321,7 @@ int32_t paf_check ( paf_jump(ps, fp); return fp; } + if ( !cont ) break; diff --git a/src/stream/stream.h b/src/stream/stream.h index 152d6b6d7..1c89fcbca 100644 --- a/src/stream/stream.h +++ b/src/stream/stream.h @@ -26,7 +26,6 @@ #include "flow/flow.h" - struct HostAttributeEntry; namespace snort diff --git a/src/stream/tcp/segment_overlap_editor.h b/src/stream/tcp/segment_overlap_editor.h index 523209285..813f0a94b 100644 --- a/src/stream/tcp/segment_overlap_editor.h +++ b/src/stream/tcp/segment_overlap_editor.h @@ -64,9 +64,7 @@ struct SegmentOverlapState bool keep_segment; ~SegmentOverlapState() - { - seglist.reset(); - } + { seglist.reset(); } void init_sos(TcpSession*, StreamPolicy); void init_soe(TcpSegmentDescriptor& tsd, TcpSegmentNode* left, TcpSegmentNode* right); diff --git a/src/stream/tcp/stream_tcp.cc b/src/stream/tcp/stream_tcp.cc index cd6281533..ba647e0d5 100644 --- a/src/stream/tcp/stream_tcp.cc +++ b/src/stream/tcp/stream_tcp.cc @@ -54,7 +54,9 @@ public: TcpStreamConfig* const config; }; -StreamTcp::StreamTcp (TcpStreamConfig* c) : config(c) {} +StreamTcp::StreamTcp (TcpStreamConfig* c) + : config(c) +{ } StreamTcp::~StreamTcp() { delete config; } diff --git a/src/stream/tcp/tcp_defs.h b/src/stream/tcp/tcp_defs.h index f1135c593..23af99b07 100644 --- a/src/stream/tcp/tcp_defs.h +++ b/src/stream/tcp/tcp_defs.h @@ -30,40 +30,33 @@ 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 TF_NONE 0x0000 -#define TF_WSCALE 0x0001 -#define TF_TSTAMP 0x0002 -#define TF_TSTAMP_ZERO 0x0004 -#define TF_MSS 0x0008 -#define TF_FORCE_FLUSH 0x0010 -#define TF_PKT_MISSED 0x0020 // sticky -#define TF_MISSING_PKT 0x0040 // used internally -#define TF_MISSING_PREV_PKT 0x0080 // reset for each reassembled +#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 TF_NONE 0x0000 +#define TF_WSCALE 0x0001 +#define TF_TSTAMP 0x0002 +#define TF_TSTAMP_ZERO 0x0004 +#define TF_MSS 0x0008 +#define TF_FORCE_FLUSH 0x0010 +#define TF_PKT_MISSED 0x0020 // sticky +#define TF_MISSING_PKT 0x0040 // used internally +#define TF_MISSING_PREV_PKT 0x0080 // reset for each reassembled #define PAWS_WINDOW 60 #define PAWS_24DAYS 2073600 /* 24 days in seconds */ -#define SUB_STATE_NONE 0x00 -#define SUB_SYN_SENT 0x01 -#define SUB_ACK_SENT 0x02 -#define SUB_SETUP_OK 0x03 -#define SUB_RST_SENT 0x04 -#define SUB_FIN_SENT 0x08 - #define STREAM_UNALIGNED 0 #define STREAM_ALIGNED 1 diff --git a/src/stream/tcp/tcp_module.cc b/src/stream/tcp/tcp_module.cc index a36d0248c..d5bdc687d 100644 --- a/src/stream/tcp/tcp_module.cc +++ b/src/stream/tcp/tcp_module.cc @@ -86,6 +86,8 @@ const PegInfo tcp_pegs[] = { CountType::MAX, "max_packets_held", "maximum number of packets held simultaneously" }, { CountType::SUM, "partial_flushes", "number of partial flushes initiated" }, { CountType::SUM, "partial_flush_bytes", "partial flush total bytes" }, + { CountType::SUM, "inspector_fallbacks", "count of fallbacks from assigned service inspector" }, + { CountType::SUM, "partial_fallbacks", "count of fallbacks from assigned service stream splitter" }, { CountType::END, nullptr, nullptr } }; diff --git a/src/stream/tcp/tcp_module.h b/src/stream/tcp/tcp_module.h index 03a98a81c..fd84df72f 100644 --- a/src/stream/tcp/tcp_module.h +++ b/src/stream/tcp/tcp_module.h @@ -73,9 +73,9 @@ struct TcpStats PegCount segs_released; PegCount segs_split; PegCount segs_used; - PegCount rebuilt_packets; //iStreamFlushes + PegCount rebuilt_packets; PegCount rebuilt_buffers; - PegCount rebuilt_bytes; //total_rebuilt_bytes + PegCount rebuilt_bytes; PegCount overlaps; PegCount gaps; PegCount exceeded_max_segs; @@ -100,6 +100,8 @@ struct TcpStats PegCount max_packets_held; PegCount partial_flushes; PegCount partial_flush_bytes; + PegCount inspector_fallbacks; + PegCount partial_fallbacks; }; extern THREAD_LOCAL struct TcpStats tcpStats; diff --git a/src/stream/tcp/tcp_normalizers.cc b/src/stream/tcp/tcp_normalizers.cc index 3de56b1da..3e71fe216 100644 --- a/src/stream/tcp/tcp_normalizers.cc +++ b/src/stream/tcp/tcp_normalizers.cc @@ -186,7 +186,7 @@ static inline int handle_repeated_syn_mswin( /* Windows has some strange behavior here. If the sequence of the reset is the * next expected sequence, it Resets. Otherwise it ignores the 2nd SYN. */ - if (SEQ_EQ(tsd.get_seg_seq(), listener->rcv_nxt)) + if ( SEQ_EQ(tsd.get_seg_seq(), listener->rcv_nxt) ) { session->flow->set_session_flags(SSNFLAG_RESET); talker->set_tcp_state(TcpStreamTracker::TCP_CLOSED); @@ -203,7 +203,7 @@ static inline int handle_repeated_syn_bsd( TcpStreamTracker* talker, const TcpSegmentDescriptor& tsd, TcpStreamSession* session) { /* If its not a retransmission of the actual SYN... RESET */ - if (!SEQ_EQ(tsd.get_seg_seq(), talker->get_iss())) + if ( !SEQ_EQ(tsd.get_seg_seq(), talker->get_iss()) ) { session->flow->set_session_flags(SSNFLAG_RESET); talker->set_tcp_state(TcpStreamTracker::TCP_CLOSED); @@ -222,7 +222,7 @@ static inline bool paws_3whs_zero_ts_not_supported( { bool check_ts = true; - if (talker->get_tf_flags() & TF_TSTAMP_ZERO) + if ( talker->get_tf_flags() & TF_TSTAMP_ZERO ) { talker->clear_tf_flags(TF_TSTAMP); listener->clear_tf_flags(TF_TSTAMP); @@ -258,7 +258,7 @@ static inline uint16_t set_urg_offset_linux(const tcp::TCPHdr* tcph, uint16_t ds { uint16_t urg_offset = 0; - if (tcph->are_flags_set(TH_URG) ) + if ( tcph->are_flags_set(TH_URG) ) { urg_offset = tcph->urp(); @@ -369,8 +369,8 @@ bool TcpNormalizerHpux11::is_paws_ts_checked_required( TcpNormalizerState& tns, TcpSegmentDescriptor& tsd) { /* HPUX 11 ignores timestamps for out of order segments */ - if ((tns.tracker->get_tf_flags() & TF_MISSING_PKT) || !SEQ_EQ(tns.tracker->rcv_nxt, - tsd.get_seg_seq())) + if ( (tns.tracker->get_tf_flags() & TF_MISSING_PKT) || !SEQ_EQ(tns.tracker->rcv_nxt, + tsd.get_seg_seq()) ) return false; else return true; diff --git a/src/stream/tcp/tcp_reassembler.cc b/src/stream/tcp/tcp_reassembler.cc index ebaf44955..7b39d13fc 100644 --- a/src/stream/tcp/tcp_reassembler.cc +++ b/src/stream/tcp/tcp_reassembler.cc @@ -416,7 +416,6 @@ int TcpReassembler::flush_data_segments( { pdu->data = sb.data; pdu->dsize = sb.length; - assert(sb.length <= Packet::max_dsize); } total_flushed += bytes_copied; @@ -546,13 +545,12 @@ int TcpReassembler::_flush_to_seq( if ( footprint == 0 ) return bytes_processed; - if ( footprint > Packet::max_dsize ) - /* this is as much as we can pack into a stream buffer */ + 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 ) ) - fallback(trs); + fallback(*trs.tracker, trs.server_side); Packet* pdu = initialize_pdu(trs, p, pkt_flags, trs.sos.seglist.cur_rseg->tv); int32_t flushed_bytes = flush_data_segments(trs, p, footprint, pdu); @@ -942,16 +940,36 @@ int32_t TcpReassembler::flush_pdu_ips(TcpReassemblerState& trs, uint32_t* flags, return -1; } -void TcpReassembler::fallback(TcpReassemblerState& trs) +static inline bool both_splitters_aborted(Flow* flow) { - bool c2s = trs.tracker->splitter->to_server(); + uint32_t both_splitters_yoinked = (SSNFLAG_ABORT_CLIENT | SSNFLAG_ABORT_SERVER); + return (flow->get_session_flags() & both_splitters_yoinked) == both_splitters_yoinked; +} + +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; + ++tcpStats.partial_fallbacks; +} - delete trs.tracker->splitter; - trs.tracker->splitter = new AtomSplitter(c2s, trs.sos.session->config->paf_max); - trs.tracker->paf_state.paf = StreamSplitter::SEARCH; +void TcpReassembler::fallback(TcpStreamTracker& tracker, bool server_side) +{ + uint16_t max = tracker.session->config->paf_max; + ::fallback(tracker, server_side, max); - trs.sos.session->flow->set_session_flags( - c2s ? SSNFLAG_ABORT_CLIENT : SSNFLAG_ABORT_SERVER ); + Flow* flow = tracker.session->flow; + if ( server_side ) + flow->set_session_flags(SSNFLAG_ABORT_SERVER); + else + flow->set_session_flags(SSNFLAG_ABORT_CLIENT); + + if ( flow->gadget and both_splitters_aborted(flow) ) + { + flow->clear_gadget(); + ++tcpStats.inspector_fallbacks; + } } // iterate over trs.sos.seglist and scan all new acked bytes @@ -1067,7 +1085,7 @@ int TcpReassembler::flush_on_data_policy(TcpReassemblerState& trs, Packet* p) if ( !flags && trs.tracker->splitter->is_paf() ) { - fallback(trs); + fallback(*trs.tracker, trs.server_side); return flush_on_data_policy(trs, p); } } @@ -1111,9 +1129,12 @@ int TcpReassembler::flush_on_ack_policy(TcpReassemblerState& trs, Packet* p) while (flush_amt >= 0) { - if (!flush_amt) + 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); + // for consistency with other cases, should return total // but that breaks flushing pipelined pdus flushed = flush_to_seq(trs, flush_amt, p, flags); @@ -1129,9 +1150,10 @@ int TcpReassembler::flush_on_ack_policy(TcpReassemblerState& trs, Packet* p) break; // bail if nothing flushed } - if (!flags && trs.tracker->splitter->is_paf()) + if ( (trs.tracker->paf_state.paf == StreamSplitter::ABORT) && + (trs.tracker->splitter && trs.tracker->splitter->is_paf()) ) { - fallback(trs); + fallback(*trs.tracker, trs.server_side); return flush_on_ack_policy(trs, p); } } diff --git a/src/stream/tcp/tcp_reassembler.h b/src/stream/tcp/tcp_reassembler.h index 6bfc0e566..81ed91cf0 100644 --- a/src/stream/tcp/tcp_reassembler.h +++ b/src/stream/tcp/tcp_reassembler.h @@ -81,7 +81,7 @@ protected: uint32_t get_reverse_packet_dir(TcpReassemblerState&, const snort::Packet*); uint32_t get_forward_packet_dir(TcpReassemblerState&, const snort::Packet*); int32_t flush_pdu_ips(TcpReassemblerState&, uint32_t*, snort::Packet*); - void fallback(TcpReassemblerState&); + void fallback(TcpStreamTracker&, bool server_side); int32_t flush_pdu_ackd(TcpReassemblerState&, uint32_t* flags, snort::Packet*); void purge_to_seq(TcpReassemblerState&, uint32_t flush_seq); diff --git a/src/stream/tcp/tcp_segment_node.cc b/src/stream/tcp/tcp_segment_node.cc index 13eaa1d44..35c75acb8 100644 --- a/src/stream/tcp/tcp_segment_node.cc +++ b/src/stream/tcp/tcp_segment_node.cc @@ -140,11 +140,9 @@ bool TcpSegmentNode::is_retransmit(const uint8_t* rdata, uint16_t rsize, if ( orig_dsize == c_len ) { - if ( ( ( c_len <= rsize )and !memcmp(data, rdata, c_len) ) - or ( ( c_len > rsize )and !memcmp(data, rdata, rsize) ) ) - { + uint16_t cmp_len = ( c_len <= rsize ) ? c_len : rsize; + if ( !memcmp(data, rdata, cmp_len) ) return true; - } } //Checking for a possible split of segment in which case //we compare complete data of the segment to find a retransmission diff --git a/src/stream/tcp/tcp_session.cc b/src/stream/tcp/tcp_session.cc index 62ca780dc..5d06521d0 100644 --- a/src/stream/tcp/tcp_session.cc +++ b/src/stream/tcp/tcp_session.cc @@ -498,7 +498,7 @@ void TcpSession::swap_trackers() } #endif -void TcpSession::NewTcpSessionOnSyn(TcpSegmentDescriptor& tsd) +void TcpSession::init_session_on_syn(TcpSegmentDescriptor& tsd) { server.init_on_syn_recv(tsd); client.init_on_syn_sent(tsd); @@ -506,7 +506,7 @@ void TcpSession::NewTcpSessionOnSyn(TcpSegmentDescriptor& tsd) tcpStats.sessions_on_syn++; } -void TcpSession::NewTcpSessionOnSynAck(TcpSegmentDescriptor& tsd) +void TcpSession::init_session_on_synack(TcpSegmentDescriptor& tsd) { server.init_on_synack_sent(tsd); client.init_on_synack_recv(tsd); @@ -552,26 +552,26 @@ bool TcpSession::handle_syn_on_reset_session(TcpSegmentDescriptor& tsd) pkt_action_mask |= ACTION_RST; return false; } - else if (tcph->is_syn_only()) + else if ( tcph->is_syn_only() ) { flow->ssn_state.direction = FROM_CLIENT; flow->session_state = STREAM_STATE_SYN; flow->set_ttl(tsd.get_pkt(), true); - NewTcpSessionOnSyn(tsd); + init_session_on_syn(tsd); tcpStats.resyns++; listener = &server; talker = &client; listener->normalizer.ecn_tracker(tcph, config->require_3whs()); flow->update_session_flags(SSNFLAG_SEEN_CLIENT); } - else if (tcph->is_syn_ack()) + else if ( tcph->is_syn_ack() ) { if (config->midstream_allowed(tsd.get_pkt())) { flow->ssn_state.direction = FROM_SERVER; flow->session_state = STREAM_STATE_SYN_ACK; flow->set_ttl(tsd.get_pkt(), false); - NewTcpSessionOnSynAck(tsd); + init_session_on_synack(tsd); tcpStats.resyns++; } @@ -868,7 +868,7 @@ void TcpSession::flush_tracker( return; tracker.set_tf_flags(TF_FORCE_FLUSH); - if ( tracker.reassembler.flush_stream(p, dir) ) + if ( tracker.reassembler.flush_stream(p, dir, final_flush) ) tracker.reassembler.purge_flushed_ackd(); tracker.clear_tf_flags(TF_FORCE_FLUSH); diff --git a/src/stream/tcp/tcp_session.h b/src/stream/tcp/tcp_session.h index c23fd1f70..c8cd67cb8 100644 --- a/src/stream/tcp/tcp_session.h +++ b/src/stream/tcp/tcp_session.h @@ -76,9 +76,8 @@ private: void process_tcp_stream(TcpSegmentDescriptor&); int process_tcp_data(TcpSegmentDescriptor&); void swap_trackers(); - void NewTcpSessionOnSyn(TcpSegmentDescriptor&); - void NewTcpSessionOnSynAck(TcpSegmentDescriptor&); - int process_dis(snort::Packet*); + void init_session_on_syn(TcpSegmentDescriptor&); + void init_session_on_synack(TcpSegmentDescriptor&); void update_on_3whs_complete(TcpSegmentDescriptor&); bool is_flow_handling_packets(snort::Packet*); void cleanup_session_if_expired(snort::Packet*); diff --git a/src/stream/tcp/tcp_stream_session.cc b/src/stream/tcp/tcp_stream_session.cc index a5b2cbe81..db3ec77aa 100644 --- a/src/stream/tcp/tcp_stream_session.cc +++ b/src/stream/tcp/tcp_stream_session.cc @@ -109,7 +109,7 @@ void TcpStreamSession::update_session_on_server_packet(TcpSegmentDescriptor& tsd void TcpStreamSession::update_session_on_client_packet(TcpSegmentDescriptor& tsd) { - /* if we got here we had to see the SYN already... */ + /* if we got here we have seen the SYN already... */ flow->set_session_flags(SSNFLAG_SEEN_CLIENT); talker = &client; listener = &server;