]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
appid: Lua API for publishing deviceinfo event
authorUmang Sharma <umasharm@cisco.com>
Wed, 8 Apr 2026 20:14:33 +0000 (16:14 -0400)
committerGitHub <noreply@github.com>
Wed, 8 Apr 2026 20:14:33 +0000 (16:14 -0400)
src/network_inspectors/appid/app_info_table.cc
src/network_inspectors/appid/appid_config.h
src/network_inspectors/appid/lua_detector_api.cc
src/network_inspectors/appid/service_plugins/service_mdns.cc
src/network_inspectors/appid/service_plugins/service_mdns.h
src/network_inspectors/rna/rna_fingerprint_deviceinfo.cc
src/network_inspectors/rna/rna_fingerprint_deviceinfo.h
src/network_inspectors/rna/rna_module.cc
src/pub_sub/deviceinfo_events.h

index 7d797bb83a1f5d6dc4bee8c24ed003d2b0494564..ef9960f75f86a745707ea2704177c047edb45947 100644 (file)
@@ -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")))
index c6390d562e1937d0ce9a9efc5f2a73a0a26ce250..c31a55f7158f81b3c5d03502931368dd24f47c36 100644 (file)
@@ -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;
index 5863be9fe87692ad5676a28267d85e6283aa1edd..216c5989956e507ba270d443df4ba1847c015994 100644 (file)
@@ -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<LuaObject>::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
index e0623cbb46930044eca567569053ec34623bddfb..873bcd64ffc258f3e963ae4df69b9329907803f7 100644 (file)
@@ -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<std::pair<std::string, std::string>>& 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<std::pair<std::string, std::string>> 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);
index 69f0801d0b0d4b97c64a94d6c6a825d09369d95c..6d3e567e81b60251e5b7c48984825d98434f6544 100644 (file)
@@ -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<std::pair<std::string, std::string>>& kv_pairs);
 
     snort::SearchTool matcher;
+    snort::SearchTool key_normalizer;
 };
 #endif
index 8843eab05beffc7cb538a8ec0a2d75c1949dd230..2445220cf01004cd0736993d2d320758d3c26071 100644 (file)
@@ -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<const std::string, DeviceInfoProtoFingerprint>& 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<const std::string, DeviceInfoProtoFingerprint>& 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<const DeviceInfoRowFingerprint*>& 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<const std::pair<std::string, std::string>, std::vector<std::pair<std::string, std::string>>>& 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<std::pair<std::string, std::string>>& 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<const struct in6_addr*>(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<const DeviceInfoRowFingerprint*> 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<MatchedRowInfo> 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<const struct in6_addr*>(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<const char*> 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<const struct in6_addr*>(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<const char*> 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<const struct in6_addr*>(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<const struct in6_addr*>(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=";
index 9793c5378da0b724bacd8049bdec98aec025cc7e..27f4ff3e507f6e222fc8f2aa3957d8dc22f238ae 100644 (file)
@@ -76,14 +76,14 @@ public:
 class SO_PUBLIC DeviceInfoProtoFingerprint
 {
 public:
-    std::string protocol_type;
+    std::string service_type;
     std::vector<DeviceInfoRowFingerprint> 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<const DeviceInfoRowFingerprint*>& rows);
+    void get_rows(const char* service, std::vector<const DeviceInfoRowFingerprint*>& rows);
 
-    bool has_pattern() const { return protocol_type_mpse != nullptr; }
+    bool has_pattern() const { return service_type_mpse != nullptr; }
 
 private:
-    std::unordered_map<std::string, DeviceInfoProtoFingerprint> protocol_type_fps;
-    snort::SearchTool* protocol_type_mpse = nullptr;
+    std::unordered_map<std::string, DeviceInfoProtoFingerprint> 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:
index b8df295959a51f1e7d6d38baf19400f864213971..035d5ee3580230a24954a2d60f11fa9300910451 100644 (file)
@@ -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"))
index 081424c883f2fca3f0fc39e298436c586cbae52b..6a3b75a88b32d9b698cac4d85a53c050e007c254 100644 (file)
@@ -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<std::string, std::string>;
 
@@ -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<DeviceKey, KeyValueVector>;
 
     // 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;
     }