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,                            // outbuf

View on GitHub (pinned to 6e0912f979)

Solutions

  1. Reorder so SetICMPErrImmunity runs immediately after creating the UDPConn, before any goroutine that could close it
  2. Audit for double Close of the same socket
  3. 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

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


AI-assisted analysis of tailscale/tailscale@6e0912f979 (2026-08-18). Data as JSON: /api/errors/e9f190f7d16a46f1. Report an issue: GitHub.