DNS 原理

2019/03/08 计算机网络

整理自DNS 原理入门

DNS(Domain Name System)的作用是根据域名查询对应的 IP 地址,DNS 协议是应用层协议。

查询过程

DNS 的查询过程非常复杂,分成多个步骤。可以用工具dig显示整个查询过程。

$ dig github.com

; <<>> DiG 9.8.3-P1 <<>> github.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 23873
;; flags: qr rd ra; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;github.com.			IN	A

;; ANSWER SECTION:
github.com.		23	IN	A	13.250.177.223
github.com.		23	IN	A	52.74.223.119
github.com.		23	IN	A	13.229.188.59

;; Query time: 22 msec
;; SERVER: 8.8.8.8#53(8.8.8.8)
;; WHEN: Fri Mar  8 14:22:32 2019
;; MSG SIZE  rcvd: 76

Mac OS X EI Capitan 10.11.2系统中只有如上信息返回,并以空行分隔为四个部分,在其他系统有待试验。

第一段是查询参数和统计;第二段是查询内容,表示查询域名 github.com 的A记录,A 是 address 的缩写。

;; QUESTION SECTION:
;github.com.			IN	A

第三段是 DNS 服务器的答复,表示 github.com 有三个记录,即四个 IP 地址。23TTL 值(Time to live 的缩写),表示缓存时间,即 23 秒内不 用重复查询。

;; ANSWER SECTION:
github.com.		23	IN	A	13.250.177.223
github.com.		23	IN	A	52.74.223.119
github.com.		23	IN	A	13.229.188.59

第四段是 DNS 服务器的一些传输信息,本机的 DNS 服务器是8.8.8.8,查询端口是53(DNS 服务器的默认端口),以及回应长度是76

;; Query time: 22 msec
;; SERVER: 8.8.8.8#53(8.8.8.8)
;; WHEN: Fri Mar  8 14:22:32 2019
;; MSG SIZE  rcvd: 76

如果不想显示这么多信息,可以加上+short,如下只返回 github.com 对应的 4 个 IP 地址(即 A 记录)。

$ dig github.com +short
13.229.188.59
52.74.223.119
13.250.177.223

DNS 服务器

本机要获取 github.com 的 IP 地址,首先要先知道 DNS 服务器的 IP 地址,否则上不了网。

WX20190308-145406.png;

DNS 服务器的 IP 地址有可能是动态的,由网关分配,这叫做DHCP 机制;也有可能是事先指定的固定地址,如上图所示可自行设定。Mac OS 与 Linux 系统 一样,也可以在/etc/resolv.conf文件中设置 DNS。

域名层级

DNS 服务器通过分级查询知道每个域名的 IP 地址。回看前述例子,域名尾部都有一个.,这是由于所有域名的尾部,实际上都有一个根域名。

;; QUESTION SECTION:
;github.com.			IN	A

举例来说,github.com真正的域名是github.com.root,简写为github.com.。因为,根域名.root对于所有域名都是一样的,所以平时是省略的。

根域名的下一级,叫做”顶级域名”(top-level domain,缩写为 TLD),比如.com.net;再下一级叫做”次级域名”(second-level domain,缩写 为 SLD),比如www.example.com中的.example,这一级域名是用户可以注册的;再下一级是主机名(host),比如www.example.com中的www, 又称为”三级域名”,这是用户在自己的域里面为服务器分配的名称,是用户可以任意分配的。域名的层级结构总结如下。

主机名.次级域名.顶级域名.根域名

host.sld.tld.root

根域名服务器

DNS 服务器根据域名的层级,进行分级查询。

需要明确的是,每一级域名都有自己的NS记录(Name Server的缩写),NS 记录指向该级域名的域名服务器。这些服务器知道下一级域名的各种记录。所谓 “分级查询”,就是从根域名开始,依次查询每一级域名的 NS 记录,直到查到最终的 IP 地址,过程大致如下。

  1. 从”根域名服务器”查到”顶级域名服务器”的 NS 记录和 A 记录(IP 地址);
  2. 从”顶级域名服务器”查到”次级域名服务器”的 NS 记录和 A 记录(IP 地址);
  3. 从”次级域名服务器”查出”主机名”的 IP 地址;

仔细看上面的过程,没有提到 DNS 服务器怎么知道”根域名服务器”的 IP 地址,因为”根域名服务器”的 NS 记录和 IP 地址一般是不会变化的,所以内置在 DNS 服务器里面。下面是内置的根域名服务器 IP 地址的一个例子。

bg2016061508.png

上表中,列出了根域名(.root)的三条 NS 记录A.ROOT-SERVERS.NETB.ROOT-SERVERS.NETC.ROOT-SERVERS.NET,以及它们的 IP 地址 (即 A 记录)198.41.0.4192.228.79.201192.33.4.12

