From 044f525eb8c41e40639e810b650e0f028c55cc16 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Sat, 20 Dec 2025 15:02:23 +0100 Subject: [PATCH] fix: include tailnetDns in wide-area beacons --- docs/bonjour.md | 1 + docs/discovery.md | 2 +- src/gateway/server.ts | 1 + src/infra/widearea-dns.test.ts | 16 ++++++++++++++++ src/infra/widearea-dns.ts | 4 ++++ 5 files changed, 23 insertions(+), 1 deletion(-) diff --git a/docs/bonjour.md b/docs/bonjour.md index 7c372d17d..0b7b8fdb0 100644 --- a/docs/bonjour.md +++ b/docs/bonjour.md @@ -60,6 +60,7 @@ In the Tailscale admin console: - Add split DNS so the domain `clawdis.internal` uses that nameserver. Once clients accept tailnet DNS, iOS nodes can browse `_clawdis-bridge._tcp` in `clawdis.internal.` without multicast. +Wide-area beacons also include `tailnetDns` (when available) so the macOS app can auto-fill SSH targets off-LAN. ### Bridge listener security (recommended) diff --git a/docs/discovery.md b/docs/discovery.md index 4b15310c5..d84d471dc 100644 --- a/docs/discovery.md +++ b/docs/discovery.md @@ -70,7 +70,7 @@ Disable/override: For London/Vienna style setups, Bonjour won’t help. The recommended “direct” target is: - Tailscale MagicDNS name (preferred) or a stable tailnet IP. -If the gateway can detect it is running under Tailscale, it publishes `tailnetDns` as an optional hint for clients. +If the gateway can detect it is running under Tailscale, it publishes `tailnetDns` as an optional hint for clients (including wide-area beacons). ### 3) Manual / SSH target diff --git a/src/gateway/server.ts b/src/gateway/server.ts index 3a21dfbf2..cdef46360 100644 --- a/src/gateway/server.ts +++ b/src/gateway/server.ts @@ -2096,6 +2096,7 @@ export async function startGatewayServer( displayName: formatBonjourInstanceName(machineDisplayName), tailnetIPv4, tailnetIPv6: tailnetIPv6 ?? undefined, + tailnetDns, }); defaultRuntime.log( `discovery: wide-area DNS-SD ${result.changed ? "updated" : "unchanged"} (${WIDE_AREA_DISCOVERY_DOMAIN} → ${result.zonePath})`, diff --git a/src/infra/widearea-dns.test.ts b/src/infra/widearea-dns.test.ts index 47aebf135..1afbefa66 100644 --- a/src/infra/widearea-dns.test.ts +++ b/src/infra/widearea-dns.test.ts @@ -28,4 +28,20 @@ describe("wide-area DNS-SD zone rendering", () => { ); expect(txt).toContain(`displayName=Mac Studio (Clawdis)`); }); + + it("includes tailnetDns when provided", () => { + const txt = renderWideAreaBridgeZoneText({ + serial: 2025121701, + bridgePort: 18790, + displayName: "Mac Studio (Clawdis)", + tailnetIPv4: "100.123.224.76", + tailnetDns: "peters-mac-studio-1.sheep-coho.ts.net", + hostLabel: "studio-london", + instanceLabel: "studio-london", + }); + + expect(txt).toContain( + `tailnetDns=peters-mac-studio-1.sheep-coho.ts.net`, + ); + }); }); diff --git a/src/infra/widearea-dns.ts b/src/infra/widearea-dns.ts index b5c6063fb..fdc67d52c 100644 --- a/src/infra/widearea-dns.ts +++ b/src/infra/widearea-dns.ts @@ -75,6 +75,7 @@ export type WideAreaBridgeZoneOpts = { tailnetIPv6?: string; instanceLabel?: string; hostLabel?: string; + tailnetDns?: string; }; function renderZone(opts: WideAreaBridgeZoneOpts & { serial: number }): string { @@ -90,6 +91,9 @@ function renderZone(opts: WideAreaBridgeZoneOpts & { serial: number }): string { `transport=bridge`, `bridgePort=${opts.bridgePort}`, ]; + if (opts.tailnetDns?.trim()) { + txt.push(`tailnetDns=${opts.tailnetDns.trim()}`); + } const records: string[] = [];