diff --git a/control/controlhttp/client.go b/control/controlhttp/client.go index 9b1d5a1a5..3b95796d0 100644 --- a/control/controlhttp/client.go +++ b/control/controlhttp/client.go @@ -96,6 +96,9 @@ func (a *Dialer) httpsFallbackDelay() time.Duration { var _ = envknob.RegisterBool("TS_USE_CONTROL_DIAL_PLAN") // to record at init time whether it's in use func (a *Dialer) dial(ctx context.Context) (*ClientConn, error) { + + a.logPort80Failure.Store(true) + // If we don't have a dial plan, just fall back to dialing the single // host we know about. useDialPlan := envknob.BoolDefaultTrue("TS_USE_CONTROL_DIAL_PLAN") @@ -278,7 +281,9 @@ func (d *Dialer) forceNoise443() bool { // This heuristic works around networks where port 80 is MITMed and // appears to work for a bit post-Upgrade but then gets closed, // such as seen in https://github.com/tailscale/tailscale/issues/13597. - d.logf("controlhttp: forcing port 443 dial due to recent noise dial") + if d.logPort80Failure.CompareAndSwap(true, false) { + d.logf("controlhttp: forcing port 443 dial due to recent noise dial") + } return true } diff --git a/control/controlhttp/constants.go b/control/controlhttp/constants.go index 971212d63..80b3fe64c 100644 --- a/control/controlhttp/constants.go +++ b/control/controlhttp/constants.go @@ -6,6 +6,7 @@ package controlhttp import ( "net/http" "net/url" + "sync/atomic" "time" "tailscale.com/health" @@ -90,6 +91,11 @@ type Dialer struct { proxyFunc func(*http.Request) (*url.URL, error) // or nil + // logPort80Failure is whether we should log about port 80 interceptions + // and forcing a port 443 dial. We do this only once per "dial" method + // which can result in many concurrent racing dialHost calls. + logPort80Failure atomic.Bool + // For tests only drainFinished chan struct{} omitCertErrorLogging bool