Golang 获取域名 DNS 信息的几种方法

在 Go 语言中,获取域名的 IP 地址和 DNS 信息有多种方法,下面介绍几种常用的实现方式:

图片[1]_Golang 获取域名 DNS 信息的几种方法_知途无界

1. 使用 net.Lookup 系列函数

Go 标准库中的 net 包提供了几个方便的 DNS 查询函数:

package main

import (
    "fmt"
    "net"
)

func main() {
    // 获取域名的所有 A 记录 (IPv4 地址)
    ips, err := net.LookupIP("example.com")
    if err != nil {
        fmt.Println("LookupIP error:", err)
        return
    }
    fmt.Println("IP addresses:")
    for _, ip := range ips {
        fmt.Println(ip)
    }

    // 获取域名的 CNAME 记录
    cname, err := net.LookupCNAME("www.example.com")
    if err != nil {
        fmt.Println("LookupCNAME error:", err)
        return
    }
    fmt.Println("CNAME:", cname)

    // 获取域名的 MX 记录
    mxs, err := net.LookupMX("example.com")
    if err != nil {
        fmt.Println("LookupMX error:", err)
        return
    }
    fmt.Println("MX records:")
    for _, mx := range mxs {
        fmt.Printf("Host: %s, Pref: %d\n", mx.Host, mx.Pref)
    }

    // 获取域名的 TXT 记录
    txts, err := net.LookupTXT("example.com")
    if err != nil {
        fmt.Println("LookupTXT error:", err)
        return
    }
    fmt.Println("TXT records:")
    for _, txt := range txts {
        fmt.Println(txt)
    }

    // 获取域名的 NS 记录
    nss, err := net.LookupNS("example.com")
    if err != nil {
        fmt.Println("LookupNS error:", err)
        return
    }
    fmt.Println("NS records:")
    for _, ns := range nss {
        fmt.Println(ns.Host)
    }
}

2. 使用 net.Resolver 进行更灵活的 DNS 查询

如果需要更细粒度的控制,可以使用 net.Resolver

package main

import (
    "context"
    "fmt"
    "net"
    "time"
)

func main() {
    r := &net.Resolver{
        PreferGo: true,
        Dial: func(ctx context.Context, network, address string) (net.Conn, error) {
            d := net.Dialer{
                Timeout: time.Millisecond * time.Duration(10000),
            }
            return d.DialContext(ctx, "udp", "8.8.8.8:53")
        },
    }

    ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
    defer cancel()

    // 查询 A 记录
    ips, err := r.LookupIPAddr(ctx, "example.com")
    if err != nil {
        fmt.Println("LookupIPAddr error:", err)
        return
    }
    fmt.Println("IP addresses:")
    for _, ip := range ips {
        fmt.Println(ip.IP)
    }

    // 查询 SRV 记录
    _, srvs, err := r.LookupSRV(ctx, "service", "tcp", "example.com")
    if err != nil {
        fmt.Println("LookupSRV error:", err)
        return
    }
    fmt.Println("SRV records:")
    for _, srv := range srvs {
        fmt.Printf("Target: %s, Port: %d, Priority: %d, Weight: %d\n",
            srv.Target, srv.Port, srv.Priority, srv.Weight)
    }
}

3. 使用第三方库 (如 github.com/miekg/dns)

对于更高级的 DNS 查询需求,可以使用专业的 DNS 库:

package main

import (
    "fmt"
    "github.com/miekg/dns"
)

func main() {
    domain := "example.com"
    server := "8.8.8.8:53" // Google Public DNS

    c := new(dns.Client)
    m := new(dns.Msg)
    m.SetQuestion(dns.Fqdn(domain), dns.TypeA)
    m.RecursionDesired = true

    r, _, err := c.Exchange(m, server)
    if err != nil {
        fmt.Println("DNS query error:", err)
        return
    }

    if r.Rcode != dns.RcodeSuccess {
        fmt.Println("DNS query failed:", dns.RcodeToString[r.Rcode])
        return
    }

    fmt.Println("DNS records:")
    for _, ans := range r.Answer {
        switch record := ans.(type) {
        case *dns.A:
            fmt.Printf("A record: %s\n", record.A)
        case *dns.AAAA:
            fmt.Printf("AAAA record: %s\n", record.AAAA)
        case *dns.CNAME:
            fmt.Printf("CNAME record: %s\n", record.Target)
        case *dns.MX:
            fmt.Printf("MX record: %s (pref %d)\n", record.Mx, record.Preference)
        case *dns.TXT:
            fmt.Printf("TXT record: %s\n", record.Txt)
        case *dns.NS:
            fmt.Printf("NS record: %s\n", record.Ns)
        }
    }
}

4. 获取本地 DNS 配置

如果需要查看系统的 DNS 配置:

package main

import (
    "fmt"
    "net"
)

func main() {
    // 获取系统 DNS 配置
    conf, err := net.ResolverConfigFile()
    if err != nil {
        fmt.Println("Error getting resolver config:", err)
        return
    }
    fmt.Println("Resolver config file:", conf)

    // 获取系统 DNS 服务器
    servers, err := net.LookupNS(".")
    if err != nil {
        fmt.Println("Error getting system DNS servers:", err)
        return
    }
    fmt.Println("System DNS servers:")
    for _, s := range servers {
        fmt.Println(s.Host)
    }
}

注意事项

  1. DNS 缓存:Go 的 net 包会缓存 DNS 查询结果,可以使用 net.DefaultResolver.PreferGo = true 绕过系统缓存
  2. 超时处理:生产环境中应该总是设置合理的超时
  3. 并发限制:大量 DNS 查询时需要考虑并发限制
  4. DNS 服务器选择:对于关键应用,建议指定可靠的 DNS 服务器而非依赖系统默认

以上方法可以根据实际需求选择使用,标准库方法适合大多数简单场景,而第三方库则提供了更专业的 DNS 查询能力。

© 版权声明
THE END
喜欢就点个赞,支持一下吧!
点赞90 分享
评论 抢沙发
头像
欢迎您留下评论!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容