手揣网教程/杀毒教程/内容

域名的概念与机制

杀毒教程2024-02-05 阅读
[摘要]1. 介绍本文主要介绍域名(DNS)的一些机制及实现方法,下面我们就具体看一下它的情况。1.1. 域名的历史产生域名的的根本动机在于管理方便,原来的主机名与IP地址映射是保存在NIC的hosts.t...

1. 介绍

本文主要介绍域名(DNS)的一些机制及实现方法,下面我们就具体看一下它的情况。

1.1. 域名的历史

产生域名的的根本动机在于管理方便,原来的主机名与IP地址映射是保存在NIC的hosts.txt文件中的,当时因为主机数量少,这个文件也不经常变化,因此其它主机几天一次从NIC的主机上下载这个文件进行主机名和IP地址映射就可以了。但随着网络的发展,这种方法变得无法使用,因为经常会有主机要求下载,对NIC的主机造成巨大的压力,而且也不能保证服务的质量。许多局域网用户希望自己管理自己的主机名,而不希望等NIC许多天把自己的主机名加在hosts.txt文件中,有些组织也希望有自己的名字空间配置。是需要一个能够简单管理的方法了。最后决定使用层次式的名字空间组织方案,以.为分隔标准不同的层次。整个名字空间以分布式数据库管理。请看阅读前不要把平常的域名和这里的域名系统混在一起。最好的方法就是把原来的观念忘记了,看现在的新东西。

1.2. DNS设计目标

DNS的设置目标影响了它的结构,主要目标是对资源有一个一致的名字空间,为了避免不同编码带来的问题,需要包括网络标记,地址,路由或其它信息作为名字的一部分。出于对实验数据的分析,看来分布式的存储条件是必须的。要在获取数据的代价和数据准确性之间有一个平衡。需要对名字所代表的资源类型有一个标记。要支持多协议访问。名字服务器操作独立于通信系统。应该能够使用不同的机器都能够使用这一系统,使用的方法可能不同,但是都要能够使用。

1.3. 基于使用的一些假设

设计系统时是基于下面假设进行的:数据库的初始大小和使用系统的主机成正比,但最后数据库的大小会和用户的数目成正比,这一过程会发生在一些资源(如邮箱和其它一些要加入到域名系统中的信息)进入系统开始;大部分的数据改变比较慢,但系统能够对改变有一些快速的适应。由相应的组织负责分布式数据库的维护。域名系统的用户可以选择自己喜欢的主机。因为其中的数据十分敏感而且重要,因此一定要保证正确性,如果因为主机或网络失败而造成无法为用户服务,用户要以原来的数据为准,不要自己胡乱想一个数据就用。在查询的时候要避免循环查询,一种方法是将未找到这一信息返回给用户,让用户再找新的主机寻找相应的地址,一种是由主机找别的主机寻找相应的地址,找到后由相应的主机返回地址给用户,这两个方法各有好处。域名系统假设所有的数据是在一个主文件中保存,这个主文件的内容分布存储于系统中的各台主机上。用户通过标准的查询程序resolover查询。主文件的标准形式使得它可以在不同主机间进行传输(利用FTP,电子邮件等方式)。本地可以使用文本编辑器进行管理,然后将这个文件传输到名字服务器那里,然后通知名字服务器的管理员加载这个文件就是了。对于resolver来说,配置好的名字服务器是地址信息的主要来源。域名系统定义了访问数据的过程和访问其它名字服务器的方法,它还定义了缓冲的大小和更新缓冲的时间等配置信息。

系统管理员需要提供:

区域(zone)边界定义

主文件数据

主文件的更新

更新策略描述

域名系统需要提供:

源数据的标准格式

查询数据库的标准方法

多其它名字服务器上更新数据的标准方法

1.4. DNS组成

DNS由下面三个部分组成:

域名空间和资源记录,域名空间是一个树状结构,资源记录是与名字相关的一些数据。从概念上说,每个结点和域名空间树的叶子结点都有一定的信息,而查询是要查询出一些与之相关的特定信息。

名字服务器是服务器程序,它保留域名树结构和相应的信息,它可以缓冲各种数据,保存域名树中的任何部分,但是通常它保存域名空间的一个子集,如果需要查询其它信息可以通过指向其它名字服务器的地址寻找。这个名字服务器是这一部分的认证权威,所有的认证信息组成一个单元称为区,这些区可以分布于不同的服务器上以保证数据的冗余。

resolver是向名字服务器提出查询请求并将结果返回给客户的程序,它必须可以访问至少一个名字服务器,并将结果直接返回给用户或向别的名字服务器查询。它通常是用户可以访问的系统方法,在resolver和用户程序之间不需要协议。

下面我们通过三个不同的角度来看看它们的相互关系:

从用户的角度,域名系统可以通过简单的过程或操作系统调用来调用本地resolver进行查询。域名空间包括一个单独的树,用户可以从树中的任何一个部分查询信息。

从resolver的角度,域名系统由一些名字服务器组成,每个服务器有域树的整个或部分数据,resolver将这些数据库视为基本是静态的。

从名字服务器的角度,域名系统由称为区(zone)的本地数据集组成,名字服务器必须定期从主备份上更新自己区内的数据,它还必须处理从resovler传送来的查询请求。

2. 域名空间和资源记录

2.1. 定义和名词

域名空间是树状结构,每个结点和资源集相对应(这个资源集可能为空),域名系统不区别树内结点和叶子结点,统称为结点。每个结点有一个标记,这个标记的长度为0到63个字节。不同的结点可以使用相同的标记。0长度的标记(空标记)为根记录保留。结点的域名是从结点到根的标记组成的。这些标记对大小写不敏感,这就是说,A和a对域名是等效的。但是你在收到域名时最好保留它的大小写状态以便以后的服务扩展便于使用。

用户需要输入域名时,每个节点的标记长度不管多长,总要以点分隔。绝对域名的最后总以点结束,例如"poneria.ISI.EDU.",而相对域名则不这样,它由本地域指明位置即可。相对域名相对于一个公认的域名或相对于用作搜索列的一串域名。相对名通常在用户接口出现,在用户接口,表示方法因实现不同而不同,相对域名也出现在主文件中,主文件相对于一个源域名而设立。为了简化实现,整个域名的长度不得大于255个字节。域由域名标记,它由其下的域组成。如果一个域包括在另一域中,则称它为这个域的子域。我们可能通过表示很直观的看出。如A.B.C.D是B.C.D,C.D,D和" "的子域。

