]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
Merge pull request #1639 in SNORT/snort3 from ~PSREENAT/snort3:cst to master
authorGeorge Koikara (gkoikara) <gkoikara@cisco.com>
Thu, 8 Aug 2019 09:08:21 +0000 (05:08 -0400)
committerGeorge Koikara (gkoikara) <gkoikara@cisco.com>
Thu, 8 Aug 2019 09:08:21 +0000 (05:08 -0400)
Squashed commit of the following:

commit d84f9984ea8e3c851e35d15a1a2e1523abca9da3
Author: Prajwal Srinivas Sreenath <psreenat@cisco.com>
Date:   Mon Jun 3 12:54:48 2019 -0400

    flow: introduced variable for handling idle session timeouts and flag for actively pruning flows based on the expire_time
    stream: updated the protocol setup and process logic of TCP,UDP,IP,ICMP and USER sessions for setting and updating idle session timeouts

12 files changed:
src/flow/flow.h
src/flow/flow_cache.cc
src/flow/test/CMakeLists.txt
src/flow/test/flow_test.cc [new file with mode: 0644]
src/stream/icmp/icmp_session.cc
src/stream/icmp/stream_icmp.cc
src/stream/icmp/stream_icmp.h
src/stream/ip/ip_session.cc
src/stream/libtcp/tcp_stream_session.cc
src/stream/tcp/tcp_session.cc
src/stream/udp/udp_session.cc
src/stream/user/user_session.cc

index e7e3018952d802ff4cce5a54042e707b975b41e8..86a8765ca928b67e9929c3c7dab583560a3db6fe 100644 (file)
@@ -72,6 +72,8 @@
 #define SSNFLAG_ABORT_CLIENT        0x10000000
 #define SSNFLAG_ABORT_SERVER        0x20000000
 
+#define SSNFLAG_HARD_EXPIRATION     0x40000000
+
 #define SSNFLAG_NONE                0x00000000 /* nothing, an MT bag of chips */
 
 #define SSNFLAG_SEEN_BOTH (SSNFLAG_SEEN_SERVER | SSNFLAG_SEEN_CLIENT)
@@ -326,6 +328,18 @@ public:
     bool is_suspended() const
     { return context_chain.front(); }
 
+    void set_default_session_timeout(uint32_t dst, bool force)
+    { 
+        if (force || (default_session_timeout == 0))
+            default_session_timeout = dst; 
+    }
+
+    void set_hard_expiration()
+    { ssn_state.session_flags |= SSNFLAG_HARD_EXPIRATION; }
+
+    bool is_hard_expiration()
+    { return (ssn_state.session_flags & SSNFLAG_HARD_EXPIRATION) != 0; }
+
 public:  // FIXIT-M privatize if possible
     // fields are organized by initialization and size to minimize
     // void space and allow for memset of tail end of struct
@@ -369,6 +383,8 @@ public:  // FIXIT-M privatize if possible
     unsigned network_policy_id;
     unsigned reputation_id;
 
+    uint32_t default_session_timeout;
+
     uint16_t client_port;
     uint16_t server_port;
 
