diff --git a/internal/amneziawgnet/bench_test.go b/internal/amneziawgnet/bench_test.go index a63327f14..b10ef3724 100644 --- a/internal/amneziawgnet/bench_test.go +++ b/internal/amneziawgnet/bench_test.go @@ -8,7 +8,6 @@ import ( "testing" "time" - awgconn "github.com/amnezia-vpn/amneziawg-go/v3/conn" "github.com/amnezia-vpn/amneziawg-go/v3/device" "github.com/amnezia-vpn/amneziawg-go/v3/tun/netstack" "gvisor.dev/gvisor/pkg/buffer" @@ -159,7 +158,7 @@ func newBenchTunnel(b *testing.B, listenPort int, serverAddr, clientAddr string) if err != nil { b.Fatalf("client CreateNetTUN: %v", err) } - clientDev := device.NewDevice(clientTun, awgconn.NewDefaultBind(), device.NewLogger(device.LogLevelSilent, "")) + clientDev := device.NewDevice(clientTun, newListenBind(""), device.NewLogger(device.LogLevelSilent, "")) clientPrivHex, err := wireguard.KeyToHex(clientPriv) if err != nil { diff --git a/internal/amneziawgnet/device_test.go b/internal/amneziawgnet/device_test.go index 0cecc488e..268290168 100644 --- a/internal/amneziawgnet/device_test.go +++ b/internal/amneziawgnet/device_test.go @@ -10,7 +10,6 @@ import ( "testing" "time" - awgconn "github.com/amnezia-vpn/amneziawg-go/v3/conn" "github.com/amnezia-vpn/amneziawg-go/v3/device" "github.com/amnezia-vpn/amneziawg-go/v3/tun/netstack" "gvisor.dev/gvisor/pkg/tcpip/adapters/gonet" @@ -107,7 +106,7 @@ func TestNewDeviceHandshakeForwarderAndIdentity(t *testing.T) { if err != nil { t.Fatalf("client CreateNetTUN: %v", err) } - clientDev := device.NewDevice(clientTun, awgconn.NewDefaultBind(), device.NewLogger(device.LogLevelSilent, "")) + clientDev := device.NewDevice(clientTun, newListenBind(""), device.NewLogger(device.LogLevelSilent, "")) defer clientDev.Close() clientPrivHex, err := wireguard.KeyToHex(clientPriv) @@ -314,7 +313,7 @@ func TestNewDeviceHeaderProtectionAndContentPaddingRoundTrip(t *testing.T) { if err != nil { t.Fatalf("client CreateNetTUN: %v", err) } - clientDev := device.NewDevice(clientTun, awgconn.NewDefaultBind(), device.NewLogger(device.LogLevelSilent, "")) + clientDev := device.NewDevice(clientTun, newListenBind(""), device.NewLogger(device.LogLevelSilent, "")) defer clientDev.Close() clientPrivHex, err := wireguard.KeyToHex(clientPriv) @@ -492,7 +491,7 @@ func TestNewDeviceRandomTrailersAndDisableCookiesRoundTrip(t *testing.T) { if err != nil { t.Fatalf("client CreateNetTUN: %v", err) } - clientDev := device.NewDevice(clientTun, awgconn.NewDefaultBind(), device.NewLogger(device.LogLevelSilent, "")) + clientDev := device.NewDevice(clientTun, newListenBind(""), device.NewLogger(device.LogLevelSilent, "")) defer clientDev.Close() clientPrivHex, err := wireguard.KeyToHex(clientPriv) diff --git a/internal/amneziawgnet/diagnostics_test.go b/internal/amneziawgnet/diagnostics_test.go index a70055a67..41b6af011 100644 --- a/internal/amneziawgnet/diagnostics_test.go +++ b/internal/amneziawgnet/diagnostics_test.go @@ -8,7 +8,6 @@ import ( "testing" "time" - awgconn "github.com/amnezia-vpn/amneziawg-go/v3/conn" "github.com/amnezia-vpn/amneziawg-go/v3/device" "github.com/amnezia-vpn/amneziawg-go/v3/tun/netstack" "gvisor.dev/gvisor/pkg/tcpip/adapters/gonet" @@ -111,7 +110,7 @@ func TestDiagnoseDeviceReportsListenPortAndPeerState(t *testing.T) { if err != nil { t.Fatalf("client CreateNetTUN: %v", err) } - clientDev := device.NewDevice(clientTun, awgconn.NewDefaultBind(), device.NewLogger(device.LogLevelSilent, "")) + clientDev := device.NewDevice(clientTun, newListenBind(""), device.NewLogger(device.LogLevelSilent, "")) defer clientDev.Close() clientPrivHex, err := wireguard.KeyToHex(clientPriv) diff --git a/internal/amneziawgnet/main_test.go b/internal/amneziawgnet/main_test.go new file mode 100644 index 000000000..be784b102 --- /dev/null +++ b/internal/amneziawgnet/main_test.go @@ -0,0 +1,11 @@ +package amneziawgnet + +import ( + "os" + "testing" +) + +func TestMain(m *testing.M) { + wildcardBindHost = "127.0.0.1" + os.Exit(m.Run()) +} diff --git a/internal/amneziawgnet/pinned_bind.go b/internal/amneziawgnet/pinned_bind.go index f9b5c075b..4e8ea9917 100644 --- a/internal/amneziawgnet/pinned_bind.go +++ b/internal/amneziawgnet/pinned_bind.go @@ -162,15 +162,26 @@ func newListenBind(listen string) awgconn.Bind { if raw != "" && !isWildcardListen(raw) { logger.Warningf("amneziawgnet: listen %q is not a bindable IP; using dual-stack wildcard", raw) } - return awgconn.NewDefaultBind() + return wildcardBind() } if !listenBindable(addr) { logger.Warningf("amneziawgnet: listen %q is not usable on this host; using dual-stack wildcard", raw) - return awgconn.NewDefaultBind() + return wildcardBind() } return newPinnedBind(addr) } +// wildcardBindHost replaces "all interfaces" for every host socket this package +// opens; TestMain pins it to loopback so Windows Firewall never prompts. +var wildcardBindHost = "" + +func wildcardBind() awgconn.Bind { + if wildcardBindHost != "" { + return newPinnedBind(netip.MustParseAddr(wildcardBindHost)) + } + return awgconn.NewDefaultBind() +} + // normalizedListenFP collapses wildcard spellings so fingerprint rebuilds // only when the effective Bind actually changes. func normalizedListenFP(listen string) string { diff --git a/internal/amneziawgnet/pinned_bind_test.go b/internal/amneziawgnet/pinned_bind_test.go index e0e66a262..2dcdda717 100644 --- a/internal/amneziawgnet/pinned_bind_test.go +++ b/internal/amneziawgnet/pinned_bind_test.go @@ -74,6 +74,9 @@ func TestNewListenBindPinsSpecificAddress(t *testing.T) { } func TestNewListenBindWildcardUsesDefault(t *testing.T) { + prev := wildcardBindHost + wildcardBindHost = "" + t.Cleanup(func() { wildcardBindHost = prev }) for _, listen := range []string{"", "0.0.0.0", "::", "::0", "[::]", "hostname.example", "203.0.113.10", "not-an-ip"} { bind := newListenBind(listen) if _, ok := bind.(*pinnedBind); ok { diff --git a/internal/amneziawgnet/portfwd.go b/internal/amneziawgnet/portfwd.go index 92e16dc9a..9f5d6c48c 100644 --- a/internal/amneziawgnet/portfwd.go +++ b/internal/amneziawgnet/portfwd.go @@ -23,9 +23,9 @@ package amneziawgnet import ( "context" - "fmt" "net" "net/netip" + "strconv" "sync" "time" @@ -304,7 +304,7 @@ type tcpForwardListener struct { // result as "not open this round" and retries on every future Reconcile // call for as long as the key stays desired. func listenPortForwardTCP(gstack *stack.Stack, inboundID int, key portForwardKey, target portForwardTargetFunc) *tcpForwardListener { - ln, err := (&net.ListenConfig{}).Listen(context.Background(), "tcp", fmt.Sprintf(":%d", key.port)) + ln, err := (&net.ListenConfig{}).Listen(context.Background(), "tcp", net.JoinHostPort(wildcardBindHost, strconv.Itoa(key.port))) if err != nil { logger.Warningf("amneziawgnet: port-forward: inbound %d peer %q: listen tcp :%d: %v", inboundID, key.email, key.port, err) return nil diff --git a/internal/amneziawgnet/portfwd_test.go b/internal/amneziawgnet/portfwd_test.go index 1c8f81811..573910719 100644 --- a/internal/amneziawgnet/portfwd_test.go +++ b/internal/amneziawgnet/portfwd_test.go @@ -10,7 +10,6 @@ import ( "testing" "time" - awgconn "github.com/amnezia-vpn/amneziawg-go/v3/conn" "github.com/amnezia-vpn/amneziawg-go/v3/device" "github.com/amnezia-vpn/amneziawg-go/v3/tun/netstack" "gvisor.dev/gvisor/pkg/tcpip/stack" @@ -190,7 +189,7 @@ func TestPortForwardSetReconcileSurvivesPreBoundPort(t *testing.T) { const collidingPort = 58911 const okPort = 58912 - blocker, err := net.Listen("tcp", fmt.Sprintf(":%d", collidingPort)) + blocker, err := net.Listen("tcp", fmt.Sprintf("127.0.0.1:%d", collidingPort)) if err != nil { t.Fatalf("pre-bind test port: %v", err) } @@ -284,7 +283,7 @@ func TestPortForwardRoundTripTCPAndUDP(t *testing.T) { if err != nil { t.Fatalf("client CreateNetTUN: %v", err) } - clientDev := device.NewDevice(clientTun, awgconn.NewDefaultBind(), device.NewLogger(device.LogLevelSilent, "")) + clientDev := device.NewDevice(clientTun, newListenBind(""), device.NewLogger(device.LogLevelSilent, "")) defer clientDev.Close() // clientDev.Close() closes the tun's packet channel without waiting for // writers, so every goroutine writing into clientNet must be gone first. diff --git a/internal/amneziawgnet/portfwd_udp.go b/internal/amneziawgnet/portfwd_udp.go index 5f1125ad5..1c315bcb5 100644 --- a/internal/amneziawgnet/portfwd_udp.go +++ b/internal/amneziawgnet/portfwd_udp.go @@ -2,9 +2,9 @@ package amneziawgnet import ( "context" - "fmt" "net" "net/netip" + "strconv" "sync" "time" @@ -46,7 +46,7 @@ type udpForwardListener struct { // toward target(key.email). Bind-failure contract matches // listenPortForwardTCP exactly: log, return nil, Reconcile retries later. func listenPortForwardUDP(gstack *stack.Stack, inboundID int, key portForwardKey, target portForwardTargetFunc) *udpForwardListener { - pc, err := (&net.ListenConfig{}).ListenPacket(context.Background(), "udp", fmt.Sprintf(":%d", key.port)) + pc, err := (&net.ListenConfig{}).ListenPacket(context.Background(), "udp", net.JoinHostPort(wildcardBindHost, strconv.Itoa(key.port))) if err != nil { logger.Warningf("amneziawgnet: port-forward: inbound %d peer %q: listen udp :%d: %v", inboundID, key.email, key.port, err) return nil diff --git a/internal/amneziawgnet/relay_e2e_test.go b/internal/amneziawgnet/relay_e2e_test.go index bd1eef366..ce4ba4ea7 100644 --- a/internal/amneziawgnet/relay_e2e_test.go +++ b/internal/amneziawgnet/relay_e2e_test.go @@ -13,7 +13,6 @@ import ( "testing" "time" - awgconn "github.com/amnezia-vpn/amneziawg-go/v3/conn" "github.com/amnezia-vpn/amneziawg-go/v3/device" "github.com/amnezia-vpn/amneziawg-go/v3/tun/netstack" "gvisor.dev/gvisor/pkg/tcpip/adapters/gonet" @@ -196,7 +195,7 @@ func TestSocksRelayAgainstRealXray(t *testing.T) { if err != nil { t.Fatalf("client CreateNetTUN: %v", err) } - clientDev := device.NewDevice(clientTun, awgconn.NewDefaultBind(), device.NewLogger(device.LogLevelSilent, "")) + clientDev := device.NewDevice(clientTun, newListenBind(""), device.NewLogger(device.LogLevelSilent, "")) defer clientDev.Close() clientPrivHex, err := wireguard.KeyToHex(clientPriv) @@ -421,7 +420,7 @@ func TestManagerEnsureAutomaticallyWiresRelay(t *testing.T) { if err != nil { t.Fatalf("client CreateNetTUN: %v", err) } - clientDev := device.NewDevice(clientTun, awgconn.NewDefaultBind(), device.NewLogger(device.LogLevelSilent, "")) + clientDev := device.NewDevice(clientTun, newListenBind(""), device.NewLogger(device.LogLevelSilent, "")) defer clientDev.Close() clientPrivHex, err := wireguard.KeyToHex(clientPriv) diff --git a/internal/amneziawgnet/udp_test.go b/internal/amneziawgnet/udp_test.go index d24f3a146..c2d79307b 100644 --- a/internal/amneziawgnet/udp_test.go +++ b/internal/amneziawgnet/udp_test.go @@ -6,7 +6,6 @@ import ( "testing" "time" - awgconn "github.com/amnezia-vpn/amneziawg-go/v3/conn" "github.com/amnezia-vpn/amneziawg-go/v3/device" "github.com/amnezia-vpn/amneziawg-go/v3/tun/netstack" "gvisor.dev/gvisor/pkg/tcpip" @@ -98,7 +97,7 @@ func TestNewDeviceUDPHandlerAndReply(t *testing.T) { if err != nil { t.Fatalf("client CreateNetTUN: %v", err) } - clientDev := device.NewDevice(clientTun, awgconn.NewDefaultBind(), device.NewLogger(device.LogLevelSilent, "")) + clientDev := device.NewDevice(clientTun, newListenBind(""), device.NewLogger(device.LogLevelSilent, "")) defer clientDev.Close() clientPrivHex, err := wireguard.KeyToHex(clientPriv)