DNS 协议

参考:

https://blog.csdn.net/crazw/article/details/8986504

http://www.ruanyifeng.com/blog/2016/06/dns.html

https://www.cnblogs.com/davidwang456/articles/10660051.html

原文作者:smilesundream
原文链接:https://blog.csdn.net/smilesundream/article/details/69397318

如果说ARP协议是用来将IP地址转换为MAC地址,那么DNS协议则是用来将域名转换为IP地址(当然也可以将IP地址转换为相应的域名地址)。 在讨论DNS协议之前,先回答几个容易想到的问题。

       问题一:网络中的主机为什么不直接使用域名而用IP地址进行通信?

       因为IP地址是固定长度的,IPv4是32位,IPv6是128位,而域名是变长的,不便于计算机处理,但便于用户使用,例如www.baidu.com这是百度的域名,我们一看就明白。总结一点就是IP地址是面向主机的,而域名则是面向用户的。

      问题二:假如用户希望通过FTP客户进程来访问运行在一台远程主机上的FTP服务器,该FTP服务器的域名为xxx.com.,给出整个处理流程大致描述?(假设xxx.com是一个实际存在的服务器域名)

       1.用户将xxx.com.传递给其主机上的FTP客户进程;

       2.FTP客户程序将xxx.com.传递给DNS客户进程;

       3.由于每一台主机在加载内核后都能获得其DNS服务器的IP地址,DNS客户进程便通过该IP地址向DNS服务器发送DNS查询报文,要求服务器给出xxx.com对应的IP地址;

       4.DNS服务器进程在收到该DNS查询报文后,通过一系列的查询操作(递归查询或迭代查询)获得xxx.com对应的IP地址后将xxx.com的IP地址写入到DNS响应报文中发回给DNS客户进程;

       5.DNS客户进程将获得的xxx.com的IP交付给FTP客户进程;

       6.FTP客户进程在收到FTP服务器的IP地址后,就可以访问FTP服务器了。

       Notice:客户进程在于服务器进程发送数据报之前,必须要知道服务进程所在服务器的IP地址,因为socket地址=(IP地址:端口号),网络进程间的通信是通过socket进行的。

      下面详细地介绍下DNS协议的工作原理。

      一、域名

       像Linux目录结构一样,现代因特网采用层次树状结构的命名方法,任何一个连接在因特网上的主机或路由器,都有一个唯一的层次结构的名字,该名字称为域名

        

           

           (1)域名的分级:域名可以划分为各个子域,子域还可以继续划分为子域的子域,这样就形成了顶级域、二级域、三级域等。

        

        其中顶级域名分为:国家顶级域名、通用顶级域名、反向域名

        国家顶级域名:中国:cn, 美国:us,英国uk...

        通用顶级域名:com 公司企业  edu教育机构 gov政府部门  int国际组织  mil军事部门  net网络

                                  org非盈利组织...

        反向域名:只有一个arpa,用于PTR查询(IP地址转换为域名) 。

       (2)域名的完整性:根据域名的完整性,我们将域名分为FQDN和PQDN。

         FQDN(Full Qualified Domain Name):完全合格的域名,也称为绝对域名(还记得绝对路径吗?Linux中的绝对路径是以/开头,而此处的绝对域名则是已.结尾)。

        PQDN(Partiallly qualified domain name):标号不是以.结束,在将该地址传递给DNS服务器之前,本主机的DNS客户进程中的解析程序可以补充缺少的部分(称为后缀),使得PQDN变为FQDN,显然DNS客户程序通常保存了一份有关后缀的列表

       一个域名服务器所负责的范围,或者说有管理权限的范围,就称为,每一个区中所有的结点必须是连通的,每一个区中都设置相应的权限域名服务器,用来保存该去中的所有主机的域名到IP地址的映射。所以,DNS服务器的负责范围不是以“域”为单位的,而是以“区”为单位,区可能小于或等于域,但一定不会大于域,区是“域”的子集

       NOTICE:同一个区可能存在多个权限域名服务器。

       域名服务器主要分为:根域名服务器、顶级域名服务器、权限域名服务器、本地域名服务器。

       根域名服务器:相当于一个总指挥,每一个域名服务器都必须知道如何与根域名服务器联系;

       顶级域名服务器:负责管理所有的二级域名;

       权限域名服务器:负责管理一个区。当一个权限域名服务器还不能给出最后的查询回答时,就会告诉查询请求的DNS客户进程,下一步应当找哪一个权限域名服务器;

       本地域名服务器:可以看成是默认域名服务器,DNS客户进程收到主机发送过来的域名后,就会最初向该域名服务器发送查询请求。

        为了保证数据的安全性,一个区域的管理者必须为该区域提供一个主域名服务(primaryserver)和 辅助域名服务器(secondary server)主域名服务器从磁盘文件中调入该区域的所有信息,而辅助域名服务器则从主域名服务器调入所有信息,我们将辅助域名服务器从主域名服务器调入信息的过程称为区域传送。当主域名服务器的磁盘文件更新时,辅助名字服务器会定时(通常为3h)向主域名服务器询问是否有数据更新,如果有,则通过区域传送方式获得新数据。建立辅助域名服务器的目的是为了保证数据的安全性,当主域名服务器出现故障时间,其辅助域名服务器可以继续对客户提供服务。

         NOTICE:一个服务器可以是某个区域的主域名服务器,同时又是另一个区域的辅助域名服务器。

       二、递归查询与迭代查询       

       在理解递归查询与迭代查询之前,必须要弄明白“递归”与“迭代”的区别。我们从C++的角度来理解递归与迭代的区别,所谓递归就是函数自己调用自己,而迭代则是函数内部循环地调用他人。下面,我们举出递归与迭代的C++程序:

