From d7ec043306ed128e5c5f540e944371a98474f36c Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Sat, 20 Sep 2025 15:55:33 -0700 Subject: [PATCH] cmd/tailscale/cli: add ts2021 debug flag to set a dial plan Updates tailscale/corp#32534 Change-Id: Ief4ee0a263ea1edbf652b74d8c335c1e5ee209d7 Signed-off-by: Brad Fitzpatrick --- cmd/tailscale/cli/debug.go | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/cmd/tailscale/cli/debug.go b/cmd/tailscale/cli/debug.go index 9e8fa0d7f..b3170d000 100644 --- a/cmd/tailscale/cli/debug.go +++ b/cmd/tailscale/cli/debug.go @@ -289,6 +289,7 @@ func debugCmd() *ffcli.Command { fs.IntVar(&ts2021Args.version, "version", int(tailcfg.CurrentCapabilityVersion), "protocol version") fs.BoolVar(&ts2021Args.verbose, "verbose", false, "be extra verbose") fs.StringVar(&ts2021Args.aceHost, "ace", "", "if non-empty, use this ACE server IP/hostname as a candidate path") + fs.StringVar(&ts2021Args.dialPlanJSONFile, "dial-plan", "", "if non-empty, use this JSON file to configure the dial plan") return fs })(), }, @@ -967,6 +968,8 @@ var ts2021Args struct { version int // 27 or whatever verbose bool aceHost string // if non-empty, FQDN of https ACE server to use ("ace.example.com") + + dialPlanJSONFile string // if non-empty, path to JSON file [tailcfg.ControlDialPlan] JSON } func runTS2021(ctx context.Context, args []string) error { @@ -1051,6 +1054,18 @@ func runTS2021(ctx context.Context, args []string) error { return fmt.Errorf("creating netmon: %w", err) } + var dialPlan *tailcfg.ControlDialPlan + if ts2021Args.dialPlanJSONFile != "" { + b, err := os.ReadFile(ts2021Args.dialPlanJSONFile) + if err != nil { + return fmt.Errorf("reading dial plan JSON file: %w", err) + } + dialPlan = new(tailcfg.ControlDialPlan) + if err := json.Unmarshal(b, dialPlan); err != nil { + return fmt.Errorf("unmarshaling dial plan JSON file: %w", err) + } + } + noiseDialer := &controlhttp.Dialer{ Hostname: ts2021Args.host, HTTPPort: "80", @@ -1058,6 +1073,7 @@ func runTS2021(ctx context.Context, args []string) error { MachineKey: machinePrivate, ControlKey: keys.PublicKey, ProtocolVersion: uint16(ts2021Args.version), + DialPlan: dialPlan, Dialer: dialFunc, Logf: logf, NetMon: netMon,