فهرست منبع

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

* Quietly log error on UDP_NETRESET ioctl on Windows.

* dampen unexpected error warnings
brad-defined 3 هفته پیش
والد
کامیت
1d73e463cd
2فایلهای تغییر یافته به همراه37 افزوده شده و 12 حذف شده
  1. 14 2
      udp/udp_generic.go
  2. 23 10
      udp/udp_rio_windows.go

+ 14 - 2
udp/udp_generic.go

@@ -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")
-			return
+			if errors.Is(err, net.ErrClosed) {
+				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(

+ 23 - 10
udp/udp_rio_windows.go

@@ -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
 		}
 		}