Browse Source

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 <[email protected]>
James Tucker 1 year ago
parent
commit
6364b5f1e0
1 changed files with 16 additions and 1 deletions
  1. 16 1
      net/netmon/state.go

+ 16 - 1
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)
 					}
 				}
 			}