From: George Koikara (gkoikara) Date: Thu, 8 Aug 2019 09:08:21 +0000 (-0400) Subject: Merge pull request #1639 in SNORT/snort3 from ~PSREENAT/snort3:cst to master X-Git-Tag: 3.0.0-259~12 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=74ac4fd973864c1b3a142001afca585f5db2a077;p=thirdparty%2Fsnort3.git Merge pull request #1639 in SNORT/snort3 from ~PSREENAT/snort3:cst to master Squashed commit of the following: commit d84f9984ea8e3c851e35d15a1a2e1523abca9da3 Author: Prajwal Srinivas Sreenath 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 --- diff --git a/src/flow/flow.h b/src/flow/flow.h index e7e301895..86a8765ca 100644 --- a/src/flow/flow.h +++ b/src/flow/flow.h @@ -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; diff --git a/src/flow/flow_cache.cc b/src/flow/flow_cache.cc index 80581a12e..817a2f87d 100644 --- a/src/flow/flow_cache.cc +++ b/src/flow/flow_cache.cc @@ -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 diff --git a/src/flow/test/CMakeLists.txt b/src/flow/test/CMakeLists.txt index e98030b44..7d0f20ffb 100644 --- a/src/flow/test/CMakeLists.txt +++ b/src/flow/test/CMakeLists.txt @@ -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 index 000000000..56104a933 --- /dev/null +++ b/src/flow/test/flow_test.cc @@ -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 +// 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 +#include + +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; +} + + diff --git a/src/stream/icmp/icmp_session.cc b/src/stream/icmp/icmp_session.cc index 7bc5b6a77..a1f2bc3b4 100644 --- a/src/stream/icmp/icmp_session.cc +++ b/src/stream/icmp/icmp_session.cc @@ -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) { diff --git a/src/stream/icmp/stream_icmp.cc b/src/stream/icmp/stream_icmp.cc index 9f5e7d7a8..00523075c 100644 --- a/src/stream/icmp/stream_icmp.cc +++ b/src/stream/icmp/stream_icmp.cc @@ -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 //------------------------------------------------------------------------- diff --git a/src/stream/icmp/stream_icmp.h b/src/stream/icmp/stream_icmp.h index 3ee5b24fa..61b3837e9 100644 --- a/src/stream/icmp/stream_icmp.h +++ b/src/stream/icmp/stream_icmp.h @@ -22,6 +22,11 @@ #include +namespace snort +{ +class Inspector; +} + struct StreamIcmpConfig { uint32_t session_timeout; @@ -29,5 +34,7 @@ struct StreamIcmpConfig StreamIcmpConfig(); }; +StreamIcmpConfig* get_icmp_cfg(snort::Inspector*); + #endif diff --git a/src/stream/ip/ip_session.cc b/src/stream/ip/ip_session.cc index ba267518c..06b50f25e 100644 --- a/src/stream/ip/ip_session.cc +++ b/src/stream/ip/ip_session.cc @@ -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; diff --git a/src/stream/libtcp/tcp_stream_session.cc b/src/stream/libtcp/tcp_stream_session.cc index e11ac3797..9da3ba3aa 100644 --- a/src/stream/libtcp/tcp_stream_session.cc +++ b/src/stream/libtcp/tcp_stream_session.cc @@ -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); diff --git a/src/stream/tcp/tcp_session.cc b/src/stream/tcp/tcp_session.cc index f4c3c9679..6be16a1d6 100644 --- a/src/stream/tcp/tcp_session.cc +++ b/src/stream/tcp/tcp_session.cc @@ -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); diff --git a/src/stream/udp/udp_session.cc b/src/stream/udp/udp_session.cc index daa35ff64..463f539a6 100644 --- a/src/stream/udp/udp_session.cc +++ b/src/stream/udp/udp_session.cc @@ -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; } diff --git a/src/stream/user/user_session.cc b/src/stream/user/user_session.cc index 82da5a5b0..ce58802bc 100644 --- a/src/stream/user/user_session.cc +++ b/src/stream/user/user_session.cc @@ -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;