]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
Pull request #4983: appid: configurable midstream service discovery
authorDaniil Kolomiiets -X (dkolomii - SOFTSERVE INC at Cisco) <dkolomii@cisco.com>
Sun, 18 Jan 2026 16:36:36 +0000 (16:36 +0000)
committerChris Sherwin (chsherwi) <chsherwi@cisco.com>
Sun, 18 Jan 2026 16:36:36 +0000 (16:36 +0000)
Merge in SNORT/snort3 from ~DKOLOMII/snort3:midstream_service_discovery to master

Squashed commit of the following:

commit 598fc31e667da263c8514a92c4f95ef2cdc3eada
Author: Daniil Kolomiiets <dkolomii@cisco.com>
Date:   Thu Dec 4 10:18:32 2025 -0500

    appid: configurable midstream service discovery

src/network_inspectors/appid/app_info_table.cc
src/network_inspectors/appid/appid_config.cc
src/network_inspectors/appid/appid_config.h
src/network_inspectors/appid/appid_session.cc
src/network_inspectors/appid/appid_session.h
src/network_inspectors/appid/service_plugins/service_discovery.cc

index 29c4a8aca13a081e6908ec502b11dfdb1925491d..72a95361e39d22b59c78ff6be3ad1255e5b480b0 100644 (file)
@@ -555,6 +555,27 @@ void AppInfoManager::load_odp_config(OdpContext& odp_ctxt, const char* path)
                     odp_ctxt.max_bytes_before_service_fail = max_bytes_before_service_fail;
                 }
             }
