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)