2.2. 管理规范

作为策略,DNS技术说明未说明一个特定的树结构或什么规则来选择标记,此说明希望达到的目的是越简单越好。应用程序的开发可以不管名字空间的边界和名字服务器的存在。这不是说没有规矩地乱来,而是把规则制定得开放以便于处理问题,树的不同部分可以有不同的规则。例如IN-ADDR.ARPA分布在网络各处,用于将网络或主机号转换为主机名,而NetBIOS域是平面式的,原因很简单,这样便于应用。但是,对于名字空间的通常部分,我们还是有规定的,目的是为了应用起来比较方便。低层域名最终被分为多个区,这样的域应该在顶层域上提供一个标记使最终的解析可能不必重名字就可以完成。在管理的时候,老的软件可能不支持结点标记中的数字,特殊字符。

2.3. 技术规范

在DNS能够被用来为某些种类的结点保存名字信息前,必须满足下面两个条件:

要有在对象名和域之间映射的规则,这个规则描述了关于对象的信息如何被访问

需要有描述对象的RR类型和数据格式

这些规则可烦可简,规则者要考虑到对现在格式和以后格式的兼容问题。多映射或映射分层是必须的。对于主机,映射取决于主机名的现有格式,它是通常文本表示域名的子集,加上描述主机地址的RR格式。因为我们需要从地址到主机的可靠映射,所以定义了将地址映射到IN-ADDR.ARPA域的方法。

对了邮箱,映射会复杂一些。通常的邮件地址<local-part>@<mail-domain>,可以通过将<local-part>转换为一个单独的标记,不要管里面的点,将<mail-domain>通过平常的域名解析方法进行解析,这两部分组合形成一个域名。因此邮件地址HOSTMASTER@SRI-NIC.ARPA,会变为HOSTMASTER.SRI-NIC.ARPA。通常的用户不关心这些定义的规则,但用户应该理解它们使用的是一种的许多要求的综合产物,有要求兼容老产品的,有要求添加新功能的。

2.4. 例子

下图是现在域名系统的一个部分,它在本文中还会经常被用到。请注意,这个树只是实际树的一个小小的子树。

                                  
            +---------------------+------------------+
                                                     
           MIL                   EDU                ARPA
                                                     
      +-----+-----+                     +------+-----+-----+
                                                           
     BRL  NOSC  DARPA                IN-ADDR  SRI-NIC     ACC
                                  
      +--------+------------------+---------------+--------+
                                                           
     UCI      MIT                                UDEL     YALE
                                 ISI
                                  
           +---+---+              
                                  
          LCS  ACHILLES  +--+-----+-----+--------+
                                                 
           XX            A  C   VAXA  VENERA Mockapetris
在此例中,根域有三个子域:MIL,EDU和ARPA,而LCS.MIT.EDU域有一个子域XX.LCS.MIT.EDU,其它的节点也是域。

2.5. 命名规则

DNS的命名规则是为了使对域名的命名比较统一。也就是要将任何现存的对象都可以在最小改动的情况下变为域名。谨慎的使用者会选择域名适合域名系统和应用程序。例如在命名邮件域名时,使用者会同时遵守相应的邮件协议。这就使对老软件的兼容性提高了。下面的规则是一个较少引起问题的规则:

<domain> ::= <subdomain>   " "
<subdomain> ::= <label>   <subdomain> "." <label>
<label> ::= <letter> [ [ <ldh-str> ] <let-dig> ]
<ldh-str> ::= <let-dig-hyp>   <let-dig-hyp> <ldh-str>
<let-dig-hyp> ::= <let-dig>   "-"
<let-dig> ::= <letter>   <digit>
<letter> ::= 大小写的A到Z,共52个
<digit> ::= 0到9

请注意:域名内不分大小写。标记必须遵守ARPANET主机名规则,它要求主机名必须以字母开始,以字母或数字结束,中间的可以是数字字母或连字符,长度没有限制。但标记必须少于63个字符。下面的字符串就表示了APARNET中的主机:

A.ISI.EDU XX.LCS.MIT.EDU SRI-NIC.ARPA

2.6. 资源记录

域名标记结点,每个结点都有资源信息集,些集可以为空。资源信息集和由分离资源集(RR)的特殊名字相关联。在集中的RR顺序没有关系,标记有这东西就是了,它不用由名字服务器,resovler或DNS的其它部分保存,只在这儿有。特定的RR我们认为有以下几个:

owner
RR能够被找到的域名

它是一个16位值,指定RR内的资源类型,它指一个抽象资源,具体的标记有以下几个:

A
主机地址

CNAME
一个拟名的统一命名

HINFO
标记由主机使用折CPU和OS

MX
标记用于域的邮件交换资源

NS
此域的权威认证名字服务器

PTR
指向其它域名空间的指针

SOA
标记区认证权威的开始

class
它是一个16位值,标记协议族或某一个协议实例,本文中使用IN代表internet系统,CH代表Chaos系统

TTL
它是RR的生存时间,它是32位整数,单位是秒,它主要用于resolver缓存RR多长时间

它是一种类型,有时是依赖于数据的类,它描述了以下资源:

A
对于class是IN的,它是一个32位IP地址,对于CH,它是后面跟一个16位八进制Chaos地址的域名

CNAME
域名

MX
作为一个域的邮件服务资源的主机名,主机名后有一个16位的配置值

NS
主机名

PTR
域名

SOA
一些域


拥有资源的名字通常是隐式的,不构成RR的一部分。TTL时间只影响缓冲内的数据,不影响区内的已经保存的认证数据。TTL通常由管理员设置,TTL=0表示禁止缓冲。RDATA内的数据是二进制串和域名的混合。域名通常使用指针指向DNS内的其它数据。

2.6.1. RR的文本表示

RR在DNS中是以二进制形式表示的,而在名字服务器或resolver中保存的时是经过压缩编码处理的。本文中我们采用相同于主文件中表示的表示方法,也就是不压缩的方法,以便显示RR的内容。行开始时给出谁拥有RR,如果这一位置空出,就表示本行RR的拥有者和上面RR的拥有者是一个。其后是TTL,type和RR的class。RR的RDATA部分是在当前数据的表示类型的基础上得到的。下面是一些RR的例子:

ISI.EDU. MX 10 VENERA.ISI.EDU.

MX 10 VAXA.ISI.EDU.

