cmd/tailscale/cli,ipn/ipnlocal,wgengine/magicsock: implement tailscale debug peer-relay-servers (#16577)

Updates tailscale/corp#30036

Signed-off-by: Jordan Whited <jordan@tailscale.com>
This commit is contained in:
Jordan Whited
2025-07-16 10:03:05 -07:00
committed by GitHub
parent 67514f5eb2
commit 3c6d17e6f1
6 changed files with 71 additions and 0 deletions

View File

@@ -356,6 +356,12 @@ func debugCmd() *ffcli.Command {
ShortHelp: "Print Go's runtime/debug.BuildInfo",
Exec: runGoBuildInfo,
},
{
Name: "peer-relay-servers",
ShortUsage: "tailscale debug peer-relay-servers",
ShortHelp: "Print the current set of candidate peer relay servers",
Exec: runPeerRelayServers,
},
}...),
}
}
@@ -1327,3 +1333,17 @@ func runDebugResolve(ctx context.Context, args []string) error {
}
return nil
}
func runPeerRelayServers(ctx context.Context, args []string) error {
if len(args) > 0 {
return errors.New("unexpected arguments")
}
v, err := localClient.DebugResultJSON(ctx, "peer-relay-servers")
if err != nil {
return err
}
e := json.NewEncoder(os.Stdout)
e.SetIndent("", " ")
e.Encode(v)
return nil
}

View File

@@ -6956,6 +6956,10 @@ func (b *LocalBackend) DebugReSTUN() error {
return nil
}
func (b *LocalBackend) DebugPeerRelayServers() set.Set[netip.AddrPort] {
return b.MagicConn().PeerRelays()
}
// ControlKnobs returns the node's control knobs.
func (b *LocalBackend) ControlKnobs() *controlknobs.Knobs {
return b.sys.ControlKnobs()

View File

@@ -696,6 +696,12 @@ func (h *Handler) serveDebug(w http.ResponseWriter, r *http.Request) {
break
}
h.b.DebugForcePreferDERP(n)
case "peer-relay-servers":
servers := h.b.DebugPeerRelayServers()
err = json.NewEncoder(w).Encode(servers)
if err == nil {
return
}
case "":
err = fmt.Errorf("missing parameter 'action'")
default:

View File

@@ -3907,3 +3907,8 @@ func (le *lazyEndpoint) FromPeer(peerPublicKey [32]byte) {
le.c.peerMap.setNodeKeyForEpAddr(le.src, pubKey)
le.c.logf("magicsock: lazyEndpoint.FromPeer(%v) setting epAddr(%v) in peerMap for node(%v)", pubKey.ShortString(), le.src, ep.nodeAddr)
}
// PeerRelays returns the current set of candidate peer relays.
func (c *Conn) PeerRelays() set.Set[netip.AddrPort] {
return c.relayManager.getServers()
}

View File

@@ -57,6 +57,7 @@ type relayManager struct {
newServerEndpointCh chan newRelayServerEndpointEvent
rxHandshakeDiscoMsgCh chan relayHandshakeDiscoMsgEvent
serversCh chan set.Set[netip.AddrPort]
getServersCh chan chan set.Set[netip.AddrPort]
discoInfoMu sync.Mutex // guards the following field
discoInfoByServerDisco map[key.DiscoPublic]*relayHandshakeDiscoInfo
@@ -185,10 +186,29 @@ func (r *relayManager) runLoop() {
if !r.hasActiveWorkRunLoop() {
return
}
case getServersCh := <-r.getServersCh:
r.handleGetServersRunLoop(getServersCh)
if !r.hasActiveWorkRunLoop() {
return
}
}
}
}
func (r *relayManager) handleGetServersRunLoop(getServersCh chan set.Set[netip.AddrPort]) {
servers := make(set.Set[netip.AddrPort], len(r.serversByAddrPort))
for server := range r.serversByAddrPort {
servers.Add(server)
}
getServersCh <- servers
}
func (r *relayManager) getServers() set.Set[netip.AddrPort] {
ch := make(chan set.Set[netip.AddrPort])
relayManagerInputEvent(r, nil, &r.getServersCh, ch)
return <-ch
}
func (r *relayManager) handleServersUpdateRunLoop(update set.Set[netip.AddrPort]) {
for k, v := range r.serversByAddrPort {
if !update.Contains(k) {
@@ -244,6 +264,7 @@ func (r *relayManager) init() {
r.newServerEndpointCh = make(chan newRelayServerEndpointEvent)
r.rxHandshakeDiscoMsgCh = make(chan relayHandshakeDiscoMsgEvent)
r.serversCh = make(chan set.Set[netip.AddrPort])
r.getServersCh = make(chan chan set.Set[netip.AddrPort])
r.runLoopStoppedCh = make(chan struct{}, 1)
r.runLoopStoppedCh <- struct{}{}
})

View File

@@ -32,4 +32,19 @@ func TestRelayManagerInitAndIdle(t *testing.T) {
rm = relayManager{}
rm.handleRelayServersSet(make(set.Set[netip.AddrPort]))
<-rm.runLoopStoppedCh
rm = relayManager{}
rm.getServers()
<-rm.runLoopStoppedCh
}
func TestRelayManagerGetServers(t *testing.T) {
rm := relayManager{}
servers := make(set.Set[netip.AddrPort], 1)
servers.Add(netip.MustParseAddrPort("192.0.2.1:7"))
rm.handleRelayServersSet(servers)
got := rm.getServers()
if !servers.Equal(got) {
t.Errorf("got %v != want %v", got, servers)
}
}