From 964282d34f06ecc06ce644769c66b0b31d118340 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Fri, 17 May 2024 13:47:57 -0700 Subject: [PATCH] ipn,wgengine: remove vestigial Prefs.AllowSingleHosts It was requested by the first customer 4-5 years ago and only used for a brief moment of time. We later added netmap visibility trimming which removes the need for this. It's been hidden by the CLI for quite some time and never documented anywhere else. This keeps the CLI flag, though, out of caution. It just returns an error if it's set to anything but true (its default). Fixes #12058 Change-Id: I7514ba572e7b82519b04ed603ff9f3bdbaecfda7 Signed-off-by: Brad Fitzpatrick --- cmd/tailscale/cli/cli_test.go | 370 ++++++++++++--------------- cmd/tailscale/cli/up.go | 21 +- cmd/tsconnect/wasm/wasm_js.go | 9 +- ipn/ipn_clone.go | 2 +- ipn/ipn_view.go | 6 +- ipn/ipnlocal/local.go | 3 - ipn/prefs.go | 35 ++- ipn/prefs_test.go | 104 ++++---- types/netmap/netmap.go | 2 +- wgengine/magicsock/magicsock_test.go | 8 +- wgengine/wgcfg/nmcfg/nmcfg.go | 7 - 11 files changed, 263 insertions(+), 304 deletions(-) diff --git a/cmd/tailscale/cli/cli_test.go b/cmd/tailscale/cli/cli_test.go index c49707612..9c87ec33f 100644 --- a/cmd/tailscale/cli/cli_test.go +++ b/cmd/tailscale/cli/cli_test.go @@ -186,12 +186,11 @@ func TestCheckForAccidentalSettingReverts(t *testing.T) { name: "losing_hostname", flags: []string{"--accept-dns"}, curPrefs: &ipn.Prefs{ - ControlURL: ipn.DefaultControlURL, - WantRunning: false, - Hostname: "foo", - CorpDNS: true, - NetfilterMode: preftype.NetfilterOn, - AllowSingleHosts: true, + ControlURL: ipn.DefaultControlURL, + WantRunning: false, + Hostname: "foo", + CorpDNS: true, + NetfilterMode: preftype.NetfilterOn, }, want: accidentalUpPrefix + " --accept-dns --hostname=foo", }, @@ -199,11 +198,10 @@ func TestCheckForAccidentalSettingReverts(t *testing.T) { name: "hostname_changing_explicitly", flags: []string{"--hostname=bar"}, curPrefs: &ipn.Prefs{ - ControlURL: ipn.DefaultControlURL, - CorpDNS: true, - NetfilterMode: preftype.NetfilterOn, - AllowSingleHosts: true, - Hostname: "foo", + ControlURL: ipn.DefaultControlURL, + CorpDNS: true, + NetfilterMode: preftype.NetfilterOn, + Hostname: "foo", }, want: "", }, @@ -211,11 +209,10 @@ func TestCheckForAccidentalSettingReverts(t *testing.T) { name: "hostname_changing_empty_explicitly", flags: []string{"--hostname="}, curPrefs: &ipn.Prefs{ - ControlURL: ipn.DefaultControlURL, - CorpDNS: true, - NetfilterMode: preftype.NetfilterOn, - AllowSingleHosts: true, - Hostname: "foo", + ControlURL: ipn.DefaultControlURL, + CorpDNS: true, + NetfilterMode: preftype.NetfilterOn, + Hostname: "foo", }, want: "", }, @@ -231,11 +228,10 @@ func TestCheckForAccidentalSettingReverts(t *testing.T) { name: "implicit_operator_change", flags: []string{"--hostname=foo"}, curPrefs: &ipn.Prefs{ - ControlURL: ipn.DefaultControlURL, - OperatorUser: "alice", - AllowSingleHosts: true, - CorpDNS: true, - NetfilterMode: preftype.NetfilterOn, + ControlURL: ipn.DefaultControlURL, + OperatorUser: "alice", + CorpDNS: true, + NetfilterMode: preftype.NetfilterOn, }, curUser: "eve", want: accidentalUpPrefix + " --hostname=foo --operator=alice", @@ -244,11 +240,10 @@ func TestCheckForAccidentalSettingReverts(t *testing.T) { name: "implicit_operator_matches_shell_user", flags: []string{"--hostname=foo"}, curPrefs: &ipn.Prefs{ - ControlURL: ipn.DefaultControlURL, - AllowSingleHosts: true, - CorpDNS: true, - NetfilterMode: preftype.NetfilterOn, - OperatorUser: "alice", + ControlURL: ipn.DefaultControlURL, + CorpDNS: true, + NetfilterMode: preftype.NetfilterOn, + OperatorUser: "alice", }, curUser: "alice", want: "", @@ -257,10 +252,9 @@ func TestCheckForAccidentalSettingReverts(t *testing.T) { name: "error_advertised_routes_exit_node_removed", flags: []string{"--advertise-routes=10.0.42.0/24"}, curPrefs: &ipn.Prefs{ - ControlURL: ipn.DefaultControlURL, - AllowSingleHosts: true, - CorpDNS: true, - NetfilterMode: preftype.NetfilterOn, + ControlURL: ipn.DefaultControlURL, + CorpDNS: true, + NetfilterMode: preftype.NetfilterOn, AdvertiseRoutes: []netip.Prefix{ netip.MustParsePrefix("10.0.42.0/24"), netip.MustParsePrefix("0.0.0.0/0"), @@ -273,10 +267,9 @@ func TestCheckForAccidentalSettingReverts(t *testing.T) { name: "advertised_routes_exit_node_removed_explicit", flags: []string{"--advertise-routes=10.0.42.0/24", "--advertise-exit-node=false"}, curPrefs: &ipn.Prefs{ - ControlURL: ipn.DefaultControlURL, - AllowSingleHosts: true, - CorpDNS: true, - NetfilterMode: preftype.NetfilterOn, + ControlURL: ipn.DefaultControlURL, + CorpDNS: true, + NetfilterMode: preftype.NetfilterOn, AdvertiseRoutes: []netip.Prefix{ netip.MustParsePrefix("10.0.42.0/24"), netip.MustParsePrefix("0.0.0.0/0"), @@ -289,10 +282,9 @@ func TestCheckForAccidentalSettingReverts(t *testing.T) { name: "advertised_routes_includes_the_0_routes", // but no --advertise-exit-node flags: []string{"--advertise-routes=11.1.43.0/24,0.0.0.0/0,::/0"}, curPrefs: &ipn.Prefs{ - ControlURL: ipn.DefaultControlURL, - AllowSingleHosts: true, - CorpDNS: true, - NetfilterMode: preftype.NetfilterOn, + ControlURL: ipn.DefaultControlURL, + CorpDNS: true, + NetfilterMode: preftype.NetfilterOn, AdvertiseRoutes: []netip.Prefix{ netip.MustParsePrefix("10.0.42.0/24"), netip.MustParsePrefix("0.0.0.0/0"), @@ -305,10 +297,9 @@ func TestCheckForAccidentalSettingReverts(t *testing.T) { name: "advertise_exit_node", // Issue 1859 flags: []string{"--advertise-exit-node"}, curPrefs: &ipn.Prefs{ - ControlURL: ipn.DefaultControlURL, - AllowSingleHosts: true, - CorpDNS: true, - NetfilterMode: preftype.NetfilterOn, + ControlURL: ipn.DefaultControlURL, + CorpDNS: true, + NetfilterMode: preftype.NetfilterOn, }, want: "", }, @@ -316,10 +307,9 @@ func TestCheckForAccidentalSettingReverts(t *testing.T) { name: "advertise_exit_node_over_existing_routes", flags: []string{"--advertise-exit-node"}, curPrefs: &ipn.Prefs{ - ControlURL: ipn.DefaultControlURL, - AllowSingleHosts: true, - CorpDNS: true, - NetfilterMode: preftype.NetfilterOn, + ControlURL: ipn.DefaultControlURL, + CorpDNS: true, + NetfilterMode: preftype.NetfilterOn, AdvertiseRoutes: []netip.Prefix{ netip.MustParsePrefix("1.2.0.0/16"), @@ -331,10 +321,9 @@ func TestCheckForAccidentalSettingReverts(t *testing.T) { name: "advertise_exit_node_over_existing_routes_and_exit_node", flags: []string{"--advertise-exit-node"}, curPrefs: &ipn.Prefs{ - ControlURL: ipn.DefaultControlURL, - AllowSingleHosts: true, - CorpDNS: true, - NetfilterMode: preftype.NetfilterOn, + ControlURL: ipn.DefaultControlURL, + CorpDNS: true, + NetfilterMode: preftype.NetfilterOn, AdvertiseRoutes: []netip.Prefix{ netip.MustParsePrefix("0.0.0.0/0"), netip.MustParsePrefix("::/0"), @@ -347,10 +336,9 @@ func TestCheckForAccidentalSettingReverts(t *testing.T) { name: "exit_node_clearing", // Issue 1777 flags: []string{"--exit-node="}, curPrefs: &ipn.Prefs{ - ControlURL: ipn.DefaultControlURL, - AllowSingleHosts: true, - CorpDNS: true, - NetfilterMode: preftype.NetfilterOn, + ControlURL: ipn.DefaultControlURL, + CorpDNS: true, + NetfilterMode: preftype.NetfilterOn, ExitNodeID: "fooID", }, @@ -360,16 +348,15 @@ func TestCheckForAccidentalSettingReverts(t *testing.T) { name: "remove_all_implicit", flags: []string{"--force-reauth"}, curPrefs: &ipn.Prefs{ - WantRunning: true, - ControlURL: ipn.DefaultControlURL, - RouteAll: true, - AllowSingleHosts: false, - ExitNodeIP: netip.MustParseAddr("100.64.5.6"), - CorpDNS: false, - ShieldsUp: true, - AdvertiseTags: []string{"tag:foo", "tag:bar"}, - Hostname: "myhostname", - ForceDaemon: true, + WantRunning: true, + ControlURL: ipn.DefaultControlURL, + RouteAll: true, + ExitNodeIP: netip.MustParseAddr("100.64.5.6"), + CorpDNS: false, + ShieldsUp: true, + AdvertiseTags: []string{"tag:foo", "tag:bar"}, + Hostname: "myhostname", + ForceDaemon: true, AdvertiseRoutes: []netip.Prefix{ netip.MustParsePrefix("10.0.0.0/16"), netip.MustParsePrefix("0.0.0.0/0"), @@ -379,22 +366,21 @@ func TestCheckForAccidentalSettingReverts(t *testing.T) { OperatorUser: "alice", }, curUser: "eve", - want: accidentalUpPrefix + " --force-reauth --accept-dns=false --accept-routes --advertise-exit-node --advertise-routes=10.0.0.0/16 --advertise-tags=tag:foo,tag:bar --exit-node=100.64.5.6 --host-routes=false --hostname=myhostname --netfilter-mode=nodivert --operator=alice --shields-up", + want: accidentalUpPrefix + " --force-reauth --accept-dns=false --accept-routes --advertise-exit-node --advertise-routes=10.0.0.0/16 --advertise-tags=tag:foo,tag:bar --exit-node=100.64.5.6 --hostname=myhostname --netfilter-mode=nodivert --operator=alice --shields-up", }, { name: "remove_all_implicit_except_hostname", flags: []string{"--hostname=newhostname"}, curPrefs: &ipn.Prefs{ - WantRunning: true, - ControlURL: ipn.DefaultControlURL, - RouteAll: true, - AllowSingleHosts: false, - ExitNodeIP: netip.MustParseAddr("100.64.5.6"), - CorpDNS: false, - ShieldsUp: true, - AdvertiseTags: []string{"tag:foo", "tag:bar"}, - Hostname: "myhostname", - ForceDaemon: true, + WantRunning: true, + ControlURL: ipn.DefaultControlURL, + RouteAll: true, + ExitNodeIP: netip.MustParseAddr("100.64.5.6"), + CorpDNS: false, + ShieldsUp: true, + AdvertiseTags: []string{"tag:foo", "tag:bar"}, + Hostname: "myhostname", + ForceDaemon: true, AdvertiseRoutes: []netip.Prefix{ netip.MustParsePrefix("10.0.0.0/16"), }, @@ -402,17 +388,16 @@ func TestCheckForAccidentalSettingReverts(t *testing.T) { OperatorUser: "alice", }, curUser: "eve", - want: accidentalUpPrefix + " --hostname=newhostname --accept-dns=false --accept-routes --advertise-routes=10.0.0.0/16 --advertise-tags=tag:foo,tag:bar --exit-node=100.64.5.6 --host-routes=false --netfilter-mode=nodivert --operator=alice --shields-up", + want: accidentalUpPrefix + " --hostname=newhostname --accept-dns=false --accept-routes --advertise-routes=10.0.0.0/16 --advertise-tags=tag:foo,tag:bar --exit-node=100.64.5.6 --netfilter-mode=nodivert --operator=alice --shields-up", }, { name: "loggedout_is_implicit", flags: []string{"--hostname=foo"}, curPrefs: &ipn.Prefs{ - ControlURL: ipn.DefaultControlURL, - LoggedOut: true, - AllowSingleHosts: true, - CorpDNS: true, - NetfilterMode: preftype.NetfilterOn, + ControlURL: ipn.DefaultControlURL, + LoggedOut: true, + CorpDNS: true, + NetfilterMode: preftype.NetfilterOn, }, want: "", // not an error. LoggedOut is implicit. }, @@ -422,10 +407,9 @@ func TestCheckForAccidentalSettingReverts(t *testing.T) { name: "make_windows_exit_node", flags: []string{"--advertise-exit-node"}, curPrefs: &ipn.Prefs{ - ControlURL: ipn.DefaultControlURL, - AllowSingleHosts: true, - CorpDNS: true, - RouteAll: true, + ControlURL: ipn.DefaultControlURL, + CorpDNS: true, + RouteAll: true, // And assume this no-op accidental pre-1.8 value: NoSNAT: true, @@ -437,8 +421,7 @@ func TestCheckForAccidentalSettingReverts(t *testing.T) { name: "ignore_netfilter_change_non_linux", flags: []string{"--accept-dns"}, curPrefs: &ipn.Prefs{ - ControlURL: ipn.DefaultControlURL, - AllowSingleHosts: true, + ControlURL: ipn.DefaultControlURL, NetfilterMode: preftype.NetfilterNoDivert, // we never had this bug, but pretend it got set non-zero on Windows somehow }, @@ -449,10 +432,9 @@ func TestCheckForAccidentalSettingReverts(t *testing.T) { name: "operator_losing_routes_step1", // https://twitter.com/EXPbits/status/1390418145047887877 flags: []string{"--operator=expbits"}, curPrefs: &ipn.Prefs{ - ControlURL: ipn.DefaultControlURL, - AllowSingleHosts: true, - CorpDNS: true, - NetfilterMode: preftype.NetfilterOn, + ControlURL: ipn.DefaultControlURL, + CorpDNS: true, + NetfilterMode: preftype.NetfilterOn, AdvertiseRoutes: []netip.Prefix{ netip.MustParsePrefix("0.0.0.0/0"), netip.MustParsePrefix("::/0"), @@ -465,10 +447,9 @@ func TestCheckForAccidentalSettingReverts(t *testing.T) { name: "operator_losing_routes_step2", // https://twitter.com/EXPbits/status/1390418145047887877 flags: []string{"--operator=expbits", "--advertise-routes=1.2.0.0/16"}, curPrefs: &ipn.Prefs{ - ControlURL: ipn.DefaultControlURL, - AllowSingleHosts: true, - CorpDNS: true, - NetfilterMode: preftype.NetfilterOn, + ControlURL: ipn.DefaultControlURL, + CorpDNS: true, + NetfilterMode: preftype.NetfilterOn, AdvertiseRoutes: []netip.Prefix{ netip.MustParsePrefix("0.0.0.0/0"), netip.MustParsePrefix("::/0"), @@ -481,11 +462,10 @@ func TestCheckForAccidentalSettingReverts(t *testing.T) { name: "errors_preserve_explicit_flags", flags: []string{"--reset", "--force-reauth=false", "--authkey=secretrand"}, curPrefs: &ipn.Prefs{ - ControlURL: ipn.DefaultControlURL, - WantRunning: false, - CorpDNS: true, - NetfilterMode: preftype.NetfilterOn, - AllowSingleHosts: true, + ControlURL: ipn.DefaultControlURL, + WantRunning: false, + CorpDNS: true, + NetfilterMode: preftype.NetfilterOn, Hostname: "foo", }, @@ -495,10 +475,9 @@ func TestCheckForAccidentalSettingReverts(t *testing.T) { name: "error_exit_node_omit_with_ip_pref", flags: []string{"--hostname=foo"}, curPrefs: &ipn.Prefs{ - ControlURL: ipn.DefaultControlURL, - AllowSingleHosts: true, - CorpDNS: true, - NetfilterMode: preftype.NetfilterOn, + ControlURL: ipn.DefaultControlURL, + CorpDNS: true, + NetfilterMode: preftype.NetfilterOn, ExitNodeIP: netip.MustParseAddr("100.64.5.4"), }, @@ -509,10 +488,9 @@ func TestCheckForAccidentalSettingReverts(t *testing.T) { flags: []string{"--hostname=foo"}, curExitNodeIP: netip.MustParseAddr("100.64.5.7"), curPrefs: &ipn.Prefs{ - ControlURL: ipn.DefaultControlURL, - AllowSingleHosts: true, - CorpDNS: true, - NetfilterMode: preftype.NetfilterOn, + ControlURL: ipn.DefaultControlURL, + CorpDNS: true, + NetfilterMode: preftype.NetfilterOn, ExitNodeID: "some_stable_id", }, @@ -523,10 +501,9 @@ func TestCheckForAccidentalSettingReverts(t *testing.T) { flags: []string{"--hostname=foo"}, curExitNodeIP: netip.MustParseAddr("100.2.3.4"), curPrefs: &ipn.Prefs{ - ControlURL: ipn.DefaultControlURL, - AllowSingleHosts: true, - CorpDNS: true, - NetfilterMode: preftype.NetfilterOn, + ControlURL: ipn.DefaultControlURL, + CorpDNS: true, + NetfilterMode: preftype.NetfilterOn, ExitNodeAllowLANAccess: true, ExitNodeID: "some_stable_id", @@ -537,10 +514,9 @@ func TestCheckForAccidentalSettingReverts(t *testing.T) { name: "ignore_login_server_synonym", flags: []string{"--login-server=https://controlplane.tailscale.com"}, curPrefs: &ipn.Prefs{ - ControlURL: "https://login.tailscale.com", - AllowSingleHosts: true, - CorpDNS: true, - NetfilterMode: preftype.NetfilterOn, + ControlURL: "https://login.tailscale.com", + CorpDNS: true, + NetfilterMode: preftype.NetfilterOn, }, want: "", // not an error }, @@ -548,10 +524,9 @@ func TestCheckForAccidentalSettingReverts(t *testing.T) { name: "ignore_login_server_synonym_on_other_change", flags: []string{"--netfilter-mode=off"}, curPrefs: &ipn.Prefs{ - ControlURL: "https://login.tailscale.com", - AllowSingleHosts: true, - CorpDNS: false, - NetfilterMode: preftype.NetfilterOn, + ControlURL: "https://login.tailscale.com", + CorpDNS: false, + NetfilterMode: preftype.NetfilterOn, }, want: accidentalUpPrefix + " --netfilter-mode=off --accept-dns=false", }, @@ -561,11 +536,10 @@ func TestCheckForAccidentalSettingReverts(t *testing.T) { name: "synology_permit_omit_accept_routes", flags: []string{"--hostname=foo"}, curPrefs: &ipn.Prefs{ - ControlURL: "https://login.tailscale.com", - CorpDNS: true, - AllowSingleHosts: true, - RouteAll: true, - NetfilterMode: preftype.NetfilterOn, + ControlURL: "https://login.tailscale.com", + CorpDNS: true, + RouteAll: true, + NetfilterMode: preftype.NetfilterOn, }, goos: "linux", distro: distro.Synology, @@ -577,11 +551,10 @@ func TestCheckForAccidentalSettingReverts(t *testing.T) { name: "not_synology_dont_permit_omit_accept_routes", flags: []string{"--hostname=foo"}, curPrefs: &ipn.Prefs{ - ControlURL: "https://login.tailscale.com", - CorpDNS: true, - AllowSingleHosts: true, - RouteAll: true, - NetfilterMode: preftype.NetfilterOn, + ControlURL: "https://login.tailscale.com", + CorpDNS: true, + RouteAll: true, + NetfilterMode: preftype.NetfilterOn, }, goos: "linux", distro: "", // not Synology @@ -591,11 +564,10 @@ func TestCheckForAccidentalSettingReverts(t *testing.T) { name: "profile_name_ignored_in_up", flags: []string{"--hostname=foo"}, curPrefs: &ipn.Prefs{ - ControlURL: "https://login.tailscale.com", - CorpDNS: true, - AllowSingleHosts: true, - NetfilterMode: preftype.NetfilterOn, - ProfileName: "foo", + ControlURL: "https://login.tailscale.com", + CorpDNS: true, + NetfilterMode: preftype.NetfilterOn, + ProfileName: "foo", }, goos: "linux", want: "", @@ -661,7 +633,6 @@ func TestPrefsFromUpArgs(t *testing.T) { NoStatefulFiltering: "false", NetfilterMode: preftype.NetfilterOn, CorpDNS: true, - AllowSingleHosts: true, AutoUpdate: ipn.AutoUpdatePrefs{ Check: true, }, @@ -675,7 +646,6 @@ func TestPrefsFromUpArgs(t *testing.T) { ControlURL: ipn.DefaultControlURL, WantRunning: true, CorpDNS: true, - AllowSingleHosts: true, RouteAll: true, NoSNAT: false, NoStatefulFiltering: "false", @@ -689,10 +659,9 @@ func TestPrefsFromUpArgs(t *testing.T) { name: "advertise_default_route", args: upArgsFromOSArgs("linux", "--advertise-exit-node"), want: &ipn.Prefs{ - ControlURL: ipn.DefaultControlURL, - WantRunning: true, - AllowSingleHosts: true, - CorpDNS: true, + ControlURL: ipn.DefaultControlURL, + WantRunning: true, + CorpDNS: true, AdvertiseRoutes: []netip.Prefix{ netip.MustParsePrefix("0.0.0.0/0"), netip.MustParsePrefix("::/0"), @@ -922,6 +891,9 @@ func TestPrefFlagMapping(t *testing.T) { continue } switch prefName { + case "AllowSingleHosts": + // Fake pref for downgrade compat. See #12058. + continue case "WantRunning", "Persist", "LoggedOut": // All explicitly handled (ignored) by checkForAccidentalSettingReverts. continue @@ -1029,7 +1001,6 @@ func TestUpdatePrefs(t *testing.T) { wantJustEditMP: &ipn.MaskedPrefs{ AdvertiseRoutesSet: true, AdvertiseTagsSet: true, - AllowSingleHostsSet: true, AppConnectorSet: true, ControlURLSet: true, CorpDNSSet: true, @@ -1062,11 +1033,10 @@ func TestUpdatePrefs(t *testing.T) { name: "change_login_server", flags: []string{"--login-server=https://localhost:1000"}, curPrefs: &ipn.Prefs{ - ControlURL: "https://login.tailscale.com", - Persist: &persist.Persist{UserProfile: tailcfg.UserProfile{LoginName: "crawshaw.github"}}, - AllowSingleHosts: true, - CorpDNS: true, - NetfilterMode: preftype.NetfilterOn, + ControlURL: "https://login.tailscale.com", + Persist: &persist.Persist{UserProfile: tailcfg.UserProfile{LoginName: "crawshaw.github"}}, + CorpDNS: true, + NetfilterMode: preftype.NetfilterOn, }, env: upCheckEnv{backendState: "Running"}, wantSimpleUp: true, @@ -1077,11 +1047,10 @@ func TestUpdatePrefs(t *testing.T) { name: "change_tags", flags: []string{"--advertise-tags=tag:foo"}, curPrefs: &ipn.Prefs{ - ControlURL: "https://login.tailscale.com", - Persist: &persist.Persist{UserProfile: tailcfg.UserProfile{LoginName: "crawshaw.github"}}, - AllowSingleHosts: true, - CorpDNS: true, - NetfilterMode: preftype.NetfilterOn, + ControlURL: "https://login.tailscale.com", + Persist: &persist.Persist{UserProfile: tailcfg.UserProfile{LoginName: "crawshaw.github"}}, + CorpDNS: true, + NetfilterMode: preftype.NetfilterOn, }, env: upCheckEnv{backendState: "Running"}, }, @@ -1090,11 +1059,10 @@ func TestUpdatePrefs(t *testing.T) { name: "explicit_empty_operator", flags: []string{"--operator="}, curPrefs: &ipn.Prefs{ - ControlURL: "https://login.tailscale.com", - CorpDNS: true, - AllowSingleHosts: true, - NetfilterMode: preftype.NetfilterOn, - OperatorUser: "somebody", + ControlURL: "https://login.tailscale.com", + CorpDNS: true, + NetfilterMode: preftype.NetfilterOn, + OperatorUser: "somebody", }, env: upCheckEnv{user: "somebody", backendState: "Running"}, wantJustEditMP: &ipn.MaskedPrefs{ @@ -1111,11 +1079,10 @@ func TestUpdatePrefs(t *testing.T) { name: "enable_ssh", flags: []string{"--ssh"}, curPrefs: &ipn.Prefs{ - ControlURL: "https://login.tailscale.com", - Persist: &persist.Persist{UserProfile: tailcfg.UserProfile{LoginName: "crawshaw.github"}}, - AllowSingleHosts: true, - CorpDNS: true, - NetfilterMode: preftype.NetfilterOn, + ControlURL: "https://login.tailscale.com", + Persist: &persist.Persist{UserProfile: tailcfg.UserProfile{LoginName: "crawshaw.github"}}, + CorpDNS: true, + NetfilterMode: preftype.NetfilterOn, }, wantJustEditMP: &ipn.MaskedPrefs{ RunSSHSet: true, @@ -1132,12 +1099,11 @@ func TestUpdatePrefs(t *testing.T) { name: "disable_ssh", flags: []string{"--ssh=false"}, curPrefs: &ipn.Prefs{ - ControlURL: "https://login.tailscale.com", - Persist: &persist.Persist{UserProfile: tailcfg.UserProfile{LoginName: "crawshaw.github"}}, - AllowSingleHosts: true, - CorpDNS: true, - RunSSH: true, - NetfilterMode: preftype.NetfilterOn, + ControlURL: "https://login.tailscale.com", + Persist: &persist.Persist{UserProfile: tailcfg.UserProfile{LoginName: "crawshaw.github"}}, + CorpDNS: true, + RunSSH: true, + NetfilterMode: preftype.NetfilterOn, }, wantJustEditMP: &ipn.MaskedPrefs{ RunSSHSet: true, @@ -1157,12 +1123,11 @@ func TestUpdatePrefs(t *testing.T) { flags: []string{"--ssh=false"}, sshOverTailscale: true, curPrefs: &ipn.Prefs{ - ControlURL: "https://login.tailscale.com", - Persist: &persist.Persist{UserProfile: tailcfg.UserProfile{LoginName: "crawshaw.github"}}, - AllowSingleHosts: true, - CorpDNS: true, - NetfilterMode: preftype.NetfilterOn, - RunSSH: true, + ControlURL: "https://login.tailscale.com", + Persist: &persist.Persist{UserProfile: tailcfg.UserProfile{LoginName: "crawshaw.github"}}, + CorpDNS: true, + NetfilterMode: preftype.NetfilterOn, + RunSSH: true, }, wantJustEditMP: &ipn.MaskedPrefs{ RunSSHSet: true, @@ -1181,11 +1146,10 @@ func TestUpdatePrefs(t *testing.T) { flags: []string{"--ssh=true"}, sshOverTailscale: true, curPrefs: &ipn.Prefs{ - ControlURL: "https://login.tailscale.com", - Persist: &persist.Persist{UserProfile: tailcfg.UserProfile{LoginName: "crawshaw.github"}}, - AllowSingleHosts: true, - CorpDNS: true, - NetfilterMode: preftype.NetfilterOn, + ControlURL: "https://login.tailscale.com", + Persist: &persist.Persist{UserProfile: tailcfg.UserProfile{LoginName: "crawshaw.github"}}, + CorpDNS: true, + NetfilterMode: preftype.NetfilterOn, }, wantJustEditMP: &ipn.MaskedPrefs{ RunSSHSet: true, @@ -1204,11 +1168,10 @@ func TestUpdatePrefs(t *testing.T) { flags: []string{"--ssh=true", "--accept-risk=lose-ssh"}, sshOverTailscale: true, curPrefs: &ipn.Prefs{ - ControlURL: "https://login.tailscale.com", - Persist: &persist.Persist{UserProfile: tailcfg.UserProfile{LoginName: "crawshaw.github"}}, - AllowSingleHosts: true, - CorpDNS: true, - NetfilterMode: preftype.NetfilterOn, + ControlURL: "https://login.tailscale.com", + Persist: &persist.Persist{UserProfile: tailcfg.UserProfile{LoginName: "crawshaw.github"}}, + CorpDNS: true, + NetfilterMode: preftype.NetfilterOn, }, wantJustEditMP: &ipn.MaskedPrefs{ RunSSHSet: true, @@ -1226,12 +1189,11 @@ func TestUpdatePrefs(t *testing.T) { flags: []string{"--ssh=false", "--accept-risk=lose-ssh"}, sshOverTailscale: true, curPrefs: &ipn.Prefs{ - ControlURL: "https://login.tailscale.com", - Persist: &persist.Persist{UserProfile: tailcfg.UserProfile{LoginName: "crawshaw.github"}}, - AllowSingleHosts: true, - CorpDNS: true, - RunSSH: true, - NetfilterMode: preftype.NetfilterOn, + ControlURL: "https://login.tailscale.com", + Persist: &persist.Persist{UserProfile: tailcfg.UserProfile{LoginName: "crawshaw.github"}}, + CorpDNS: true, + RunSSH: true, + NetfilterMode: preftype.NetfilterOn, }, wantJustEditMP: &ipn.MaskedPrefs{ RunSSHSet: true, @@ -1249,10 +1211,9 @@ func TestUpdatePrefs(t *testing.T) { flags: []string{"--force-reauth"}, sshOverTailscale: true, curPrefs: &ipn.Prefs{ - ControlURL: "https://login.tailscale.com", - AllowSingleHosts: true, - CorpDNS: true, - NetfilterMode: preftype.NetfilterOn, + ControlURL: "https://login.tailscale.com", + CorpDNS: true, + NetfilterMode: preftype.NetfilterOn, }, env: upCheckEnv{backendState: "Running"}, wantErrSubtr: "aborted, no changes made", @@ -1262,10 +1223,9 @@ func TestUpdatePrefs(t *testing.T) { flags: []string{"--force-reauth", "--accept-risk=lose-ssh"}, sshOverTailscale: true, curPrefs: &ipn.Prefs{ - ControlURL: "https://login.tailscale.com", - AllowSingleHosts: true, - CorpDNS: true, - NetfilterMode: preftype.NetfilterOn, + ControlURL: "https://login.tailscale.com", + CorpDNS: true, + NetfilterMode: preftype.NetfilterOn, }, wantJustEditMP: nil, env: upCheckEnv{backendState: "Running"}, @@ -1274,10 +1234,9 @@ func TestUpdatePrefs(t *testing.T) { name: "advertise_connector", flags: []string{"--advertise-connector"}, curPrefs: &ipn.Prefs{ - ControlURL: ipn.DefaultControlURL, - AllowSingleHosts: true, - CorpDNS: true, - NetfilterMode: preftype.NetfilterOn, + ControlURL: ipn.DefaultControlURL, + CorpDNS: true, + NetfilterMode: preftype.NetfilterOn, }, wantJustEditMP: &ipn.MaskedPrefs{ AppConnectorSet: true, @@ -1294,10 +1253,9 @@ func TestUpdatePrefs(t *testing.T) { name: "no_advertise_connector", flags: []string{"--advertise-connector=false"}, curPrefs: &ipn.Prefs{ - ControlURL: ipn.DefaultControlURL, - AllowSingleHosts: true, - CorpDNS: true, - NetfilterMode: preftype.NetfilterOn, + ControlURL: ipn.DefaultControlURL, + CorpDNS: true, + NetfilterMode: preftype.NetfilterOn, AppConnector: ipn.AppConnectorPrefs{ Advertise: true, }, diff --git a/cmd/tailscale/cli/up.go b/cmd/tailscale/cli/up.go index 16b28233e..602e1f1ab 100644 --- a/cmd/tailscale/cli/up.go +++ b/cmd/tailscale/cli/up.go @@ -104,7 +104,7 @@ func newUpFlagSet(goos string, upArgs *upArgsT, cmd string) *flag.FlagSet { upf.StringVar(&upArgs.server, "login-server", ipn.DefaultControlURL, "base URL of control server") 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.singleRoutes, "host-routes", true, hidden+"install host routes to other Tailscale nodes") + 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.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") @@ -143,6 +143,18 @@ func newUpFlagSet(goos string, upArgs *upArgsT, cmd string) *flag.FlagSet { return upf } +// notFalseVar is is a flag.Value that can only be "true", if set. +type notFalseVar struct{} + +func (notFalseVar) IsBoolFlag() bool { return true } +func (notFalseVar) Set(v string) error { + if v != "true" { + return fmt.Errorf("unsupported value; only 'true' is allowed") + } + return nil +} +func (notFalseVar) String() string { return "true" } + func defaultNetfilterMode() string { if distro.Get() == distro.Synology { return "off" @@ -156,7 +168,6 @@ type upArgsT struct { server string acceptRoutes bool acceptDNS bool - singleRoutes bool exitNodeIP string exitNodeAllowLANAccess bool shieldsUp bool @@ -278,7 +289,6 @@ func prefsFromUpArgs(upArgs upArgsT, warnf logger.Logf, st *ipnstate.Status, goo prefs.ExitNodeAllowLANAccess = upArgs.exitNodeAllowLANAccess prefs.CorpDNS = upArgs.acceptDNS - prefs.AllowSingleHosts = upArgs.singleRoutes prefs.ShieldsUp = upArgs.shieldsUp prefs.RunSSH = upArgs.runSSH prefs.RunWebClient = upArgs.runWebClient @@ -740,7 +750,6 @@ func init() { addPrefFlagMapping("accept-dns", "CorpDNS") addPrefFlagMapping("accept-routes", "RouteAll") addPrefFlagMapping("advertise-tags", "AdvertiseTags") - addPrefFlagMapping("host-routes", "AllowSingleHosts") addPrefFlagMapping("hostname", "Hostname") addPrefFlagMapping("login-server", "ControlURL") addPrefFlagMapping("netfilter-mode", "NetfilterMode") @@ -779,7 +788,7 @@ func addPrefFlagMapping(flagName string, prefNames ...string) { // correspond to an ipn.Pref. func preflessFlag(flagName string) bool { switch flagName { - case "auth-key", "force-reauth", "reset", "qr", "json", "timeout", "accept-risk": + case "auth-key", "force-reauth", "reset", "qr", "json", "timeout", "accept-risk", "host-routes": return true } return false @@ -975,8 +984,6 @@ func prefsToFlags(env upCheckEnv, prefs *ipn.Prefs) (flagVal map[string]any) { set(prefs.ControlURL) case "accept-routes": set(prefs.RouteAll) - case "host-routes": - set(prefs.AllowSingleHosts) case "accept-dns": set(prefs.CorpDNS) case "shields-up": diff --git a/cmd/tsconnect/wasm/wasm_js.go b/cmd/tsconnect/wasm/wasm_js.go index 0724af395..517c66b3c 100644 --- a/cmd/tsconnect/wasm/wasm_js.go +++ b/cmd/tsconnect/wasm/wasm_js.go @@ -298,11 +298,10 @@ func (i *jsIPN) run(jsCallbacks js.Value) { go func() { err := i.lb.Start(ipn.Options{ UpdatePrefs: &ipn.Prefs{ - ControlURL: i.controlURL, - RouteAll: false, - AllowSingleHosts: true, - WantRunning: true, - Hostname: i.hostname, + ControlURL: i.controlURL, + RouteAll: false, + WantRunning: true, + Hostname: i.hostname, }, AuthKey: i.authKey, }) diff --git a/ipn/ipn_clone.go b/ipn/ipn_clone.go index abbee9fa1..9457c50f0 100644 --- a/ipn/ipn_clone.go +++ b/ipn/ipn_clone.go @@ -40,7 +40,6 @@ func (src *Prefs) Clone() *Prefs { var _PrefsCloneNeedsRegeneration = Prefs(struct { ControlURL string RouteAll bool - AllowSingleHosts bool ExitNodeID tailcfg.StableNodeID ExitNodeIP netip.Addr InternalExitNodePrior tailcfg.StableNodeID @@ -67,6 +66,7 @@ var _PrefsCloneNeedsRegeneration = Prefs(struct { PostureChecking bool NetfilterKind string DriveShares []*drive.Share + AllowSingleHosts marshalAsTrueInJSON Persist *persist.Persist }{}) diff --git a/ipn/ipn_view.go b/ipn/ipn_view.go index 7d30f3571..ff48b9c89 100644 --- a/ipn/ipn_view.go +++ b/ipn/ipn_view.go @@ -67,7 +67,6 @@ func (v *PrefsView) UnmarshalJSON(b []byte) error { func (v PrefsView) ControlURL() string { return v.ж.ControlURL } func (v PrefsView) RouteAll() bool { return v.ж.RouteAll } -func (v PrefsView) AllowSingleHosts() bool { return v.ж.AllowSingleHosts } func (v PrefsView) ExitNodeID() tailcfg.StableNodeID { return v.ж.ExitNodeID } func (v PrefsView) ExitNodeIP() netip.Addr { return v.ж.ExitNodeIP } func (v PrefsView) InternalExitNodePrior() tailcfg.StableNodeID { return v.ж.InternalExitNodePrior } @@ -98,13 +97,13 @@ func (v PrefsView) NetfilterKind() string { return v.ж.Netfilte func (v PrefsView) DriveShares() views.SliceView[*drive.Share, drive.ShareView] { return views.SliceOfViews[*drive.Share, drive.ShareView](v.ж.DriveShares) } -func (v PrefsView) Persist() persist.PersistView { return v.ж.Persist.View() } +func (v PrefsView) AllowSingleHosts() marshalAsTrueInJSON { return v.ж.AllowSingleHosts } +func (v PrefsView) Persist() persist.PersistView { return v.ж.Persist.View() } // A compilation failure here means this code must be regenerated, with the command at the top of this file. var _PrefsViewNeedsRegeneration = Prefs(struct { ControlURL string RouteAll bool - AllowSingleHosts bool ExitNodeID tailcfg.StableNodeID ExitNodeIP netip.Addr InternalExitNodePrior tailcfg.StableNodeID @@ -131,6 +130,7 @@ var _PrefsViewNeedsRegeneration = Prefs(struct { PostureChecking bool NetfilterKind string DriveShares []*drive.Share + AllowSingleHosts marshalAsTrueInJSON Persist *persist.Persist }{}) diff --git a/ipn/ipnlocal/local.go b/ipn/ipnlocal/local.go index 88f1110d5..7e5384592 100644 --- a/ipn/ipnlocal/local.go +++ b/ipn/ipnlocal/local.go @@ -3649,9 +3649,6 @@ func (b *LocalBackend) authReconfig() { if prefs.RouteAll() { flags |= netmap.AllowSubnetRoutes } - if prefs.AllowSingleHosts() { - flags |= netmap.AllowSingleHosts - } if hasPAC && disableSubnetsIfPAC { if flags&netmap.AllowSubnetRoutes != 0 { b.logf("authReconfig: have PAC; disabling subnet routes") diff --git a/ipn/prefs.go b/ipn/prefs.go index 3a603ecf2..179b66e4b 100644 --- a/ipn/prefs.go +++ b/ipn/prefs.go @@ -75,18 +75,6 @@ type Prefs struct { // controlled by ExitNodeID/IP below. RouteAll bool - // AllowSingleHosts specifies whether to install routes for each - // node IP on the tailscale network, in addition to a route for - // the whole network. - // This corresponds to the "tailscale up --host-routes" value, - // which defaults to true. - // - // TODO(danderson): why do we have this? It dumps a lot of stuff - // into the routing table, and a single network route _should_ be - // all that we need. But when I turn this off in my tailscaled, - // packets stop flowing. What's up with that? - AllowSingleHosts bool - // ExitNodeID and ExitNodeIP specify the node that should be used // as an exit node for internet traffic. At most one of these // should be non-zero. @@ -252,6 +240,16 @@ type Prefs struct { // by name. DriveShares []*drive.Share + // AllowSingleHosts was a legacy field that was always true + // for the past 4.5 years. It controlled whether Tailscale + // peers got /32 or /127 routes for each other. + // As of 2024-05-17 we're starting to ignore it, but to let + // people still downgrade Tailscale versions and not break + // all peer-to-peer networking we still write it to disk (as JSON) + // so it can be loaded back by old versions. + // TODO(bradfitz): delete this in 2025 sometime. See #12058. + AllowSingleHosts marshalAsTrueInJSON + // The Persist field is named 'Config' in the file for backward // compatibility with earlier versions. // TODO(apenwarr): We should move this out of here, it's not a pref. @@ -282,6 +280,13 @@ func (au1 AutoUpdatePrefs) Equals(au2 AutoUpdatePrefs) bool { ok1 == ok2 } +type marshalAsTrueInJSON struct{} + +var trueJSON = []byte("true") + +func (marshalAsTrueInJSON) MarshalJSON() ([]byte, error) { return trueJSON, nil } +func (*marshalAsTrueInJSON) UnmarshalJSON([]byte) error { return nil } + // AppConnectorPrefs are the app connector settings for the node agent. type AppConnectorPrefs struct { // Advertise specifies whether the app connector subsystem is advertising @@ -299,7 +304,6 @@ type MaskedPrefs struct { ControlURLSet bool `json:",omitempty"` RouteAllSet bool `json:",omitempty"` - AllowSingleHostsSet bool `json:",omitempty"` ExitNodeIDSet bool `json:",omitempty"` ExitNodeIPSet bool `json:",omitempty"` InternalExitNodePriorSet bool `json:",omitempty"` // Internal; can't be set by LocalAPI clients @@ -484,9 +488,6 @@ func (p *Prefs) pretty(goos string) string { var sb strings.Builder sb.WriteString("Prefs{") fmt.Fprintf(&sb, "ra=%v ", p.RouteAll) - if !p.AllowSingleHosts { - sb.WriteString("mesh=false ") - } fmt.Fprintf(&sb, "dns=%v want=%v ", p.CorpDNS, p.WantRunning) if p.RunSSH { sb.WriteString("ssh=true ") @@ -579,7 +580,6 @@ func (p *Prefs) Equals(p2 *Prefs) bool { return p.ControlURL == p2.ControlURL && p.RouteAll == p2.RouteAll && - p.AllowSingleHosts == p2.AllowSingleHosts && p.ExitNodeID == p2.ExitNodeID && p.ExitNodeIP == p2.ExitNodeIP && p.InternalExitNodePrior == p2.InternalExitNodePrior && @@ -663,7 +663,6 @@ func NewPrefs() *Prefs { ControlURL: "", RouteAll: true, - AllowSingleHosts: true, CorpDNS: true, WantRunning: false, NetfilterMode: preftype.NetfilterOn, diff --git a/ipn/prefs_test.go b/ipn/prefs_test.go index 45f8829a6..65aa80d04 100644 --- a/ipn/prefs_test.go +++ b/ipn/prefs_test.go @@ -38,7 +38,6 @@ func TestPrefsEqual(t *testing.T) { prefsHandles := []string{ "ControlURL", "RouteAll", - "AllowSingleHosts", "ExitNodeID", "ExitNodeIP", "InternalExitNodePrior", @@ -65,6 +64,7 @@ func TestPrefsEqual(t *testing.T) { "PostureChecking", "NetfilterKind", "DriveShares", + "AllowSingleHosts", "Persist", } if have := fieldsOf(reflect.TypeFor[Prefs]()); !reflect.DeepEqual(have, prefsHandles) { @@ -123,18 +123,6 @@ func TestPrefsEqual(t *testing.T) { &Prefs{RouteAll: true}, true, }, - - { - &Prefs{AllowSingleHosts: true}, - &Prefs{AllowSingleHosts: false}, - false, - }, - { - &Prefs{AllowSingleHosts: true}, - &Prefs{AllowSingleHosts: true}, - true, - }, - { &Prefs{ExitNodeID: "n1234"}, &Prefs{}, @@ -376,7 +364,7 @@ func checkPrefs(t *testing.T, p Prefs) { p2b = new(Prefs) err = PrefsFromBytes(p2.ToBytes(), p2b) if err != nil { - t.Fatalf("PrefsFromBytes(p2) failed\n") + t.Fatalf("PrefsFromBytes(p2) failed: bytes=%q; err=%v\n", p2.ToBytes(), err) } p2p := p2.Pretty() p2bp := p2b.Pretty() @@ -427,46 +415,43 @@ func TestPrefsPretty(t *testing.T) { { Prefs{}, "linux", - "Prefs{ra=false mesh=false dns=false want=false routes=[] nf=off update=off Persist=nil}", + "Prefs{ra=false dns=false want=false routes=[] nf=off update=off Persist=nil}", }, { Prefs{}, "windows", - "Prefs{ra=false mesh=false dns=false want=false update=off Persist=nil}", + "Prefs{ra=false dns=false want=false update=off Persist=nil}", }, { Prefs{ShieldsUp: true}, "windows", - "Prefs{ra=false mesh=false dns=false want=false shields=true update=off Persist=nil}", + "Prefs{ra=false dns=false want=false shields=true update=off Persist=nil}", }, { - Prefs{AllowSingleHosts: true}, + Prefs{}, "windows", "Prefs{ra=false dns=false want=false update=off Persist=nil}", }, { Prefs{ - NotepadURLs: true, - AllowSingleHosts: true, + NotepadURLs: true, }, "windows", "Prefs{ra=false dns=false want=false notepad=true update=off Persist=nil}", }, { Prefs{ - AllowSingleHosts: true, - WantRunning: true, - ForceDaemon: true, // server mode + WantRunning: true, + ForceDaemon: true, // server mode }, "windows", "Prefs{ra=false dns=false want=true server=true update=off Persist=nil}", }, { Prefs{ - AllowSingleHosts: true, - WantRunning: true, - ControlURL: "http://localhost:1234", - AdvertiseTags: []string{"tag:foo", "tag:bar"}, + WantRunning: true, + ControlURL: "http://localhost:1234", + AdvertiseTags: []string{"tag:foo", "tag:bar"}, }, "darwin", `Prefs{ra=false dns=false want=true tags=tag:foo,tag:bar url="http://localhost:1234" update=off Persist=nil}`, @@ -476,7 +461,7 @@ func TestPrefsPretty(t *testing.T) { Persist: &persist.Persist{}, }, "linux", - `Prefs{ra=false mesh=false dns=false want=false routes=[] nf=off update=off Persist{lm=, o=, n= u=""}}`, + `Prefs{ra=false dns=false want=false routes=[] nf=off update=off Persist{lm=, o=, n= u=""}}`, }, { Prefs{ @@ -485,21 +470,21 @@ func TestPrefsPretty(t *testing.T) { }, }, "linux", - `Prefs{ra=false mesh=false dns=false want=false routes=[] nf=off update=off Persist{lm=, o=, n=[B1VKl] u=""}}`, + `Prefs{ra=false dns=false want=false routes=[] nf=off update=off Persist{lm=, o=, n=[B1VKl] u=""}}`, }, { Prefs{ ExitNodeIP: netip.MustParseAddr("1.2.3.4"), }, "linux", - `Prefs{ra=false mesh=false dns=false want=false exit=1.2.3.4 lan=false routes=[] nf=off update=off Persist=nil}`, + `Prefs{ra=false dns=false want=false exit=1.2.3.4 lan=false routes=[] nf=off update=off Persist=nil}`, }, { Prefs{ ExitNodeID: tailcfg.StableNodeID("myNodeABC"), }, "linux", - `Prefs{ra=false mesh=false dns=false want=false exit=myNodeABC lan=false routes=[] nf=off update=off Persist=nil}`, + `Prefs{ra=false dns=false want=false exit=myNodeABC lan=false routes=[] nf=off update=off Persist=nil}`, }, { Prefs{ @@ -507,21 +492,21 @@ func TestPrefsPretty(t *testing.T) { ExitNodeAllowLANAccess: true, }, "linux", - `Prefs{ra=false mesh=false dns=false want=false exit=myNodeABC lan=true routes=[] nf=off update=off Persist=nil}`, + `Prefs{ra=false dns=false want=false exit=myNodeABC lan=true routes=[] nf=off update=off Persist=nil}`, }, { Prefs{ ExitNodeAllowLANAccess: true, }, "linux", - `Prefs{ra=false mesh=false dns=false want=false routes=[] nf=off update=off Persist=nil}`, + `Prefs{ra=false dns=false want=false routes=[] nf=off update=off Persist=nil}`, }, { Prefs{ Hostname: "foo", }, "linux", - `Prefs{ra=false mesh=false dns=false want=false routes=[] nf=off host="foo" update=off Persist=nil}`, + `Prefs{ra=false dns=false want=false routes=[] nf=off host="foo" update=off Persist=nil}`, }, { Prefs{ @@ -531,7 +516,7 @@ func TestPrefsPretty(t *testing.T) { }, }, "linux", - `Prefs{ra=false mesh=false dns=false want=false routes=[] nf=off update=check Persist=nil}`, + `Prefs{ra=false dns=false want=false routes=[] nf=off update=check Persist=nil}`, }, { Prefs{ @@ -541,7 +526,7 @@ func TestPrefsPretty(t *testing.T) { }, }, "linux", - `Prefs{ra=false mesh=false dns=false want=false routes=[] nf=off update=on Persist=nil}`, + `Prefs{ra=false dns=false want=false routes=[] nf=off update=on Persist=nil}`, }, { Prefs{ @@ -550,7 +535,7 @@ func TestPrefsPretty(t *testing.T) { }, }, "linux", - `Prefs{ra=false mesh=false dns=false want=false routes=[] nf=off update=off appconnector=advertise Persist=nil}`, + `Prefs{ra=false dns=false want=false routes=[] nf=off update=off appconnector=advertise Persist=nil}`, }, { Prefs{ @@ -559,21 +544,21 @@ func TestPrefsPretty(t *testing.T) { }, }, "linux", - `Prefs{ra=false mesh=false dns=false want=false routes=[] nf=off update=off Persist=nil}`, + `Prefs{ra=false dns=false want=false routes=[] nf=off update=off Persist=nil}`, }, { Prefs{ NetfilterKind: "iptables", }, "linux", - `Prefs{ra=false mesh=false dns=false want=false routes=[] nf=off netfilterKind=iptables update=off Persist=nil}`, + `Prefs{ra=false dns=false want=false routes=[] nf=off netfilterKind=iptables update=off Persist=nil}`, }, { Prefs{ NetfilterKind: "", }, "linux", - `Prefs{ra=false mesh=false dns=false want=false routes=[] nf=off update=off Persist=nil}`, + `Prefs{ra=false dns=false want=false routes=[] nf=off update=off Persist=nil}`, }, } for i, tt := range tests { @@ -633,8 +618,9 @@ func TestMaskedPrefsSetsInternal(t *testing.T) { func TestMaskedPrefsFields(t *testing.T) { have := map[string]bool{} for _, f := range fieldsOf(reflect.TypeFor[Prefs]()) { - if f == "Persist" { - // This one can't be edited. + switch f { + case "Persist", "AllowSingleHosts": + // These can't be edited. continue } have[f] = true @@ -753,13 +739,12 @@ func TestMaskedPrefsPretty(t *testing.T) { { m: &MaskedPrefs{ Prefs: Prefs{ - Hostname: "bar", - OperatorUser: "galaxybrain", - AllowSingleHosts: true, - RouteAll: false, - ExitNodeID: "foo", - AdvertiseTags: []string{"tag:foo", "tag:bar"}, - NetfilterMode: preftype.NetfilterNoDivert, + Hostname: "bar", + OperatorUser: "galaxybrain", + RouteAll: false, + ExitNodeID: "foo", + AdvertiseTags: []string{"tag:foo", "tag:bar"}, + NetfilterMode: preftype.NetfilterNoDivert, }, RouteAllSet: true, HostnameSet: true, @@ -1064,3 +1049,24 @@ func TestNotifyPrefsJSONRoundtrip(t *testing.T) { t.Fatal("Prefs should not be valid after deserialization") } } + +// Verify that our Prefs type writes out an AllowSingleHosts field so we can +// downgrade to older versions that require it. +func TestPrefsDowngrade(t *testing.T) { + var p Prefs + j, err := json.Marshal(p) + if err != nil { + t.Fatal(err) + } + + type oldPrefs struct { + AllowSingleHosts bool + } + var op oldPrefs + if err := json.Unmarshal(j, &op); err != nil { + t.Fatal(err) + } + if !op.AllowSingleHosts { + t.Fatal("AllowSingleHosts should be true") + } +} diff --git a/types/netmap/netmap.go b/types/netmap/netmap.go index 13806b5a8..79459a6b5 100644 --- a/types/netmap/netmap.go +++ b/types/netmap/netmap.go @@ -388,6 +388,6 @@ func (nm *NetworkMap) JSON() string { type WGConfigFlags int const ( - AllowSingleHosts WGConfigFlags = 1 << iota + _ WGConfigFlags = 1 << iota AllowSubnetRoutes ) diff --git a/wgengine/magicsock/magicsock_test.go b/wgengine/magicsock/magicsock_test.go index b4477cce6..2df05fcb0 100644 --- a/wgengine/magicsock/magicsock_test.go +++ b/wgengine/magicsock/magicsock_test.go @@ -331,7 +331,7 @@ func meshStacks(logf logger.Logf, mutateNetmap func(idx int, nm *netmap.NetworkM peerSet.Add(peer.Key()) } m.conn.UpdatePeers(peerSet) - wg, err := nmcfg.WGCfg(nm, logf, netmap.AllowSingleHosts, "") + wg, err := nmcfg.WGCfg(nm, logf, 0, "") if err != nil { // We're too far from the *testing.T to be graceful, // blow up. Shouldn't happen anyway. @@ -2354,7 +2354,7 @@ func TestIsWireGuardOnlyPeer(t *testing.T) { } m.conn.SetNetworkMap(nm) - cfg, err := nmcfg.WGCfg(nm, t.Logf, netmap.AllowSingleHosts|netmap.AllowSubnetRoutes, "") + cfg, err := nmcfg.WGCfg(nm, t.Logf, netmap.AllowSubnetRoutes, "") if err != nil { t.Fatal(err) } @@ -2416,7 +2416,7 @@ func TestIsWireGuardOnlyPeerWithMasquerade(t *testing.T) { } m.conn.SetNetworkMap(nm) - cfg, err := nmcfg.WGCfg(nm, t.Logf, netmap.AllowSingleHosts|netmap.AllowSubnetRoutes, "") + cfg, err := nmcfg.WGCfg(nm, t.Logf, netmap.AllowSubnetRoutes, "") if err != nil { t.Fatal(err) } @@ -2456,7 +2456,7 @@ func applyNetworkMap(t *testing.T, m *magicStack, nm *netmap.NetworkMap) { m.conn.noV6.Store(true) // Turn the network map into a wireguard config (for the tailscale internal wireguard device). - cfg, err := nmcfg.WGCfg(nm, t.Logf, netmap.AllowSingleHosts|netmap.AllowSubnetRoutes, "") + cfg, err := nmcfg.WGCfg(nm, t.Logf, netmap.AllowSubnetRoutes, "") if err != nil { t.Fatal(err) } diff --git a/wgengine/wgcfg/nmcfg/nmcfg.go b/wgengine/wgcfg/nmcfg/nmcfg.go index eb15b340e..d156f7fcb 100644 --- a/wgengine/wgcfg/nmcfg/nmcfg.go +++ b/wgengine/wgcfg/nmcfg/nmcfg.go @@ -10,7 +10,6 @@ import ( "net/netip" "strings" - "tailscale.com/net/tsaddr" "tailscale.com/tailcfg" "tailscale.com/types/logger" "tailscale.com/types/logid" @@ -124,12 +123,6 @@ func WGCfg(nm *netmap.NetworkMap, logf logger.Logf, flags netmap.WGConfigFlags, } fmt.Fprintf(skippedUnselected, "%q (%v)", nodeDebugName(peer), peer.Key().ShortString()) continue - } else if allowedIP.IsSingleIP() && tsaddr.IsTailscaleIP(allowedIP.Addr()) && (flags&netmap.AllowSingleHosts) == 0 { - if skippedIPs.Len() > 0 { - skippedIPs.WriteString(", ") - } - fmt.Fprintf(skippedIPs, "%v from %q (%v)", allowedIP.Addr(), nodeDebugName(peer), peer.Key().ShortString()) - continue } else if cidrIsSubnet(peer, allowedIP) { if (flags & netmap.AllowSubnetRoutes) == 0 { if skippedSubnets.Len() > 0 {