]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
Pull request #4369: appid: Notify binder on service change
authorOleksandr Stepanov -X (ostepano - SOFTSERVE INC at Cisco) <ostepano@cisco.com>
Mon, 26 Aug 2024 14:35:54 +0000 (14:35 +0000)
committerChris Sherwin (chsherwi) <chsherwi@cisco.com>
Mon, 26 Aug 2024 14:35:54 +0000 (14:35 +0000)
Merge in SNORT/snort3 from ~OSTEPANO/snort3:appid_binder to master

Squashed commit of the following:

commit b95ee6c0632260fe1a295f7eba7b90ae7be4424d
Author: Oleksandr Stepanov <ostepano@cisco.com>
Date:   Mon Jul 1 09:00:35 2024 -0400

    appid: Notify binder on service change

src/flow/flow.h
src/network_inspectors/binder/bind_module.cc
src/network_inspectors/binder/bind_module.h
src/network_inspectors/binder/binder.cc
src/network_inspectors/binder/binding.cc
src/network_inspectors/binder/binding.h

index 9f1e46452e1925d53ed5a8182ea39740e3c91a4a..6e4bb03a69ec8b56ad01d9449a96f1d1b8a37568 100644 (file)
@@ -521,6 +521,8 @@ public:  // FIXIT-M privatize if possible
         bool ips_block_event_suppressed : 1; // Set if event filters have suppressed a block ips event
         bool ips_wblock_event_suppressed : 1; // set if event filters have suppressed a would block/drop ips event
         bool ips_pblock_event_suppressed : 1; // set if event filters have suppressed a partial block ips event
+        bool binder_action_allow : 1;
+        bool binder_action_block : 1;
     } flags = {};
 
     FlowState flow_state = FlowState::SETUP;
index 6d034702cce60a887bc51add9d7195c4d2ef0721..1f8c095bedde75135d05f455024e076a11ae2f3f 100644 (file)
@@ -40,6 +40,8 @@ using namespace std;
 #define INSPECTION_KEY ".inspection"
 #define IPS_KEY ".ips"
 
+unsigned int BinderModule::module_id = 0;
+
 THREAD_LOCAL BindStats bstats;
 
 static const PegInfo bind_pegs[] =
@@ -122,7 +124,7 @@ static const Parameter binder_when_params[] =
       "use the given configuration on one or any end of a session" },
 
     { "service", Parameter::PT_STRING, nullptr, nullptr,
-      "override default configuration" },
+      "space separated list of services" },
 
     { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
 };
@@ -232,6 +234,9 @@ bool BinderModule::begin(const char* fqn, int idx, SnortConfig*)
         policy_type.clear();
     }
 
+    if (!module_id)
+        module_id = FlowData::create_flow_data_id();
+
     return true;
 }
 
@@ -240,7 +245,7 @@ bool BinderModule::set(const char* fqn, Value& v, SnortConfig*)
     // both
     if ( !strcmp(fqn, "binder.when.service") )
     {
-        binding.when.svc = v.get_string();
+        binding.when.parse_service(v.get_string());
         binding.when.add_criteria(BindWhen::Criteria::BWC_SVC);
     }
     else if ( !strcmp(fqn, "binder.use.service") )
