diff options
Diffstat (limited to 'control/controlhttp')
| -rw-r--r-- | control/controlhttp/client.go | 15 | ||||
| -rw-r--r-- | control/controlhttp/constants.go | 7 |
2 files changed, 22 insertions, 0 deletions
diff --git a/control/controlhttp/client.go b/control/controlhttp/client.go index e01cb1f9a..522318c0e 100644 --- a/control/controlhttp/client.go +++ b/control/controlhttp/client.go @@ -310,6 +310,21 @@ func (a *Dialer) dialHost(ctx context.Context, addr netip.Addr) (*ClientConn, er if debugNoiseDial() { a.logf("noise dial (%v, %v) = (%v, %v)", u, addr, cbConn, err) } + + // We've seen some networks where the connection upgrades + // successfully, but then fails when we make a request after + // the upgrade. Work around this by making a request over the + // now-upgraded connection before we tell the outer function + // that we've got a connection. + if err == nil && a.TestConn != nil { + err = a.TestConn(cbConn) + if err != nil { + // Close and don't leak the connection. + cbConn.Close() + cbConn = nil + } + } + select { case ch <- tryURLRes{u, cbConn, err}: case <-ctx.Done(): diff --git a/control/controlhttp/constants.go b/control/controlhttp/constants.go index 6b5116262..ffa61edec 100644 --- a/control/controlhttp/constants.go +++ b/control/controlhttp/constants.go @@ -88,6 +88,13 @@ type Dialer struct { // plan before falling back to DNS. DialPlan *tailcfg.ControlDialPlan + // TestConn, if non-nil, is called with a dialed connection to verify + // that it's ready to serve real requests. If this function returns an + // error, the connection is closed and not used. If this function + // returns an error for all dialed connections, an error is returned + // from Dial. + TestConn func(*ClientConn) error + proxyFunc func(*http.Request) (*url.URL, error) // or nil // For tests only |
