Separate internal WireGuard encryption from data carriers

AWG-only policy also selected a competing end-to-end plugin, so compatible
external links could still have no compatible encrypted data channel. Carrier
changes replaced tunnel state and status selected counters from different
engines. Use one internal WireGuard plugin and a separate DataCarrier contract
for external capabilities/lifecycle. Keep the logical link, keys, handshake,
interface and counter epoch across policy, fallback and direct/relay changes.
Control/discovery transport selection and membership remain independent.

Share the bounded per-neighbour UDP WireGuard engine between ordinary WG and
Amnezia masking. Encrypt the relay envelope inside the outer hop channel with
fresh pair keys/PSK. Remove duplicate WG key/device code and the TCP/TLS inner
cipher. TLS carries opaque internal WireGuard frames. Refuse missing native
transports instead of letting default iroh impersonate their protocol names.
Probe the actual authenticated carrier, independently of the shared IP tunnel;
failed local probe submissions count as loss too.

Apply the vendored iroh interface exclusion to actual direct candidates, not
just public discovery records. Exclude overlay subnets from introductions and
propagate the actual owned interface name, including kernel-assigned utun names,
to every carrier. Production logs showed paths through the overlay itself.
This removes a recursive transport path; it does not establish the historical
cause of the reported 100 GB absolute counter. Exit-node traffic is also real
peer IP traffic even when local applications are idle.

Hide inner cipher choices/handshake clutter in CLI and tray. Report external
routes, readiness and actionable policy/version failures. Count original IP
packets only when their ciphertext is accepted by the logical transport,
including queued packets' exact unpadded lengths. Exclude physical probes and
keepalives. Export counter epochs; sum per-peer rate deltas and discard stale
histories so joins/restarts cannot turn old totals into fresh traffic. Status
also prints exact IP byte totals for comparison with the tray.

Coordinated upgrade: data ALPN 6, internal wireguard-e2e capability v4,
wg/awg v2, QUIC carrier v1, TLS v2, local IPC v23. Control ALPN 8, device/network
identity derivation, signed records and saved network choices stay unchanged.
Keep the historical wg-quic key store; transactionally import missing keys from
wg then awg without replacing canonical keys. Forget removes legacy copies too,
on the blocking pool, to prevent resurrection after restart. Preserve historic
cipher options as shared settings, rejecting contradictory values.

Validation on Linux in the Nix development shell:
- cargo fmt --all -- --check
- cargo clippy --locked --workspace --all-targets -- -D warnings
- cargo test --locked --workspace --all-targets (562 passed, 3 ignored)
The inherited service socket/secret/group environment overrides were removed
for isolated CLI process tests. A new carrier test initially raced the first
peer announcement; its deadline polling now waits for a peer row explicitly.
Real loopback endpoints, membership, SQLite, WG/AWG/TLS encryption and memory
TUNs cover mixed-carrier relaying and one smoltcp TCP connection surviving
relay/direct/policy changes and a dropped transmission. Counter tests check
exact plaintext lengths, refused sends, epochs, joins and stale histories.
Public DHT, privileged kernel and manual benchmark tests remain ignored;
macOS/Windows native TUNs, desktop GUI and WAN/DPI behavior were not run.
This commit is contained in:
Aleksandr Bogomiakov committed 2026-10-22 01:07:52 +01:00
1 parent 8a6216bccb
commit 2166ba4800
76 files changed
+3903 -6811

No files matched your search

+13 -11
View File
@@ -16,8 +16,8 @@ the default 1280-byte interface MTU also works on small QUIC paths.
Each authenticated control session advertises that peer's own direct data
links. There is one table for each network, whatever protocols run over it: a
link is a way to reach a neighbour, and a protocol is an end-to-end tunnel to a
peer. The envelope names the protocol, so the two are independent. A neighbour
link is a way to reach a neighbour, while the single internal protocol is an
end-to-end tunnel to a peer. The envelope names the protocol, so the two are independent. A neighbour
reached over several kinds of transport (UDP, TCP, QUIC datagrams) is sent to
over the best open one, in the order the protocols were configured, and over
the next if that one fails or cannot carry the frame. Every authenticated
@@ -28,14 +28,16 @@ Link arrival, closure and changed announcements rebuild routes immediately.
Unchanged announcements refresh their age without republishing the forwarding
snapshot.
Which protocol a pair of members runs their tunnel in is settled without
asking: the member with the lower endpoint id decides, by the order it
announces its protocols in, among those both have enabled at the same wire
version. Both ends read the same answer from what they already hold. The
tunnel is created as soon as the peer is reachable by any path, and it does not
change when a direct link comes or goes underneath it: as soon as a direct
link comes up it is shorter than the path through others, and traffic moves to
it with nothing to redo. The user sees only a lower round-trip time.
Every pair uses one internal WireGuard channel, matched by its fixed opaque
capability and independent of the selected external protocols. The tunnel is
created when a member and its key are known; its logical link survives temporary
loss of all physical paths. Carrier selection changes, automatic fallback and
shorter routes keep the same keys, interface and counters. The lower endpoint
id still chooses the mutually enabled external carrier in its preference order.
A relayed AWG first hop can lead to a QUIC next hop: the user's choice governs
this device's adjacent links, while the inner ciphertext stays unchanged.
An existing TCP connection continues after transient loss if its own timeout
has not expired; a sufficiently long outage can still terminate it.
Breadth-first search computes the shortest directed paths and every equal-cost
first hop in sorted order. An actual direct link always wins. The first row is
@@ -124,5 +126,5 @@ counts sends without storing frames. Results are CPU forwarding cost, **not**
end-to-end network latency or VPN throughput; encryption, fragmentation,
sockets, congestion and scheduling contribute separately.
Wire compatibility: control ALPN `tsunagi/ctrl/8`, data ALPN `tsunagi/data/5`.
Wire compatibility: control ALPN `tsunagi/ctrl/8`, data ALPN `tsunagi/data/6`.
Upgrade every participant together; saved identities and network state persist.