index 80581a12e2a5a6f59a00ba71f529dd0a1fad5cdb..817a2f87d6a9bf74e0ed95a5e34c99e904a1a3f0 100644 (file)
@@ -328,7 +328,12 @@ unsigned FlowCache::timeout(unsigned num_flows, time_t thetime)
 
     while ( flow and (retired < num_flows) )
     {
-        if ( flow->last_data_seen + config.proto[to_utype(flow->key->pkt_type)].nominal_timeout > thetime )
+        if ( flow->is_hard_expiration() )
+        {
+            if ( flow->expire_time > (uint64_t) thetime )
+                break;
+        }
+        else if ( flow->last_data_seen + config.proto[to_utype(flow->key->pkt_type)].nominal_timeout > thetime )
             break;
 
         if ( HighAvailabilityManager::in_standby(flow) or
index e98030b440cf54e2313a7477c333f9868ae464e8..7d0f20ffbc2f1e7ad856c89d429b70538dd16679 100644 (file)
@@ -9,3 +9,7 @@ add_cpputest( flow_control_test
 )
 
 add_cpputest( session_test )
+
+add_cpputest( flow_test
+    SOURCES ../flow.cc
+)
diff --git a/src/flow/test/flow_test.cc b/src/flow/test/flow_test.cc
new file mode 100644 (file)
index 0000000..56104a9
--- /dev/null
@@ -0,0 +1,124 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2019-2019 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation.  You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//--------------------------------------------------------------------------
+
+// flow_test.cc author Prajwal Srinivas <psreenat@cisco.com>
+// unit test main
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "protocols/ip.h"
+#include "protocols/layer.h"
+#include "protocols/packet.h"
+#include "flow/flow.h"
+#include "flow/flow_stash.h"
+#include "flow/ha.h"
+#include "main/snort_debug.h"
+#include "framework/inspector.h"
+#include "framework/data_bus.h"
+#include "memory/memory_cap.h"
+#include "detection/detection_engine.h"
+
+#include <CppUTest/CommandLineTestRunner.h>
+#include <CppUTest/TestHarness.h>
+
+using namespace snort;
+
+Packet::Packet(bool) { }
+Packet::~Packet() { }
+
+void Inspector::rem_ref() {}
+
+void Inspector::add_ref() {}
+
+void memory::MemoryCap::update_allocations(size_t n) {}
+
+void memory::MemoryCap::update_deallocations(size_t n) {}
+
+bool memory::MemoryCap::free_space(size_t n) { return false; }
+
+bool HighAvailabilityManager::active() { return false; }
+
+FlowHAState::FlowHAState() = default;
+
+void FlowHAState::reset() {}
+
+snort::FlowStash::~FlowStash() {}
+
+void FlowStash::reset() {}
+
+void DetectionEngine::onload(Flow* flow) {}
+
+Packet* DetectionEngine::set_next_packet(Packet* parent) { return nullptr; }
+
+IpsContext* DetectionEngine::get_context() { return nullptr; }
+
+DetectionEngine::DetectionEngine() = default;
+
+DetectionEngine::~DetectionEngine() {}
+
+bool snort::layer::set_outer_ip_api(const Packet* const p,
+    ip::IpApi& api,
+    int8_t& curr_layer)
+{ return false; }
+
+uint8_t ip::IpApi::ttl() const { return 0; }
+
+const Layer* snort::layer::get_mpls_layer(const Packet* const p) { return nullptr; }
+
+void snort::DataBus::publish(const char* key, Packet* p, Flow* f) {}
+
+TEST_GROUP(nondefault_timeout)
+{
+    void setup() override
+    {
+    }
+
+    void teardown() override
+    {
+    }
+};
+
+TEST(nondefault_timeout, hard_expiration)
+{
+    uint64_t validate = 100;
+    Packet pkt(false);
+    Flow *flow = new Flow();
+    DAQ_PktHdr_t pkthdr;
+
+    pkt.pkth = &pkthdr;
+    pkthdr.ts.tv_sec = 0;
+
+    flow->set_default_session_timeout(validate, true);
+    flow->set_hard_expiration();
+    flow->set_expire(&pkt, validate);
+    
+    CHECK( flow->is_hard_expiration() == true);
+    CHECK( flow->expire_time == validate );
+    
+    delete flow;
+}
+
+int main(int argc, char** argv)
+{
+    int return_value = CommandLineTestRunner::RunAllTests(argc, argv);
+    return return_value;
+}
+
+
index 7bc5b6a778dd82eeb7c8e49b95223fb1d773077f..a1f2bc3b4b00f9c9b84fc659457862203c32db7c 100644 (file)
@@ -190,6 +190,10 @@ bool IcmpSession::setup(Packet*)
     ssn_time.tv_usec = 0;
     flow->ssn_state.session_flags |= SSNFLAG_SEEN_SENDER;
     SESSION_STATS_ADD(icmpStats);
+    
+    StreamIcmpConfig* pc = get_icmp_cfg(flow->ssn_server);
+    flow->set_default_session_timeout(pc->session_timeout, false);
+
     return true;
 }
 
@@ -202,6 +206,8 @@ void IcmpSession::clear()
 int IcmpSession::process(Packet* p)
 {
     int status;
+    
+    flow->set_expire(p, flow->default_session_timeout);
 
     switch (p->ptrs.icmph->type)
     {
index 9f5e7d7a846c825583e5e5c28e56d1a1858f08c0..00523075c671937dd877ceb268ba2bcea0856e98 100644 (file)
@@ -59,7 +59,7 @@ public:
     void show(SnortConfig*) override;
     NORETURN_ASSERT void eval(Packet*) override;
 
-private:
+public:
     StreamIcmpConfig* config;
 };
 
@@ -84,6 +84,12 @@ NORETURN_ASSERT void StreamIcmp::eval(Packet*)
     assert(false);
 }
 
+StreamIcmpConfig* get_icmp_cfg(Inspector* ins)
+{
+    assert(ins);
+    return ((StreamIcmp*)ins)->config;
+}
+
 //-------------------------------------------------------------------------
 // api stuff
 //-------------------------------------------------------------------------
index 3ee5b24fa2b1f94704ac62067fa4c7ff4dd5321c..61b3837e9ce671ba3b1d646807014dcdd8fd8aeb 100644 (file)
 
 #include <cstdint>
 
+namespace snort
+{
+class Inspector;
+}
+
 struct StreamIcmpConfig
 {
     uint32_t session_timeout;
@@ -29,5 +34,7 @@ struct StreamIcmpConfig
     StreamIcmpConfig();
 };
 
+StreamIcmpConfig* get_icmp_cfg(snort::Inspector*);
+
 #endif
 
index ba267518c0a11d9df7799801088690880d41d781..06b50f25e3958bb759f78cc2c01cda0ffabd0b86 100644 (file)
@@ -111,8 +111,7 @@ static inline void update_session(Packet* p, Flow* lws)
     // Reset the session timeout.
     if ( lws->ssn_server )
     {
-        StreamIpConfig* pc = get_ip_cfg(lws->ssn_server);
-        lws->set_expire(p, pc->session_timeout);
+        lws->set_expire(p, lws->default_session_timeout);
     }
 }
 
