深入探究DNS流程与报文

DNS服务器类型

root nameserver

即负责.域名的, 全球只有13台(至于为啥只有13台, 自己google吧):

davywalkerdeMBP:_assets davywalker$ dig baidu.com +trace

; <<>> DiG 9.10.6 <<>> baidu.com +trace
;; global options: +cmd
.			1	IN	NS	m.root-servers.net.
.			1	IN	NS	a.root-servers.net.
.			1	IN	NS	h.root-servers.net.
.			1	IN	NS	l.root-servers.net.
.			1	IN	NS	i.root-servers.net.
.			1	IN	NS	g.root-servers.net.
.			1	IN	NS	j.root-servers.net.
.			1	IN	NS	c.root-servers.net.
.			1	IN	NS	k.root-servers.net.
.			1	IN	NS	e.root-servers.net.
.			1	IN	NS	f.root-servers.net.
.			1	IN	NS	b.root-servers.net.
.			1	IN	NS	d.root-servers.net.
;; Received 239 bytes from 192.168.1.1#53(192.168.1.1) in 7 ms

TLD(Top Level Domain) nameserver

即对应 .com, .gov, .cn 等的解析服务器.

authoritative nameserver

即对应 .baidu.com .hangzhou.gov, gitee.cn 等的解析服务器.
通常 authoritative nameserver 是DNS解析的最后一步

The authoritative nameserver is usually the resolver’s last step in the journey for an IP address.

DNS查询类型

递归式(Recursive Query)

DNS请求:

如下, 是个请求中的标识位, 使用dig命令,

  • 如果+trace则请求自动禁用递归(即如下递归标识设置为false);
  • 不加+trace, 则请求自动使用递归.

DNS响应:

如下,

  • 代表当前LocalDNS服务器支持递归查询.
  • 与此形成鲜明对比的是ROOT根DNS服务器返回不支持递归查询.

迭代式(Iterative Query)

dig 重要参数与模式

指定域名解析服务器

方式1: 使用+trace参数:

例如 dig @8.8.8.8 baidu.com +trace:

  1. @8.8.8.8 则dig +trace时, 代表获取ROOT Server域名列表, 会请求8.8.8.8
  2. 之后会把每个ROOT Server的域名, 例如 a.root-servers.net b.root-servers.net 等, 请求LocalDNS(如图中的30.30.30.30), 通过递归方式(recurse=1), 获取到对应的A记录. 注意, 这里就不再是请求 8.8.8.8 了!!
  3. 之后再请求某个ROOT Server, 获取到TLD Server的域名. 依次类推, 走正常迭代DNS方式.
    所以 @x.x.x.x +trace, 本质上是从 8.8.8.8 获取到根域名地址. 之后还是走的正常迭代查询DNS流程.

方式2: 不使用+trace参数:

例如 dig @8.8.8.8 baidu.com

  1. @8.8.8.8 则dig时, 会请求8.8.8.8, 让8.8.8.8通过递归方式, 直接给出对应baidu.com对应的IP地址.
  2. 注意: 这种就是实际常用的正常DNS解析流程.

如下图, 这是从浏览器里输入baidu.com之后的DNS流程, 可知是递归式的:

指定域名解析服务器总结

如果不指定, 则默认:

  1. 请求LocalDNS, 通过 cat /etc/resolv.conf 可知LocalDNS的IP
  2. 让LocalDNS使用递归的方式给出结果.

指定使用TCP协议解析

默认DNS协议是基于UDP 53端口; 但也可以基于TCP 53端口完成请求.

命令

dig @8.8.8.8 baidu.com +tcp

包解析

其他

// TODO:
// 1. 可以思考下 DNS over TCP(DoT) 与DNS over UDP(DoU)各自的优缺点
// 2. 近几年有 DNS over TLS; DNS over HTTP; DNS over HTTPS; 为啥会有这么多套娃协议? 是为了解决啥问题? 优缺点是啥?

WireShark抓包实战

简单的顶级域名DNS抓包

命令

# 就简单地对baidu.com进行DNS抓包
davywalkerdeMBP:_assets davywalker$ dig baidu.com +trace

+trace迭代式, WireShark分析

第一步: 向LocalDNS发起请求, 请求获取.对应的root nameserver

请求

可以看到:

  • 请求的目标IP是/etc/resolv.conf中对应的LocalDNS IP
  • 请求是UDP协议, 目标LocalDNS的端口号是53
  • 请求内容是: <ROOT>, 即根域名DNS; 类型是 NS, 即nameserver; 就是请求根域名的nameserver

响应

可以看到:

  • 响应内容里有13个根域名服务器的域名
  • 但注意: 没有返回nameserver的domain对应的IP地址!!! , 经分析与推测, 由于全球13个根域名服务器的IP是永远不会变的(有可能会变化, 历史上也变化过), 各个domain对应的IP地址应该是通过Root Hint File, 缓存在操作系统中.

第二步: 向root nameserver请求, 请求获取.com.对应的TLD’s nameserver

请求

可以看到:

  • 请求的目标IP是202.12.27.33, 经分析, 是m.root-servers.net.对应的IP地址. 应该是按照某种算法随机选的.
  • 请求想要直接从root nameserver中获取到 baidu.com 的A记录
响应

可以看到:

  • 响应内容里有13个.com.域名服务器的域名.
  • 但注意: 同时在Additional records部分, 把各个域名服务器对应的IP也都以A记录形式返回. 这个就是所谓的 Glue Record, 试想下, 如果没有返回A记录, 那么如果.com.返回的nameserver是a.com., 那么如何获取到这个domain对应的IP? 通过DNS么? 那就无限递归了!
  • Additional records中AAAA记录, 代表的是各个域名服务器对应的IPV6地址.

