关于我遇到的一个DNS问题

34次阅读

共计 5241 个字符,预计需要花费 14 分钟才能阅读完成。

最近遇到一个小问题,在某些用户的请求中会莫名其妙的出现重定向然后导致 404,在这里分享下导致这种问题的原因。
这里不会介绍 DNS 和 CDN,如果想了解请 google 或百度,有好几斤的数据可以看,我也没必要再说了。这篇文章主要是从关于客户端 DNS 解析和 CDN 服务解析的整个流程角度去解释我遇到的这个很幼稚的 bug。
DNS 服务器可以部署在很多阶段
DNS 对于大多数同学来说都可能知道是干嘛的,但是深入了解工作原理可能有些模糊,首先它它分布在很多个阶段,整体分为两大块:本地 DNS 服务,远端 DNS 服务。
本地(Local Resolver)
每台电脑本地都会配置一个 DNS 解析文件,在 Nginx 上我们可以在 /etc/resolv.conf 中查看,当然也可以从界面中查看。
下面是我在 CLI 查看我的本地 DNS 服务配置,即 DNS 客户机配置(/etc/resolv.conf)
下面是我在设置中查看 DNS 服务配置
大家会问,这两个一样吗?只不过一个是在文件系统查看一个是在 GUI 上查看,两者没区别吧?嗯,是的没区别。
实际上,修改本地的 DNS 解析规则,在 Nginx 上有三个地方,分别是
hosts 文件 –> 网卡配置文件 –>DNS 服务器地址配置文件
我们刚才修改的只是系统的 DNS 服务器地址配置文件,当然 GUI 上也是对应的这个文件。前两个配置方式比较粗暴,在这里就不讲了,有伤大雅。
分析一下配置文件中的字段(实际上还有很多,先说两个吧):

domain 提供一个基本的搜索域,解析失败的域名会和这个基本的搜索域拼接,再去做 DNS 解析,看我下面偷的这一句话,就明白它的作用了。例如,如果您指定搜索域为 apple.com,在您的网页浏览器中键入“store”将会前往 store.apple.com。或者,如果使用 campus.university.edu 作为搜索域,那么您可以在“访达”的“连接服务器”对话框中键入“server1”来连接到 server1.campus.university.edu。

nameserver,也就是本地的 DNS 服务器列表,它的格式是 IP 地址,v4 v6 d 都可以,远端或本地地址都可以,甚至这个地址可以填写一个本地的服务,然后我们就可以自定义处理 DNS 解析服务了。

nameserver 这个字段就太好玩了,通常家庭版的地址是 192.168.0.1,也就是大多数路由器的 IP 地址,然后用户可以在自己的路由器设置页面配置 DNS 解析服务器的地址。below

当然,你也可以不使用路由器来转发你的 DNS 解析,直接填写这个根 DNS 服务器地址,也就是图上面的 222.*。
作为程序员,突发奇想,我们还可以玩的更浪一些~~~,就比如:
添加一个本地域名解析服务,也就是添加一个 127.0.0.1 在你的 DNS 配置文件中,注意一定要添加在第一行,别忘了 nameserver 是 in order 的哦。

然后在本地开一个 UDP 服务,监听 53 端口(为什么是 UDP 为什么是 53 端口,好奇同学请 trace here),你就会看到本地的 DNS 处理记录:
let dgram = require(‘dgram’);
let socket = dgram.createSocket(‘udp4′);
// 服务端监听一个端口 数据到来时 可以读出信息
socket.bind(53,’localhost’,function(){
// 读取消息
socket.on(‘message’,function(data,rinfo){
console.log(data.toString());
})
});
下面这些乱七八糟的,就是 DNS 解析记录 …

我们可以修改上面的代码来自定义解析后的信息,我不知道这个返回状态应该怎么设定,没事闲的同学可以去查查怎么可以伪造这个信息,听起来很刺激 … 不过我觉得不太可能,53 端口受特殊保护,就连监听和查看它的占用情况都需要提权,上述代码 linux 上出 EACCES 错的可以加上 sudo,win 提权太麻烦不说了。
说了 一大堆没用的,回正题,现在开始我们假设本地 DNS 服务接受了一个软件的解析请求~~
我们假设上述的 hosts 文件 –> 网卡配置文件 –>DNS 服务器地址配置文件,前两个不做任何处理的情况下。以下顺序处理。

在 DNS 解析服务开始之前,系统会找到本地的这个 DNS 服务器列表,在我这是两个,10.10. and 10.120. 从第一个开始向这个 DNS 服务器发送域名解析请求。
如果第一个处理失败,或者查询不到,就用第二个找。也就是 10.120.*。
如果 10.120.* 也找不到(最后一个 nameserver),那么使用这个 domain 来处理了。

