From 129e4f5292124784211c88ab700a709760889e76 Mon Sep 17 00:00:00 2001 From: Jay Hemnani <193022578+jayhemnani9910@users.noreply.github.com> Date: Tue, 3 Nov 2026 20:22:09 +0530 Subject: [PATCH] fix(link): keep IPv6 brackets in imported wireguard endpoints (#6976) parseWireguard joined u.Hostname(), which strips IPv6 brackets, with the port, so wireguard://key@[2001:db8::1]:51820 became 2001:db8::1:51820 and Xray's ParseDestination rejected it. The endpoint is now built with net.JoinHostPort, matching the frontend parser; IPv4 and hostname endpoints are unchanged. --- internal/util/link/outbound.go | 3 ++- internal/util/link/outbound_helpers_test.go | 22 +++++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/internal/util/link/outbound.go b/internal/util/link/outbound.go index 5a64164b5..930cfc97c 100644 --- a/internal/util/link/outbound.go +++ b/internal/util/link/outbound.go @@ -10,6 +10,7 @@ import ( "fmt" "maps" "math" + "net" "net/url" "regexp" "slices" @@ -657,7 +658,7 @@ func parseWireguard(link string) (*ParseResult, error) { portStr := u.Port() endpoint := host if portStr != "" { - endpoint = host + ":" + portStr + endpoint = net.JoinHostPort(host, portStr) } addrRaw := firstParam(params, "address", "ip") diff --git a/internal/util/link/outbound_helpers_test.go b/internal/util/link/outbound_helpers_test.go index 254c891f8..d8755dc1f 100644 --- a/internal/util/link/outbound_helpers_test.go +++ b/internal/util/link/outbound_helpers_test.go @@ -431,6 +431,28 @@ func TestParse_VmessFinalMask(t *testing.T) { } } +func TestParseWireguard_Endpoint(t *testing.T) { + cases := []struct { + link string + want string + }{ + {"wireguard://key@a.com:51820?publickey=pub#x", "a.com:51820"}, + {"wireguard://key@1.2.3.4:51820?publickey=pub#x", "1.2.3.4:51820"}, + {"wireguard://key@[2001:db8::1]:51820?publickey=pub#x", "[2001:db8::1]:51820"}, + {"wireguard://key@a.com?publickey=pub#x", "a.com"}, + } + for _, c := range cases { + res, err := ParseLink(c.link) + if err != nil { + t.Fatalf("parse %s: %v", c.link, err) + } + peer := res.Outbound["settings"].(map[string]any)["peers"].([]any)[0].(map[string]any) + if peer["endpoint"] != c.want { + t.Errorf("%s: endpoint = %v, want %q", c.link, peer["endpoint"], c.want) + } + } +} + func TestParse_RemarkDecodedOnce(t *testing.T) { // Remarks as the subscription server writes them (encodeURIComponent). cases := []struct {