diff --git a/health/health.go b/health/health.go index 662114f2d..84e336dce 100644 --- a/health/health.go +++ b/health/health.go @@ -36,6 +36,11 @@ var ( ipnState string ipnWantRunning bool anyInterfaceUp = true // until told otherwise + + receiveIPv4Running bool + receiveIPv6Started bool + receiveIPv6Running bool + receiveDERPRunning bool ) // Subsystem is the name of a subsystem whose health can be monitored. @@ -213,6 +218,18 @@ func SetAnyInterfaceUp(up bool) { selfCheckLocked() } +func SetReceiveIPv4Running(running bool) { setHealthBool(&receiveIPv4Running, running) } +func SetReceiveIPv6Started(running bool) { setHealthBool(&receiveIPv6Started, running) } +func SetReceiveIPv6Running(running bool) { setHealthBool(&receiveIPv6Running, running) } +func SetReceiveDERPRunning(running bool) { setHealthBool(&receiveDERPRunning, running) } + +func setHealthBool(dst *bool, b bool) { + mu.Lock() + defer mu.Unlock() + *dst = b + selfCheckLocked() +} + func timerSelfCheck() { mu.Lock() defer mu.Unlock() @@ -263,6 +280,15 @@ func overallErrorLocked() error { _ = lastMapRequestHeard var errs []error + if !receiveIPv4Running { + errs = append(errs, errors.New("receiveIPv4 not running")) + } + if !receiveDERPRunning { + errs = append(errs, errors.New("receiveDERP not running")) + } + if receiveIPv6Started && !receiveIPv6Running { + errs = append(errs, errors.New("receiveIPv6 not running")) + } for sys, err := range sysErr { if err == nil || sys == SysOverall { continue diff --git a/wgengine/magicsock/magicsock.go b/wgengine/magicsock/magicsock.go index 51b5c0af1..9acdc4f47 100644 --- a/wgengine/magicsock/magicsock.go +++ b/wgengine/magicsock/magicsock.go @@ -1581,6 +1581,9 @@ func (c *Conn) noteRecvActivityFromEndpoint(e conn.Endpoint) { // receiveIPv6 receives a UDP IPv6 packet. It is called by wireguard-go. func (c *Conn) receiveIPv6(b []byte) (int, conn.Endpoint, error) { + health.SetReceiveIPv6Started(true) + health.SetReceiveIPv6Running(true) + defer health.SetReceiveIPv6Running(false) for { n, ipp, err := c.pconn6.ReadFromNetaddr(b) if err != nil { @@ -1594,6 +1597,8 @@ func (c *Conn) receiveIPv6(b []byte) (int, conn.Endpoint, error) { // receiveIPv4 receives a UDP IPv4 packet. It is called by wireguard-go. func (c *Conn) receiveIPv4(b []byte) (n int, ep conn.Endpoint, err error) { + health.SetReceiveIPv4Running(true) + defer health.SetReceiveIPv4Running(false) for { n, ipp, err := c.pconn4.ReadFromNetaddr(b) if err != nil { @@ -1646,6 +1651,8 @@ func (c *Conn) receiveIP(b []byte, ipp netaddr.IPPort, cache *ippEndpointCache) // If the packet was a disco message or the peer endpoint wasn't // found, the returned error is errLoopAgain. func (c *connBind) receiveDERP(b []byte) (n int, ep conn.Endpoint, err error) { + health.SetReceiveDERPRunning(true) + defer health.SetReceiveDERPRunning(false) for dm := range c.derpRecvCh { if c.Closed() { break @@ -2436,6 +2443,7 @@ func (c *connBind) Close() error { // Unblock all outstanding receives. c.pconn4.Close() if c.pconn6 != nil { + health.SetReceiveIPv6Started(false) c.pconn6.Close() } // Send an empty read result to unblock receiveDERP,