The raw endpoint approach (ExtractGVisorStack + EnableRawSockets + NewRawEndpoint) was a dead end — gvisor can't forward ICMP through WireGuard regardless of raw socket permissions. spoofPingConn (TCP probe + reply synthesis) is the only working approach and doesn't need any gvisor internals.
tailnet
Clean-room Tailscale protocol implementation. No fork needed, no platform-specific syscall dependencies.
Why
tailscale.com/tsnet bundles the full Tailscale engine including netmon which calls syscall.NetlinkRIB — blocked on Android. This library reimplements only what's needed: control plane auth, DERP relay, NAT traversal, and WireGuard integration.
Architecture
┌─────────────────────────────────────────────────────────┐
│ outbound.go — Orchestrator │
│ Start: register → fetchNetworkMap → startMapPoll │
│ → initDisco → createWireGuard → startBackground │
│ API: DialContext / Listen / Peers / Metrics / Close │
├─────────────────────────────────────────────────────────┤
│ control.go — Control Plane (888 lines) │
│ Noise IK handshake → HTTP/2 over Noise │
│ Register / MapLite / MapPoll / SendEndpointUpdate │
│ noiseTransport: lazy connect + auto-reconnect │
├──────────────┬──────────────────────────────────────────┤
│ magicbind.go │ derpclient.go │ disco.go │
│ conn.Bind │ DERP relay │ NAT traversal │
│ │ │ │
│ Send: │ ConnectRegion │ STUN endpoint │
│ 1.lastRecv │ Send (failover) │ CallMeMaybe │
│ 2.BestAddr │ recvLoop+reconnect │ Ping/Pong │
│ 3.DERP │ healthCheckLoop │ RTT EWMA+demotion │
│ │ │ OnNetworkChange │
├──────────────┴──────────────────────┴─────────────────────┤
│ netwatch.go — Network change detection │
│ Poll interface state + Poke() for platform callbacks │
├────────────────────────────────────────────────────────────┤
│ funnel.go — Tailscale Funnel TCP proxy │
├────────────────────────────────────────────────────────────┤
│ WireGuard (wireguard-go) + netstack (gVisor) or TUN │
└────────────────────────────────────────────────────────────┘
Files
| File | Lines | Role |
|---|---|---|
control.go |
888 | Control plane: Noise IK, Register, MapPoll, endpoint updates, key expiry |
disco.go |
854 | NAT traversal: STUN, Ping/Pong, CallMeMaybe, path health (RTT EWMA, demotion/restore) |
outbound.go |
798 | Orchestrator: wires control+DERP+disco+WireGuard, handles MapResponse, WG IPC |
derpclient.go |
421 | DERP relay: per-region connections, health check, auto-reconnect, failover |
magicbind.go |
368 | conn.Bind: multiplexes direct UDP + DERP, symmetric routing, packet metrics |
funnel.go |
325 | Funnel: TCP proxy with TLS termination on netstack listener |
netwatch.go |
112 | Network change: interface state polling + Poke() for instant platform callbacks |
mobile/mobile.go |
218 | gomobile API for Android/iOS |
cmd/demo/ |
314 | CLI demo: netstack mode (listen, dial, self-test) |
cmd/tun-demo/ |
181 | CLI demo: system TUN mode |
Key Features
- MapPoll auto-reconnect — stream disconnect triggers exponential backoff reconnect
- DERP health monitoring — periodic probes, unhealthy region failover
- Path health tracking — EWMA RTT baseline, 3x degradation demotion, timeout-based failure counting
- Symmetric routing — reply to last received address for WireGuard handshake completion
- Network change detection — polling + Poke() API for Android/iOS callbacks
- MagicDNS short names — "worker" resolves via search domains from control plane
- Graceful shutdown — sends empty endpoint update so control marks node offline
- Metrics — atomic packet counters (direct/DERP), disco stats, exposed via
Metrics() - Node key expiry — warns at 7d/1d/expired from MapResponse
Dependencies
Uses from tailscale.com (types/crypto only):
control/controlbase— Noise IK protocoltailcfg— Protocol message typestypes/key— Key types (Node, Machine, Disco)derp+derp/derphttp— DERP clientdisco— Disco message parsingnet/stun— STUN binding requests
Does NOT use: wgengine, magicsock, netstack, netmon, ipn, tun
Platforms
| Platform | Status | Notes |
|---|---|---|
| Linux | Tested | labs server, full functionality |
| Android | Tested | Samsung S25, VPN bypass (3-layer socket protection) |
| macOS | Tested | Development machine |
| Windows | Compiles | Cross-compilation verified, untested at runtime |
| iOS | Compiles | gomobile API ready, untested at runtime |
Build
# Library
go build ./...
# Android shared library
CGO_ENABLED=1 GOOS=android GOARCH=arm64 go build -tags with_gvisor -buildmode=c-shared -o libminising.so ./cmd/android-lib/
# CLI demo
go build -tags with_gvisor -o demo ./cmd/demo/
# Cross-compile Windows
GOOS=windows GOARCH=amd64 go build ./...
Description
Languages
Go
97.6%
Kotlin
2.4%