From: Umang Sharma Date: Wed, 8 Apr 2026 20:14:33 +0000 (-0400) Subject: appid: Lua API for publishing deviceinfo event X-Git-Tag: 3.12.2.0~16 X-Git-Url: http://git.ipfire.org/gitweb/?a=commitdiff_plain;h=6e8e97fc8d316fdffc6295dce516013dfa144619;p=thirdparty%2Fsnort3.git appid: Lua API for publishing deviceinfo event --- diff --git a/src/network_inspectors/appid/app_info_table.cc b/src/network_inspectors/appid/app_info_table.cc index 7d797bb83..ef9960f75 100644 --- a/src/network_inspectors/appid/app_info_table.cc +++ b/src/network_inspectors/appid/app_info_table.cc @@ -402,15 +402,15 @@ void AppInfoManager::load_odp_config(OdpContext& odp_ctxt, const char* path) odp_ctxt.recheck_for_portservice_appid = true; } } - else if (!(strcasecmp(conf_key, "mdns_deviceinfo"))) + else if (!(strcasecmp(conf_key, "detector_deviceinfo"))) { if (!(strcasecmp(conf_val, "enabled"))) { - odp_ctxt.mdns_deviceinfo = true; + odp_ctxt.detector_deviceinfo = true; } else if (!(strcasecmp(conf_val, "disabled"))) { - odp_ctxt.mdns_deviceinfo = false; + odp_ctxt.detector_deviceinfo = false; } } else if (!(strcasecmp(conf_key, "bittorrent_aggressiveness"))) diff --git a/src/network_inspectors/appid/appid_config.h b/src/network_inspectors/appid/appid_config.h index c6390d562..c31a55f71 100644 --- a/src/network_inspectors/appid/appid_config.h +++ b/src/network_inspectors/appid/appid_config.h @@ -140,7 +140,7 @@ public: bool dns_host_reporting = true; bool referred_appId_disabled = false; bool mdns_user_reporting = true; - bool mdns_deviceinfo = true; + bool detector_deviceinfo = true; bool chp_userid_disabled = false; bool is_host_port_app_cache_runtime = false; bool check_host_port_app_cache = false; diff --git a/src/network_inspectors/appid/lua_detector_api.cc b/src/network_inspectors/appid/lua_detector_api.cc index 5863be9fe..216c59899 100644 --- a/src/network_inspectors/appid/lua_detector_api.cc +++ b/src/network_inspectors/appid/lua_detector_api.cc @@ -57,6 +57,8 @@ #include "service_plugins/service_discovery.h" #include "service_plugins/service_ssl.h" +#include "pub_sub/deviceinfo_events.h" + using namespace snort; using namespace std; @@ -3395,6 +3397,60 @@ int lua_remove_registry_table_test(lua_State* L) } #endif +static int detector_publish_device_info(lua_State* L) +{ + auto& ud = *UserData::check(L, DETECTOR, 1); + LuaStateDescriptor* lsd = ud->validate_lua_state(true); + if (!lsd) + return 0; + if (!lua_istable(L, 2)) + return 0; + if (!ud->get_odp_ctxt().detector_deviceinfo) + return 0; + + DeviceInfoEvent::KeyValueVector kv_pairs; + std::string service_type = DEVINFO_SERVICE_NULL; + std::string device_name; + + lua_pushnil(L); + while (lua_next(L, 2) != 0) + { + if (lua_type(L, -2) != LUA_TSTRING) + { + lua_pop(L, 1); + continue; + } + const char* key = lua_tostring(L, -2); + const char* value = (lua_type(L, -1) == LUA_TSTRING) ? lua_tostring(L, -1) : nullptr; + if (!key || !value) + { + lua_pop(L, 1); + continue; + } + if (strcmp(key, DEVINFO_META_SERVICE_TYPE) == 0) + service_type = value; + else + { + kv_pairs.emplace_back(key, value); + if (strcmp(key, DEVINFO_KEY_DEVICENAME) == 0) + device_name = value; + } + lua_pop(L, 1); + } + + if (kv_pairs.empty()) + return 0; + + const Packet* pkt = lsd->ldp.pkt; + if (!pkt) + return 0; + + DeviceInfoEvent event(pkt, service_type, device_name, kv_pairs); + DataBus::publish(DataBus::get_id(deviceinfo_pub_key), DeviceInfoEventIds::DEVICEINFO, event); + + return 0; +} + static const luaL_Reg detector_methods[] = { /* Obsolete API names. No longer use these! They are here for backward @@ -3527,6 +3583,8 @@ static const luaL_Reg detector_methods[] = {"addCipService", detector_add_cip_service}, {"addEnipCommand", detector_add_enip_command}, + {"publishDeviceInfo", detector_publish_device_info}, + #ifdef REG_TEST {"luaRemoveRegistryTableTest", lua_remove_registry_table_test}, #endif diff --git a/src/network_inspectors/appid/service_plugins/service_mdns.cc b/src/network_inspectors/appid/service_plugins/service_mdns.cc index e0623cbb4..873bcd64f 100644 --- a/src/network_inspectors/appid/service_plugins/service_mdns.cc +++ b/src/network_inspectors/appid/service_plugins/service_mdns.cc @@ -49,7 +49,6 @@ using namespace snort; #define MDNS_PATTERN1 "\x00\x00\x84\x00\x00\x00" #define MDNS_PATTERN2 "\x00\x00\x08\x00\x00\x00" #define MDNS_PATTERN3 "\x00\x00\x04\x00\x00\x00" -#define MDNS_PATTERN4 "\x00\x00\x00\x00" #define SRV_RECORD "\x00\x21" #define SRV_RECORD_OFFSET 6 #define LENGTH_OFFSET 8 @@ -98,6 +97,50 @@ struct MatchedPatterns MatchedPatterns* next; }; +struct MdnsKeyNormEntry +{ + const char* raw_key; + unsigned raw_key_len; + const char* normalized; +}; + +static MdnsKeyNormEntry key_norm_entries[] = +{ + { "md", 2, "model" }, + { "mdl", 3, "model" }, + { "MDL", 3, "model" }, + { "usb_MDL", 7, "model" }, + { "ModelName", 9, "model" }, + { "modelid", 7, "model" }, + { "mn", 2, "model" }, + { "am", 2, "model" }, + { "rpMd", 4, "model" }, + { "mfg", 3, "manufacturer" }, + { "MFG", 3, "manufacturer" }, + { "usb_MFG", 7, "manufacturer" }, + { "integrator", 10, "manufacturer" }, + { "osxvers", 7, "osxvers" }, + { "osvers", 6, "osxvers" }, +}; + +struct KeyNormResult +{ + const char* normalized; + unsigned key_len; +}; + +static int key_norm_match(void* id, void*, int match_end_pos, void* data, void*) +{ + MdnsKeyNormEntry* entry = (MdnsKeyNormEntry*)id; + KeyNormResult* result = (KeyNormResult*)data; + if ((unsigned)(match_end_pos - entry->raw_key_len) == 0 && (unsigned)match_end_pos == result->key_len) + { + result->normalized = entry->normalized; + return 1; + } + return 0; +} + static MdnsPattern patterns[] = { { (const uint8_t*)PATTERN_STR_LOCAL_1, sizeof(PATTERN_STR_LOCAL_1) - 1 }, @@ -127,12 +170,17 @@ MdnsServiceDetector::MdnsServiceDetector(ServiceDiscovery* sd) matcher.add((const char*)patterns[i].pattern, patterns[i].length, &patterns[i]); matcher.prep(); + for (unsigned i = 0; i < sizeof(key_norm_entries) / sizeof(*key_norm_entries); i++) + key_normalizer.add((const uint8_t*)key_norm_entries[i].raw_key, key_norm_entries[i].raw_key_len, &key_norm_entries[i], false); + key_normalizer.prep(); + handler->register_detector(name, this, proto); } void MdnsServiceDetector::do_custom_reload() { matcher.reload(); + key_normalizer.reload(); } int MdnsServiceDetector::validate(AppIdDiscoveryArgs& args) @@ -188,8 +236,6 @@ int MdnsServiceDetector::validate_reply(const uint8_t* data, uint16_t size) ret_val = 1; else if (memcmp(data,MDNS_PATTERN3, sizeof(MDNS_PATTERN3)-1) == 0) ret_val = 1; - else if (memcmp(data,MDNS_PATTERN4, sizeof(MDNS_PATTERN4)-1) == 0) - ret_val = 1; else ret_val = 0; @@ -312,7 +358,7 @@ static std::string clean_mdns_string(const std::string& str) void MdnsServiceDetector::process_txt_record(const snort::Packet* pkt, const char* srv_original, const char* rdata_start, uint16_t data_len, const char* packet_end, - std::string& protocol_type, std::string& device_name, + std::string& service_type, std::string& device_name, std::vector>& kv_pairs) { const char* dns_name_start = srv_original; @@ -371,7 +417,7 @@ void MdnsServiceDetector::process_txt_record(const snort::Packet* pkt, const cha size_t dot_pos = device_name.find('.'); if (dot_pos != std::string::npos and dot_pos > 0) { - protocol_type = device_name.substr(dot_pos + DNS_LABEL_LENGTH_SKIP); + service_type = device_name.substr(dot_pos + DNS_LABEL_LENGTH_SKIP); device_name = device_name.substr(0, dot_pos); } @@ -388,9 +434,9 @@ void MdnsServiceDetector::process_txt_record(const snort::Packet* pkt, const cha } else { - if (!protocol_type.empty()) - protocol_type += "."; - protocol_type += label; + if (!service_type.empty()) + service_type += "."; + service_type += label; } name_parser += label_len; @@ -429,7 +475,12 @@ void MdnsServiceDetector::process_txt_record(const snort::Packet* pkt, const cha { key = clean_mdns_string(key); value = clean_mdns_string(value); - kv_pairs.emplace_back(key, value); + KeyNormResult result = { nullptr, (unsigned)key.size() }; + key_normalizer.find_all(key.c_str(), key.size(), key_norm_match, false, &result); + if (result.normalized) + kv_pairs.emplace_back(result.normalized, value); + else + kv_pairs.emplace_back(key, value); } } else @@ -534,16 +585,16 @@ int MdnsServiceDetector::analyze_user(AppIdSession& asd, const Packet* pkt, uint if (rdata_start + data_len > packet_end) return -1; - if (record_type == TXT_RECORD_TYPE and data_len > 0 and asd.get_odp_ctxt().mdns_deviceinfo) + if (record_type == TXT_RECORD_TYPE and data_len > 0 and asd.get_odp_ctxt().detector_deviceinfo) { - std::string protocol_type, device_name; + std::string service_type, device_name; std::vector> kv_pairs; const char* dns_name_ptr = srv_original; process_txt_record(pkt, dns_name_ptr, rdata_start, data_len, packet_end, - protocol_type, device_name, kv_pairs); - if (!protocol_type.empty() || !device_name.empty()) + service_type, device_name, kv_pairs); + if (!service_type.empty() || !device_name.empty()) { - auto device_key = std::make_pair(protocol_type, device_name); + auto device_key = std::make_pair(service_type, device_name); device_info_map[device_key] = std::move(kv_pairs); } } @@ -616,7 +667,7 @@ int MdnsServiceDetector::analyze_user(AppIdSession& asd, const Packet* pkt, uint else return 0; - if (!device_info_map.empty() and asd.get_odp_ctxt().mdns_deviceinfo) + if (!device_info_map.empty() and asd.get_odp_ctxt().detector_deviceinfo) { DeviceInfoEvent event(pkt, device_info_map); DataBus::publish(DataBus::get_id(deviceinfo_pub_key), DeviceInfoEventIds::DEVICEINFO, event); diff --git a/src/network_inspectors/appid/service_plugins/service_mdns.h b/src/network_inspectors/appid/service_plugins/service_mdns.h index 69f0801d0..6d3e567e8 100644 --- a/src/network_inspectors/appid/service_plugins/service_mdns.h +++ b/src/network_inspectors/appid/service_plugins/service_mdns.h @@ -50,9 +50,10 @@ private: int reference_pointer(const char* start_ptr, const char* end_pkt, const char** resp_endptr, int* start_index, uint16_t data_size, uint8_t* user_name_len, unsigned size, MatchedPatterns*& pattern_list); void process_txt_record(const snort::Packet* pkt, const char* srv_original, const char* rdata_start, - uint16_t data_len, const char* packet_end, std::string& protocol_type, std::string& device_name, + uint16_t data_len, const char* packet_end, std::string& service_type, std::string& device_name, std::vector>& kv_pairs); snort::SearchTool matcher; + snort::SearchTool key_normalizer; }; #endif diff --git a/src/network_inspectors/rna/rna_fingerprint_deviceinfo.cc b/src/network_inspectors/rna/rna_fingerprint_deviceinfo.cc index 8843eab05..2445220cf 100644 --- a/src/network_inspectors/rna/rna_fingerprint_deviceinfo.cc +++ b/src/network_inspectors/rna/rna_fingerprint_deviceinfo.cc @@ -81,24 +81,24 @@ void DeviceInfoRowFingerprint::set_mac(const std::string& mac) DeviceInfoFpProcessor::~DeviceInfoFpProcessor() { - delete protocol_type_mpse; + delete service_type_mpse; } void DeviceInfoFpProcessor::make_mpse(bool priority) { if (priority) { - delete protocol_type_mpse; - protocol_type_mpse = nullptr; + delete service_type_mpse; + service_type_mpse = nullptr; } - if (protocol_type_mpse or protocol_type_fps.empty()) + if (service_type_mpse or service_type_fps.empty()) return; - protocol_type_mpse = new SearchTool; - for (std::pair& kv : protocol_type_fps) - protocol_type_mpse->add(kv.second.protocol_type.c_str(), kv.second.protocol_type.size(), &kv.second); - protocol_type_mpse->prep(); + service_type_mpse = new SearchTool; + for (std::pair& kv : service_type_fps) + service_type_mpse->add(kv.second.service_type.c_str(), kv.second.service_type.size(), &kv.second); + service_type_mpse->prep(); } static int collect_rows(void* id, void*, int, void* data, void*) @@ -110,19 +110,19 @@ static int collect_rows(void* id, void*, int, void* data, void*) return 0; } -void DeviceInfoFpProcessor::get_rows(const char* protocol, +void DeviceInfoFpProcessor::get_rows(const char* service, std::vector& rows) { rows.clear(); - if (!protocol_type_mpse) + if (!service_type_mpse) return; - protocol_type_mpse->find_all(protocol, strlen(protocol), collect_rows, false, &rows); + service_type_mpse->find_all(service, strlen(service), collect_rows, false, &rows); } void DeviceInfoFpProcessor::push(const DeviceInfoRawFingerprint& raw_fp) { - DeviceInfoProtoFingerprint& proto_fp = protocol_type_fps[raw_fp.protocol_type]; - proto_fp.protocol_type = raw_fp.protocol_type; + DeviceInfoProtoFingerprint& proto_fp = service_type_fps[raw_fp.service_type]; + proto_fp.service_type = raw_fp.service_type; DeviceInfoRowFingerprint row; row.fpid = raw_fp.fpid; @@ -232,26 +232,41 @@ void RnaDeviceDiscovery::process(const snort::DeviceInfoEvent* event, RnaLogger& for (const std::pair, std::vector>>& entry : device_info_map) { - const std::string& protocol_type = entry.first.first; + const std::string& service_type = entry.first.first; const std::string& device_name = entry.first.second; const std::vector>& txt_kv_pairs = entry.second; - if (device_name.empty() || protocol_type.empty()) + if (device_name.empty() || service_type.empty()) continue; if (!is_printable_string(device_name.c_str())) continue; + std::string clean_device_name = clean_field_value(device_name); + if (is_printable_string(clean_device_name.c_str())) + { + if (rt->set_device_name(clean_device_name.c_str())) + { + debug_logf(rna_trace, pkt, "DeviceInfo: logging CHANGE_DEVICE_NAME event, name='%s'\n", + clean_device_name.c_str()); + logger.log(RNA_EVENT_CHANGE, CHANGE_DEVICE_NAME, pkt, rt, + reinterpret_cast(pkt->flow->client_ip.get_ip6_ptr()), + rt->get_last_seen_mac(mac_addr), nullptr, packet_time(), + nullptr, clean_device_name.c_str()); + } + } + std::vector rows; - processor->get_rows(protocol_type.c_str(), rows); + processor->get_rows(service_type.c_str(), rows); if (rows.empty()) { - debug_logf(rna_trace, pkt, "DeviceInfo: no fingerprint rows found for protocol %s\n", protocol_type.c_str()); + debug_logf(rna_trace, pkt, "DeviceInfo: no fingerprint rows found for service %s\n", service_type.c_str()); continue; } - std::string global_hardware_info; + std::vector matched_rows; + const MatchedRowInfo* best_hardware_row = nullptr; for (const DeviceInfoRowFingerprint* row : rows) { @@ -263,64 +278,75 @@ void RnaDeviceDiscovery::process(const snort::DeviceInfoEvent* event, RnaLogger& if (!rt->add_deviceinfo_fingerprint(row->fpid)) continue; - std::string field_values[DEVICEINFO_FIELD_MAX]; + MatchedRowInfo info; + info.row = row; for (uint8_t i = 0; i < DEVICEINFO_FIELD_MAX; i++) - field_values[i] = clean_field_value(extracted_values[i]); - - field_values[DEVICEINFO_FIELD_DEVICENAME] = clean_field_value(device_name); + info.field_values[i] = clean_field_value(extracted_values[i]); + info.field_values[DEVICEINFO_FIELD_DEVICENAME] = clean_field_value(device_name); - uint8_t mask = row->field_mask; - std::string hardware_info = field_values[DEVICEINFO_FIELD_MANUFACTURER] + - (field_values[DEVICEINFO_FIELD_MANUFACTURER].empty() || field_values[DEVICEINFO_FIELD_MODEL].empty() ? "" : " ") + - field_values[DEVICEINFO_FIELD_MODEL]; + info.hardware_info = info.field_values[DEVICEINFO_FIELD_MANUFACTURER] + + (info.field_values[DEVICEINFO_FIELD_MANUFACTURER].empty() || info.field_values[DEVICEINFO_FIELD_MODEL].empty() ? "" : " ") + + info.field_values[DEVICEINFO_FIELD_MODEL]; - if (global_hardware_info.empty() && !hardware_info.empty()) - global_hardware_info = hardware_info; + info.has_predefined_model = (row->field_mask & DEVICEINFO_MASK_MODEL) && !row->values[DEVICEINFO_FIELD_MODEL].empty(); + info.has_hardware = (row->field_mask & (DEVICEINFO_MASK_MODEL | DEVICEINFO_MASK_MANUFACTURER)) && + !info.hardware_info.empty() && is_printable_string(info.hardware_info.c_str()); - if (is_printable_string(field_values[DEVICEINFO_FIELD_DEVICENAME].c_str())) - { - debug_logf(rna_trace, pkt, "DeviceInfo: logging CHANGE_DEVICE_NAME event for fingerprint %u, name='%s'\n", - row->fpid, field_values[DEVICEINFO_FIELD_DEVICENAME].c_str()); - logger.log(RNA_EVENT_CHANGE, CHANGE_DEVICE_NAME, pkt, rt, - reinterpret_cast(pkt->flow->client_ip.get_ip6_ptr()), - rt->get_last_seen_mac(mac_addr), row, packet_time(), - hardware_info.c_str(), field_values[DEVICEINFO_FIELD_DEVICENAME].c_str()); - - rt->set_device_name(field_values[DEVICEINFO_FIELD_DEVICENAME].c_str()); - } + if (row->field_mask & DEVICEINFO_MASK_OS) + info.os_cpe = row->os_prefix + info.field_values[DEVICEINFO_FIELD_OS] + row->os_postfix; - const std::string& hw_for_os = hardware_info.empty() ? global_hardware_info : hardware_info; - if ((mask & DEVICEINFO_MASK_OS) && is_printable_string(hw_for_os.c_str())) - { - std::string os_cpe = row->os_prefix + field_values[DEVICEINFO_FIELD_OS] + row->os_postfix; - debug_logf(rna_trace, pkt, "DeviceInfo: logging NEW_OS event for fingerprint %u, os_cpe='%s'\n", - row->fpid, os_cpe.c_str()); - std::vector cpes; - cpes.push_back(os_cpe.c_str()); - FpFingerprint fp; - fp.fpid = row->fpid; - fp.fpuuid = row->fpuuid; - fp.fp_type = FpFingerprint::FpType::FP_TYPE_DEVICEINFO; - - logger.log(RNA_EVENT_NEW, NEW_OS, pkt, rt, - reinterpret_cast(pkt->flow->client_ip.get_ip6_ptr()), - rt->get_last_seen_mac(mac_addr), &fp, &cpes, packet_time(), hw_for_os.c_str()); - } + matched_rows.push_back(std::move(info)); + } + + if (matched_rows.empty()) + continue; + + for (const MatchedRowInfo& info : matched_rows) + { + if (!info.has_hardware) + continue; + if (!best_hardware_row) + best_hardware_row = &info; + else if (info.has_predefined_model && !best_hardware_row->has_predefined_model) + best_hardware_row = &info; + } + + const std::string& preferred_hardware_info = best_hardware_row ? best_hardware_row->hardware_info : ""; - if ((mask & (DEVICEINFO_MASK_MODEL | DEVICEINFO_MASK_MANUFACTURER)) && is_printable_string(hardware_info.c_str())) + bool os_logged = false; + for (const MatchedRowInfo& info : matched_rows) + { + if (!os_logged && (info.row->field_mask & DEVICEINFO_MASK_OS) && !info.os_cpe.empty()) { - bool is_high_priority = (mask & DEVICEINFO_MASK_MODEL) && !row->values[DEVICEINFO_FIELD_MODEL].empty(); - if (rt->set_deviceinfo_hardware(hardware_info, is_high_priority)) + const std::string& hw_for_os = info.hardware_info.empty() ? preferred_hardware_info : info.hardware_info; + if (is_printable_string(hw_for_os.c_str())) { - debug_logf(rna_trace, pkt, "DeviceInfo: logging NEW_OS hardware event for fingerprint %u, hardware='%s'\n", - row->fpid, hardware_info.c_str()); + debug_logf(rna_trace, pkt, "DeviceInfo: logging NEW_OS event for fingerprint %u, os_cpe='%s'\n", + info.row->fpid, info.os_cpe.c_str()); + std::vector cpes; + cpes.push_back(info.os_cpe.c_str()); + FpFingerprint fp; + fp.fpid = info.row->fpid; + fp.fpuuid = info.row->fpuuid; + fp.fp_type = FpFingerprint::FpType::FP_TYPE_DEVICEINFO; + logger.log(RNA_EVENT_NEW, NEW_OS, pkt, rt, reinterpret_cast(pkt->flow->client_ip.get_ip6_ptr()), - rt->get_last_seen_mac(mac_addr), row, packet_time(), - hardware_info.c_str(), nullptr); + rt->get_last_seen_mac(mac_addr), &fp, &cpes, packet_time(), hw_for_os.c_str()); + os_logged = true; } } } + + if (best_hardware_row && rt->set_deviceinfo_hardware(best_hardware_row->hardware_info, best_hardware_row->has_predefined_model)) + { + debug_logf(rna_trace, pkt, "DeviceInfo: logging NEW_OS hardware event for fingerprint %u, hardware='%s'\n", + best_hardware_row->row->fpid, best_hardware_row->hardware_info.c_str()); + logger.log(RNA_EVENT_NEW, NEW_OS, pkt, rt, + reinterpret_cast(pkt->flow->client_ip.get_ip6_ptr()), + rt->get_last_seen_mac(mac_addr), best_hardware_row->row, packet_time(), + best_hardware_row->hardware_info.c_str(), nullptr); + } } } @@ -337,7 +363,7 @@ TEST_CASE("get_rows_basic", "[rna_fingerprint_deviceinfo]") rawfp.fpid = 100606; rawfp.fp_type = 15; rawfp.fpuuid = "680f888c-8f20-4fed-ad9b-c9875d206fcb"; - rawfp.protocol_type = "_airplay._tcp.local"; + rawfp.service_type = "_airplay._tcp.local"; rawfp.manufacturer_pattern = "manufacturer="; rawfp.model_pattern = "model="; processor->push(rawfp); @@ -361,7 +387,7 @@ TEST_CASE("get_rows_with_values", "[rna_fingerprint_deviceinfo]") rawfp.fpid = 100604; rawfp.fp_type = 15; rawfp.fpuuid = "6a23f14f-e02a-46bd-95d3-e18853083dc3"; - rawfp.protocol_type = "_printer._tcp.local"; + rawfp.service_type = "_printer._tcp.local"; rawfp.manufacturer_pattern = "usb_MFG="; rawfp.manufacturer = "HP"; rawfp.model_pattern = "usb_MDL="; @@ -385,7 +411,7 @@ TEST_CASE("get_rows_multiple_same_protocol", "[rna_fingerprint_deviceinfo]") fp1.fpid = 100601; fp1.fp_type = 15; fp1.fpuuid = "ecd3e238-44e1-4cb3-8383-49d83f4f8d5b"; - fp1.protocol_type = "_mediaremotetv._tcp.local"; + fp1.service_type = "_mediaremotetv._tcp.local"; fp1.model_pattern = "model="; processor.push(fp1); @@ -393,7 +419,7 @@ TEST_CASE("get_rows_multiple_same_protocol", "[rna_fingerprint_deviceinfo]") fp2.fpid = 100602; fp2.fp_type = 15; fp2.fpuuid = "cefa3bb2-eb5f-447e-aa7d-64bda5a49ae5"; - fp2.protocol_type = "_mediaremotetv._tcp.local"; + fp2.service_type = "_mediaremotetv._tcp.local"; fp2.model_pattern = "model="; fp2.manufacturer_pattern = "mfg="; processor.push(fp2); @@ -427,7 +453,7 @@ TEST_CASE("get_rows_with_predefined_values", "[rna_fingerprint_deviceinfo]") rawfp.fpid = 100611; rawfp.fp_type = 15; rawfp.fpuuid = "google-cast-uuid"; - rawfp.protocol_type = "_googlecast._tcp.local"; + rawfp.service_type = "_googlecast._tcp.local"; rawfp.model_pattern = "md="; rawfp.model = "Chromecast"; rawfp.manufacturer_pattern = "fn="; @@ -453,7 +479,7 @@ TEST_CASE("get_rows_mac_address", "[rna_fingerprint_deviceinfo]") rawfp.fpid = 100600; rawfp.fp_type = 15; rawfp.fpuuid = "d827d911-e50e-404f-9f5d-5aa56b580b35"; - rawfp.protocol_type = "_hap._tcp.local"; + rawfp.service_type = "_hap._tcp.local"; rawfp.manufacturer_pattern = "md="; rawfp.manufacturer = "Apple"; rawfp.mac_addr = "A4:83:E7"; @@ -477,7 +503,7 @@ TEST_CASE("get_rows_field_mask", "[rna_fingerprint_deviceinfo]") rawfp.fpid = 100700; rawfp.fp_type = 15; rawfp.fpuuid = "field-mask-test-uuid"; - rawfp.protocol_type = "_test._tcp.local"; + rawfp.service_type = "_test._tcp.local"; rawfp.manufacturer_pattern = "mfg="; rawfp.model_pattern = "mdl="; rawfp.os_pattern = "os="; diff --git a/src/network_inspectors/rna/rna_fingerprint_deviceinfo.h b/src/network_inspectors/rna/rna_fingerprint_deviceinfo.h index 9793c5378..27f4ff3e5 100644 --- a/src/network_inspectors/rna/rna_fingerprint_deviceinfo.h +++ b/src/network_inspectors/rna/rna_fingerprint_deviceinfo.h @@ -76,14 +76,14 @@ public: class SO_PUBLIC DeviceInfoProtoFingerprint { public: - std::string protocol_type; + std::string service_type; std::vector rows; }; class SO_PUBLIC DeviceInfoRawFingerprint : public FpFingerprint { public: - std::string protocol_type; + std::string service_type; std::string manufacturer_pattern; std::string manufacturer; std::string model_pattern; @@ -104,17 +104,27 @@ public: void make_mpse(bool priority = false); void push(const DeviceInfoRawFingerprint&); - void get_rows(const char* protocol, std::vector& rows); + void get_rows(const char* service, std::vector& rows); - bool has_pattern() const { return protocol_type_mpse != nullptr; } + bool has_pattern() const { return service_type_mpse != nullptr; } private: - std::unordered_map protocol_type_fps; - snort::SearchTool* protocol_type_mpse = nullptr; + std::unordered_map service_type_fps; + snort::SearchTool* service_type_mpse = nullptr; }; } +struct MatchedRowInfo +{ + const snort::DeviceInfoRowFingerprint* row = nullptr; + std::string field_values[snort::DEVICEINFO_FIELD_MAX]; + std::string hardware_info; + std::string os_cpe; + bool has_predefined_model = false; + bool has_hardware = false; +}; + class RnaDeviceDiscovery { public: diff --git a/src/network_inspectors/rna/rna_module.cc b/src/network_inspectors/rna/rna_module.cc index b8df29595..035d5ee35 100644 --- a/src/network_inspectors/rna/rna_module.cc +++ b/src/network_inspectors/rna/rna_module.cc @@ -341,8 +341,8 @@ static const Parameter rna_fp_params[] = { "flags", Parameter::PT_INT, "0:max32", nullptr, "smb flags" }, - { "protocol_type", Parameter::PT_STRING, nullptr, nullptr, - "deviceinfo protocol type" }, + { "service_type", Parameter::PT_STRING, nullptr, nullptr, + "deviceinfo service type" }, { "manufacturer_pattern", Parameter::PT_STRING, nullptr, nullptr, "deviceinfo manufacturer pattern" }, @@ -504,7 +504,7 @@ bool RnaModule::begin(const char* fqn, int, SnortConfig*) deviceinfo_fingerprint.fpid = 0; deviceinfo_fingerprint.fp_type = 0; deviceinfo_fingerprint.fpuuid.clear(); - deviceinfo_fingerprint.protocol_type.clear(); + deviceinfo_fingerprint.service_type.clear(); deviceinfo_fingerprint.manufacturer_pattern.clear(); deviceinfo_fingerprint.manufacturer.clear(); deviceinfo_fingerprint.model_pattern.clear(); @@ -605,8 +605,8 @@ bool RnaModule::set(const char* fqn, Value& v, SnortConfig*) fingerprint.smb_minor = v.get_uint32(); else if (v.is("flags")) fingerprint.smb_flags = v.get_uint32(); - else if (v.is("protocol_type")) - deviceinfo_fingerprint.protocol_type = v.get_string(); + else if (v.is("service_type")) + deviceinfo_fingerprint.service_type = v.get_string(); else if (v.is("manufacturer_pattern")) deviceinfo_fingerprint.manufacturer_pattern = v.get_string(); else if (v.is("manufacturer")) diff --git a/src/pub_sub/deviceinfo_events.h b/src/pub_sub/deviceinfo_events.h index 081424c88..6a3b75a88 100644 --- a/src/pub_sub/deviceinfo_events.h +++ b/src/pub_sub/deviceinfo_events.h @@ -41,12 +41,17 @@ struct DeviceInfoEventIds { enum : unsigned { DEVICEINFO, num_ids }; }; const PubKey deviceinfo_pub_key { "deviceinfo", DeviceInfoEventIds::num_ids }; +constexpr const char* DEVINFO_SERVICE_NULL = "*"; +constexpr const char* DEVINFO_META_SERVICE_TYPE = "service_type"; +constexpr const char* DEVINFO_KEY_DEVICENAME = "devicename"; + // DataEvent that contains device identification data including protocol type, device name, and attributes class DeviceInfoEvent : public DataEvent { public: // Composite key for unique device identification consisting of protocol type and device name - // The protocol type identifies the network protocol (e.g., "_airplay._tcp.local", "_http._tcp.local") + // The service type identifies the service advertised in service discovery protocols ( e.g. mDNS/DNS-SD service ) + // wherever applicable or it should be a wildcard // The device name identifies the specific device instance (e.g., "John's iPhone", "Office Printer") using DeviceKey = std::pair; @@ -57,7 +62,7 @@ public: // Maps device identifiers to their corresponding attribute collections // Allows multiple devices to be tracked within a single event, each with their own attributes - // Key: (protocol_type, device_name), Value: vector of device attribute key-value pairs + // Key: (service_type, device_name), Value: vector of device attribute key-value pairs using DeviceInfoMap = std::map; // Constructor for creating an event containing multiple devices with their attributes @@ -68,12 +73,12 @@ public: // Constructor for creating an event containing a single device with its attributes // Used when network protocol analysis identifies a specific device and its characteristics - // The device is uniquely identified by protocol type and device name combination - DeviceInfoEvent(const snort::Packet* p, const std::string& protocol_type, + // The device is uniquely identified by service type and device name combination + DeviceInfoEvent(const snort::Packet* p, const std::string& service_type, const std::string& device_name, const KeyValueVector& kv_pairs) : pkt(p) { - device_info_map[std::make_pair(protocol_type, device_name)] = kv_pairs; + device_info_map[std::make_pair(service_type, device_name)] = kv_pairs; } const Packet* get_packet() const override @@ -82,13 +87,13 @@ public: const DeviceInfoMap& get_device_info_map() const { return device_info_map; } - // Retrieve device attributes for a specific device identified by protocol type and device name + // Retrieve device attributes for a specific device identified by service type and device name // Returns nullptr if the specified device is not found in this event // Used by subscribers to extract specific device information from the event - const KeyValueVector* get_key_value_pairs(const std::string& protocol_type, + const KeyValueVector* get_key_value_pairs(const std::string& service_type, const std::string& device_name) const { - auto it = device_info_map.find(std::make_pair(protocol_type, device_name)); + auto it = device_info_map.find(std::make_pair(service_type, device_name)); return (it != device_info_map.end()) ? &it->second : nullptr; }