Quietly log error on UDP_NETRESET ioctl on Windows. (#1453)

* Quietly log error on UDP_NETRESET ioctl on Windows.

* dampen unexpected error warnings
This commit is contained in:
brad-defined
2025-08-19 17:33:31 -04:00
committed by GitHub
parent 105e0ec66c
commit 1d73e463cd
2 changed files with 37 additions and 12 deletions

View File

@@ -10,9 +10,11 @@ package udp
import ( import (
"context" "context"
"errors"
"fmt" "fmt"
"net" "net"
"net/netip" "net/netip"
"time"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"github.com/slackhq/nebula/config" "github.com/slackhq/nebula/config"
@@ -80,12 +82,22 @@ func (u *GenericConn) ListenOut(r EncReader, lhf LightHouseHandlerFunc, cache *f
fwPacket := &firewall.Packet{} fwPacket := &firewall.Packet{}
nb := make([]byte, 12, 12) nb := make([]byte, 12, 12)
var lastRecvErr time.Time
for { for {
// Just read one packet at a time // Just read one packet at a time
n, rua, err := u.ReadFromUDPAddrPort(buffer) n, rua, err := u.ReadFromUDPAddrPort(buffer)
if err != nil { if err != nil {
u.l.WithError(err).Debug("udp socket is closed, exiting read loop") if errors.Is(err, net.ErrClosed) {
return u.l.WithError(err).Debug("udp socket is closed, exiting read loop")
return
}
// Dampen unexpected message warns to once per minute
if lastRecvErr.IsZero() || time.Since(lastRecvErr) > time.Minute {
lastRecvErr = time.Now()
u.l.WithError(err).Warn("unexpected udp socket receive error")
}
continue
} }
r( r(

View File

@@ -14,6 +14,7 @@ import (
"sync" "sync"
"sync/atomic" "sync/atomic"
"syscall" "syscall"
"time"
"unsafe" "unsafe"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
@@ -69,7 +70,7 @@ func NewRIOListener(l *logrus.Logger, addr netip.Addr, port int) (*RIOConn, erro
u := &RIOConn{l: l} u := &RIOConn{l: l}
err := u.bind(&windows.SockaddrInet6{Addr: addr.As16(), Port: port}) err := u.bind(l, &windows.SockaddrInet6{Addr: addr.As16(), Port: port})
if err != nil { if err != nil {
return nil, fmt.Errorf("bind: %w", err) return nil, fmt.Errorf("bind: %w", err)
} }
@@ -85,11 +86,11 @@ func NewRIOListener(l *logrus.Logger, addr netip.Addr, port int) (*RIOConn, erro
return u, nil return u, nil
} }
func (u *RIOConn) bind(sa windows.Sockaddr) error { func (u *RIOConn) bind(l *logrus.Logger, sa windows.Sockaddr) error {
var err error var err error
u.sock, err = winrio.Socket(windows.AF_INET6, windows.SOCK_DGRAM, windows.IPPROTO_UDP) u.sock, err = winrio.Socket(windows.AF_INET6, windows.SOCK_DGRAM, windows.IPPROTO_UDP)
if err != nil { if err != nil {
return err return fmt.Errorf("winrio.Socket error: %w", err)
} }
// Enable v4 for this socket // Enable v4 for this socket
@@ -103,35 +104,40 @@ func (u *RIOConn) bind(sa windows.Sockaddr) error {
size := uint32(unsafe.Sizeof(flag)) size := uint32(unsafe.Sizeof(flag))
err = syscall.WSAIoctl(syscall.Handle(u.sock), syscall.SIO_UDP_CONNRESET, (*byte)(unsafe.Pointer(&flag)), size, nil, 0, &ret, nil, 0) err = syscall.WSAIoctl(syscall.Handle(u.sock), syscall.SIO_UDP_CONNRESET, (*byte)(unsafe.Pointer(&flag)), size, nil, 0, &ret, nil, 0)
if err != nil { if err != nil {
return err // This is a best-effort to prevent errors from being returned by the udp recv operation.
// Quietly log a failure and continue.
l.WithError(err).Debug("failed to set UDP_CONNRESET ioctl")
} }
ret = 0 ret = 0
flag = 0 flag = 0
size = uint32(unsafe.Sizeof(flag)) size = uint32(unsafe.Sizeof(flag))
SIO_UDP_NETRESET := uint32(syscall.IOC_IN | syscall.IOC_VENDOR | 15) SIO_UDP_NETRESET := uint32(syscall.IOC_IN | syscall.IOC_VENDOR | 15)
err = syscall.WSAIoctl(syscall.Handle(u.sock), SIO_UDP_NETRESET, (*byte)(unsafe.Pointer(&flag)), size, nil, 0, &ret, nil, 0) err = syscall.WSAIoctl(syscall.Handle(u.sock), SIO_UDP_NETRESET, (*byte)(unsafe.Pointer(&flag)), size, nil, 0, &ret, nil, 0)
if err != nil { if err != nil {
return err // This is a best-effort to prevent errors from being returned by the udp recv operation.
// Quietly log a failure and continue.
l.WithError(err).Debug("failed to set UDP_NETRESET ioctl")
} }
err = u.rx.Open() err = u.rx.Open()
if err != nil { if err != nil {
return err return fmt.Errorf("error rx.Open(): %w", err)
} }
err = u.tx.Open() err = u.tx.Open()
if err != nil { if err != nil {
return err return fmt.Errorf("error tx.Open(): %w", err)
} }
u.rq, err = winrio.CreateRequestQueue(u.sock, packetsPerRing, 1, packetsPerRing, 1, u.rx.cq, u.tx.cq, 0) u.rq, err = winrio.CreateRequestQueue(u.sock, packetsPerRing, 1, packetsPerRing, 1, u.rx.cq, u.tx.cq, 0)
if err != nil { if err != nil {
return err return fmt.Errorf("error CreateRequestQueue: %w", err)
} }
err = windows.Bind(u.sock, sa) err = windows.Bind(u.sock, sa)
if err != nil { if err != nil {
return err return fmt.Errorf("error windows.Bind(): %w", err)
} }
return nil return nil
@@ -144,15 +150,22 @@ func (u *RIOConn) ListenOut(r EncReader, lhf LightHouseHandlerFunc, cache *firew
fwPacket := &firewall.Packet{} fwPacket := &firewall.Packet{}
nb := make([]byte, 12, 12) nb := make([]byte, 12, 12)
var lastRecvErr time.Time
for { for {
// Just read one packet at a time // Just read one packet at a time
n, rua, err := u.receive(buffer) n, rua, err := u.receive(buffer)
if err != nil { if err != nil {
if errors.Is(err, net.ErrClosed) { if errors.Is(err, net.ErrClosed) {
u.l.WithError(err).Debug("udp socket is closed, exiting read loop") u.l.WithError(err).Debug("udp socket is closed, exiting read loop")
return return
} }
u.l.WithError(err).Error("unexpected udp socket receive error") // Dampen unexpected message warns to once per minute
if lastRecvErr.IsZero() || time.Since(lastRecvErr) > time.Minute {
lastRecvErr = time.Now()
u.l.WithError(err).Warn("unexpected udp socket receive error")
}
continue continue
} }