summaryrefslogtreecommitdiffhomepage
path: root/control/controlhttp
diff options
context:
space:
mode:
Diffstat (limited to 'control/controlhttp')
-rw-r--r--control/controlhttp/client.go15
-rw-r--r--control/controlhttp/constants.go7
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