Compare commits
3 Commits
main
...
raggi/acce
Author | SHA1 | Date |
---|---|---|
![]() |
919ad7df82 | |
![]() |
627c60b0d1 | |
![]() |
2d0ecbb883 |
|
@ -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")
|
||||
|
|
|
@ -35,6 +35,7 @@ func (src *Prefs) Clone() *Prefs {
|
|||
var _PrefsCloneNeedsRegeneration = Prefs(struct {
|
||||
ControlURL string
|
||||
RouteAll bool
|
||||
AcceptRoutesFilter string
|
||||
AllowSingleHosts bool
|
||||
ExitNodeID tailcfg.StableNodeID
|
||||
ExitNodeIP netip.Addr
|
||||
|
|
|
@ -2775,18 +2775,42 @@ func ipPrefixLess(ri, rj netip.Prefix) bool {
|
|||
return ri.Addr().Less(rj.Addr())
|
||||
}
|
||||
|
||||
func (b *LocalBackend) filterRoutes(routes []netip.Prefix, acceptFilter *netipx.IPSet) []netip.Prefix {
|
||||
if acceptFilter == nil {
|
||||
return routes
|
||||
}
|
||||
var builder netipx.IPSetBuilder
|
||||
for _, r := range routes {
|
||||
builder.AddPrefix(r)
|
||||
}
|
||||
builder.Intersect(acceptFilter)
|
||||
set, err := builder.IPSet()
|
||||
if err != nil {
|
||||
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()
|
||||
}
|
||||
|
||||
// routerConfig produces a router.Config from a wireguard config and IPN prefs.
|
||||
func (b *LocalBackend) routerConfig(cfg *wgcfg.Config, prefs *ipn.Prefs, oneCGNATRoute bool) *router.Config {
|
||||
singleRouteThreshold := 10_000
|
||||
if oneCGNATRoute {
|
||||
singleRouteThreshold = 1
|
||||
}
|
||||
|
||||
acceptRoutesFilterSet, err := ipn.ParseAcceptRoutesFilter(prefs.AcceptRoutesFilter)
|
||||
if err != nil {
|
||||
b.logf("accept routes filter: failed to build filter set from %q: %v", prefs.AcceptRoutesFilter, err)
|
||||
}
|
||||
|
||||
rs := &router.Config{
|
||||
LocalAddrs: unmapIPPrefixes(cfg.Addresses),
|
||||
SubnetRoutes: unmapIPPrefixes(prefs.AdvertiseRoutes),
|
||||
SNATSubnetRoutes: !prefs.NoSNAT,
|
||||
NetfilterMode: prefs.NetfilterMode,
|
||||
Routes: peerRoutes(cfg.Peers, singleRouteThreshold),
|
||||
Routes: b.filterRoutes(peerRoutes(cfg.Peers, singleRouteThreshold), acceptRoutesFilterSet),
|
||||
}
|
||||
|
||||
if distro.Get() == distro.Synology {
|
||||
|
|
49
ipn/prefs.go
49
ipn/prefs.go
|
@ -17,6 +17,7 @@ import (
|
|||
"runtime"
|
||||
"strings"
|
||||
|
||||
"go4.org/netipx"
|
||||
"tailscale.com/atomicfile"
|
||||
"tailscale.com/ipn/ipnstate"
|
||||
"tailscale.com/net/netaddr"
|
||||
|
@ -70,6 +71,13 @@ type Prefs struct {
|
|||
// controlled by ExitNodeID/IP below.
|
||||
RouteAll bool
|
||||
|
||||
// AcceptRoutesFilter specifies an ordered list of IP ranges that are to be
|
||||
// included or excluded from peer routes. The value is comma-seprated IP CIDRs
|
||||
// with an optional leading `-` prefix indicating an exclusion, e.g.
|
||||
// "0.0.0.0/0,-192.168.20.0/24" meaning "all routes except those intersecting
|
||||
// 192.168.20.0/24".
|
||||
AcceptRoutesFilter string
|
||||
|
||||
// AllowSingleHosts specifies whether to install routes for each
|
||||
// node IP on the tailscale network, in addition to a route for
|
||||
// the whole network.
|
||||
|
@ -206,6 +214,7 @@ type MaskedPrefs struct {
|
|||
|
||||
ControlURLSet bool `json:",omitempty"`
|
||||
RouteAllSet bool `json:",omitempty"`
|
||||
AcceptRoutesFilterSet bool `json:",omitempty"`
|
||||
AllowSingleHostsSet bool `json:",omitempty"`
|
||||
ExitNodeIDSet bool `json:",omitempty"`
|
||||
ExitNodeIPSet bool `json:",omitempty"`
|
||||
|
@ -293,6 +302,9 @@ func (p *Prefs) pretty(goos string) string {
|
|||
var sb strings.Builder
|
||||
sb.WriteString("Prefs{")
|
||||
fmt.Fprintf(&sb, "ra=%v ", p.RouteAll)
|
||||
if p.RouteAll || p.AcceptRoutesFilter != "" {
|
||||
fmt.Fprintf(&sb, "acceptfilter=%q ", p.AcceptRoutesFilter)
|
||||
}
|
||||
if !p.AllowSingleHosts {
|
||||
sb.WriteString("mesh=false ")
|
||||
}
|
||||
|
@ -366,6 +378,7 @@ func (p *Prefs) Equals(p2 *Prefs) bool {
|
|||
return p != nil && p2 != nil &&
|
||||
p.ControlURL == p2.ControlURL &&
|
||||
p.RouteAll == p2.RouteAll &&
|
||||
p.AcceptRoutesFilter == p2.AcceptRoutesFilter &&
|
||||
p.AllowSingleHosts == p2.AllowSingleHosts &&
|
||||
p.ExitNodeID == p2.ExitNodeID &&
|
||||
p.ExitNodeIP == p2.ExitNodeIP &&
|
||||
|
@ -423,11 +436,12 @@ func NewPrefs() *Prefs {
|
|||
// later anyway.
|
||||
ControlURL: "",
|
||||
|
||||
RouteAll: true,
|
||||
AllowSingleHosts: true,
|
||||
CorpDNS: true,
|
||||
WantRunning: false,
|
||||
NetfilterMode: preftype.NetfilterOn,
|
||||
RouteAll: true,
|
||||
AcceptRoutesFilter: "0.0.0.0/0,::/0",
|
||||
AllowSingleHosts: true,
|
||||
CorpDNS: true,
|
||||
WantRunning: false,
|
||||
NetfilterMode: preftype.NetfilterOn,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -644,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()
|
||||
}
|
||||
|
|
|
@ -38,6 +38,7 @@ func TestPrefsEqual(t *testing.T) {
|
|||
prefsHandles := []string{
|
||||
"ControlURL",
|
||||
"RouteAll",
|
||||
"AcceptRoutesFilter",
|
||||
"AllowSingleHosts",
|
||||
"ExitNodeID",
|
||||
"ExitNodeIP",
|
||||
|
|
Loading…
Reference in New Issue