From 4084c6186d254a9d6e7cbede476f0590949a8df1 Mon Sep 17 00:00:00 2001 From: Jordan Whited Date: Mon, 16 Sep 2024 19:00:12 -0700 Subject: [PATCH] wgengine/magicsock: add side-effect-free function for netcheck UDP sends (#13487) Updates #13484 Updates tailscale/corp#17879 Signed-off-by: Jordan Whited --- wgengine/magicsock/magicsock.go | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/wgengine/magicsock/magicsock.go b/wgengine/magicsock/magicsock.go index 221d2d62f..190a4ad39 100644 --- a/wgengine/magicsock/magicsock.go +++ b/wgengine/magicsock/magicsock.go @@ -491,15 +491,9 @@ func NewConn(opts Options) (*Conn, error) { c.connCtx, c.connCtxCancel = context.WithCancel(context.Background()) c.donec = c.connCtx.Done() c.netChecker = &netcheck.Client{ - Logf: logger.WithPrefix(c.logf, "netcheck: "), - NetMon: c.netMon, - SendPacket: func(b []byte, ap netip.AddrPort) (int, error) { - ok, err := c.sendUDP(ap, b) - if !ok { - return 0, err - } - return len(b), err - }, + Logf: logger.WithPrefix(c.logf, "netcheck: "), + NetMon: c.netMon, + SendPacket: c.sendUDPNetcheck, SkipExternalNetwork: inTest(), PortMapper: c.portMapper, UseDNSCache: true, @@ -582,7 +576,7 @@ func (c *Conn) updateEndpoints(why string) { c.muCond.Broadcast() }() c.dlogf("[v1] magicsock: starting endpoint update (%s)", why) - if c.noV4Send.Load() && runtime.GOOS != "js" { + if c.noV4Send.Load() && runtime.GOOS != "js" && !c.onlyTCP443.Load() { c.mu.Lock() closed := c.closed c.mu.Unlock() @@ -1175,6 +1169,24 @@ func (c *Conn) maybeRebindOnError(os string, err error) bool { return false } +// sendUDPNetcheck sends b via UDP to addr. It is used exclusively by netcheck. +// It returns the number of bytes sent along with any error encountered. It +// returns errors.ErrUnsupported if the client is explicitly configured to only +// send data over TCP port 443 and/or we're running on wasm. +func (c *Conn) sendUDPNetcheck(b []byte, addr netip.AddrPort) (int, error) { + if c.onlyTCP443.Load() || runtime.GOOS == "js" { + return 0, errors.ErrUnsupported + } + switch { + case addr.Addr().Is4(): + return c.pconn4.WriteToUDPAddrPort(b, addr) + case addr.Addr().Is6(): + return c.pconn6.WriteToUDPAddrPort(b, addr) + default: + panic("bogus sendUDPNetcheck addr type") + } +} + // sendUDP sends UDP packet b to addr. // See sendAddr's docs on the return value meanings. func (c *Conn) sendUDPStd(addr netip.AddrPort, b []byte) (sent bool, err error) {