VENERA.ISI.EDU. A 128.9.0.32

A 10.1.0.52

VAXA.ISI.EDU. A 10.2.0.27

A 128.9.0.33

其中我们注意到MX那一部分,它的RDATA部分有是一个16位数后面跟一个域名组成。其它的也就不说了。本例子显示了6个RR,第三个域名有两个RR。下面是一个例子,它显示在不同的class下如何表示:

XX.LCS.MIT.EDU. IN A 10.0.0.44

CH A MIT.EDU. 2420

2.6.2. 别名和统一命名

现存的系统中有时会对相同的资源有不同的命名,不但主机是这样,邮箱也是这样,不同的名字指向的是同一个位置。大部分系统都能够对多个名字指定一个是统一命名的结果,另外的是别名。域名系统提供使用统一命名的机制(CNAME RR),CNAME RR标记它的owner名为别名,并指出在RDATA部分的相应统一命名。如果一个结点存在CNAME RR,不应该有其它的数据,这保证了统一命名和它的别名不能不同。这也使得缓冲的CNAME可以不用检索认证权威服务器就可以提供服务。在有CNAME RR时,DNS软件如果查询不到与域名相关的资源,它会检查资源集中是不是有一个有匹配class的CNAME,如果有,名字服务器返回的应答中包括这个CNAME记录,并根据在CNAME中指定的数据开始新的查询。下面我们看一个例子,假设名字服务器处理对USC-ISIC.ARPA的查询,它要求查询A信息,下面是RR的内容:

USC-ISIC.ARPA IN CNAME C.ISI.EDU

C.ISI.EDU IN A 10.0.0.52

这两个RR都作为响应返回,而只查询CNAME的*查询则只返回CNAME。

RR中指向其它名字的域名应该指向主名而不是别名,这就避免了查询中过多的转向查询。例如,对于上面的RR,它的IN-ADDR.ARPA记录应该是:

52.0.0.10.IN-ADDR.ARPA IN PTR C.ISI.EDU

最后指向的是C.ISI.EDU,而不是USC-ISIC.ARPA,当然一个健壮的域名软件不会因为提供了循环的CNAME而失败。

2.7. 查询

查询就是发向名字服务器要求响应的一个请求。在Internet上,这种请求以UDP或TCP传输,名字服务器的响应可以是查询结果,或是另一个名字名字器地址,要么就是一个错误信息。通常用户并不直接发送请求,而是向resolver发送请求,由resolver依次将一个或多个请求发向名字服务器,并负责处理错误情况。请求和响应有标准格式,它们包括一个头和数个固定的域,然后是包括查询参数和RR的四个部分。头中最重要的域是称为操作符的东西,它指出要进行什么操作。在所有可能的16个值中,标准查询是必须的,反向查询和状态查询是可选的,有一个完全查询已经过时,其它的还未指定。而上面的提到的四个部分如下:

Question
包括查询名和其它参数

Answer
包括查询结果的RR

Authority
包括一个RR,但这个RR包括的是另一个名字服务器

Additional
包括了一个些在其它部分中使用RR时会有用的信息


请注意:因头中操作符(码)的不同,这些部分的内容可能不同,但格式可是一样的。

2.7.1. 标准查询

标准查询指定一个目标域名(QNAME),查询类型(QTYPE)和查询类(QCLASS),然后寻找相应的RR,这类的查询占了DNS查询的绝大部分,如果未有特殊说明,一般都指这种查询。

QTYPE和QCLASS域为16位,是定义的type和class的超集。QTYPE域可以包括:

<any type>:和相应类型相匹配的RR matches just that type. (e.g., A, PTR).

AXFR:由QTYPE指定的特定区

MAILB:和RR相关的所有邮箱

*:所有RR类型

QCLASS域可以包括:

<any class>:和相应类相匹配的RR

*:所有的RR类

使用查询域名,QTYPE和QCLASS,名字服务器就会检查相应的RR,服务器可以返回一个可能包括相应RR的服务器名。例如:希望向Mockapetris@ISI.EDU发邮件,应用程序会向resolver要求了解关于ISI.EDU的信息,会产生下面的查询:QNAME=ISI.EDU,QTYPE=MX,QCLASS=IN,可能产生响应的区可能是:

ISI.EDU. MX 10 VENERA.ISI.EDU.

MX 10 VAXA.ISI.EDU.

随此以外还有:

VAXA.ISI.EDU. A 10.2.0.27

A 128.9.0.33

VENERA.ISI.EDU. A 10.1.0.52

A 128.9.0.32

服务器假设如果请求者希望得到邮件交换(exchange)信息,它会马上请求交换服务器的地址,所以找到两个。这里需要注意QCLASS=*类型的查询,因为服务器不可能知道了解域名系统中所有类的可用信息,它也不是所有类的认证权威,因此这类查询不能得到认证。

2.7.2. 反向查询(可选)

名字服务器可以反映资源和域名之间的映射关系。标准查询可以对将域名映射到SOA RR,相应的反向查询则映射SOA RR到域名。

对于名字服务器来说这种实现是可选的,但是所有的名字服务器必须至少能够理解反向查询消息,不能说发来的消息当不知道。域名系统不保证反向查询的完全和唯一性,因为系统是按照域名而非主机地址或其它资源类型安排的。反向查询主要用于调试,以及和数据库支持相关的活动中。反向查询可以不返回正确的TTL,也不标明RR是某个集合中的一员,我们不知道它是不是唯一的,因此反向查询的结果不缓冲。反向查询对于映射主机地址到主机名是不合适的,此时要用IN-ADDR.ARPA域。

2.8. 状态查询(实验中)

没有定义

2.9. 完整查询(过时的)

这里就不说了,以后可能会支持重设计(redegsign)服务。

3. 名字服务器

3.1. 介绍

名字服务器保存了许多信息,这些信息组成了域数据库。数据库被分为区,这些区在不同的服务器上保存。服务器可以有不同的可选函数和数据源,它最基本的工作是响应查询,它的响应是是一种简单的形式进行的,响应可以仅根据本地数据作出,也可以根据其它相关服务器而做出。一个给定的区可以根据不同的服务器来保证其有效性,通过管理命令,用户可以查询由至少两台服务器保存的一个区上的数据,多台服务器保存信息保证了适当的冗余。

给定的名字服务器通常支持一个或多个区,但只充当域树一小部分的认证权威。它有一些缓冲的非认证信息,这些信息是域树其它部分的,在响应查询时名字服务器会给出什么时它认证的,什么是它缓冲的。

