diff --git a/cmd/tailscale/cli/up.go b/cmd/tailscale/cli/up.go index d93058956..d98c9fb3a 100644 --- a/cmd/tailscale/cli/up.go +++ b/cmd/tailscale/cli/up.go @@ -69,14 +69,17 @@ func effectiveGOOS() string { // acceptRouteDefault returns the CLI's default value of --accept-routes as // a function of the platform it's running on. -func acceptRouteDefault(goos string) bool { +func acceptRouteDefault(goos string) string { switch goos { case "windows": - return true + return "true" case "darwin": - return version.IsSandboxedMacOS() + if version.IsSandboxedMacOS() { + return "true" + } + return "false" default: - return false + return "false" } } @@ -93,7 +96,7 @@ func newUpFlagSet(goos string, upArgs *upArgsT) *flag.FlagSet { upf.BoolVar(&upArgs.reset, "reset", false, "reset unspecified settings to their default values") 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.StringVar(&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, "install host routes to other Tailscale nodes") 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") @@ -131,7 +134,7 @@ type upArgsT struct { qr bool reset bool server string - acceptRoutes bool + acceptRoutes string acceptDNS bool singleRoutes bool exitNodeIP string @@ -307,7 +310,25 @@ func prefsFromUpArgs(upArgs upArgsT, warnf logger.Logf, st *ipnstate.Status, goo prefs := ipn.NewPrefs() prefs.ControlURL = upArgs.server prefs.WantRunning = true - prefs.RouteAll = upArgs.acceptRoutes + + switch upArgs.acceptRoutes { + case "0", "f", "false": + prefs.RouteAll = false + case "1", "t", "true": + prefs.RouteAll = true + default: + prefs.RouteAll = true + prefs.AcceptRoutesFilter = upArgs.acceptRoutes + + // accept-routes accepts an include/exclude ip range of the form: + // 0.0.0.0/0,-192.168.20.0/24 + // Ensure that the provided values parse correctly, as the backend can only + // bury errors in the logs. + _, err := ipn.ParseAcceptRoutesFilter(prefs.AcceptRoutesFilter) + if err != nil { + return nil, fmt.Errorf("accept-routes filter %q did not parse: %w", prefs.AcceptRoutesFilter, err) + } + } if upArgs.exitNodeIP != "" { if err := prefs.SetExitNodeIP(upArgs.exitNodeIP, st); err != nil { @@ -453,7 +474,7 @@ func runUp(ctx context.Context, args []string) (retErr error) { if distro.Get() == distro.Synology { notSupported := "not supported on Synology; see https://github.com/tailscale/tailscale/issues/1995" - if upArgs.acceptRoutes { + if upArgs.acceptRoutes != "" && upArgs.acceptRoutes != "f" && upArgs.acceptRoutes != "false" { return errors.New("--accept-routes is " + notSupported) } if upArgs.exitNodeIP != "" { @@ -735,10 +756,10 @@ func init() { // And this flag has two ipn.Prefs: addPrefFlagMapping("exit-node", "ExitNodeIP", "ExitNodeID") + addPrefFlagMapping("accept-routes", "RouteAll", "AcceptRoutesFilter") // The rest are 1:1: addPrefFlagMapping("accept-dns", "CorpDNS") - addPrefFlagMapping("accept-routes", "RouteAll") addPrefFlagMapping("advertise-tags", "AdvertiseTags") addPrefFlagMapping("host-routes", "AllowSingleHosts") addPrefFlagMapping("hostname", "Hostname") diff --git a/ipn/ipnlocal/local.go b/ipn/ipnlocal/local.go index 7f130f2db..03c25d52e 100644 --- a/ipn/ipnlocal/local.go +++ b/ipn/ipnlocal/local.go @@ -2775,32 +2775,6 @@ func ipPrefixLess(ri, rj netip.Prefix) bool { return ri.Addr().Less(rj.Addr()) } -func (b *LocalBackend) parseAcceptRoutesFilter(acceptFilter string) (*netipx.IPSet, error) { - var acceptFilterBuilder netipx.IPSetBuilder - for _, af := range strings.Split(acceptFilter, ",") { - af = strings.TrimSpace(af) - if af == "" { - continue - } - includeRange := true - if strings.HasPrefix(af, "-") { - includeRange = false - af = af[1:] - } - pfx, err := netip.ParsePrefix(af) - if err != nil { - b.logf("accept routes filter: invalid prefix %q will be ignored: %v (check accept-routes flag)", af, err) - continue - } - if includeRange { - acceptFilterBuilder.AddPrefix(pfx) - } else { - acceptFilterBuilder.RemovePrefix(pfx) - } - } - return acceptFilterBuilder.IPSet() -} - func (b *LocalBackend) filterRoutes(routes []netip.Prefix, acceptFilter *netipx.IPSet) []netip.Prefix { if acceptFilter == nil { return routes @@ -2815,6 +2789,7 @@ func (b *LocalBackend) filterRoutes(routes []netip.Prefix, acceptFilter *netipx. b.logf("accept routes filter: failed to build filtered set, all routes will be accepted: %v (check accept-routes flag)", err) return routes } + b.logf("accept routes filter: accepting routes: %v", set.Ranges()) return set.Prefixes() } @@ -2825,9 +2800,9 @@ func (b *LocalBackend) routerConfig(cfg *wgcfg.Config, prefs *ipn.Prefs, oneCGNA singleRouteThreshold = 1 } - acceptRoutesFilterSet, err := b.parseAcceptRoutesFilter(prefs.AcceptRoutesFilter) + acceptRoutesFilterSet, err := ipn.ParseAcceptRoutesFilter(prefs.AcceptRoutesFilter) if err != nil { - b.logf("accept routes filter: failed to build filter set: %v", err) + b.logf("accept routes filter: failed to build filter set from %q: %v", prefs.AcceptRoutesFilter, err) } rs := &router.Config{ diff --git a/ipn/prefs.go b/ipn/prefs.go index 49c1a236c..aaf369dda 100644 --- a/ipn/prefs.go +++ b/ipn/prefs.go @@ -17,6 +17,7 @@ import ( "runtime" "strings" + "go4.org/netipx" "tailscale.com/atomicfile" "tailscale.com/ipn/ipnstate" "tailscale.com/net/netaddr" @@ -657,3 +658,28 @@ func SavePrefs(filename string, p *Prefs) { log.Printf("SavePrefs: %v\n", err) } } + +func ParseAcceptRoutesFilter(acceptFilter string) (*netipx.IPSet, error) { + var acceptFilterBuilder netipx.IPSetBuilder + for _, af := range strings.Split(acceptFilter, ",") { + af = strings.TrimSpace(af) + if af == "" { + continue + } + includeRange := true + if strings.HasPrefix(af, "-") { + includeRange = false + af = af[1:] + } + pfx, err := netip.ParsePrefix(af) + if err != nil { + return nil, err + } + if includeRange { + acceptFilterBuilder.AddPrefix(pfx) + } else { + acceptFilterBuilder.RemovePrefix(pfx) + } + } + return acceptFilterBuilder.IPSet() +}