From a430372bab645fc4841622419286c57804b40388 Mon Sep 17 00:00:00 2001 From: Codescribe Date: Wed, 1 Apr 2026 06:41:20 -0400 Subject: [PATCH] fix: bracket IPv6 addresses in VPN DNS upstream config upstreamConfigFor() used strings.Contains(":") to decide whether to append ":53", which always evaluates true for IPv6 addresses. This left bare addresses like "2a0d:6fc0:9b0:3600::1" without brackets or port, causing net.Dial to reject with "too many colons in address". Use net.JoinHostPort() which handles IPv6 bracketing automatically, producing "[2a0d:6fc0:9b0:3600::1]:53". --- cmd/cli/vpn_dns.go | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/cmd/cli/vpn_dns.go b/cmd/cli/vpn_dns.go index 6b5fb88..e117ffc 100644 --- a/cmd/cli/vpn_dns.go +++ b/cmd/cli/vpn_dns.go @@ -2,6 +2,7 @@ package cli import ( "context" + "net" "strings" "sync" "sync/atomic" @@ -222,10 +223,12 @@ func (m *vpnDNSManager) Routes() map[string][]string { // upstreamConfigFor creates a legacy upstream configuration for the given VPN DNS server. func (m *vpnDNSManager) upstreamConfigFor(server string) *ctrld.UpstreamConfig { - endpoint := server - if !strings.Contains(server, ":") { - endpoint = server + ":53" - } + // Use net.JoinHostPort to correctly handle both IPv4 and IPv6 addresses. + // Previously, the strings.Contains(":") check would skip appending ":53" + // for IPv6 addresses (they contain colons), leaving a bare address like + // "2a0d:6fc0:9b0:3600::1" which net.Dial rejects with "too many colons". + // net.JoinHostPort produces "[2a0d:6fc0:9b0:3600::1]:53" as required. + endpoint := net.JoinHostPort(server, "53") return &ctrld.UpstreamConfig{ Name: "VPN DNS",