Golang DNS解析

func Dial(network, address string) (Conn, error)net.Dialer

net.Dialer

DialContextResolver *Resolver
Resolver *Resolver

Resolver的工作流程如下:




使用cgo还是purego去解析

在图中步骤4中,会计算出解析方式的顺序,顺序有5种。分为两类

hostLookupCgo

其它四个是另一类,表示go去读取文件/etc/hosts和/etc/resolv.conf去解析,files表示先看看/etc/hosts有没有对应的记录,dns表示通过/etc/resolv.conf的server去解析。四个指定了不同的解析方式顺序

/etc/nsswitch.conf

如果你确定你机器上有/etc/hosts和/etc/resolv.conf这两个文件,而且格式正确,应用程序有访问权限,那个你可以设置Resovler.PreferGo=true,强制使用purego。

DNS缓存

但你通过net.Dial或者net.DialContext去创建连接,或者使用Resolver去解析DNS时,都是没有缓存的。这个意思就是说你每创建一个连接,Resolver都回去解析一次。那我们肯定需要一个dns缓存,如果dns server挂掉了不会影响到我们呀。

但有个特别坑爹的地方, Resolver是个struct,不是个interface,这样我们就没办法直接实现一个Resolver,然后替换掉Dialer里的Resolver。

Resolver.resolverAddrListResolver.LookupIPAddr
dialer.Dialer.DialContextDialer.DialContext

带缓存的Resolver,很简单,就是定时去解析一下,你也可以实现一个带有过期时间的缓存。

go的Dialer和Resover需要改进的地方

现在的Dialer和Resover太过于耦合了

  1. Dialer的Resolver是个struct, 我要实现我自己的Resolver呢
  2. Resover的resolveAddrList、internetAddrList方法里包含了对addr检查和过滤的逻辑,但是没有暴露给用户。比如是否为unxi检查,是否有端口的检查,还有一些地址的校验逻辑。