]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
Pull request #3955: appid: prefer eve client over appid detected client after decrypt...
authorSreeja Athirkandathil Narayanan (sathirka) <sathirka@cisco.com>
Wed, 16 Aug 2023 20:12:17 +0000 (20:12 +0000)
committerChris Sherwin (chsherwi) <chsherwi@cisco.com>
Wed, 16 Aug 2023 20:12:17 +0000 (20:12 +0000)
Merge in SNORT/snort3 from ~SATHIRKA/snort3:decrypted_http to master

Squashed commit of the following:

commit 2e2b0425f9228cea79a2023959c9e71bee040923
Author: Sreeja Athirkandathil Narayanan <sathirka@cisco.com>
Date:   Wed May 24 20:01:09 2023 -0400

    appid: prefer eve client over appid detected client after decryption and use appid detected client version if eve client equals appid client

src/network_inspectors/appid/appid_session.cc
src/network_inspectors/appid/appid_session_api.cc
src/network_inspectors/appid/appid_session_api.h
src/network_inspectors/appid/test/appid_session_api_test.cc

index ac655792e551e246a16cea448f9f07025e395e38..f3f31c4464ad83d2226831fd3d051e5fef0cabdb 100644 (file)
@@ -858,11 +858,17 @@ AppId AppIdSession::pick_ss_misc_app_id() const
 
 AppId AppIdSession::pick_ss_client_app_id() const
 {
-    if (api.service.get_id() == APP_ID_HTTP2 or
-        (api.service.get_id() == APP_ID_HTTP3 and !api.hsessions.empty()))
+    bool prefer_eve_client = use_eve_client_app_id();
+    if (api.service.get_id() == APP_ID_HTTP2 and !prefer_eve_client)
+    {
+        api.client.set_eve_client_app_detect_type(CLIENT_APP_DETECT_APPID);
+        return APP_ID_NONE;
+    }
+
+    if (api.service.get_id() == APP_ID_HTTP3 and !api.hsessions.empty())
         return APP_ID_NONE;
 
-    if (use_eve_client_app_id())
+    if (prefer_eve_client)
     {
         api.client.set_eve_client_app_detect_type(CLIENT_APP_DETECT_TLS_FP);
         return api.client.get_eve_client_app_id();
index 8c80649f15763b23b77e4f0c9406ca3f165cc551..09137735164a7bab8472ee3dfa6dcff92cad562b 100644 (file)
@@ -83,12 +83,21 @@ AppId AppIdSessionApi::get_misc_app_id(uint32_t stream_index) const
     return APP_ID_NONE;
 }
 
+bool AppIdSessionApi::prefer_eve_client_over_appid_http_client() const
+{
+    return ((client.get_eve_client_app_id() > APP_ID_NONE) and pkt_thread_odp_ctxt
+        and pkt_thread_odp_ctxt->eve_http_client);
+}
+
 AppId AppIdSessionApi::get_client_app_id(uint32_t stream_index) const
 {
-    if (get_service_app_id() == APP_ID_HTTP2 or get_service_app_id() == APP_ID_HTTP3)
+    AppId service_id = get_service_app_id();
+    if (service_id == APP_ID_HTTP2 or service_id == APP_ID_HTTP3)
     {
         if ((stream_index != 0) and (stream_index >= get_hsessions_size()))
             return APP_ID_NONE;
+        else if (service_id == APP_ID_HTTP2 and prefer_eve_client_over_appid_http_client())
+            return application_ids[APP_PROTOID_CLIENT];
         else if (AppIdHttpSession* hsession = get_hsession(stream_index))
             return hsession->client.get_id();
         else if ((get_service_app_id() == APP_ID_HTTP3) and (stream_index == 0))
@@ -135,7 +144,8 @@ AppId AppIdSessionApi::get_referred_app_id(uint32_t stream_index) const
 void AppIdSessionApi::get_app_id(AppId& service, AppId& client,
     AppId& payload, AppId& misc, AppId& referred, uint32_t stream_index) const
 {
-    if (get_service_app_id() == APP_ID_HTTP2 or get_service_app_id() == APP_ID_HTTP3)
+    AppId service_id = get_service_app_id();
+    if (service_id == APP_ID_HTTP2 or service_id == APP_ID_HTTP3)
     {
         if ((stream_index != 0) and (stream_index >= get_hsessions_size()))
         {
@@ -144,8 +154,11 @@ void AppIdSessionApi::get_app_id(AppId& service, AppId& client,
         }
         else if (AppIdHttpSession* hsession = get_hsession(stream_index))
         {
-            service = get_service_app_id();
-            client = hsession->client.get_id();
+            service = service_id;
+            if (service_id == APP_ID_HTTP2 and prefer_eve_client_over_appid_http_client())
+                client = application_ids[APP_PROTOID_CLIENT];
+            else
+                client = hsession->client.get_id();
             payload = hsession->payload.get_id();
             misc = hsession->misc_app_id;
             referred = hsession->referred_payload_app_id;
@@ -160,7 +173,8 @@ void AppIdSessionApi::get_app_id(AppId& service, AppId& client,
 void AppIdSessionApi::get_app_id(AppId* service, AppId* client,
     AppId* payload, AppId* misc, AppId* referred, uint32_t stream_index) const
 {
-    if (get_service_app_id() == APP_ID_HTTP2 or get_service_app_id() == APP_ID_HTTP3)
+    AppId service_id = get_service_app_id();
+    if (service_id == APP_ID_HTTP2 or service_id == APP_ID_HTTP3)
     {
         if ((stream_index != 0) and (stream_index >= get_hsessions_size()))
         {
@@ -179,9 +193,14 @@ void AppIdSessionApi::get_app_id(AppId* service, AppId* client,
         else if (AppIdHttpSession* hsession = get_hsession(stream_index))
         {
             if (service)
-                *service = get_service_app_id();
+                *service = service_id;
             if (client)
-                *client = hsession->client.get_id();
+            {
+                if (service_id == APP_ID_HTTP2 and prefer_eve_client_over_appid_http_client())
+                    *client = application_ids[APP_PROTOID_CLIENT];
+                else
+                    *client = hsession->client.get_id();
+            }
             if (payload)
                 *payload = hsession->payload.get_id();
             if (misc)
@@ -192,9 +211,14 @@ void AppIdSessionApi::get_app_id(AppId* service, AppId* client,
         }
     }
     if (service)
-        *service = get_service_app_id();
+        *service = service_id;
     if (client)
-        *client = get_client_app_id();
+    {
+        if (service_id == APP_ID_HTTP2 and prefer_eve_client_over_appid_http_client())
+            *client = application_ids[APP_PROTOID_CLIENT];
+        else
+            *client = get_client_app_id();
+    }
     if (payload)
         *payload = get_payload_app_id();
     if (misc)
@@ -263,15 +287,22 @@ bool AppIdSessionApi::is_appid_available(uint32_t stream_index) const
 
 const char* AppIdSessionApi::get_client_info(uint32_t stream_index) const
 {
-    if (client.get_eve_client_app_id() > APP_ID_NONE and pkt_thread_odp_ctxt and
-        pkt_thread_odp_ctxt->eve_http_client)
-        return client.get_version();
     if (uint32_t num_hsessions = get_hsessions_size())
     {
         if (stream_index >= num_hsessions)
             return nullptr;
         else if (AppIdHttpSession* hsession = get_hsession(stream_index))
-            return hsession->client.get_version();
+        {
+            if (prefer_eve_client_over_appid_http_client())
+            {
+                if (hsession->client.get_id() == client.get_eve_client_app_id())
+                    return hsession->client.get_version();
+                else
+                    return nullptr;
+            }
+            else
+                return hsession->client.get_version();
+        }
     }
     else if (stream_index == 0)
         return client.get_version();
@@ -437,7 +468,10 @@ void AppIdSessionApi::get_first_stream_app_ids(AppId& service_id, AppId& client_
     }
     else if (AppIdHttpSession* hsession = get_hsession(0))
     {
-        client_id = hsession->client.get_id();
+        if (service_id == APP_ID_HTTP2 and prefer_eve_client_over_appid_http_client())
+            client_id = application_ids[APP_PROTOID_CLIENT];
+        else
+            client_id = hsession->client.get_id();
         payload_id = hsession->payload.get_id();
         misc_id = hsession->misc_app_id;
     }
@@ -466,7 +500,10 @@ void AppIdSessionApi::get_first_stream_app_ids(AppId& service_id, AppId& client_
     }
     else if (AppIdHttpSession* hsession = get_hsession(0))
     {
-        client_id = hsession->client.get_id();
+        if (service_id == APP_ID_HTTP2 and prefer_eve_client_over_appid_http_client())
+            client_id = application_ids[APP_PROTOID_CLIENT];
+        else
+            client_id = hsession->client.get_id();
         payload_id = hsession->payload.get_id();
     }
     else if (service_id == APP_ID_HTTP3)
index 684feda22c97c204fd55414bba2b5476ac020475..c79b0e6a0a250fb9409ecb08942c2bca9100a8a4 100644 (file)
@@ -194,6 +194,7 @@ private:
     void set_application_ids_service(AppId service_id, AppidChangeBits& change_bits, Flow& flow);
     void set_netbios_name(AppidChangeBits& change_bits, const char* name);
     void set_netbios_domain(AppidChangeBits& change_bits, const char* domain);
+    bool prefer_eve_client_over_appid_http_client() const;
 
     AppIdHttpSession* get_hsession(uint32_t stream_index = 0) const;
 
index 750c0d6370ef79c09c99d2a0d2307215ca75cc64..c6e53ac38bef7611e5b98c2f9c5974cd7bf66426 100644 (file)
@@ -110,6 +110,36 @@ TEST(appid_session_api, get_client_app_id)
     CHECK_EQUAL(APP_ID_NONE, id);
 }
 
+TEST(appid_session_api, get_client_app_id_with_eve_for_http2)
+{
+    SfIp ip;
+    AppIdSession asd(IpProtocol::TCP, &ip, 1492, dummy_appid_inspector, odpctxt);
+    asd.flow = &flow;
+    AppidChangeBits change_bits;
+    asd.set_ss_application_ids(APP_ID_HTTP2, APPID_UT_ID, APPID_UT_ID, APPID_UT_ID, APPID_UT_ID, change_bits);
+
+    // Service id is HTTP2 but hsession hasn't been created yet. For example, after SSL decryption,
+    // third-party returns HTTP2 but http2 inspector hasn't given appid the metadata
+    AppId id = asd.get_api().get_client_app_id();
+    CHECK_EQUAL(id, APP_ID_NONE);
+
+    // hsession is created and eve appid is available
+    AppId eve_client = APPID_UT_ID + 100;
+    asd.create_http_session();
+    asd.set_eve_client_app_id(eve_client);
+    asd.get_odp_ctxt().eve_http_client = true;
+    asd.set_ss_application_ids(APP_ID_HTTP2, eve_client, APPID_UT_ID, APPID_UT_ID, APPID_UT_ID, change_bits);
+
+    id = asd.get_api().get_client_app_id(0);
+    CHECK_EQUAL(eve_client, id);
+
+    // invalid stream id
+    id = asd.get_api().get_client_app_id(3);
+    CHECK_EQUAL(APP_ID_NONE, id);
+
+    delete &asd.get_api();
+}
+
 TEST(appid_session_api, get_payload_app_id)
 {
     AppId id = mock_session->get_api().get_payload_app_id();
@@ -159,6 +189,146 @@ TEST(appid_session_api, get_app_id)
     delete &asd.get_api();
 }
 
+TEST(appid_session_api, get_app_id_with_eve_for_http2)
+{
+    SfIp ip;
+    AppIdSession asd(IpProtocol::TCP, &ip, 1492, dummy_appid_inspector, odpctxt);
+    asd.flow = &flow;
+    AppidChangeBits change_bits;
+    asd.set_application_ids_service(APP_ID_HTTP2, change_bits);
+
+    // invalid stream id
+    AppId service, client, payload, misc, referred;
+    asd.get_api().get_app_id(service, client, payload, misc, referred, 10);
+    CHECK_EQUAL(service, APP_ID_UNKNOWN);
+    CHECK_EQUAL(client, APP_ID_UNKNOWN);
+    CHECK_EQUAL(payload, APP_ID_UNKNOWN);
+    CHECK_EQUAL(misc, APP_ID_UNKNOWN);
+    CHECK_EQUAL(referred, APP_ID_UNKNOWN);
+
+    service = client = payload = misc = referred = APPID_UT_ID;
+    asd.get_api().get_app_id(&service, &client, &payload, &misc, &referred, 10);
+    CHECK_EQUAL(service, APP_ID_UNKNOWN);
+    CHECK_EQUAL(client, APP_ID_UNKNOWN);
+    CHECK_EQUAL(payload, APP_ID_UNKNOWN);
+    CHECK_EQUAL(misc, APP_ID_UNKNOWN);
+    CHECK_EQUAL(referred, APP_ID_UNKNOWN);
+
+    // hsession not created yet and eve appid is not available
+    service = client = payload = misc = referred = APP_ID_NONE;
+    asd.get_api().get_app_id(service, client, payload, misc, referred, 0);
+    CHECK_EQUAL(service, APP_ID_HTTP2);
+    CHECK_EQUAL(client, APP_ID_NONE);
+    CHECK_EQUAL(payload, APP_ID_NONE);
+    CHECK_EQUAL(misc, APP_ID_NONE);
+    CHECK_EQUAL(referred, APP_ID_NONE);
+
+    service = client = payload = misc = referred = APPID_UT_ID;
+    asd.get_api().get_app_id(&service, &client, &payload, &misc, &referred, 0);
+    CHECK_EQUAL(service, APP_ID_HTTP2);
+    CHECK_EQUAL(client, APP_ID_NONE);
+    CHECK_EQUAL(payload, APP_ID_NONE);
+    CHECK_EQUAL(misc, APP_ID_NONE);
+    CHECK_EQUAL(referred, APP_ID_NONE);
+
+    // hsession not created yet and eve appid is available
+    AppId eve_client = APPID_UT_ID + 100;
+    asd.set_eve_client_app_id(eve_client);
+    asd.get_odp_ctxt().eve_http_client = true;
+    asd.set_ss_application_ids(APP_ID_HTTP2, eve_client, APP_ID_NONE, APP_ID_NONE, APP_ID_NONE, change_bits);
+
+    service = client = payload = misc = referred = APP_ID_NONE;
+    asd.get_api().get_app_id(&service, &client, &payload, &misc, &referred, 0);
+    CHECK_EQUAL(service, APP_ID_HTTP2);
+    CHECK_EQUAL(client, eve_client);
+    CHECK_EQUAL(payload, APP_ID_NONE);
+    CHECK_EQUAL(misc, APP_ID_NONE);
+    CHECK_EQUAL(referred, APP_ID_NONE);
+
+    // hsession is created and eve appid is not available
+    AppIdHttpSession* hsession = asd.create_http_session();
+    asd.set_eve_client_app_id(APP_ID_NONE);
+    asd.set_ss_application_ids(APP_ID_HTTP2, hsession->client.get_id(), APP_ID_NONE, APP_ID_NONE, APP_ID_NONE, change_bits);
+
+    service = client = payload = misc = referred = APP_ID_NONE;
+    asd.get_api().get_app_id(service, client, payload, misc, referred, 0);
+    CHECK_EQUAL(service, APP_ID_HTTP2);
+    CHECK_EQUAL(client, hsession->client.get_id());
+    CHECK_EQUAL(payload, hsession->payload.get_id());
+    CHECK_EQUAL(misc, hsession->misc_app_id);
+    CHECK_EQUAL(referred, hsession->referred_payload_app_id);
+
+    // hsession is created and eve appid is available
+    asd.set_eve_client_app_id(eve_client);
+    asd.set_ss_application_ids(APP_ID_HTTP2, eve_client, APP_ID_NONE, APP_ID_NONE, APP_ID_NONE, change_bits);
+
+    service = client = payload = misc = referred = APP_ID_NONE;
+    asd.get_api().get_app_id(service, client, payload, misc, referred, 0);
+    CHECK_EQUAL(service, APP_ID_HTTP2);
+    CHECK_EQUAL(client, eve_client);
+    CHECK_EQUAL(payload, hsession->payload.get_id());
+    CHECK_EQUAL(misc, hsession->misc_app_id);
+    CHECK_EQUAL(referred, hsession->referred_payload_app_id);
+
+    service = client = payload = misc = referred = APPID_UT_ID + 1;
+    asd.get_api().get_app_id(&service, &client, &payload, &misc, &referred, 0);
+
+    CHECK_EQUAL(service, APP_ID_HTTP2);
+    CHECK_EQUAL(client, eve_client);
+    CHECK_EQUAL(payload, hsession->payload.get_id());
+    CHECK_EQUAL(misc, hsession->misc_app_id);
+    CHECK_EQUAL(referred, hsession->referred_payload_app_id);
+
+    delete &asd.get_api();
+}
+
+TEST(appid_session_api, get_first_stream_appids_for_http2)
+{
+    SfIp ip;
+    AppIdSession asd(IpProtocol::TCP, &ip, 1492, dummy_appid_inspector, odpctxt);
+    asd.flow = &flow;
+    AppidChangeBits change_bits;
+    asd.set_application_ids_service(APP_ID_HTTP2, change_bits);
+
+    // hsession is created, eve appid not available
+    AppIdHttpSession* hsession = asd.create_http_session();
+
+    AppId service, client, payload, misc;
+    asd.get_api().get_first_stream_app_ids(service, client, payload, misc);
+    CHECK_EQUAL(service, APP_ID_HTTP2);
+    CHECK_EQUAL(client, hsession->client.get_id());
+    CHECK_EQUAL(payload, hsession->payload.get_id());
+    CHECK_EQUAL(misc, hsession->misc_app_id);
+
+    service = client = payload = APP_ID_NONE;
+    asd.get_api().get_first_stream_app_ids(service, client, payload);
+    CHECK_EQUAL(service, APP_ID_HTTP2);
+    CHECK_EQUAL(client, hsession->client.get_id());
+    CHECK_EQUAL(payload, hsession->payload.get_id());
+
+    // hsession is created, eve appid available
+    AppId eve_client = APPID_UT_ID + 100;
+    asd.set_eve_client_app_id(eve_client);
+    asd.get_odp_ctxt().eve_http_client = true;
+    asd.set_ss_application_ids(APP_ID_HTTP2, eve_client, APP_ID_NONE, APP_ID_NONE, APP_ID_NONE, change_bits);
+
+    service = client = payload = misc = APP_ID_NONE;
+    asd.get_api().get_first_stream_app_ids(service, client, payload, misc);
+
+    CHECK_EQUAL(service, APP_ID_HTTP2);
+    CHECK_EQUAL(client, eve_client);
+    CHECK_EQUAL(payload, hsession->client.get_id());
+    CHECK_EQUAL(misc, hsession->misc_app_id);
+
+    service = client = payload = APP_ID_NONE;
+    asd.get_api().get_first_stream_app_ids(service, client, payload);
+    CHECK_EQUAL(service, APP_ID_HTTP2);
+    CHECK_EQUAL(client, eve_client);
+    CHECK_EQUAL(payload, hsession->payload.get_id());
+
+    delete &asd.get_api();
+}
+
 TEST(appid_session_api, get_tls_host)
 {
     AppidChangeBits change_bits;
@@ -259,6 +429,50 @@ TEST(appid_session_api, get_client_info)
     val = mock_session->get_api().get_client_info(2);
     STRCMP_EQUAL(nullptr, val);
 }
+
+TEST(appid_session_api, get_client_info_http2)
+{
+    SfIp ip;
+    AppIdSession asd(IpProtocol::TCP, &ip, 1492, dummy_appid_inspector, odpctxt);
+    asd.flow = &flow;
+    AppidChangeBits change_bits;
+    asd.set_ss_application_ids(APP_ID_HTTP2, APPID_UT_ID + 1, APPID_UT_ID, APPID_UT_ID, APPID_UT_ID, change_bits);
+    asd.get_odp_ctxt().eve_http_client = true;
+
+    const char* val;
+    AppId client;
+    // both eve client and hsession not available - default client version in appid session is used.
+    val = asd.get_api().get_client_info();
+    STRCMP_EQUAL(APPID_UT_CLIENT_VERSION, val);
+    client = asd.get_api().get_client_app_id();
+    CHECK_EQUAL(client, APP_ID_NONE);
+
+    // hsession is available. eve client not equals hsession client id - eve client = APPID_UT_ID + 100 and
+    // hsession client id is APPID_UT_ID; so client version is not used.
+    AppId eve_client = APPID_UT_ID + 100;
+    asd.set_eve_client_app_id(eve_client);
+    asd.set_ss_application_ids(APP_ID_HTTP2, eve_client, APPID_UT_ID, APPID_UT_ID, APPID_UT_ID, change_bits);
+    AppIdHttpSession* hsession = asd.create_http_session();
+    hsession->client.set_version("TEST_VERSION");
+
+    val = asd.get_api().get_client_info();
+    STRCMP_EQUAL(nullptr, val);
+    client = asd.get_api().get_client_app_id();
+    CHECK_EQUAL(client, eve_client);
+
+    // eve client equals hsession client id
+    eve_client = APPID_UT_ID + 200;
+    asd.set_eve_client_app_id(eve_client);
+    hsession->client.set_id(eve_client);
+    asd.set_ss_application_ids(APP_ID_HTTP2, eve_client, APPID_UT_ID, APPID_UT_ID, APPID_UT_ID, change_bits);
+    val = asd.get_api().get_client_info();
+    STRCMP_EQUAL("TEST_VERSION", val);
+    client = asd.get_api().get_client_app_id();
+    CHECK_EQUAL(client, eve_client);
+
+    delete &asd.get_api();
+}
+
 TEST(appid_session_api, get_http_session)
 {
     const AppIdHttpSession* val;