DNS 科普·从 DNS 到 DNS 劫持

本文为科普向,文字描述较为浅显易懂,不适合想要深入了解的读者。

Get Started

在了解 DNS 劫持是怎么进行之前,我们需要先了解 DNS 是怎么进行的。这里回到一道经典的面试题:

当你在浏览器里输入 www.baidu.com 时做了哪些事情?

这道题之所以经典,是因为千人千面,你能从「前端」、「后端」、「运维」、「Devops」这几种工种中得到截然不同的答案。

而今天讨论的就是这个问题的第一步:「DNS」。

考虑到这是一篇科普向的文章,我们用一句话解释下 「What is DNS」。

DNS 可以看做一个 domain to IP 的黄页,你告诉它域名,它给你对应的 IP 地址。

那么下一个问题:「DNS 是怎么运作的」。

如图所示,一个用户发起请求后经过浏览器和 ISP 的 DNS 解析器(英文通常是 DNS resolver 或者 Local DNS),然后经由「根域名服务器」、「TLD 域名服务器」和「权威域名服务器」,最终拿到一个域名的门牌号。

17003745014829.jpg
下一个问题是,图中的每个节点到底是拿来做什么的呢?

域名解析绑定

在完全开始之前,一次域名购买到解析的经历能帮助你更好的理解这一切。以 cloudflare 为例,假设你的域名放在 cloudflare 解析,那么 cloudflare 会为你提供两个 NS 记录:
17003745598837.jpg
并且告诉你将这俩 NS 记录绑定到你的域名上。

绑定成功并验证通过后,你就可以进行下一步操作,也就是进行记录绑定了:
17003745693070.jpg

节点解析

简单消化一下,上面的插叙并非突发奇想,而会构成你理解下面步骤的重要部分。

根据上图中讲到的步骤,我们用更拟人的方式来解释每一步:

  1. 用户键入了「codesky.me」这个地址后,首先先问本地的 DNS 记录(你在 Network 的 DNS 设置里能看到对应的 IP,通常第一跳指向路由器),DNS 记录转发去路由器,路由器中下一跳的 IP 地址。路由器说:「你等等,我去帮你问问 ISP,你这个域名的门牌号是什么」。(图中步骤 1)
  2. ISP 收到了请求,但它也不知道,不过作为一个优秀的中间商,它选择问出来了再告诉你。「让我先去挨个问问」ISP 这么想。(图中步骤 2)
  3. 于是它先找了根域名服务器,毕竟现在他还没有任何线索,根域名服务器说,「.me 啊,你去找 .me TLD 域名服务器吧,这是他的名片」。(图中步骤 3、4)
  4. 于是 ISP 又找到了 TLD 域名服务器,TLD 域名服务器说:「codesky.me 啊,它在我这里登记的 NS 记录是这个,你去那边找他吧」(图中步骤 5、6)
  5. 好不容易,ISP 总算是到了「权威域名服务器」处(比如上文我们绑的 cloudflare),权威域名服务器吭哧吭哧的找到对应的 A 记录,返回给 ISP。ISP 总算使命必达了。(图中 7、8)
  6. ISP 拿着对应的 IP 回复路由器,路由器再回复给用户,这下,你总算能访问「codesky.me」了。(图中的 9、10)

然而,如果你绑定的不是一条 A 记录,而是 Cname:
17003746284354.jpg
那么可能「DNS 解析器」又要重新跑一遍了。

而实际上,我们会发现,本图中的步骤数字有些特殊之处—— ISP 自己全问了一遍,而用户到路由器、路由器到 ISP 只是在躺平等通知,这就是两类查询类型:「迭代查询」和「递归查询」。

节点缓存