+            else if (!(strcasecmp(conf_key, "max_midstream_packet_before_service_fail")))
+            {
+                int32_t max_midstream_packet_before_service_fail = atoi(conf_val);
+                if (max_midstream_packet_before_service_fail != MIDSTREAM_SERVICE_INSPECTION_OFF &&
+                    (max_midstream_packet_before_service_fail > MAX_MIDSTREAM_PKTS_BEFORE_SERVICE_FAIL ||
+                     max_midstream_packet_before_service_fail < MIN_MIDSTREAM_PKTS_BEFORE_SERVICE_FAIL))
+                {
+                    APPID_LOG(nullptr, TRACE_WARNING_LEVEL, "appid: invalid "
+                        "max_midstream_packet_before_service_fail %" PRIu16 ", must be %u or in the range %u-%u.\n",
+                        max_midstream_packet_before_service_fail, MIDSTREAM_SERVICE_INSPECTION_OFF,
+                        MIN_MIDSTREAM_PKTS_BEFORE_SERVICE_FAIL, MAX_MIDSTREAM_PKTS_BEFORE_SERVICE_FAIL);
+                        
+                    odp_ctxt.max_midstream_packet_before_service_fail = 
+                        max_midstream_packet_before_service_fail > MAX_MIDSTREAM_PKTS_BEFORE_SERVICE_FAIL ? 
+                            MAX_MIDSTREAM_PKTS_BEFORE_SERVICE_FAIL : MIN_MIDSTREAM_PKTS_BEFORE_SERVICE_FAIL;
+                }
+                else
+                {
+                    odp_ctxt.max_midstream_packet_before_service_fail = max_midstream_packet_before_service_fail;
+                }
+            }
             else if (!(strcasecmp(conf_key, "max_packet_before_service_fail")))
             {
                 uint16_t max_packet_before_service_fail = atoi(conf_val);
index 59b92a5176560832b2fa751302a030c356e6c3b8..b4ff9710220b5691dbc2d112ba5d2b6652cc362c 100644 (file)
@@ -206,33 +206,34 @@ unsigned OdpContext::get_pattern_count()
 
 void OdpContext::dump_appid_config()
 {
-    APPID_LOG(nullptr, TRACE_INFO_LEVEL, "Appid Config: dns_host_reporting                   %s\n", (dns_host_reporting ? "True" : "False"));
-    APPID_LOG(nullptr, TRACE_INFO_LEVEL, "Appid Config: referred_appId_disabled              %s\n", (referred_appId_disabled ? "True" : "False"));
-    APPID_LOG(nullptr, TRACE_INFO_LEVEL, "Appid Config: mdns_user_reporting                  %s\n", (mdns_user_reporting ? "True" : "False"));
-    APPID_LOG(nullptr, TRACE_INFO_LEVEL, "Appid Config: chp_userid_disabled                  %s\n", (chp_userid_disabled ? "True" : "False"));
-    APPID_LOG(nullptr, TRACE_INFO_LEVEL, "Appid Config: is_host_port_app_cache_runtime       %s\n", (is_host_port_app_cache_runtime ? "True" : "False"));
-    APPID_LOG(nullptr, TRACE_INFO_LEVEL, "Appid Config: check_host_port_app_cache            %s\n", (check_host_port_app_cache ? "True" : "False"));
-    APPID_LOG(nullptr, TRACE_INFO_LEVEL, "Appid Config: check_host_cache_unknown_ssl         %s\n", (check_host_cache_unknown_ssl ? "True" : "False"));
-    APPID_LOG(nullptr, TRACE_INFO_LEVEL, "Appid Config: ftp_userid_disabled                  %s\n", (ftp_userid_disabled ? "True" : "False"));
-    APPID_LOG(nullptr, TRACE_INFO_LEVEL, "Appid Config: chp_body_collection_disabled         %s\n", (chp_body_collection_disabled ? "True" : "False"));
-    APPID_LOG(nullptr, TRACE_INFO_LEVEL, "Appid Config: chp_body_collection_max              %d\n", chp_body_collection_max);
-    APPID_LOG(nullptr, TRACE_INFO_LEVEL, "Appid Config: rtmp_max_packets                     %d\n", rtmp_max_packets);
-    APPID_LOG(nullptr, TRACE_INFO_LEVEL, "Appid Config: max_tp_flow_depth                    %d\n", max_tp_flow_depth);
-    APPID_LOG(nullptr, TRACE_INFO_LEVEL, "Appid Config: tp_allow_probes                      %s\n", (tp_allow_probes ? "True" : "False"));
-    APPID_LOG(nullptr, TRACE_INFO_LEVEL, "Appid Config: host_port_app_cache_lookup_interval  %d\n", host_port_app_cache_lookup_interval);
-    APPID_LOG(nullptr, TRACE_INFO_LEVEL, "Appid Config: host_port_app_cache_lookup_range     %d\n", host_port_app_cache_lookup_range);
-    APPID_LOG(nullptr, TRACE_INFO_LEVEL, "Appid Config: allow_port_wildcard_host_cache       %s\n", (allow_port_wildcard_host_cache ? "True" : "False"));
-    APPID_LOG(nullptr, TRACE_INFO_LEVEL, "Appid Config: allow_port_wildcard_firstpkt_cache   %s\n", (allow_port_wildcard_firstpkt_cache ? "True" : "False"));
-    APPID_LOG(nullptr, TRACE_INFO_LEVEL, "Appid Config: recheck_for_portservice_appid        %s\n", (recheck_for_portservice_appid ? "True" : "False"));
-    APPID_LOG(nullptr, TRACE_INFO_LEVEL, "Appid Config: max_bytes_before_service_fail        %" PRIu64" \n", max_bytes_before_service_fail);
-    APPID_LOG(nullptr, TRACE_INFO_LEVEL, "Appid Config: max_packet_before_service_fail       %" PRIu16" \n", max_packet_before_service_fail);
-    APPID_LOG(nullptr, TRACE_INFO_LEVEL, "Appid Config: max_packet_service_fail_ignore_bytes %" PRIu16" \n", max_packet_service_fail_ignore_bytes);
-    APPID_LOG(nullptr, TRACE_INFO_LEVEL, "Appid Config: eve_http_client                      %s\n", (eve_http_client ? "True" : "False"));
-    APPID_LOG(nullptr, TRACE_INFO_LEVEL, "Appid Config: appid_cpu_profiler                   %s\n", (appid_cpu_profiler ? "True" : "False"));
-    APPID_LOG(nullptr, TRACE_INFO_LEVEL, "Appid Config: shadow_traffic_status                %s\n", (get_appid_shadow_traffic_status() ? "True" : "False"));
-    APPID_LOG(nullptr, TRACE_INFO_LEVEL, "Appid Config: brute_force_inprocess_threshold      %" PRId8" \n", brute_force_inprocess_threshold);
-    APPID_LOG(nullptr, TRACE_INFO_LEVEL, "Appid Config: failed_state_expiration_secs         %" PRId32" \n", failed_state_expiration_secs);
-    APPID_LOG(nullptr, TRACE_INFO_LEVEL, "Appid Config: inspect_ooo_flows                    %s\n", inspect_ooo_flows ? "True" : "False");
+    APPID_LOG(nullptr, TRACE_INFO_LEVEL, "Appid Config: dns_host_reporting                       %s\n", (dns_host_reporting ? "True" : "False"));
+    APPID_LOG(nullptr, TRACE_INFO_LEVEL, "Appid Config: referred_appId_disabled                  %s\n", (referred_appId_disabled ? "True" : "False"));
+    APPID_LOG(nullptr, TRACE_INFO_LEVEL, "Appid Config: mdns_user_reporting                      %s\n", (mdns_user_reporting ? "True" : "False"));
+    APPID_LOG(nullptr, TRACE_INFO_LEVEL, "Appid Config: chp_userid_disabled                      %s\n", (chp_userid_disabled ? "True" : "False"));
+    APPID_LOG(nullptr, TRACE_INFO_LEVEL, "Appid Config: is_host_port_app_cache_runtime           %s\n", (is_host_port_app_cache_runtime ? "True" : "False"));
+    APPID_LOG(nullptr, TRACE_INFO_LEVEL, "Appid Config: check_host_port_app_cache                %s\n", (check_host_port_app_cache ? "True" : "False"));
+    APPID_LOG(nullptr, TRACE_INFO_LEVEL, "Appid Config: check_host_cache_unknown_ssl             %s\n", (check_host_cache_unknown_ssl ? "True" : "False"));
+    APPID_LOG(nullptr, TRACE_INFO_LEVEL, "Appid Config: ftp_userid_disabled                      %s\n", (ftp_userid_disabled ? "True" : "False"));
+    APPID_LOG(nullptr, TRACE_INFO_LEVEL, "Appid Config: chp_body_collection_disabled             %s\n", (chp_body_collection_disabled ? "True" : "False"));
+    APPID_LOG(nullptr, TRACE_INFO_LEVEL, "Appid Config: chp_body_collection_max                  %d\n", chp_body_collection_max);
+    APPID_LOG(nullptr, TRACE_INFO_LEVEL, "Appid Config: rtmp_max_packets                         %d\n", rtmp_max_packets);
+    APPID_LOG(nullptr, TRACE_INFO_LEVEL, "Appid Config: max_tp_flow_depth                        %d\n", max_tp_flow_depth);
+    APPID_LOG(nullptr, TRACE_INFO_LEVEL, "Appid Config: tp_allow_probes                          %s\n", (tp_allow_probes ? "True" : "False"));
+    APPID_LOG(nullptr, TRACE_INFO_LEVEL, "Appid Config: host_port_app_cache_lookup_interval      %d\n", host_port_app_cache_lookup_interval);
+    APPID_LOG(nullptr, TRACE_INFO_LEVEL, "Appid Config: host_port_app_cache_lookup_range         %d\n", host_port_app_cache_lookup_range);
+    APPID_LOG(nullptr, TRACE_INFO_LEVEL, "Appid Config: allow_port_wildcard_host_cache           %s\n", (allow_port_wildcard_host_cache ? "True" : "False"));
+    APPID_LOG(nullptr, TRACE_INFO_LEVEL, "Appid Config: allow_port_wildcard_firstpkt_cache       %s\n", (allow_port_wildcard_firstpkt_cache ? "True" : "False"));
+    APPID_LOG(nullptr, TRACE_INFO_LEVEL, "Appid Config: recheck_for_portservice_appid            %s\n", (recheck_for_portservice_appid ? "True" : "False"));
+    APPID_LOG(nullptr, TRACE_INFO_LEVEL, "Appid Config: max_bytes_before_service_fail            %" PRIu64" \n", max_bytes_before_service_fail);
+    APPID_LOG(nullptr, TRACE_INFO_LEVEL, "Appid Config: max_packet_before_service_fail           %" PRIu16" \n", max_packet_before_service_fail);
+    APPID_LOG(nullptr, TRACE_INFO_LEVEL, "Appid Config: max_packet_service_fail_ignore_bytes     %" PRIu16" \n", max_packet_service_fail_ignore_bytes);
+    APPID_LOG(nullptr, TRACE_INFO_LEVEL, "Appid Config: max_midstream_packet_before_service_fail %d\n", max_midstream_packet_before_service_fail);
+    APPID_LOG(nullptr, TRACE_INFO_LEVEL, "Appid Config: eve_http_client                          %s\n", (eve_http_client ? "True" : "False"));
+    APPID_LOG(nullptr, TRACE_INFO_LEVEL, "Appid Config: appid_cpu_profiler                       %s\n", (appid_cpu_profiler ? "True" : "False"));
+    APPID_LOG(nullptr, TRACE_INFO_LEVEL, "Appid Config: shadow_traffic_status                    %s\n", (get_appid_shadow_traffic_status() ? "True" : "False"));
+    APPID_LOG(nullptr, TRACE_INFO_LEVEL, "Appid Config: brute_force_inprocess_threshold          %" PRId8" \n", brute_force_inprocess_threshold);
+    APPID_LOG(nullptr, TRACE_INFO_LEVEL, "Appid Config: failed_state_expiration_secs             %" PRId32" \n", failed_state_expiration_secs);
+    APPID_LOG(nullptr, TRACE_INFO_LEVEL, "Appid Config: inspect_ooo_flows                        %s\n", inspect_ooo_flows ? "True" : "False");
 }
 
 bool OdpContext::is_appid_cpu_profiler_running()
index bb3992100a9546cacd57faba764932c7290bfec0..6729321a8db88bfa4a9ef982a442827a5ba541cb 100644 (file)
 #define MIN_BRUTE_FORCE_INPROCESS_STATE_THRESHOLD 1
 #define MAX_BRUTE_FORCE_INPROCESS_STATE_THRESHOLD 50
 
+#define MIDSTREAM_SERVICE_INSPECTION_OFF 0
+#define DEFAULT_MIDSTREAM_PKTS_BEFORE_SERVICE_FAIL 2
+#define MIN_MIDSTREAM_PKTS_BEFORE_SERVICE_FAIL 2
+#define MAX_MIDSTREAM_PKTS_BEFORE_SERVICE_FAIL 10
+
 
 enum SnortProtoIdIndex
 {
@@ -153,6 +158,7 @@ public:
     uint8_t brute_force_inprocess_threshold = DEFAULT_BRUTE_FORCE_INPROCESS_STATE_THRESHOLD;
     uint16_t max_packet_before_service_fail = DEFAULT_MAX_PKTS_BEFORE_SERVICE_FAIL;
     uint16_t max_packet_service_fail_ignore_bytes = DEFAULT_MAX_PKT_BEFORE_SERVICE_FAIL_IGNORE_BYTES;
+    uint16_t max_midstream_packet_before_service_fail = DEFAULT_MIDSTREAM_PKTS_BEFORE_SERVICE_FAIL;
     uint32_t chp_body_collection_max = 0;
     uint32_t rtmp_max_packets = 15;
     uint32_t max_tp_flow_depth = 5;
index 0d5697eabde7b561cff43728b98c671b847796e6..72d9dbd25aac9d7ef238cc4ef16a6ffaf37902c0 100644 (file)
@@ -789,6 +789,11 @@ bool AppIdSession::is_svc_taking_too_much_time() const
         init_bytes_without_reply > odp_ctxt.max_bytes_before_service_fail));
 }
 