递归程序:f(n)=f(n-1)+n,f(1)=1,我们用C++递归实现如下

[cpp] view plain copy  在CODE上查看代码片派生到我的代码片

  1. #include<iostream>  
  2. int f(int n)  
  3. {  
  4.     if(n==1)  
  5.         return 1;  
  6.     else  
  7.         return f(n-1)+n;<span style="color:#ff0000;">//递归过程</span>  
  8. }  

迭代程序:f(n)=1+2+3+...+n,我们用C++迭代实现如下

[cpp] view plain copy  在CODE上查看代码片派生到我的代码片

  1. #include<iostream>  
  2. int f(int n)  
  3. {  
  4.     int i,sum=0;  
  5.     for(i=1;i<=n;i++)  
  6.     {  
  7.         sum+=i;<span style="color:#ff0000;">//迭代过程</span>  
  8.     }  
  9.     return sum;  
  10. }  

       NOTICE递归和迭代的区别,通俗地说:递归就是把一件事情交给别人,如果事情没有办完,哪怕已经办了很多,都不要把结果告诉我,我要的是你的最终结果,而不是中间结果;如果你没办完,请你找别人办完;而迭代则是我交给你一件事,你能办多少就告诉我你办了多少,然后剩下的事情就由我来办。

        下面给出这两种查询方式在DNS查询中的应用图:

         递归查询

         迭代查询:

         Notice:通常情况下,主机向本地域名服务器的查询一般都是采用递归查询,本地域名服务器向根根域名服务器的查询通常采用迭代查询。

         三、DNS报文格式

         

         下面注意介绍下DNS报文中的标志部分(注意不是标识,标识只是给出一个序列号,客户在每次发送查询时使用不同的标识好,服务器在响应的响应中重复这个标识号):

                              

      QR:定义报文类型,QR=0表示查询报文,1表示响应报文;

      opcode:定义查询或响应的类型,0表示标准的,1表示反向的,2表示服务器状态请求;

       AA(Authoritative answer):授权回答,只用于响应报文。1表示该域名服务器是该区域的授权服务器;

       TC(Truncated):可截断的,使用UDP服务时,若响应报文的总长度超过512B,则只返回前512B;

       RD(Recursion Desired):期望递归,0表示DNS客户进程希望迭代查询,1表示DNS客户希望递归查询;

       RA(Recursion Available):递归可用,只用于响应报文。若域名服务器支持递归,则该服务器便在响应报文中将 RA=1。

       (zero):保留字段;

       rcode:表示在响应中的差错状态,只有权限服务器才能做出该判断。具体如下:

                     0:无差错               1:格式差错            2:问题出在域名服务器上

                     3:名字差错           4:查询类型不支持  5:在管理上被禁止           6~15:保留

      查询问题(问题记录):

      查询名:包含域名的可变长度字段,每个域以计数开头,最后一个字符为0(零),每个字符占1B。如:www.baidu.com可以这样记录:3www5baidu3com0

      查询类型:每一个问题的查询有一个类型,响应也有一个类型。

                           其中最常用的查询是A类型和PTR类型:A类型就是域名到IP地址,PTR查询就是IP地址到域名。

       查询类:定义了使用DNS的特定协议,1表示因特网。

       资源记录(RR)

        响应报文中的三种资源记录回答、授权、附加)均采用相同的格式,如下图所示:

        上图域名、类型和类与查询报文中的问题记录中的查询名、查询类型、查询类对应;

         生存时间:    以s为单位,定义了此回答的有效期(一般为2天)。在这段有效期内,客户长须可以将此回答保存在caching中,当TTL设置为0表示该资源记录只能用于本次回答,而不能存放在caching中;

         资源数据长度:用于记录后面资源数据的长度;

         资源数据:包含对查询的回答(在回答部分),或者权限服务器的域名(在授权部分),或者一些附加信息(在附加信息部分)。这个字段的格式和内容取决于类型字段的值。它可以是下述之一:

          a.数值  这个数以八位组为单位,例如IPv4是4个八位组的整数倍;

          b.域名   记录域名由两种方法,方法一就是查询报文中所提到的如:3www5baidu3com0,方法二是采用指针的方法,因为一个回答报文中可能同时包含多种资源记录RR,而对于每一种资源记录RR,都会重复域名部分,为了节约空间,在后面的RR(非第一个RR)的域名部分,我们采用偏移指针的方式。偏移指针(占用16位)指的是偏离DNS响应报文首部最开始的位置(以字节为单位)且以11开头,偏移值范围为0~63B。例如偏离首部最开始部分12B可以记录为:1100 0000 0000 1100。

