ipn,ipn/local: always accept routes for Tailscale Services (cgnat range)

Updates #18198

Co-authored-by: James Tucker <raggi@tailscale.com>
Signed-off-by: chaosinthecrd <tom@tmlabs.co.uk>
chaosinthecrd 2 months ago
parent 8ea90ba80d
commit e9a47f3c04
No known key found for this signature in database
GPG Key ID: 52ED56820AF046EE

@ -5051,7 +5051,6 @@ func (b *LocalBackend) authReconfig() {
//
// b.mu must be held.
func (b *LocalBackend) authReconfigLocked() {
if b.shutdownCalled {
b.logf("[v1] authReconfig: skipping because in shutdown")
return
@ -5083,9 +5082,9 @@ func (b *LocalBackend) authReconfigLocked() {
}
var flags netmap.WGConfigFlags
if prefs.RouteAll() {
flags |= netmap.AllowSubnetRoutes
}
// NOTE: we want to always allow subnet routes for the sake of enabling services
flags |= netmap.AllowSubnetRoutes
if hasPAC && disableSubnetsIfPAC {
if flags&netmap.AllowSubnetRoutes != 0 {
b.logf("authReconfig: have PAC; disabling subnet routes")
@ -5429,6 +5428,34 @@ func peerRoutes(logf logger.Logf, peers []wgcfg.Peer, cgnatThreshold int) (route
return routes
}
func (b *LocalBackend) servicesRoutes(routes []netip.Prefix) []netip.Prefix {
var servicesRangeBuilder netipx.IPSetBuilder
servicesRangeBuilder.AddPrefix(tsaddr.CGNATRange())
servicesRangeBuilder.AddPrefix(tsaddr.TailscaleULARange())
services, err := servicesRangeBuilder.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
}
var builder netipx.IPSetBuilder
for _, r := range routes {
builder.AddPrefix(r)
}
builder.Intersect(services)
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.
//
// b.mu must be held.
@ -5455,13 +5482,20 @@ func (b *LocalBackend) routerConfigLocked(cfg *wgcfg.Config, prefs ipn.PrefsView
doStatefulFiltering = true
}
var routes []netip.Prefix
if prefs.RouteAll() {
routes = peerRoutes(b.logf, cfg.Peers, singleRouteThreshold)
} else {
routes = b.servicesRoutes(peerRoutes(b.logf, cfg.Peers, singleRouteThreshold))
}
rs := &router.Config{
LocalAddrs: unmapIPPrefixes(cfg.Addresses),
SubnetRoutes: unmapIPPrefixes(prefs.AdvertiseRoutes().AsSlice()),
SNATSubnetRoutes: !prefs.NoSNAT(),
StatefulFiltering: doStatefulFiltering,
NetfilterMode: prefs.NetfilterMode(),
Routes: peerRoutes(b.logf, cfg.Peers, singleRouteThreshold),
Routes: routes,
NetfilterKind: netfilterKind,
}
@ -7774,9 +7808,7 @@ func maybeUsernameOf(actor ipnauth.Actor) string {
return username
}
var (
metricCurrentWatchIPNBus = clientmetric.NewGauge("localbackend_current_watch_ipn_bus")
)
var metricCurrentWatchIPNBus = clientmetric.NewGauge("localbackend_current_watch_ipn_bus")
func (b *LocalBackend) stateEncrypted() opt.Bool {
switch runtime.GOOS {

@ -7295,3 +7295,102 @@ func TestStripKeysFromPrefs(t *testing.T) {
})
}
}
func TestRouteAllDisabled(t *testing.T) {
pp := netip.MustParsePrefix
tests := []struct {
name string
peers []wgcfg.Peer
wantEndpoints []netip.Prefix
routeAll bool
}{
{
name: "route_all_disabled",
routeAll: false,
peers: []wgcfg.Peer{
{
AllowedIPs: []netip.Prefix{
// if one ip in the Tailscale ULA range is added, the entire range is added to the router config
pp("fd7a:115c:a1e0::2501:9b83/128"),
pp("100.80.207.38/32"),
pp("100.80.207.56/32"),
pp("100.80.207.40/32"),
pp("100.94.122.93/32"),
pp("100.79.141.115/32"),
// ips outside the tailscale cgnat/ula range are not added to the router config
pp("192.168.0.45/32"),
pp("fd7a:115c:b1e0::2501:9b83/128"),
pp("fdf8:f966:e27c:0:5:0:0:10/128"),
},
},
},
wantEndpoints: []netip.Prefix{
pp("100.80.207.38/32"),
pp("100.80.207.56/32"),
pp("100.80.207.40/32"),
pp("100.94.122.93/32"),
pp("100.79.141.115/32"),
pp("fd7a:115c:a1e0::/48"),
},
},
{
name: "route_all_enabled",
routeAll: true,
peers: []wgcfg.Peer{
{
AllowedIPs: []netip.Prefix{
// if one ip in the Tailscale ULA range is added, the entire range is added to the router config
pp("fd7a:115c:a1e0::2501:9b83/128"),
pp("100.80.207.38/32"),
pp("100.80.207.56/32"),
pp("100.80.207.40/32"),
pp("100.94.122.93/32"),
pp("100.79.141.115/32"),
// ips outside the tailscale cgnat/ula range are not added to the router config
pp("192.168.0.45/32"),
pp("fd7a:115c:b1e0::2501:9b83/128"),
pp("fdf8:f966:e27c:0:5:0:0:10/128"),
},
},
},
wantEndpoints: []netip.Prefix{
pp("100.80.207.38/32"),
pp("100.80.207.56/32"),
pp("100.80.207.40/32"),
pp("100.94.122.93/32"),
pp("100.79.141.115/32"),
pp("192.168.0.45/32"),
pp("fd7a:115c:a1e0::/48"),
pp("fd7a:115c:b1e0::2501:9b83/128"),
pp("fdf8:f966:e27c:0:5:0:0:10/128"),
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
prefs := ipn.Prefs{RouteAll: tt.routeAll}
lb := newTestLocalBackend(t)
cfg := &wgcfg.Config{
Peers: tt.peers,
}
rcfg := lb.routerConfigLocked(cfg, prefs.View(), false)
for _, p := range rcfg.Routes {
found := false
for _, r := range tt.wantEndpoints {
if p.Addr() == r.Addr() {
found = true
break
}
}
if !found {
t.Errorf("unexpected prefix %q in router config", p.String())
}
}
})
}
}

@ -13,6 +13,7 @@ import (
"strings"
"time"
"tailscale.com/net/tsaddr"
"tailscale.com/tailcfg"
"tailscale.com/tka"
"tailscale.com/types/key"
@ -154,8 +155,11 @@ func (nm *NetworkMap) SelfNodeOrZero() tailcfg.NodeView {
// AnyPeersAdvertiseRoutes reports whether any peer is advertising non-exit node routes.
func (nm *NetworkMap) AnyPeersAdvertiseRoutes() bool {
for _, p := range nm.Peers {
if p.PrimaryRoutes().Len() > 0 {
return true
// NOTE: (ChaosInTheCRD) if the peer being advertised is a tailscale ip, we ignore it in this check
for _, r := range p.PrimaryRoutes().AsSlice() {
if !tsaddr.IsTailscaleIP(r.Addr()) {
return true
}
}
}
return false

Loading…
Cancel
Save