另外,可以看到所有记录的 TTL 值是 3600000 秒,相当于 1000 小时,也就是每 1000 小时才查询一次根域名服务器列表。目前,世界上一共有十三组域名服务器,从A.ROOT-SERVERS.NET一直到M.ROOT-SERVERS.NET

以下是在 CentOS7 中 dig 查到的根域名服务器信息。

$ dig

; <<>> DiG 9.11.4-P2-RedHat-9.11.4-9.P2.el7 <<>>
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 3426
;; flags: qr rd ra; QUERY: 1, ANSWER: 13, AUTHORITY: 0, ADDITIONAL: 27

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;.                              IN      NS

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

;; ADDITIONAL SECTION:
a.root-servers.net.     502708  IN      A       198.41.0.4
b.root-servers.net.     604697  IN      A       199.9.14.201
c.root-servers.net.     356889  IN      A       192.33.4.12
d.root-servers.net.     542615  IN      A       199.7.91.13
e.root-servers.net.     603186  IN      A       192.203.230.10
f.root-servers.net.     603283  IN      A       192.5.5.241
g.root-servers.net.     95352   IN      A       192.112.36.4
h.root-servers.net.     142370  IN      A       198.97.190.53
i.root-servers.net.     336668  IN      A       192.36.148.17
j.root-servers.net.     335018  IN      A       192.58.128.30
k.root-servers.net.     331806  IN      A       193.0.14.129
l.root-servers.net.     603283  IN      A       199.7.83.42
m.root-servers.net.     603281  IN      A       202.12.27.33
a.root-servers.net.     410800  IN      AAAA    2001:503:ba3e::2:30
b.root-servers.net.     604668  IN      AAAA    2001:500:200::b
c.root-servers.net.     327659  IN      AAAA    2001:500:2::c
d.root-servers.net.     500152  IN      AAAA    2001:500:2d::d
e.root-servers.net.     604668  IN      AAAA    2001:500:a8::e
f.root-servers.net.     602243  IN      AAAA    2001:500:2f::f
g.root-servers.net.     94833   IN      AAAA    2001:500:12::d0d
h.root-servers.net.     191449  IN      AAAA    2001:500:1::53
i.root-servers.net.     340956  IN      AAAA    2001:7fe::53
j.root-servers.net.     335960  IN      AAAA    2001:503:c27::2:30
k.root-servers.net.     328199  IN      AAAA    2001:7fd::1
l.root-servers.net.     602243  IN      AAAA    2001:500:9f::42
m.root-servers.net.     602923  IN      AAAA    2001:dc3::35

;; Query time: 122 msec
;; SERVER: 192.168.244.1#53(192.168.244.1)
;; WHEN: Sat Mar 28 15:26:17 CST 2020
;; MSG SIZE  rcvd: 811

ADDITIONAL 部分显示了完整的根域名 IP。

分级查询的实例

dig命令的+trace参数可以显示 DNS 的整个分级查询过程。

$ dig +trace github.com

; <<>> DiG 9.8.3-P1 <<>> +trace github.com
;; global options: +cmd
.			73568	IN	NS	a.root-servers.net.
.			73568	IN	NS	b.root-servers.net.
.			73568	IN	NS	c.root-servers.net.
.			73568	IN	NS	d.root-servers.net.
.			73568	IN	NS	e.root-servers.net.
.			73568	IN	NS	f.root-servers.net.
.			73568	IN	NS	g.root-servers.net.
.			73568	IN	NS	h.root-servers.net.
.			73568	IN	NS	i.root-servers.net.
.			73568	IN	NS	j.root-servers.net.
.			73568	IN	NS	k.root-servers.net.
.			73568	IN	NS	l.root-servers.net.
.			73568	IN	NS	m.root-servers.net.
;; Received 228 bytes from 8.8.8.8#53(8.8.8.8) in 453 ms

com.			172800	IN	NS	c.gtld-servers.net.
com.			172800	IN	NS	b.gtld-servers.net.
com.			172800	IN	NS	f.gtld-servers.net.
com.			172800	IN	NS	d.gtld-servers.net.
com.			172800	IN	NS	e.gtld-servers.net.
com.			172800	IN	NS	i.gtld-servers.net.
com.			172800	IN	NS	g.gtld-servers.net.
com.			172800	IN	NS	a.gtld-servers.net.
com.			172800	IN	NS	k.gtld-servers.net.
com.			172800	IN	NS	h.gtld-servers.net.
com.			172800	IN	NS	m.gtld-servers.net.
com.			172800	IN	NS	l.gtld-servers.net.
com.			172800	IN	NS	j.gtld-servers.net.
;; Received 488 bytes from 192.33.4.12#53(192.33.4.12) in 33142 ms

