AeroTUN v2 is incompatible with v1. Upgrade both ends together. Existing tunnel addresses, names and generated PSKs can be reused. The implementation does not fall back to the insecure v1 wire format.
On the inspected LXC host, /dev/net/tun is absent, so AeroTUN uses veth plus an
AF_PACKET socket. The original implementation forwarded packets with unfinished
TX checksums and potentially unsegmented GSO payloads. A raw socket does not
complete these operations. A TCP SYN can therefore arrive with an invalid
checksum and be discarded, making a bandwidth test time out before data starts.
There were two additional bugs: RX and TX used the same Ethernet buffer concurrently, and the socket read its own injected PACKET_OUTGOING frames. Those could corrupt packets and feed received traffic back through the tunnel.
The fixes disable TX checksum/TSO/GSO/GRO offloads on both veth ends, use separate RX/TX buffers, and ignore outgoing frames both at the socket and in userspace. PeerAddress now installs an explicit peer host route and, for veth, a permanent neighbour entry. Required configuration errors are returned, rather than ignored. No existing interface is deleted to make room for a new tunnel.
All bandwidth tests used disposable network namespaces and a private veth underlay; they did not change production links, routes, or services.
These are local host measurements, not an Internet benchmark or a throughput
promise. Compressible iperf payloads are useful for exercising LZ4 but do not
represent already compressed or encrypted application traffic. The initial local tests exercised veth because this LXC has no /dev/net/tun.
The subsequent deployment also exercised native TUN on the ARM64 peer; see
the live deployment report.
Run checks from the repository root:
go test ./...
go test -race ./internal/aerotun
go vet ./...
node --check internal/web/static/app.js
# Requires root, ip, nsenter, iperf3, network namespace privileges, and veth fallback:
AEROTUN_INTEGRATION=1 go test -run TestVethBandwidthIntegration -v ./internal/aerotun
Each runner creates a random 128-bit boot identity. Control messages carry a two-byte effective MTU advertisement. Both peers reduce to the lower advertised MTU after session authentication, including when their underlay MTUs differ. HELLO, ACK, and CONFIRM bind sessions to both current boot identities. HMAC-SHA256 derives distinct keys for each direction and session pair. XChaCha20-Poly1305 uses the sender identity and a monotonic 64-bit counter as its 24-byte nonce. Counters never wrap. Data from a previous receiver boot is rejected; retired sender sessions cannot replace a newer session. The replay window is updated only after AEAD authentication. This is a custom PSK protocol, without forward secrecy or an independent audit. Use a generated random PSK; validation requires at least 32 characters.
A client sends HELLO immediately and retries every two seconds while disconnected. Keepalives run every 20 seconds. A server learns/roams its endpoint only from authenticated session traffic. A client pins its configured endpoint.
running means the local runner exists. connected additionally requires an
authenticated peer packet within 65 seconds. The dashboard uses connected for
its connection flag and active count. last_handshake is retained for API
compatibility and reports the last authenticated session packet. last_error,
dropped_packets, auth_failures, and replay_drops expose failures. Traffic
counters advance only after successful socket/device writes; wire counters cover
UDP payloads, including control messages, and exclude outer IP/UDP headers.
The server supports one peer per tunnel instance. Use different instances/ports and PSKs for independent peer connections. A peer restart may take up to the 65-second liveness timeout to trigger a new handshake on the remaining peer.
V2 adds 60 bytes of authenticated header/tag, plus 28 bytes for IPv4/UDP or 48 bytes for IPv6/UDP. The requested MTU is capped by the local route/link MTU minus that overhead, at startup or authenticated peer discovery, and to the peer advertisement. Both veth ends use the same effective MTU. Smaller MTUs elsewhere on the path still require an explicit lower setting; this is not full path MTU discovery.
On the inspected host, the remote endpoint uses a WireGuard interface with MTU
PeerAddress adds a /32 or /128 host route. It does not automatically advertise LAN subnets or enable forwarding/NAT. Add those routes and firewall rules as needed.
DefaultRoute is supported for clients with a fixed IPv4 endpoint. It pins the endpoint to its existing underlay route, then adds 0.0.0.0/1 and 128.0.0.0/1 via the overlay. The original default remains intact. Existing host routes are preserved; conflicting routes cause an error and rollback. Stop removes only routes added by this runner. The server shuts runners down on normal exit. Uncatchable process/host failures can leave veth devices behind; an existing interface is deliberately reported as an error rather than deleted blindly.
The prepared binary is at:
/root/.local/share/debtik-builds/aerotun-v2/debtik.
The ARM64 build is alongside it as debtik-linux-arm64. Both hosts were
subsequently upgraded; see the deployment report.
For future upgrades, ensure both ends have v2 and management access independent
of this AeroTUN connection. Preserve the
old binary and /etc/debtik/vpn/aerotun_instances.json on each host.
On each end, after coordinating the restart:
cp /usr/local/bin/debtik /usr/local/bin/debtik.pre-aerotun-v2
install -m 0755 /path/to/new/debtik /usr/local/bin/debtik.next
systemctl stop debtik
mv /usr/local/bin/debtik.next /usr/local/bin/debtik
systemctl start debtik
journalctl -u debtik -n 50 --no-pager
If an old veth remains after stopping the OLD service, verify its ownership and that no runner uses it before removing that specific old AeroTUN interface. V1 shutdown did not reliably clean up its veths. Do not delete unrelated interfaces.
Then test the peer overlay address before testing LAN routing or a default route. For iperf3, start the server on the opposite overlay address and run the client against that address; testing the underlay address does not measure AeroTUN. Start UDP tests with a 1000-byte payload and increase only after confirming MTU.
For the subsequent default-UDP congestion and RX fix, see the Bandwidth Test follow-up.
The deployed pair has since moved to AeroTUN v3. V2 remains an explicit legacy option for coordinated rollback.