@@ -483,7 +488,7 @@ bool BinderModule::end(const char* fqn, int idx, SnortConfig* sc)
 void BinderModule::add(const char* svc, const char* type)
 {
     binding.clear();
-    binding.when.svc = svc;
+    binding.when.parse_service(svc);
     binding.when.add_criteria(BindWhen::Criteria::BWC_SVC);
     binding.use.type = type;
     binding.use.name = type;
index 2fda481b6a144da953df22e8bac1fe464c6ab27b..5cfd3a6c3593cbf656c8179b358e589670bec976 100644 (file)
@@ -68,6 +68,8 @@ public:
     Usage get_usage() const override
     { return INSPECT; }
 
+    static unsigned int module_id;
+
 private:
     Binding binding;
     std::vector<Binding> bindings;
index ccef0efb19ad413025bef9c4f630e1cfac79d0a4..cab438ebcb14d44078dbe2bcaaed5054040e8b47 100644 (file)
@@ -21,6 +21,8 @@
 #include "config.h"
 #endif
 
+
+#include "appid/appid_session_api.h"
 #include "detection/detection_engine.h"
 #include "flow/flow.h"
 #include "framework/pig_pen.h"
@@ -30,6 +32,7 @@
 #include "packet_io/active.h"
 #include "profiler/profiler.h"
 #include "protocols/packet.h"
+#include "pub_sub/appid_events.h"
 #include "pub_sub/assistant_gadget_event.h"
 #include "pub_sub/intrinsic_event_ids.h"
 #include "pub_sub/stream_event_ids.h"
@@ -198,7 +201,7 @@ static std::string to_string(const BindWhen& bw)
     }
 
     if (bw.has_criteria(BindWhen::Criteria::BWC_SVC))
-        when += " service = " + bw.svc + ",";
+        when += " service = " + bw.get_service_list() + ",";
 
     if (bw.has_criteria(BindWhen::Criteria::BWC_SPLIT_NETS))
     {
@@ -489,6 +492,7 @@ public:
     void handle_flow_service_change(Flow&);
     void handle_assistant_gadget(const char* service, Flow&);
     void handle_flow_after_reload(Flow&);
+    void handle_appid_service_change(DataEvent&,Flow&);
 
 private:
     void get_policy_bindings(Flow&, const char* service);
@@ -533,6 +537,19 @@ public:
     }
 };
 
+class AppIDServiceChangeHandler : public DataHandler
+{
+    public:
+    AppIDServiceChangeHandler() : DataHandler(BIND_NAME) { }
+
+    void handle(DataEvent& event, Flow* flow) override
+    {
+        Binder* binder = (Binder*)InspectorManager::get_binder();
+        if (binder && flow)
+            binder->handle_appid_service_change(event, *flow);
+    }
+};
+
 // When a flow's service changes, re-evaluate service to inspector mapping.
 class FlowServiceChangeHandler : public DataHandler
 {
@@ -636,6 +653,7 @@ bool Binder::configure(SnortConfig* sc)
     DataBus::subscribe(intrinsic_pub_key, IntrinsicEventIds::FLOW_SERVICE_CHANGE, new FlowServiceChangeHandler());
     DataBus::subscribe(intrinsic_pub_key, IntrinsicEventIds::FLOW_ASSISTANT_GADGET, new AssistantGadgetHandler());
     DataBus::subscribe(intrinsic_pub_key, IntrinsicEventIds::FLOW_STATE_RELOADED, new RebindFlow());
+    DataBus::subscribe(appid_pub_key, AppIdEventIds::ANY_CHANGE, new AppIDServiceChangeHandler());
 
     DataBus::subscribe(stream_pub_key, StreamEventIds::HA_NEW_FLOW, new StreamHANewFlowHandler());
 
@@ -752,6 +770,49 @@ void Binder::handle_flow_setup(Flow& flow, bool standby)
     bstats.verdicts[stuff.action]++;
 }
 
