tailscale/tailscale · error
SetICMPErrImmunity: getting SyscallConn failed: %v
Error message
SetICMPErrImmunity: getting SyscallConn failed: %v
What it means
Windows-only helper that makes a UDP socket immune to WSAENETRESET / ICMP-unreachable errors (it issues the SIO_UDP_NETRESET ioctl). This variant means (*net.UDPConn).SyscallConn() itself failed, which for a live UDPConn essentially only happens when the connection is already closed or in a broken state. Non-UDP conns are silently skipped, so reaching this error implies the conn was a *net.UDPConn.
Source
Thrown at net/sockopts/sockopts_windows.go:30
"golang.org/x/sys/windows"
"tailscale.com/types/nettype"
)
// SetICMPErrImmunity sets socket options on pconn to prevent ICMP reception,
// e.g. ICMP Port Unreachable, from surfacing as a syscall error.
//
// If pconn is not a [*net.UDPConn], then SetICMPErrImmunity is no-op.
func SetICMPErrImmunity(pconn nettype.PacketConn) error {
c, ok := pconn.(*net.UDPConn)
if !ok {
// not a UDP connection; nothing to do
return nil
}
sysConn, err := c.SyscallConn()
if err != nil {
return fmt.Errorf("SetICMPErrImmunity: getting SyscallConn failed: %v", err)
}
// 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, // outbufView on GitHub (pinned to 6e0912f979)
Solutions
- Reorder so SetICMPErrImmunity runs immediately after creating the UDPConn, before any goroutine that could close it
- Audit for double Close of the same socket
- Treat the returned error as fatal for that socket and recreate it, rather than continuing without ICMP immunity
Example fix
// before
conn, _ := net.ListenPacket("udp", ":0")
go closeOnRebind(conn) // may Close concurrently
SetICMPErrImmunity(conn.(*net.UDPConn)) // SyscallConn fails if closed
// after
uc := conn.(*net.UDPConn)
if err := sockopts.SetICMPErrImmunity(uc); err != nil {
uc.Close() // socket unusable; recreate
return err
} Defensive patterns
Strategy: try-catch
Try / catch
if err := sockopts.SetICMPErrImmunity(conn); err != nil {
conn.Close() // socket is in a broken state; recreate it
return fmt.Errorf("udp setup failed: %w", err)
} Prevention
- Call SetICMPErrImmunity synchronously right after creating the UDPConn, before exposing it to any goroutine that may close it
- Keep single ownership of the socket so Close cannot race setup
When it happens
Trigger: Calling SetICMPErrImmunity(pconn) on a *net.UDPConn whose Close already ran (close-then-configure race in socket setup), producing a SyscallConn error that sockopts_windows.go:30 wraps with the function name.
Common situations: Socket setup code that configures options concurrently with teardown (e.g. wireguard-style bind rebinds); double-close of the socket before the ioctl; wrapping the UDPConn so the type assertion still passes but the underlying conn is dead.
Related errors
- SetICMPErrImmunity: could not set SIO_UDP_NETRESET: %v
- SetICMPErrImmunity: SyscallConn.Control failed: %v
- Does not appear to be PCP MAP response
- Invalid PCP common header
- failed to open the %s key: %w
AI-assisted analysis of tailscale/tailscale@6e0912f979 (2026-08-18).
Data as JSON: /api/errors/e9f190f7d16a46f1.
Report an issue: GitHub.