Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I get the CNAME of a host for which DNS resolution fails (NXDOMAIN) in Go?

Tags:

go

dns

cname

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?

like image 767
jub0bs Avatar asked Jul 02 '19 15:07

jub0bs


People also ask

What is the CNAME record on a DNS server?

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.

How is a CNAME resolved?

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.


1 Answers

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.
}

like image 82
Peter Avatar answered Sep 23 '22 21:09

Peter