Fix the TUN setup recipe: the overlay address was being flushed

The setup this tool printed did not work, and the agent then correctly
refused to start. A persistent TUN interface has no carrier until a process
attaches to it, and Linux flushes IPv6 addresses from an interface that
loses carrier unless net.ipv6.conf.<dev>.keep_addr_on_down is set, which it
is not by default. So `ip -6 address add` on a freshly created interface
silently lost the address before the agent ever ran.

The recipe now brings the link up first, sets keep_addr_on_down, and adds
the address with `nodad` — without which duplicate address detection can
never finish on an interface with no carrier and the address stays
tentative and unusable.

The agent's own retry loop made this worse: it attached, failed the address
check, dropped the device and toggled the carrier, which flushed the
address again. The check now runs before attaching to an existing
interface, so looking is not destructive.

Failures are self-diagnosing now: the check parses the IFA_F_* flags, tells
tentative and DAD-failed apart from missing, and lists the addresses the
interface actually has.

Four new tests, including one that reads this host's real /proc/net/if_inet6
and one that pins the ordering of the setup commands.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
tsunagi
2026-09-21 12:36:16 +01:00
co-authored by Claude Opus 5
parent 0f8a4eb485
commit 38beb762d8
5 changed files with 256 additions and 28 deletions
+5
View File
@@ -190,6 +190,11 @@ async fn main() -> Result<()> {
* **Userspace costs CPU.** Kernel WireGuard is faster. A kernel backend could
return behind the same boundary, but it would give up transport-provided NAT
traversal unless paired with a local proxy.
* **A persistent TUN interface needs `keep_addr_on_down`.** Without a process
attached it has no carrier, and Linux then flushes its IPv6 addresses. The
setup printed by `tsunagi tun-setup` sets it; the agent checks the address is
present *and usable* — not tentative, not DAD-failed — before attaching, and
reports what it actually found.
* **The agent cannot assign the overlay address itself.** The `tun` crate sets
addresses through an IPv4-only ioctl, so the IPv6 overlay address must come
from `ip -6 address add` or an equivalent. The agent verifies the address is