1 //--------------------------------------------------------------------------
2 // Copyright (C) 2014-2021 Cisco and/or its affiliates. All rights reserved.
3 // Copyright (C) 2005-2013 Sourcefire, Inc.
4 //
5 // This program is free software; you can redistribute it and/or modify it
6 // under the terms of the GNU General Public License Version 2 as published
7 // by the Free Software Foundation. You may not use, modify or distribute
8 // this program under any other version of the GNU General Public License.
9 //
10 // This program is distributed in the hope that it will be useful, but
11 // WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 // General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License along
16 // with this program; if not, write to the Free Software Foundation, Inc.,
17 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 //--------------------------------------------------------------------------
19
20 // app_info_table.cc author Sourcefire Inc.
21
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25
26 #include "app_info_table.h"
27
28 #include <climits>
29 #include <fstream>
30 #include <string>
31 #include <unistd.h>
32
33 #include "log/unified2.h"
34 #include "main/snort_config.h"
35 #include "target_based/snort_protocols.h"
36 #include "utils/util_cstring.h"
37 #include "appid_api.h"
38 #include "appid_config.h"
39 #include "appid_inspector.h"
40 #include "appid_peg_counts.h"
41
42 using namespace snort;
43
44 #define MAX_TABLE_LINE_LEN 1024
45 static const char* CONF_SEPARATORS = "\t\n\r";
46 static const int MIN_MAX_TP_FLOW_DEPTH = 1;
47 static const int MAX_MAX_TP_FLOW_DEPTH = 1000000;
48 static const int MIN_HOST_PORT_APP_CACHE_LOOKUP_INTERVAL = 1;
49 static const int MAX_HOST_PORT_APP_CACHE_LOOKUP_INTERVAL = 1000000;
50 static const int MIN_HOST_PORT_APP_CACHE_LOOKUP_RANGE = 1;
51 static const int MAX_HOST_PORT_APP_CACHE_LOOKUP_RANGE = 1000000;
52 static const char* APP_CONFIG_FILE = "appid.conf";
53 static const char* USR_CONFIG_FILE = "userappid.conf";
54 const char* APP_MAPPING_FILE = "appMapping.data";
55
AppInfoTableEntry(AppId id,char * name)56 AppInfoTableEntry::AppInfoTableEntry(AppId id, char* name)
57 : appId(id), serviceId(id), clientId(id), payloadId(id), app_name(name)
58 {
59 app_name_key = AppInfoManager::strdup_to_lower(name);
60 }
61
AppInfoTableEntry(AppId id,char * name,AppId sid,AppId cid,AppId pid)62 AppInfoTableEntry::AppInfoTableEntry(AppId id, char* name, AppId sid, AppId cid, AppId pid) :
63 appId(id), serviceId(sid), clientId(cid), payloadId(pid), app_name(name)
64 {
65 app_name_key = AppInfoManager::strdup_to_lower(name);
66 }
67
~AppInfoTableEntry()68 AppInfoTableEntry::~AppInfoTableEntry()
69 {
70 if (app_name)
71 snort_free(app_name);
72 if (app_name_key)
73 snort_free(app_name_key);
74 }
75
is_existing_entry(AppInfoTableEntry * entry)76 bool AppInfoManager::is_existing_entry(AppInfoTableEntry* entry)
77 {
78 AppInfoNameTable::iterator app;
79
80 app = app_info_name_table.find(entry->app_name_key);
81 return app != app_info_name_table.end();
82 }
83
find_app_info_by_name(const char * app_name)84 AppInfoTableEntry* AppInfoManager::find_app_info_by_name(const char* app_name)
85 {
86 AppInfoTableEntry* entry = nullptr;
87 AppInfoNameTable::iterator app;
88 const char* search_name = AppInfoManager::strdup_to_lower(app_name);
89
90 app = app_info_name_table.find(search_name);
91 if (app != app_info_name_table.end())
92 entry = app->second;
93
94 snort_free((void*)search_name);
95 return entry;
96 }
97
add_entry_to_app_info_name_table(const char * app_name,AppInfoTableEntry * entry)98 bool AppInfoManager::add_entry_to_app_info_name_table(const char* app_name,
99 AppInfoTableEntry* entry)
100 {
101 bool added = true;
102
103 if (!is_existing_entry(entry))
104 app_info_name_table[app_name] = entry;
105 else
106 {
107 WarningMessage("App name, \"%s\" is a duplicate entry will be shared by each detector.\n",
108 app_name);
109 added = false;
110 }
111 return added;
112 }
113
get_static_app_info_entry(AppId appid)114 AppId AppInfoManager::get_static_app_info_entry(AppId appid)
115 {
116 if (appid > 0 && appid < SF_APPID_BUILDIN_MAX)
117 return appid;
118 if ((appid >= SF_APPID_CSD_MIN) &&
119 appid < (SF_APPID_CSD_MIN + (SF_APPID_MAX - SF_APPID_BUILDIN_MAX)))
120 return (SF_APPID_BUILDIN_MAX + appid - SF_APPID_CSD_MIN);
121 return 0;
122 }
123
strdup_to_lower(const char * source)124 char* AppInfoManager::strdup_to_lower(const char* source)
125 {
126 char* dest = snort_strdup(source);
127 char* lcd = dest;
128
129 while (*lcd)
130 {
131 *lcd = tolower(*lcd);
132 lcd++;
133 }
134 return dest;
135 }
136
configured()137 bool AppInfoManager::configured()
138 {
139 return !app_info_table.empty();
140 }
141
get_app_info_entry(AppId appId,const AppInfoTable & lookup_table)142 AppInfoTableEntry* AppInfoManager::get_app_info_entry(AppId appId,
143 const AppInfoTable& lookup_table)
144 {
145 AppId tmp;
146 AppInfoTable::const_iterator app;
147 AppInfoTableEntry* entry = nullptr;
148
149 if ((tmp = get_static_app_info_entry(appId)))
150 {
151 app = lookup_table.find(tmp);
152 if (app != lookup_table.end())
153 entry = app->second;
154 }
155 else
156 {
157 app = custom_app_info_table.find(appId);
158 if (app != custom_app_info_table.end())
159 entry = app->second;
160 }
161 return entry;
162 }
163
get_app_info_entry(AppId appId)164 AppInfoTableEntry* AppInfoManager::get_app_info_entry(AppId appId)
165 {
166 return get_app_info_entry(appId, app_info_table);
167 }
168
add_dynamic_app_entry(const char * app_name)169 AppInfoTableEntry* AppInfoManager::add_dynamic_app_entry(const char* app_name)
170 {
171 if (!app_name || strlen(app_name) >= MAX_EVENT_APPNAME_LEN)
172 {
173 ErrorMessage("Appname invalid or too long: %s\n", app_name);
174 return nullptr;
175 }
176
177 AppInfoTableEntry* entry = find_app_info_by_name(app_name);
178 if (!entry)
179 {
180 entry = new AppInfoTableEntry(next_custom_appid++, snort_strdup(app_name));
181 custom_app_info_table[entry->appId] = entry;
182
183 if (!add_entry_to_app_info_name_table(entry->app_name_key, entry))
184 {
185 delete entry;
186 return nullptr;
187 }
188 }
189 return entry;
190 }
191
cleanup_appid_info_table()192 void AppInfoManager::cleanup_appid_info_table()
193 {
194 for (auto& kv: app_info_table)
195 delete(kv.second);
196 app_info_table.erase(app_info_table.begin(), app_info_table.end());
197
198 for (auto& kv: custom_app_info_table)
199 delete(kv.second);
200
201 custom_app_info_table.erase(custom_app_info_table.begin(), custom_app_info_table.end());
202 app_info_name_table.erase(app_info_name_table.begin(), app_info_name_table.end());
203 }
204
dump_app_info_table()205 void AppInfoManager::dump_app_info_table()
206 {
207 LogMessage("Cisco provided detectors:\n");
208 for (auto& kv: app_info_table)
209 LogMessage("%s\t%d\t%s\n", kv.second->app_name, kv.second->appId,
210 (kv.second->flags & APPINFO_FLAG_ACTIVE) ? "active" : "inactive");
211
212 LogMessage("User provided detectors:\n");
213 for (auto& kv: custom_app_info_table)
214 LogMessage("%s\t%d\t%s\n", kv.second->app_name, kv.second->appId,
215 (kv.second->flags & APPINFO_FLAG_ACTIVE) ? "active" : "inactive");
216 }
217
get_appid_by_service_id(uint32_t id)218 AppId AppInfoManager::get_appid_by_service_id(uint32_t id)
219 {
220 AppInfoTableEntry* entry = get_app_info_entry(id, app_info_service_table);
221 return entry ? entry->appId : APP_ID_NONE;
222 }
223
get_appid_by_client_id(uint32_t id)224 AppId AppInfoManager::get_appid_by_client_id(uint32_t id)
225 {
226 AppInfoTableEntry* entry = get_app_info_entry(id, app_info_client_table);
227 return entry ? entry->appId : APP_ID_NONE;
228 }
229
get_appid_by_payload_id(uint32_t id)230 AppId AppInfoManager::get_appid_by_payload_id(uint32_t id)
231 {
232 AppInfoTableEntry* entry = get_app_info_entry(id, app_info_payload_table);
233 return entry ? entry->appId : APP_ID_NONE;
234 }
235
get_app_name(int32_t id)236 const char* AppInfoManager::get_app_name(int32_t id)
237 {
238 AppInfoTableEntry* entry = get_app_info_entry(id);
239 return entry ? entry->app_name : nullptr;
240 }
241
get_app_name_key(int32_t id)242 const char* AppInfoManager::get_app_name_key(int32_t id)
243 {
244 AppInfoTableEntry* entry = get_app_info_entry(id);
245 return entry ? entry->app_name_key : nullptr;
246 }
247
get_appid_by_name(const char * app_name)248 AppId AppInfoManager::get_appid_by_name(const char* app_name)
249 {
250 AppInfoTableEntry* entry = find_app_info_by_name(app_name);
251 return entry ? entry->appId : APP_ID_NONE;
252 }
253
set_app_info_active(AppId appId)254 void AppInfoManager::set_app_info_active(AppId appId)
255 {
256 if (appId == APP_ID_NONE)
257 return;
258
259 AppInfoTableEntry* entry = get_app_info_entry(appId);
260 if (entry)
261 entry->flags |= APPINFO_FLAG_ACTIVE;
262 else
263 ParseWarning(WARN_PLUGINS, "appid: no entry in %s for %d", APP_MAPPING_FILE, appId);
264 }
265
load_odp_config(OdpContext & odp_ctxt,const char * path)266 void AppInfoManager::load_odp_config(OdpContext& odp_ctxt, const char* path)
267 {
268 char buf[MAX_TABLE_LINE_LEN];
269 unsigned line = 0;
270
271 FILE* config_file = fopen(path, "r");
272 if (config_file == nullptr)
273 return;
274
275 while (fgets(buf, sizeof(buf), config_file) != nullptr)
276 {
277 char* context;
278
279 line++;
280 char* token = strtok_r(buf, CONF_SEPARATORS, &context);
281 if (token == nullptr)
282 {
283 ParseWarning(WARN_CONF, "appid: No 'conf_type' value at line %s:%u\n", path, line);
284 continue;
285 }
286 char* conf_type = token;
287
288 token = strtok_r(nullptr, CONF_SEPARATORS, &context);
289 if (token == nullptr)
290 {
291 ParseWarning(WARN_CONF, "appid: No 'conf_key' value at line %s:%u\n", path, line);
292 continue;
293 }
294 char* conf_key = token;
295
296 token = strtok_r(nullptr, CONF_SEPARATORS, &context);
297 if (token == nullptr)
298 {
299 ParseWarning(WARN_CONF, "appid: No 'conf_val' value at line %s:%u\n", path, line);
300 continue;
301 }
302 char* conf_val = token;
303
304 /* APPID configurations are for anything else - currently we only have ssl_reinspect */
305 if (!(strcasecmp(conf_type, "appid")))
306 {
307 if (!(strcasecmp(conf_key, "max_tp_flow_depth")))
308 {
309 int max_tp_flow_depth = atoi(conf_val);
310 if (max_tp_flow_depth < MIN_MAX_TP_FLOW_DEPTH
311 || max_tp_flow_depth > MAX_MAX_TP_FLOW_DEPTH)
312 {
313 ParseWarning(WARN_CONF,
314 "appid: invalid max_tp_flow_depth %d, must be between %d and %d\n.",
315 max_tp_flow_depth, MIN_MAX_TP_FLOW_DEPTH, MAX_MAX_TP_FLOW_DEPTH);
316 }
317 else
318 {
319 odp_ctxt.max_tp_flow_depth = max_tp_flow_depth;
320 }
321 }
322 else if (!(strcasecmp(conf_key, "host_port_app_cache_lookup_interval")))
323 {
324 int host_port_app_cache_lookup_interval = atoi(conf_val);
325 if (host_port_app_cache_lookup_interval <
326 MIN_HOST_PORT_APP_CACHE_LOOKUP_INTERVAL ||
327 host_port_app_cache_lookup_interval >
328 MAX_HOST_PORT_APP_CACHE_LOOKUP_INTERVAL)
329 {
330 ParseWarning(WARN_CONF,
331 "appid: invalid host_port_app_cache_lookup_interval %d, "
332 "must be between %d and %d\n.",
333 host_port_app_cache_lookup_interval,
334 MIN_HOST_PORT_APP_CACHE_LOOKUP_INTERVAL,
335 MAX_HOST_PORT_APP_CACHE_LOOKUP_INTERVAL);
336 }
337 else
338 {
339 odp_ctxt.host_port_app_cache_lookup_interval =
340 host_port_app_cache_lookup_interval;
341 }
342 }
343 else if (!(strcasecmp(conf_key, "host_port_app_cache_lookup_range")))
344 {
345 int host_port_app_cache_lookup_range = atoi(conf_val);
346 if (host_port_app_cache_lookup_range < MIN_HOST_PORT_APP_CACHE_LOOKUP_RANGE
347 || host_port_app_cache_lookup_range > MAX_HOST_PORT_APP_CACHE_LOOKUP_RANGE)
348 {
349 ParseWarning(WARN_CONF,
350 "appid: invalid host_port_app_cache_lookup_range %d, "
351 "must be between %d and %d\n.", host_port_app_cache_lookup_range,
352 MIN_HOST_PORT_APP_CACHE_LOOKUP_RANGE,
353 MAX_HOST_PORT_APP_CACHE_LOOKUP_RANGE);
354 }
355 else
356 {
357 odp_ctxt.host_port_app_cache_lookup_range = host_port_app_cache_lookup_range;
358 }
359 }
360 else if (!(strcasecmp(conf_key, "is_host_port_app_cache_runtime")))
361 {
362 if (!(strcasecmp(conf_val, "enabled")))
363 {
364 odp_ctxt.is_host_port_app_cache_runtime = true;
365 }
366 }
367 else if (!(strcasecmp(conf_key, "check_host_port_app_cache")))
368 {
369 if (!(strcasecmp(conf_val, "enabled")))
370 {
371 odp_ctxt.check_host_port_app_cache = true;
372 }
373 }
374 else if (!(strcasecmp(conf_key, "check_host_cache_unknown_ssl")))
375 {
376 if (!(strcasecmp(conf_val, "enabled")))
377 {
378 odp_ctxt.check_host_cache_unknown_ssl = true;
379 }
380 }
381 else if (!(strcasecmp(conf_key, "allow_port_wildcard_host_cache")))
382 {
383 if (!(strcasecmp(conf_val, "enabled")))
384 {
385 odp_ctxt.allow_port_wildcard_host_cache = true;
386 }
387 }
388 else if (!(strcasecmp(conf_key, "recheck_for_portservice_appid")))
389 {
390 if (!(strcasecmp(conf_val, "enabled")))
391 {
392 odp_ctxt.recheck_for_portservice_appid = true;
393 }
394 }
395 else if (!(strcasecmp(conf_key, "bittorrent_aggressiveness")))
396 {
397 int aggressiveness = atoi(conf_val);
398 LogMessage("AppId: bittorrent_aggressiveness %d\n", aggressiveness);
399 if (aggressiveness >= 50)
400 {
401 odp_ctxt.host_port_app_cache_lookup_interval = 5;
402 odp_ctxt.recheck_for_portservice_appid = true;
403 set_app_info_flags(APP_ID_BITTORRENT, APPINFO_FLAG_DEFER);
404 set_app_info_flags(APP_ID_BITTORRENT, APPINFO_FLAG_DEFER_PAYLOAD);
405 odp_ctxt.max_tp_flow_depth = 25;
406 LogMessage("AppId: host_port_app_cache_lookup_interval %d\n",
407 odp_ctxt.host_port_app_cache_lookup_interval);
408 LogMessage("AppId: recheck_for_portservice_appid enabled\n");
409 LogMessage("AppId: defer_to_thirdparty %d\n", APP_ID_BITTORRENT);
410 LogMessage("AppId: defer_payload_to_thirdparty %d\n", APP_ID_BITTORRENT);
411 LogMessage("AppId: max_tp_flow_depth %d\n", odp_ctxt.max_tp_flow_depth);
412 }
413 if (aggressiveness >= 80)
414 {
415 odp_ctxt.allow_port_wildcard_host_cache = true;
416 LogMessage("AppId: allow_port_wildcard_host_cache enabled\n");
417 }
418 }
419 else if (!(strcasecmp(conf_key, "ultrasurf_aggressiveness")))
420 {
421 int aggressiveness = atoi(conf_val);
422 LogMessage("AppId: ultrasurf_aggressiveness %d\n", aggressiveness);
423 if (aggressiveness >= 50)
424 {
425 odp_ctxt.check_host_cache_unknown_ssl = true;
426 set_app_info_flags(APP_ID_ULTRASURF, APPINFO_FLAG_DEFER);
427 set_app_info_flags(APP_ID_ULTRASURF, APPINFO_FLAG_DEFER_PAYLOAD);
428 odp_ctxt.max_tp_flow_depth = 25;
429 LogMessage("AppId: check_host_cache_unknown_ssl enabled\n");
430 LogMessage("AppId: defer_to_thirdparty %d\n", APP_ID_ULTRASURF);
431 LogMessage("AppId: defer_payload_to_thirdparty %d\n", APP_ID_ULTRASURF);
432 LogMessage("AppId: max_tp_flow_depth %d\n", odp_ctxt.max_tp_flow_depth);
433 }
434 if (aggressiveness >= 80)
435 {
436 odp_ctxt.allow_port_wildcard_host_cache = true;
437 LogMessage("AppId: allow_port_wildcard_host_cache enabled\n");
438 }
439 }
440 else if (!(strcasecmp(conf_key, "psiphon_aggressiveness")))
441 {
442 int aggressiveness = atoi(conf_val);
443 LogMessage("AppId: psiphon_aggressiveness %d\n", aggressiveness);
444 if (aggressiveness >= 50)
445 {
446 odp_ctxt.check_host_cache_unknown_ssl = true;
447 set_app_info_flags(APP_ID_PSIPHON, APPINFO_FLAG_DEFER);
448 set_app_info_flags(APP_ID_PSIPHON, APPINFO_FLAG_DEFER_PAYLOAD);
449 odp_ctxt.max_tp_flow_depth = 25;
450 LogMessage("AppId: check_host_cache_unknown_ssl enabled\n");
451 LogMessage("AppId: defer_to_thirdparty %d\n", APP_ID_PSIPHON);
452 LogMessage("AppId: defer_payload_to_thirdparty %d\n", APP_ID_PSIPHON);
453 LogMessage("AppId: max_tp_flow_depth %d\n", odp_ctxt.max_tp_flow_depth);
454 }
455 if (aggressiveness >= 80)
456 {
457 odp_ctxt.allow_port_wildcard_host_cache = true;
458 LogMessage("AppId: allow_port_wildcard_host_cache enabled\n");
459 }
460 }
461 else if (!(strcasecmp(conf_key, "tp_allow_probes")))
462 {
463 if (!(strcasecmp(conf_val, "enabled")))
464 {
465 odp_ctxt.tp_allow_probes = true;
466 }
467 }
468 else if (!(strcasecmp(conf_key, "tp_client_app")))
469 {
470 set_app_info_flags(atoi(conf_val), APPINFO_FLAG_TP_CLIENT);
471 }
472 else if (!(strcasecmp(conf_key, "ssl_reinspect")))
473 {
474 set_app_info_flags(atoi(conf_val), APPINFO_FLAG_SSL_INSPECT);
475 }
476 else if (!(strcasecmp(conf_key, "defer_to_thirdparty")))
477 {
478 set_app_info_flags(atoi(conf_val), APPINFO_FLAG_DEFER);
479 }
480 else if (!(strcasecmp(conf_key, "defer_payload_to_thirdparty")))
481 {
482 set_app_info_flags(atoi(conf_val), APPINFO_FLAG_DEFER_PAYLOAD);
483 }
484 else if (!(strcasecmp(conf_key, "chp_userid")))
485 {
486 if (!(strcasecmp(conf_val, "disabled")))
487 {
488 odp_ctxt.chp_userid_disabled = true;
489 continue;
490 }
491 }
492 else if (!(strcasecmp(conf_key, "chp_body_collection")))
493 {
494 if (!(strcasecmp(conf_val, "disabled")))
495 {
496 odp_ctxt.chp_body_collection_disabled = true;
497 continue;
498 }
499 }
500 else if (!(strcasecmp(conf_key, "ftp_userid")))
501 {
502 if (!(strcasecmp(conf_val, "disabled")))
503 {
504 odp_ctxt.ftp_userid_disabled = true;
505 continue;
506 }
507 }
508 else if (!(strcasecmp(conf_key, "max_bytes_before_service_fail")))
509 {
510 uint64_t max_bytes_before_service_fail = atoi(conf_val);
511 if (max_bytes_before_service_fail < MIN_MAX_BYTES_BEFORE_SERVICE_FAIL)
512 {
513 ParseWarning(WARN_CONF, "appid: invalid max_bytes_before_service_fail "
514 "%" PRIu64 " must be greater than %u.\n", max_bytes_before_service_fail,
515 MIN_MAX_BYTES_BEFORE_SERVICE_FAIL);
516 }
517 else
518 {
519 odp_ctxt.max_bytes_before_service_fail = max_bytes_before_service_fail;
520 }
521 }
522 else if (!(strcasecmp(conf_key, "max_packet_before_service_fail")))
523 {
524 uint16_t max_packet_before_service_fail = atoi(conf_val);
525 if (max_packet_before_service_fail < MIN_MAX_PKTS_BEFORE_SERVICE_FAIL)
526 {
527 ParseWarning(WARN_CONF, "appid: invalid max_packet_before_service_fail "
528 "%" PRIu16 ", must be greater than %u.\n", max_packet_before_service_fail,
529 MIN_MAX_PKTS_BEFORE_SERVICE_FAIL);
530 }
531 else
532 {
533 odp_ctxt.max_packet_before_service_fail = max_packet_before_service_fail;
534 }
535 }
536 else if (!(strcasecmp(conf_key, "max_packet_service_fail_ignore_bytes")))
537 {
538 uint16_t max_packet_service_fail_ignore_bytes = atoi(conf_val);
539 if (max_packet_service_fail_ignore_bytes <
540 MIN_MAX_PKT_BEFORE_SERVICE_FAIL_IGNORE_BYTES)
541 {
542 ParseWarning(WARN_CONF, "appid: invalid max_packet_service_fail_ignore_bytes"
543 "%" PRIu16 ", must be greater than %u.\n",
544 max_packet_service_fail_ignore_bytes,
545 MIN_MAX_PKT_BEFORE_SERVICE_FAIL_IGNORE_BYTES);
546 }
547 else
548 {
549 odp_ctxt.max_packet_service_fail_ignore_bytes =
550 max_packet_service_fail_ignore_bytes;
551 }
552 }
553 /* App Priority bit set*/
554 else if (!(strcasecmp(conf_key, "app_priority")))
555 {
556 int temp_appid;
557 temp_appid = strtol(conf_val, nullptr, 10);
558 token = strtok_r(nullptr, CONF_SEPARATORS, &context);
559 if (token == nullptr)
560 {
561 ParseWarning(WARN_CONF, "appid: Could not read app_priority at line %u\n", line);
562 continue;
563 }
564 conf_val = token;
565 uint8_t temp_val;
566 temp_val = strtol(conf_val, nullptr, 10);
567 set_app_info_priority (temp_appid, temp_val);
568 }
569 else if (!(strcasecmp(conf_key, "referred_appId")))
570 {
571 if (!(strcasecmp(conf_val, "disabled")))
572 {
573 odp_ctxt.referred_appId_disabled = true;
574 continue;
575 }
576 else if (!odp_ctxt.referred_appId_disabled)
577 {
578 char referred_app_list[4096];
579 int referred_app_index = safe_snprintf(referred_app_list, 4096, "%d ",
580 atoi(conf_val));
581 set_app_info_flags(atoi(conf_val), APPINFO_FLAG_REFERRED);
582
583 while ((token = strtok_r(nullptr, CONF_SEPARATORS, &context)) != nullptr)
584 {
585 AppId id = atoi(token);
586 referred_app_index += safe_snprintf(referred_app_list + referred_app_index,
587 sizeof(referred_app_list) - referred_app_index, "%d ", id);
588 set_app_info_flags(id, APPINFO_FLAG_REFERRED);
589 }
590 }
591 }
592 else if (!(strcasecmp(conf_key, "rtmp_max_packets")))
593 {
594 odp_ctxt.rtmp_max_packets = atoi(conf_val);
595 }
596 else if (!(strcasecmp(conf_key, "mdns_user_report")))
597 {
598 odp_ctxt.mdns_user_reporting = atoi(conf_val) ? true : false;
599 }
600 else if (!(strcasecmp(conf_key, "dns_host_report")))
601 {
602 odp_ctxt.dns_host_reporting = atoi(conf_val) ? true : false;
603 }
604 else if (!(strcasecmp(conf_key, "chp_body_max_bytes")))
605 {
606 odp_ctxt.chp_body_collection_max = atoi(conf_val);
607 }
608 else if (!(strcasecmp(conf_key, "ignore_thirdparty_appid")))
609 {
610 set_app_info_flags(atoi(conf_val), APPINFO_FLAG_IGNORE);
611 }
612 else
613 ParseWarning(WARN_CONF, "appid: unsupported configuration: %s\n", conf_key);
614 }
615 }
616
617 fclose(config_file);
618 }
619
dump_appid_configurations(const std::string & file_path) const620 void AppInfoManager::dump_appid_configurations(const std::string& file_path) const
621 {
622 std::ifstream conf_file(file_path);
623 if (!conf_file.is_open())
624 return;
625
626 LogMessage("AppId: Configuration file %s\n", file_path.c_str());
627 std::string line;
628 while (getline(conf_file, line))
629 LogMessage("%s\n", line.c_str());
630
631 conf_file.close();
632 }
633
add_appid_protocol_reference(const char * protocol,SnortConfig * sc)634 SnortProtocolId AppInfoManager::add_appid_protocol_reference(const char* protocol,
635 SnortConfig* sc)
636 {
637 SnortProtocolId snort_protocol_id = sc->proto_ref->add(protocol);
638 return snort_protocol_id;
639 }
640
init_appid_info_table(const AppIdConfig & config,SnortConfig * sc,OdpContext & odp_ctxt)641 void AppInfoManager::init_appid_info_table(const AppIdConfig& config,
642 SnortConfig* sc, OdpContext& odp_ctxt)
643 {
644 if (!config.app_detector_dir)
645 {
646 return; // no lua detectors, no rule support, already warned
647 }
648
649 char filepath[PATH_MAX];
650 snprintf(filepath, sizeof(filepath), "%s/odp/%s", config.app_detector_dir,
651 APP_MAPPING_FILE);
652
653 FILE* tableFile = fopen(filepath, "r");
654
655 if (!tableFile)
656 {
657 ParseError("appid: could not open %s", filepath);
658 }
659 else
660 {
661 char buf[MAX_TABLE_LINE_LEN];
662
663 while (fgets(buf, sizeof(buf), tableFile))
664 {
665 AppId app_id;
666 uint32_t client_id, service_id, payload_id;
667 char* app_name;
668 char* context;
669
670 const char* token = strtok_r(buf, CONF_SEPARATORS, &context);
671 if (!token)
672 {
673 ErrorMessage("Could not read id for AppId\n");
674 continue;
675 }
676 app_id = strtol(token, nullptr, 10);
677
678 token = strtok_r(nullptr, CONF_SEPARATORS, &context);
679 if (!token)
680 {
681 ErrorMessage("Could not read app_name. Line %s\n", buf);
682 continue;
683 }
684 app_name = snort_strdup(token);
685
686 token = strtok_r(nullptr, CONF_SEPARATORS, &context);
687 if (!token)
688 {
689 ErrorMessage("Could not read service id for AppId\n");
690 snort_free(app_name);
691 continue;
692 }
693 service_id = strtol(token, nullptr, 10);
694
695 token = strtok_r(nullptr, CONF_SEPARATORS, &context);
696 if (!token)
697 {
698 ErrorMessage("Could not read client id for AppId\n");
699 snort_free(app_name);
700 continue;
701 }
702 client_id = strtol(token, nullptr, 10);
703
704 token = strtok_r(nullptr, CONF_SEPARATORS, &context);
705 if (!token)
706 {
707 ErrorMessage("Could not read payload id for AppId\n");
708 snort_free(app_name);
709 continue;
710 }
711 payload_id = strtol(token, nullptr, 10);
712
713 AppInfoTableEntry* entry = new AppInfoTableEntry(app_id, app_name, service_id,
714 client_id, payload_id);
715
716 /* snort service key, if it exists */
717 token = strtok_r(nullptr, CONF_SEPARATORS, &context);
718
719 // FIXIT-RC: Sometimes the token is "~". Should we ignore those?
720 if (token)
721 entry->snort_protocol_id = add_appid_protocol_reference(token, sc);
722
723 if ((app_id = get_static_app_info_entry(entry->appId)))
724 {
725 app_info_table[app_id] = entry;
726 AppIdPegCounts::add_app_peg_info(entry->app_name_key, app_id);
727 }
728
729 if ((app_id = get_static_app_info_entry(entry->serviceId)))
730 app_info_service_table[app_id] = entry;
731 if ((app_id = get_static_app_info_entry(entry->clientId)))
732 app_info_client_table[app_id] = entry;
733 if ((app_id = get_static_app_info_entry(entry->payloadId)))
734 app_info_payload_table[app_id] = entry;
735
736 if (!add_entry_to_app_info_name_table(entry->app_name_key, entry))
737 delete entry;
738 }
739 fclose(tableFile);
740
741 snprintf(filepath, sizeof(filepath), "%s/odp/%s", config.app_detector_dir,
742 APP_CONFIG_FILE);
743 load_odp_config(odp_ctxt, filepath);
744 snprintf(filepath, sizeof(filepath), "%s/custom/%s", config.app_detector_dir,
745 USR_CONFIG_FILE);
746 if (access (filepath, F_OK))
747 snprintf(filepath, sizeof(filepath), "%s/../%s", config.app_detector_dir,
748 USR_CONFIG_FILE);
749 load_odp_config(odp_ctxt, filepath);
750 }
751 }
752
753