diff --git a/wgengine/magicsock/magicsock.go b/wgengine/magicsock/magicsock.go index f9ddd4383..7b121d415 100644 --- a/wgengine/magicsock/magicsock.go +++ b/wgengine/magicsock/magicsock.go @@ -2538,6 +2538,7 @@ func (c *Conn) bindSocket(ruc *RebindingUDPConn, network string, curPortFate cur } } trySetSocketBuffer(pconn, c.logf) + trySetUDPSocketOptions(pconn, c.logf) // Success. if debugBindSocket() { diff --git a/wgengine/magicsock/magicsock_notwindows.go b/wgengine/magicsock/magicsock_notwindows.go new file mode 100644 index 000000000..7c31c8202 --- /dev/null +++ b/wgengine/magicsock/magicsock_notwindows.go @@ -0,0 +1,13 @@ +// Copyright (c) Tailscale Inc & AUTHORS +// SPDX-License-Identifier: BSD-3-Clause + +//go:build !windows + +package magicsock + +import ( + "tailscale.com/types/logger" + "tailscale.com/types/nettype" +) + +func trySetUDPSocketOptions(pconn nettype.PacketConn, logf logger.Logf) {} diff --git a/wgengine/magicsock/magicsock_windows.go b/wgengine/magicsock/magicsock_windows.go new file mode 100644 index 000000000..fe2a80e0b --- /dev/null +++ b/wgengine/magicsock/magicsock_windows.go @@ -0,0 +1,58 @@ +// Copyright (c) Tailscale Inc & AUTHORS +// SPDX-License-Identifier: BSD-3-Clause + +//go:build windows + +package magicsock + +import ( + "net" + "unsafe" + + "golang.org/x/sys/windows" + "tailscale.com/types/logger" + "tailscale.com/types/nettype" +) + +func trySetUDPSocketOptions(pconn nettype.PacketConn, logf logger.Logf) { + c, ok := pconn.(*net.UDPConn) + if !ok { + // not a UDP connection; nothing to do + return + } + + sysConn, err := c.SyscallConn() + if err != nil { + logf("trySetUDPSocketOptions: getting SyscallConn failed: %v", err) + return + } + + // Similar to https://github.com/golang/go/issues/5834 (which involved + // WSAECONNRESET), Windows can return a WSAENETRESET error, even on UDP + // reads. Disable this. + const SIO_UDP_NETRESET = windows.IOC_IN | windows.IOC_VENDOR | 15 + + var ioctlErr error + err = sysConn.Control(func(fd uintptr) { + ret := uint32(0) + flag := uint32(0) + size := uint32(unsafe.Sizeof(flag)) + ioctlErr = windows.WSAIoctl( + windows.Handle(fd), + SIO_UDP_NETRESET, // iocc + (*byte)(unsafe.Pointer(&flag)), // inbuf + size, // cbif + nil, // outbuf + 0, // cbob + &ret, // cbbr + nil, // overlapped + 0, // completionRoutine + ) + }) + if ioctlErr != nil { + logf("trySetUDPSocketOptions: could not set SIO_UDP_NETRESET: %v", ioctlErr) + } + if err != nil { + logf("trySetUDPSocketOptions: SyscallConn.Control failed: %v", err) + } +}