+bool AppIdSession::is_midstream_svc_taking_too_much_time() const
+{
+    return srv_midstream_packet_inspected >= odp_ctxt.max_midstream_packet_before_service_fail;
+}
+
 void AppIdSession::delete_session_data()
 {
     api.service.reset();
index dcdf4958a24bb27540b650eeb0c9d3f6e4bcef27..7ce82510b7b1534598c6eb4d2dbe0f6c993376c2 100644 (file)
@@ -273,6 +273,7 @@ public:
     uint16_t session_packet_count = 0;
     uint16_t init_pkts_without_reply = 0;
     uint64_t init_bytes_without_reply = 0;
+    uint16_t srv_midstream_packet_inspected = 0;
     AppId first_pkt_service_id = 0;
     AppId first_pkt_payload_id = 0;
     AppId first_pkt_client_id = 0;
@@ -352,6 +353,7 @@ public:
         false : true; }
     bool is_decrypted() const { return ((flags & APPID_SESSION_DECRYPTED) == 0) ? false : true; }
     bool is_svc_taking_too_much_time() const;
+    bool is_midstream_svc_taking_too_much_time() const;
 
     AppIdFlowData* get_flow_data(unsigned id) const;
     int add_flow_data(AppIdFlowData* data, unsigned id);
index afda335797040586fa115ea02e840d6f3983e2a4..82aad224c7f6af981e70a20a2353e11647bddcf7 100644 (file)
@@ -638,7 +638,7 @@ bool ServiceDiscovery::do_service_discovery(AppIdSession& asd, Packet* p,
                 }
                 asd.service_disco_state = APPID_DISCO_STATE_STATEFUL;
             }
