上一篇文章从工作原理角度分析了DNS的作用与意义,这次来看看DNS到底是以什么形式进行通信的。 DNS报文格式如下所示: DNS报文由12字节长的首部和4个长度可变的字段组成。 1。标识,由主机端设置,为的是唯一标识当前DNS报文。 2。16bit的标志字段被划分为若干子字段。 a。第1位为query或response,0为请求,1为响应 b。opcode是操作码,0是标准查询(大部分情况),1是反向查询,2是服务器状态请求 c。AA是1bit标志,表示授权回答(authoritativeanswer),默认是0。 d。TC表示是否可截断,用UDP时,表示应答长度超过512字节时,只返回前512字节 e。RD表示期望递归请求,与RA对应,一般是请求端发送。该标志为1,说明服务器必须对该请求进行处理。若为0,且请求的DNS没有一个授权回答,就返回一个能够解答这种查询的其他DNS列表,这种方式成为迭代查询。 f。RA表示可用递归,是RD的响应。大部分DNS都可响应RD,除了少部分根服务器 g。后面三位必须是0 h。rcode通常只有两种情况,0为没有差错,3为名字有错,表示查询中指定的域名不存在。 3。随后的4个16bit字段说明最后4个变长字段中包含的条目数。对于查询报文,问题数通常是1,而其他3项则均为0。对于应答报文,回答数至少是1,剩下的两项可以是0或非0。 4。DNS查询报文中的问题部分(通常一个DNS报文只有一个问题) a。查询名是要查找的名字,它是一个或多个标识符的序列。每个标识符以首字节的计数值来说明随后标识符的字节长度,每个名字以最后字节为0结束,长度为0的标识符是根标识符。 计数字节的值必须是063的数,因为标识符的最大长度仅为63 上图中的00001011是第一个标识符的计数值,1011代表11,说明后面11个字节为一个标识符,对应的是chenjingjiu这11个字符,后面的点被省略 然后是这个00000010,说明后面的标识符只有两个字节。 00000000表示根标识符,结束查询名字段。 这里要注意,从问题部分的图片可以看出,查询名字段虽然画成了整4字节的倍数的样子,但其实是可以随意变长的。可以是11字节,也可以是17字节,不一定是4字节的整倍数。 b。每个问题有一个查询类型,而每个响应也有一个类型。大约有20个不同的类型值,其中的一些目前已经过时。下图中是目前常用的类型记录。 最常用的查询类型是A类型,表示期望获得查询名的IP地址。一个PTR查询则请求获得一个IP地址对应的域名,这是一个指针查询。 c。查询类通常是1,指互联网地址(某些站点也支持其他非IP地址)。 下面是用wireshark抓取到的访问我的个人博客产生的DNS记录。 该DNS报文标识符为首先来看第一条数据0x290a,标志位第一位为0表示是一个请求,opcode是0表示该请求为标准请求,AA标志为0,TC标志为0说明未截断,RD为1表示请求递归,后面是保留位,最后4bit为0表示未出错。该DNS报文为一个请求报文,所以问题数为1,其余为0。再往后请求为http:chenjingjiu。cn,类型为A类型,为一个InterNet请求。 5。DNS响应报文中的资源记录部分 DNS报文中最后的三个字段,回答字段、授权字段和附加信息字段,均采用一种称为资源记录RR(ResourceRecord)的相同格式。 a。域名是记录中资源数据对应的名字。它的格式和前面介绍的查询名字段格式相同 b。类型说明RR的类型码。它的值和前面介绍的查询类型值是一样的。通常是1,指InterNet数据 c。生存时间字段是客户程序保留该资源记录的秒数。资源记录通常的生存时间值为2天。 d。资源数据长度说明资源数据的数量。该数据的格式依赖于类型字段的值。对于A类型资源,该值为4 e。对于A类型资源,资源数据是4字节的IP地址 接下来看第一个DNS请求的响应报文 可以看出前面与请求报文是相同的,只有后面不同。但是后面最有意思的是Name字段仅占用2字节,而请求时的报文可是用了16字节呢,这种差距不可谓不大了。这是DNS报文设计之初就考虑到每个报文中可能有很多重复的Name字段,因此设计了一种压缩表示法。前两bit为11表示压缩格式,而后面跟的14bit表示的是Name所在的位置相对于DNS首部的偏移值。本例中1100转换为12,说明相对于DNS首部偏移值是12字节,正好是DNS首部的定长字段。而第13字节就是请求的Name。所以该字段值一般都是12。 后面指示的类型2字节,类别2字节,TTL是4字节,数据长度2字节,地址占用4字节。返回博客IP地址188。131。238。222。 来看一下报文的长度,请求报文74字节,响应报文90字节。做一个简单的计算: 请求报文(74)Ether(14)IP(20)UDP(8)DNS(32)Ether〔DMAC(6)SMAC(6)IPtype(2)〕IP〔Version(0。5)Headerlen(0。5)Servicetype(1)Totallen(2)Identity(2)Flag(3bit)Offset(13bit)TTL(1)Protocol(1)Checksum(2)SIP(4)DIP(4)〕UDP〔Sport(2)Dport(2)UDPLen(2)Checksum(2)〕DNS〔TID(2)Flag(2)Question(2)AnsRR(2)AuthRR(2)AddRR(2)Name(16)DNStype(2)Class(2)〕 响应报文(90)请求报文(74)DNSresponse〔Name(2)Type(2)Class(2)TTL(4)Datalen(2)Address(4)〕 最后来考虑一下DNS到底是用UDP还是TCP? DNS名字服务器使用的熟知端口号无论对UDP还是TCP都是53,这意味着DNS均支持UDP和TCP访问。但从刚才wireshark抓出的包可以看出,基本上DNS都是通过UDP传输的,那么什么时候用TCP呢? 前面介绍过一个TC位,当DNS发出一个查询请求,并且返回响应中的TC位为1,说明该DNS响应长度超过512字节,后面的响应有缺失,因此此时需要利用TCP进行重传。TCP可以分段传输任意长度的报文。 本文就到这里,后面还会接触到一个叫DNS2TCP的隧道,并且利用这个隧道来实现上网。 原文链接:https:zhuanlan。zhihu。comp61782663