HOME

DNS 101

DNS全称Domain Name System,是我们每天都在使用的基础互联网设施。

它被发明出来的原因很简单,计算机之间的通信用的是IP地址,是一串数字,人类记忆起来十分不方便,因此,我们给地址起个名字,然后将名字和IP之间的关系记录起来,这样,我们只用记住名字就行了。

从上面可以看出,DNS系统类似我们日常使用的电话本,只不过里面存储的是域名和IP之间的关系。和人与电话之间的关系一样,一个域名可以有多个IP,一个IP也可以有多个域名。

基本概念

现在我们来介绍几个DNS系统的概念。

DNS Server: DNS服务器,这是我们获取DNS服务的入口。每台上网的计算机都需要配置DNS服务器的IP地址,之后所有的域名查询,就通过询问这个服务器完成。

Record: 记录,域名在DNS系统的一条配置,称为一条记录。最常见的记录就是域名对应的IP是什么。

Record Type: 记录类型,除了域名对应的IP,域名还有别的信息,比如域名对应的邮件服务器是什么等等,也就是,记录有不同的类型。

常见的记录类型如下:

  • A: Address记录,域名对应的IPv4地址
  • AAAA: 域名对应的IPv6地址
  • MX: 域名对应的电子邮件服务器地址
  • NS: 域名对应的域名服务器域名,有点绕,简单来说,你想知道A域名的信息,需要去问A域名的NS记录对应的域名
  • CNAME: 域名的Canonical Name,类似于文件系统中的链接

这里是完整的记录列表

当我们购买了域名以后,就可以在服务商提供的配置系统中设置域名的相关记录。一般来说,服务商会默认配置两条NS记录到他们的域名服务器,当然,我们也可以修改这个记录,使用第三方域名服务器,比如DNS Pod

分级结构

互联网的规模太大,域名数量更是数不胜数,一台DNS Server将这些数据都存储下来是不现实的,因此DNS在设计的时候,采用的是分级结构,每一部分存储下一级的相关信息。

举个例子,我们想知道www.example.com的IP地址是什么,将这个请求发送给了我们的DNS Server。

DNS Server需要先问根域名服务器,谁负责管理.com?然后再问.com域名服务器,谁负责管理example.com?最后,再问example.com域名服务器,www.example.com的IP地址是什么,从而获得答案返回给我们。

这就是域名的分级结构,域名查询需要从根开始,一级一级的向下,直到获得答案。

当然,因为域名查询是一个高频词的动作,无时无刻都在发生,如果每次都是这样一层一层获取,效率将十分低下,因此,DNS系统中大量使用缓存,每一个中间环节都会缓存相关结果来节省时间提高效率。

根域名服务器

上面的描述引入了一个问题。因为我们每次查询(不考虑缓存)都需要询问根域名服务器,那么DNS Server是如何得知根域名服务器的地址呢?

答案是使用配置文件写死,就是这么简单。

目前全世界一共有13组根域名服务器,分别是[a-m].root-servers.net

IANA提供了根域名服务器配置文件,下载下来配置相关的DNS软件就行了。

常用工具

DNS相关的常用工具有两个,一个是dig,功能强大,十分灵活。

用法是dig <记录类型> <查询名称>

例如,我想知道根域名服务器的相关信息。

$ dig ns . # 注意,`.`代表根域名,这条指令表示查询根域名的NS记录
; <<>> DiG 9.8.3-P1 <<>> ns .
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 12846
;; flags: qr rd ra; QUERY: 1, ANSWER: 13, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;.        IN  NS

;; ANSWER SECTION:
.     40368 IN  NS  h.root-servers.net.
.     40368 IN  NS  m.root-servers.net.
.     40368 IN  NS  f.root-servers.net.
.     40368 IN  NS  c.root-servers.net.
.     40368 IN  NS  e.root-servers.net.
.     40368 IN  NS  l.root-servers.net.
.     40368 IN  NS  k.root-servers.net.
.     40368 IN  NS  a.root-servers.net.
.     40368 IN  NS  i.root-servers.net.
.     40368 IN  NS  b.root-servers.net.
.     40368 IN  NS  d.root-servers.net.
.     40368 IN  NS  g.root-servers.net.
.     40368 IN  NS  j.root-servers.net.

;; Query time: 10 msec
;; SERVER: 116.228.111.118#53(116.228.111.118)
;; WHEN: Tue May  1 16:53:16 2018
;; MSG SIZE  rcvd: 228

从返回的结果可以看出,根域名有13条NS记录,对应13组域名服务器。

使用dig获取cjting.me的IPv4地址。

$ dig cjting.me # 记录类型默认为`A`
; <<>> DiG 9.8.3-P1 <<>> cjting.me
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 25983
;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;cjting.me.     IN  A

;; ANSWER SECTION:
cjting.me.    598 IN  A 192.30.252.153
cjting.me.    598 IN  A 192.30.252.154

;; Query time: 10 msec
;; SERVER: 116.228.111.118#53(116.228.111.118)
;; WHEN: Tue May  1 16:55:06 2018
;; MSG SIZE  rcvd: 59

可以看到,cjting.me这个域名有两条A记录,即查询到了两条IP地址。

第二个指令是host指令,相比dig指令,功能比较简单,输出也比较简洁。

使用host获取cjting.me的相关信息。

