]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
Pull request #3916: detection: service_mapping config
authorMaya Dagon (mdagon) <mdagon@cisco.com>
Fri, 21 Jul 2023 11:05:54 +0000 (11:05 +0000)
committerOleksii Shumeiko -X (oshumeik - SOFTSERVE INC at Cisco) <oshumeik@cisco.com>
Fri, 21 Jul 2023 11:05:54 +0000 (11:05 +0000)
Merge in SNORT/snort3 from ~MDAGON/snort3:service_map to master

Squashed commit of the following:

commit 5188c7c6ead8b7dae5b512167470ffe949fbfd74
Author: maya dagon <mdagon@cisco.com>
Date:   Thu Jul 20 11:08:55 2023 -0400

    ips_options: remove FIXIT comment from SD_Pattern

commit a08b568ab39443470dba17ae278cbf94fe43b238
Author: maya dagon <mdagon@cisco.com>
Date:   Fri Jul 7 14:05:01 2023 -0400

    detection: service_extension config

src/detection/detection_module.cc
src/detection/detection_module.h
src/detection/fp_utils.cc
src/ips_options/ips_sd_pattern.cc
src/main/snort_config.h
src/parser/parse_conf.cc

index 3f4a71dcb26f80351ddea677f593efd0f5577bad..a87a0b073870726ac539668e4379d6e951b2bddd 100644 (file)
@@ -54,6 +54,26 @@ static const TraceOption detection_trace_options[] =
 };
 #endif
 
+
+static const Parameter extend_to_service[] =
+{
+    { "extend_to_service", Parameter::PT_STRING, nullptr, nullptr,
+      "service to extend to" },
+
+    { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
+};
+
+static const Parameter service_extension[] =
+{
+    { "service", Parameter::PT_STRING, nullptr, nullptr,
+      "service to perform extension for" },
+
+    { "extend_to", Parameter::PT_LIST, extend_to_service, nullptr,
+      "comma separated list of services to extend to"},
+
+    { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
+};
+
 static const Parameter detection_params[] =
 {
     { "allow_missing_so_rules", Parameter::PT_BOOL, nullptr, "false",
@@ -106,6 +126,10 @@ static const Parameter detection_params[] =
     { "max_continuations_per_flow", Parameter::PT_INT, "0:65535", "1024",
       "maximum number of continuations stored simultaneously on the flow" },
 
+    { "service_extension", Parameter::PT_LIST, service_extension, nullptr,
+      "List of maps outlining single service extension to multiple services "
+      "(defaults to http:http2,http3; netbios-ssn:dcerpc)" },
+
     { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
 };
 /* *INDENT-ON* */
@@ -130,8 +154,48 @@ const TraceOption* DetectionModule::get_trace_options() const
 #endif
 }
 
-bool DetectionModule::end(const char*, int, SnortConfig* sc)
+bool DetectionModule::begin(const char* fqn, int idx, SnortConfig* sc)
 {
+    if ( !strcmp(fqn, "detection.service_extension") and ( idx == 0 ) )
+        sc->service_extension.clear();
+
+    return true;
+}
+
+bool DetectionModule::add_service_extension(SnortConfig* sc)
+{
+     const bool ok = (sc->service_extension.insert({service, extend_to})).second;
+     if (!ok)
+         ParseWarning(WARN_CONF,"Duplicate service entry %s in service extension\n", service.c_str());
+     service.clear();
+     extend_to.clear();
+     return true;
+}
+
+bool DetectionModule::end(const char* fqn, int idx, SnortConfig* sc)
+{
+    if ( !strcmp(fqn, "detection.service_extension") )
+    {
+        if ( idx == 0 and service.empty() and extend_to.empty() )
+            return true;
+
+        if ( service.empty() )
+        {
+            ParseError("An entry in detection.service_extension missing a service name");
+            extend_to.clear();
+            return true;
+        }
+
+        if ( extend_to.empty() )
+        {
+            ParseError("Service %s in detection.service_extension missing extend_to", service.c_str());
+            service.clear();
+            return true;
+        }
+
+        return add_service_extension(sc);
+    }
+
     if ( sc->offload_threads and ThreadConfig::get_instance_max() != 1 )
         ParseError("You can not enable experimental offload with more than one packet thread.");
 
@@ -220,5 +284,11 @@ bool DetectionModule::set(const char*, Value& v, SnortConfig* sc)
     else if ( v.is("max_continuations_per_flow") )
         sc->max_continuations = v.get_uint16();
 
+    else if ( v.is("service") )
+        service = v.get_string();
+
+    else if ( v.is("extend_to_service") )
+        extend_to.emplace_back(v.get_string());
+
     return true;
 }
index 2d0f0147700a3001fe1e0822d2483623fc5b581c..862cc6bc1e3dd4aac2f9493233f0a2d0831dd8ee 100644 (file)
@@ -31,6 +31,7 @@ class DetectionModule : public Module
 public:
     DetectionModule();
 
+    bool begin(const char*, int, snort::SnortConfig*) override;
     bool set(const char*, Value&, SnortConfig*) override;
     bool end(const char*, int, SnortConfig*) override;
 
@@ -45,6 +46,12 @@ public:
 
     void set_trace(const Trace*) const override;
     const TraceOption* get_trace_options() const override;
+
+private:
+    bool add_service_extension(snort::SnortConfig*);
+
+    std::string service;
+    std::vector<std::string> extend_to;
 };
 }
 
index 094be3b488341974c45970c6eba3962b3dffab7b..066f310c83067ffabcaee4bdb23c59fad87d7766 100644 (file)
@@ -140,23 +140,11 @@ void update_buffer_map(const char** bufs, const char* svc)
         return;
     }
 
-    // FIXIT-M update NHI and H2I api.buffers and remove the hard-coded foo below
     for ( int i = 0; bufs[i]; ++i )