3.2. 数据库如何被划分为区

划分数据库有两种方法,一种是根据class,另一种是在名字空间的结点间进行分隔,而产生,我们称这种分隔为cut。class(以下我们称为类)分隔比较简单,在传统上,名字空间和所有类是一回事,分隔的类可被认为是一系列平行的名字空间树。创建新类的通常理由是要为已有的类型创建新的数据格式,或是为了对已有的名字空间进行分隔管理。在一个类中可在两个相邻的结点进行cut(以下我们称为切分),在所有的切分完成后,相连空间的每个组就是一个独立的区。此区是在相连区域内所有数据的认证权威。

这种方法意味着所有的区至少有一个结点,域名和所有特定区内的结点是相连的。给定的树型结构一定有一个点更加靠近根,我们用这个点标记这个区。虽然可能没什么用,也可以将每个域名分在不同的区中,也可以让所有的结点在一个区中。另外,数据库也可根据不同企业对名字的控制进行划分,有些企业可能希望自己管理某一部分域名子树,这时这个企业就可以对域名进行相应的增加或删除操作,可以自己加入自己的下一级域名。当然,这个企业也可以对自己管理的名字空间进行进一步划分。

3.2.1. 技术问题

描述一个区的数据有四部分:

区中所有结点的认证数据

定义区内顶结点的数据(此数据可被认为是认证数据的一部分)

描述代表子区的数据

访问服务器子区的数据(我们也称为“相关”(glue)数据)

所有这些数据以RR的形式表示,所有区可以被RR集的形式描述。通过传输RR,可以传输整个区,具体的方法可以是通过FTP传输相应的文本文件,或是通过网络消息的形式传输。一个区的认证数据是所有的RR,这些RR和树中所有的结点是关联的,要么就是切分后的结点关联。描述顶结点的RR对于区的管理特别重要,这些RR有两种类型,名字服务器RR,它描述了区中的服务器列表;另一种是SOA RR,它描述的区的管理参数。

描述切分的RR是NS RR,因为切分是在结点间进行的,所有RR不是区认证数据的一部分,它应该和相应的在子区内的顶结点一致。因为名字服务器通常和区边界相关,NS RR只在一些区的顶结点上有。在组成一个区的数据中,NS RR在顶层结点和在边界底的切分处出现,不在其它地方。

区结构所要实现的一个目标是任何区都有足够的数据可以和任何子区建立通信。也就是说,父区有足够的信息可以访问子区中的任何一台名字服务器。NS RR命名了子区服务器,它不足以完成上面的要求,因此有了名字但仍然不知道地址。特别地,如果名字服务器的名字在子区内是它自己,我们就无法知道通过它的任何信息了。为了解决这一问题,区中包括了一个关联RR,它不是认证权威数据的一部分,但它表示了服务器的地址。如果名字服务器名在切分下,就需要这些RR了。

3.2.2. 管理问题

当有些组织希望掌握自己的域时,第一步是标记合适的父区,然后取得父区中管理结点的许可来管理。管理的时候没有什么具体的技术问题,可是还是有一些规则的,对中型的区可以没有这些规定,但是小型的就不行了。本文不具体讨论这一问题了,有兴趣可参阅相关的资料。

一旦选择了子区的名字,此区的新管理结点要冗余的名字服务器来支持。注意:没有要求一个区的服务器必须在此域中有名字的主机上。在许多种情况下,一个区要想被更容易地访问到最好把内容放得分散一点,不要集中在一起。现在许多国家的名字服务器是放置在别国的,这样在取得名字解析的时候不用把请求千里迢迢送到远程主机上去了。作为配置的最后一步,就是要选择NS RR和关联RR。

3.3. 深入名字服务器

3.3.1. 查询和响应

名字服务器的主要内容就是响应标准查询。查询和响应有专用的格式,查询包括QTYPE,QCLASS和QNAME,它描述了需要数据的类型,类(class)和名字。服务器的响应取决于它支持不支持循环查询:

最简单的是不支持循环查询,它返回的要么是本地信息,要么是一个错误码,告诉用户你要的信息这里没有,然后再返回一个邻近服务器的地址,让用户到那里去查一查。

如果支持循环查询,那名字服务器如果未能在本地找到相应的信息,就代替用户向其它服务器进行查询,这时它是代替用户扮演了resolver的角色,直到最后把结果找到(也可能根本没有结果,那就返回错误),并返回给用户为止。

使用循环查询要客户和服务器双方都支持才行。这个信息通过查询和响应中的两位来交换:

如果允许循环查询则设置RA位,服务器方可以不管客户是否进行请求而直接设置此位

查询中如果请求循环查询则设置RD位,客户只有在知道服务器方支持循环查询后才能够进行循环查询请求

客户可以在响应中同时设置RA和RD位来确认是否支持循环查询请求。请注意:服务器在客户未指明RD位时不会自己进行循环查询。

如果请求了循环查询,同时也支持循环查询,对查询的响应会是以下之一:

查询指定的CNAME RR有多个别名

指定的名字服务器不存在

临时错误

如果未请求循环查询或不支持循环查询,则响应可以可能是:

- 认证权威服务器指出名字不存在

- 临时错误

另外还会提供一些信息,指出所查询的RR是否从一个区来,或者是不是被缓存;另一种信息指明名字服务器指出还有一个服务器拥有相同的记录,这个服务器更靠近要查询的名字的祖先。

3.3.2. 算法

名字服务器使用的算法和本地操作系统和数据结构相关,下面的算法假设RR以几个树型结构组织,一个树就是区,有一个树是用于缓冲的:

是不是支持循环查询要看服务器,如果支持,而且需要循环查询,转到第5步;

查询最靠近QNAME祖先的结点所在的区,如果未找到这个区,转第4步;

开始在区内从上到下进行匹配,匹配过程的结束条件有以下几个:

如果整个QNAME匹配了,我们就找到了。如果数据所在结果是CNAME,QTYPE不匹配CNAME,复制CNAME RR到响应的应答区,将QNAME改变为CNAME RR中的标准形式后返回第1步;否则复制所有匹配QTYPE的RR到响应的应答区,然后转第6步;

如果匹配的结果使我们离开了认证权威,我们就获得一个参照(referral),我们这时会碰到一个带有NS RR的结点,复制NS RR到响应的认证区内,在其它区域随便放上什么地址,如果从认证数据或缓冲内没有获得地址,可以使用关联RR。然后转到第4步;

