From 9eb59c72c13d062482686afc8ad46f891c0c3d74 Mon Sep 17 00:00:00 2001 From: James Tucker Date: Wed, 25 Sep 2024 16:06:21 -0700 Subject: [PATCH] wgengine/magicsock: fix check for EPERM on macOS Like Linux, macOS will reply to sendto(2) with EPERM if the firewall is currently blocking writes, though this behavior is like Linux undocumented. This is often caused by a faulting network extension or content filter from EDR software. Updates #11710 Updates #12891 Updates #13511 Signed-off-by: James Tucker --- wgengine/magicsock/magicsock.go | 4 ++-- wgengine/magicsock/magicsock_test.go | 15 ++++++++++----- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/wgengine/magicsock/magicsock.go b/wgengine/magicsock/magicsock.go index 9e1bcd059..aceab3be5 100644 --- a/wgengine/magicsock/magicsock.go +++ b/wgengine/magicsock/magicsock.go @@ -1149,8 +1149,8 @@ func (c *Conn) sendUDP(ipp netip.AddrPort, b []byte) (sent bool, err error) { // maybeRebindOnError performs a rebind and restun if the error is defined and // any conditionals are met. func (c *Conn) maybeRebindOnError(os string, err error) bool { - switch err { - case syscall.EPERM: + switch { + case errors.Is(err, syscall.EPERM): why := "operation-not-permitted-rebind" switch os { // We currently will only rebind and restun on a syscall.EPERM if it is experienced diff --git a/wgengine/magicsock/magicsock_test.go b/wgengine/magicsock/magicsock_test.go index f979834c9..6b2d961b9 100644 --- a/wgengine/magicsock/magicsock_test.go +++ b/wgengine/magicsock/magicsock_test.go @@ -2965,26 +2965,31 @@ func TestMaybeRebindOnError(t *testing.T) { tstest.PanicOnLog() tstest.ResourceCheck(t) - conn := newTestConn(t) - defer conn.Close() + err := fmt.Errorf("outer err: %w", syscall.EPERM) t.Run("darwin-rebind", func(t *testing.T) { - rebound := conn.maybeRebindOnError("darwin", syscall.EPERM) + conn := newTestConn(t) + defer conn.Close() + rebound := conn.maybeRebindOnError("darwin", err) if !rebound { t.Errorf("darwin should rebind on syscall.EPERM") } }) t.Run("linux-not-rebind", func(t *testing.T) { - rebound := conn.maybeRebindOnError("linux", syscall.EPERM) + conn := newTestConn(t) + defer conn.Close() + rebound := conn.maybeRebindOnError("linux", err) if rebound { t.Errorf("linux should not rebind on syscall.EPERM") } }) t.Run("no-frequent-rebind", func(t *testing.T) { + conn := newTestConn(t) + defer conn.Close() conn.lastEPERMRebind.Store(time.Now().Add(-1 * time.Second)) - rebound := conn.maybeRebindOnError("darwin", syscall.EPERM) + rebound := conn.maybeRebindOnError("darwin", err) if rebound { t.Errorf("darwin should not rebind on syscall.EPERM within 5 seconds of last") }