mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-11-02 08:44:45 +03:00
fix(amneziawgnet): stop tests binding fixed ports in the ephemeral range
The race job failed TestEnsureRebuildsWhenS4ChangesTheDerivedMTU with "bind 127.0.0.1:58720: address already in use". The package hardcoded WireGuard and port-forward ports 58712-58922, all inside Linux's ephemeral range (32768-60999), so any concurrent :0 socket could already hold one; several were also reused across tests (58713 x3, 58715, 58717, 58720). Tests that never dial the server now use ListenPort 0; tests that need the number take an OS-assigned one via freeUDPPort / freeTCPUDPPort (the latter for port forwards, which bind TCP and UDP on the same port).
This commit is contained in:
@@ -210,7 +210,7 @@ func (t *benchTunnel) dial(b *testing.B, dest netip.AddrPort) *gonet.TCPConn {
|
||||
func BenchmarkTunnelThroughput(b *testing.B) {
|
||||
const chunkSize = 64 << 10
|
||||
const serverAddr = "10.203.0.1"
|
||||
tun := newBenchTunnel(b, 58714, serverAddr, "10.203.0.2")
|
||||
tun := newBenchTunnel(b, freeUDPPort(b), serverAddr, "10.203.0.2")
|
||||
defer tun.closeFn()
|
||||
|
||||
b.Run("upload", func(b *testing.B) {
|
||||
|
||||
@@ -39,7 +39,7 @@ func TestNewDeviceHandshakeForwarderAndIdentity(t *testing.T) {
|
||||
t.Fatalf("generate client keypair: %v", err)
|
||||
}
|
||||
|
||||
const listenPort = 58712 // fixed loopback test port, matches the validated Phase 0 spike approach
|
||||
listenPort := freeUDPPort(t)
|
||||
const wantEmail = "test-peer@example.com"
|
||||
|
||||
inst := amneziawg.Instance{
|
||||
@@ -243,7 +243,7 @@ func TestNewDeviceHeaderProtectionAndContentPaddingRoundTrip(t *testing.T) {
|
||||
t.Fatalf("generate header protection key: %v", err)
|
||||
}
|
||||
|
||||
const listenPort = 58713 // fixed loopback test port, distinct from the handshake test above
|
||||
listenPort := freeUDPPort(t)
|
||||
const contentPaddingAddition = "20-40"
|
||||
|
||||
inst := amneziawg.Instance{
|
||||
@@ -429,7 +429,7 @@ func TestNewDeviceRandomTrailersAndDisableCookiesRoundTrip(t *testing.T) {
|
||||
t.Fatalf("generate client keypair: %v", err)
|
||||
}
|
||||
|
||||
const listenPort = 58721 // fixed loopback test port, distinct from every other test in this package
|
||||
listenPort := freeUDPPort(t)
|
||||
|
||||
inst := amneziawg.Instance{
|
||||
Id: 3,
|
||||
@@ -591,7 +591,7 @@ func TestValidatedObfuscationAlwaysApplies(t *testing.T) {
|
||||
}},
|
||||
}
|
||||
|
||||
for i, tc := range cases {
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
o := base
|
||||
tc.mut(&o)
|
||||
@@ -599,7 +599,7 @@ func TestValidatedObfuscationAlwaysApplies(t *testing.T) {
|
||||
return // rejected before saving, which is the whole point
|
||||
}
|
||||
inst := amneziawg.Instance{
|
||||
Id: 88, InterfaceName: "awgcontract", ListenPort: 58900 + i,
|
||||
Id: 88, InterfaceName: "awgcontract", ListenPort: 0,
|
||||
PrivateKey: priv, PublicKey: pub,
|
||||
Address: []string{"10.198.0.1/24"}, MTU: 1420,
|
||||
Obfuscation: o,
|
||||
|
||||
@@ -45,7 +45,7 @@ func TestDiagnoseDeviceReportsListenPortAndPeerState(t *testing.T) {
|
||||
t.Fatalf("generate idle-peer keypair: %v", err)
|
||||
}
|
||||
|
||||
const listenPort = 58713 // distinct from device_test.go's fixed port
|
||||
listenPort := freeUDPPort(t)
|
||||
const activeEmail = "active@example.com"
|
||||
const idleEmail = "idle@example.com"
|
||||
|
||||
|
||||
@@ -57,12 +57,7 @@ func newPairedTunnelForTest(t *testing.T) *pairedTunnel {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
pc, err := net.ListenPacket("udp", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
listenPort := pc.LocalAddr().(*net.UDPAddr).Port
|
||||
pc.Close()
|
||||
listenPort := freeUDPPort(t)
|
||||
|
||||
obf := amneziawg.Obfuscation31{Jc: 4, Jmin: 40, Jmax: 70, S1: 20, S2: 30, S3: 20, S4: 20}
|
||||
serverInst := amneziawg.Instance{
|
||||
@@ -133,12 +128,7 @@ func newPairedTunnelV6ForTest(t *testing.T) *pairedTunnel {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
pc, err := net.ListenPacket("udp", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
listenPort := pc.LocalAddr().(*net.UDPAddr).Port
|
||||
pc.Close()
|
||||
listenPort := freeUDPPort(t)
|
||||
|
||||
obf := amneziawg.Obfuscation31{Jc: 4, Jmin: 40, Jmax: 70, S1: 20, S2: 30, S3: 20, S4: 20}
|
||||
serverInst := amneziawg.Instance{
|
||||
|
||||
@@ -29,7 +29,7 @@ func TestManagerLifecycle(t *testing.T) {
|
||||
inst := amneziawg.Instance{
|
||||
Id: 3,
|
||||
InterfaceName: "awgtest3",
|
||||
ListenPort: 58714,
|
||||
ListenPort: 0,
|
||||
PrivateKey: priv,
|
||||
PublicKey: pub,
|
||||
Address: []string{"10.203.0.1/24"},
|
||||
@@ -117,7 +117,7 @@ func TestEnsureRebuildsWhenS4ChangesTheDerivedMTU(t *testing.T) {
|
||||
inst := amneziawg.Instance{
|
||||
Id: 9 + i,
|
||||
InterfaceName: fmt.Sprintf("awgtest%d", 9+i),
|
||||
ListenPort: 58719 + i,
|
||||
ListenPort: 0,
|
||||
PrivateKey: priv,
|
||||
PublicKey: pub,
|
||||
Address: []string{"10.209.0.1/24"},
|
||||
@@ -214,7 +214,7 @@ func TestEnsureUnchangedInstanceDoesNotResetLivePeers(t *testing.T) {
|
||||
inst := amneziawg.Instance{
|
||||
Id: 4,
|
||||
InterfaceName: "awgtest4",
|
||||
ListenPort: 58715,
|
||||
ListenPort: 0,
|
||||
PrivateKey: priv,
|
||||
PublicKey: pub,
|
||||
Address: []string{"10.204.0.1/24"},
|
||||
@@ -351,7 +351,7 @@ func TestEnsureDropsFlowsOfReassignedTunnelAddress(t *testing.T) {
|
||||
inst := amneziawg.Instance{
|
||||
Id: 9,
|
||||
InterfaceName: "awgtest9",
|
||||
ListenPort: 58720,
|
||||
ListenPort: 0,
|
||||
PrivateKey: priv,
|
||||
PublicKey: pub,
|
||||
Address: []string{"10.206.0.1/24"},
|
||||
@@ -465,7 +465,7 @@ func TestEnsureHeaderProtectionKeyChangeReconfiguresInPlace(t *testing.T) {
|
||||
inst := amneziawg.Instance{
|
||||
Id: 7,
|
||||
InterfaceName: "awgtest7",
|
||||
ListenPort: 58717,
|
||||
ListenPort: 0,
|
||||
PrivateKey: priv,
|
||||
PublicKey: pub,
|
||||
Address: []string{"10.207.0.1/24"},
|
||||
@@ -525,7 +525,7 @@ func TestEnsureRejectsHeaderProtectionKeyWithLowS1S4(t *testing.T) {
|
||||
inst := amneziawg.Instance{
|
||||
Id: 8,
|
||||
InterfaceName: "awgtest8",
|
||||
ListenPort: 58718,
|
||||
ListenPort: 0,
|
||||
PrivateKey: priv,
|
||||
PublicKey: pub,
|
||||
Address: []string{"10.208.0.1/24"},
|
||||
|
||||
@@ -145,7 +145,7 @@ func TestPortForwardSetReconcileOpensAndClosesListeners(t *testing.T) {
|
||||
gs := newTestStack(t, "10.211.0.1")
|
||||
set := NewPortForwardSet(gs, 501)
|
||||
|
||||
const port = 58910
|
||||
port := freeTCPUDPPort(t)
|
||||
inst := amneziawg.Instance{Peers: []amneziawg.Peer{
|
||||
peerWithPortsAndIPs("a@x", fmt.Sprintf("%d", port), "10.211.0.2/32"),
|
||||
}}
|
||||
@@ -190,8 +190,7 @@ func TestPortForwardSetReconcileSurvivesPreBoundPort(t *testing.T) {
|
||||
gs := newTestStack(t, "10.211.1.1")
|
||||
set := NewPortForwardSet(gs, 502)
|
||||
|
||||
const collidingPort = 58911
|
||||
const okPort = 58912
|
||||
collidingPort, okPort := freeTCPUDPPort(t), freeTCPUDPPort(t)
|
||||
blocker, err := net.Listen("tcp", fmt.Sprintf("127.0.0.1:%d", collidingPort))
|
||||
if err != nil {
|
||||
t.Fatalf("pre-bind test port: %v", err)
|
||||
@@ -280,9 +279,8 @@ func TestPortForwardRoundTripTCPAndUDP(t *testing.T) {
|
||||
t.Fatalf("generate client keypair: %v", err)
|
||||
}
|
||||
|
||||
const listenPort = 58920 // fixed loopback test port, matches this package's existing test convention
|
||||
const tcpPort = 58921
|
||||
const udpPort = 58922
|
||||
listenPort := freeUDPPort(t)
|
||||
tcpPort, udpPort := freeTCPUDPPort(t), freeTCPUDPPort(t)
|
||||
const clientAddr = "10.202.0.2"
|
||||
|
||||
inst := amneziawg.Instance{
|
||||
@@ -510,7 +508,7 @@ func waitPortForwardSlots(t *testing.T, slots chan struct{}, want int) {
|
||||
}
|
||||
|
||||
func TestPortForwardUDPSessionsAreCapped(t *testing.T) {
|
||||
const port = 58913
|
||||
port := freeUDPPort(t)
|
||||
const free, sources = 3, 10
|
||||
held := leavePortForwardSlots(t, portForwardUDPSlots, free)
|
||||
|
||||
@@ -551,7 +549,7 @@ func TestPortForwardUDPSessionsAreCapped(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestPortForwardTCPConnectionsAreCapped(t *testing.T) {
|
||||
const port = 58914
|
||||
port := freePort(t)
|
||||
const free, clients = 3, 10
|
||||
held := leavePortForwardSlots(t, portForwardTCPSlots, free)
|
||||
|
||||
|
||||
@@ -77,7 +77,7 @@ func TestSocksRelayAgainstRealXray(t *testing.T) {
|
||||
t.Fatalf("generate client keypair: %v", err)
|
||||
}
|
||||
|
||||
const listenPort = 58715
|
||||
listenPort := freeUDPPort(t)
|
||||
inst := amneziawg.Instance{
|
||||
Id: 4,
|
||||
InterfaceName: "awgtest4",
|
||||
@@ -305,7 +305,7 @@ func TestManagerEnsureAutomaticallyWiresRelay(t *testing.T) {
|
||||
}
|
||||
|
||||
const wantEmail = "manager-e2e-peer@example.com"
|
||||
const listenPort = 58716
|
||||
listenPort := freeUDPPort(t)
|
||||
const inboundID = 5
|
||||
|
||||
tcpEcho, tcpEchoAddr := startTCPEcho(t, localIP)
|
||||
@@ -595,6 +595,39 @@ func freePort(t *testing.T) int {
|
||||
return l.Addr().(*net.TCPAddr).Port
|
||||
}
|
||||
|
||||
// freeUDPPort asks the OS for a free loopback UDP port: a fixed one sits in the
|
||||
// Linux ephemeral range, where any concurrent :0 socket can already hold it.
|
||||
func freeUDPPort(tb testing.TB) int {
|
||||
tb.Helper()
|
||||
pc, err := net.ListenPacket("udp", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
tb.Fatal(err)
|
||||
}
|
||||
defer pc.Close()
|
||||
return pc.LocalAddr().(*net.UDPAddr).Port
|
||||
}
|
||||
|
||||
// freeTCPUDPPort finds a loopback port free for both protocols, since a port
|
||||
// forward binds a TCP and a UDP listener on the same number.
|
||||
func freeTCPUDPPort(t *testing.T) int {
|
||||
t.Helper()
|
||||
for range 20 {
|
||||
l, err := net.Listen("tcp", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
port := l.Addr().(*net.TCPAddr).Port
|
||||
pc, err := net.ListenPacket("udp", fmt.Sprintf("127.0.0.1:%d", port))
|
||||
l.Close()
|
||||
if err == nil {
|
||||
pc.Close()
|
||||
return port
|
||||
}
|
||||
}
|
||||
t.Fatal("no loopback port free for both TCP and UDP")
|
||||
return 0
|
||||
}
|
||||
|
||||
func waitForPort(t *testing.T, port int) {
|
||||
t.Helper()
|
||||
deadline := time.Now().Add(15 * time.Second)
|
||||
|
||||
@@ -34,7 +34,7 @@ func TestNewDeviceUDPHandlerAndReply(t *testing.T) {
|
||||
t.Fatalf("generate client keypair: %v", err)
|
||||
}
|
||||
|
||||
const listenPort = 58713 // distinct from the TCP test's port
|
||||
listenPort := freeUDPPort(t)
|
||||
const wantEmail = "udp-test-peer@example.com"
|
||||
const echoPayload = "hello-from-client"
|
||||
|
||||
|
||||
@@ -305,7 +305,7 @@ func TestManagerRemoveLeavesHostOwnedAddressInPlace(t *testing.T) {
|
||||
inst := amneziawg.Instance{
|
||||
Id: 7,
|
||||
InterfaceName: "awgtest7",
|
||||
ListenPort: 58717,
|
||||
ListenPort: 0,
|
||||
PrivateKey: priv,
|
||||
PublicKey: pub,
|
||||
Address: []string{"10.207.0.1/24", "fd86:ea04:1115::1/64"},
|
||||
|
||||
Reference in New Issue
Block a user