summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorAlex Chan <alex@alexwlchan.net>2025-09-03 13:47:32 +0100
committerGitHub <noreply@github.com>2025-09-03 13:47:32 +0100
commitc9f214e503af5357c2cea77629441d8647e6402f (patch)
treefd0bd22d6e04d3e4ae025c8d8d38a0698043d7fb
parentd06d9007a6854b381fede40e25047c213c5e9bc3 (diff)
downloadtailscale-c9f214e503af5357c2cea77629441d8647e6402f.tar.xz
tailscale-c9f214e503af5357c2cea77629441d8647e6402f.zip
ipn: warn about self as the exit node if backend is running (#17018)
Before: $ tailscale ip -4 1.2.3.4 $ tailscale set --exit-node=1.2.3.4 no node found in netmap with IP 1.2.3.4 After: $ tailscale set --exit-node=1.2.3.4 cannot use 1.2.3.4 as an exit node as it is a local IP address to this machine; did you mean --advertise-exit-node? The new error message already existed in the code, but would only be triggered if the backend wasn't running -- which means, in practice, it would almost never be triggered. The old error message is technically true, but could be confusing if you don't know the distinction between "netmap" and "tailnet" -- it could sound like the exit node isn't part of your tailnet. A node is never in its own netmap, but it is part of your tailnet. This error confused me when I was doing some local dev work, and it's confused customers before (e.g. #7513). Using the more specific error message should reduce confusion. Updates #7513 Updates https://github.com/tailscale/corp/issues/23596 Signed-off-by: Alex Chan <alexc@tailscale.com>
-rw-r--r--ipn/prefs.go6
-rw-r--r--ipn/prefs_test.go17
2 files changed, 20 insertions, 3 deletions
diff --git a/ipn/prefs.go b/ipn/prefs.go
index 14b8078c0..88c73ead3 100644
--- a/ipn/prefs.go
+++ b/ipn/prefs.go
@@ -847,6 +847,9 @@ func exitNodeIPOfArg(s string, st *ipnstate.Status) (ip netip.Addr, err error) {
}
ip, err = netip.ParseAddr(s)
if err == nil {
+ if !isRemoteIP(st, ip) {
+ return ip, ExitNodeLocalIPError{s}
+ }
// If we're online already and have a netmap, double check that the IP
// address specified is valid.
if st.BackendState == "Running" {
@@ -858,9 +861,6 @@ func exitNodeIPOfArg(s string, st *ipnstate.Status) (ip netip.Addr, err error) {
return ip, fmt.Errorf("node %v is not advertising an exit node", ip)
}
}
- if !isRemoteIP(st, ip) {
- return ip, ExitNodeLocalIPError{s}
- }
return ip, nil
}
match := 0
diff --git a/ipn/prefs_test.go b/ipn/prefs_test.go
index 7aac20c80..3339a631c 100644
--- a/ipn/prefs_test.go
+++ b/ipn/prefs_test.go
@@ -898,6 +898,23 @@ func TestExitNodeIPOfArg(t *testing.T) {
wantErr: `no node found in netmap with IP 1.2.3.4`,
},
{
+ name: "ip_is_self",
+ arg: "1.2.3.4",
+ st: &ipnstate.Status{
+ TailscaleIPs: []netip.Addr{mustIP("1.2.3.4")},
+ },
+ wantErr: "cannot use 1.2.3.4 as an exit node as it is a local IP address to this machine",
+ },
+ {
+ name: "ip_is_self_when_backend_running",
+ arg: "1.2.3.4",
+ st: &ipnstate.Status{
+ BackendState: "Running",
+ TailscaleIPs: []netip.Addr{mustIP("1.2.3.4")},
+ },
+ wantErr: "cannot use 1.2.3.4 as an exit node as it is a local IP address to this machine",
+ },
+ {
name: "ip_not_exit",
arg: "1.2.3.4",
st: &ipnstate.Status{