diff --git a/client/iface/wgproxy/loopback/addr_test.go b/client/iface/wgproxy/loopback/addr_test.go index 89343424c..3df3576d4 100644 --- a/client/iface/wgproxy/loopback/addr_test.go +++ b/client/iface/wgproxy/loopback/addr_test.go @@ -47,29 +47,38 @@ func TestAllocatorSkipsNetworkAndBroadcastHosts(t *testing.T) { func TestAllocatorReusesReleasedAddresses(t *testing.T) { var a allocator taken := make(map[netip.Addr]bool) - - first, err := a.next(func(candidate netip.Addr) bool { return taken[candidate] }) - if err != nil { - t.Fatalf("allocate: %v", err) - } - taken[first] = true - - // release it and allocate until the cursor wraps back around to it - delete(taken, first) - for i := 0; i < 10; i++ { - addr, err := a.next(func(candidate netip.Addr) bool { return taken[candidate] }) + inUse := func(candidate netip.Addr) bool { return taken[candidate] } + alloc := func() netip.Addr { + t.Helper() + addr, err := a.next(inUse) if err != nil { - t.Fatalf("allocate %d: %v", i, err) - } - if addr == first { - return + t.Fatalf("allocate: %v", err) } taken[addr] = true + return addr } - // the cursor moves forward, so reuse only happens after a full wrap. Assert - // the released address is at least still considered free. - if inUse := taken[first]; inUse { - t.Fatalf("released address %s still marked in use", first) + + first := alloc() + second := alloc() + delete(taken, first) + + // The cursor only moves forward, so a released address comes back after a + // wrap. Park the cursor near the end of the range instead of allocating + // 2^23 addresses: the next call takes the last usable address, and the one + // after that wraps past the skipped .255 and .0 hosts to the released one. + a.cursor = addrRangeSize - 3 + last := alloc() + if want := netip.MustParseAddr("127.255.255.254"); last != want { + t.Fatalf("expected the last usable address %s before the wrap, got %s", want, last) + } + + if reused := alloc(); reused != first { + t.Fatalf("expected the released address %s after the wrap, got %s", first, reused) + } + + // second is still held, so the allocator must step over it. + if next := alloc(); next == second { + t.Fatalf("allocator handed out %s while it was still in use", second) } } diff --git a/client/iface/wgproxy/loopback/proxy_privileged_test.go b/client/iface/wgproxy/loopback/proxy_privileged_test.go index e7a7692ff..6314fe2de 100644 --- a/client/iface/wgproxy/loopback/proxy_privileged_test.go +++ b/client/iface/wgproxy/loopback/proxy_privileged_test.go @@ -79,7 +79,7 @@ func TestProxyDemuxesByDestinationAddress(t *testing.T) { seen[endpoint.IP.String()] = true } - wgSock, err := net.ListenUDP("udp", &net.UDPAddr{IP: net.ParseIP("127.0.0.1"), Port: testWGPort}) + wgSock, err := net.ListenUDP("udp", &net.UDPAddr{IP: net.ParseIP("127.0.0.1")}) if err != nil { t.Fatalf("wg socket: %v", err) }