如何在 Go 中获取 DNS 解析失败(NXDOMAIN)的主机的 CNAME?

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

我正在寻找一种方法(在 Go 中)获取给定主机的 CNAME(如果有的话),无论该主机的 DNS 解析是否失败

主机的 DNS 解析可能会失败并产生 NXDOMAIN,但有问题的主机可能仍有 CNAME 记录。在写这个问题的时候,tst1crmapps.starbucks.com 是这样一个主机的例子:

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

(macOS 上运行)

函数 net.LookupCNAME 似乎正合我意,但如果主机的 DNS 解析失败,它就无法 return CNAME。 运行

package main

import (
    "log"
    "net"
)

func main() {
    cname, err := net.LookupCNAME("tst1crmapps.starbucks.com")
    if err != nil {
        log.Fatal(err)
    }
    log.Println(cname)
}

产量

yyyy/MM/dd hh:mm:ss lookup tst1crmapps.starbucks.com: no such host

我是不是误会了net.LookupCNAME?还是我用错了功能?

Go 的 LookupCNAME 函数会尝试一直跟踪 CNAME 链,直到结束。这意味着它认为没有 CNAME 和 A 记录的 DNS 名称是错误的:

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 在标准库中不提供 low-level DNS API。为此使用的 de-facto 标准包是 github.com/miekg/dns(为简洁起见省略了错误处理和类型检查):

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