-            else
+            else if (asd.is_midstream_svc_taking_too_much_time())
             {
                 asd.set_session_flags(APPID_SESSION_SERVICE_DETECTED);
                 asd.service_disco_state = APPID_DISCO_STATE_FINISHED;
@@ -647,12 +647,39 @@ bool ServiceDiscovery::do_service_discovery(AppIdSession& asd, Packet* p,
                     (asd.is_tp_appid_available() or asd.get_session_flags(APPID_SESSION_NO_TPI)))
                     asd.set_payload_id(APP_ID_UNKNOWN);
             }
+            else
+            {
+                asd.service_disco_state = APPID_DISCO_STATE_STATEFUL;
+                ++asd.srv_midstream_packet_inspected;
+            }
         }
         else
         {
             asd.service_disco_state = APPID_DISCO_STATE_STATEFUL;
         }
     }
+    else if ((p->flow->get_session_flags() & SSNFLAG_MIDSTREAM) and
+        asd.service_disco_state != APPID_DISCO_STATE_FINISHED and
+        !(asd.protocol == IpProtocol::TCP and (p->ptrs.sp == 21 or p->ptrs.dp == 21) and
+            !(p->ptrs.tcph->is_fin() or p->ptrs.tcph->is_rst())))
+    {
+        if (asd.is_midstream_svc_taking_too_much_time())
+        {
+            asd.set_session_flags(APPID_SESSION_SERVICE_DETECTED);
+            asd.service_disco_state = APPID_DISCO_STATE_FINISHED;
+
+            if ((asd.get_payload_id() == APP_ID_NONE) and
+                (asd.is_tp_appid_available() or asd.get_session_flags(APPID_SESSION_NO_TPI)))
+            {
+                asd.set_payload_id(APP_ID_UNKNOWN);
+            }
+        }
+        else
+        {
+            ++asd.srv_midstream_packet_inspected;
+        }
+    }
+    
 
     if (asd.is_encrypted_oportunistic_tls_session() and asd.encrypted.service_id > 0)
     {
@@ -681,6 +708,9 @@ bool ServiceDiscovery::do_service_discovery(AppIdSession& asd, Packet* p,
         bool service_found = identify_service(asd, p, direction, change_bits) == APPID_SUCCESS;
         is_discovery_done = true;
 
+        if ((p->flow->get_session_flags() & SSNFLAG_MIDSTREAM) and service_found)
+            asd.srv_midstream_packet_inspected = 0;
+
         // Check to see if we want to stop any detectors for SIP/RTP.
         if (tp_app_id == APP_ID_SIP)
         {