mirror of
https://github.com/netbirdio/netbird.git
synced 2026-09-17 12:19:07 +02:00
remove old math rand lib
This commit is contained in:
@@ -3,9 +3,10 @@ package labelgen
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/rand"
|
|
||||||
"sort"
|
"sort"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"github.com/netbirdio/netbird/management/server/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
// pickAttempts caps the random retries before falling back to the
|
// pickAttempts caps the random retries before falling back to the
|
||||||
@@ -40,16 +41,15 @@ func uniqueWords() []string {
|
|||||||
// PickUnique selects a label not already in `taken`. It tries up to
|
// PickUnique selects a label not already in `taken`. It tries up to
|
||||||
// pickAttempts random picks; on exhaustion it scans the deduplicated
|
// pickAttempts random picks; on exhaustion it scans the deduplicated
|
||||||
// wordlist for any remaining free entry, and if none is left appends
|
// wordlist for any remaining free entry, and if none is left appends
|
||||||
// `-<fallbackSuffix>` to a deterministic word and returns. The caller
|
// `-<fallbackSuffix>` to a random word and returns.
|
||||||
// is responsible for seeding rng (math/rand).
|
func PickUnique(taken map[string]struct{}, fallbackSuffix string) string {
|
||||||
func PickUnique(rng *rand.Rand, taken map[string]struct{}, fallbackSuffix string) string {
|
|
||||||
pool := uniqueWords()
|
pool := uniqueWords()
|
||||||
if len(pool) == 0 {
|
if len(pool) == 0 {
|
||||||
return fallbackSuffix
|
return fallbackSuffix
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := 0; i < pickAttempts; i++ {
|
for i := 0; i < pickAttempts; i++ {
|
||||||
w := pool[rng.Intn(len(pool))]
|
w := pool[util.RandIntn(len(pool))]
|
||||||
if _, ok := taken[w]; !ok {
|
if _, ok := taken[w]; !ok {
|
||||||
return w
|
return w
|
||||||
}
|
}
|
||||||
@@ -61,6 +61,6 @@ func PickUnique(rng *rand.Rand, taken map[string]struct{}, fallbackSuffix string
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
w := pool[rng.Intn(len(pool))]
|
w := pool[util.RandIntn(len(pool))]
|
||||||
return fmt.Sprintf("%s-%s", w, fallbackSuffix)
|
return fmt.Sprintf("%s-%s", w, fallbackSuffix)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package labelgen
|
package labelgen
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"math/rand"
|
"slices"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
@@ -9,19 +9,12 @@ import (
|
|||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TestPickUnique_DeterministicWithSeededRng locks the property the
|
// TestPickUnique_ReturnsWordFromPool confirms a pick against an empty
|
||||||
// caller relies on: same seed + same taken set → same pick. Without
|
// taken set is always drawn verbatim from the wordlist.
|
||||||
// that, the bootstrap flow can't reproduce a label across retries.
|
func TestPickUnique_ReturnsWordFromPool(t *testing.T) {
|
||||||
func TestPickUnique_DeterministicWithSeededRng(t *testing.T) {
|
got := PickUnique(map[string]struct{}{}, "abcd")
|
||||||
taken := map[string]struct{}{}
|
|
||||||
|
|
||||||
rngA := rand.New(rand.NewSource(42))
|
assert.True(t, slices.Contains(uniqueWords(), got), "Pick %q must be drawn from the wordlist", got)
|
||||||
rngB := rand.New(rand.NewSource(42))
|
|
||||||
|
|
||||||
a := PickUnique(rngA, taken, "abcd")
|
|
||||||
b := PickUnique(rngB, taken, "abcd")
|
|
||||||
|
|
||||||
assert.Equal(t, a, b, "Same seed and taken set must produce identical pick")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestPickUnique_AvoidsTakenWordsWhenMostAreReserved seeds taken with
|
// TestPickUnique_AvoidsTakenWordsWhenMostAreReserved seeds taken with
|
||||||
@@ -46,8 +39,7 @@ func TestPickUnique_AvoidsTakenWordsWhenMostAreReserved(t *testing.T) {
|
|||||||
taken[w] = struct{}{}
|
taken[w] = struct{}{}
|
||||||
}
|
}
|
||||||
|
|
||||||
rng := rand.New(rand.NewSource(7))
|
got := PickUnique(taken, "abcd")
|
||||||
got := PickUnique(rng, taken, "abcd")
|
|
||||||
|
|
||||||
_, isFree := free[got]
|
_, isFree := free[got]
|
||||||
assert.True(t, isFree, "PickUnique must return one of the free words; got %q", got)
|
assert.True(t, isFree, "PickUnique must return one of the free words; got %q", got)
|
||||||
@@ -65,8 +57,7 @@ func TestPickUnique_FallsBackWhenAllReserved(t *testing.T) {
|
|||||||
taken[w] = struct{}{}
|
taken[w] = struct{}{}
|
||||||
}
|
}
|
||||||
|
|
||||||
rng := rand.New(rand.NewSource(99))
|
got := PickUnique(taken, "abcd")
|
||||||
got := PickUnique(rng, taken, "abcd")
|
|
||||||
|
|
||||||
assert.True(t, strings.HasSuffix(got, "-abcd"), "Exhausted pool must produce <word>-<suffix>; got %q", got)
|
assert.True(t, strings.HasSuffix(got, "-abcd"), "Exhausted pool must produce <word>-<suffix>; got %q", got)
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/rand"
|
|
||||||
"slices"
|
"slices"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
@@ -123,11 +122,6 @@ type managerImpl struct {
|
|||||||
// accountID, then by synthesised service ID.
|
// accountID, then by synthesised service ID.
|
||||||
reconcileMu sync.Mutex
|
reconcileMu sync.Mutex
|
||||||
reconcileCache map[string]map[string]*proto.ProxyMapping
|
reconcileCache map[string]map[string]*proto.ProxyMapping
|
||||||
|
|
||||||
// labelRngMu guards labelRng. PickUnique consumes math/rand.Source
|
|
||||||
// state; concurrent provider creates would otherwise race.
|
|
||||||
labelRngMu sync.Mutex
|
|
||||||
labelRng *rand.Rand
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewManager constructs the persistent Agent Network manager. The
|
// NewManager constructs the persistent Agent Network manager. The
|
||||||
@@ -147,7 +141,6 @@ func NewManager(
|
|||||||
permissionsManager: permissionsManager,
|
permissionsManager: permissionsManager,
|
||||||
proxyController: proxyController,
|
proxyController: proxyController,
|
||||||
reconcileCache: make(map[string]map[string]*proto.ProxyMapping),
|
reconcileCache: make(map[string]map[string]*proto.ProxyMapping),
|
||||||
labelRng: rand.New(rand.NewSource(time.Now().UnixNano())),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -653,9 +646,7 @@ func (m *managerImpl) bootstrapSettingsIfNeeded(ctx context.Context, accountID,
|
|||||||
suffix = suffix[:4]
|
suffix = suffix[:4]
|
||||||
}
|
}
|
||||||
|
|
||||||
m.labelRngMu.Lock()
|
subdomain := labelgen.PickUnique(taken, suffix)
|
||||||
subdomain := labelgen.PickUnique(m.labelRng, taken, suffix)
|
|
||||||
m.labelRngMu.Unlock()
|
|
||||||
|
|
||||||
now := time.Now().UTC()
|
now := time.Now().UTC()
|
||||||
settings := &types.Settings{
|
settings := &types.Settings{
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/rand"
|
|
||||||
"net"
|
"net"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
"os"
|
"os"
|
||||||
@@ -63,7 +62,7 @@ const (
|
|||||||
type userLoggedInOnce bool
|
type userLoggedInOnce bool
|
||||||
|
|
||||||
func cacheEntryExpiration() time.Duration {
|
func cacheEntryExpiration() time.Duration {
|
||||||
r := rand.Intn(int(nbcache.DefaultIDPCacheExpirationMax.Milliseconds()-nbcache.DefaultIDPCacheExpirationMin.Milliseconds())) + int(nbcache.DefaultIDPCacheExpirationMin.Milliseconds())
|
r := util.RandIntn(int(nbcache.DefaultIDPCacheExpirationMax.Milliseconds()-nbcache.DefaultIDPCacheExpirationMin.Milliseconds())) + int(nbcache.DefaultIDPCacheExpirationMin.Milliseconds())
|
||||||
return time.Duration(r) * time.Millisecond
|
return time.Duration(r) * time.Millisecond
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2455,8 +2454,7 @@ func (am *DefaultAccountManager) ensureIPv6Subnet(ctx context.Context, transacti
|
|||||||
return transaction.UpdateAccountNetworkV6(ctx, accountID, network.NetV6)
|
return transaction.UpdateAccountNetworkV6(ctx, accountID, network.NetV6)
|
||||||
}
|
}
|
||||||
if network.NetV6.IP == nil {
|
if network.NetV6.IP == nil {
|
||||||
r := rand.New(rand.NewSource(time.Now().UnixNano()))
|
network.NetV6 = types.AllocateIPv6Subnet()
|
||||||
network.NetV6 = types.AllocateIPv6Subnet(r)
|
|
||||||
|
|
||||||
// Sync settings to match the allocated subnet so SaveAccountSettings persists it.
|
// Sync settings to match the allocated subnet so SaveAccountSettings persists it.
|
||||||
ones, _ := network.NetV6.Mask.Size()
|
ones, _ := network.NetV6.Mask.Size()
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package server
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"math/rand"
|
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -28,7 +27,7 @@ func TestGroupIPv6Assignment(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Allocate IPv6 subnet for the account
|
// Allocate IPv6 subnet for the account
|
||||||
account.Network.NetV6 = types.AllocateIPv6Subnet(rand.New(rand.NewSource(time.Now().UnixNano())))
|
account.Network.NetV6 = types.AllocateIPv6Subnet()
|
||||||
require.NoError(t, am.Store.SaveAccount(ctx, account))
|
require.NoError(t, am.Store.SaveAccount(ctx, account))
|
||||||
|
|
||||||
// Create setup key
|
// Create setup key
|
||||||
|
|||||||
@@ -2,11 +2,12 @@ package idp
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"math/rand"
|
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/netbirdio/netbird/management/server/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -33,31 +34,32 @@ func GeneratePassword(passwordLength, minSpecialChar, minNum, minUpperCase int)
|
|||||||
|
|
||||||
//Set special character
|
//Set special character
|
||||||
for i := 0; i < minSpecialChar; i++ {
|
for i := 0; i < minSpecialChar; i++ {
|
||||||
random := rand.Intn(len(specialCharSet))
|
random := util.RandIntn(len(specialCharSet))
|
||||||
password.WriteString(string(specialCharSet[random]))
|
password.WriteString(string(specialCharSet[random]))
|
||||||
}
|
}
|
||||||
|
|
||||||
//Set numeric
|
//Set numeric
|
||||||
for i := 0; i < minNum; i++ {
|
for i := 0; i < minNum; i++ {
|
||||||
random := rand.Intn(len(numberSet))
|
random := util.RandIntn(len(numberSet))
|
||||||
password.WriteString(string(numberSet[random]))
|
password.WriteString(string(numberSet[random]))
|
||||||
}
|
}
|
||||||
|
|
||||||
//Set uppercase
|
//Set uppercase
|
||||||
for i := 0; i < minUpperCase; i++ {
|
for i := 0; i < minUpperCase; i++ {
|
||||||
random := rand.Intn(len(upperCharSet))
|
random := util.RandIntn(len(upperCharSet))
|
||||||
password.WriteString(string(upperCharSet[random]))
|
password.WriteString(string(upperCharSet[random]))
|
||||||
}
|
}
|
||||||
|
|
||||||
remainingLength := passwordLength - minSpecialChar - minNum - minUpperCase
|
remainingLength := passwordLength - minSpecialChar - minNum - minUpperCase
|
||||||
for i := 0; i < remainingLength; i++ {
|
for i := 0; i < remainingLength; i++ {
|
||||||
random := rand.Intn(len(allCharSet))
|
random := util.RandIntn(len(allCharSet))
|
||||||
password.WriteString(string(allCharSet[random]))
|
password.WriteString(string(allCharSet[random]))
|
||||||
}
|
}
|
||||||
inRune := []rune(password.String())
|
inRune := []rune(password.String())
|
||||||
rand.Shuffle(len(inRune), func(i, j int) {
|
for i := len(inRune) - 1; i > 0; i-- {
|
||||||
|
j := util.RandIntn(i + 1)
|
||||||
inRune[i], inRune[j] = inRune[j], inRune[i]
|
inRune[i], inRune[j] = inRune[j], inRune[i]
|
||||||
})
|
}
|
||||||
return string(inRune)
|
return string(inRune)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,14 +1,13 @@
|
|||||||
package types
|
package types
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/rand"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/rand"
|
|
||||||
"net"
|
"net"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
"slices"
|
"slices"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/c-robinson/iplib"
|
"github.com/c-robinson/iplib"
|
||||||
"github.com/rs/xid"
|
"github.com/rs/xid"
|
||||||
@@ -137,14 +136,12 @@ func NewNetwork() *Network {
|
|||||||
n := iplib.NewNet4(net.ParseIP("100.64.0.0"), NetSize)
|
n := iplib.NewNet4(net.ParseIP("100.64.0.0"), NetSize)
|
||||||
sub, _ := n.Subnet(SubnetSize)
|
sub, _ := n.Subnet(SubnetSize)
|
||||||
|
|
||||||
s := rand.NewSource(time.Now().UnixNano())
|
intn := util.RandIntn(len(sub))
|
||||||
r := rand.New(s)
|
|
||||||
intn := r.Intn(len(sub))
|
|
||||||
|
|
||||||
return &Network{
|
return &Network{
|
||||||
Identifier: xid.New().String(),
|
Identifier: xid.New().String(),
|
||||||
Net: sub[intn].IPNet,
|
Net: sub[intn].IPNet,
|
||||||
NetV6: AllocateIPv6Subnet(r),
|
NetV6: AllocateIPv6Subnet(),
|
||||||
Dns: "",
|
Dns: "",
|
||||||
Serial: 0,
|
Serial: 0,
|
||||||
}
|
}
|
||||||
@@ -154,18 +151,13 @@ func NewNetwork() *Network {
|
|||||||
// The format follows RFC 4193 section 3.1: fd + 40-bit Global ID + 16-bit Subnet ID.
|
// The format follows RFC 4193 section 3.1: fd + 40-bit Global ID + 16-bit Subnet ID.
|
||||||
// The Global ID and Subnet ID are randomized (simplified from the SHA-1 algorithm
|
// The Global ID and Subnet ID are randomized (simplified from the SHA-1 algorithm
|
||||||
// in section 3.2.2), giving 2^56 possible /64 subnets across all accounts.
|
// in section 3.2.2), giving 2^56 possible /64 subnets across all accounts.
|
||||||
func AllocateIPv6Subnet(r *rand.Rand) net.IPNet {
|
func AllocateIPv6Subnet() net.IPNet {
|
||||||
ip := make(net.IP, 16)
|
ip := make(net.IP, 16)
|
||||||
ip[0] = 0xfd
|
ip[0] = 0xfd
|
||||||
// Bytes 1-5: 40-bit random Global ID
|
// Bytes 1-5: 40-bit random Global ID, bytes 6-7: 16-bit random Subnet ID
|
||||||
ip[1] = byte(r.Intn(256))
|
if _, err := rand.Read(ip[1:8]); err != nil {
|
||||||
ip[2] = byte(r.Intn(256))
|
panic(err)
|
||||||
ip[3] = byte(r.Intn(256))
|
}
|
||||||
ip[4] = byte(r.Intn(256))
|
|
||||||
ip[5] = byte(r.Intn(256))
|
|
||||||
// Bytes 6-7: 16-bit random Subnet ID
|
|
||||||
ip[6] = byte(r.Intn(256))
|
|
||||||
ip[7] = byte(r.Intn(256))
|
|
||||||
|
|
||||||
return net.IPNet{
|
return net.IPNet{
|
||||||
IP: ip,
|
IP: ip,
|
||||||
@@ -217,11 +209,10 @@ func AllocatePeerIP(prefix netip.Prefix, takenIps []netip.Addr) (netip.Addr, err
|
|||||||
taken[binary.BigEndian.Uint32(ab[:])] = struct{}{}
|
taken[binary.BigEndian.Uint32(ab[:])] = struct{}{}
|
||||||
}
|
}
|
||||||
|
|
||||||
rng := rand.New(rand.NewSource(time.Now().UnixNano()))
|
|
||||||
maxAttempts := (int(totalIPs) - len(taken)) / 100
|
maxAttempts := (int(totalIPs) - len(taken)) / 100
|
||||||
|
|
||||||
for i := 0; i < maxAttempts; i++ {
|
for i := 0; i < maxAttempts; i++ {
|
||||||
offset := uint32(rng.Intn(int(totalIPs-2))) + 1
|
offset := uint32(util.RandIntn(int(totalIPs-2))) + 1
|
||||||
candidate := baseIP + offset
|
candidate := baseIP + offset
|
||||||
if _, exists := taken[candidate]; !exists {
|
if _, exists := taken[candidate]; !exists {
|
||||||
return uint32ToIP(candidate), nil
|
return uint32ToIP(candidate), nil
|
||||||
@@ -245,8 +236,7 @@ func AllocateRandomPeerIP(prefix netip.Prefix) (netip.Addr, error) {
|
|||||||
hostBits := 32 - prefix.Bits()
|
hostBits := 32 - prefix.Bits()
|
||||||
totalIPs := uint32(1 << hostBits)
|
totalIPs := uint32(1 << hostBits)
|
||||||
|
|
||||||
rng := rand.New(rand.NewSource(time.Now().UnixNano()))
|
offset := uint32(util.RandIntn(int(totalIPs-2))) + 1
|
||||||
offset := uint32(rng.Intn(int(totalIPs-2))) + 1
|
|
||||||
|
|
||||||
candidate := baseIP + offset
|
candidate := baseIP + offset
|
||||||
return uint32ToIP(candidate), nil
|
return uint32ToIP(candidate), nil
|
||||||
@@ -262,23 +252,26 @@ func AllocateRandomPeerIPv6(prefix netip.Prefix) (netip.Addr, error) {
|
|||||||
|
|
||||||
ip := prefix.Addr().As16()
|
ip := prefix.Addr().As16()
|
||||||
|
|
||||||
rng := rand.New(rand.NewSource(time.Now().UnixNano()))
|
|
||||||
|
|
||||||
// Determine which byte the host bits start in
|
// Determine which byte the host bits start in
|
||||||
firstHostByte := ones / 8
|
firstHostByte := ones / 8
|
||||||
// If the prefix doesn't end on a byte boundary, handle the partial byte
|
// If the prefix doesn't end on a byte boundary, handle the partial byte
|
||||||
partialBits := ones % 8
|
partialBits := ones % 8
|
||||||
|
|
||||||
|
var rnd [16]byte
|
||||||
|
if _, err := rand.Read(rnd[firstHostByte:]); err != nil {
|
||||||
|
return netip.Addr{}, err
|
||||||
|
}
|
||||||
|
|
||||||
if partialBits > 0 {
|
if partialBits > 0 {
|
||||||
// Keep the network bits in the partial byte, randomize the rest
|
// Keep the network bits in the partial byte, randomize the rest
|
||||||
hostMask := byte(0xff >> partialBits)
|
hostMask := byte(0xff >> partialBits)
|
||||||
ip[firstHostByte] = (ip[firstHostByte] & ^hostMask) | (byte(rng.Intn(256)) & hostMask)
|
ip[firstHostByte] = (ip[firstHostByte] & ^hostMask) | (rnd[firstHostByte] & hostMask)
|
||||||
firstHostByte++
|
firstHostByte++
|
||||||
}
|
}
|
||||||
|
|
||||||
// Randomize remaining full host bytes
|
// Randomize remaining full host bytes
|
||||||
for i := firstHostByte; i < 16; i++ {
|
for i := firstHostByte; i < 16; i++ {
|
||||||
ip[i] = byte(rng.Intn(256))
|
ip[i] = rnd[i]
|
||||||
}
|
}
|
||||||
|
|
||||||
// Avoid all-zeros and all-ones host parts by checking only host bits.
|
// Avoid all-zeros and all-ones host parts by checking only host bits.
|
||||||
|
|||||||
@@ -1,5 +1,20 @@
|
|||||||
package util
|
package util
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/rand"
|
||||||
|
"math/big"
|
||||||
|
)
|
||||||
|
|
||||||
|
// RandIntn returns a uniformly distributed int in [0, n) sourced from
|
||||||
|
// crypto/rand. It panics if n <= 0 or the platform randomness source fails.
|
||||||
|
func RandIntn(n int) int {
|
||||||
|
v, err := rand.Int(rand.Reader, big.NewInt(int64(n)))
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return int(v.Int64())
|
||||||
|
}
|
||||||
|
|
||||||
// Difference returns the elements in `a` that aren't in `b`.
|
// Difference returns the elements in `a` that aren't in `b`.
|
||||||
func Difference(a, b []string) []string {
|
func Difference(a, b []string) []string {
|
||||||
mb := make(map[string]struct{}, len(b))
|
mb := make(map[string]struct{}, len(b))
|
||||||
|
|||||||
Reference in New Issue
Block a user