From 95dd871e2d648eafe00d27da4c3002946c22e5a3 Mon Sep 17 00:00:00 2001 From: Codescribe Date: Mon, 30 Mar 2026 13:55:08 -0400 Subject: [PATCH] fix: bracket IPv6 addresses in VPN DNS upstream config upstreamConfigFor() used strings.Contains(":") to detect whether to append ":53", but IPv6 addresses contain colons, so IPv6 servers were passed as bare addresses (e.g. "2a0d:6fc0:9b0:3600::1") to net.Dial which rejects them with "too many colons in address". Use net.JoinHostPort() which handles both IPv4 and IPv6 correctly, producing "[2a0d:6fc0:9b0:3600::1]:53" for IPv6. --- 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 03b5478..bc4b1a1 100644 --- a/cmd/cli/vpn_dns.go +++ b/cmd/cli/vpn_dns.go @@ -2,6 +2,7 @@ package cli import ( "context" + "net" "strings" "sync" @@ -241,10 +242,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",