cmd/tailscale/cli: add support for tailscale {up,set} --exit-node=auto:any
If the specified exit node string starts with "auto:" (i.e., can be parsed as an ipn.ExitNodeExpression), we update ipn.Prefs.AutoExitNode instead of ipn.Prefs.ExitNodeID. Fixes #16459 Signed-off-by: Nick Khyl <nickk@tailscale.com>
This commit is contained in:
@@ -972,8 +972,7 @@ func TestPrefFlagMapping(t *testing.T) {
|
|||||||
// No CLI flag for this.
|
// No CLI flag for this.
|
||||||
continue
|
continue
|
||||||
case "AutoExitNode":
|
case "AutoExitNode":
|
||||||
// TODO(nickkhyl): should be handled by tailscale {set,up} --exit-node.
|
// Handled by tailscale {set,up} --exit-node=auto:any.
|
||||||
// See tailscale/tailscale#16459.
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
t.Errorf("unexpected new ipn.Pref field %q is not handled by up.go (see addPrefFlagMapping and checkForAccidentalSettingReverts)", prefName)
|
t.Errorf("unexpected new ipn.Pref field %q is not handled by up.go (see addPrefFlagMapping and checkForAccidentalSettingReverts)", prefName)
|
||||||
@@ -1338,6 +1337,27 @@ func TestUpdatePrefs(t *testing.T) {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "auto_exit_node",
|
||||||
|
flags: []string{"--exit-node=auto:any"},
|
||||||
|
curPrefs: &ipn.Prefs{
|
||||||
|
ControlURL: ipn.DefaultControlURL,
|
||||||
|
CorpDNS: true, // enabled by [ipn.NewPrefs] by default
|
||||||
|
NetfilterMode: preftype.NetfilterOn, // enabled by [ipn.NewPrefs] by default
|
||||||
|
},
|
||||||
|
wantJustEditMP: &ipn.MaskedPrefs{
|
||||||
|
WantRunningSet: true, // enabled by default for tailscale up
|
||||||
|
AutoExitNodeSet: true,
|
||||||
|
ExitNodeIDSet: true, // we want ExitNodeID cleared
|
||||||
|
ExitNodeIPSet: true, // same for ExitNodeIP
|
||||||
|
},
|
||||||
|
env: upCheckEnv{backendState: "Running"},
|
||||||
|
checkUpdatePrefsMutations: func(t *testing.T, newPrefs *ipn.Prefs) {
|
||||||
|
if newPrefs.AutoExitNode != ipn.AnyExitNode {
|
||||||
|
t.Errorf("AutoExitNode: got %q; want %q", newPrefs.AutoExitNode, ipn.AnyExitNode)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ func newSetFlagSet(goos string, setArgs *setArgsT) *flag.FlagSet {
|
|||||||
setf.StringVar(&setArgs.profileName, "nickname", "", "nickname for the current account")
|
setf.StringVar(&setArgs.profileName, "nickname", "", "nickname for the current account")
|
||||||
setf.BoolVar(&setArgs.acceptRoutes, "accept-routes", acceptRouteDefault(goos), "accept routes advertised by other Tailscale nodes")
|
setf.BoolVar(&setArgs.acceptRoutes, "accept-routes", acceptRouteDefault(goos), "accept routes advertised by other Tailscale nodes")
|
||||||
setf.BoolVar(&setArgs.acceptDNS, "accept-dns", true, "accept DNS configuration from the admin panel")
|
setf.BoolVar(&setArgs.acceptDNS, "accept-dns", true, "accept DNS configuration from the admin panel")
|
||||||
setf.StringVar(&setArgs.exitNodeIP, "exit-node", "", "Tailscale exit node (IP or base name) for internet traffic, or empty string to not use an exit node")
|
setf.StringVar(&setArgs.exitNodeIP, "exit-node", "", "Tailscale exit node (IP, base name, or auto:any) for internet traffic, or empty string to not use an exit node")
|
||||||
setf.BoolVar(&setArgs.exitNodeAllowLANAccess, "exit-node-allow-lan-access", false, "Allow direct access to the local network when routing traffic via an exit node")
|
setf.BoolVar(&setArgs.exitNodeAllowLANAccess, "exit-node-allow-lan-access", false, "Allow direct access to the local network when routing traffic via an exit node")
|
||||||
setf.BoolVar(&setArgs.shieldsUp, "shields-up", false, "don't allow incoming connections")
|
setf.BoolVar(&setArgs.shieldsUp, "shields-up", false, "don't allow incoming connections")
|
||||||
setf.BoolVar(&setArgs.runSSH, "ssh", false, "run an SSH server, permitting access per tailnet admin's declared policy")
|
setf.BoolVar(&setArgs.runSSH, "ssh", false, "run an SSH server, permitting access per tailnet admin's declared policy")
|
||||||
@@ -173,7 +173,10 @@ func runSet(ctx context.Context, args []string) (retErr error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if setArgs.exitNodeIP != "" {
|
if setArgs.exitNodeIP != "" {
|
||||||
if err := maskedPrefs.Prefs.SetExitNodeIP(setArgs.exitNodeIP, st); err != nil {
|
if expr, useAutoExitNode := ipn.ParseAutoExitNodeString(setArgs.exitNodeIP); useAutoExitNode {
|
||||||
|
maskedPrefs.AutoExitNode = expr
|
||||||
|
maskedPrefs.AutoExitNodeSet = true
|
||||||
|
} else if err := maskedPrefs.Prefs.SetExitNodeIP(setArgs.exitNodeIP, st); err != nil {
|
||||||
var e ipn.ExitNodeLocalIPError
|
var e ipn.ExitNodeLocalIPError
|
||||||
if errors.As(err, &e) {
|
if errors.As(err, &e) {
|
||||||
return fmt.Errorf("%w; did you mean --advertise-exit-node?", err)
|
return fmt.Errorf("%w; did you mean --advertise-exit-node?", err)
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ func newUpFlagSet(goos string, upArgs *upArgsT, cmd string) *flag.FlagSet {
|
|||||||
upf.BoolVar(&upArgs.acceptRoutes, "accept-routes", acceptRouteDefault(goos), "accept routes advertised by other Tailscale nodes")
|
upf.BoolVar(&upArgs.acceptRoutes, "accept-routes", acceptRouteDefault(goos), "accept routes advertised by other Tailscale nodes")
|
||||||
upf.BoolVar(&upArgs.acceptDNS, "accept-dns", true, "accept DNS configuration from the admin panel")
|
upf.BoolVar(&upArgs.acceptDNS, "accept-dns", true, "accept DNS configuration from the admin panel")
|
||||||
upf.Var(notFalseVar{}, "host-routes", hidden+"install host routes to other Tailscale nodes (must be true as of Tailscale 1.67+)")
|
upf.Var(notFalseVar{}, "host-routes", hidden+"install host routes to other Tailscale nodes (must be true as of Tailscale 1.67+)")
|
||||||
upf.StringVar(&upArgs.exitNodeIP, "exit-node", "", "Tailscale exit node (IP or base name) for internet traffic, or empty string to not use an exit node")
|
upf.StringVar(&upArgs.exitNodeIP, "exit-node", "", "Tailscale exit node (IP, base name, or auto:any) for internet traffic, or empty string to not use an exit node")
|
||||||
upf.BoolVar(&upArgs.exitNodeAllowLANAccess, "exit-node-allow-lan-access", false, "Allow direct access to the local network when routing traffic via an exit node")
|
upf.BoolVar(&upArgs.exitNodeAllowLANAccess, "exit-node-allow-lan-access", false, "Allow direct access to the local network when routing traffic via an exit node")
|
||||||
upf.BoolVar(&upArgs.shieldsUp, "shields-up", false, "don't allow incoming connections")
|
upf.BoolVar(&upArgs.shieldsUp, "shields-up", false, "don't allow incoming connections")
|
||||||
upf.BoolVar(&upArgs.runSSH, "ssh", false, "run an SSH server, permitting access per tailnet admin's declared policy")
|
upf.BoolVar(&upArgs.runSSH, "ssh", false, "run an SSH server, permitting access per tailnet admin's declared policy")
|
||||||
@@ -278,7 +278,9 @@ func prefsFromUpArgs(upArgs upArgsT, warnf logger.Logf, st *ipnstate.Status, goo
|
|||||||
prefs.NetfilterMode = preftype.NetfilterOff
|
prefs.NetfilterMode = preftype.NetfilterOff
|
||||||
}
|
}
|
||||||
if upArgs.exitNodeIP != "" {
|
if upArgs.exitNodeIP != "" {
|
||||||
if err := prefs.SetExitNodeIP(upArgs.exitNodeIP, st); err != nil {
|
if expr, useAutoExitNode := ipn.ParseAutoExitNodeString(upArgs.exitNodeIP); useAutoExitNode {
|
||||||
|
prefs.AutoExitNode = expr
|
||||||
|
} else if err := prefs.SetExitNodeIP(upArgs.exitNodeIP, st); err != nil {
|
||||||
var e ipn.ExitNodeLocalIPError
|
var e ipn.ExitNodeLocalIPError
|
||||||
if errors.As(err, &e) {
|
if errors.As(err, &e) {
|
||||||
return nil, fmt.Errorf("%w; did you mean --advertise-exit-node?", err)
|
return nil, fmt.Errorf("%w; did you mean --advertise-exit-node?", err)
|
||||||
@@ -408,6 +410,9 @@ func updatePrefs(prefs, curPrefs *ipn.Prefs, env upCheckEnv) (simpleUp bool, jus
|
|||||||
if env.upArgs.reset {
|
if env.upArgs.reset {
|
||||||
visitFlags = env.flagSet.VisitAll
|
visitFlags = env.flagSet.VisitAll
|
||||||
}
|
}
|
||||||
|
if prefs.AutoExitNode.IsSet() {
|
||||||
|
justEditMP.AutoExitNodeSet = true
|
||||||
|
}
|
||||||
visitFlags(func(f *flag.Flag) {
|
visitFlags(func(f *flag.Flag) {
|
||||||
updateMaskedPrefsFromUpOrSetFlag(justEditMP, f.Name)
|
updateMaskedPrefsFromUpOrSetFlag(justEditMP, f.Name)
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user