Each Conn wraps a Tailscale userspace WireGuard engine + gvisor netstack.
The stack: gvisor TCP/IP → tstun.Wrapper → WireGuard device → magicsock → network.
-
DERP relay (default) — WireGuard packets are relayed through a DERP server over TLS+HTTP upgrade. Both peers maintain a persistent connection to their home DERP region. Packets arrive within ~50ms for same-region peers.
-
Direct UDP — magicsock uses STUN + disco probes to discover direct paths. Once a direct path is found, traffic upgrades from DERP to UDP transparently. The DERP connection is kept alive as a fallback.
-
WebSocket DERP — when standard DERP (HTTP upgrade) is blocked by proxies, the derphttp client falls back to WebSocket transport (
TS_DEBUG_DERP_WS_CLIENT=1orts_debug_websocketsbuild tag).
NewConn
└─ applyNetworkMap(nil)
├─ engine.SetNetworkMap(nm) — stores netmap in engine
├─ magicConn.SetNetworkMap(self, peers) — populates magicsock peer map
├─ netStack.UpdateNetstackIPs(nm) — registers local addrs on gvisor NIC
└─ engine.Reconfig(cfg, ...) — configures WireGuard device
└─ userspaceEngine.Reconfig
├─ magicConn.SetPrivateKey(cfg.PrivateKey) ← from nmToCfg
├─ magicConn.UpdatePeers(peerSet)
└─ maybeReconfigWireguardLocked(cfg)
└─ wgdev.Reconfig → magicConn.ParseEndpoint(peer)
nmToCfg() must include PrivateKey and Addresses. Without PrivateKey,
every Reconfig zeroes the magicsock key, disabling DERP connections.
netstack.Create(...)— creates gvisor stacksys.Tun.Get().Start()— unblocks TUN wrapper reads (required!)sys.Tun.Get().SetFilter(filter.NewAllowAllForTest(logf))— nil filter drops all packetsns.Start(lb)— starts netstack packet processingapplyNetworkMap(nil)— initial engine + magicsock config
Both Tun.Start() and SetFilter() are easy to miss since they're normally
handled by LocalBackend.Start() which we don't call.