@@ -144,6 +143,9 @@ bool IpSession::setup(Packet* p)
     SESSION_STATS_ADD(ip_stats);
     memset(&tracker, 0, sizeof(tracker));
 
+    StreamIpConfig* pc = get_ip_cfg(flow->ssn_server);
+    flow->set_default_session_timeout(pc->session_timeout, false);
+
     if ( p->ptrs.decode_flags & DECODE_FRAG )
     {
         ip_stats.trackers_created++;
@@ -261,6 +263,7 @@ TEST_CASE("IP Session", "[ip_session]")
     {
         StreamIpConfig* sic = new StreamIpConfig;
         sic->session_timeout = 360;
+        lws.set_default_session_timeout(sic->session_timeout, true);
         StreamIp si(sic);
         lws.ssn_server = &si;
 
index e11ac3797b0ea3df9aa0d3f2234101cc653dc6b0..9da3ba3aa1629ce7d780f366a66988868f1db987 100644 (file)
@@ -53,7 +53,8 @@ void TcpStreamSession::init_new_tcp_session(TcpSegmentDescriptor& tsd)
 
     /* New session, previous was marked as reset.  Clear the reset flag. */
     flow->clear_session_flags(SSNFLAG_RESET);
-    flow->set_expire(tsd.get_pkt(), config->session_timeout);
+
+    flow->set_expire(tsd.get_pkt(), flow->default_session_timeout); 
 
     update_perf_base_state(TcpStreamTracker::TCP_SYN_SENT);
 
index f4c3c9679cbb5625400f130b757e5cc76430da1c..6be16a1d6dfee901f09d9f703a3379679b4c01c2 100644 (file)
@@ -96,6 +96,9 @@ bool TcpSession::setup(Packet* p)
     TcpStreamSession::setup(p);
     splitter_init = false;
 
+    TcpStreamConfig* pc = get_tcp_cfg(flow->ssn_server);
+    flow->set_default_session_timeout(pc->session_timeout, false);
+
     SESSION_STATS_ADD(tcpStats);
     tcpStats.setups++;
     return true;
@@ -905,7 +908,8 @@ void TcpSession::do_packet_analysis_post_checks(Packet* p)
     if (!(pkt_action_mask & ACTION_LWSSN_CLOSED))
     {
         flow->markup_packet_flags(p);
-        flow->set_expire(p, config->session_timeout);
+
+        flow->set_expire(p, flow->default_session_timeout);
     }
     else
         TcpHAManager::process_deletion(*p->flow);
index daa35ff64e5a18a5a6dc027beda379f72f4f60e7..463f539a6fb1837b5ee83abacecd8112ffe3c705 100644 (file)
@@ -119,7 +119,7 @@ bool UdpSession::setup(Packet* p)
     flow->ssn_state.direction = FROM_CLIENT;
 
     StreamUdpConfig* pc = get_udp_cfg(flow->ssn_server);
-    flow->set_expire(p, pc->session_timeout);
+    flow->set_default_session_timeout(pc->session_timeout, false);
 
     SESSION_STATS_ADD(udpStats);
 
@@ -192,7 +192,8 @@ int UdpSession::process(Packet* p)
 
     ProcessUdp(flow, p, pc, nullptr);
     flow->markup_packet_flags(p);
-    flow->set_expire(p, pc->session_timeout);
+    
+    flow->set_expire(p, flow->default_session_timeout);
 
     return 0;
 }
index 82da5a5b08c14178540f7173b1cc8188256f2012..ce58802bc436f6229da229bc7d43540aea48b392 100644 (file)
@@ -405,8 +405,7 @@ void UserSession::update(Packet* p, Flow* flow)
         }
     }
 
-    StreamUserConfig* pc = get_user_cfg(flow->ssn_server);
-    flow->set_expire(p, pc->session_timeout);
+    flow->set_expire(p, flow->default_session_timeout);
 }
 
 void UserSession::restart(Packet* p)
@@ -441,6 +440,9 @@ bool UserSession::setup(Packet*)
     client.init();
     server.init();
 
+    StreamUserConfig* pc = get_user_cfg(flow->ssn_server);
+    flow->set_default_session_timeout(pc->session_timeout, false);
+
 #ifdef ENABLE_EXPECTED_USER
     if ( Stream::expected_flow(flow, p) )
         return false;