]> git.ipfire.org Git - thirdparty/snort3.git/blob - src/network_inspectors/appid/test/appid_api_test.cc
Pull request #4152: flow: Add tenant ID to FlowKey
[thirdparty/snort3.git] / src / network_inspectors / appid / test / appid_api_test.cc
1 //--------------------------------------------------------------------------
2 // Copyright (C) 2016-2023 Cisco and/or its affiliates. All rights reserved.
3 //
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.
8 //
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.
13 //
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 //--------------------------------------------------------------------------
18
19 // appid_api_test.cc author davis mcpherson <davmcphe@cisco.com>
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include "network_inspectors/appid/appid_api.cc"
26
27 #include <string>
28
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"
33
34 #include "appid_http_session.h"
35 #include "tp_appid_module_api.h"
36 #include "tp_appid_session_api.h"
37
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"
42
43 #include "network_inspectors/appid/appid_peg_counts.h"
44
45 #include <CppUTest/CommandLineTestRunner.h>
46 #include <CppUTest/TestHarness.h>
47 #include <CppUTestExt/MockSupport.h>
48
49 using namespace snort;
50
51 static SnortProtocolId dummy_http2_protocol_id = 1;
52 char const* APPID_UT_ORG_UNIT = "Google";
53
54 namespace snort
55 {
56
57 class Inspector* InspectorManager::get_inspector(const char*, bool, const SnortConfig*)
58 { return &dummy_appid_inspector; }
59
60 Packet::Packet(bool) { }
61 Packet::~Packet() = default;
62
63 Packet* DetectionEngine::get_current_packet()
64 {
65 static Packet p;
66 return &p;
67 }
68
69 AppIdSessionApi::AppIdSessionApi(const AppIdSession*, const SfIp&) :
70 StashGenericObject(STASH_GENERIC_OBJECT_APPID) {}
71 }
72
73 void AppIdModule::reset_stats() {}
74
75 class DummyInspector : public snort::Inspector
76 {
77 public:
78 void eval(Packet*) override {};
79 };
80
81 void DataBus::publish(unsigned, unsigned, DataEvent& event, Flow*)
82 {
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");
88 }
89
90 void AppIdSession::publish_appid_event(AppidChangeBits& change_bits, const Packet& p, bool, uint32_t)
91 {
92 AppidEvent app_event(change_bits, false, 0, this->get_api(), p);
93 DataBus::publish(0, AppIdEventIds::ANY_CHANGE, app_event, p.flow);
94 }
95
96 bool SslPatternMatchers::scan_hostname(const uint8_t* server_name, size_t, AppId& client_id, AppId& payload_id)
97 {
98 if (((const char*)server_name) == APPID_UT_TLS_HOST)
99 {
100 client_id = APPID_UT_ID + 1;
101 payload_id = APPID_UT_ID + 1;
102 }
103 else
104 {
105 client_id = 0;
106 payload_id = 0;
107 }
108 return true;
109 }
110
111 bool SslPatternMatchers::scan_cname(const uint8_t* cname, size_t, AppId& client_id, AppId& payload_id)
112 {
113 if (((const char*)cname) == APPID_UT_TLS_HOST)
114 {
115 client_id = APPID_UT_ID + 2;
116 payload_id = APPID_UT_ID + 2;
117 }
118 else if (((const char*)cname) == APPID_UT_ORG_UNIT)
119 {
120 client_id = APPID_UT_ID + 3;
121 payload_id = APPID_UT_ID + 3;
122 }
123 else
124 {
125 client_id = 0;
126 payload_id = 0;
127 }
128 return true;
129 }
130
131 void ApplicationDescriptor::set_id(const Packet&, AppIdSession&, AppidSessionDirection, AppId, AppidChangeBits&) { }
132
133 const char* AppInfoManager::get_app_name(AppId)
134 {
135 return test_app_name;
136 }
137
138 AppId AppInfoManager::get_appid_by_name(const char*)
139 {
140 return APPID_UT_ID;
141 }
142
143 AppId AppIdSessionApi::get_service_app_id() const
144 {
145 return application_ids[APP_PROTOID_SERVICE];
146 }
147
148 AppId AppIdSessionApi::get_client_app_id(uint32_t) const
149 {
150 return application_ids[APP_PROTOID_CLIENT];
151 }
152
153 AppId AppIdSessionApi::get_payload_app_id(uint32_t) const
154 {
155 return application_ids[APP_PROTOID_PAYLOAD];
156 }
157
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)
160 {
161 if (api.application_ids[APP_PROTOID_SERVICE] != service_id)
162 {
163 api.application_ids[APP_PROTOID_SERVICE] = service_id;
164 change_bits.set(APPID_SERVICE_BIT);
165 }
166 if (api.application_ids[APP_PROTOID_CLIENT] != client_id)
167 {
168 api.application_ids[APP_PROTOID_CLIENT] = client_id;
169 change_bits.set(APPID_CLIENT_BIT);
170 }
171 if (api.application_ids[APP_PROTOID_PAYLOAD] != payload_id)
172 {
173 api.application_ids[APP_PROTOID_PAYLOAD] = payload_id;
174 change_bits.set(APPID_PAYLOAD_BIT);
175 }
176 if (api.application_ids[APP_PROTOID_MISC] != misc_id)
177 {
178 api.application_ids[APP_PROTOID_MISC] = misc_id;
179 change_bits.set(APPID_MISC_BIT);
180 }
181 if (api.application_ids[APP_PROTOID_REFERRED] != referred_id)
182 {
183 api.application_ids[APP_PROTOID_REFERRED] = referred_id;
184 change_bits.set(APPID_REFERRED_BIT);
185 }
186 }
187
188 void AppIdSession::set_ss_application_ids(AppId client_id, AppId payload_id,
189 AppidChangeBits& change_bits)
190 {
191 if (api.application_ids[APP_PROTOID_CLIENT] != client_id)
192 {
193 api.application_ids[APP_PROTOID_CLIENT] = client_id;
194 change_bits.set(APPID_CLIENT_BIT);
195 }
196 if (api.application_ids[APP_PROTOID_PAYLOAD] != payload_id)
197 {
198 api.application_ids[APP_PROTOID_PAYLOAD] = payload_id;
199 change_bits.set(APPID_PAYLOAD_BIT);
200 }
201 }
202
203 AppIdHttpSession* AppIdSession::get_http_session(uint32_t) const { return nullptr; }
204
205 Flow* flow = nullptr;
206 AppIdSession* mock_session = nullptr;
207
208 TEST_GROUP(appid_api)
209 {
210 char test_log[256];
211 void setup() override
212 {
213 mock_init_appid_pegs();
214 SfIp ip;
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();
218 flow = new Flow;
219 flow->set_flow_data(mock_session);
220 mock().setDataObject("test_log", "char", test_log);
221 }
222
223 void teardown() override
224 {
225 delete flow;
226 mock().clear();
227 mock_cleanup_appid_pegs();
228 delete &mock_session->get_api();
229 delete mock_session;
230 }
231 };
232
233 TEST(appid_api, get_application_name)
234 {
235 AppIdConfig config;
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);
239 }
240
241 TEST(appid_api, get_application_id)
242 {
243 AppIdConfig config;
244 AppIdContext ctxt(config);
245 AppId id = appid_api.get_application_id(test_app_name, ctxt);
246 CHECK_EQUAL(id, 1492);
247 }
248
249 TEST(appid_api, ssl_app_group_id_lookup)
250 {
251 mock().expectNCalls(6, "publish");
252 AppId service, client, payload = APP_ID_NONE;
253 bool val = false;
254
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);
260 CHECK_TRUE(val);
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);
265
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);
272 CHECK_TRUE(val);
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);
279
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);
289 CHECK_TRUE(val);
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);
296
297 // First alt name based detection
298 change_bits.reset();
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);
302 CHECK_TRUE(val);
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);
308
309 // Org unit based detection
310 string host = "";
311 change_bits.reset();
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);
315 CHECK_TRUE(val);
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);
320
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;
326 change_bits.reset();
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);
332 CHECK_TRUE(val);
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);
339
340 mock().checkExpectations();
341
342 // When appid session is not existing
343 // 1. Match based on server name
344 Flow* f = new Flow;
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);
351 CHECK_TRUE(val);
352 CHECK_EQUAL(client, APPID_UT_ID + 1);
353 CHECK_EQUAL(payload, APPID_UT_ID + 1);
354
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);
360 CHECK_TRUE(val);
361 CHECK_EQUAL(client, APPID_UT_ID + 1);
362 CHECK_EQUAL(payload, APPID_UT_ID + 1);
363
364 // 3. CN match
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);
369 CHECK_TRUE(val);
370 CHECK_EQUAL(client, APPID_UT_ID + 2);
371 CHECK_EQUAL(payload, APPID_UT_ID + 2);
372
373 // 4. Org unit match
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);
378 CHECK_TRUE(val);
379 CHECK_EQUAL(client, APPID_UT_ID + 2);
380 CHECK_EQUAL(payload, APPID_UT_ID + 2);
381
382 delete f;
383 }
384
385 TEST(appid_api, is_inspection_needed)
386 {
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;
391
392 CHECK_TRUE(appid_api.is_inspection_needed(inspector));
393
394 inspector.set_service(dummy_http2_protocol_id + 1);
395 CHECK_FALSE(appid_api.is_inspection_needed(inspector));
396 }
397
398 TEST(appid_api, is_service_http_type)
399 {
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));
404 }
405
406 TEST(appid_api, get_appid_detector_directory)
407 {
408 STRCMP_EQUAL(appid_api.get_appid_detector_directory(), "/path/to/appid/detectors/");
409 }
410
411 int main(int argc, char** argv)
412 {
413 int rc = CommandLineTestRunner::RunAllTests(argc, argv);
414 return rc;
415 }