github.com.		172800	IN	NS	ns1.p16.dynect.net.
github.com.		172800	IN	NS	ns3.p16.dynect.net.
github.com.		172800	IN	NS	ns2.p16.dynect.net.
github.com.		172800	IN	NS	ns4.p16.dynect.net.
github.com.		172800	IN	NS	ns-520.awsdns-01.net.
github.com.		172800	IN	NS	ns-421.awsdns-52.com.
github.com.		172800	IN	NS	ns-1707.awsdns-21.co.uk.
github.com.		172800	IN	NS	ns-1283.awsdns-32.org.
;; Received 264 bytes from 192.12.94.30#53(192.12.94.30) in 1952 ms

github.com.		60	IN	A	13.250.177.223
github.com.		60	IN	A	13.229.188.59
github.com.		60	IN	A	52.74.223.119
github.com.		900	IN	NS	ns-520.awsdns-01.net.
github.com.		900	IN	NS	ns1.p16.dynect.net.
github.com.		900	IN	NS	ns-1283.awsdns-32.org.
github.com.		900	IN	NS	ns-421.awsdns-52.com.
github.com.		900	IN	NS	ns2.p16.dynect.net.
github.com.		900	IN	NS	ns3.p16.dynect.net.
github.com.		900	IN	NS	ns-1707.awsdns-21.co.uk.
github.com.		900	IN	NS	ns4.p16.dynect.net.
;; Received 296 bytes from 208.78.70.16#53(208.78.70.16) in 176 ms

第一段列出根域名.的所有 NS 记录,即所有根域名服务器;根据内置的根域名服务器 IP 地址,DNS 服务器向所有这些 IP 发出查询请求,询问github.com 的顶级域名服务器com.的 NS 记录。最先回复的根域名服务器将被缓存,以后只向这台服务器发请求。

第二段显示了.com域名的 13 条 NS 记录,同时返回的还有每一条记录对应的 IP 地址(TODO: 如果返回的 IP 是在终端上显示的话,目前只看到一个 IP 啊)。

第三段 DNS 服务器向这些顶级域名服务器发出查询请求,询问github.com次级域名的NS 记录

第四段 DNS 服务器向第三段的 NS 服务器查询github.com主机名。最后结果如下。

github.com.		60	IN	A	13.250.177.223
github.com.		60	IN	A	13.229.188.59
github.com.		60	IN	A	52.74.223.119
github.com.		900	IN	NS	ns-520.awsdns-01.net.
github.com.		900	IN	NS	ns1.p16.dynect.net.
github.com.		900	IN	NS	ns-1283.awsdns-32.org.
github.com.		900	IN	NS	ns-421.awsdns-52.com.
github.com.		900	IN	NS	ns2.p16.dynect.net.
github.com.		900	IN	NS	ns3.p16.dynect.net.
github.com.		900	IN	NS	ns-1707.awsdns-21.co.uk.
github.com.		900	IN	NS	ns4.p16.dynect.net.
;; Received 296 bytes from 208.78.70.16#53(208.78.70.16) in 176 ms

