]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
Merge pull request #2595 in SNORT/snort3 from ~KDEWANGA/snort3:ftp_test to master
authorCynthia Leonard (cyleonar) <cyleonar@cisco.com>
Tue, 10 Nov 2020 06:31:07 +0000 (06:31 +0000)
committerCynthia Leonard (cyleonar) <cyleonar@cisco.com>
Tue, 10 Nov 2020 06:31:07 +0000 (06:31 +0000)
Squashed commit of the following:

commit 2cd7609ecc9008ca733be3cabb7ff3aacdb01fc1
Author: kdewanga <kdewanga@cisco.com>
Date:   Wed Nov 4 04:48:06 2020 -0500

    ftp: Handling FTP detection when ftp data segment size changes

src/service_inspectors/ftp_telnet/ftp_data.cc
src/service_inspectors/ftp_telnet/ftp_module.cc
src/service_inspectors/ftp_telnet/ftpdata_splitter.cc
src/service_inspectors/ftp_telnet/ftpp_si.h

index f00f84c9a8b710c0a8efc771c4c536a1cb09a46c..52bc27c30d0fc10eef9c4d2dba0dde36a2fddaa0 100644 (file)
@@ -30,6 +30,7 @@
 #include "packet_tracer/packet_tracer.h"
 #include "parser/parse_rule.h"
 #include "profiler/profiler.h"
+#include "protocols/tcp.h"
 #include "pub_sub/opportunistic_tls_event.h"
 #include "stream/stream.h"
 #include "utils/util.h"
@@ -238,16 +239,50 @@ void FtpDataFlowData::handle_expected(Packet* p)
     }
 }
 
+void FtpDataFlowData::handle_retransmit(Packet* p)
+{
+    FTP_DATA_SESSION* data_ssn = &session;
+
+    if ((data_ssn->eof_seq > 0) and (data_ssn->eof_seq == p->ptrs.tcph->seq() + p->dsize))
+    {
+        // only process the final data segment
+        initFilePosition(&data_ssn->position, get_file_processed_size(p->flow));
+        finalFilePosition(&data_ssn->position);
+
+        FileFlows* file_flows = FileFlows::get_file_flows(p->flow);
+        if (file_flows)
+        {
+            file_flows->file_process(DetectionEngine::get_current_packet(),
+                p->data, 0, SNORT_FILE_END, data_ssn->direction, data_ssn->path_hash);
+
+            eof_handled = true;
+        }
+    }
+}
+
 void FtpDataFlowData::handle_eof(Packet* p)
 {
     FTP_DATA_SESSION* data_ssn = &session;
+    data_ssn->eof_seq = 0;
 
     if (!PROTO_IS_FTP_DATA(data_ssn) || !FTPDataDirection(p, data_ssn))
         return;
 
-    initFilePosition(&data_ssn->position, get_file_processed_size(p->flow));
-    finalFilePosition(&data_ssn->position);
-    eof_handled = true;
+    if (p->dsize != 0)
+    {
+        initFilePosition(&data_ssn->position, get_file_processed_size(p->flow));
+        finalFilePosition(&data_ssn->position);
+        eof_handled = true;
+    }
+    else
+    {
+        Active* act = p->active;
+        act->set_delayed_action(Active::ACT_RETRY, true);
+        data_ssn->eof_seq = p->ptrs.tcph->seq();
+    }
+
+    if (data_ssn->mss_changed)
+        ftstats.total_sessions_mss_changed++;
 }
 
 //-------------------------------------------------------------------------
index 212a28fe1aaf6a9b25ed41a973ad5916145f0bc2..8688f14ec837b1a25fc07a24eeff61e4a0bba13f 100644 (file)
@@ -347,7 +347,8 @@ static const PegInfo ftp_pegs[] =
     { CountType::SUM, "start_tls", "total STARTTLS events generated" },
     { CountType::SUM, "ssl_search_abandoned", "total SSL search abandoned" },
     { CountType::SUM, "ssl_srch_abandoned_early", "total SSL search abandoned too soon" },
