From: Mike Stepanek (mstepane) Date: Wed, 18 Dec 2019 16:39:00 +0000 (+0000) Subject: Merge pull request #1881 in SNORT/snort3 from ~MDAGON/snort3:assitant_gadget to master X-Git-Tag: 3.0.0-267~3 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=15438f13af2514e09e32086644d96b6a7e727cf7;p=thirdparty%2Fsnort3.git Merge pull request #1881 in SNORT/snort3 from ~MDAGON/snort3:assitant_gadget to master Squashed commit of the following: commit f7fbbb6f69f2b80e8be8bb0bbdab36d72cca33ac Author: mdagon Date: Wed Dec 4 13:59:02 2019 -0500 binder: assitant gadget support. Currently used by Http2 to setup Http as assistant gadget. Flow was updated as well to support assistant gadget. --- diff --git a/src/flow/flow.cc b/src/flow/flow.cc index 58678296c..c04fb0a45 100644 --- a/src/flow/flow.cc +++ b/src/flow/flow.cc @@ -137,6 +137,9 @@ void Flow::term() if ( gadget ) gadget->rem_ref(); + if (assistant_gadget) + assistant_gadget->rem_ref(); + if ( ha_state ) delete ha_state; diff --git a/src/flow/flow.h b/src/flow/flow.h index 43548acd7..d64d5c9e9 100644 --- a/src/flow/flow.h +++ b/src/flow/flow.h @@ -120,7 +120,7 @@ public: void update_allocations(size_t); void update_deallocations(size_t); - Inspector* get_handler() {return handler;} + Inspector* get_handler() { return handler; } // return fixed size (could be an approx avg) // this must be fixed for life of flow data instance @@ -153,7 +153,8 @@ struct LwState char ignore_direction; }; -enum DeferredWhitelist { +enum DeferredWhitelist +{ WHITELIST_DEFER_OFF = 0, WHITELIST_DEFER_ON, WHITELIST_DEFER_STARTED, @@ -246,9 +247,7 @@ public: int set_ignore_direction(char ignore_direction) { - if (ssn_state.ignore_direction != ignore_direction) - ssn_state.ignore_direction = ignore_direction; - + ssn_state.ignore_direction = ignore_direction; return ssn_state.ignore_direction; } @@ -312,6 +311,20 @@ public: { gadget->rem_ref(); gadget = nullptr; + if (assistant_gadget != nullptr) + clear_assistant_gadget(); + } + + void set_assistant_gadget(Inspector* ins) + { + assistant_gadget = ins; + assistant_gadget->add_ref(); + } + + void clear_assistant_gadget() + { + assistant_gadget->rem_ref(); + assistant_gadget = nullptr; } void set_data(Inspector* pd) @@ -336,9 +349,9 @@ public: { return context_chain.front(); } void set_default_session_timeout(uint32_t dst, bool force) - { + { if (force || (default_session_timeout == 0)) - default_session_timeout = dst; + default_session_timeout = dst; } void set_hard_expiration() @@ -384,6 +397,7 @@ public: // FIXIT-M privatize if possible FlowData* flow_data; Inspector* clouseau; // service identifier Inspector* gadget; // service handler + Inspector* assistant_gadget; Inspector* data; const char* service; @@ -437,7 +451,6 @@ inline void Flow::set_to_server_detection(bool enable) else ssn_state.session_flags |= SSNFLAG_NO_DETECT_TO_SERVER; } - } #endif diff --git a/src/network_inspectors/binder/binder.cc b/src/network_inspectors/binder/binder.cc index c5bfe94b6..aff1f41cd 100644 --- a/src/network_inspectors/binder/binder.cc +++ b/src/network_inspectors/binder/binder.cc @@ -32,6 +32,7 @@ #include "protocols/packet.h" #include "protocols/tcp.h" #include "protocols/udp.h" +#include "pub_sub/assistant_gadget_event.h" #include "stream/stream.h" #include "stream/stream_splitter.h" #include "target_based/sftarget_reader.h" @@ -202,6 +203,14 @@ inline bool Binding::check_service(const Flow* flow) const return false; } +inline bool Binding::check_service(const char* service) const +{ + if ( when.svc == service ) + return true; + + return false; +} + // we want to correlate src_zone to src_nets and src_ports, and dst_zone to dst_nets and // dst_ports. it doesn't matter if the packet is actually moving in the opposite direction as // binder is only evaluated once per flow and we need to capture the correct binding from @@ -234,7 +243,7 @@ static Binding::DirResult directional_match(const When& when_src, const When& wh if ( forward_match ) return Binding::DR_FORWARD; - + if ( reverse_match ) return Binding::DR_REVERSE; @@ -351,7 +360,7 @@ inline Binding::DirResult Binding::check_split_zone(const Packet* p, const Bindi { return traffic_val == DAQ_PKTHDR_UNKNOWN ? true : when_val.test(traffic_val); }); } -bool Binding::check_all(const Flow* flow, Packet* p) const +bool Binding::check_all(const Flow* flow, Packet* p, const char* service) const { Binding::DirResult dir = Binding::DR_ANY_MATCH; @@ -386,7 +395,12 @@ bool Binding::check_all(const Flow* flow, Packet* p) const if ( dir == Binding::DR_NO_MATCH ) return false; - if ( !check_service(flow) ) + if (service) + { + if (!check_service(service)) + return false; + } + else if ( !check_service(flow) ) return false; if ( !check_zone(p) ) @@ -434,6 +448,13 @@ static Inspector* get_gadget(Flow* flow) return InspectorManager::get_inspector(s); } +static Inspector* get_gadget_by_id(const char* service) +{ + const SnortProtocolId id = SnortConfig::get_conf()->proto_ref->find(service); + const char* s = SnortConfig::get_conf()->proto_ref->get_name(id); + return InspectorManager::get_inspector(s); +} + //------------------------------------------------------------------------- // stuff stuff //------------------------------------------------------------------------- @@ -461,6 +482,7 @@ struct Stuff bool apply_action(Flow*); void apply_session(Flow*, const HostAttributeEntry*); void apply_service(Flow*, const HostAttributeEntry*); + void apply_assistant(Flow*, const char*); }; bool Stuff::update(Binding* pb) @@ -592,6 +614,15 @@ void Stuff::apply_service(Flow* flow, const HostAttributeEntry* host) flow->set_clouseau(wizard); } +void Stuff::apply_assistant(Flow* flow, const char* service) +{ + if ( !gadget ) + gadget = get_gadget_by_id(service); + + if ( gadget ) + flow->set_assistant_gadget(gadget); +} + //------------------------------------------------------------------------- // class stuff //------------------------------------------------------------------------- @@ -617,11 +648,13 @@ public: void handle_flow_setup(Packet*); void handle_flow_service_change(Flow*); void handle_new_standby_flow(Flow*); + void handle_assistant_gadget(const char* service, Packet*); private: void set_binding(SnortConfig*, Binding*); - void get_bindings(Flow*, Stuff&, Packet* = nullptr); // may be null when dealing with HA flows + void get_bindings(Flow*, Stuff&, Packet* = nullptr, const char* = nullptr); // may be null when dealing with HA flows void apply(Flow*, Stuff&); + void apply_assistant(Flow*, Stuff&, const char*); Inspector* find_gadget(Flow*); private: @@ -668,6 +701,22 @@ public: } }; +class AssistantGadgetHandler : public DataHandler +{ +public: + AssistantGadgetHandler() : DataHandler(BIND_NAME) { } + + void handle(DataEvent& event, Flow*) override + { + Binder* binder = InspectorManager::get_binder(); + AssistantGadgetEvent* assistant_event = (AssistantGadgetEvent*)&event; + + if (binder) + binder->handle_assistant_gadget(assistant_event->get_service(), + assistant_event->get_packet()); + } +}; + Binder::Binder(vector& v) { bindings = std::move(v); @@ -704,6 +753,7 @@ bool Binder::configure(SnortConfig* sc) DataBus::subscribe(FLOW_STATE_SETUP_EVENT, new FlowStateSetupHandler()); DataBus::subscribe(FLOW_SERVICE_CHANGE_EVENT, new FlowServiceChangeHandler()); DataBus::subscribe(STREAM_HA_NEW_FLOW_EVENT, new StreamHANewFlowHandler()); + DataBus::subscribe(FLOW_ASSISTANT_GADGET_EVENT, new AssistantGadgetHandler()); return true; } @@ -823,6 +873,16 @@ void Binder::handle_new_standby_flow( Flow* flow ) ++bstats.verdicts[stuff.action]; } +void Binder::handle_assistant_gadget(const char* service, Packet* p) +{ + Profile profile(bindPerfStats); + Stuff stuff; + Flow* flow = p->flow; + + get_bindings(flow, stuff, p, service); + apply_assistant(flow, stuff, service); +} + //------------------------------------------------------------------------- // implementation stuff //------------------------------------------------------------------------- @@ -860,7 +920,7 @@ void Binder::set_binding(SnortConfig* sc, Binding* pb) // FIXIT-P this is a simple linear search until functionality is nailed // down. performance should be the focus of the next iteration. -void Binder::get_bindings(Flow* flow, Stuff& stuff, Packet* p) +void Binder::get_bindings(Flow* flow, Stuff& stuff, Packet* p, const char* service) { unsigned sz = bindings.size(); @@ -881,27 +941,30 @@ void Binder::get_bindings(Flow* flow, Stuff& stuff, Packet* p) (!pb->use.network_index or network_set) ) continue; - if ( !pb->check_all(flow, p) ) + if ( !pb->check_all(flow, p, service) ) continue; if ( pb->use.inspection_index and !inspection_set ) { set_inspection_policy(SnortConfig::get_conf(), pb->use.inspection_index - 1); - flow->inspection_policy_id = pb->use.inspection_index - 1; + if (!service) + flow->inspection_policy_id = pb->use.inspection_index - 1; inspection_set = true; } if ( pb->use.ips_index and !ips_set ) { set_ips_policy(SnortConfig::get_conf(), pb->use.ips_index - 1); - flow->ips_policy_id = pb->use.ips_index - 1; + if (!service) + flow->ips_policy_id = pb->use.ips_index - 1; ips_set = true; } if ( pb->use.network_index and !network_set ) { set_network_policy(SnortConfig::get_conf(), pb->use.network_index - 1); - flow->network_policy_id = pb->use.network_index - 1; + if (!service) + flow->network_policy_id = pb->use.network_index - 1; network_set = true; } } @@ -924,7 +987,7 @@ void Binder::get_bindings(Flow* flow, Stuff& stuff, Packet* p) if ( pb->use.ips_index or pb->use.inspection_index or pb->use.network_index ) continue; - if ( !pb->check_all(flow, p) ) + if ( !pb->check_all(flow, p, service) ) continue; if ( stuff.update(pb) ) @@ -954,6 +1017,11 @@ void Binder::apply(Flow* flow, Stuff& stuff) stuff.apply_service(flow, host); } +void Binder::apply_assistant(Flow* flow, Stuff& stuff, const char* service) +{ + stuff.apply_assistant(flow, service); +} + //------------------------------------------------------------------------- // api stuff //------------------------------------------------------------------------- diff --git a/src/network_inspectors/binder/binding.h b/src/network_inspectors/binder/binding.h index 8e31dc1f4..4352e4775 100644 --- a/src/network_inspectors/binder/binding.h +++ b/src/network_inspectors/binder/binding.h @@ -104,7 +104,7 @@ struct Binding Binding(); ~Binding(); - bool check_all(const snort::Flow*, snort::Packet*) const; + bool check_all(const snort::Flow*, snort::Packet*, const char* = nullptr) const; bool check_ips_policy(const snort::Flow*) const; bool check_iface(const snort::Packet*) const; bool check_vlan(const snort::Flow*) const; @@ -116,6 +116,7 @@ struct Binding bool check_zone(const snort::Packet*) const; DirResult check_split_zone(const snort::Packet*, const DirResult) const; bool check_service(const snort::Flow*) const; + bool check_service(const char* service) const; }; #endif diff --git a/src/pub_sub/assistant_gadget_event.h b/src/pub_sub/assistant_gadget_event.h new file mode 100644 index 000000000..db52ab6b1 --- /dev/null +++ b/src/pub_sub/assistant_gadget_event.h @@ -0,0 +1,56 @@ +//-------------------------------------------------------------------------- +// 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. +//-------------------------------------------------------------------------- +// assistant_gadget_events.h author Maya Dagon + +#ifndef ASSISTANT_GADGET_EVENTS_H +#define ASSISTANT_GADGET_EVENTS_H + +#include "framework/data_bus.h" +#include "target_based/snort_protocols.h" +#include "utils/util.h" + +// A flow is setting up assistant inspector. +// For example used by HTTP2 to set NHI as assistant inspector. + +#define FLOW_ASSISTANT_GADGET_EVENT "flow.assistant_gadget" + +namespace snort +{ +struct Packet; +} + +class AssistantGadgetEvent : public snort::DataEvent +{ +public: + AssistantGadgetEvent(snort::Packet* packet, const char* _service) + : p(packet), service(_service) + { } + + snort::Packet* get_packet() override + { return p; } + + const char* get_service() + { return service.c_str(); } + +private: + snort::Packet* p; + std::string service; +}; + +#endif + diff --git a/src/service_inspectors/http2_inspect/http2_stream_splitter.cc b/src/service_inspectors/http2_inspect/http2_stream_splitter.cc index 60fb7bd63..c1b938838 100644 --- a/src/service_inspectors/http2_inspect/http2_stream_splitter.cc +++ b/src/service_inspectors/http2_inspect/http2_stream_splitter.cc @@ -23,7 +23,9 @@ #include +#include "framework/data_bus.h" #include "protocols/packet.h" +#include "pub_sub/assistant_gadget_event.h" #include "service_inspectors/http_inspect/http_common.h" #include "service_inspectors/http_inspect/http_field.h" #include "service_inspectors/http_inspect/http_stream_splitter.h" @@ -52,6 +54,8 @@ StreamSplitter::Status Http2StreamSplitter::scan(Packet* pkt, const uint8_t* dat { pkt->flow->set_flow_data(session_data = new Http2FlowData); Http2Module::increment_peg_counts(PEG_FLOW); + AssistantGadgetEvent event(pkt, "http"); + DataBus::publish(FLOW_ASSISTANT_GADGET_EVENT, event); } // General mechanism to abort using scan @@ -189,7 +193,7 @@ bool Http2StreamSplitter::finish(Flow* flow) // due to lack of reliable feedback to stream that scan has been called...if that is // addressed in stream reassembly rewrite this can be reverted to an assert //assert(session_data != nullptr); - if(!session_data) + if (!session_data) return false; #ifdef REG_TEST