From fe50ded95c237e59f0c7018c90392949f31e6198 Mon Sep 17 00:00:00 2001 From: Josh Bleecher Snyder Date: Wed, 28 Apr 2021 10:36:54 -0700 Subject: [PATCH] health: track whether we have a functional udp4 bind Suggested-by: Brad Fitzpatrick Signed-off-by: Josh Bleecher Snyder --- health/health.go | 14 +++++++++++++- wgengine/magicsock/magicsock.go | 6 ++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/health/health.go b/health/health.go index bd2178fdc..b3264931b 100644 --- a/health/health.go +++ b/health/health.go @@ -37,6 +37,7 @@ ipnState string ipnWantRunning bool anyInterfaceUp = true // until told otherwise + udp4Unbound bool ) // Subsystem is the name of a subsystem whose health can be monitored. @@ -47,7 +48,7 @@ // the system, rather than one particular subsystem. SysOverall = Subsystem("overall") - // SysRouter is the name the wgengine/router subsystem. + // SysRouter is the name of the wgengine/router subsystem. SysRouter = Subsystem("router") // SysDNS is the name of the net/dns subsystem. @@ -214,6 +215,14 @@ func SetAnyInterfaceUp(up bool) { selfCheckLocked() } +// SetUDP4Unbound sets whether the udp4 bind failed completely. +func SetUDP4Unbound(unbound bool) { + mu.Lock() + defer mu.Unlock() + udp4Unbound = unbound + selfCheckLocked() +} + func timerSelfCheck() { mu.Lock() defer mu.Unlock() @@ -257,6 +266,9 @@ func overallErrorLocked() error { if d := now.Sub(derpRegionLastFrame[rid]).Round(time.Second); d > tooIdle { return fmt.Errorf("haven't heard from home DERP region %v in %v", rid, d) } + if udp4Unbound { + return errors.New("no udp4 bind") + } // TODO: use _ = inMapPollSince diff --git a/wgengine/magicsock/magicsock.go b/wgengine/magicsock/magicsock.go index d7cbfb7ea..809972e0c 100644 --- a/wgengine/magicsock/magicsock.go +++ b/wgengine/magicsock/magicsock.go @@ -2671,6 +2671,9 @@ func (c *Conn) bindSocket(rucPtr **RebindingUDPConn, network string) error { } // Success. ruc.pconn = pconn + if network == "udp4" { + health.SetUDP4Unbound(false) + } return nil } @@ -2679,6 +2682,9 @@ func (c *Conn) bindSocket(rucPtr **RebindingUDPConn, network string) error { // This keeps the receive funcs alive for a future in which // we get a link change and we can try binding again. ruc.pconn = newBlockForeverConn() + if network == "udp4" { + health.SetUDP4Unbound(true) + } return fmt.Errorf("failed to bind any ports (tried %v)", ports) }