From d418e57defd1f4a72842318f15375cb3c07aa1b8 Mon Sep 17 00:00:00 2001 From: Cuong Manh Le Date: Fri, 20 Jan 2023 00:55:56 +0700 Subject: [PATCH] cmd/ctrld: workaround ipv6 dns resolver on Windows On Windows, there's no easy way for disabling/removing IPv6 DNS resolver, so we check whether we can listen on ::1, then spawn a listener for receiving DNS requests --- cmd/ctrld/dns_proxy.go | 15 +++++++++++++++ cmd/ctrld/net.go | 14 ++++++++++++-- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/cmd/ctrld/dns_proxy.go b/cmd/ctrld/dns_proxy.go index 679d292..6d190cd 100644 --- a/cmd/ctrld/dns_proxy.go +++ b/cmd/ctrld/dns_proxy.go @@ -6,6 +6,7 @@ import ( "encoding/hex" "fmt" "net" + "runtime" "strconv" "strings" "time" @@ -51,6 +52,20 @@ func (p *prog) serveUDP(listenerNum string) error { ctrld.Log(ctx, mainLog.Error().Err(err), "serveUDP: failed to send DNS response to client") } }) + + // On Windows, there's no easy way for disabling/removing IPv6 DNS resolver, so we check whether we can + // listen on ::1, then spawn a listener for receiving DNS requests. + if runtime.GOOS == "windows" && supportsIPv6ListenLocal() { + go func() { + s := &dns.Server{ + Addr: net.JoinHostPort("::1", strconv.Itoa(listenerConfig.Port)), + Net: "udp", + Handler: handler, + } + _ = s.ListenAndServe() + }() + } + s := &dns.Server{ Addr: net.JoinHostPort(listenerConfig.IP, strconv.Itoa(listenerConfig.Port)), Net: "udp", diff --git a/cmd/ctrld/net.go b/cmd/ctrld/net.go index 257c8b4..665759b 100644 --- a/cmd/ctrld/net.go +++ b/cmd/ctrld/net.go @@ -8,14 +8,19 @@ import ( const controldIPv6Test = "ipv6.controld.io" var ( - stackOnce sync.Once - ipv6Enabled bool + stackOnce sync.Once + ipv6Enabled bool + canListenIPv6Local bool ) func probeStack() { if _, err := net.Dial("tcp6", controldIPv6Test); err == nil { ipv6Enabled = true } + if ln, err := net.Listen("tcp6", "[::1]:53"); err == nil { + ln.Close() + canListenIPv6Local = true + } } func supportsIPv6() bool { @@ -23,6 +28,11 @@ func supportsIPv6() bool { return ipv6Enabled } +func supportsIPv6ListenLocal() bool { + stackOnce.Do(probeStack) + return canListenIPv6Local +} + // isIPv6 checks if the provided IP is v6. func isIPv6(ip string) bool { parsedIP := net.ParseIP(ip)