]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
Merge pull request #1881 in SNORT/snort3 from ~MDAGON/snort3:assitant_gadget to master
authorMike Stepanek (mstepane) <mstepane@cisco.com>
Wed, 18 Dec 2019 16:39:00 +0000 (16:39 +0000)
committerMike Stepanek (mstepane) <mstepane@cisco.com>
Wed, 18 Dec 2019 16:39:00 +0000 (16:39 +0000)
Squashed commit of the following:

commit f7fbbb6f69f2b80e8be8bb0bbdab36d72cca33ac
Author: mdagon <mdagon@cisco.com>
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.

src/flow/flow.cc
src/flow/flow.h
src/network_inspectors/binder/binder.cc
src/network_inspectors/binder/binding.h
src/pub_sub/assistant_gadget_event.h [new file with mode: 0644]
src/service_inspectors/http2_inspect/http2_stream_splitter.cc

index 58678296c5e838d83ae8add068cafc75a80e80e5..c04fb0a45bcf0fc67ffb34b64ce701f74383ba41 100644 (file)
@@ -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;
 
index 43548acd7ffe70e95a99d94d02c569e167306cb5..d64d5c9e90e9df835efe8ce683a884bf2b625594 100644 (file)
@@ -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
index c5bfe94b66377fc05c699ad1ba809e1b9f7d064f..aff1f41cdfb11327d7c469edbd98177a341af3ba 100644 (file)
@@ -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<Binding*>& 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
 //-------------------------------------------------------------------------
index 8e31dc1f4c6a01246e4008eca1550aca25d595cb..4352e4775902579110b5411131da910dea04bebe 100644 (file)
@@ -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 (file)
index 0000000..db52ab6
--- /dev/null
@@ -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 <mdagon@cisco.com>
+
+#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
+
index 60fb7bd631988935c85837ad3413a68c9f1546b4..c1b9388385596fa1c5765d13a43d7ce495f4f0c2 100644 (file)
@@ -23,7 +23,9 @@
 
 #include <cassert>
 
+#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