如果在一些标记上不可能有匹配,看看是不是有"*"标记存在,如果"*"标记不存在,检查我们要查找的名字是不是QNAME,如果名字就是原来的QNAME,在响应中设置错误,否则退出。如果"*"存在,以RR和QTYPE匹配,如果匹配成功,将它们复制到响应中,但设置RR的拥有者(owner)为QNAME,不是带有"*"的结点,然后转到第6步;

在缓冲中进行匹配,如果在缓冲中找到QNAME,将所有和它关联的而且匹配QTYPE的RR复制到响应区,如果没有从认证权威来的授权,可以在缓冲中寻找最好的一个,将它放在认证区内,然后转到第6步;

使用本地resolver响应请求。保存包括中间CNAME在内的结果到应答中。

仅使用本地数据,试着加入其它有用的RR到查询的附加部分。然后退出。

3.3.3. Wildcard

在前面的算法中,我们对其拥有者以*开始的RR进行了特殊处理,这类的RR称为wildcards。Wildcard RR可以看成合成RR的指令,在有合适的条件时,服务器创建RR,这个RR的拥有者名和查询名相同,而内容是从wildcard RR获得的。这种机制经常用于创建一个区,这个区可用于在网络上从一个邮件系统向另一个邮件系统转发邮件。这种情况下,通常的假设是区中的所有名字都存在,只要没有说不存在,都认为有。

wildcard RR的内容遵守通常RR的格式,区中的wildcard有一个拥有者名,它控制者可以进行匹配的查询名。wildcard RR的拥有者名是以下的形式:"*.<anydomain>",其中<anydomain>是任何域名,<anydomain>不应该再包括其它*标记,而且它应该在区的认证数据之中。我们可以把wildcard看成是通配符的作用。wildcard RR在以下情况中不适用:

查询在应该在别的区中;

如果区中已经存在了它所代表的某个域。例如,如果wildcard RR有"*.X",区中包括了B.X,那么wildcard就不代表B.X,A.B.X或X,而只能代表Z.X了。

在查询名中的*没有什么特殊作用,它只用于在认证权威区中检测wildcard,这样的查询是唯一可以在响应中获得包括拥有者名中包含*的查询请求,其它请求的响应都不能包含*。这样查询的结果不能缓冲。在合成RR时,wildcard RR的内容不应该被改变。

下面是一个例子,我们假设一个大公司有一个大型的非TCP/IP网络,它要创建一个邮件网关。如果公司是X.COM,而TCP/IP网关为A.X.COM,下面的RR可能会在COM区中:

X.COM
MX
10
A.X.COM

*.X.COM
MX
10
A.X.COM

A.X.COM
A
1.2.3.4
 
A.X.COM
MX
10
A.X.COM

*.A.X.COM
MX
10
A.X.COM


对于所有X.COM中的MX查询,都会得到A.X.COM。存在两个wildcard RR是必须的,因为有A.X.COM,就必须要有*.A.X.COM,否则W.A.X.COM就查询不出来,原因请在本节中的wildcard RR不适用的情况中寻找。

3.3.4. 否定响应缓冲(可选)

DNS可以允许服务器提供一种否定响应缓冲服务,在这种服务下服务器返回一个否定响应和一个TTL,resolver可以认为在TTL的时间之内相同的查询都会获得否定响应。同样的,resolver可以进行一个配置多个类型的查询,并缓冲不存在的类型。

实现的方法是当数据是被认证时服务器加入一个SOA RR到响应的附加区域,SOA必须是那个区的,而且这个区必须中响应中数据的认证权威区,SOA的MINIMUM域控制缓冲否定响应的时间。在有些情况下,响应数据可能包括多个拥有者名,这时SOA机制应该用于匹配QNAME的数据上,它才是唯一被认证了的数据。服务器和resovler不应该试图添加SOA到非认证响应的附加区域,也不应该进行任何推测。

这个功能是可选的,虽然现在它越来越有可能成为标准,但是服务器并非非要加SOA RR到所有的认证响应中去,resolver也不一定非要缓冲否定结果。所有的resolver和支持循环查询的服务器都应该可以忽略SOA RR。

3.3.5. 区的维护与传输

区管理员的部分工作是维护所有服务器上的区数据。当必须要进行修改时,修改必须让所有的名字服务器知道。这一过程可以通过FTP或其它什么过程完成,而推荐的方法是DNS协议的区传输部分所指出的方法。通常的自动更新模式是一个服务器是区的主服务器,管理员对区内的域名文件(master file)进行修改,修改后管理员通知主服务器装载新的数据,其它的非主服务器定期和主服务器进行同步。

为了知道是否发生了修改,非主服务器必须检查SOA的SERIAL域,只要有改变,SERIAL域就会改变,这种改变可能是加一,也可能是其它的什么算法,反正变了就行。因为我们改变的域大小是有范围的,因此理论上必须有一个修改的时间间隔,基本上,老的复本必须在序列号(就是那个域)用完其空间一半时消失。实际上只要保证比较操作的正确性就可以了。

非主服务器的定期同步由区内SOA RR的参数REFRESH,RETRY和EXPIRE决定。当非主服务器装入新区时,它会在REFRESH秒后向主服务器查询新序列号,如果查询未能完成,它会每隔RETRY秒重新进行一次。如果查询得到的序列号和原来的序列号一样,则不需要进行改变。在REFRESH时间间隔后重新开始。如果非主服务器在EXPIRE间隔后不能进行查询,它必须抛弃现有的区数据。

当查询后知道区内的数据已经改变,非主服务器必须通过AXFR请求请求主服务器传送区数据。AXFR可能会被拒绝而产生错误,但是通常情况下会得到一系列响应信息。第一个和最后一个信息必须包括区内顶认证结点的数据。中间的信息包括区内其它RR的信息,包括认证的和非认证的。这些数据使非主服务器得到区数据的复本,因为必须保证数据的准确,我们必须使用基于连接的协议。以上的查询操作不但可以在主服务器非主服务器之间进行,而且可以在非主服务器之间进行。这可以提高整体的运行效率。

4. RESOLVERS

4.1. 介绍