本地 DNS 服务的任务就是接受计算机软件的 DNS 解析服务,去向根 DNS 服务器发送请求,获得最终的 IP 地址。
如果本地有 DNS resolver 的话,也是可以缓存你的 DNS 解析的,什么是 Resover?就是咱们刚才建立在 53 端口的服务,它就是一个 Resolver。
// 验证是否存在 resolver
sduo lsof -i:53
// or 查看 /etc/resolv.conf
resolver 有可能缓存上一次 DNS 解析结果。如果碰到恶意的 resolver,看谁不顺眼就可以筛选所有某站的主域名 (比如竞争对手的 … 嘿嘿) 返回一个不存在的 ip 地址,然后这个域名在那台电脑上就 over 了,除非技术手动撤销这个 resolver,否则卸载重装,重启,统统不好使。
所以,友情提醒:尽量不要使用本地的 DNS resolver。,
根 DNS(Root DNS)
接着从上面的本地 DNS 服务开始说,它把解析请求发送给 20.20.* 服务器,这个服务器就是根 DNS,所有 DNS 解析请求都经过它来转发,根 DNS 服务器免费的没有几个,国内的 114.114* 比较快一点,国外的 Google 的 4 个 8 或者 4 个 1,都是普遍使用的。那么又一个问题,世界上这么多电脑才这么几个服务器,而且每台电脑的 DNS 解析请求是非常频繁的,这几个服务器受得住吗?
首先,它确实是接受所有的请求的,但它不负责处理这个解析,只负责分类并返回子 DNS 服务器 IP。然后 LocalDNS 接收到这个子 DNS 服务器 IP 后,再去向子 DNS 迭代查询。
这个阶段,如果你本地有 DNS 缓存服务的话,它会记住某个域名与它所属的子 DNS 的 IP 地址,下次请求直接去子 DNS 地址,而不用经过 ROOT DNS 处理。
子 DNS
子 DNS 分很多区,这个分类其实就是根据域名的后缀来的,比如,有 COM DNS 服务器,它只负责 com 这个后缀的域名解析。当然还有其他类型的,比如 .cn .net。当然,不可能每个后缀都来一台服务器,流量较少的的后缀应该被分在一个区里。
子 DNS 接到 LocalDNS 请求之后,查询此域名之后发现它已经交给专属 DNS 服务器 (也就是你购买域名时设置的域名解析服务器) 处理
子 DNS 的作用就是帮助 RootDNS 减少很多查库和处理请求的时间。
服务器 DNS
服务器 DNS 属于我们域名下的专属 DNS 服务器,我们可以使用自己的 DNS 服务器配置到你的域名上(申请 DNS 服务器需要到国内注册局申请办理)。
如果是本地内网搭建,就没那么多规则,可以使用 Bind ((Berkeley Internet Name Domain))。
通常,我们在阿里云购买的域名绑定上域名解析就可以了,默认使用的是万网的 DNS 服务器,如果你有自己的 DNS 服务器的话,可以在域名管理中配置。
最后来张图通一通。以我司客户端为例:

LocalDNS 接收到一个客户端发送的域名解析请求,看看本地有没有上次缓存的现成的 hetao101 域下的 DNS 服务器。如果没有,取出第一个 nameserver(也就是根 DNS 服务器),进行迭代查询。如果有,直接跳到第 5 步。

根 DNS 解析我们的 www.hetao101.com 地址属于 com 区,然后把 com 区的子 DNS 服务器的 IP 返回给 LocalDNS 处理。

LocalDNS 收到子 DNS 的 IP,然后再次发送迭代查询向子 DNS

子 DNS 查询数据库,找到 www.hetao101.com 这个域名对应的服务器 DNS 地址,然后把地址返回给 LocalDNS。
LocalDNS 发送请求到 www.hetao101.com 的 DNS 服务器,然后返回给它域名对应的 IP 地址。
LocalDNS 拿到 IP 后非常鸡冻(来回串了这么多服务器终于拿到了),赶紧握握手亲热亲热,然后开始了建立网络通道(e.g TCP)。

注意,以上的递归查询和迭代查询的区别,递归查询的是: 我向 A 请求,A 你必须得给我一个结果,不到黄河不死心。而迭代查询是,我向 A 请求,A 有可能没有这个东西,它把 B 返回给你,让你和 B 问 …

