feat: recognize every NextDNS endpoint under nextdns.io

NextDNS serves alternative DoH endpoints beside dns.nextdns.io: the
ultralow and anycast variants of dns, dns1 and dns2. They are the same
service and take the same client info headers, but isNextDNS matched
the one host, so an upstream pointed at any of them was treated as a
third party and sent no client info.

Recognition now follows the parent domain through dns.IsSubDomain, as
IsControlD already does for the ControlD domains. The label by label
comparison is case insensitive and keeps lookalikes such as
notnextdns.io and nextdns.io.example.com out.

Based on the change proposed by Mike (Github username @mike406).
See: https://github.com/Control-D-Inc/ctrld/pull/335.
This commit is contained in:
Cuong Manh Le committed 2026-09-22 21:08:18 +07:00
1 parent 4879574605
commit 682c6c8a29
2 files changed
+71 -1

No files matched your search

+8 -1
View File
@@ -78,6 +78,12 @@ const (
controlDNetDomain = "controld.net"
controlDDevDomain = "controld.dev"
// nextDNSDomain is the parent domain of the NextDNS DoH endpoints. Beside
// dns.nextdns.io, NextDNS serves alternative endpoints under it, such as
// ultralow.dns.nextdns.io and anycast.dns2.nextdns.io, which are the same
// service and take the same client info headers.
nextDNSDomain = "nextdns.io"
endpointPrefixHTTPS = "https://"
endpointPrefixQUIC = "quic://"
endpointPrefixH3 = "h3://"
@@ -761,6 +767,7 @@ func (uc *UpstreamConfig) IsControlD() bool {
return false
}
// isNextDNS reports whether this is a NextDNS upstream.
func (uc *UpstreamConfig) isNextDNS() bool {
domain := uc.Domain
if domain == "" {
@@ -768,7 +775,7 @@ func (uc *UpstreamConfig) isNextDNS() bool {
domain = u.Hostname()
}
}
return domain == "dns.nextdns.io"
return dns.IsSubDomain(nextDNSDomain, domain)
}
func (uc *UpstreamConfig) dohTransport(ctx context.Context, dnsType uint16) http.RoundTripper {