Skip to content

feat: resilient iface watch and per-interface .local answers - #7

Merged
keskad merged 6 commits into
mainfrom
feat/iface-reliability-per-iface-resolve
Aug 12, 2026
Merged

feat: resilient iface watch and per-interface .local answers#7
keskad merged 6 commits into
mainfrom
feat/iface-reliability-per-iface-resolve

Conversation

@keskad

@keskad keskad commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Survive network drop/return and interface add/remove without crashing: rtnetlink watcher plus polling fallback refreshes the advertisement set; missing configured interfaces log a warning and retry.
  • Add optional interfaces allowlist (empty = all usable ifaces) alongside existing skipInterfaces.
  • Own hostname A/AAAA answers per receiving interface via IP_PKTINFO / IPV6_PKTINFO, so a WiFi client resolving bigfred.local gets the WiFi address. mdns-sd registers PTR/SRV/TXT only (no host A/AAAA).

Test plan

  • cargo test
  • cargo clippy --all-targets -- -D warnings
  • On a multi-homed host: resolve bigfred.local from a WiFi client and confirm the WiFi IP (not Ethernet)
  • Bring an interface down/up and confirm daemon stays up, logs warn/recover, and re-joins multicast
  • Config with "interfaces": ["eth"] while only wlan0 is up: warn, no crash; restore eth → recover

Made with Cursor

keskad and others added 6 commits August 12, 2026 08:16
Survive network drop/return and interface add/remove via rtnetlink (with
polling fallback), add an optional interfaces allowlist, and answer
hostname A/AAAA from the receiving interface so WiFi clients get the
WiFi address.

Co-authored-by: Cursor <cursoragent@cursor.com>
Bound the iface-change channel, recover poisoned mutexes instead of
unwrapping, isolate Linux FFI in sys/, introduce IfaceAddr4/6 newtypes,
drop intermediate Vecs in per-iface choosers, narrow iface_watch to
pub(crate), and run release-assertions in CI.

Co-authored-by: Cursor <cursoragent@cursor.com>
When the usable interface set changes, log each interface name, ifindex,
and IPv4/IPv6 addresses. On mDNS multicast join, log iface, local IP, and
group so operators can see which address serves which interface.

Co-authored-by: Cursor <cursoragent@cursor.com>
Suppressing host A/AAAA records in mdns-sd (relying solely on the
legacy unicast responder) broke local `.local` resolution on hosts
running avahi-daemon + nss-mdns: avahi ignores self-originated unicast
responses (RFC 6762 §11 / SO_REUSEPORT delivery), so it never cached
bigfred.local and getent/ping timed out.

Re-enable A/AAAA publication through mdns-sd's multicast announcements
(preferred IPv4 + IPv6, allow/skip filtered), falling back to
enable_addr_auto() when no interface has an address yet. This restores
the pre-PR behavior where avahi caches the multicast A/AAAA and
nss-mdns resolves locally. The legacy unicast responder still answers
direct (non-5353) legacy queries for old Android clients.

Co-authored-by: Cursor <cursoragent@cursor.com>
Address review findings from PR #7:

1. DesiredAds only tracked IPv4 `ips`, so SLAAC/privacy IPv6 address
   churn left mdns-sd AAAA announcements stale (reconcile was skipped
   because `desired == last_desired` held when IPv4 was stable). Add
   `ips_v6: Vec<Ipv6Addr>` to DesiredAds and include it in the
   `ips_changed` comparison so A/AAAA are re-registered on IPv6 changes.

2. refresh_memberships compared sorted+deduped `want_v4` against
   `joined_v4` which was appended in declaration order, so with 2+ IPv4
   addresses the membership flapped (leave/rejoin) on every refresh.
   Sort+dedup `joined_v4` after the join loop so the set comparison is
   order-independent.

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
@keskad
keskad merged commit ec75549 into main Aug 12, 2026
2 checks passed
@keskad
keskad deleted the feat/iface-reliability-per-iface-resolve branch August 12, 2026 07:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant