Files
ddidderr 4d5881d6b0 fix(mdns): retain origin and bound daemon state
Vendor the pinned mdns-sd 0.21.1 source so response records retain their observed source IP. Bound unauthenticated cache records to 1024 globally and 128 per source, deduplicate and cap timers at 4096, and poll at least once per second for expiry cleanup.

Expose packet provenance through lanspread-mdns, drop originless resolutions, and add a dedicated vendor test recipe while keeping third-party sources outside workspace formatting and Clippy.

Test Plan:
- just mdns-vendor-test (106 tests passed with socket access)
- just test
- just fmt
- just clippy
- cache/per-source, exact-refresh, timer-cap, and serde tests
- git diff --check
2026-09-12 13:08:26 +02:00

101 lines
3.3 KiB
Rust

//! A mDNS query client.
//!
//! Run with:
//!
//! cargo run --example query <service_type_without_domain>
//!
//! Example:
//!
//! cargo run --example query _my-service._udp
//!
//! Note: there is no '.' at the end as the program adds ".local."
//! automatically.
//!
//! Keeps listening for new events.
use mdns_sd::{ServiceDaemon, ServiceEvent};
fn main() {
env_logger::builder().format_timestamp_millis().init();
let mut service_type = match std::env::args().nth(1) {
Some(arg) => arg,
None => {
print_usage();
return;
}
};
service_type.push_str(".local.");
// Showcase `verify` functionality for IPv4 addresses
let should_verify = match std::env::args().nth(2) {
Some(arg) if arg == "--verify" => true,
_ => false,
};
// Create a daemon
let mdns = ServiceDaemon::new().expect("Failed to create daemon");
// Browse for the service type
let receiver = mdns.browse(&service_type).expect("Failed to browse");
let now = std::time::Instant::now();
while let Ok(event) = receiver.recv() {
match event {
ServiceEvent::ServiceResolved(info) => {
println!(
"At {:?}: Resolved a new service: {}\n host: {}\n port: {}",
now.elapsed(),
info.fullname,
info.host,
info.port,
);
let mut found_ipv4 = false;
for addr in info.addresses.iter() {
println!(" Address: {addr}");
if addr.is_ipv4() {
found_ipv4 = true;
}
}
for prop in info.txt_properties.iter() {
println!(" Property: {}", prop);
}
if should_verify && found_ipv4 {
println!("Will verify after 3 seconds...");
std::thread::sleep(std::time::Duration::from_secs(3));
let instance_fullname = info.fullname;
let timeout = std::time::Duration::from_secs(2);
if let Err(e) = mdns.verify(instance_fullname, timeout) {
println!("Verify failed: {}", e);
} else {
println!("Verify started");
}
}
}
ServiceEvent::ServiceRemoved(service_type, fullname) => {
println!(
"At {:?}: ** service removed **: {service_type}: {fullname}",
now.elapsed(),
);
}
other_event => {
println!("At {:?}: {:?}", now.elapsed(), &other_event);
}
}
}
}
fn print_usage() {
println!("Usage: cargo run --example query <service_type_without_domain_postfix> [--verify]");
println!("Example: ");
println!("cargo run --example query _my-service._udp");
println!();
println!("Options:");
println!("--verify: make the client attempt to verify IPv4 addresses of resolved services.");
println!();
println!("You can also do a meta-query per RFC 6763 to find which services are available:");
println!("cargo run --example query _services._dns-sd._udp");
}