From: Mike Stepanek (mstepane) Date: Tue, 12 Mar 2019 16:37:43 +0000 (-0400) Subject: Merge pull request #1541 in SNORT/snort3 from ~SHRARANG/snort3:session_stash to master X-Git-Tag: 3.0.0-251~24 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=1c8b56aceb18f105f72acfd35f73fee2032f0ae1;p=thirdparty%2Fsnort3.git Merge pull request #1541 in SNORT/snort3 from ~SHRARANG/snort3:session_stash to master Squashed commit of the following: commit 2d5082c967e200a4e0199e40813d5a4a1844438a Author: Shravan Rangaraju Date: Mon Mar 11 11:11:21 2019 -0400 flow: support for flow stash - allows storage of integers and strings --- diff --git a/src/flow/CMakeLists.txt b/src/flow/CMakeLists.txt index 6397f883d..f567ae580 100644 --- a/src/flow/CMakeLists.txt +++ b/src/flow/CMakeLists.txt @@ -2,6 +2,8 @@ set (FLOW_INCLUDES expect_cache.h flow.h flow_key.h + flow_stash.h + stash_item.h ) add_library (flow OBJECT @@ -14,12 +16,15 @@ add_library (flow OBJECT flow_control.cc flow_control.h flow_key.cc + flow_stash.h + flow_stash.cc ha.cc ha.h ha_module.cc ha_module.h prune_stats.h session.h + stash_item.h ) install(FILES ${FLOW_INCLUDES} diff --git a/src/flow/flow.cc b/src/flow/flow.cc index 1b28fd04a..54854ebd1 100644 --- a/src/flow/flow.cc +++ b/src/flow/flow.cc @@ -92,6 +92,8 @@ void Flow::init(PktType type) } mpls_client.length = 0; mpls_server.length = 0; + + stash = new FlowStash; } void Flow::term() @@ -127,6 +129,9 @@ void Flow::term() if ( ha_state ) delete ha_state; + + if (stash) + delete stash; } inline void Flow::clean() @@ -189,6 +194,9 @@ void Flow::reset(bool do_cleanup) if ( ha_state ) ha_state->reset(); + if ( stash ) + stash->reset(); + constexpr size_t offset = offsetof(Flow, flow_data); // FIXIT-L need a struct to zero here to make future proof memset((uint8_t*)this+offset, 0, sizeof(Flow)-offset); diff --git a/src/flow/flow.h b/src/flow/flow.h index 5e28e1f3d..9d378bb38 100644 --- a/src/flow/flow.h +++ b/src/flow/flow.h @@ -34,6 +34,7 @@ #include "protocols/layer.h" #include "sfip/sf_ip.h" #include "target_based/snort_protocols.h" +#include "flow_stash.h" #define SSNFLAG_SEEN_CLIENT 0x00000001 #define SSNFLAG_SEEN_SENDER 0x00000001 @@ -188,6 +189,31 @@ public: void set_mpls_layer_per_dir(Packet*); Layer get_mpls_layer_per_dir(bool); void set_service(Packet* pkt, const char* new_service); + bool get_attr(const std::string& key, int32_t& val); + bool get_attr(const std::string& key, std::string& val); + void set_attr(const std::string& key, const int32_t& val); + void set_attr(const std::string& key, const std::string& val); + // Use this API when the publisher of the attribute allocated memory for it and can give up its + // ownership after the call. + void set_attr(const std::string& key, std::string* val) + { + assert(stash); + stash->store(key, val); + } + + template + bool get_attr(const std::string& key, T& val) + { + assert(stash); + return stash->get(key, val); + } + + template + void set_attr(const std::string& key, const T& val) + { + assert(stash); + stash->store(key, val); + } uint32_t update_session_flags(uint32_t flags) { return ssn_state.session_flags = flags; } @@ -307,6 +333,7 @@ public: // FIXIT-M privatize if possible Session* session; BitOp* bitop; FlowHAState* ha_state; + FlowStash* stash; uint8_t ip_proto; PktType pkt_type; // ^^ diff --git a/src/flow/flow_stash.cc b/src/flow/flow_stash.cc new file mode 100644 index 000000000..59c033eaa --- /dev/null +++ b/src/flow/flow_stash.cc @@ -0,0 +1,107 @@ +//-------------------------------------------------------------------------- +// 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_stash.cc author Shravan Rangaraju + +#include "flow_stash.h" + +#include + +using namespace snort; +using namespace std; + +FlowStash::~FlowStash() +{ + reset(); +} + +void FlowStash::reset() +{ + for(map::iterator it = container.begin(); it != container.end(); ++it) + { + delete it->second; + } + container.clear(); +} + +bool FlowStash::get(const string& key, int32_t& val) +{ + return get(key, val, STASH_ITEM_TYPE_INT32); +} + +bool FlowStash::get(const string& key, string& val) +{ + return get(key, val, STASH_ITEM_TYPE_STRING); +} + +void FlowStash::store(const string& key, int32_t val) +{ + store(key, val, STASH_ITEM_TYPE_INT32); +} + +void FlowStash::store(const string& key, const string& val) +{ + store(key, val, STASH_ITEM_TYPE_STRING); +} + +void FlowStash::store(const std::string& key, std::string* val) +{ + auto item = new StashItem(val); + auto it_and_status = container.emplace(make_pair(key, item)); + + if (!it_and_status.second) + { + assert(it_and_status.first->second->get_type() == STASH_ITEM_TYPE_STRING); + delete it_and_status.first->second; + it_and_status.first->second = item; + } +} + +template +bool FlowStash::get(const string& key, T& val, StashItemType type) +{ +#ifdef NDEBUG + UNUSED(type); +#endif + auto it = container.find(key); + + if (it != container.end()) + { + assert(it->second->get_type() == type); + it->second->get_val(val); + return true; + } + return false; +} + +template +void FlowStash::store(const string& key, T& val, StashItemType type) +{ +#ifdef NDEBUG + UNUSED(type); +#endif + auto item = new StashItem(val); + auto it_and_status = container.emplace(make_pair(key, item)); + + if (!it_and_status.second) + { + assert(it_and_status.first->second->get_type() == type); + delete it_and_status.first->second; + it_and_status.first->second = item; + } +} diff --git a/src/flow/flow_stash.h b/src/flow/flow_stash.h new file mode 100644 index 000000000..2373aa2aa --- /dev/null +++ b/src/flow/flow_stash.h @@ -0,0 +1,54 @@ +//-------------------------------------------------------------------------- +// 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_stash.h author Shravan Rangaraju + +#ifndef FLOW_STASH_H +#define FLOW_STASH_H + +#include +#include + +#include "main/snort_types.h" + +#include "stash_item.h" + +namespace snort { + +class FlowStash { +public: + ~FlowStash(); + void reset(); + bool get(const std::string& key, int32_t& val); + bool get(const std::string& key, std::string& val); + void store(const std::string& key, int32_t val); + void store(const std::string& key, const std::string& val); + void store(const std::string& key, std::string* val); + +private: + std::map container; + + template + bool get(const std::string& key, T& val, StashItemType type); + template + void store(const std::string& key, T& val, StashItemType type); +}; + +} + +#endif diff --git a/src/flow/stash_item.h b/src/flow/stash_item.h new file mode 100644 index 000000000..a1ec98a84 --- /dev/null +++ b/src/flow/stash_item.h @@ -0,0 +1,87 @@ +//-------------------------------------------------------------------------- +// 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. +//-------------------------------------------------------------------------- + +// stash_item.h author Shravan Rangaraju + +#ifndef STASH_ITEM_H +#define STASH_ITEM_H + +#include +#include + +namespace snort { + +enum StashItemType { + STASH_ITEM_TYPE_INT32, + STASH_ITEM_TYPE_STRING +}; + +union StashItemVal { + int32_t int32_val; + std::string* str_val; +}; + +class StashItem { +private: + StashItemType type; + StashItemVal val; + +public: + StashItem(int32_t int32_val) + { + type = STASH_ITEM_TYPE_INT32; + val.int32_val = int32_val; + } + + StashItem(const std::string& str_val) + { + type = STASH_ITEM_TYPE_STRING; + val.str_val = new std::string(str_val); + } + + StashItem(std::string* str_val) + { + type = STASH_ITEM_TYPE_STRING; + val.str_val = str_val; + } + + ~StashItem() + { + switch (type) + { + case STASH_ITEM_TYPE_STRING: + delete val.str_val; + break; + default: + break; + } + } + + StashItemType get_type() const + { return type; } + + void get_val(int32_t& int32_val) const + { int32_val = val.int32_val; } + + void get_val(std::string& str_val) const + { str_val = *(val.str_val); } +}; + +} + +#endif diff --git a/src/flow/test/CMakeLists.txt b/src/flow/test/CMakeLists.txt index 05bb4b4f2..a94b730cc 100644 --- a/src/flow/test/CMakeLists.txt +++ b/src/flow/test/CMakeLists.txt @@ -10,3 +10,7 @@ add_cpputest( ha_module_test ../../sfip/sf_ip.cc $ ) + +add_cpputest( flow_stash_test + SOURCES ../flow_stash.cc +) diff --git a/src/flow/test/flow_stash_test.cc b/src/flow/test/flow_stash_test.cc new file mode 100644 index 000000000..a9537fb07 --- /dev/null +++ b/src/flow/test/flow_stash_test.cc @@ -0,0 +1,137 @@ +//-------------------------------------------------------------------------- +// 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_stash_test.cc author Shravan Rangaraju + +#include + +#include "flow/flow_stash.h" + +#include +#include + +using namespace snort; +using namespace std; + +TEST_GROUP(stash_tests) +{ + void setup() + { + } + + void teardown() + { + } +}; + +TEST(stash_tests, new_int32_item) +{ + FlowStash stash; + + stash.store("item_1", 10); + + int32_t val; + + CHECK(stash.get("item_1", val)); + CHECK_EQUAL(val, 10); +} + +TEST(stash_tests, update_int32_item) +{ + FlowStash stash; + + stash.store("item_1", 10); + stash.store("item_1", 20); + + int32_t val; + + CHECK(stash.get("item_1", val)); + CHECK_EQUAL(val, 20); +} + +TEST(stash_tests, new_str_item_ref) +{ + FlowStash stash; + + stash.store("item_1", "value_1"); + + string val; + + CHECK(stash.get("item_1", val)); + STRCMP_EQUAL(val.c_str(), "value_1"); +} + +TEST(stash_tests, new_str_item_ptr) +{ + FlowStash stash; + + stash.store("item_1", new string("value_1")); + + string val; + + CHECK(stash.get("item_1", val)); + STRCMP_EQUAL(val.c_str(), "value_1"); +} + +TEST(stash_tests, update_str_item) +{ + FlowStash stash; + + stash.store("item_1", "value_1"); + stash.store("item_1", new string("value_2")); + + string val; + + CHECK(stash.get("item_1", val)); + STRCMP_EQUAL(val.c_str(), "value_2"); +} + +TEST(stash_tests, non_existent_item) +{ + FlowStash stash; + + stash.store("item_1", 10); + + int32_t val; + + CHECK_FALSE(stash.get("item_2", val)); +} + +TEST(stash_tests, mixed_items) +{ + FlowStash stash; + + stash.store("item_1", 10); + stash.store("item_2", "value_2"); + stash.store("item_3", 30); + + int32_t int32_val; + string str_val; + + CHECK(stash.get("item_1", int32_val)); + CHECK_EQUAL(int32_val, 10); + CHECK(stash.get("item_2", str_val)); + STRCMP_EQUAL(str_val.c_str(), "value_2"); + CHECK(stash.get("item_3", int32_val)); + CHECK_EQUAL(int32_val, 30); +} + +int main(int argc, char** argv) +{ + return CommandLineTestRunner::RunAllTests(argc, argv); +} diff --git a/src/flow/test/ha_test.cc b/src/flow/test/ha_test.cc index dc208edbc..44ea78ab0 100644 --- a/src/flow/test/ha_test.cc +++ b/src/flow/test/ha_test.cc @@ -163,6 +163,8 @@ void packet_gettimeofday(struct timeval* tv) Flow::Flow() { ha_state = new FlowHAState; key = new FlowKey; } +FlowStash::~FlowStash() { } + SideChannel* SideChannelManager::get_side_channel(SCPort) { return &s_side_channel; } diff --git a/src/network_inspectors/appid/test/appid_mock_flow.h b/src/network_inspectors/appid/test/appid_mock_flow.h index 1d0148a06..6004686f8 100644 --- a/src/network_inspectors/appid/test/appid_mock_flow.h +++ b/src/network_inspectors/appid/test/appid_mock_flow.h @@ -50,5 +50,7 @@ int Flow::set_flow_data(FlowData* fd) return 0; } +FlowStash::~FlowStash() { } + #endif