|
|
@ -32,10 +32,12 @@ import (
|
|
|
|
"tailscale.com/ipn"
|
|
|
|
"tailscale.com/ipn"
|
|
|
|
"tailscale.com/ipn/ipnstate"
|
|
|
|
"tailscale.com/ipn/ipnstate"
|
|
|
|
"tailscale.com/net/netutil"
|
|
|
|
"tailscale.com/net/netutil"
|
|
|
|
|
|
|
|
"tailscale.com/net/tsaddr"
|
|
|
|
"tailscale.com/safesocket"
|
|
|
|
"tailscale.com/safesocket"
|
|
|
|
"tailscale.com/tailcfg"
|
|
|
|
"tailscale.com/tailcfg"
|
|
|
|
"tailscale.com/types/logger"
|
|
|
|
"tailscale.com/types/logger"
|
|
|
|
"tailscale.com/types/preftype"
|
|
|
|
"tailscale.com/types/preftype"
|
|
|
|
|
|
|
|
"tailscale.com/types/views"
|
|
|
|
"tailscale.com/util/dnsname"
|
|
|
|
"tailscale.com/util/dnsname"
|
|
|
|
"tailscale.com/version"
|
|
|
|
"tailscale.com/version"
|
|
|
|
"tailscale.com/version/distro"
|
|
|
|
"tailscale.com/version/distro"
|
|
|
@ -1015,7 +1017,7 @@ func prefsToFlags(env upCheckEnv, prefs *ipn.Prefs) (flagVal map[string]any) {
|
|
|
|
set(prefs.OperatorUser)
|
|
|
|
set(prefs.OperatorUser)
|
|
|
|
case "advertise-routes":
|
|
|
|
case "advertise-routes":
|
|
|
|
var sb strings.Builder
|
|
|
|
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 {
|
|
|
|
if i > 0 {
|
|
|
|
sb.WriteByte(',')
|
|
|
|
sb.WriteByte(',')
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -1023,7 +1025,7 @@ func prefsToFlags(env upCheckEnv, prefs *ipn.Prefs) (flagVal map[string]any) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
set(sb.String())
|
|
|
|
set(sb.String())
|
|
|
|
case "advertise-exit-node":
|
|
|
|
case "advertise-exit-node":
|
|
|
|
set(hasExitNodeRoutes(prefs.AdvertiseRoutes))
|
|
|
|
set(tsaddr.ContainsExitRoutes(views.SliceOf(prefs.AdvertiseRoutes)))
|
|
|
|
case "advertise-connector":
|
|
|
|
case "advertise-connector":
|
|
|
|
set(prefs.AppConnector.Advertise)
|
|
|
|
set(prefs.AppConnector.Advertise)
|
|
|
|
case "snat-subnet-routes":
|
|
|
|
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)))
|
|
|
|
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
|
|
|
|
// exitNodeIP returns the exit node IP from p, using st to map
|
|
|
|
// it from its ID form to an IP address if needed.
|
|
|
|
// it from its ID form to an IP address if needed.
|
|
|
|
func exitNodeIP(p *ipn.Prefs, st *ipnstate.Status) (ip netip.Addr) {
|
|
|
|
func exitNodeIP(p *ipn.Prefs, st *ipnstate.Status) (ip netip.Addr) {
|
|
|
|