diff --git a/cmd/tailscaled/depaware.txt b/cmd/tailscaled/depaware.txt index c5da78609..24f6cb4da 100644 --- a/cmd/tailscaled/depaware.txt +++ b/cmd/tailscaled/depaware.txt @@ -514,7 +514,6 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de hash from compress/zlib+ hash/adler32 from compress/zlib+ hash/crc32 from compress/gzip+ - hash/fnv from tailscale.com/wgengine/magicsock hash/maphash from go4.org/mem html from html/template+ html/template from github.com/gorilla/csrf diff --git a/util/rands/cheap.go b/util/rands/cheap.go index 06e46a1b0..69785e086 100644 --- a/util/rands/cheap.go +++ b/util/rands/cheap.go @@ -23,6 +23,14 @@ func Shuffle[T any](seed uint64, data []T) { } } +// IntN is like rand.IntN, but it is seeded on the stack and does not allocate +// or lock any RNG state. +func IntN(seed uint64, n int) int { + var pcg randv2.PCG + pcg.Seed(seed, seed) + return int(uint64n(&pcg, uint64(n))) +} + // Perm is like rand.Perm, but it is seeded on the stack and does not allocate // or lock any RNG state. func Perm(seed uint64, n int) []int { diff --git a/wgengine/magicsock/derp.go b/wgengine/magicsock/derp.go index a5f43cda0..8a1c4d367 100644 --- a/wgengine/magicsock/derp.go +++ b/wgengine/magicsock/derp.go @@ -7,8 +7,6 @@ import ( "bufio" "context" "fmt" - "hash/fnv" - "math/rand" "net" "net/netip" "reflect" @@ -16,6 +14,7 @@ import ( "sort" "sync" "time" + "unsafe" "github.com/tailscale/wireguard-go/conn" "tailscale.com/derp" @@ -31,6 +30,7 @@ import ( "tailscale.com/types/key" "tailscale.com/types/logger" "tailscale.com/util/mak" + "tailscale.com/util/rands" "tailscale.com/util/sysresources" "tailscale.com/util/testenv" ) @@ -94,7 +94,6 @@ type activeDerp struct { } var ( - processStartUnixNano = time.Now().UnixNano() pickDERPFallbackForTests func() int ) @@ -136,10 +135,7 @@ func (c *Conn) pickDERPFallback() int { return pickDERPFallbackForTests() } - // TODO: use math/rand/v2 here. - h := fnv.New64() - fmt.Fprintf(h, "%p/%d", c, processStartUnixNano) // arbitrary - return ids[rand.New(rand.NewSource(int64(h.Sum64()))).Intn(len(ids))] + return ids[rands.IntN(uint64(uintptr(unsafe.Pointer(c))), len(ids))] } // This allows existing tests to pass, but allows us to still test the