Description
LookupCNAME is pretty weird right now.
Despite the name, it entirely ignores CNAME records on Unix. It launches A
and AAAA
record lookups to recursive resolvers and returns the first response name found in the A
and AAAA
, skipping over any CNAME
. (and not even asking for a CNAME
)
But it documents that it does that...
https://pkg.go.dev/net#LookupCNAME
A canonical name is the final name after following zero or more CNAME records. LookupCNAME does not return an error if host does not contain DNS "CNAME" records, as long as host resolves to address records.
OTOH, on Windows, it does what you would expect from the name itself: it looks up CNAME records:
func (*Resolver) lookupCNAME(ctx context.Context, name string) (string, error) {
// TODO(bradfitz): finish ctx plumbing. Nothing currently depends on this.
acquireThread()
defer releaseThread()
var r *syscall.DNSRecord
e := syscall.DnsQuery(name, syscall.DNS_TYPE_CNAME, 0, nil, &r, nil)
Here's a demo of a program behaving differently:
func main() {
txt, err := net.LookupTXT("cname-to-txt.go4.org")
log.Printf("LookupTXT = %q, %v", txt, err)
cname, err := net.LookupCNAME("cname-to-txt.go4.org")
log.Printf("cname = %q, %v", cname, err)
}
On Linux/Mac:
2021/12/10 21:19:45 LookupTXT = ["foo=bar"], <nil>
2021/12/10 21:19:45 cname = "", lookup cname-to-txt.go4.org: no such host
On Windows:
2021/12/10 21:11:45 LookupTXT = ["foo=bar"], <nil>
2021/12/10 21:11:45 cname = "test-txt-record.go4.org.", <nil>
I like the Windows behavior better, FWIW. That's what I was looking for, but apparently it doesn't exist.
Can we either:
- add
LookupCNAMERecord
that actually looks up a CNAME record - redefine
LookupCNAME
to be like Windows, perhaps adding aLookupCanonicalName
with the current weird Unix behavior ofLookupCNAME
?
But at minimum: document whatever the rules are and make Unix and Windows match? At least in Resolver.PreferGo
mode?