NameserverNameserverGolangNameserver
DNS解析过程
Golangnet.ResolverLookupHost(ctx context.Context, host string) (addrs []string, err error)
hostsresolv.confnameservernameservernameservernameserver
/etc/resolv.confnameserverkubernetessidecarservicednsPolicyClusterFirst
自定义Nameserver
GolangNameserverResolverhttpClientDialContext()
Resolver
// 默认dialer
dialer := &net.Dialer{
Timeout: 1 * time.Second,
}
// 定义resolver
resolver := &net.Resolver{
Dial: func(ctx context.Context, network, address string) (net.Conn, error) {
return dialer.DialContext(ctx, "tcp", nameserver) // 通过tcp请求nameserver解析域名
},
}
Dialer
type Dialer struct {
dialer *net.Dialer
resolver *net.Resolver
nameserver string
}
// NewDialer create a Dialer with user's nameserver.
func NewDialer(dialer *net.Dialer, nameserver string) (*Dialer, error) {
conn, err := dialer.Dial("tcp", nameserver)
if err != nil {
return nil, err
}
defer conn.Close()
return &Dialer{
dialer: dialer,
resolver: &net.Resolver{
Dial: func(ctx context.Context, network, address string) (net.Conn, error) {
return dialer.DialContext(ctx, "tcp", nameserver)
},
},
nameserver: nameserver, // 用户设置的nameserver
}, nil
}
// DialContext connects to the address on the named network using
// the provided context.
func (d *Dialer) DialContext(ctx context.Context, network, address string) (net.Conn, error) {
host, port, err := net.SplitHostPort(address)
if err != nil {
return nil, err
}
ips, err := d.resolver.LookupHost(ctx, host) // 通过自定义nameserver查询域名
for _, ip := range ips {
// 创建链接
conn, err := d.dialer.DialContext(ctx, network, ip+":"+port)
if err == nil {
return conn, nil
}
}
return d.dialer.DialContext(ctx, network, address)
}
httpClientDialContext()
ndialer, _ := NewDialer(dialer, nameserver)
client := &http.Client{
Transport: &http.Transport{
DialContext: ndialer.DialContext,
TLSHandshakeTimeout: 10 * time.Second,
},
Timeout: timeout,
}
总结
NameserverDailer