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太过于耦合了
- Dialer的Resolver是个struct, 我要实现我自己的Resolver呢
- Resover的resolveAddrList、internetAddrList方法里包含了对addr检查和过滤的逻辑,但是没有暴露给用户。比如是否为unxi检查,是否有端口的检查,还有一些地址的校验逻辑。