mirror of
https://github.com/juanfont/headscale.git
synced 2026-07-16 04:50:45 +09:00
db: handle degenerate prefixes in random IP allocation
Single-address prefixes panicked; zero-high-byte addresses failed to encode.
This commit is contained in:
committed by
Kristoffer Dalby
parent
10696fa634
commit
99ad555d64
+10
-1
@@ -251,6 +251,12 @@ func randomNext(pfx netip.Prefix) (netip.Addr, error) {
|
||||
// after.
|
||||
tempMax := big.NewInt(0).Sub(&to, &from)
|
||||
|
||||
// A single-address prefix (/32 or /128) has from == to, so tempMax is 0 and
|
||||
// rand.Int would panic on a non-positive bound. Return the sole address.
|
||||
if tempMax.Sign() <= 0 {
|
||||
return fromIP, nil
|
||||
}
|
||||
|
||||
out, err := rand.Int(rand.Reader, tempMax)
|
||||
if err != nil {
|
||||
return netip.Addr{}, fmt.Errorf("generating random IP: %w", err)
|
||||
@@ -258,7 +264,10 @@ func randomNext(pfx netip.Prefix) (netip.Addr, error) {
|
||||
|
||||
valInRange := big.NewInt(0).Add(&from, out)
|
||||
|
||||
ip, ok := netip.AddrFromSlice(valInRange.Bytes())
|
||||
// big.Int.Bytes() strips leading zero bytes, so a value with a zero high
|
||||
// byte yields a too-short slice that AddrFromSlice rejects. Pad to the
|
||||
// prefix's address width.
|
||||
ip, ok := netip.AddrFromSlice(valInRange.FillBytes(make([]byte, len(fromIP.AsSlice()))))
|
||||
if !ok {
|
||||
return netip.Addr{}, errGeneratedIPBytesInvalid
|
||||
}
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"net/netip"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// TestRandomNextSingleAddressPrefix ensures a single-address prefix (/32 or
|
||||
// /128) does not panic. from == to makes the random range zero, and rand.Int
|
||||
// panics on a non-positive bound; the sole address must be returned instead.
|
||||
func TestRandomNextSingleAddressPrefix(t *testing.T) {
|
||||
for _, p := range []string{"100.64.0.1/32", "fd7a:115c:a1e0::1/128"} {
|
||||
pfx := netip.MustParsePrefix(p)
|
||||
require.NotPanics(t, func() {
|
||||
ip, err := randomNext(pfx)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, pfx.Addr(), ip)
|
||||
}, "prefix %s", p)
|
||||
}
|
||||
}
|
||||
|
||||
// TestRandomNextLeadingZeroBytes ensures prefixes whose addresses have a zero
|
||||
// high byte allocate successfully. big.Int.Bytes() strips leading zeros, so the
|
||||
// drawn value would be too short for netip.AddrFromSlice without padding.
|
||||
func TestRandomNextLeadingZeroBytes(t *testing.T) {
|
||||
pfx := netip.MustParsePrefix("0.0.0.0/16")
|
||||
for range 100 {
|
||||
ip, err := randomNext(pfx)
|
||||
require.NoError(t, err)
|
||||
assert.True(t, pfx.Contains(ip), "ip %s not in %s", ip, pfx)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user