$ host cjting.me
cjting.me has address 192.30.252.154
cjting.me has address 192.30.252.153

一次完整的查询

dig有一个很高级的功能,叫做trace,即可以追踪输出每一级查询的具体信息,而不是只给一个最终结果。

下面我们来看一个完整的例子,dig +trace cjting.me,看看到底发生了哪些请求,最终的IP地址是如何得到的。

$ dig +trace cjting.me
; <<>> DiG 9.8.3-P1 <<>> +trace cjting.me @8.8.8.8
;; global options: +cmd
.                       209918  IN      NS      a.root-servers.net.
.                       209918  IN      NS      m.root-servers.net.
.                       209918  IN      NS      b.root-servers.net.
.                       209918  IN      NS      l.root-servers.net.
.                       209918  IN      NS      f.root-servers.net.
.                       209918  IN      NS      d.root-servers.net.
.                       209918  IN      NS      j.root-servers.net.
.                       209918  IN      NS      i.root-servers.net.
.                       209918  IN      NS      g.root-servers.net.
.                       209918  IN      NS      k.root-servers.net.
.                       209918  IN      NS      e.root-servers.net.
.                       209918  IN      NS      h.root-servers.net.
.                       209918  IN      NS      c.root-servers.net.
;; Received 228 bytes from 8.8.8.8#53(8.8.8.8) in 117 ms

me.                     172800  IN      NS      a2.nic.me.
me.                     172800  IN      NS      a0.nic.me.
me.                     172800  IN      NS      c0.nic.me.
me.                     172800  IN      NS      b0.nic.me.
me.                     172800  IN      NS      b2.nic.me.
;; Received 336 bytes from 199.9.14.201#53(199.9.14.201) in 768 ms

cjting.me.              86400   IN      NS      f1g1ns2.dnspod.net.
cjting.me.              86400   IN      NS      f1g1ns1.dnspod.net.
;; Received 81 bytes from 199.253.60.1#53(199.253.60.1) in 361 ms

cjting.me.              600     IN      A       192.30.252.154
cjting.me.              600     IN      A       192.30.252.153
cjting.me.              86400   IN      NS      f1g1ns1.dnspod.net.
cjting.me.              86400   IN      NS      f1g1ns2.dnspod.net.
;; Received 123 bytes from 180.163.19.15#53(180.163.19.15) in 8 ms

dig会输出每一步的关键信息,但并不完整。例如,第二段中,dig询问199.9.14.201获取到了.me域名的相关信息,但是199.9.14.201这个IP是如何来的呢?

下面我列出这中间发生的完整步骤,假设我的本机IP是192.168.0.100,DNS Server的IP是192.168.0.1。

  1. 192.168.0.100 -> 192.168.0.1: .的NS记录是什么?
  2. 192.168.0.1 -> 192.168.0.100: 是a.root-servers.net, b.root-servers.net… 3.
    • 192.168.0.100 -> 192.168.0.1: a.root-servers.net的A记录是什么?
    • 192.168.0.1 -> 192.168.0.100: 是198.41.0.4
    • 192.168.0.100 -> 192.168.0.1: b.root-servers.net的A记录是什么?
    • 192.168.0.1 -> 192.168.0.100: 是199.9.14.201
    • dig会选择一个IP进行下一步,同时该地址对应的IP会被缓存起来,此时选中的是199.9.14.201
  3. 192.168.0.100 -> 199.9.14.201: cjting.me的A记录是什么?
  4. 199.9.14.201 -> dig: .me的NS记录是a2.nic.me, b0.nic.me… 6.
    • 192.168.0.100 -> 192.168.0.1: b0.nic.me的A记录是什么?
    • 192.168.0.1 -> 192.168.0.100: 是199.253.60.1
    • 192.168.0.100 -> 192.168.0.1: a2.nic.me的A记录是什么?
    • 192.168.0.1 -> 192.168.0.100: 是199.253.59.1
    • dig会选择一个IP进行下一步,同时该地址对应的IP会被缓存,此时选中的是199.253.60.1
  5. 192.168.0.100 -> 199.253.60.1: cjting.me的A记录是什么?
  6. 199.253.60.1 -> dig: cjting.me的NS记录是f1g1ns1.dnspod.netf1g1ns2.dnspod.net 9.
    • 192.168.0.100 -> 192.168.0.1: f1g1ns2.dnspod.net的A记录是什么?
    • 192.168.0.1 -> 192.168.0.100: 是182.140.167.188, 101.226.220.16, …
    • 192.168.0.100 -> 192.168.0.1: f1g1ns1.dnspod.net的A记录是什么?
    • 192.168.0.1 -> 192.168.0.100: 是61.151.180.44, 58.247.212.36, …
    • dig会选择一个进行下一步,同时该地址对应的IP会被缓存,此时选中的是180.163.19.15
  7. 192.168.0.100 -> 180.163.19.15: cjting.me的A记录是什么?
  8. 180.163.19.15 -> 192.168.0.100: A记录是192.30.252.154和192.30.252.153, NS记录是f1g1ns1.dnspod.net和f1g1ns2.dnspod.net
  9. 至此整个过程结束

可以看出,一共进行了1 + 1 + 13*2 + 1 + 1 + 5*2 + 1 + 1 + 2*2 + 1 + 1 = 48次通信(请求+响应),可见,如果不进行缓存的话,DNS是多么地浪费资源。