diff --git a/cmd/tailscale/cli/cli_test.go b/cmd/tailscale/cli/cli_test.go index c497076125890..9c87ec33f8728 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 16b28233ed193..602e1f1ab31bf 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 0724af395c691..517c66b3ca0c8 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 abbee9fa17d9a..9457c50f0d9a1 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 7d30f3571deb3..ff48b9c8975f9 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 88f1110d5fa48..7e538459255c4 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 3a603ecf26754..179b66e4b8c39 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 45f8829a6d95e..65aa80d04644b 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 13806b5a852d4..79459a6b5105e 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 b4477cce602ce..2df05fcb0e961 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 eb15b340ec691..d156f7fcb0ef2 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 {