Resolver是用户程序和域名服务器之间的接口,最简单的情况下,resolver接收从用户来的请求,返回符合本地数据格式的查询结果。resolver和请求DNS服务的程序在同一台机器上,但DNS服务器则在其它机器上,因为resolver可能要查询多个名字服务器,所有它需要有一个本地缓冲,而查询的时间则可能因具体查询不同而差别很大。resolver的一个重要作用是就是它有一个多个程序可以共享的缓冲区,这里保存着一些查询结果,使用这些结果可以减少对服务器反复的查询。

4.2. 客户-resolver接口

4.2.1. 典型函数

这个接口因主机不同而不同,但有三个函数是大家必须都有的:

主机名到主机地址转换,此函数通常定义用来模拟原来基于HOSTS.TXT的函数。给定一个字符串,返回一个32位IP地址,在DNS下,它转换为请求类型A的RR请求。因为DNS不保存RR的顺序,函数会进行排序将返回的许多地址中的一个返回给用户。请注意:最好是返回多个地址,但单个地址是模拟原来基于HOSTS.TXT服务的。

主机地址到主机名转换,给定32位IP地址,返回字符串。查询时采用PRT查询,主机名加上"IN-ADDR.ARPA"后缀进行查询,如IP地址为1.2.3.4,则PTR RR查询域名"4.3.2.1.IN-ADDR.ARPA"。

通用查询函数,调用者提供QNAME,QTYPE和QCLASS,希望所有匹配的RR,函数会使用DNS格式而非本机格式返回查询结果,结果中包括所有RR的内容。

在resolver执行上面的函数时,会返回以下的结果给客户:

给定请求数据的一个或多个RR,此时resovler以合适的格式返回结果

名字错误(NE),在查询的名字不存在是会返回NE

未找到数据错误,查询的名字存在,但合适类型的数据不存在时产生这种错误,如把主机地址用于邮箱地址时会返回错误

需要注意的是,有时某些函数会在查询时名字错误和数据未找到错误会被合并为另一种类型的错误,但通常函数不会。一个原因是程序通常先查询一个名字(包括类型信息),然后是同一个名字的另外类型,如果两个错误合起来,反面会减慢查询速度。

4.2.2. 别名

当试图解析一个特殊的名字查询时,resolver可能发现这是一个别名,如果可能这种情况会返回给客户。但是经常,当resolver碰到一个CNAME时,它会重新开始一个查询。然而,在执行通常函数而且CNAME RR配置查询类型时,resolver不应该要别名。在有别名的时候有几种特殊情况。多级别名应该避免,因为太缺乏效率,但这也不应该被做为错误返回给客户。对于别名循环和别名指向不存在的名字时应该将错误返回给客户。

4.2.3. 临时错误

有时候因为网络等原因,resolver可能不能完成某个请求,这时不应该返回没有名字或未查询到这类错误。这类错误对人类用户来说可是件烦心的事。在某些时候可以阻塞请求,但这并不是个好的解决之道,特别是服务器就等它完成以转向其它任务的时候。推荐的方法是返回错误指示现在出现临时错误。

4.3. Resolver内部

每个resolver的实现都不相同,会有复杂的逻辑处理各种错误,而本文只讨论一个纲领。

4.3.1. 根(Stub)resolvers

一种实现resolver的方法就是在支持循环查询的服务器上实现,这样可以节省PC机上的资源,也可以对查询结果缓冲进行集中管理。其它的事情就是要一个支持循环查询服务器地址的文件在PC机上,PC机上资源有限,支持一个域名数据库可能不太现实。用户必须确定所列的名字服务器支持循环查询,服务器可以拒绝进行任何客户的循环查询请求,因此用户必须向管理员核对。这种类型的服务有一些不足,因为循环查询较费时,根对UDP重发时间的选择比较难以确定,服务器会因为根的反复重发而崩溃。使用TCP或许会好,但这样会严重占用主机时间,使用TCP相当于实现一个实时的查询系统。

4.3.2. 资源

除了自己的资源外,resolver可以访问本地服务器保存的区数据。这会使resolver的速度加快,但是也可以让缓冲数据冲掉区数据。本文中指的本地信息是说缓冲和共享区数据,在有认证数据和缓冲数据时应该优先使用认证数据。下面的算法假设所有函数被转换为一个通常的查询函数,使用下面的数据结构代表进行中的请求的状态:

SNAME
要查询的域名

STYPE
查询请求的QTYPE

SCLASS
查询请求的QCLASS

SLIST
表示正在查询的名字服务器和区,它保存resolver的预测,预测希望查询的数据在什么地方,通过接收的数据,此结构内的数据会发生变化。它包括服务器地址,区内已知的服务器,历史记录,以及表示查询距离目标还有多远的标记(查询从树顶开始向下,直到目标)。

SBELT
在resolver无法从本地信息知道应该查询哪个服务器时,它就派上用场了。

CACHE
保存前一次响应的结果,因为resolver会抛弃达到TTL时间的RR,所有大部分resolver实现将接收到RR的时间转换为绝对时间,然后保存在缓冲中,resolver可以在查询时顺便将过期RR抛弃,也可定期进行维护。


4.3.3. 算法

大体上,算法有四步:

检查结果是否在本地,如果是则直接返回;

向最合适的服务器查询;

向多个服务器发出请求,直到得到响应;

分析结果:

如果响应给出了结果或包含名字错误,缓冲并返回结果给用户;

如果响应指出更合适的服务器,缓冲这个结果,转第2步;

如果响应显示CNAME,但并不是答案,缓冲CNAME,将SNAME改为CNAME RR中的统一名称,然后转第1步;

如果响应显示服务器失败或其它不可识别的内容,从SLIST中删除此服务器,然后转第3步。

第1步在缓冲内查找,如果找到了,那就返回给用户。有些resolver可以设置不使用缓冲内的数据,但并不推荐把它做为默认情况。如果resolver能够直接访问服务器的区,而且能够找到数据的认证形式,则不要使用缓冲内的数据。

第2步向服务器查询需要的数据,通常的办法是寻找本地提供的服务器RR,提供SNAME,然后给出SNAME的父域名,父域名的父域名,以此类推,直到根。因此,如果SNAME=Mockapetris.ISI.EDU,查询NS RR的顺序为Mockapetris.ISI.EDU,ISI.EDU,EDU,最后是.(根)。NS RR列出了此区的或在SNAME之上的主机名,复制名字到SLIST,使用本地信息设置它们的地址,可能地址不可用,此时resolver有几种不同的选择,最好是进行并行搜索,一个搜索现在可用的,一个去寻找新的,当然实现起来就有麻烦了,我们把实现的一些规则列于下面:

