Add passive mDNS/Bonjour discovery scanner

Introduce a second discovery module that passively listens for mDNS
multicast announcements (224.0.0.251:5353) and feeds discovered devices
into the existing devices/events/notifications pipeline, running in its
own task alongside the ARP scanner.

Since mDNS carries an IP and hostname but no MAC (the device key), the
module resolves IP->MAC via the OS ARP cache with a targeted ARP-probe
fallback. The advertised hostname is stored in a new optional `name`
column on devices (blank for ARP-only devices); the single `update`
writes `name` only when set so ARP rescans never clobber it. Device
names are included in event/notification messages.

Adds a GET /api/mdns_scanner/status endpoint (is_listening, devices_seen,
last_device_seen_seconds_ago) wired into OpenAPI, an optional
[mdns_scanner] config section, and the corresponding Nix module option.
Also aligns the Nix module's stale `timings` section with the current
`arp_scanner` schema.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
rzuasti
2026-05-29 09:37:33 -04:00
co-authored by Claude Opus 4.7
parent 2fe850c070
commit ca83009944
26 changed files with 778 additions and 157 deletions
+9 -4
View File
@@ -31,21 +31,26 @@ in {
description = "Log level for the oott service";
default = "info";
};
timings.wait_between_scans = mkOption {
arp_scanner.wait_between_scans = mkOption {
type = types.str;
description = "Wait time between scans. This does not include the scan time.";
default = "15m";
default = "30m";
};
timings.arp_sender_timeout = mkOption {
arp_scanner.sender_timeout = mkOption {
type = types.str;
description = "If the ARP sender process takes longer than this it will be stopped (for a class C network - 254 IPs - it should take less than a minute).";
default = "1m";
};
timings.arp_scan_duration = mkOption {
arp_scanner.scan_duration = mkOption {
type = types.str;
description = "How long to wait for response packets on each scan (5m to 10m is a good timeframe for a class B or C network).";
default = "10m";
};
mdns_scanner.probe_timeout = mkOption {
type = types.str;
description = "When an mDNS-discovered IP is not in the OS ARP cache, how long to wait for a targeted ARP probe reply to resolve its MAC address.";
default = "2s";
};
notifications.method = mkOption {
type = types.str;
description = "For now just pushover, you can set this to none to avoid sending notifications (it will just log).";