Commit Graph
2 Commits
Author SHA1 Message Date
tsunagiandClaude Opus 5 cfab38824d Make the overlay dual stack
Every member now also derives an IPv4 address, from the same inputs as its
IPv6 one, into 100.64.0.0/10 by default. The range is configurable and IPv4
can be turned off with --no-ipv4.

IPv4 is honestly weaker than IPv6 here and the code says so. A 64 bit
interface identifier makes an IPv6 collision impossible in practice; IPv4
has nothing like that room, and in a /10 with 50 members two will derive the
same address about 0.03% of the time. A mesh with no coordinator cannot
allocate around that, so a collision is detected and resolved instead: the
member whose public key sorts lower keeps the address, a rule every member
computes identically and therefore agrees on. The other keeps IPv6 and is
flagged in the status. IPv6 always works; IPv4 almost always works and
degrades predictably.

Routing and address-ownership enforcement now cover both families: a packet
goes to the peer that owns its destination, and a decrypted packet is
dropped unless its source is an address derived for the peer that sent it,
IPv4 included.

Six new tests, among them a real IPv4 packet crossing a tunnel next to an
IPv6 one, a spoofed IPv4 source being dropped, and an IPv6-only overlay.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-21 13:00:35 +01:00
tsunagiandClaude Opus 5 be459e5bd0 Add tsunagi status over a local control socket
There was no way to ask a running agent what it was doing; the only status
came from the periodic print of the `up` process itself.

The new ipc module is an adapter over the public API: nothing in the agent
core knows it exists, so a Windows named pipe or an authenticated loopback
socket can be added beside it. It is also a different interface from the
peer-to-peer protocol — between processes on one machine, authorised by
filesystem permissions rather than the network secret. The socket is 0600
inside an owner-only directory, the wire format is length-prefixed postcard
with the same bounds the network protocol uses, and the report types are
their own stable format rather than the crate's internals.

The socket path is derived from the state directory into XDG_RUNTIME_DIR
when there is one. A Unix socket address is limited to about 100 bytes, and
a deeply nested state directory overflows it — which is exactly what
happened on the first attempt.

Two presentation fixes while here. Multicast is counted separately from
unroutable traffic, because Linux emits multicast on every IPv6 interface
and it was showing up as "packets for unknown addresses" on a healthy
agent. And WireGuard protocol errors are no longer added into the dropped
counter: a few are normal while both ends start a handshake at once, and a
working tunnel was reporting "dropped 3" with no traffic at all.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-21 12:53:04 +01:00