9

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?

3
  • Add a '.' at the end and it should work. had the same issue and fixed it like that. For reference serverfault.com/a/1085782 Commented Jun 24, 2024 at 12:41
  • @Apolonius Not sure what you're referring to. Adding a trailing dot changes nothing to the output of my program. Commented Jun 25, 2024 at 4:10
  • I had the same issue with "no such host" error. Adding a dot at the end resolved it for me. I am using Azure DNS Zone. Maybe it differs somehow from other DNS services Commented Jun 25, 2024 at 11:32

1 Answer 1

13

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

Sign up to request clarification or add additional context in comments.

1 Comment

I'm surprised the standard library doesn't provide the functionality I was looking for. Thanks for this!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.