From: Mike Stepanek (mstepane) Date: Mon, 1 Jul 2019 14:15:54 +0000 (-0400) Subject: Merge pull request #1593 in SNORT/snort3 from ~DERAMADA/snort3:appid_stash_store... X-Git-Tag: 3.0.0-258~14 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=1880af5f2b31ed968fc4a790384720d560acec1c;p=thirdparty%2Fsnort3.git Merge pull request #1593 in SNORT/snort3 from ~DERAMADA/snort3:appid_stash_store to master Squashed commit of the following: commit 51382ddd1e26171b1a1ca0973ff950d1e073aa5c Author: deramada Date: Mon Apr 29 15:49:05 2019 -0400 appid: use stash to store flow attributes --- diff --git a/src/flow/CMakeLists.txt b/src/flow/CMakeLists.txt index f84e14131..09dcbf5bb 100644 --- a/src/flow/CMakeLists.txt +++ b/src/flow/CMakeLists.txt @@ -4,6 +4,7 @@ set (FLOW_INCLUDES flow_key.h flow_stash.h ha.h + flow_stash_keys.h stash_item.h ) diff --git a/src/flow/flow.cc b/src/flow/flow.cc index db315555e..f7cf144ee 100644 --- a/src/flow/flow.cc +++ b/src/flow/flow.cc @@ -215,8 +215,13 @@ void Flow::restart(bool dump_flow_data) DetectionEngine::onload(this); if ( dump_flow_data ) + { free_flow_data(); + if ( stash ) + stash->reset(); + } + clean(); ssn_state.ignore_direction = 0; diff --git a/src/flow/flow.h b/src/flow/flow.h index e7e301895..813c32b43 100644 --- a/src/flow/flow.h +++ b/src/flow/flow.h @@ -191,32 +191,41 @@ 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) + void set_attr(const int& key, std::string* val) { assert(stash); stash->store(key, val); } + bool get_attr(const int& key, std::string*& val) + { + assert(stash); + return stash->get(key, val); + } + template - bool get_attr(const std::string& key, T& val) + bool get_attr(const int& key, T& val) { assert(stash); return stash->get(key, val); } template - void set_attr(const std::string& key, const T& val) + void set_attr(const int& key, const T& val) { assert(stash); stash->store(key, val); } + void remove_attr(const FlowStashKey& key) + { + assert(stash); + stash->remove(key); + } + uint32_t update_session_flags(uint32_t flags) { return ssn_state.session_flags = flags; } diff --git a/src/flow/flow_stash.cc b/src/flow/flow_stash.cc index 13a2f3156..c1c11c699 100644 --- a/src/flow/flow_stash.cc +++ b/src/flow/flow_stash.cc @@ -38,113 +38,131 @@ FlowStash::~FlowStash() void FlowStash::reset() { - for(map::iterator it = container.begin(); it != container.end(); ++it) + for (auto& it : container) { - delete it->second; + if (it) + { + delete it; + it = nullptr; + } } - container.clear(); } -bool FlowStash::get(const string& key, int32_t& val) +void FlowStash::remove(const FlowStashKey& key) +{ + auto& item = container[key]; + + if (item) + { + delete item; + item = nullptr; + } +} + +bool FlowStash::get(const int& key, int32_t& val) { return get(key, val, STASH_ITEM_TYPE_INT32); } -bool FlowStash::get(const string& key, uint32_t& val) +bool FlowStash::get(const int& key, uint32_t& val) { return get(key, val, STASH_ITEM_TYPE_UINT32); } -bool FlowStash::get(const string& key, string& val) +bool FlowStash::get(const int& key, string& val) { return get(key, val, STASH_ITEM_TYPE_STRING); } -bool FlowStash::get(const std::string& key, StashGenericObject* &val) +bool FlowStash::get(const int& key, string*& val) +{ + auto& it = container[key]; + + if (it) + { + assert(it->get_type() == STASH_ITEM_TYPE_STRING); + it->get_val(val); + return true; + } + return false; +} + +bool FlowStash::get(const int& key, StashGenericObject* &val) { return get(key, val, STASH_ITEM_TYPE_GENERIC_OBJECT); } -void FlowStash::store(const string& key, int32_t val) +void FlowStash::store(const int& key, int32_t val) { store(key, val, STASH_ITEM_TYPE_INT32); } -void FlowStash::store(const string& key, uint32_t val) +void FlowStash::store(const int& key, uint32_t val) { store(key, val, STASH_ITEM_TYPE_UINT32); } -void FlowStash::store(const string& key, const string& val) +void FlowStash::store(const int& key, const string& val) { store(key, val, STASH_ITEM_TYPE_STRING); } -void FlowStash::store(const std::string& key, StashGenericObject* val) +void FlowStash::store(const int& key, StashGenericObject* val) { store(key, val, STASH_ITEM_TYPE_GENERIC_OBJECT); } -void FlowStash::store(const string& key, StashGenericObject* &val, StashItemType type) +void FlowStash::store(const int& key, StashGenericObject* &val, StashItemType type) { #ifdef NDEBUG UNUSED(type); #endif - auto item = new StashItem(val); - auto it_and_status = container.emplace(make_pair(key, item)); + auto& it = container[key]; + if (it) + delete it; - if (!it_and_status.second) - { - StashGenericObject* stored_object; - assert(it_and_status.first->second->get_type() == type); - it_and_status.first->second->get_val(stored_object); - assert(stored_object->get_object_type() == val->get_object_type()); - delete it_and_status.first->second; - it_and_status.first->second = item; - } + it = new StashItem(val); + assert(it->get_type() == type); - StashEvent e(item); - DataBus::publish(key.c_str(), e); + StashEvent e(it); + DataBus::publish(get_key_name(key), e); } -void FlowStash::store(const std::string& key, std::string* val) +void FlowStash::store(const int& key, std::string* val) { store(key, val, STASH_ITEM_TYPE_STRING); } template -bool FlowStash::get(const string& key, T& val, StashItemType type) +bool FlowStash::get(const int& key, T& val, StashItemType type) { #ifdef NDEBUG UNUSED(type); #endif - auto it = container.find(key); + auto& it = container[key]; - if (it != container.end()) + if (it) { - assert(it->second->get_type() == type); - it->second->get_val(val); + assert(it->get_type() == type); + it->get_val(val); return true; } return false; } template -void FlowStash::store(const string& key, T& val, StashItemType type) +void FlowStash::store(const int& 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)); + auto& it = container[key]; + if (it) + delete it; - 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; - } + it = new StashItem(val); + assert(it->get_type() == type); - StashEvent e(item); - DataBus::publish(key.c_str(), e); + StashEvent e(it); + DataBus::publish(get_key_name(key), e); } diff --git a/src/flow/flow_stash.h b/src/flow/flow_stash.h index a422555e3..8794f1240 100644 --- a/src/flow/flow_stash.h +++ b/src/flow/flow_stash.h @@ -21,11 +21,12 @@ #ifndef FLOW_STASH_H #define FLOW_STASH_H -#include #include +#include #include "main/snort_types.h" +#include "flow_stash_keys.h" #include "stash_item.h" namespace snort @@ -34,26 +35,29 @@ namespace snort class SO_PUBLIC FlowStash { public: + FlowStash() : container(STASH_MAX_SIZE, nullptr) { } ~FlowStash(); void reset(); - bool get(const std::string& key, int32_t& val); - bool get(const std::string& key, uint32_t& val); - bool get(const std::string& key, std::string& val); - bool get(const std::string& key, StashGenericObject* &val); - void store(const std::string& key, int32_t val); - void store(const std::string& key, uint32_t val); - void store(const std::string& key, const std::string& val); - void store(const std::string& key, std::string* val); - void store(const std::string& key, StashGenericObject* val); + bool get(const int& key, int32_t& val); + bool get(const int& key, uint32_t& val); + bool get(const int& key, std::string& val); + bool get(const int& key, std::string*& val); + bool get(const int& key, StashGenericObject* &val); + void store(const int& key, int32_t val); + void store(const int& key, uint32_t val); + void store(const int& key, const std::string& val); + void store(const int& key, std::string* val); + void store(const int& key, StashGenericObject* val); + void remove(const FlowStashKey& key); private: - std::map container; + std::vector container; template - bool get(const std::string& key, T& val, StashItemType type); + bool get(const int& key, T& val, StashItemType type); template - void store(const std::string& key, T& val, StashItemType type); - void store(const std::string& key, StashGenericObject* &val, StashItemType type); + void store(const int& key, T& val, StashItemType type); + void store(const int& key, StashGenericObject* &val, StashItemType type); }; } diff --git a/src/flow/flow_stash_keys.h b/src/flow/flow_stash_keys.h new file mode 100644 index 000000000..39057eb7e --- /dev/null +++ b/src/flow/flow_stash_keys.h @@ -0,0 +1,69 @@ +//-------------------------------------------------------------------------- +// 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_keys.h author Deepak Ramadass + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifndef FLOW_STASH_KEYS_H +#define FLOW_STASH_KEYS_H + +enum FlowStashKey +{ + STASH_APPID_SERVICE = 0, + STASH_APPID_CLIENT, + STASH_APPID_PAYLOAD, + STASH_APPID_MISC, + STASH_APPID_REFERRED, + + STASH_HOST, + STASH_TLS_HOST, + STASH_URL, + STASH_USER_AGENT, + STASH_RESPONSE_CODE, + STASH_REFERER, + STASH_XFF, + STASH_CLIENT_VERSION, + + STASH_MAX_SIZE +}; + +static const char* FlowStashKeyNames[] = +{ + "appid-service", + "appid-client", + "appid-payload", + "appid-misc", + "appid-referred", + "host", + "tls-host", + "url", + "user-agent", + "response-code", + "referer", + "xff", + "client-version" +}; + +inline const char * get_key_name( int key ) +{ + return FlowStashKeyNames[key]; +} +#endif diff --git a/src/flow/stash_item.h b/src/flow/stash_item.h index 63daf304c..cbbbe7e35 100644 --- a/src/flow/stash_item.h +++ b/src/flow/stash_item.h @@ -101,6 +101,7 @@ public: break; case STASH_ITEM_TYPE_GENERIC_OBJECT: delete val.generic_obj_val; + break; default: break; } @@ -118,6 +119,9 @@ public: void get_val(std::string& str_val) const { str_val = *(val.str_val); } + void get_val(std::string*& str_val) const + { str_val = val.str_val; } + void get_val(StashGenericObject* &obj_val) const { obj_val = val.generic_obj_val; } diff --git a/src/flow/test/flow_stash_test.cc b/src/flow/test/flow_stash_test.cc index ffd1200e4..311bb19cf 100644 --- a/src/flow/test/flow_stash_test.cc +++ b/src/flow/test/flow_stash_test.cc @@ -47,8 +47,6 @@ class DBConsumer : public DataHandler { public: - static const char* STASH_EVENT; - // event we'll be listening to on the DataBus: // static constexpr char STASH_EVENT[] = "foo.stash.event"; @@ -62,7 +60,7 @@ public: Type get_from_stash(FlowStash& stash) { - stash.get(STASH_EVENT, value); + stash.get(STASH_APPID_SERVICE, value); return value; } @@ -72,10 +70,6 @@ private: Type value; }; -template -const char* DBConsumer::STASH_EVENT = "foo.stash.event"; - - // DataBus mock: most functions are stubs, but _subscribe() and _publish() // are (close to) real. @@ -152,27 +146,27 @@ TEST(stash_tests, data_bus_publish_test) typedef int32_t value_t; // DB deletes the subscribers so make c a pointer, not a local object. - DBConsumer* c = new DBConsumer("foo"); - DataBus::subscribe(DBConsumer::STASH_EVENT, c); + DBConsumer* c = new DBConsumer("appid-service"); + DataBus::subscribe("appid-service", c); FlowStash stash; value_t vin, vout; // stash/publish 10 vin = 10; - stash.store(DBConsumer::STASH_EVENT, vin); + stash.store(STASH_APPID_SERVICE, vin); vout = c->get_value(); CHECK_EQUAL(vin, vout); // stash/publish 20, with the same key as before vin = 20; - stash.store(DBConsumer::STASH_EVENT, vin); + stash.store(STASH_APPID_SERVICE, vin); vout = c->get_value(); CHECK_EQUAL(vin, vout); // do we get some event that we're not listening to? value_t before = c->get_value(); - stash.store("bar.stash.event", 30); + stash.store(STASH_APPID_CLIENT, 30); value_t after = c->get_value(); CHECK_EQUAL(before, after); @@ -188,11 +182,11 @@ TEST(stash_tests, new_int32_item) { FlowStash stash; - stash.store("item_1", 10); + stash.store(STASH_APPID_SERVICE, 10); int32_t val; - CHECK(stash.get("item_1", val)); + CHECK(stash.get(STASH_APPID_SERVICE, val)); CHECK_EQUAL(val, 10); } @@ -200,12 +194,12 @@ TEST(stash_tests, update_int32_item) { FlowStash stash; - stash.store("item_1", 10); - stash.store("item_1", 20); + stash.store(STASH_APPID_SERVICE, 10); + stash.store(STASH_APPID_SERVICE, 20); int32_t val; - CHECK(stash.get("item_1", val)); + CHECK(stash.get(STASH_APPID_SERVICE, val)); CHECK_EQUAL(val, 20); } @@ -213,11 +207,11 @@ TEST(stash_tests, new_uint32_item) { FlowStash stash; - stash.store("item_1", 10u); + stash.store(STASH_APPID_SERVICE, 10u); uint32_t val; - CHECK(stash.get("item_1", val)); + CHECK(stash.get(STASH_APPID_SERVICE, val)); CHECK_EQUAL(val, 10u); } @@ -225,12 +219,12 @@ TEST(stash_tests, update_uint32_item) { FlowStash stash; - stash.store("item_1", 10u); - stash.store("item_1", 20u); + stash.store(STASH_APPID_SERVICE, 10u); + stash.store(STASH_APPID_SERVICE, 20u); uint32_t val; - CHECK(stash.get("item_1", val)); + CHECK(stash.get(STASH_APPID_SERVICE, val)); CHECK_EQUAL(val, 20u); } @@ -238,11 +232,11 @@ TEST(stash_tests, new_str_item_ref) { FlowStash stash; - stash.store("item_1", "value_1"); + stash.store(STASH_HOST, "value_1"); string val; - CHECK(stash.get("item_1", val)); + CHECK(stash.get(STASH_HOST, val)); STRCMP_EQUAL(val.c_str(), "value_1"); } @@ -250,11 +244,11 @@ TEST(stash_tests, new_str_item_ptr) { FlowStash stash; - stash.store("item_1", new string("value_1")); + stash.store(STASH_HOST, new string("value_1")); string val; - CHECK(stash.get("item_1", val)); + CHECK(stash.get(STASH_HOST, val)); STRCMP_EQUAL(val.c_str(), "value_1"); } @@ -262,12 +256,12 @@ TEST(stash_tests, update_str_item) { FlowStash stash; - stash.store("item_1", "value_1"); - stash.store("item_1", new string("value_2")); + stash.store(STASH_HOST, "value_1"); + stash.store(STASH_HOST, new string("value_2")); string val; - CHECK(stash.get("item_1", val)); + CHECK(stash.get(STASH_HOST, val)); STRCMP_EQUAL(val.c_str(), "value_2"); } @@ -275,11 +269,11 @@ TEST(stash_tests, non_existent_item) { FlowStash stash; - stash.store("item_1", 10); + stash.store(STASH_HOST, 10); int32_t val; - CHECK_FALSE(stash.get("item_2", val)); + CHECK_FALSE(stash.get(STASH_URL, val)); } TEST(stash_tests, new_generic_object) @@ -287,10 +281,10 @@ TEST(stash_tests, new_generic_object) FlowStash stash; TestStashObject *test_object = new TestStashObject(111); - stash.store("item_1", test_object); + stash.store(STASH_XFF, test_object); StashGenericObject *retrieved_object; - CHECK(stash.get("item_1", retrieved_object)); + CHECK(stash.get(STASH_XFF, retrieved_object)); POINTERS_EQUAL(test_object, retrieved_object); CHECK_EQUAL(test_object->get_object_type(), ((TestStashObject*)retrieved_object)->get_object_type()); } @@ -299,13 +293,13 @@ TEST(stash_tests, update_generic_object) { FlowStash stash; TestStashObject *test_object = new TestStashObject(111); - stash.store("item_1", test_object); + stash.store(STASH_XFF, test_object); TestStashObject *new_test_object = new TestStashObject(111); - stash.store("item_1", new_test_object); + stash.store(STASH_XFF, new_test_object); StashGenericObject *retrieved_object; - CHECK(stash.get("item_1", retrieved_object)); + CHECK(stash.get(STASH_XFF, retrieved_object)); POINTERS_EQUAL(new_test_object, retrieved_object); } @@ -313,7 +307,7 @@ TEST(stash_tests, non_existent_generic_object) { FlowStash stash; StashGenericObject *retrieved_object; - CHECK_FALSE(stash.get("item_1", retrieved_object)); + CHECK_FALSE(stash.get(STASH_XFF, retrieved_object)); } TEST(stash_tests, mixed_items) @@ -321,23 +315,23 @@ TEST(stash_tests, mixed_items) FlowStash stash; TestStashObject *test_object = new TestStashObject(111); - stash.store("item_1", 10); - stash.store("item_2", "value_2"); - stash.store("item_3", 30); - stash.store("item_4", test_object); + stash.store(STASH_APPID_SERVICE, 10); + stash.store(STASH_HOST, "value_2"); + stash.store(STASH_APPID_CLIENT, 30); + stash.store(STASH_XFF, test_object); int32_t int32_val; string str_val; - CHECK(stash.get("item_1", int32_val)); + CHECK(stash.get(STASH_APPID_SERVICE, int32_val)); CHECK_EQUAL(int32_val, 10); - CHECK(stash.get("item_2", str_val)); + CHECK(stash.get(STASH_HOST, str_val)); STRCMP_EQUAL(str_val.c_str(), "value_2"); - CHECK(stash.get("item_3", int32_val)); + CHECK(stash.get(STASH_APPID_CLIENT, int32_val)); CHECK_EQUAL(int32_val, 30); StashGenericObject *retrieved_object; - CHECK(stash.get("item_4", retrieved_object)); + CHECK(stash.get(STASH_XFF, retrieved_object)); POINTERS_EQUAL(test_object, retrieved_object); CHECK_EQUAL(test_object->get_object_type(), ((TestStashObject*)retrieved_object)->get_object_type()); } diff --git a/src/network_inspectors/appid/appid_discovery.cc b/src/network_inspectors/appid/appid_discovery.cc index aae4e48f7..d416107aa 100644 --- a/src/network_inspectors/appid/appid_discovery.cc +++ b/src/network_inspectors/appid/appid_discovery.cc @@ -1080,5 +1080,6 @@ void AppIdDiscovery::do_post_discovery(Packet* p, AppIdSession& asd, asd.set_application_ids(service_id, asd.pick_client_app_id(), payload_id, asd.pick_misc_app_id(), change_bits); + asd.update_flow_attrs(change_bits); publish_appid_event(change_bits, p->flow); } diff --git a/src/network_inspectors/appid/appid_http_event_handler.cc b/src/network_inspectors/appid/appid_http_event_handler.cc index cd3c48fe3..d8993fd7d 100644 --- a/src/network_inspectors/appid/appid_http_event_handler.cc +++ b/src/network_inspectors/appid/appid_http_event_handler.cc @@ -134,7 +134,7 @@ void HttpEventHandler::handle(DataEvent& event, Flow* flow) asd->set_application_ids(asd->pick_service_app_id(), asd->pick_client_app_id(), asd->pick_payload_app_id(), asd->pick_misc_app_id(), change_bits); } - + asd->update_flow_attrs(change_bits); AppIdDiscovery::publish_appid_event(change_bits, flow); } diff --git a/src/network_inspectors/appid/appid_http_session.cc b/src/network_inspectors/appid/appid_http_session.cc index d7b9ef8f7..a08948ea6 100644 --- a/src/network_inspectors/appid/appid_http_session.cc +++ b/src/network_inspectors/appid/appid_http_session.cc @@ -103,6 +103,49 @@ void AppIdHttpSession::set_http_change_bits(AppidChangeBits& change_bits, HttpFi } } +void AppIdHttpSession::update_flow_attrs(AppidChangeBits& change_bits) +{ + if (change_bits[APPID_HOST_BIT]) + { + if (meta_data[REQ_HOST_FID] and !meta_data[REQ_HOST_FID]->empty()) + asd.flow->set_attr(STASH_HOST, *meta_data[REQ_HOST_FID]); + else + asd.flow->remove_attr(STASH_HOST); + } + + if (change_bits[APPID_URL_BIT]) + { + if (meta_data[MISC_URL_FID] and !meta_data[MISC_URL_FID]->empty()) + asd.flow->set_attr(STASH_URL, *meta_data[MISC_URL_FID]); + else + asd.flow->remove_attr(STASH_URL); + } + + if (change_bits[APPID_USERAGENT_BIT]) + { + if (meta_data[REQ_AGENT_FID] and !meta_data[REQ_AGENT_FID]->empty()) + asd.flow->set_attr(STASH_USER_AGENT, *meta_data[REQ_AGENT_FID]); + else + asd.flow->remove_attr(STASH_USER_AGENT); + } + + if (change_bits[APPID_RESPONSE_BIT]) + { + if (meta_data[MISC_RESP_CODE_FID] and !meta_data[MISC_RESP_CODE_FID]->empty()) + asd.flow->set_attr(STASH_RESPONSE_CODE, *meta_data[MISC_RESP_CODE_FID]); + else + asd.flow->remove_attr(STASH_RESPONSE_CODE); + } + + if (change_bits[APPID_REFERER_BIT]) + { + if (meta_data[REQ_REFERER_FID] and !meta_data[REQ_REFERER_FID]->empty()) + asd.flow->set_attr(STASH_REFERER, *meta_data[REQ_REFERER_FID]); + else + asd.flow->remove_attr(STASH_REFERER); + } +} + int AppIdHttpSession::initial_chp_sweep(ChpMatchDescriptor& cmd) { CHPApp* cah = nullptr; diff --git a/src/network_inspectors/appid/appid_http_session.h b/src/network_inspectors/appid/appid_http_session.h index e507f0c54..10fde2d65 100644 --- a/src/network_inspectors/appid/appid_http_session.h +++ b/src/network_inspectors/appid/appid_http_session.h @@ -26,6 +26,7 @@ #include #include "flow/flow.h" +#include "flow/flow_stash_keys.h" #include "pub_sub/appid_events.h" #include "sfip/sf_ip.h" @@ -106,8 +107,11 @@ public: { delete meta_data[id]; meta_data[id] = str; + if (str) + { set_http_change_bits(change_bits, id); + } } void set_field(HttpFieldIds id, const uint8_t* str, int32_t len, AppidChangeBits& change_bits) @@ -189,6 +193,8 @@ public: void clear_all_fields(); + void update_flow_attrs(AppidChangeBits& change_bits); + protected: void init_chp_match_descriptor(ChpMatchDescriptor& cmd); diff --git a/src/network_inspectors/appid/appid_session.cc b/src/network_inspectors/appid/appid_session.cc index 2255ee18f..f9458bb8c 100644 --- a/src/network_inspectors/appid/appid_session.cc +++ b/src/network_inspectors/appid/appid_session.cc @@ -104,7 +104,6 @@ AppIdSession::AppIdSession(IpProtocol proto, const SfIp* ip, uint16_t port, length_sequence.proto = IpProtocol::PROTO_NOT_SET; length_sequence.sequence_cnt = 0; memset(length_sequence.sequence, '\0', sizeof(length_sequence.sequence)); - memset(application_ids, 0, sizeof(application_ids)); appid_stats.total_sessions++; } @@ -778,63 +777,103 @@ AppId AppIdSession::pick_referred_payload_app_id() void AppIdSession::set_application_ids(AppId service_id, AppId client_id, AppId payload_id, AppId misc_id, AppidChangeBits& change_bits) { - if (application_ids[APP_PROTOID_SERVICE] != service_id) + AppId service, client, payload, misc; + service = client = payload = misc = APP_ID_NONE; + + flow->get_attr(STASH_APPID_SERVICE, service); + if (service != service_id) { - application_ids[APP_PROTOID_SERVICE] = service_id; + flow->set_attr(STASH_APPID_SERVICE, service_id); change_bits.set(APPID_SERVICE_BIT); } - if (application_ids[APP_PROTOID_CLIENT] != client_id) + + flow->get_attr(STASH_APPID_CLIENT, client); + if (client != client_id) { - application_ids[APP_PROTOID_CLIENT] = client_id; + flow->set_attr(STASH_APPID_CLIENT, client_id); change_bits.set(APPID_CLIENT_BIT); } - if (application_ids[APP_PROTOID_PAYLOAD] != payload_id) + + flow->get_attr(STASH_APPID_PAYLOAD, payload); + if (payload != payload_id) { - application_ids[APP_PROTOID_PAYLOAD] = payload_id; + flow->set_attr(STASH_APPID_PAYLOAD, payload_id); change_bits.set(APPID_PAYLOAD_BIT); } - if (application_ids[APP_PROTOID_MISC] != misc_id) + + flow->get_attr(STASH_APPID_MISC, misc); + if (misc != misc_id) { - application_ids[APP_PROTOID_MISC] = misc_id; + flow->set_attr(STASH_APPID_MISC, misc_id); change_bits.set(APPID_MISC_BIT); } } + void AppIdSession::update_flow_attrs(AppidChangeBits& change_bits) + { + if (change_bits[APPID_REFERRED_BIT]) + flow->set_attr(STASH_APPID_REFERRED, referred_payload_app_id); + + if (change_bits[APPID_TLSHOST_BIT] and tsession and tsession->get_tls_host()) + flow->set_attr(STASH_TLS_HOST, tsession->get_tls_host()); + + if (change_bits[APPID_VERSION_BIT]) + { + if (client.get_version()) + flow->set_attr(STASH_CLIENT_VERSION, client.get_version()); + else + flow->remove_attr(STASH_CLIENT_VERSION); + } + + if (hsession) + hsession->update_flow_attrs(change_bits); +} + void AppIdSession::get_application_ids(AppId& service_id, AppId& client_id, AppId& payload_id, AppId& misc_id) { - service_id = application_ids[APP_PROTOID_SERVICE]; - client_id = application_ids[APP_PROTOID_CLIENT]; - payload_id = application_ids[APP_PROTOID_PAYLOAD]; - misc_id = application_ids[APP_PROTOID_MISC]; + service_id = client_id = payload_id = misc_id = APP_ID_NONE; + flow->get_attr(STASH_APPID_SERVICE, service_id); + flow->get_attr(STASH_APPID_CLIENT, client_id); + flow->get_attr(STASH_APPID_PAYLOAD, payload_id); + flow->get_attr(STASH_APPID_MISC, misc_id); } void AppIdSession::get_application_ids(AppId& service_id, AppId& client_id, AppId& payload_id) -{ - service_id = application_ids[APP_PROTOID_SERVICE]; - client_id = application_ids[APP_PROTOID_CLIENT]; - payload_id = application_ids[APP_PROTOID_PAYLOAD]; +{ + service_id = client_id = payload_id = APP_ID_NONE; + flow->get_attr(STASH_APPID_SERVICE, service_id); + flow->get_attr(STASH_APPID_CLIENT, client_id); + flow->get_attr(STASH_APPID_PAYLOAD, payload_id); } AppId AppIdSession::get_application_ids_service() { - return application_ids[APP_PROTOID_SERVICE]; + AppId service_id = APP_ID_NONE;; + flow->get_attr(STASH_APPID_SERVICE, service_id); + return service_id; } AppId AppIdSession::get_application_ids_client() { - return application_ids[APP_PROTOID_CLIENT]; + AppId client_id = APP_ID_NONE;; + flow->get_attr(STASH_APPID_CLIENT, client_id); + return client_id; } AppId AppIdSession::get_application_ids_payload() { - return application_ids[APP_PROTOID_PAYLOAD]; + AppId payload_id = APP_ID_NONE;; + flow->get_attr(STASH_APPID_PAYLOAD, payload_id); + return payload_id; } AppId AppIdSession::get_application_ids_misc() { - return application_ids[APP_PROTOID_MISC]; + AppId misc_id = APP_ID_NONE;; + flow->get_attr(STASH_APPID_MISC, misc_id); + return misc_id; } bool AppIdSession::is_ssl_session_decrypted() diff --git a/src/network_inspectors/appid/appid_session.h b/src/network_inspectors/appid/appid_session.h index 8a1493a04..3bc3cf1b7 100644 --- a/src/network_inspectors/appid/appid_session.h +++ b/src/network_inspectors/appid/appid_session.h @@ -27,6 +27,8 @@ #include #include "pub_sub/appid_events.h" +#include "flow/flow.h" +#include "flow/flow_stash_keys.h" #include "app_info_table.h" #include "appid_api.h" @@ -37,10 +39,10 @@ #include "length_app_cache.h" #include "service_state.h" -class ClientDetector; -class ServiceDetector; class AppIdDnsSession; class AppIdHttpSession; +class ClientDetector; +class ServiceDetector; class ThirdPartyAppIDSession; using AppIdFreeFCN = void (*)(void*); @@ -306,6 +308,7 @@ public: AppId get_application_ids_client(); AppId get_application_ids_payload(); AppId get_application_ids_misc(); + void update_flow_attrs(AppidChangeBits& change_bits); bool is_ssl_session_decrypted(); void examine_ssl_metadata(snort::Packet*, AppidChangeBits& change_bits); @@ -361,7 +364,6 @@ private: void delete_session_data(); static THREAD_LOCAL uint32_t appid_flow_data_id; - AppId application_ids[APP_PROTOID_MAX]; bool tp_app_id_deferred = false; bool tp_payload_app_id_deferred = false; diff --git a/src/network_inspectors/appid/ips_appid_option.cc b/src/network_inspectors/appid/ips_appid_option.cc index c8f5d0120..e2c5b7f0e 100644 --- a/src/network_inspectors/appid/ips_appid_option.cc +++ b/src/network_inspectors/appid/ips_appid_option.cc @@ -108,6 +108,9 @@ bool AppIdIpsOption::match_id_against_rule(int32_t id) if ( nullptr != app_name_key ) { string app_name(app_name_key); + //FIXIT-L: Inbuilt find of the set class does a partial (equivalent) key + //match. It does not match the complete appid id. Ex: "foo" will be + //matched with "foo bar" if ( appid_table.find(app_name) != appid_table.end() ) return true; } diff --git a/src/network_inspectors/appid/test/appid_discovery_test.cc b/src/network_inspectors/appid/test/appid_discovery_test.cc index 8e843ab15..98041f695 100644 --- a/src/network_inspectors/appid/test/appid_discovery_test.cc +++ b/src/network_inspectors/appid/test/appid_discovery_test.cc @@ -188,6 +188,7 @@ AppIdSession* AppIdSession::allocate_session(const Packet*, IpProtocol, { return nullptr; } +void AppIdSession::update_flow_attrs(AppidChangeBits&) {} // Stubs for ServiceDiscovery void ServiceDiscovery::initialize() {} @@ -268,6 +269,8 @@ AppId check_session_for_AF_forecast(AppIdSession&, Packet*, AppidSessionDirectio return APP_ID_UNKNOWN; } +void AppIdHttpSession::update_flow_attrs(AppidChangeBits&) {} + TEST_GROUP(appid_discovery_tests) { void setup() override @@ -316,6 +319,7 @@ TEST(appid_discovery_tests, event_published_when_ignoring_flow) AppIdSession* asd = new AppIdSession(IpProtocol::TCP, nullptr, 21, ins); Flow* flow = new Flow; flow->set_flow_data(asd); + flow->stash = new snort::FlowStash; p.flow = flow; asd->config = &my_app_config; asd->common.initiator_port = 21; @@ -328,6 +332,7 @@ TEST(appid_discovery_tests, event_published_when_ignoring_flow) CHECK_EQUAL(databus_publish_called, true); STRCMP_EQUAL(test_log, "Published change_bits == 0000000001111"); delete asd; + delete flow->stash; delete flow; } @@ -347,6 +352,7 @@ TEST(appid_discovery_tests, event_published_when_processing_flow) AppIdSession* asd = new AppIdSession(IpProtocol::TCP, nullptr, 21, ins); Flow* flow = new Flow; flow->set_flow_data(asd); + flow->stash = new snort::FlowStash; p.flow = flow; asd->config = &my_app_config; asd->common.initiator_port = 21; @@ -356,8 +362,9 @@ TEST(appid_discovery_tests, event_published_when_processing_flow) // Detect changes in service, client, payload, and misc appid CHECK_EQUAL(databus_publish_called, true); - STRCMP_EQUAL(test_log, "Published change_bits == 0000000001111"); + STRCMP_EQUAL(test_log, "Published change_bits == 0000000001110"); delete asd; + delete flow->stash; delete flow; } @@ -401,8 +408,9 @@ TEST(appid_discovery_tests, change_bits_for_non_http_appid) AppIdModule app_module; AppIdInspector ins(app_module); AppIdSession* asd = new AppIdSession(IpProtocol::TCP, nullptr, 21, ins); - Flow* flow = new Flow; + FakeFlow* flow = new FakeFlow; flow->set_flow_data(asd); + flow->stash = new snort::FlowStash; p.flow = flow; asd->config = &my_app_config; asd->common.initiator_port = 21; @@ -432,6 +440,7 @@ TEST(appid_discovery_tests, change_bits_for_non_http_appid) CHECK_EQUAL(asd->service.get_id(), APP_ID_DNS); delete asd; + delete flow->stash; delete flow; } diff --git a/src/network_inspectors/appid/test/appid_http_event_test.cc b/src/network_inspectors/appid/test/appid_http_event_test.cc index 171d44a04..140d121e0 100644 --- a/src/network_inspectors/appid/test/appid_http_event_test.cc +++ b/src/network_inspectors/appid/test/appid_http_event_test.cc @@ -44,6 +44,9 @@ THREAD_LOCAL AppIdDebug* appidDebug = nullptr; void AppIdDebug::activate(const Flow*, const AppIdSession*, bool) { active = true; } +//Stubs for AppIdHttpSession +void AppIdSession::update_flow_attrs(AppidChangeBits&) {} + using namespace snort; namespace snort diff --git a/src/network_inspectors/appid/test/appid_mock_flow.h b/src/network_inspectors/appid/test/appid_mock_flow.h index 39dbe6f03..846c9ccac 100644 --- a/src/network_inspectors/appid/test/appid_mock_flow.h +++ b/src/network_inspectors/appid/test/appid_mock_flow.h @@ -51,7 +51,11 @@ int Flow::set_flow_data(FlowData* fd) return 0; } -FlowStash::~FlowStash() { } +bool snort::FlowStash::get(const int&, int32_t&) { return true; } +void snort::FlowStash::store(const int&, const int32_t) { } +void snort::FlowStash::store(const int&, const std::string&) { } +void snort::FlowStash::remove(const FlowStashKey&) { } +snort::FlowStash::~FlowStash() { } #endif diff --git a/src/network_inspectors/appid/test/appid_mock_session.h b/src/network_inspectors/appid/test/appid_mock_session.h index 5bc9334bc..ffb990823 100644 --- a/src/network_inspectors/appid/test/appid_mock_session.h +++ b/src/network_inspectors/appid/test/appid_mock_session.h @@ -167,26 +167,36 @@ void* AppIdSession::remove_flow_data(unsigned type) } void AppIdSession::set_application_ids(AppId service_id, AppId client_id, - AppId payload_id, AppId misc_id, AppidChangeBits& change_bits) + AppId payload_id, AppId misc_id, AppidChangeBits& change_bits) { - if (application_ids[APP_PROTOID_SERVICE] != service_id) + AppId service, client, payload, misc; + service = client = payload = misc = APP_ID_NONE; + + flow->get_attr(STASH_APPID_SERVICE, service); + if (service != service_id) { - application_ids[APP_PROTOID_SERVICE] = service_id; + flow->set_attr(STASH_APPID_SERVICE, service_id); change_bits.set(APPID_SERVICE_BIT); } - if (application_ids[APP_PROTOID_CLIENT] != client_id) + + flow->get_attr(STASH_APPID_CLIENT, client); + if (client != client_id) { - application_ids[APP_PROTOID_CLIENT] = client_id; + flow->set_attr(STASH_APPID_CLIENT, client_id); change_bits.set(APPID_CLIENT_BIT); } - if (application_ids[APP_PROTOID_PAYLOAD] != payload_id) + + flow->get_attr(STASH_APPID_PAYLOAD, payload); + if (payload != payload_id) { - application_ids[APP_PROTOID_PAYLOAD] = payload_id; + flow->set_attr(STASH_APPID_PAYLOAD, payload_id); change_bits.set(APPID_PAYLOAD_BIT); } - if (application_ids[APP_PROTOID_MISC] != misc_id) + + flow->get_attr(STASH_APPID_MISC, misc); + if (misc != misc_id) { - application_ids[APP_PROTOID_MISC] = misc_id; + flow->set_attr(STASH_APPID_MISC, misc_id); change_bits.set(APPID_MISC_BIT); } }