Bläddra i källkod

fix(amneziawg): let the wrapped bind build peer endpoints

resolvingBind.ParseEndpoint resolved a hostname and then built a
StdNetEndpoint itself. That matches StdNetBind, the default bind on
Linux, but on Windows the default is WinRingBind, whose Send refuses any
endpoint it did not parse ("endpoint type does not correspond with bind
type"). Every handshake initiation failed there, so no AmneziaWG tunnel,
inbound or outbound, could come up on the Windows builds. ParseEndpoint
now hands the resolved literal to the wrapped bind's own parser, which
returns the endpoint type that bind sends to; StdNetBind and pinnedBind
build the same StdNetEndpoint as before.

The resolvingBind tests now read endpoints through the Endpoint
interface instead of asserting StdNetEndpoint, which had pinned the bug.
MHSanaei 6 timmar sedan
förälder
incheckning
044e2926a0
2 ändrade filer med 37 tillägg och 10 borttagningar
  1. 3 3
      internal/amneziawgnet/resolving_bind.go
  2. 34 7
      internal/amneziawgnet/resolving_bind_test.go

+ 3 - 3
internal/amneziawgnet/resolving_bind.go

@@ -39,8 +39,8 @@ func newResolvingBind(listen string) *resolvingBind {
 	return &resolvingBind{Bind: newListenBind(listen)}
 }
 
-// ParseEndpoint resolves hostnames before handing the address to amneziawg-go
-// (whose own implementation accepts literal IPs only).
+// ParseEndpoint resolves hostnames, then lets the wrapped bind build the endpoint:
+// its own parser takes literal IPs only, and WinRingBind sends to its own type only.
 func (b *resolvingBind) ParseEndpoint(s string) (awgconn.Endpoint, error) {
 	host, portStr, err := net.SplitHostPort(strings.TrimSpace(s))
 	if err != nil {
@@ -63,5 +63,5 @@ func (b *resolvingBind) ParseEndpoint(s string) (awgconn.Endpoint, error) {
 		}
 		addr = addrs[0]
 	}
-	return &awgconn.StdNetEndpoint{AddrPort: netip.AddrPortFrom(addr.Unmap(), uint16(port64))}, nil
+	return b.Bind.ParseEndpoint(netip.AddrPortFrom(addr.Unmap(), uint16(port64)).String())
 }

+ 34 - 7
internal/amneziawgnet/resolving_bind_test.go

@@ -14,12 +14,39 @@ func mustResolvingBind(t *testing.T) *resolvingBind {
 	return newResolvingBind("")
 }
 
-func endpointAddrPort(ep awgconn.Endpoint) netip.AddrPort {
-	std, ok := ep.(*awgconn.StdNetEndpoint)
-	if !ok {
-		panic("unexpected endpoint type")
+// endpointAddrPort reads any bind's endpoint; Windows' default bind has its own type.
+func endpointAddrPort(t *testing.T, ep awgconn.Endpoint) netip.AddrPort {
+	t.Helper()
+	ap, err := netip.ParseAddrPort(ep.DstToString())
+	if err != nil {
+		t.Fatalf("endpoint %q: %v", ep.DstToString(), err)
+	}
+	return ap
+}
+
+// ownEndpointBind accepts only endpoints it parsed itself, as WinRingBind does.
+type ownEndpointBind struct{ awgconn.Bind }
+
+type ownEndpoint struct{ awgconn.StdNetEndpoint }
+
+func (ownEndpointBind) ParseEndpoint(s string) (awgconn.Endpoint, error) {
+	ap, err := netip.ParseAddrPort(s)
+	if err != nil {
+		return nil, err
+	}
+	return &ownEndpoint{awgconn.StdNetEndpoint{AddrPort: ap}}, nil
+}
+
+// WinRingBind, the default bind on Windows, refuses to send to an endpoint of any
+// other type, so a hand-built StdNetEndpoint killed every handshake there.
+func TestResolvingBind_ParseEndpointComesFromTheWrappedBind(t *testing.T) {
+	ep, err := (&resolvingBind{Bind: ownEndpointBind{}}).ParseEndpoint("203.0.113.7:51820")
+	if err != nil {
+		t.Fatalf("ParseEndpoint: %v", err)
+	}
+	if _, ok := ep.(*ownEndpoint); !ok {
+		t.Fatalf("endpoint is %T, not the wrapped bind's own type", ep)
 	}
-	return std.AddrPort
 }
 
 func TestResolvingBind_ParseEndpointIPLiteral(t *testing.T) {
@@ -28,7 +55,7 @@ func TestResolvingBind_ParseEndpointIPLiteral(t *testing.T) {
 	if err != nil {
 		t.Fatalf("IP endpoint rejected: %v", err)
 	}
-	got := endpointAddrPort(ep)
+	got := endpointAddrPort(t, ep)
 	if got.Addr().String() != "203.0.113.7" || got.Port() != 51820 {
 		t.Fatalf("endpoint = %v, want 203.0.113.7:51820", got)
 	}
@@ -49,7 +76,7 @@ func TestResolvingBind_ParseEndpointHostnameResolves(t *testing.T) {
 	if err != nil {
 		t.Fatalf("hostname endpoint rejected: %v", err)
 	}
-	if got := endpointAddrPort(ep); got.Addr().String() != "198.51.100.9" || got.Port() != 443 {
+	if got := endpointAddrPort(t, ep); got.Addr().String() != "198.51.100.9" || got.Port() != 443 {
 		t.Fatalf("endpoint = %v, want 198.51.100.9:443", got)
 	}
 }