当然,倒也不用每次都这么辛苦,毕竟「一切能被缓存的东西终将被缓存」。拿你的这一次访问来说,实际上浏览器第一步会先问问自己:「我有缓存吗?」有的话我就不挣扎了(Chrome 浏览器缓存可见:chrome://net-internals/#dns)

如果没有,Chrome 在进行一次系统调用,让操作系统干活。但操作系统说:「且慢,让我来看看我有没有缓存」。

等到操作系统也确认自己没有缓存了,他再去路由器里问(下面同理不再赘述,台词不好编)。
当然,并不需要完全命中也行:假设查完 dashboard.var.moe,他指向了一个 CNAME f.var.moe,但 f.var.moe 之前已经查询过了,那也是可以直接用的。

所以劫持是什么

这里我们说的劫持更多的是个中性词,因为它不止能违法乱纪,还能做些特殊的引流操作。

过去我们往往听到的词是「运营商(ISP)劫持」,运营商个个是人才,说话又好听,可以看到,上文的链路中一直是经过 ISP 的,ISP 自然也是希望降本提效的,因此他会尽可能的缓存下来结果,方便下一次更快的返回,但黑心商户做的可能不止这么多,他们甚至可能会缓存整个网页信息,直接指向一个缓存后的网页而并非你的源站,大聪明觉得:这样我不是更省钱了?你还会觉得访问特别快。

病毒或者木马的劫持是另一种,同样都是基于缓存「直接返回」做的恶。

而在公司内部我们提到劫持的时候,就显得单纯不少了,我们只是在第一跳中将某某域名强制绑定在某个 IP 中,比如在办公网环境下绑定了一个 1.2.3.4 到 codesky.me,那么我们向公司的路由器(或者交换机,或者上游解析服务器)请求时,「DNS 解析器」直接说「不用找了,去 1.2.3.4」。而如果在服务器机房内调用时,由于不经过对应的解析服务器,所以就会按照你绑定的记录正常访问。

17003746742572.jpg

为什么劫持有时候会失败

从上文中我们知道了为什么我们会需要分开来挨个配置不同场景的 DNS 劫持:「DNS 解析器不一样」。

那么失败又是为什么呢?试想一下这样的场景:

公司今天新买了一批用来做办公网访问的设备,小明配置好了,能联网了,但是忘了还要更新劫持清单。

「忘了」,就是最简单的理由,也就是设备列表没理清楚,少更新了。

如何体验:自己搭建一个 DNS 服务器

可以参考 2017 年我曾经写过的一篇文章(实际上我自己都忘了):[[翻译]在 macOS 使用 Dnsmasq 进行本地开发](https://www.codesky.me/archives/macos-dnsmasq-to-local-dev.wind),你可以通过 dnsmasq 体验一个「DNS 解析器」的配置与运行。

附录

DNS Records

上述我们所提到的 NS、A 记录以及 CNAME,如果是初次接触 DNS 的读者一定会疑问:这到底是什么东西,实际上 DNS 记录不只有上面说的几种,但常用的就那么几个,简单介绍一下:

  • A 记录:保存域名 IPV4 门牌号。
  • AAAA:保存 IPV6 门牌号。
  • CNAME:你去找谁(域名)问。
  • NS:谁是权威。

当然,A 和 AAAA 可以不止一条,他会以循环的方式以此请求,以便进行多 IP 的负载均衡。
另外:iOS 一直在实验 HTTPS 记录,它还是一个 rfc:https://www.rfc-editor.org/rfc/rfc9460.html,用于传递更多信息,比如:

example.com 3600 IN HTTPS 1 . alpn=”h3,h2” ipv4hint=”192.0.2.1” ipv6hint=”2001:db8::1”

这一记录中表明支持的 HTTP 版本和 ipv4、ipv6 的地址,设备会同时发起对 A / AAAA / HTTPS 的请求,如上文 HTTPS 记录中的信息表示齐全,那么就不会使用 A / AAAA 的内容了。

Reference

植入部分

如果您觉得文章不错,可以通过赞助支持我。

如果您不希望打赏,也可以通过关闭广告屏蔽插件的形式帮助网站运作。

标签: 知识

添加新评论