第三步: 向TLD’s nameserver请求, 请求获取baidu.com.对应的authoritative nameserver

请求

可以看到:

  • 请求的目标IP是192.31.80.30, 通过翻看上一个Glue Record, 可以知道正是d.gtld-servers.net: type A, class IN, addr 192.31.80.30对应的IP.
响应

可以看到:

  • 响应的内容里没有baidu.com的A记录信息, 而是一堆的NS记录信息, 以及NS对应的IP, 因此还需要继续往下查.
  • 如果是查询顶级域名(例如github.com), 或者二级域名(例如login.github.com)等:
    • 那么理论上这个时候就可以直接返回A记录了. 即不用再走第四步了. 此时A记录可以是个VIP, 然后根据请求具体的二级域名, 例如login.github.com, 通过Nginx等反向代理到对应服务即可.
    • 但实际分析了下, 大部分网站(如下图中alibaba.com, zhihu.com, aliyun.com等), 都是在这里返回自己的authoritative nameserver, 自己思考了下原因:
      • 一是: 因为 TLD’s nameserver 通常是由国家或者组织统一管理的, 各个公司如果IP变化, 不好同步到 TLD 中. 而 authoritative nameserver 一般都是各个公司自己管理, 时效性与灵活性都很高. 例如可以给某些二级/三级域名配置不同的IP.
      • 二是: 因为如果直接A记录注册在TLD上, 那么整个网站的所有二级/三级域名等, 就只能有一个IP入口了. 整体风险就很大了. 如果VIP挂了, 整个网站都不可用了. 如果是不同的二级域名, 分配不同nameserver, 则




第四步: 向authoritative nameserver请求, 请求获取baidu.com.对应的ip

请求

可以看到:

  • 请求的目标IP是14.215.178.80, 通过翻看上一个Glue Record, 可以知道正是ns4.baidu.com: type A, class IN, addr 14.215.178.80对应的IP.

响应

可以看到:

  • 正确地返回了baidu.com的A记录

不加+trace递归式, WireShark分析

第一步: 向LocalDNS发起请求, 请求获取aliyun.com的IP地址(A记录)

请求

可以看到:

  • 请求的目标IP是/etc/resolv.conf中对应的LocalDNS IP
响应

可以看到:

  • LocalDNS直接把DNS的A记录结果返回了. 所有的迭代操作都是LocalDNS执行的了.

疑问

域名服务器本身IP解析问题

DNS协议返回了根域名服务器的域名, 例如m.root-servers.net., 但实际后续向根域名服务器发起查询TLD域名服务器的请求时, 是需要知道根域名服务器的IP的! 这个IP从哪里获取? 通过WireShark抓包, 发现返回的根域名服务器域名列表里, 没有这些域名对应的IP地址. 难道也是通过DNS解析的么? 这样就涉及到循环.
Glue Record

dig请求能否使用指定”递归式”或者”迭代式”么?

切换查询中的 RD(要求递归)位设置。
在缺省情况下设置该位,也就是说 dig 正常情形下发送递归查询。
当使用查询选项 +nssearch 或 +trace 时,递归自动禁用。

有CNAME的DNS请求具体是咋样的?

例如 dig passport.baidu.com +trace, 返回:

passport.baidu.com. 1200 IN CNAME passport.n.shifen.com.
  • 在dig调用流程中, 到CNAME就结束了; 因为没有继续执行dig passport.n.shifen.com +trace
  • 但在实际浏览器访问时, 浏览器收到CNAME记录, 会重新发一个DNS请求解析passport.n.shifen.com域名.

直接使用DNS返回的IP访问网站可以么?

测试

如下, 返回的baidu.com的A记录39.156.66.10IP地址:

^CdavywalkerdeMBP:~ davywalker$ dig baidu.com
;; QUESTION SECTION:
;baidu.com.			IN	A
;; ANSWER SECTION:
baidu.com.		1	IN	A	110.242.68.66
baidu.com.		1	IN	A	39.156.66.10
  • 是否可以不用域名直接通过IP访问?
  • 答案是不可以

为啥要禁止直接通过ip访问?

  • 虚拟主机,主机上放置了N个网站,而每个网站绑定1个或以上域名,所以用域名访问主机可以解析到网站目录,但用IP的话服务器就不知道解析到哪个目录了!
  • 为了避免别人把未备案的域名解析到自己的服务器IP而导致服务器被断网; 目前国内很多机房都要求网站主关闭空主机头,防止未备案的域名指向过来造成麻烦
  • 可能是出于安全的考虑, 如果直接使用IP访问, 则HTTPS证书有效性就无法校验了. 这样被钓鱼了也不知道.

实践: 如何设置禁止ip直接访问(以Nginx为例)

实践: 如何设置单Host多域名, 不同域名访问不同服务(以Nginx为例)

nslookup 如何指定 nameserver?

  • 如下, 指定 ns7.taobao.com. 为查询 taobao.com 域名的ns

    nslookup taobao.com ns7.taobao.com.
  • 完整的nslookup命令参见: How to Use the nslookup Command

“Non-authoritative answer” 代表啥意思?

如下, “Non-authoritative answer” 代表请求不是由对应的权威服务器返回, 而是由本地或者其他DNS缓存的结果.

> google.com
Server:  one.one.one.one
Address:  1.1.1.1

Non-authoritative answer:
google.com      MX preference = 10, mail exchanger = aspmx.l.google.com
google.com      MX preference = 20, mail exchanger = alt1.aspmx.l.google.com
google.com      MX preference = 30, mail exchanger = alt2.aspmx.l.google.com
google.com      MX preference = 40, mail exchanger = alt3.aspmx.l.google.com
google.com      MX preference = 50, mail exchanger = alt4.aspmx.l.google.com

Refs