derp/derphttp: don't block in LocalAddr method

The derphttp.Client mutex is held during connects (for up to 10
seconds) so this LocalAddr method (blocking on said mutex) could also
block for up to 10 seconds, causing a pileup upstream in
magicsock/wgengine and ultimately a watchdog timeout resulting in a
crash.

Updates #11519

Change-Id: Idd1d94ee00966be1b901f6899d8b9492f18add0f
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
Brad Fitzpatrick
2024-04-06 10:43:47 -07:00
committed by Brad Fitzpatrick
parent e6983baa73
commit b27238b654
2 changed files with 42 additions and 7 deletions
+14
View File
@@ -7,6 +7,7 @@ import (
"bytes"
"context"
"crypto/tls"
"fmt"
"net"
"net/http"
"net/netip"
@@ -447,3 +448,16 @@ func TestRunWatchConnectionLoopServeConnect(t *testing.T) {
}
watcher.RunWatchConnectionLoop(ctx, key.NodePublic{}, t.Logf, noopAdd, noopRemove)
}
// verify that the LocalAddr method doesn't acquire the mutex.
// See https://github.com/tailscale/tailscale/issues/11519
func TestLocalAddrNoMutex(t *testing.T) {
var c Client
c.mu.Lock()
defer c.mu.Unlock() // not needed in test but for symmetry
_, err := c.LocalAddr()
if got, want := fmt.Sprint(err), "client not connected"; got != want {
t.Errorf("got error %q; want %q", got, want)
}
}