+void Binder::handle_appid_service_change(DataEvent& event, Flow& flow)
+{
+    AppidEvent& appid_event = static_cast<AppidEvent&>(event);
+
+    if(appid_event.get_change_bitset().test(APPID_SERVICE_BIT))
+    {
+        if ((appid_event.get_appid_session_api().get_service_app_id() <= 0)
+            or (flow.ssn_state.snort_protocol_id == 0))
+            return;
+
+        Stuff stuff;
+        const SnortConfig* sc = SnortConfig::get_conf();
+        const char* service = sc->proto_ref->get_name(flow.ssn_state.snort_protocol_id);
+        get_bindings(flow, stuff, service);
+
+        if(stuff.action == BindUse::BA_ALLOW)
+        {
+            flow.set_deferred_trust(BinderModule::module_id, true);
+            flow.flags.binder_action_allow = true;
+        }
+        else if (stuff.action == BindUse::BA_BLOCK)
+        {
+            flow.flags.binder_action_block = true;
+        }
+    }
+
+    if(appid_event.get_change_bitset().test(APPID_DISCOVERY_FINISHED_BIT))
+    {
+        //apply action for delay
+        if(flow.flags.binder_action_allow)
+        {
+            flow.try_trust();
+            flow.set_deferred_trust(BinderModule::module_id, false);
+        }
+        else if(flow.flags.binder_action_block)
+        {
+            flow.block();
+            auto p = const_cast<Packet*>(appid_event.get_packet());
+            p->active->block_session(p, true);
+        }
+    }
+}
+
 void Binder::handle_flow_service_change(Flow& flow)
 {
     bstats.service_changes++;
@@ -763,6 +824,7 @@ void Binder::handle_flow_service_change(Flow& flow)
     if (stuff.action != BindUse::BA_INSPECT)
     {
         stuff.apply_action(flow);
+        flow.disable_inspection();
         return;
     }
 
index bac7f5a0f023b8741b71419b3554884e41c59d87..9519343e46dbb9e948d0d853d92d91ee1e77ea88 100644 (file)
@@ -45,7 +45,7 @@ void Binding::clear()
     when.ips_id_user = 0;
     when.protos = PROTO_BIT__ANY_TYPE;
     when.role = BindWhen::BR_EITHER;
-    when.svc.clear();
+    when.svc_list.clear();
 
     if (when.src_nets)
     {
@@ -587,7 +587,7 @@ inline bool Binding::check_service(const Flow& flow) const
     if (!flow.service)
         return false;
 
-    return when.svc == flow.service;
+    return when.svc_list.find(flow.service) != when.svc_list.end();
 }
 
 inline bool Binding::check_service(const char* service) const
@@ -597,7 +597,7 @@ inline bool Binding::check_service(const char* service) const
     if (!when.has_criteria(BindWhen::Criteria::BWC_SVC))
         return false;
 
-    return when.svc == service;
+    return when.svc_list.find(service) != when.svc_list.end();
 }
 
 inline bool Binding::check_service() const
index bc27133fba95a422daf7021839312efe24c4fafc..d96d4bd702973af1b9c24ed084a87d68089a3cc9 100644 (file)
@@ -21,6 +21,7 @@
 #define BINDING_H
 
 #include <string>
+#include <sstream>
 
 #include "main/policy.h"
 #include "sfip/sf_ipvar.h"
@@ -42,7 +43,6 @@ struct BindWhen
     unsigned ips_id_user;
     unsigned protos;
     Role role;
-    std::string svc;
 
     sfip_var_t* src_nets;
     sfip_var_t* dst_nets;
@@ -52,6 +52,8 @@ struct BindWhen
     PortBitSet src_ports;
     PortBitSet dst_ports;
 
+    std::unordered_set<std::string> svc_list;
+
     std::unordered_set<int32_t> src_intfs;
     std::unordered_set<int32_t> dst_intfs;
 
@@ -85,6 +87,28 @@ struct BindWhen
     { criteria_flags |= flags; }
     bool has_criteria(uint16_t flags) const
     { return (criteria_flags & flags) == flags; }
+
+    void parse_service(const std::string& service)
+    {
+        if (service.find(" ") == std::string::npos)
+        {
+            svc_list.emplace(service);
+            return;
+        }
+
+        std::string buf;
+        std::stringstream ss(service);
+        while(getline(ss, buf, ' '))
+            svc_list.emplace(buf);
+    }
+
+    std::string get_service_list() const
+    {
+        std::string res;
+        for(const auto& entry : svc_list)
+            res += entry;
+        return res;
+    }
 };
 
 struct BindUse