起因
之前在面试时,被问到了DNS底层采用了什么协议。“UDP。”我脱口而出。面试官追问:“还有么?”我又想了想,说DoT和DoH会用TCP协议。面试官对我的回答并不是特别满意,说普通的DNS查询也支持用TCP协议。
面试结束之后,查询了相关资料,发现理论上标准的DNS协议确实也支持TCP传输,但一般的DNS客户端会比较少遇到这种情况,因为:
- 只有在解析配置过于复杂,或者记录值过长,使得没有自带分包功能的UDP协议无法承载的情况下,才会用TCP查询。
- 很多DNS服务提供商不支持TCP查询。
既然已经知道了对应的原理,有必要做个小实验来验证一下。
实验
我采用的系统环境是Windows 11 23H2,运行着Wireshark 4.2.4。为了采集DNS协议的包,我们可以使用port 53
或者dns
过滤器。
UDP协议的普通DNS查询与响应
开始捕获后,我们可以打开终端,用nslookup
命令查询任意常见域名的对应IP地址。我这里用了自己博客的域名。
PS C:\Users\tian> nslookup tian051011.me
服务器: RT-AC1900P-B8B8.lan
Address: 192.168.50.1
非权威应答:
名称: tian051011.me
Address: 185.186.147.19
如果没有出意外的话,Wireshark应该就捕获到我们的DNS查询的查询和响应了。如下图,可以看到此时的DNS查询与响应确实采用了UDP协议。
TCP协议的DNS查询
首先我们需要寻找或构造一个够长的记录,让UDP塞不下这个记录,服务器才会给我们发TCP格式的响应。
这里我给tian051011.me这个域名增加了test主机记录,记录类型为TXT,记录内容是768个1,实测DNSPod是支持这么长的TXT记录的。
让我们来看看对这个域名进行DNS查询会发生什么吧。
PS C:\Users\tian> nslookup -type=TXT test.tian051011.me
服务器: RT-AC1900P-B8B8.lan
Address: 192.168.50.1
非权威应答:
test.tian051011.me text =
"111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111"
"111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111"
"111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111"
"11"
nslookup成功查出来了我们设置的TXT记录。让我们看看Wireshark那边都捕获到了些什么。
我们可以发现客户端首先发送了UDP格式的查询,并得到了UDP格式的响应,但这个响应很特殊,里面并没有Answers,Truncated标记位也告诉我们这个响应是被截断的。
接下来,客户端就用TCP发送了查询请求,并得到了TCP包中的完整响应。
不支持TCP协议的DNS服务器
根据我的实测,不同的DNS服务提供商对于这种响应超长的查询会有不同的响应,例如114DNS会直接响应“无可用记录”、阿里云公共DNS会出现“未定义错误”,这也反映出很多DNS服务器的实现可能不符合RFC标准。
我这里采用了DNSPod Public DNS,让我们来看看这种情况下对test.tian051011.me进行TXT查询会发生什么吧。
PS C:\Users\tian> nslookup -type=TXT test.tian051011.me 119.29.29.29
服务器: pdns.dnspod.cn
Address: 119.29.29.29
tian051011.me nameserver = f1g1ns1.dnspod.net
tian051011.me nameserver = Invalid Name at offset 80!
*** Error: record size incorrect (-408812189280 != 10)
tian051011.me nameserver = f1g1ns1.dnspod.net
tian051011.me nameserver = Invalid Name at offset 80!
*** Error: record size incorrect (-408812189280 != 10)
*** pdns.dnspod.cn 找不到 test.tian051011.me: Unspecified error
nslookup报错了,从报错信息我们可以大致了解到出现的问题是记录大小不对。那么在这种情况下,Wireshark捕获到了什么呢?
首先,查询和响应都没有出现TCP格式。
其次,DNS响应的记录是损坏的,Truncated标记位也没有被设置。
另一种情况-区域传送
其实,还有一种情况,DNS记录基本是在TCP协议下被传送的,那就是“DNS区域传送(zone-transfer)”。在这种情况下,一台备用服务器会使用来自主服务器的数据来刷新自己的域(zone)数据库。由于这种传送要求可靠性高且数据量大,一般会采用TCP协议,不过一般用户是接触不到这种情况的。目前暂时没有条件做区域传送的实验,可以先了解一下相关概念。