diff --git a/ipn/ipnlocal/serve.go b/ipn/ipnlocal/serve.go index 56636596f..b84259957 100644 --- a/ipn/ipnlocal/serve.go +++ b/ipn/ipnlocal/serve.go @@ -93,7 +93,9 @@ func (s *serveListener) Run() { for { ln, err := net.Listen("tcp", s.ap.String()) if err != nil { - s.logf("serve failed to listen on %v, backing off: %v", s.ap, err) + if s.shouldWarnAboutListenError(err) { + s.logf("serve failed to listen on %v, backing off: %v", s.ap, err) + } s.bo.BackOff(s.ctx, err) continue } @@ -111,6 +113,17 @@ func (s *serveListener) Run() { } } +func (s *serveListener) shouldWarnAboutListenError(err error) bool { + if !s.b.e.GetLinkMonitor().InterfaceState().HasIP(s.ap.Addr()) { + // Machine likely doesn't have IPv6 enabled (or the IP is still being + // assigned). No need to warn. Notably, WSL2 (Issue 6303). + return false + } + // TODO(bradfitz): check errors.Is(err, syscall.EADDRNOTAVAIL) etc? Let's + // see what happens in practice. + return true +} + // handleServeListenersAccept accepts connections for the Listener. // Calls incoming handler in a new goroutine for each accepted connection. func (s *serveListener) handleServeListenersAccept(ln net.Listener) error { diff --git a/net/interfaces/interfaces.go b/net/interfaces/interfaces.go index f0ca77913..e9bafe3b7 100644 --- a/net/interfaces/interfaces.go +++ b/net/interfaces/interfaces.go @@ -400,6 +400,22 @@ func (s *State) EqualFiltered(s2 *State, useInterface InterfaceFilter, useIP IPF return true } +// HasIP reports whether any interface has the provided IP address. +func (s *State) HasIP(ip netip.Addr) bool { + if s == nil { + return false + } + want := netip.PrefixFrom(ip, ip.BitLen()) + for _, pv := range s.InterfaceIPs { + for _, p := range pv { + if p == want { + return true + } + } + } + return false +} + func interfacesEqual(a, b Interface) bool { return a.Index == b.Index && a.MTU == b.MTU &&