-    {
         buffer_map[bufs[i]].push_back(svc);
-        if ( !strcmp(svc, "http") )
-        {
-            buffer_map[bufs[i]].push_back("http2");
-            buffer_map[bufs[i]].push_back("http3");
-        }
-    }
 
     if ( !strcmp(svc, "http") )
-    {
         buffer_map["file_data"].push_back("http");
-        buffer_map["file_data"].push_back("http2");
-        buffer_map["file_data"].push_back("http3");
-    }
 }
 
 void add_default_services(SnortConfig* sc, const std::string& buf, OptTreeNode* otn)
@@ -501,35 +489,41 @@ void validate_services(SnortConfig* sc, OptTreeNode* otn)
             continue;
 
         CursorActionType cat = ofl->ips_opt->get_cursor_type();
-        const char* s = ofl->ips_opt->get_name();
+        const char* opt = ofl->ips_opt->get_name();
 
         if ( cat <= CAT_ADJUST )
         {
             if ( !guess )
-                guess = guess_service(s);
+                guess = guess_service(opt);
 
             continue;
         }
 
-        unsigned n = get_num_services(s);
+        unsigned n = get_num_services(opt);
 
         if ( !n )
             continue;
 
         if ( n > 1 )
         {
-            multi_svc_buf = s;
+            multi_svc_buf = opt;
             continue;
         }
 
-        s = get_service(s);
+        const char* opt_svc = get_service(opt);
+        const auto& search = sc->service_extension.find(opt_svc);
+        if (search != sc->service_extension.end())
+        {
+            multi_svc_buf = opt;
+            continue;
+        }
 
-        if ( !svc.empty() and svc != s )
+        if ( !svc.empty() and svc != opt_svc )
         {
             ParseWarning(WARN_RULES, "%u:%u:%u has mixed service buffers (%s and %s)",
-                otn->sigInfo.gid, otn->sigInfo.sid, otn->sigInfo.rev, svc.c_str(), s);
+                otn->sigInfo.gid, otn->sigInfo.sid, otn->sigInfo.rev, svc.c_str(), opt_svc);
         }
-        svc = s;
+        svc = opt_svc;
     }
 
     if ( !svc.empty() or !multi_svc_buf.empty() or guess )
@@ -561,9 +555,6 @@ void validate_services(SnortConfig* sc, OptTreeNode* otn)
             otn->sigInfo.gid, otn->sigInfo.sid, otn->sigInfo.rev, guess);
 
         add_service_to_otn(sc, otn, guess);
-
-        if ( !strcmp(guess, "netbios-ssn") )  // :(
-            add_service_to_otn(sc, otn, "dcerpc");
     }
 }
 
index c4ea15370e7321c3dc55f8896441244f9688400b..dc671a180b1a88bb814a25911a0058b5c4f2dd9c 100644 (file)
@@ -223,7 +223,7 @@ bool SdPatternOption::operator==(const IpsOption& ips) const
 
     const SdPatternOption& rhs = static_cast<const SdPatternOption&>(ips);
 
-    if ( config == rhs.config )  // FIXIT-H seems incorrect
+    if ( config == rhs.config )
         return true;
 
     return false;
index d0d87f4d00986146aa4440db686f8edf08e1ce75..3d20cd31c47c49213bee87310ff3cb17a41a1779 100644 (file)
@@ -237,6 +237,12 @@ public:
     bool enable_strict_reduction = false;
     uint16_t max_continuations = 1024;
 
+    std::unordered_map<std::string, std::vector<std::string>> service_extension =
+        {
+             { "http", {"http2", "http3"} },
+             { "netbios-ssn", {"dcerpc"} },
+        };
+
     //------------------------------------------------------
     // process stuff
 
index 81600eba27565b0943f26cf1b7c2daebe99aeaeb..1777b203d05eaf31985b54abc4cfc47e6f7c30cd 100644 (file)
@@ -250,6 +250,18 @@ void ParseIpVar(const char* var, const char* value)
     }
 }
 
+static void add_service_to_otn_helper(SnortConfig* sc, OptTreeNode* otn, const char* svc_name)
+{
+    SnortProtocolId svc_id = sc->proto_ref->add(svc_name);
+
+    for ( const auto& si : otn->sigInfo.services )
+        if ( si.snort_protocol_id == svc_id )
+            return;  // already added
+
+    SignatureServiceInfo si(svc_name, svc_id);
+    otn->sigInfo.services.emplace_back(si);
+}
+
 void add_service_to_otn(SnortConfig* sc, OptTreeNode* otn, const char* svc_name)
 {
     if ( !strcmp(svc_name, "file") and otn->sigInfo.services.empty() )
@@ -262,20 +274,13 @@ void add_service_to_otn(SnortConfig* sc, OptTreeNode* otn, const char* svc_name)
         return;
     }
 
-    if ( !strcmp(svc_name, "http") )
+    add_service_to_otn_helper(sc, otn, svc_name);
+    const auto& search = sc->service_extension.find(svc_name);
+    if ( search != sc->service_extension.end() )
     {
-        add_service_to_otn(sc, otn, "http2");
-        add_service_to_otn(sc, otn, "http3");
+        for ( const auto& svc : search->second)
+            add_service_to_otn_helper(sc, otn, svc.c_str());
     }
-
-    SnortProtocolId svc_id = sc->proto_ref->add(svc_name);
-
-    for ( const auto& si : otn->sigInfo.services )
-        if ( si.snort_protocol_id == svc_id )
-            return;  // already added
-
-    SignatureServiceInfo si(svc_name, svc_id);
-    otn->sigInfo.services.emplace_back(si);
 }
 
 ListHead* get_rule_list(SnortConfig* sc, const char* s)