feat: resilient iface watch and per-interface .local answers - #7
Merged
Conversation
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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
interfacesallowlist (empty = all usable ifaces) alongside existingskipInterfaces.IP_PKTINFO/IPV6_PKTINFO, so a WiFi client resolvingbigfred.localgets the WiFi address. mdns-sd registers PTR/SRV/TXT only (no host A/AAAA).Test plan
cargo testcargo clippy --all-targets -- -D warningsbigfred.localfrom a WiFi client and confirm the WiFi IP (not Ethernet)"interfaces": ["eth"]while onlywlan0is up: warn, no crash; restore eth → recoverMade with Cursor