mirror of
https://github.com/netbirdio/netbird.git
synced 2026-08-29 02:51:29 +02:00
input validation for peer ip allocation
This commit is contained in:
@@ -191,10 +191,22 @@ func (n *Network) Copy() *Network {
|
||||
}
|
||||
}
|
||||
|
||||
// validateIPv4Prefix ensures the prefix is an IPv4 network with assignable host addresses.
|
||||
func validateIPv4Prefix(prefix netip.Prefix) error {
|
||||
if !prefix.IsValid() || !prefix.Addr().Is4() || prefix.Bits() < 1 || prefix.Bits() >= 31 {
|
||||
return fmt.Errorf("invalid IPv4 subnet: %s", prefix.String())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// AllocatePeerIP picks an available IP from a netip.Prefix.
|
||||
// This method considers already taken IPs and reuses IPs if there are gaps in takenIps.
|
||||
// E.g. if prefix=100.30.0.0/16 and takenIps=[100.30.0.1, 100.30.0.4] then the result would be 100.30.0.2 or 100.30.0.3.
|
||||
func AllocatePeerIP(prefix netip.Prefix, takenIps []netip.Addr) (netip.Addr, error) {
|
||||
if err := validateIPv4Prefix(prefix); err != nil {
|
||||
return netip.Addr{}, err
|
||||
}
|
||||
|
||||
b := prefix.Masked().Addr().As4()
|
||||
baseIP := binary.BigEndian.Uint32(b[:])
|
||||
hostBits := 32 - prefix.Bits()
|
||||
@@ -205,6 +217,9 @@ func AllocatePeerIP(prefix netip.Prefix, takenIps []netip.Addr) (netip.Addr, err
|
||||
taken[baseIP+totalIPs-1] = struct{}{} // reserve broadcast IP
|
||||
|
||||
for _, ip := range takenIps {
|
||||
if !ip.Is4() {
|
||||
continue
|
||||
}
|
||||
ab := ip.As4()
|
||||
taken[binary.BigEndian.Uint32(ab[:])] = struct{}{}
|
||||
}
|
||||
@@ -231,6 +246,10 @@ func AllocatePeerIP(prefix netip.Prefix, takenIps []netip.Addr) (netip.Addr, err
|
||||
|
||||
// AllocateRandomPeerIP picks a random available IP from a netip.Prefix.
|
||||
func AllocateRandomPeerIP(prefix netip.Prefix) (netip.Addr, error) {
|
||||
if err := validateIPv4Prefix(prefix); err != nil {
|
||||
return netip.Addr{}, err
|
||||
}
|
||||
|
||||
b := prefix.Masked().Addr().As4()
|
||||
baseIP := binary.BigEndian.Uint32(b[:])
|
||||
hostBits := 32 - prefix.Bits()
|
||||
|
||||
@@ -143,6 +143,34 @@ func TestAllocatePeerIPVariousCIDRs(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestAllocateIPv4InvalidPrefixes(t *testing.T) {
|
||||
prefixes := []netip.Prefix{
|
||||
{},
|
||||
netip.MustParsePrefix("0.0.0.0/0"),
|
||||
netip.MustParsePrefix("192.168.1.0/31"),
|
||||
netip.MustParsePrefix("192.168.1.1/32"),
|
||||
netip.MustParsePrefix("fd12:3456:7890:abcd::/64"),
|
||||
}
|
||||
|
||||
for _, prefix := range prefixes {
|
||||
t.Run(prefix.String(), func(t *testing.T) {
|
||||
_, err := AllocatePeerIP(prefix, nil)
|
||||
assert.Error(t, err)
|
||||
|
||||
_, err = AllocateRandomPeerIP(prefix)
|
||||
assert.Error(t, err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAllocatePeerIPIgnoresNonIPv4TakenIPs(t *testing.T) {
|
||||
prefix := netip.MustParsePrefix("192.168.1.0/29")
|
||||
|
||||
ip, err := AllocatePeerIP(prefix, []netip.Addr{netip.MustParseAddr("fd12:3456:7890:abcd::1")})
|
||||
require.NoError(t, err)
|
||||
assert.True(t, prefix.Contains(ip))
|
||||
}
|
||||
|
||||
func TestGenerateIPs(t *testing.T) {
|
||||
ipNet := net.IPNet{IP: net.ParseIP("100.64.0.0"), Mask: net.IPMask{255, 255, 255, 0}}
|
||||
ips, ipsLen := generateIPs(&ipNet, map[string]struct{}{"100.64.0.0": {}})
|
||||
|
||||
Reference in New Issue
Block a user