I'm looking for a way (in Go) to get the CNAME (if any) of a given host, whether that host's DNS resolution fails or not.
The DNS resolution of a host may fail and yield NXDOMAIN
, but the host in question may still have a CNAME record. At the time of writing this question, tst1crmapps.starbucks.com
is an example of such a host:
$ dig tst1crmapps.starbucks.com | grep -E 'NXDOMAIN|CNAME'
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 50444
tst1crmapps.starbucks.com. 86400 IN CNAME bigip-tst1crmapps-starbucks.oracle.com.
(run on macOS)
Function net.LookupCNAME
seems to be right up my alley, but it fails to return the CNAME if the host's DNS resolution fails. Running
package main
import (
"log"
"net"
)
func main() {
cname, err := net.LookupCNAME("tst1crmapps.starbucks.com")
if err != nil {
log.Fatal(err)
}
log.Println(cname)
}
yields
yyyy/MM/dd hh:mm:ss lookup tst1crmapps.starbucks.com: no such host
Am I misunderstanding net.LookupCNAME
? Or am I using the wrong function?
A Canonical Name or CNAME record is a type of DNS record that maps an alias name to a true or canonical domain name. CNAME records are typically used to map a subdomain such as www or mail to the domain hosting that subdomain's content.
DNS Resolution Process for CNAME RecordsA DNS resolver receives the request and finds the Authoritative Name Server that holds the DNS Zone file with DNS records for the “example.com” domain. The DNS request is resolved and the CNAME record is returned to the client.
Go's LookupCNAME function tries to follow a CNAME chain all the way to its end. This means it considers a DNS name without both CNAME and A records an error:
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.
Go does not provide a low-level DNS API in the standard library. The de-facto standard package to use for that is github.com/miekg/dns (error handling and type checking elided for brevity):
package main
import (
"fmt"
"github.com/miekg/dns"
)
func main() {
config, _ := dns.ClientConfigFromFile("/etc/resolv.conf")
c := new(dns.Client)
m := new(dns.Msg)
// Note the trailing dot. miekg/dns is very low-level and expects canonical names.
m.SetQuestion("tst1crmapps.starbucks.com.", dns.TypeCNAME)
m.RecursionDesired = true
r, _, _ := c.Exchange(m, config.Servers[0]+":"+config.Port)
fmt.Println(r.Answer[0].(*dns.CNAME).Target) // bigip-tst1crmapps-starbucks.oracle.com.
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With