Q: 平时用Sniffer观察到的DNS报文都在使用53/UDP,什么时候会用到53/TCP?
A: 对于DNS服务器,递归解析时用53/UDP,区传输因需要可靠传输,必须使用53/TCP。DNS服务器的标准实现必须同时支持53/TCP和53/UDP。 对于DNS客户端,默认使用53/UDP进行A记录查询。nslookup进行A记录查询时,可以强制使用53/TCP。用Sniffer观察下述操作引发的通信报文:
nslookup
> set vc
> www.anydomain.cn
RFC 1035中指出,53/UDP上的UDP数据区(不包括UDP首部)不得超过512字节,发送时如果超过512字节,将被截断成512字节,同时DNS协议Flags字段Truncated位置位。
53/TCP上的数据区最前面是big-endian序的2字节长度域,不包括自身这2字节,指明了后续数据长度。
更多细节参看"http://www.ietf.org/rfc/rfc1035.txt"。
网上曾经流行过这样一个说法,当DNS服务产生的响应数据大于512字节(指UDP数据区)时会自动改用53/TCP。注意,RFC 1035从来没有给出过这种说法,即使确有其事那也是DNS服务实现相关的,不是标准行为。
参看<<TCP/IP Illustrated, Volume 1>> 14.8节。
名字解析器(DNS Client或递归解析中的DNS Server)发出UDP请求报文,名字服务器(必然是DNS Server)产生的UDP响应数据大于512字节时,只会向名字解析器发送前512字节,同时TC位置位。名字解析器通过TC位得知响应数据没有全部返回,一般实现会选择用TCP重新请求,名字服务器将用TCP返回完整的响应数据。
何时用TCP是由名字解析器决定的,也就是说,名字解析器用TCP发送请求,名字服务器才会用TCP发送响应,正常情况下决不会出现请求报文是UDP而响应报文是TCP的情形。之所以强调正常情况下,是因为有一些非正常情况。
以BIND 8.3.3为例。我曾搭建过如下测试环境:
Server B(xxx.org.)
/
Client A - Server A(org.)
\
Fake Server B
Client A向Server A发送UDP请求报文进行A记录查询(1.xxx.org)。Server A进行递归解析,向Server B发送UDP请求报文,源端口不是53/UDP。
Client A向Server A发送TCP请求报文进行A记录查询(1.xxx.org)。Server A进行递归解析,仍然向Server B发送UDP请求报文而不是TCP请求报文,源端口不是53/UDP。
Server B收到来自Server A的UDP请求报文后,一般会发送UDP响应报文。现在用FakeServer B换掉Server B,同样是处理来自Server A的UDP请求报文。Fake Server B可以向Server A的53/TCP主动发起连接请求,并在此TCP连接上发送DNS响应数据,源端口不要求是53/TCP。而Server A居然接受来自Fake Server B的异常TCP响应。
不知道正常通信中会出现此类现象否。总之,BIND 8.3.3曾经支持这种异常行为。