diff --git a/ipn/ipnlocal/local.go b/ipn/ipnlocal/local.go index 7856dc490..7f130f2db 100644 --- a/ipn/ipnlocal/local.go +++ b/ipn/ipnlocal/local.go @@ -2775,18 +2775,67 @@ 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 + } + 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 + } + 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 := b.parseAcceptRoutesFilter(prefs.AcceptRoutesFilter) + if err != nil { + b.logf("accept routes filter: failed to build filter set: %v", 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 {