cmd/tsconnect/wasm: don't return non-nil net.Conn interface on dial error

The NetstackDialTCP/UDP hooks returned the result of DialContextTCP/UDP
directly, so on error they returned a non-nil net.Conn interface holding
a nil *gonet.TCPConn or *gonet.UDPConn pointer, tripping up callers that
check the interface against nil and then call Close, crashing the wasm
worker. Apply the same fix that 46bdbb387 made for tailscaled and tsnet.

Fixes #20529

Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
Change-Id: I4fd66bb7615ee9b2d204256a43288ed7b7a12f35
This commit is contained in:
Brad Fitzpatrick 2026-07-19 13:12:31 +00:00 committed by Brad Fitzpatrick
parent 7be0054a7b
commit ece1b12ebf

View File

@ -131,10 +131,24 @@ func newIPN(jsConfig js.Value) map[string]any {
return true
}
dialer.NetstackDialTCP = func(ctx context.Context, dst netip.AddrPort) (net.Conn, error) {
return ns.DialContextTCP(ctx, dst)
// Note: don't just return ns.DialContextTCP or we'll return
// *gonet.TCPConn(nil) instead of a nil interface which trips up
// callers.
tcpConn, err := ns.DialContextTCP(ctx, dst)
if err != nil {
return nil, err
}
return tcpConn, nil
}
dialer.NetstackDialUDP = func(ctx context.Context, dst netip.AddrPort) (net.Conn, error) {
return ns.DialContextUDP(ctx, dst)
// Note: don't just return ns.DialContextUDP or we'll return
// *gonet.UDPConn(nil) instead of a nil interface which trips up
// callers.
udpConn, err := ns.DialContextUDP(ctx, dst)
if err != nil {
return nil, err
}
return udpConn, nil
}
sys.NetstackRouter.Set(true)
sys.Tun.Get().Start()