前言
Cracking the code interview 中有一道题:当你在浏览器中输入一个URL,并按下 Enter后都发生了什么?,在 Github 上有一个仓库:what-happens-when-zh_CN 也介绍了在浏览器中输入URL后发生的事情,其中都只是简单地介绍了 DNS 域名解析的过程,但其实域名解析远比这个复杂,因此本文将介绍关于 DNS 的基础知识。
本文演讲PPT请参见:xiazdong.github.io/slides/dns
DNS 相关介绍
DNS 基本概念
DNS(Domain Name System, 域名系统) 是互联网的基础设施,主要负责域名解析,即负责将域名转换成 IP 地址。1983 年由 Paul Mockapetris 设计出来。
域名是一个树状结构构成的,如下图,每个域名对应一个或多个 DNS 服务器,域名解析请求也是从上到下一步一步进行下发的。
下面介绍两个基本概念:
- Zone: 以上图来说,就是一棵子树。比如”.com”的 Zone 就是以 “.com” 为根的子树。因此 “www.taobao.com” 是在 “.com” 的 Zone 里的。
- Domain: 树中的一条路径。比如 “taobao.com.” 是 Domain,”www.taobao.com.” 也是 Domain。
从上图可知,域名(Domain)分成很多类:
- 根域名(Root Domain): 是树状结构的根,在 URL 中对应的是:”.”。全世界一共有13个根域名服务器(每个服务器都是一个集群,通过 Anycast 技术共用一个 IP),这13个根域名服务器的名字分别是
[A-M].root-servers.net
,根域名服务器的分布图如下:
- 顶级域名(Top Level Domain, TLD): 根域名的下一层,URL 中对应例如:”.com”,”.cn”,”.net”。TLD 分成两类:
- gTLD(generic TLD, 国际顶级域名): 比如
.com
,.net
。 - ccTLD(Country Code TLD, 国家和地区顶级域名): 比如
.cn
,.jp
。
- gTLD(generic TLD, 国际顶级域名): 比如
- 二级域名(Second Level Domain):这层就是一般我们用钱去 Godaddy 买的域名,比如”taobao.com”。
- 三级、四级域名…
URL 就是一个由”.”分隔的字符串,总长度必须小于等于255字节,每个分隔的子串必须小于等于63字节。其实完整的每个URL都是以”.”结尾的,比如”www.taobao.com.”,只是现在大家默认都会省去这个点。
为了完成域名解析,不得不介绍一下 Local DNS。
- 一般上网我们都是设置为 DHCP(Dynamic Host Configuration Protocol)的,Local DNS 是你连上网之后,由网络服务提供商(ISP, Internet Service Provider, 比如移动、连通、电信)自动就近分配(地理位置尽量近以加快域名解析的速度)给计算机的(一般会分配两个,一个主DNS,一个备用DNS),因此 Local DNS 是由 ISP 自己维护的, ISP 还会为计算机分配 IP。如果你想自己设置 DNS 也是可以的(可以是公共 DNS,比如 AliDNS 或 Google 的
8.8.8.8
),这样计算机就不使用 Local DNS 了。 - 因为 Root DNS 的13个 IP 都是公开的,因此一般 Local DNS 会以静态文件的形式内置这13个 Root DNS 的 IP。
Local DNS 是负责帮你完成域名解析的大功臣,你只需要把 DNS 域名解析的报文请求发送给 Local DNS,它会以递归的方式帮你完成一系列的请求解析(因为要不断请求不同层级的 DNS,先从根 DNS 开始,再到 TLD,…),并最终返回给你域名的 IP。 Local DNS 执行流程如下图:
> - 内网 IP: 这是局域网内部的IP地址,输入
ipconfig
看到的是内网IP,比如 “192.168.0.103”。> - 公网 IP: 这是运营商分配的IP地址,这个地址并不是你电脑独占的,比如我在家里电脑和手机连的是同一个网,那么他们共享同一个公网 IP。在百度里输入 IP,就能看到自己的外网 IP。
查看公网 IP 和 Local DNS 的 IP 的简便方法是访问:阿里的昆仑镜或者腾讯的华佗。
> 如果要自己搭一个 DNS 服务器,一般使用 BIND(Berkeley Internet Name Domain)。
### DNS 分类
- 递归 DNS:负责接收域名解析请求,并帮助用户一次又一次递归地请求不同的 DNS 服务器,最后得到 IP 并返回给用户。比如 Local DNS, 公共 DNS。
- 权威 DNS:保存某个域 DNS 解析的权威信息,怎么解析他说了算。 至于哪个 DNS 服务器是权威 DNS,则在上一级的 Zone File 中通过 NS 记录设置。比如为了让 DNSPod 的 “f1g1ns1.dnspod.net”和” f1g1ns2.dnspod.net” 作为 “xiazdong.me” 的权威 DNS,必须要到 Godaddy 中设置 Nameserver(即设置 NS 记录:
xiazdong.me NS f1g1ns1.dnspod.net
),表明现在 “xiazdong.me” 有两个权威 DNS 服务器。> 一个 DNS 既可以作为递归 DNS,也可以同时作为权威 DNS,即当 DNS 请求该 DNS 负责的域名时,则进行解析;当 DNS 请求不是他负责的域名时,则作为递归 DNS 使用。
### DNS 攻击
- DNS 劫持(DNS Hijacking or DNS redirection):攻击的人会 劫持 DNS 服务器,并获得管理权限,从而修改映射关系。常见的 DNS 劫持是 DNS 广告劫持,现象是比如你访问”www.taobao.com”,会在页面上弹出一个不相关广告,这是运营商干的,Local DNS 是 ISP 管理的,当你发一个 DNS 域名请求到 Local DNS,他会将 DNS 响应报文中的 IP 改成自己搭的广告服务器的IP,他预先会写一个静态页面在广告服务器,其中
<iframe>
依旧请求原页面,但是区别是多加一些代码用来弹广告。这个解决方法就是投诉。- DNS 污染(DNS cache poisoning):DNS 服务器的缓存映射被篡改。假设 Root DNS 被污染,那么如果用户请求 “www.taobao.com”,Root DNS 直接返回一个假 IP,让用户访问不了淘宝。如果 Root DNS 都被污染了,那就无解了。因此 DNS 劫持是对 DNS 服务器本身做修改,而 DNS 污染是对 DNS 服务器缓存做修改。
- DDOS(Distributed Deny Of Service, 分布式拒绝服务): 搞一堆肉机,制造大量 DNS 解析请求,大量提升 QPS,导致 DNS 服务器的带宽被塞满,无法为其他用户提供服务。一些常见的解决方法是:黑名单(不对黑名单中 IP 提供 DNS 解析请求服务)、白名单(只对白名单中的 IP 提供 DNS 解析请求服务)。
### DNS Zone File
DNS Zone File(DNS 区域文件)是每个 DNS 服务器都需要有的一个文本文件,用来进行域名解析。一般格式如下:
|
解释如下:
- 文件中每行都是一个资源记录(Resource Record,RR),资源记录有很多类型,比如 SOA(Start Of Authority), A(Address), NS(Name Server), MX(Mail eXchange), CNAME(别名,一般出于调度考虑)。
-
$ORIGIN example.com.
: 这个 Zone File 的 DNS 的域是 “example.com.”-
$TTL 1h
: 该文件的记录的最大存活时间是1小时。-
example.com. IN SOA ns.example.com. username.example.com.
: “example.com.” 的首选 DNS 服务器是 “ns.example.com.”,管理员邮箱是”username@example.com.”。-
example.com. IN NS ns
: “ns.example.com.” 是 “example.com” 的 Nameserver。-
example.com. IN NS ns.somewhere.example.
: “ns.somewhere.example.” 是 “example.com” 的另一个 Nameserver。-
example.com. IN MX 10 mail.example.com.
: “mail.example.com.” 是 “example.com.” 的邮件服务器,优先级是10(优先级数字越小,则优先级越高)。MX 表示 Mail eXchange。-
@ IN MX 20 mail2.example.com.
: 也是设置邮件服务器,优先级是20。-
@ IN MX 50 mail3
: “mail3.example.com.” 是 “example.com” 的邮件服务器,优先级是50。-
example.com. IN A 192.0.2.1
: “example.com” 的 IPv4 地址是 “192.0.2.1”。-
IN AAAA 2001:db8:10::1
: “example.com” 的IPv6 地址是 “2001:db8:10::1”。-
ns IN A 192.0.2.2
: “ns.example.com.” 的 IPv4 地址是 “192.0.2.2”。-
www IN CNAME example.com.
: “www.example.com.” 是 “example.com” 的别名。-
wwwtest IN CNAME www
: “wwwtest.example.com.” 是 “www.example.com.” 的别名。-
mail IN A 192.0.2.3
: “mail.example.com” 的 IPv4 地址是 “192.0.2.3”。-
mail2 IN A 192.0.2.4
: “mail2.example.com” 的 IPv4 地址是 “192.0.2.4”。-
mail3 IN A 192.0.2.5
: “mail3.example.com” 的 IPv4 地址是 “192.0.2.5”。那么 CNAME 能不能被 A 替代呢?答案是不能,主要是看需求。因为:
- 定义不同: A 记录对应的是 IP,CNAME 对应的是 URL,他只是域名解析的中间结果,因此 CNAME 引入了中间态。
- 应用场景不同: 如果我想把某个域名指向 google.com,而 google.com 有很多 IP 地址,而且可能随时会更换,因此最好的方式是通过 CNAME 指向 google.com,而不是用 A 记录指向 google.com 对应的一个 IP 地址。
一般来说,一个域名的 DNS 服务器会有很多台,会以 Master-Slave 的形式部署,而每台 Master 或 Slave 都会有 Zone File,Slave 会通过 AXFR(全量传输), IXFR(增量传输) 或 Notify 的方式同步 Master 的 Zone File。如下图:
从上面这张图看出:Remote Admin 是 DNSPod 提供的操作界面,当你修改了记录后,他会同步到 Master 的 Zone File 中,并通知 Slave 更新。
DNSPod 的权威 DNS 是”f1g1ns1.dnspod.net”和” f1g1ns2.dnspod.net”,我的博客”xiazdong.me”的权威 DNS 设置成了这两个 URL,为了让这个权威 DNS 生效,我需要去申请域名的平台(Godaddy)将 DNS NameServer 设置为这两个 URL,这样才能够生效,一般来说 Master DNS 服务器和 Slave DNS 服务器都是权威 DNS。如果你在 DNSPod 平台上修改 A 记录,那么会把修改同步到 Master DNS 服务器,Slave 再通过某种方式同步 Master 的 Zone File。
域名解析全过程
比如你在 Chrome 中输入 “www.taobao.com”,并按下回车,域名解析会进行如下步骤:
- 查看浏览器 DNS 缓存。Chrome 可以通过
chrome://net-internals/#dns
查看浏览器的 DNS 缓存,一般这些缓存的 TTL(Time To Live) 是几分钟。 - 查看系统 DNS 缓存。 Windows 可以通过
ipconfig /displaydns
查看系统 DNS 缓存。这里面包含了 hosts 文件设置的映射,有时候修改了 hosts 文件后,为了让 hosts 文件生效,需要执行ipconfig /flushdns
。 - 查看路由器 DNS 缓存。
- 查看 Local DNS 的 DNS 缓存。这部分缓存是由 ISP 自己实现,有些 ISP 为了减少域名解析次数,会将缓存的 TTL 特意变长一点,比如原来 TTL=10min,但是 ISP 自己实现的时候,设置缓存的时间是30min。这也会导致你更改了 DNS 服务器的 A 记录后不能马上生效的原因。
- 如果这些缓存都没有域名对应的IP,那么 Local DNS 会帮你递归地开始进行域名解析。
- 因为在 Local DNS 中内置了 13个 Root DNS 的 IP,因此任意选择一个 Root DNS 的 IP 发起 DNS 解析请求报文,当 Root DNS 收到 Local DNS 的请求后,会发现这个 URL 的顶级域名是 “.com”,因此他会把 “.com” 的 DNS 服务器的 IP(通常会发13个 “.com” 的服务器的 IP)发送给 Local DNS 作为响应。
- Local DNS 收到 Root DNS 的响应后,会继续把请求发送给 “.com” 的 DNS 服务器(它的 IP 从 Root DNS 的响应中获得),”.com” 的 DNS 服务器收到请求后,会发现这个 URL 的二级域名是 “taobao.com”,因此会把 “taobao.com” 的 DNS 服务器的 IP(通常也会有多个)发送给 Local DNS 作为响应。
- Local DNS 收到 “.com” DNS 的响应后,会继续把请求发送给 “.taobao.com” 的 DNS 服务器(它的 IP 从 “.com” DNS 的响应中获得),”taobao.com” 的 DNS 服务器收到请求后,会发现这个 URL 的子域名是 “www.taobao.com”,那么会把 “www.taobao.com” 的 DNS 服务器的 IP 发送给 Local DNS 作为响应。当然这里可能会有一个问题,因为”www.taobao.com”会有多个IP对应,那么到底返回哪个IP呢?一般 DNS 会有调度原则,实现方法是:DNS 服务器会内置一个 IP 库,会根据请求源的 IP(Local DNS 的 IP) 确定他的国家、地区、运营商,因此会返回就近的 IP,这就实现了就近调度。一般 CDN(Content Delivery Network, 内容分发网络, 主要存储静态文件如 CSS, JS)的实现原理就是这样。
- Local DNS 收到了 “www.taobao.com” 的 IP,也就完成了任务,他会把这个 IP 送回给计算机。
- 域名请求和响应是以 UDP 协议发送的。
- RTT(Round Trip Time): 一次请求+响应的时间。
- TTL(Time To Live): 当 DNS 服务器返回 IP 时,会带有 TTL,表示这个映射你能缓存的时间,比如 TTL=10min,那么这个映射关系只能缓存10分钟,10分钟之后就过期了。但是 ISP 的 Local DNS 可能并不会那么听话,他可能会缓存半个小时。
在无线端的域名解析,需要提几点:
- 在开发移动应用时,为了节省域名解析的时间,采用”IP直连“的方式,即在应用中内置可能会用到的域名的 IP(比如手机淘宝可能会访问的域名其实都是可预料的),这样就省去了域名解析的时间(一般解析时间在200ms-400ms)。
- 由于 Local DNS 运维水平参差不齐,可能会出现 DNS 劫持、ISP 分配给用户的 Local DNS 不在一个地区,又因为一个应用可能会访问的域名是固定的,因此大公司都会自己实现一套异步的 DNS 解析,比如腾讯的 HttpDNS。
HttpDNS 的实现思路是:
- 开辟一个线程,从应用启动后定期地发起 HttpDNS 的域名解析请求(同时可以请求解析多个域名)到 HttpDNS 服务器(定期发起请求是因为怕 IP 过期),该请求走 HTTP 协议,然后 HttpDNS 服务器把 HTTP 请求转换成 DNS 请求,并对后端的 DNS 服务器进行 DNS 域名解析请求,当解析完成后,会将请求域名的 IP 地址送回给客户端,并缓存起来。
- 当应用发起网络请求,会首先看 HttpDNS 的缓存中是不是存在已经解析好的 IP 地址,如果有,则直接拿来用(这里可能会出现 IP 过期,也需要降级走 Local DNS);如果没有,则降级走 Local DNS。
dig 命令
上一节已经介绍了 DNS 域名解析的基本流程,本节我们通过 Linux 中的 dig(Domain Information Groper) 命令来验证这个解析流程。以 dig +trace www.taobao.com
为例。
输出如下:
|