1 //--------------------------------------------------------------------------
2 // Copyright (C) 2016-2023 Cisco and/or its affiliates. All rights reserved.
4 // This program is free software; you can redistribute it and/or modify it
5 // under the terms of the GNU General Public License Version 2 as published
6 // by the Free Software Foundation. You may not use, modify or distribute
7 // this program under any other version of the GNU General Public License.
9 // This program is distributed in the hope that it will be useful, but
10 // WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 // General Public License for more details.
14 // You should have received a copy of the GNU General Public License along
15 // with this program; if not, write to the Free Software Foundation, Inc.,
16 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 //--------------------------------------------------------------------------
19 // appid_api_test.cc author davis mcpherson <davmcphe@cisco.com>
25 #include "network_inspectors/appid/appid_api.cc"
29 #include "framework/data_bus.h"
30 #include "protocols/protocol_ids.h"
31 #include "pub_sub/appid_event_ids.h"
32 #include "service_inspectors/http_inspect/http_msg_header.h"
34 #include "appid_http_session.h"
35 #include "tp_appid_module_api.h"
36 #include "tp_appid_session_api.h"
38 #include "appid_mock_definitions.h"
39 #include "appid_mock_http_session.h"
40 #include "appid_mock_inspector.h"
41 #include "appid_mock_session.h"
43 #include "network_inspectors/appid/appid_peg_counts.h"
45 #include <CppUTest/CommandLineTestRunner.h>
46 #include <CppUTest/TestHarness.h>
47 #include <CppUTestExt/MockSupport.h>
49 using namespace snort
;
51 static SnortProtocolId dummy_http2_protocol_id
= 1;
52 char const* APPID_UT_ORG_UNIT
= "Google";
57 class Inspector
* InspectorManager::get_inspector(const char*, bool, const SnortConfig
*)
58 { return &dummy_appid_inspector
; }
60 Packet::Packet(bool) { }
61 Packet::~Packet() = default;
63 Packet
* DetectionEngine::get_current_packet()
69 AppIdSessionApi::AppIdSessionApi(const AppIdSession
*, const SfIp
&) :
70 StashGenericObject(STASH_GENERIC_OBJECT_APPID
) {}
73 void AppIdModule::reset_stats() {}
75 class DummyInspector
: public snort::Inspector
78 void eval(Packet
*) override
{};
81 void DataBus::publish(unsigned, unsigned, DataEvent
& event
, Flow
*)
83 AppidEvent
* appid_event
= (AppidEvent
*)&event
;
84 char* test_log
= (char*)mock().getData("test_log").getObjectPointer();
85 snprintf(test_log
, 256, "Published change_bits == %s",
86 appid_event
->get_change_bitset().to_string().c_str());
87 mock().actualCall("publish");
90 void AppIdSession::publish_appid_event(AppidChangeBits
& change_bits
, const Packet
& p
, bool, uint32_t)
92 AppidEvent
app_event(change_bits
, false, 0, this->get_api(), p
);
93 DataBus::publish(0, AppIdEventIds::ANY_CHANGE
, app_event
, p
.flow
);
96 bool SslPatternMatchers::scan_hostname(const uint8_t* server_name
, size_t, AppId
& client_id
, AppId
& payload_id
)
98 if (((const char*)server_name
) == APPID_UT_TLS_HOST
)
100 client_id
= APPID_UT_ID
+ 1;
101 payload_id
= APPID_UT_ID
+ 1;
111 bool SslPatternMatchers::scan_cname(const uint8_t* cname
, size_t, AppId
& client_id
, AppId
& payload_id
)
113 if (((const char*)cname
) == APPID_UT_TLS_HOST
)
115 client_id
= APPID_UT_ID
+ 2;
116 payload_id
= APPID_UT_ID
+ 2;
118 else if (((const char*)cname
) == APPID_UT_ORG_UNIT
)
120 client_id
= APPID_UT_ID
+ 3;
121 payload_id
= APPID_UT_ID
+ 3;
131 void ApplicationDescriptor::set_id(const Packet
&, AppIdSession
&, AppidSessionDirection
, AppId
, AppidChangeBits
&) { }
133 const char* AppInfoManager::get_app_name(AppId
)
135 return test_app_name
;
138 AppId
AppInfoManager::get_appid_by_name(const char*)
143 AppId
AppIdSessionApi::get_service_app_id() const
145 return application_ids
[APP_PROTOID_SERVICE
];
148 AppId
AppIdSessionApi::get_client_app_id(uint32_t) const
150 return application_ids
[APP_PROTOID_CLIENT
];
153 AppId
AppIdSessionApi::get_payload_app_id(uint32_t) const
155 return application_ids
[APP_PROTOID_PAYLOAD
];
158 void AppIdSession::set_ss_application_ids(AppId service_id
, AppId client_id
, AppId payload_id
,
159 AppId misc_id
, AppId referred_id
, AppidChangeBits
& change_bits
)
161 if (api
.application_ids
[APP_PROTOID_SERVICE
] != service_id
)
163 api
.application_ids
[APP_PROTOID_SERVICE
] = service_id
;
164 change_bits
.set(APPID_SERVICE_BIT
);
166 if (api
.application_ids
[APP_PROTOID_CLIENT
] != client_id
)
168 api
.application_ids
[APP_PROTOID_CLIENT
] = client_id
;
169 change_bits
.set(APPID_CLIENT_BIT
);
171 if (api
.application_ids
[APP_PROTOID_PAYLOAD
] != payload_id
)
173 api
.application_ids
[APP_PROTOID_PAYLOAD
] = payload_id
;
174 change_bits
.set(APPID_PAYLOAD_BIT
);
176 if (api
.application_ids
[APP_PROTOID_MISC
] != misc_id
)
178 api
.application_ids
[APP_PROTOID_MISC
] = misc_id
;
179 change_bits
.set(APPID_MISC_BIT
);
181 if (api
.application_ids
[APP_PROTOID_REFERRED
] != referred_id
)
183 api
.application_ids
[APP_PROTOID_REFERRED
] = referred_id
;
184 change_bits
.set(APPID_REFERRED_BIT
);
188 void AppIdSession::set_ss_application_ids(AppId client_id
, AppId payload_id
,
189 AppidChangeBits
& change_bits
)
191 if (api
.application_ids
[APP_PROTOID_CLIENT
] != client_id
)
193 api
.application_ids
[APP_PROTOID_CLIENT
] = client_id
;
194 change_bits
.set(APPID_CLIENT_BIT
);
196 if (api
.application_ids
[APP_PROTOID_PAYLOAD
] != payload_id
)
198 api
.application_ids
[APP_PROTOID_PAYLOAD
] = payload_id
;
199 change_bits
.set(APPID_PAYLOAD_BIT
);
203 AppIdHttpSession
* AppIdSession::get_http_session(uint32_t) const { return nullptr; }
205 Flow
* flow
= nullptr;
206 AppIdSession
* mock_session
= nullptr;
208 TEST_GROUP(appid_api
)
211 void setup() override
213 mock_init_appid_pegs();
215 mock_session
= new AppIdSession(IpProtocol::TCP
, &ip
, 1492, dummy_appid_inspector
,
216 dummy_appid_inspector
.get_ctxt().get_odp_ctxt(), 0, 0);
217 pkt_thread_odp_ctxt
= &mock_session
->get_odp_ctxt();
219 flow
->set_flow_data(mock_session
);
220 mock().setDataObject("test_log", "char", test_log
);
223 void teardown() override
227 mock_cleanup_appid_pegs();
228 delete &mock_session
->get_api();
233 TEST(appid_api
, get_application_name
)
236 AppIdContext
ctxt(config
);
237 const char* app_name
= appid_api
.get_application_name(1066, ctxt
.get_odp_ctxt());
238 STRCMP_EQUAL(app_name
, test_app_name
);
241 TEST(appid_api
, get_application_id
)
244 AppIdContext
ctxt(config
);
245 AppId id
= appid_api
.get_application_id(test_app_name
, ctxt
);
246 CHECK_EQUAL(id
, 1492);
249 TEST(appid_api
, ssl_app_group_id_lookup
)
251 mock().expectNCalls(6, "publish");
252 AppId service
, client
, payload
= APP_ID_NONE
;
255 AppidChangeBits change_bits
;
256 mock_session
->set_ss_application_ids(APPID_UT_ID
, APPID_UT_ID
, APPID_UT_ID
,
257 APPID_UT_ID
, APPID_UT_ID
, change_bits
);
258 val
= appid_api
.ssl_app_group_id_lookup(flow
, nullptr, nullptr, nullptr, nullptr,
259 false, service
, client
, payload
);
261 CHECK_EQUAL(service
, APPID_UT_ID
);
262 CHECK_EQUAL(client
, APPID_UT_ID
);
263 CHECK_EQUAL(payload
, APPID_UT_ID
);
264 STRCMP_EQUAL("Published change_bits == 00000000000000000000", test_log
);
266 // Server name based detection
267 service
= APP_ID_NONE
;
268 client
= APP_ID_NONE
;
269 payload
= APP_ID_NONE
;
270 val
= appid_api
.ssl_app_group_id_lookup(flow
, (const char*)APPID_UT_TLS_HOST
, (const char*)APPID_UT_TLS_HOST
,
271 (const char*)APPID_UT_TLS_HOST
, (const char*)APPID_UT_TLS_HOST
, false, service
, client
, payload
);
273 CHECK_EQUAL(client
, APPID_UT_ID
+ 1);
274 CHECK_EQUAL(payload
, APPID_UT_ID
+ 1);
275 STRCMP_EQUAL(mock_session
->tsession
->get_tls_host(), APPID_UT_TLS_HOST
);
276 STRCMP_EQUAL(mock_session
->tsession
->get_tls_first_alt_name(), APPID_UT_TLS_HOST
);
277 STRCMP_EQUAL(mock_session
->tsession
->get_tls_cname(), APPID_UT_TLS_HOST
);
278 STRCMP_EQUAL("Published change_bits == 00000000000100011000", test_log
);
280 // Common name based detection
281 mock_session
->tsession
->set_tls_host("www.cisco.com", 13, change_bits
);
282 mock_session
->tsession
->set_tls_cname("www.cisco.com", 13, change_bits
);
283 mock_session
->tsession
->set_tls_org_unit("Cisco", 5);
284 STRCMP_EQUAL(mock_session
->tsession
->get_tls_host(), "www.cisco.com");
285 STRCMP_EQUAL(mock_session
->tsession
->get_tls_cname(), "www.cisco.com");
286 STRCMP_EQUAL(mock_session
->tsession
->get_tls_org_unit(), "Cisco");
287 val
= appid_api
.ssl_app_group_id_lookup(flow
, (const char*)"www.google.com",
288 nullptr, (const char*)APPID_UT_TLS_HOST
, nullptr, false, service
, client
, payload
);
290 CHECK_EQUAL(client
, APPID_UT_ID
+ 2);
291 CHECK_EQUAL(payload
, APPID_UT_ID
+ 2);
292 STRCMP_EQUAL(mock_session
->tsession
->get_tls_host(), APPID_UT_TLS_HOST
);
293 STRCMP_EQUAL(mock_session
->tsession
->get_tls_cname(), APPID_UT_TLS_HOST
);
294 STRCMP_EQUAL(mock_session
->tsession
->get_tls_org_unit(), "Cisco");
295 STRCMP_EQUAL("Published change_bits == 00000000000100011000", test_log
);
297 // First alt name based detection
299 mock_session
->tsession
->set_tls_host("", 0, change_bits
);
300 val
= appid_api
.ssl_app_group_id_lookup(flow
, nullptr, (const char*)APPID_UT_TLS_HOST
,
301 nullptr, nullptr, false, service
, client
, payload
);
303 CHECK_EQUAL(client
, APPID_UT_ID
+ 1);
304 CHECK_EQUAL(payload
, APPID_UT_ID
+ 1);
305 STRCMP_EQUAL(mock_session
->tsession
->get_tls_host(), APPID_UT_TLS_HOST
);
306 STRCMP_EQUAL(mock_session
->tsession
->get_tls_first_alt_name(), APPID_UT_TLS_HOST
);
307 STRCMP_EQUAL("Published change_bits == 00000000000100011000", test_log
);
309 // Org unit based detection
312 mock_session
->tsession
->set_tls_host("", 0, change_bits
);
313 val
= appid_api
.ssl_app_group_id_lookup(flow
, (const char*)(host
.c_str()), nullptr,
314 nullptr, (const char*)APPID_UT_ORG_UNIT
, false, service
, client
, payload
);
316 CHECK_EQUAL(client
, APPID_UT_ID
+ 3);
317 CHECK_EQUAL(payload
, APPID_UT_ID
+ 3);
318 STRCMP_EQUAL(mock_session
->tsession
->get_tls_org_unit(), APPID_UT_ORG_UNIT
);
319 STRCMP_EQUAL("Published change_bits == 00000000000000011000", test_log
);
321 // Override client id found by SSL pattern matcher with the client id provided by
322 // Encrypted Visibility Engine if available
323 service
= APP_ID_NONE
;
324 client
= APP_ID_NONE
;
325 payload
= APP_ID_NONE
;
327 mock_session
->tsession
->set_tls_host("", 0, change_bits
);
328 mock_session
->set_client_id(APP_ID_NONE
);
329 mock_session
->set_eve_client_app_id(APPID_UT_ID
+ 100);
330 val
= appid_api
.ssl_app_group_id_lookup(flow
, (const char*)APPID_UT_TLS_HOST
, (const char*)APPID_UT_TLS_HOST
,
331 (const char*)APPID_UT_TLS_HOST
, (const char*)APPID_UT_TLS_HOST
, false, service
, client
, payload
);
333 CHECK_EQUAL(client
, APPID_UT_ID
+ 100);
334 CHECK_EQUAL(payload
, APPID_UT_ID
+ 1);
335 STRCMP_EQUAL(mock_session
->tsession
->get_tls_host(), APPID_UT_TLS_HOST
);
336 STRCMP_EQUAL(mock_session
->tsession
->get_tls_first_alt_name(), APPID_UT_TLS_HOST
);
337 STRCMP_EQUAL(mock_session
->tsession
->get_tls_cname(), APPID_UT_TLS_HOST
);
338 STRCMP_EQUAL("Published change_bits == 00000000000100011000", test_log
);
340 mock().checkExpectations();
342 // When appid session is not existing
343 // 1. Match based on server name
345 flow
->set_flow_data(nullptr);
346 service
= APP_ID_NONE
;
347 client
= APP_ID_NONE
;
348 payload
= APP_ID_NONE
;
349 val
= appid_api
.ssl_app_group_id_lookup(f
, (const char*)APPID_UT_TLS_HOST
, (const char*)APPID_UT_TLS_HOST
,
350 (const char*)APPID_UT_TLS_HOST
, (const char*)APPID_UT_TLS_HOST
, false, service
, client
, payload
);
352 CHECK_EQUAL(client
, APPID_UT_ID
+ 1);
353 CHECK_EQUAL(payload
, APPID_UT_ID
+ 1);
355 // 2. First alt name match
356 client
= APP_ID_NONE
;
357 payload
= APP_ID_NONE
;
358 val
= appid_api
.ssl_app_group_id_lookup(f
, nullptr, (const char*)APPID_UT_TLS_HOST
,
359 (const char*)APPID_UT_TLS_HOST
, (const char*)APPID_UT_TLS_HOST
, false, service
, client
, payload
);
361 CHECK_EQUAL(client
, APPID_UT_ID
+ 1);
362 CHECK_EQUAL(payload
, APPID_UT_ID
+ 1);
365 client
= APP_ID_NONE
;
366 payload
= APP_ID_NONE
;
367 val
= appid_api
.ssl_app_group_id_lookup(f
, nullptr, nullptr, (const char*)APPID_UT_TLS_HOST
,
368 (const char*)APPID_UT_TLS_HOST
, false, service
, client
, payload
);
370 CHECK_EQUAL(client
, APPID_UT_ID
+ 2);
371 CHECK_EQUAL(payload
, APPID_UT_ID
+ 2);
374 client
= APP_ID_NONE
;
375 payload
= APP_ID_NONE
;
376 val
= appid_api
.ssl_app_group_id_lookup(f
, nullptr, nullptr, nullptr, (const char*)APPID_UT_TLS_HOST
,
377 false, service
, client
, payload
);
379 CHECK_EQUAL(client
, APPID_UT_ID
+ 2);
380 CHECK_EQUAL(payload
, APPID_UT_ID
+ 2);
385 TEST(appid_api
, is_inspection_needed
)
387 DummyInspector inspector
;
388 inspector
.set_service(dummy_http2_protocol_id
);
389 dummy_appid_inspector
.get_ctxt().config
.snort_proto_ids
[PROTO_INDEX_HTTP2
] =
390 dummy_http2_protocol_id
;
392 CHECK_TRUE(appid_api
.is_inspection_needed(inspector
));
394 inspector
.set_service(dummy_http2_protocol_id
+ 1);
395 CHECK_FALSE(appid_api
.is_inspection_needed(inspector
));
398 TEST(appid_api
, is_service_http_type
)
400 CHECK_TRUE(appid_api
.is_service_http_type(APP_ID_HTTP
));
401 CHECK_TRUE(appid_api
.is_service_http_type(APP_ID_HTTPS
));
402 CHECK_TRUE(appid_api
.is_service_http_type(APP_ID_SMTPS
));
403 CHECK_FALSE(appid_api
.is_service_http_type(APP_ID_SMTP
));
406 TEST(appid_api
, get_appid_detector_directory
)
408 STRCMP_EQUAL(appid_api
.get_appid_detector_directory(), "/path/to/appid/detectors/");
411 int main(int argc
, char** argv
)
413 int rc
= CommandLineTestRunner::RunAllTests(argc
, argv
);