加入一些限制,让请求不会进入无限循环,也不会造成对链式请求和对其它服务的链式请求,即使在有人错误配置的情况下也不能造成上述情况

尽一切可以获得响应

避免不必要的传输

尽快获得响应

如果查询NS RR失败,resolver从SBELT中初始化SLIST,基本的思想是当resolver不知道哪个服务器在工作时,它会从一个配置文件中取得相应的信息。虽然是特殊情况,但基本上要有两个根服务器地址存在于这种配置文件中。有两个是为了冗余,根服务器可以对所有的域空间进行探索,两个本地服务器将允许resolver继续尝试利用本地资源解析域名。除了名字的名字和地址,SLIST中可以保存服务器的优先查询顺序,保证高优先级在前,本地服务器在远程服务器前,也可能是由成功的统计结果得到,算法不尽相同。

第3步发出请求,直到收到响应。算法基本思想是对所有列出的服务器以循环方式进行发送。实际上,要重视多穴(multihomed)主机的多个地址,在使用多个resolver的时候要注意对相同主机进行重新传输对时间的影响。SLIST通常包括一个值,用于控制和监视传输的超时。

第4步涉及分析结果,resovler应该检查响应的ID域看是不是和请求的ID一致。理想的响应是从认证权威那里收到的数据,它要么给出需要的数据,要么给出名字错误。在TTL大于0的时候,结果保存于缓冲,同时结果返回给用户。如果结果指出其它服务器A,要对这个服务器A和SLIST中的主机进行比较,看是不是更合适,这可以通过比较SLIST中的匹配计数完成,这个匹配计数是通过SNAME和服务器A中的NS RR计算得到。如果不合适,这个响应会被忽略,如果合适,结果会被缓冲,相应的服务器会进入SLIST,新的查询开始。如果响应包括CNAME,新查询将从CNAME开始,除非响应有标准格式的数据,或CNAME就中结果。

5.例子