-
+    { CountType::SUM, "pkt_segment_size_changed", "total number of FTP data packets with segment size change" },
+    { CountType::SUM, "flow_segment_size_changed", "total number of FTP sessions with segment size change" },
     { CountType::END, nullptr, nullptr }
 };
 
index 07e9c4e2beeb39773cb08a9fd0be2bfafb467d19..8414d8fb42be37a3f94a40a100cc76c2acbe8bc0 100644 (file)
@@ -26,6 +26,8 @@
 #include "detection/detection_engine.h"
 #include "file_api/file_flows.h"
 #include "flow/session.h"
+#include "packet_io/active.h"
+#include "protocols/tcp.h"
 #include "stream/stream.h"
 
 #include "ftpp_si.h"
@@ -49,7 +51,10 @@ StreamSplitter::Status FtpDataSplitter::scan(Packet* pkt, const uint8_t*, uint32
 {
     Flow* flow = pkt->flow;
     assert(flow);
+    FtpDataFlowData* fdfd = (FtpDataFlowData*)flow->get_flow_data(FtpDataFlowData::inspector_id);
 
+    if (!fdfd)
+        return SEARCH;
     if ( len )
     {
         if(expected_seg_size == 0)
@@ -70,11 +75,24 @@ StreamSplitter::Status FtpDataSplitter::scan(Packet* pkt, const uint8_t*, uint32
 
         if ( len != expected_seg_size )
         {
-            // Treat this as the last packet of the FTP data transfer.
-            set_ftp_flush_flag(flow);
+            ftstats.total_packets_mss_changed++;
+            fdfd->session.mss_changed = true;
+            if (fdfd->session.bytes_seen == 0)
+            {
+                // Segmented pkt is  smaller than expected_seg_size
+                set_ftp_flush_flag(flow);
+            }
+            else if (pkt->ptrs.tcph and !pkt->ptrs.tcph->is_fin())
+            {
+                Active* act = pkt->active;
+                // add packet to retry queue to consider this is not end of ftp flow
+                if (!(pkt->flow->flags.trigger_detained_packet_event))
+                    act->set_delayed_action(Active::ACT_RETRY, true);
+            }
             expected_seg_size = len;
             restart_scan();
             *fp = len;
+               fdfd->session.bytes_seen += len;
             return FLUSH;
         }
         else
@@ -82,9 +100,11 @@ StreamSplitter::Status FtpDataSplitter::scan(Packet* pkt, const uint8_t*, uint32
             segs++;
             bytes += len;
         }
+        fdfd->session.bytes_seen += len;
 
-        if ( segs >= 2 && bytes >= min )
+        if ((segs >= 2 and bytes >= min) or (pkt->ptrs.tcph and pkt->ptrs.tcph->is_fin()))
         {
+            // Either FIN or smaller size do FLUSH to continue inspection
             restart_scan();
             *fp = len;
             return FLUSH;
index 0feeebaa70ae63b3d577894b59e33070cc0bef7a..ac1d77831e6a5704a7c58a4f4f67347792fc36b8 100644 (file)
@@ -212,13 +212,16 @@ struct FTP_DATA_SESSION
     FTP_TELNET_SESSION ft_ssn;
     snort::FlowKey ftp_key;
     char* filename;
+    uint32_t eof_seq;
     size_t path_hash;
     int data_chan;
     int file_xfer_info;
     FilePosition position;
-    bool direction;
+    uint32_t bytes_seen;
     unsigned char mode;
     unsigned char packet_flags;
+    bool direction;
+    bool mss_changed;
 };
 
 class FtpDataFlowData : public snort::FlowData
@@ -232,7 +235,7 @@ public:
 
     void handle_expected(snort::Packet*) override;
     void handle_eof(snort::Packet*) override;
-
+    void handle_retransmit(snort::Packet*) override;
     size_t size_of() override
     { return sizeof(*this); }
 
@@ -293,6 +296,8 @@ struct FtpStats
     PegCount starttls;
     PegCount ssl_search_abandoned;
     PegCount ssl_search_abandoned_too_soon;
+    PegCount total_packets_mss_changed;
+    PegCount total_sessions_mss_changed;
 };
 
 struct TelnetStats