github.com 有 3 条 A 记录,即这四个 IP 地址都可以访问到网站。并且还显示,最先返回结果的 NS 服务器是208.79.70.16(试着 ping 了一下,是 ns1.p16.dynect.net的 IP)。(TODO: 剩下几个 NS 记录应该是 github.com 自己的 DNS 服务器吧?

NS 记录的查询

dig命令可以单独查看每一级域名的 NS 记录。

$ dig +short ns .
k.root-servers.net.
b.root-servers.net.
c.root-servers.net.
j.root-servers.net.
g.root-servers.net.
a.root-servers.net.
l.root-servers.net.
d.root-servers.net.
e.root-servers.net.
f.root-servers.net.
m.root-servers.net.
h.root-servers.net.
i.root-servers.net.
$ dig +short ns com
c.gtld-servers.net.
a.gtld-servers.net.
h.gtld-servers.net.
k.gtld-servers.net.
m.gtld-servers.net.
e.gtld-servers.net.
g.gtld-servers.net.
j.gtld-servers.net.
d.gtld-servers.net.
b.gtld-servers.net.
f.gtld-servers.net.
l.gtld-servers.net.
i.gtld-servers.net.
$ dig +short ns github.com
ns-1283.awsdns-32.org.
ns3.p16.dynect.net.
ns-1707.awsdns-21.co.uk.
ns4.p16.dynect.net.
ns-520.awsdns-01.net.
ns2.p16.dynect.net.
ns1.p16.dynect.net.
ns-421.awsdns-52.com.

DNS 的记录类型

域名与 IP 之间的对应关系,称为”记录”(record)。根据使用场景,”记录”可以分成不同的类型(type),前面已经看到了A记录和NS记录。常见的 DNS 记录类型如下。

  1. A:地址记录(Address),返回域名指向的 IP 地址;
  2. NS:域名服务器记录(Name Server),返回保存下一级域名信息的服务器地址。该记录只能设置为域名,不能设置为 IP 地址;
  3. MX:邮件记录(Mail eXchange),返回接收电子邮件的服务器地址;
  4. CNAME:规范名称记录(Canonical Name)`,返回另一个域名,即当前查询的域名的另一个域名的跳转,详见下文;
  5. PTR:逆向查询记录(Pointer Record),只用于从 IP 地址查询域名,详见下文;

一般来说,为了服务的安全可靠,至少应该有两条 NS 记录,而 A 记录和 MX 记录也可以有多条,这样就提供了服务的冗余性,防止出现单点失败。

CNAME 记录主要用于域名的内部跳转,为服务器配置提供灵活性,用户感知不到,如下。

$ dig pages.github.com

; <<>> DiG 9.8.3-P1 <<>> pages.github.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 5058
;; flags: qr rd ra; QUERY: 1, ANSWER: 5, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;pages.github.com.		IN	A

;; ANSWER SECTION:
pages.github.com.	37	IN	CNAME	github.github.io.
github.github.io.	1985	IN	A	185.199.111.153
github.github.io.	1985	IN	A	185.199.110.153
github.github.io.	1985	IN	A	185.199.108.153
github.github.io.	1985	IN	A	185.199.109.153

;; Query time: 35 msec
;; SERVER: 114.114.114.114#53(114.114.114.114)
;; WHEN: Mon Mar 11 10:03:08 2019
;; MSG SIZE  rcvd: 128

上面结果显示,pages.github.com的 CNAME 记录指向github.github.io。也就是说,用户查询pages.github.com的时候,实际上返回 的是github.github.io的 IP 地址。这样的好处是,变更服务器 IP 地址的时候,只要修改github.github.io这个域名就可以了, 用户的pages.github.com域名不用修改。

CNAME记录就是一个替换,所以域名一旦设置CNAME记录以后,就不能再设置其他记录了(比如 A 记录和 MX 记录),这是为了防止产生冲突。

PTR记录用于从 IP 地址反查域名。dig命令的-x参数用于查询 PTR 记录。

$ dig -x 192.30.252.153

...

;; ANSWER SECTION:
153.252.30.192.in-addr.arpa. 3600 IN    PTR pages.github.com.

上面结果显示,192.30.252.153这台服务器的域名是pages.github.com(TODO:同样跟我查询出来的结果不一致)。

逆向查询的一个应用,是可以防止垃圾邮件,即验证发送邮件的 IP 地址,是否真的有它所声称的域名。

dig命令可以查看指定的记录类型。

$ dig a github.com
$ dig ns github.com
$ dig mx github.com

其他 DNS 工具

host 命令

host 命令可以看作 dig 命令的简化版本,返回当前请求域名的各种记录。

$ host github.com
github.com has address 52.74.223.119
github.com has address 13.229.188.59
github.com has address 13.250.177.223
github.com mail is handled by 10 alt4.aspmx.l.google.com.
github.com mail is handled by 10 alt3.aspmx.l.google.com.
github.com mail is handled by 5 alt1.aspmx.l.google.com.
github.com mail is handled by 1 aspmx.l.google.com.
github.com mail is handled by 5 alt2.aspmx.l.google.com.

host 命令也可以用于逆向查询,等同于dig -x <ip>

$ host 13.229.188.59
59.188.229.13.in-addr.arpa domain name pointer ec2-13-229-188-59.ap-southeast-1.compute.amazonaws.com.

nslookup 命令

nslookup 命令用于互动式查询域名记录。

$ nslookup
> github.com
Server:		114.114.114.114
Address:	114.114.114.114#53

Non-authoritative answer:
Name:	github.com
Address: 13.250.177.223
Name:	github.com
Address: 13.229.188.59
Name:	github.com
Address: 52.74.223.119
>

whois 命令

whois 命令用来查看域名的注册情况。

   Domain Name: GITHUB.COM
   Registry Domain ID: 1264983250_DOMAIN_COM-VRSN
   Registrar WHOIS Server: whois.markmonitor.com
   Registrar URL: http://www.markmonitor.com
   Updated Date: 2017-06-26T16:02:39Z
   Creation Date: 2007-10-09T18:20:50Z
   ...

Search

    Table of Contents