|
|
|
|
@ -32,10 +32,12 @@ import ( |
|
|
|
|
"tailscale.com/ipn" |
|
|
|
|
"tailscale.com/ipn/ipnstate" |
|
|
|
|
"tailscale.com/net/netutil" |
|
|
|
|
"tailscale.com/net/tsaddr" |
|
|
|
|
"tailscale.com/safesocket" |
|
|
|
|
"tailscale.com/tailcfg" |
|
|
|
|
"tailscale.com/types/logger" |
|
|
|
|
"tailscale.com/types/preftype" |
|
|
|
|
"tailscale.com/types/views" |
|
|
|
|
"tailscale.com/util/dnsname" |
|
|
|
|
"tailscale.com/version" |
|
|
|
|
"tailscale.com/version/distro" |
|
|
|
|
@ -1015,7 +1017,7 @@ func prefsToFlags(env upCheckEnv, prefs *ipn.Prefs) (flagVal map[string]any) { |
|
|
|
|
set(prefs.OperatorUser) |
|
|
|
|
case "advertise-routes": |
|
|
|
|
var sb strings.Builder |
|
|
|
|
for i, r := range withoutExitNodes(prefs.AdvertiseRoutes) { |
|
|
|
|
for i, r := range tsaddr.WithoutExitRoutes(views.SliceOf(prefs.AdvertiseRoutes)).All() { |
|
|
|
|
if i > 0 { |
|
|
|
|
sb.WriteByte(',') |
|
|
|
|
} |
|
|
|
|
@ -1023,7 +1025,7 @@ func prefsToFlags(env upCheckEnv, prefs *ipn.Prefs) (flagVal map[string]any) { |
|
|
|
|
} |
|
|
|
|
set(sb.String()) |
|
|
|
|
case "advertise-exit-node": |
|
|
|
|
set(hasExitNodeRoutes(prefs.AdvertiseRoutes)) |
|
|
|
|
set(tsaddr.ContainsExitRoutes(views.SliceOf(prefs.AdvertiseRoutes))) |
|
|
|
|
case "advertise-connector": |
|
|
|
|
set(prefs.AppConnector.Advertise) |
|
|
|
|
case "snat-subnet-routes": |
|
|
|
|
@ -1057,36 +1059,6 @@ func fmtFlagValueArg(flagName string, val any) string { |
|
|
|
|
return fmt.Sprintf("--%s=%v", flagName, shellquote.Join(fmt.Sprint(val))) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func hasExitNodeRoutes(rr []netip.Prefix) bool { |
|
|
|
|
var v4, v6 bool |
|
|
|
|
for _, r := range rr { |
|
|
|
|
if r.Bits() == 0 { |
|
|
|
|
if r.Addr().Is4() { |
|
|
|
|
v4 = true |
|
|
|
|
} else if r.Addr().Is6() { |
|
|
|
|
v6 = true |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return v4 && v6 |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// withoutExitNodes returns rr unchanged if it has only 1 or 0 /0
|
|
|
|
|
// routes. If it has both IPv4 and IPv6 /0 routes, then it returns
|
|
|
|
|
// a copy with all /0 routes removed.
|
|
|
|
|
func withoutExitNodes(rr []netip.Prefix) []netip.Prefix { |
|
|
|
|
if !hasExitNodeRoutes(rr) { |
|
|
|
|
return rr |
|
|
|
|
} |
|
|
|
|
var out []netip.Prefix |
|
|
|
|
for _, r := range rr { |
|
|
|
|
if r.Bits() > 0 { |
|
|
|
|
out = append(out, r) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return out |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// exitNodeIP returns the exit node IP from p, using st to map
|
|
|
|
|
// it from its ID form to an IP address if needed.
|
|
|
|
|
func exitNodeIP(p *ipn.Prefs, st *ipnstate.Status) (ip netip.Addr) { |
|
|
|
|
|