CDN 服务器
网络就是数个灯泡中间的导线,电线长了,电流抵达的速度也就慢了,灯泡亮的速度就慢了。。。
所以,我们在导线的中间加上了一个继电器式的资源服务器。也就是 CDN 服务器。保证资源快速响应给局部用户。
CDN 服务器通常包括一个源站和子节点(其他区域的资源服务器),上传文件到 CDN 服务器首先到达源站,然后源站分发给子节点。
如果源站的资源被替换或者删除,子节点也会与它同步。
简单的打了个比方,具体使用场景及原理,可以自行 Goog,不多说了废话了,下面简单说下我遇到那个问题。
最近遇到一个小问题,在更新资源文件后,在某些用户的请求中会莫名其妙的出现 302 然后重定向地址是 404,在这里分享下导致这种问题的原因。
上下文:这个请求是阿里云 OSS 的,客户是河北沧州移动运营商,重定向后的 IP 地址后面添加相比源路径多了很多层路径,位置是河北石家庄的移动网络。
我一开始的分析是,本地 DNS 服务或运营商缓存了 DNS 解析(阿里云 DNS 解析后的 IP 是可以根据客户端的区域分配就近节点的,所以应该被分到了石家庄节点),然后当我更新这个文件时,由于 ISP 缓存没有到期(假定是 ISP,还有可能是本地 DNS Resolver),然后更新文件后,继续请求上次的解析后的地址(地址上是有文件的 hash 的),导致资源 404(hash 值被更新)。
仔细想一下是不对的,首先 DNS 解析只会返回域名区段,不会给你添加路径。第二如果是阿里云子节点在上传文件到源站的时候,就会同步到各个子节点,所以不会出现 404 的情况。
那么,如果这个重定向的 IP 地址不是阿里云的,难道是运营商自己的,它把响应文件缓存起来,然后放到自己的缓存服务器,如果请求在缓存期内就从运营商自己的缓存服务器里取?我估计这个也不可能,因为,条件是每次在阿里云 OSS 上更新文件时,才会出现这个问题,所以,有两种可能:

因为资源是和阿里云源站同步的,所以,可判定这个地址并不是运营商的地址(是阿里云的)。
DNS 劫持,劫持和缓存一样,区别是前者以攻击为目的,给你返回期望之外的 IP,后者是给你目标 IP。

而当我分析上面说的 302 返回的重定向地址时,我不太确信这是一个 DNS 劫持,因为这地址看起来太正经,如:
http://111.**.135.171/files/317200004364C385/***.oss-cn-beijing.aliyuncs.com/***.zip
第一段 IP,后面的的路径非常有规律,files 下面的 file hash,然后是源站的下载地址。
这么正经的 IP 不可能是被劫持吧,那么再说回去,如果 302 是运营商的 DNS 缓存导致的,302 后的地址也就是这个地址,它是怎么来的呢??
我分别测试了山东和杭州的网络,DNS 解析 ***.oss-cn-beijing.aliyuncs.com 这个源下载地址并没有返回动态子节点 IP,实际上还是 beijing 区的源站 IP,这说明 DNS 解析是没有动态返回节点的。
不是运营商也不是阿里云,究竟是什么?
愁了我一个星期,在阿里云栖社区问了此问题,也没有收到特别准确的回答,因为用户的问题已经使用其他方式修复,所以没有办法再次确定问题,目前只能认为是

DNS 劫持。
运营商缓存文件之后不是直接从他自己文件服务器拿的,而是去向上次阿里云 OSS 的地址取 (是 IP 地址,没有域名),但是我是替换的文件,按道理来说即便是旧的地址运营商向阿里云请求也可以拿到文件呀,这里还有一个小知识。那就是 DNS 解析后的 IP 是不能直接替换域名的,DNS 是为了取 IP,而 IP 是在建立连接层之根基,但是连接层上还有写一层,一些服务器上的 httpserver,比如 Apach 或者 Nginx 会提供一个叫做虚拟站点的功能,简单来说根据你请求的 host(域名) 来分拨出不同的文件路径,也就是说一台服务器是可以享有多个域名的。当然不仅是分拨路径,中间还可以去向其他服务请求(有点像 proxy,但是根据域名来判断的 proxy 分拨),想了解更多请搜索 虚拟站点。

如果你对于我的问题有其他看法,请评论。如果你觉得我说的不对,请纠正(有悬赏)。如果你想跳槽,请看我的个人资料右上角。如果你觉还有点帮助,请使劲儿点个赞。如果你觉得这篇文章浪费了你的时间,没啥干货,请私聊大声的骂我一顿。

正文完
 0