DNS解析查询

我们都知道DNS的概念,DNS允许使用域名代替难记的IP来标识主机,客户端可以使用DNS协议将域名解析为IP地址,这样我们就能通过域名访问服务端了。前面我们经常使用net.Dial()函数来向目标主机发送数据,它也支持传入域名,当我们传域名时,在代码底层实际上就发生了DNS解析将域名解析为了IP地址。实际上,我们也可以调用net包中的相关函数直接实现DNS解析步骤,这篇笔记我们学习Go语言net包中和DNS协议相关的内容。

解析域名记录

net.LookupHost()函数可以解析域名为IP地址(即获取DNS的A记录和AAAA记录),返回结果为字符串数组,它同时支持IPv4和IPv6。

package main

import (
    "fmt"
    "log/slog"
    "net"
)

func main() {
    addrs, err := net.LookupHost("www.google.com")
    if err != nil {
        slog.Error(err.Error())
        return
    }
    for _, addr := range addrs {
        fmt.Println(addr)
    }
}

代码输出如下:

2404:6800:4004:825::2004
142.250.196.132

可以看到输出结果是谷歌www.google.com的IPv4和IPv6地址。

除了net.LookupHost()函数,我们还可以使用net.LookupIP()函数解析域名,它们的作用是类似的,只不过net.LookupIP()函数返回的是net.IP类型。

自定义DNS服务器

Go语言的DNS解析功能还支持自定义DNS服务器,下面例子中我们设置DNS服务器为Cloudflare的公共DNS服务1.1.1.1并基于该DNS服务器解析域名。

package main

import (
    "context"
    "fmt"
    "log/slog"
    "net"
    "time"
)

func main() {
    resolver := &net.Resolver{
        PreferGo: true,
        Dial: func(ctx context.Context, network, address string) (net.Conn, error) {
            d := net.Dialer{
                Timeout: time.Second * 5,
            }
            return d.DialContext(ctx, "udp", "1.1.1.1:53")
        },
    }

    addrs, err := resolver.LookupHost(context.Background(), "www.google.com")
    if err != nil {
        slog.Error(err.Error())
        return
    }
    for _, addr := range addrs {
        fmt.Println(addr)
    }
}

注:这里resolver.LookupHost()需要额外传一个上下文对象,我们使用context.Background()生成了一个空上下文传入。

作者:Gacfox
版权声明:本网站为非盈利性质,文章如非特殊说明均为原创,版权遵循知识共享协议CC BY-NC-ND 4.0进行授权,转载必须署名,禁止用于商业目的或演绎修改后转载。