“DNS协议大家都应该很熟悉,最近有同学问到如何获得UDP承载的超过512字节的DNS报文,借此机会,我们一起了解下DNS协议与报文长度有关的一些细节。”
在之前的文章里,对DNS协议进行了介绍:
看完这两篇文章,大家应该对DNS协议有一些初步的了解。对DNS协议而言,在IETF网站上,能够很容易地获取到相关的RFC文档及扩展信息。
在大部分讲解DNS协议的文章里,都会这样描述DNS协议的特性:
当封装的DNS响应的长度超过512字节时,协议应采用TCP传输,而不是UDP。
根据协议标准文档RFC1035,这当然是对的,实际使用DNS协议的过程中,抓取的报文也确实是这样的,但是,不要忘记这份RFC文档产生于三十年前,这么多年,随着网络环境的变化,协议是会发展的,大家想想,网络上是不是到处都是超过512字节的UDP数据呀,那超过512字节的UDP DNS又有何不可?
RFC 6891这份标准文档,对DNS进行了扩展,描述了超过512字节的DNS的情况,即EDNS0。
本文将首先描述DNS协议的长度限制情况,然后对EDNS0进行说明,接着用示例说明DNS工具在超过512字节时的通常情况,最后将介绍如何方便地产生超过512字节的UDP承载的DNS报文。大家可以根据需要,跳到对应章节查阅。
01
—
DNS的512字节限制
根据协议标准,DNS协议同时占用UDP和TCP的53端口,这是为什么呢?
翻阅DNS资料,可以发现,DNS协议默认按UDP传输,为优化传输性能,DNS协议有一个512字节的限制,当数据长度超过了512字节时,DNS协议会改用TCP进行传输。
DNS协议从UDP切换到TCP的过程如下:
1、客户端向服务器发起UDP DNS请求;
2、如果服务器发现DNS响应数据超过512字节,则返回UDP DNS响应中置truncated位,告知客户端改用TCP进行重新请求;
3、客户端向服务器发起TCP DNS请求;
4、服务器返回TCP DNS响应。
那为什么限制是512字节呢?
一个说法是:IPV4标准规定了各个主机必须能够重组576字节或更少字节的数据包。具有512字节内容的DNS报文加上IP头和UDP头,将小于576字节。
02
—
EDNS0
EDNS0:即Extension Mechanisms for DNS (EDNS(0)),详细情况可参考RFC 6891这份文档。
EDNS0是随着网络的发展,在DNS消息格式和它支持的消息内容已不足以满足一些DNS服务器的需求的情况下被提出的,它用于传递包大小,扩展了DNS协议。
EDNS0是在遵循已有的DNS消息格式的基础上增加一些字段,来支持更多的DNS请求业务。当然,具备向后兼容性,未支持EDNS0的旧的DNS服务器仍然能够很好地处理EDNS0。
EDNS0特征如下:
扩展DNS使用UDP传输时的最大报文限制,可以超过512字节
扩展RCODE,由4为增加到12位
建议利用域名标签类型的剩余两个
我们在这里关注的是ENDS0突破DNS 512字节限制的能力。
DNS协议在发起请求时,通过在Additional部分增加OPT RR字段,告知服务器能处理的最大UDP报文长度,当服务器准备进行回应时,如果响应数据大于该值,则在DNS协议中置truncated位,否则,可发送小于该值大小的报文。这相当于突破了512字节的长度限制。
在ENDS0标准文档中,很容易找到OPT RR字段的格式:
各字段如下:
NAME:目前为空
TYPE:OPT RR的类型编号,41
CLASS:最大UDP报文长度
TTL:扩展的DNS消息头部
RDLEN:紧接着的RDATA的长度
RDATA:可变部分数据。
RDATA格式如下:
说明如下:
OPTION-CODE:由IANA分配
OPTION-LENGTH:OPTION-DATA的长度
OPTION-DATA:具体内容
而TTL则是用来存储扩展消息头部中的RCODE和flags,格式如下:
说明如下:
EXTENDED-RCODE:扩展RCODE(返回状态码),这8个bit加上DNS头部的4bit总共有12bit(8bit在高位),这样就可以表示更多的返回类型
VERSOION:EDNS的版本
DO:DNSSEC OK,见相关RFC文档定义
Z:一般被发送者设置为0,接收方可以忽略它
因此,只要在进行DNS请求时,设置了OPT RR的CLASS值,则当响应超过了512字节,但未超过该值时,会仍然使用UDP进行传输。
03
—
DNS超过512字节时常规交互
在进行示例之前,我们首先要找到能够产生超过512字节DNS报文的域名及DNS服务器。这是由于大部分的DNS响应都不会很长,而同时,不同的DNS服务器缓存的DNS数据是有差异的。
经过搜集,我们选取了微软的DNS服务器之一:208.84.2.53,同时,选取了进行示例的域名:outlook.com。
常规的DNS请求,不会设置OPT RR的CLASS值,因此会默认在DNS报文大于512字节时,换用TCP传输。
常规DNS交互的实力,选择使用windows自带的nslookup服务进行,命令如下:
nslookup -qt=ANY outlook.com 208.84.2.53
使用Wireshark抓包可看到报文如下:
可以看到,DNS在UDP传输之后自动进行了TCP DNS请求,响应体长度达到1010字节。
自动进行的关键是UDP的DNS响应报文里给truncated进行了置位:
因此,我们只需要找到超过512字节DNS响应的域名及DNS服务器,就能很容易获取到DNS TCP的报文。
04
—
DNS突破UDP 512字节限制
对于超过512字节的DNS UDP报文,就不是那么容易获得的。一个简单的办法是,到骨干网络上去抓包,抓取DNS服务器之间的DNS同步报文。当然,对很多分析DNS协议的朋友,这不现实。
这里,将介绍一种在PC上产生超过512字节的UDP DNS报文的办法。
使用的仍然是前一节的DNS域名和服务器。
这里,需要找到设置DNS协议的OPT RR的CLASS值的方法,很幸运,有这样的工具存在,即dig这个小工具,一款Linux下用于查看域名详情的小工具,类似于nslookup,但功能更强大。dig也存在Windows版,它包含在BIND工具包中,BIND工具包可以在BIND官网下载,地址如下:https://www.isc.org/downloads/
在页面下方即可找到BIND各个版本的下载按钮。
下载好bind包,解压后,直接命令行进入解压目录,即可使用dig进行DNS请求,为构造UDP的DNS大包,设置了参数+notcp以及+bufsize=1400:
dig.exe @208.84.2.53 outlook.com ANY IN +notcp +bufsize=1400
wireshark获取到报文如下:
没有从UDP跳转为TCP进行DNS请求,而是直接在UDP中返回了完整的DNS数据。
其中请求如下:
在OPT RR中,设置了UDP的payload size 1400。
响应如下:
响应体达1031字节。
很容易地,就设置了DNS协议的OPT RR的CLASS值。从而获得了超过512字节的UDP承载的DNS协议报文。
05
—
总结
只要找到合适的方法,就能很方便地突破DNS协议的UDP 512字节限制。如果有什么疑问,可以随时联系我。
长按进行关注。