summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorClaus Lensbøl <claus@tailscale.com>2026-04-23 12:23:57 -0400
committerGitHub <noreply@github.com>2026-04-23 12:23:57 -0400
commitee76a7d3f8a8d4bcdb7620f64dd0d9715643559b (patch)
treeaf75354e3418959b8bd946792da01a2272743a2b
parenta7d8aeb8aebc4bb01066eb6ffa69b9d8fe178b81 (diff)
downloadtailscale-ee76a7d3f8a8d4bcdb7620f64dd0d9715643559b.tar.xz
tailscale-ee76a7d3f8a8d4bcdb7620f64dd0d9715643559b.zip
wgengine/magicsock: do not send TSMP disco when connected (#19497)
When there is an active connection between devices, do not send new disco keys via TSMP. Updates #12639 Signed-off-by: Claus Lensbøl <claus@tailscale.com>
-rw-r--r--wgengine/magicsock/magicsock.go24
-rw-r--r--wgengine/magicsock/magicsock_test.go29
2 files changed, 39 insertions, 14 deletions
diff --git a/wgengine/magicsock/magicsock.go b/wgengine/magicsock/magicsock.go
index 17c32a875..1f6e89591 100644
--- a/wgengine/magicsock/magicsock.go
+++ b/wgengine/magicsock/magicsock.go
@@ -4430,11 +4430,8 @@ type NewDiscoKeyAvailable struct {
// maybeSendTSMPDiscoAdvert conditionally emits an event indicating that we
// should send our DiscoKey to the first node address of the magicksock endpoint.
-// The event is only emitted if we have not yet contacted that endpoint since
-// the DiscoKey changed.
-//
-// This condition is most likely met only once per endpoint, after the start of
-// tailscaled, but not until we contact the endpoint for the first time.
+// The event is only emitted if we are not already communicating directly and
+// more than 60 seconds has passed since the last DiscoKey was sent.
//
// We do not need the Conn to be locked, but the endpoint should be.
func (c *Conn) maybeSendTSMPDiscoAdvert(de *endpoint) {
@@ -4444,11 +4441,16 @@ func (c *Conn) maybeSendTSMPDiscoAdvert(de *endpoint) {
de.mu.Lock()
defer de.mu.Unlock()
- if mono.Now().Sub(de.lastDiscoKeyAdvertisement) > discoKeyAdvertisementInterval {
- de.lastDiscoKeyAdvertisement = mono.Now()
- c.tsmpDiscoKeyAvailablePub.Publish(NewDiscoKeyAvailable{
- NodeFirstAddr: de.nodeAddr,
- NodeID: de.nodeID,
- })
+
+ now := mono.Now()
+ if now.Sub(de.lastDiscoKeyAdvertisement) <= discoKeyAdvertisementInterval ||
+ (!de.lastDiscoKeyAdvertisement.IsZero() && de.bestAddr.isDirect()) {
+ return
}
+
+ de.lastDiscoKeyAdvertisement = now
+ c.tsmpDiscoKeyAvailablePub.Publish(NewDiscoKeyAvailable{
+ NodeFirstAddr: de.nodeAddr,
+ NodeID: de.nodeID,
+ })
}
diff --git a/wgengine/magicsock/magicsock_test.go b/wgengine/magicsock/magicsock_test.go
index c592751e9..a6510a57f 100644
--- a/wgengine/magicsock/magicsock_test.go
+++ b/wgengine/magicsock/magicsock_test.go
@@ -4443,7 +4443,6 @@ func TestReceiveTSMPDiscoKeyAdvertisement(t *testing.T) {
}
func TestSendingTSMPDiscoTimer(t *testing.T) {
- t.Setenv("TS_USE_CACHED_NETMAP", "1")
conn := newTestConn(t)
tw := eventbustest.NewWatcher(t, conn.eventBus)
t.Cleanup(func() { conn.Close() })
@@ -4476,12 +4475,36 @@ func TestSendingTSMPDiscoTimer(t *testing.T) {
t.Errorf("Original disco key %s, does not match %s", discoKey.ShortString(), ep.discoShort())
}
+ // Only one gets through, second is rate limited.
conn.maybeSendTSMPDiscoAdvert(ep)
conn.maybeSendTSMPDiscoAdvert(ep)
- eventbustest.ExpectExactly(tw, eventbustest.Type[NewDiscoKeyAvailable]())
+ if err := eventbustest.ExpectExactly(tw, eventbustest.Type[NewDiscoKeyAvailable]()); err != nil {
+ t.Errorf("expected only one event, got: %s", err)
+ }
+
+ // Reset to get the event firing again.
ep.mu.Lock()
ep.lastDiscoKeyAdvertisement = 0
ep.mu.Unlock()
conn.maybeSendTSMPDiscoAdvert(ep)
- eventbustest.Expect(tw, eventbustest.Type[NewDiscoKeyAvailable]())
+ if err := eventbustest.Expect(tw, eventbustest.Type[NewDiscoKeyAvailable]()); err != nil {
+ t.Errorf("expected only one event, got: %s", err)
+ }
+
+ // With a direct bestAddr and a non-zero lastDiscoKeyAdvertisement past the
+ // rate-limit interval. No advert should be sent due to the active bestAddr.
+ ep.mu.Lock()
+ ep.lastDiscoKeyAdvertisement = mono.Now().Add(-discoKeyAdvertisementInterval - time.Second)
+ ep.bestAddr = addrQuality{epAddr: epAddr{ap: netip.MustParseAddrPort("1.2.3.4:567")}}
+ ep.mu.Unlock()
+ conn.maybeSendTSMPDiscoAdvert(ep)
+
+ // Simulating restart should send an advert.
+ ep.mu.Lock()
+ ep.lastDiscoKeyAdvertisement = 0
+ ep.mu.Unlock()
+ conn.maybeSendTSMPDiscoAdvert(ep)
+ if err := eventbustest.ExpectExactly(tw, eventbustest.Type[NewDiscoKeyAvailable]()); err != nil {
+ t.Errorf("expected only one event, got: %s", err)
+ }
}