From 6364b5f1e0f643cabefec3534e3b4e5b5847ae3b Mon Sep 17 00:00:00 2001 From: James Tucker Date: Fri, 10 Jan 2025 14:17:16 -0800 Subject: [PATCH] net/netmon: trim IPv6 endpoints in already routable subnets We have observed some clients with extremely large lists of IPv6 endpoints, in some cases from subnets where the machine also has the zero address for a whole /48 with then arbitrary addresses additionally assigned within that /48. It is in general unnecessary for reachability to report all of these addresses, typically only one will be necessary for reachability. We report two, to cover some other common cases such as some styles of IPv6 private address rotations. Updates tailscale/corp#25850 Signed-off-by: James Tucker --- net/netmon/state.go | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/net/netmon/state.go b/net/netmon/state.go index d9b360f5e..a612dd06d 100644 --- a/net/netmon/state.go +++ b/net/netmon/state.go @@ -19,8 +19,14 @@ import ( "tailscale.com/net/netaddr" "tailscale.com/net/tsaddr" "tailscale.com/net/tshttpproxy" + "tailscale.com/util/mak" ) +// forceAllIPv6Endpoints is a debug knob that when set forces the client to +// report all IPv6 endpoints rather than trim endpoints that are siblings on the +// same interface and subnet. +var forceAllIPv6Endpoints = envknob.RegisterBool("TS_DEBUG_FORCE_ALL_IPV6_ENDPOINTS") + // LoginEndpointForProxyDetermination is the URL used for testing // which HTTP proxy the system should use. var LoginEndpointForProxyDetermination = "https://controlplane.tailscale.com/" @@ -65,6 +71,7 @@ func LocalAddresses() (regular, loopback []netip.Addr, err error) { if err != nil { return nil, nil, err } + var subnets map[netip.Addr]int for _, a := range addrs { switch v := a.(type) { case *net.IPNet: @@ -102,7 +109,15 @@ func LocalAddresses() (regular, loopback []netip.Addr, err error) { if ip.Is4() { regular4 = append(regular4, ip) } else { - regular6 = append(regular6, ip) + curMask, _ := netip.AddrFromSlice(v.IP.Mask(v.Mask)) + // Limit the number of addresses reported per subnet for + // IPv6, as we have seen some nodes with extremely large + // numbers of assigned addresses being carved out of + // same-subnet allocations. + if forceAllIPv6Endpoints() || subnets[curMask] < 2 { + regular6 = append(regular6, ip) + } + mak.Set(&subnets, curMask, subnets[curMask]+1) } } }