From: Sreeja Athirkandathil Narayanan (sathirka) Date: Wed, 16 Aug 2023 20:12:17 +0000 (+0000) Subject: Pull request #3955: appid: prefer eve client over appid detected client after decrypt... X-Git-Tag: 3.1.69.0~9 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=a5a2576125322301fb3ae70d8f5573919706f1ca;p=thirdparty%2Fsnort3.git Pull request #3955: appid: prefer eve client over appid detected client after decryption and use appid detected client version if eve client equals appid client Merge in SNORT/snort3 from ~SATHIRKA/snort3:decrypted_http to master Squashed commit of the following: commit 2e2b0425f9228cea79a2023959c9e71bee040923 Author: Sreeja Athirkandathil Narayanan 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 --- diff --git a/src/network_inspectors/appid/appid_session.cc b/src/network_inspectors/appid/appid_session.cc index ac655792e..f3f31c446 100644 --- a/src/network_inspectors/appid/appid_session.cc +++ b/src/network_inspectors/appid/appid_session.cc @@ -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(); diff --git a/src/network_inspectors/appid/appid_session_api.cc b/src/network_inspectors/appid/appid_session_api.cc index 8c80649f1..091377351 100644 --- a/src/network_inspectors/appid/appid_session_api.cc +++ b/src/network_inspectors/appid/appid_session_api.cc @@ -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) diff --git a/src/network_inspectors/appid/appid_session_api.h b/src/network_inspectors/appid/appid_session_api.h index 684feda22..c79b0e6a0 100644 --- a/src/network_inspectors/appid/appid_session_api.h +++ b/src/network_inspectors/appid/appid_session_api.h @@ -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; diff --git a/src/network_inspectors/appid/test/appid_session_api_test.cc b/src/network_inspectors/appid/test/appid_session_api_test.cc index 750c0d637..c6e53ac38 100644 --- a/src/network_inspectors/appid/test/appid_session_api_test.cc +++ b/src/network_inspectors/appid/test/appid_session_api_test.cc @@ -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;