Files
oott/backend/src/data/mac_vendor_finder.rs
T
rzuastiandClaude Opus 4.7 98a23aa7fd Deduce vendor from mDNS services for privacy MACs
Modern devices increasingly use randomized ("Private WiFi Address") MACs,
which are locally administered and have no real OUI, so the MAC-prefix
vendor lookup returns nothing. Such devices still advertise distinctive
mDNS service types, which we now use to deduce their vendor.

- Extend the mDNS parser to also capture PTR service types alongside
  A-record hostnames.
- Add a service-type -> vendor mapping (data/mdns-service-vendor.json) and
  a service_vendor_finder, using canonical vendor names so device-type
  resolution still chains.
- Add utils::network::is_locally_administered to detect randomized MACs.
- In the mDNS scanner, fall back to service-based deduction only when the
  OUI lookup is empty and the MAC is locally administered.
- Group the three finders under a new data module.
- Preserve a known vendor (and its derived device_type) when a later
  sighting cannot deduce one, and suppress the spurious "vendor changed"
  notification in that case.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-29 13:56:39 -04:00

54 lines
1.5 KiB
Rust

use lazy_static::lazy_static;
use log::{debug, error, info};
use serde::Deserialize;
use std::collections::HashMap;
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
struct MacRecord {
pub mac_prefix: String,
pub vendor_name: String,
// private: bool,
// block_type: String,
// last_update: String,
}
// Initialize mac vendors database as a static lazy loaded unit
lazy_static! {
static ref MAC_VENDORS_DATABASE: HashMap<String, String> = {
info!("Loading MAC vendor database into memory");
let mut database = HashMap::new();
let data = include_str!("../../data/mac-vendors-export.json");
let json: Vec<MacRecord> = match serde_json::from_str(data) {
Ok(value) => value,
Err(error) => {
error!(
"Error parsing mac vendors database (data/mac-vendors-export.json): {error}"
);
panic!(
"Error parsing mac vendors database (data/mac-vendors-export.json): {error}"
);
}
};
debug!("Found {} records in the database", json.len());
for el in json {
database.insert(el.mac_prefix.to_uppercase(), el.vendor_name);
}
info!("MAC vendor database loaded");
database
};
}
// Find a vendor based on the MAC prefix
pub fn find(mac_prefix: String) -> String {
MAC_VENDORS_DATABASE
.get(&mac_prefix.to_uppercase())
.unwrap_or(&"".to_string())
.to_string()
}