Notice:当在响应报文中出现域名重复时,DNS要求用偏移指针来代替域名,DNS定义了2B的偏移指针,格式“11+偏移长度”,最高位固定为11,从而实现压缩

         c.字符串 字符串用1B的长度字段紧跟着一串长度的字符。长度字段并不像域名长度哪有受限。字符串可以多打255个字符(包括长度字段)

        四、高速缓存Caching 

        DNS客户程序将查询报文交给某个DNS服务器后(通常是主机域名服务器),若被查询的域名不在该DNS服务器的映射表中,则该DNS服务器会向另外一个DNS服务器请求 映射并在接收到响应后,把该映射信息返回给DNS客户程序之前,先要将该映射存储在自己的Caching中。若同一个客户或另一个客户请求同样的映射时,它就检查caching,并能够快速实现解析。当然,由于该服务器不是DNS程序的所请求域名的权限服务器,为了告知DNS客户程序这个响应是来自caching,而不是一个授权的信息源,这个服务器要把响应标记为未授权的。

         Caching可以提高解析效率,当然“如何更新Caching”是一个问题。可以采取如下方案反正Caching过时:

         方案一:权限域名服务器把TTL的信息添加到映射上,因为TTL定义了接收信息的服务器可以把映射信息放入Caching的时间长度(通常为2天),经过这段时间后,这个映射就变为无效的,因而任何查询都必须在发送给权限服务器。

        方案二:DNS要求每一个权限服务器对Caching中的每一条映射都有保持一个TTL计数器。Caching必须定期地搜索并清除那些TTL到期的映射。

        五、DNS请求中UDP和TCP的选择

         DNS可以使用UDP/53,也可以使用TCP/53,当响应报文的长度小于512B时就使用UDP(因为UDP的最大报文长度为512B),若响应报文的长度超过512B,则选用TCP。DNS协议关于UDP和TCP的选择通常为以下两种情况:

        (1)若DNS客户程序事先知道响应报文的长度512B,则应当使用TCP连接;

          NOTICE:主域名服务器与辅助域名服务器在进行区域传送时,通常数据量都比较大,所有DNS规定,区域传送使用TCP协议。

        (2)若解析程序不知道响应报文的长度,它一般使用UDP协议发送DNS查询报文,若DNS响应报文的长度大于512B,服务器就截断响应报文,并把TC(truncated)位置1,在这种情况下,DNS客户程序通常使用TCP重发原来的查询请求,从而它将来能够从DNS服务器中收到完整的响应。

          综上所述,我们可以得出结论:DNS客户程序在不知情(不知道DNS响应报文的长度是否超过512B)的情况下通常采用UDP与DNS服务器程序连接,在知情的情况下则采用TCP进行连接

发布了51 篇原创文章 · 获赞 7 · 访问量 5602

猜你喜欢

转载自blog.csdn.net/xxx0028/article/details/104740599