fix(wireguard): step over wide address claims when allocating

allocateWireguardAddress walked the scope one address at a time and
tested each against every wide claim, so a claim covering an IPv6 /64
(a node can report such allowedIPs) turned the next address-less client
add into a 2^64-step loop that also held every later client change on
that inbound. The scan now jumps past a wide claim in one step, so it is
bounded by the number of claims.
This commit is contained in:
MHSanaei
2026-10-31 14:35:01 +01:00
parent 351a01ff0c
commit d69b924baf
2 changed files with 27 additions and 10 deletions
+24 -10
View File
@@ -117,16 +117,15 @@ func allocateWireguardAddress(used []string, base string, allowWidening bool) (s
wide = append(wide, p)
}
}
isTaken := func(a netip.Addr) bool {
if _, ok := taken[a]; ok {
return true
}
// wideClaimOf returns a wide claim holding a, so the scan can step over the whole claim:
// a node may report one spanning the scope, and walking it is 2^64 steps in IPv6.
wideClaimOf := func(a netip.Addr) (netip.Prefix, bool) {
for _, p := range wide {
if p.Contains(a) {
return true
return p, true
}
}
return false
return netip.Prefix{}, false
}
scopes := []netip.Prefix{prefix}
if allowWidening && prefix.Addr().Is4() && prefix.Bits() > wireguardPoolFloorBits {
@@ -136,16 +135,31 @@ func allocateWireguardAddress(used []string, base string, allowWidening bool) (s
}
for _, scope := range scopes {
addr := scope.Masked().Addr().Next().Next()
for scope.Contains(addr) {
if !isTaken(addr) {
return addr.String() + "/" + hostBits, nil
for addr.IsValid() && scope.Contains(addr) {
if _, ok := taken[addr]; ok {
addr = addr.Next()
continue
}
addr = addr.Next()
if claim, ok := wideClaimOf(addr); ok {
addr = lastPrefixAddr(claim).Next()
continue
}
return addr.String() + "/" + hostBits, nil
}
}
return "", common.NewError("wireguard: no free address available in", scopes[len(scopes)-1].String())
}
// lastPrefixAddr is the highest address of p.
func lastPrefixAddr(p netip.Prefix) netip.Addr {
bytes := p.Masked().Addr().AsSlice()
for bit := p.Bits(); bit < len(bytes)*8; bit++ {
bytes[bit/8] |= 0x80 >> (bit % 8)
}
addr, _ := netip.AddrFromSlice(bytes)
return addr
}
// normalizeWireguardAllowedIPs validates user-supplied allowedIPs entries and
// canonicalizes them: bare addresses become single-host prefixes, duplicates drop.
func normalizeWireguardAllowedIPs(values []string) ([]string, error) {