在我们的例子空间中,假设我们希望将根管理权分散到MIL,EDU,MIT.EDU和ISI.EDU区,我们可以按下图分配名字服务器:(认证权威将被加上括号)



                                   (C.ISI.EDU,SRI-NIC.ARPA
                                    A.ISI.EDU)
            +---------------------+------------------+
                                                     
           MIL                   EDU                ARPA
             (SRI-NIC.ARPA,        (SRI-NIC.ARPA,    
              A.ISI.EDU             C.ISI.EDU)       
      +-----+-----+                     +------+-----+-----+
                                                           
     BRL  NOSC  DARPA                IN-ADDR  SRI-NIC     ACC
                                  
      +--------+------------------+---------------+--------+
                                                           
     UCI      MIT                                UDEL     YALE
                (XX.LCS.MIT.EDU, ISI
                ACHILLES.MIT.EDU)  (VAXA.ISI.EDU,VENERA.ISI.EDU,
           +---+---+                A.ISI.EDU)
                                  
          LCS   ACHILLES +--+-----+-----+--------+
                                                 
           XX            A  C   VAXA  VENERA Mockapetris
根名字服务器在C.ISI.EDU,SRI-NIC.ARPA和A.ISI.EDU,MIL域由SRI-NIC.ARPA和A.ISI.EDU支撑;EDU域由SRI-NIC.ARPA和C.ISI.EDU,服务器拥有的区可以连接也可以不连接,本例中,C.ISI.EDU和根及EDU域连接,A.ISI.EDU和根及MIL域有连接,但和ISI.EDU有一个不连接的区。

5.1. C.ISI.EDU名字服务器

C.ISI.EDU是IN级的根,MIL,EDU域的名字服务器,也拥有这些域的区,对根域的区数据如下:

   .       IN      SOA     SRI-NIC.ARPA. HOSTMASTER.SRI-NIC.ARPA. (
                           870611          ;serial
                           1800            ;refresh every 30 min
                           300             ;retry every 5 min
                           604800          ;expire after a week
                           86400)          ;minimum of a day
                   NS      A.ISI.EDU.
                   NS      C.ISI.EDU.
                   NS      SRI-NIC.ARPA.
   MIL.    86400   NS      SRI-NIC.ARPA.
           86400   NS      A.ISI.EDU.
   EDU.    86400   NS      SRI-NIC.ARPA.
           86400   NS      C.ISI.EDU.
   SRI-NIC.ARPA.   A       26.0.0.73
                   A       10.0.0.51
                   MX      0 SRI-NIC.ARPA.
                   HINFO   DEC-2060 TOPS20
   ACC.ARPA.       A       26.6.0.65
                   HINFO   PDP-11/70 UNIX
                   MX      10 ACC.ARPA.
   USC-ISIC.ARPA.  CNAME   C.ISI.EDU.
   73.0.0.26.IN-ADDR.ARPA.  PTR    SRI-NIC.ARPA.
   65.0.6.26.IN-ADDR.ARPA.  PTR    ACC.ARPA.
   51.0.0.10.IN-ADDR.ARPA.  PTR    SRI-NIC.ARPA.
   52.0.0.10.IN-ADDR.ARPA.  PTR    C.ISI.EDU.
   103.0.3.26.IN-ADDR.ARPA. PTR    A.ISI.EDU.
   A.ISI.EDU. 86400 A      26.3.0.103
   C.ISI.EDU. 86400 A      10.0.0.52
这些数据可能存在于配置文件中(master file)中。大多数RR是一行一个,唯一的例外是SOA RR,它表示多行RR的结束。因为一个区中的所有RR的class必须相同,因此只有区中的第一个RR需要指定class。当服务器装入一个区时,它设置所有认证数据的TTL至少于SOA域的MINUMUM那么大或为一天,这里为86400秒。NS RR标记了MIL和EDU域的相关服务器,它和服务器地址关联RR一起的,但是NS RR并不是区中认证数据。

有四个RR和根结点相关:一个描述根区的RR,3个用于列出根的名字服务器。在SOA RR中的数据描述对区的管理。区数据由主机SRI-NIC.ARPA保存,区的责任方是HOSTMASTER@SRI-NIC.ARPA,SOA的主要条目是86400秒(TTL),这就意味着区中所有认证数据至少是TTL,也可以指定更大的数值。

MIL和EDU域的NS RR标准了根区和MIL,EDU区的边界。注意本例中支持最低区的服务器也支持根区。EDU区中的配置文件(master file)必须相对于源EDU设置,EDU域中的数据可能是:

   EDU.  IN SOA SRI-NIC.ARPA. HOSTMASTER.SRI-NIC.ARPA. (
                           870729 ;serial
                           1800 ;refresh every 30 minutes
                           300 ;retry every 5 minutes
                           604800 ;expire after a week
                           86400 ;minimum of a day
                           )
                   NS SRI-NIC.ARPA.
                   NS C.ISI.EDU.
   UCI 172800 NS ICS.UCI
                   172800 NS ROME.UCI
   ICS.UCI 172800 A 192.5.19.1
   ROME.UCI 172800 A 192.5.19.31
   ISI 172800 NS VAXA.ISI
                   172800 NS A.ISI
                   172800 NS VENERA.ISI.EDU.
   VAXA.ISI 172800 A 10.2.0.27
                   172800 A 128.9.0.33
   VENERA.ISI.EDU. 172800 A 10.1.0.52
                   172800 A 128.9.0.32
   A.ISI 172800 A 26.3.0.103
   UDEL.EDU.  172800 NS LOUIE.UDEL.EDU.
                   172800 NS UMN-REI-UC.ARPA.
   LOUIE.UDEL.EDU. 172800 A 10.0.0.96
                   172800 A 192.5.39.3
   YALE.EDU.  172800 NS YALE.ARPA.
   YALE.EDU.  172800 NS YALE-BULLDOG.ARPA.
   MIT.EDU.  43200 NS XX.LCS.MIT.EDU.
                     43200 NS ACHILLES.MIT.EDU.
   XX.LCS.MIT.EDU.  43200 A 10.0.0.44
   ACHILLES.MIT.EDU. 43200 A 18.72.0.8
请注意相对名字的使用,ISI.EDU.的拥有者是一个相对名。文件可以使用相对名和绝对名,混合使用。

5.2. 标准查询例子

下面的查询和响应显示了服务器的动作,除非说明,查询都没有进行循环查询。注意,对非循环查询的响应必须依赖于查询的服务器,不依赖于请求者。

5.2.1. QNAME=SRI-NIC.ARPA,QTYPE=A

查询如下:

              +---------------------------------------------+
   Header       OPCODE=SQUERY                               
              +---------------------------------------------+
   Question     QNAME=SRI-NIC.ARPA., QCLASS=IN, QTYPE=A     
              +---------------------------------------------+
   Answer       <empty>                                     
              +---------------------------------------------+
   Authority    <empty>                                     
              +---------------------------------------------+
   Additional   <empty>                                     
              +---------------------------------------------+
响应应该是:
              +--------------------------------------------+
   Header       OPCODE=SQUERY, RESPONSE, AA                
              +--------------------------------------------+
   Question     QNAME=SRI-NIC.ARPA., QCLASS=IN, QTYPE=A    
              +--------------------------------------------+
   Answer       SRI-NIC.ARPA. 86400 IN A 26.0.0.73         
                              86400 IN A 10.0.0.51         
              +--------------------------------------------+
   Authority    <empty>                                    
              +--------------------------------------------+
   Additional   <empty>                                    
              +--------------------------------------------+

响应的头和查询头挺象,除了RESPONSE位的设置不同,还有就是AA位的设置,表示此数据来自认证权威。响应的question区和查询的question区一致。如果相同的查询发送到其它非SRI-NIC.ARPA的认证性质服务器,响应可能是:

              +---------------------------------------------------+
   Header       OPCODE=SQUERY,RESPONSE                            
              +---------------------------------------------------+
   Question     QNAME=SRI-NIC.ARPA., QCLASS=IN, QTYPE=A           
              +---------------------------------------------------+
   Answer       SRI-NIC.ARPA. 1777 IN A 10.0.0.51                 
                              1777 IN A 26.0.0.73                 
              +---------------------------------------------------+
   Authority    <empty>                                           
              +---------------------------------------------------+
   Additional   <empty>                                           
              +---------------------------------------------------+

这个响应和上面的响应不同,AA位不同,TTL不同,此数据可能不来自于一个区,而来自缓冲。认证TTL和这里的TTL不同是因为处于缓冲中的原因,响应区中的RR的不同不用注意。

5.2.2. QNAME=SRI-NIC.ARPA,QTYPE=* 

这个查询和上面的很象,但是QTYPE=*,从C.ISI.EDU接收到的响应如下: 

              +---------------------------------------------------+
   Header       OPCODE=SQUERY, RESPONSE, AA                       
              +---------------------------------------------------+
   Question     QNAME=SRI-NIC.ARPA., QCLASS=IN, QTYPE=*           
              +---------------------------------------------------+
   Answer       SRI-NIC.ARPA. 86400 IN  A     26.0.0.73           
                                        A     10.0.0.51           
                                        MX    0 SRI-NIC.ARPA.     
                                        HINFO DEC-2060 TOPS20     
              +---------------------------------------------------+
   Authority    <empty>                                           
              +---------------------------------------------------+
   Additional   <empty>                                           
              +---------------------------------------------------+
如果相同的查询发到两个非SRI-NIC.ARPA区中的非认证性质的服务器,响应如下:
              +---------------------------------------------------+
   Header       OPCODE=SQUERY, RESPONSE                           
              +---------------------------------------------------+
   Question     QNAME=SRI-NIC.ARPA., QCLASS=IN, QTYPE=*           
              +---------------------------------------------------+
   Answer       SRI-NIC.ARPA. 12345 IN     A       26.0.0.73      
                                           A       10.0.0.51      
              +---------------------------------------------------+
   Authority    <empty>                                           
              +---------------------------------------------------+
   Additional   <empty>                                           
              +---------------------------------------------------+

              +---------------------------------------------------+
   Header       OPCODE=SQUERY, RESPONSE                           
              +---------------------------------------------------+
   Question     QNAME=SRI-NIC.ARPA., QCLASS=IN, QTYPE=*           
              +---------------------------------------------------+
   Answer       SRI-NIC.ARPA. 1290 IN HINFO  DEC-2060 TOPS20      
              +---------------------------------------------------+
   Authority    <empty>                      &n
网络的神奇作用吸引着越来越多的用户加入其中,正因如此,网络的承受能力也面临着越来越严峻的考验―从硬件上、软件上、所用标准上......,各项技术都需要适时应势,对应发展,这正是网络迅速走向进步的催化剂。

……

相关阅读