TCP/IP详解(三) 

JavaGG 发布于 2009/05/05 15:00
阅读 846
收藏 3

TCP/IP详解(三)  

6.6 ICMP报文的4.4BSD处理 
由于ICMP覆盖的范围很广泛,从致命差错到信息差错,因此即使在一个给定的系统实现中,对每个ICMP报文的处理都是不相同的。图6.12的内容与图6.3相同,它显示的是4.4BSD系统对每个可能的ICMP报文的处理方法。 
如果最后一列标明是“内核”,那么ICMP就由内核来处理。如果最后一列指明是“用户进程”,那么报文就被传送到所有在内核中登记的用户进程,以读取收到的ICMP报文。如果不存在任何这样的用户进程,那么报文就悄悄地被丢弃。(这些用户进程还会收到所有其他类型的ICMP报文的拷贝,虽然它们应该由内核来处理,当然用户进程只有在内核处理以后才能收到这些报文。)有一些报文完全被忽略。最后,如果最后一列标明的是引号内的一串字符,那么它就是对应的Unix差错。其中一些差错,如TCP对发送端关闭的处理等,我们将在以后的章节中对它们进行讨论。 

(下面是图6.12的译文) 
类型 
代码 
描述 
处理方法 


回显回答 
用户进程 


目的不可到达: 



网络不可到达 
“无路由到达主机” 


主机不可到达 
“无路由到达主机” 


协议不可到达 
“连接被拒绝” 


端口不可到达 
“连接被拒绝” 


需要进行分片但设置了不分片比特DF 
“报文太长” 


源站路由选择失败 
“无路由到达主机” 


目的网络不认识 
“无路由到达主机” 


目的主机不认识 
“无路由到达主机” 


源主机被隔离(作废不用) 
“无路由到达主机” 


目的网络被强制禁止 
“无路由到达主机” 

10 
目的主机被强制禁止 
“无路由到达主机” 

11 
由于服务类型TOS网络不可到达 
“无路由到达主机” 

12 
由于服务类型TOS主机不可到达 
“无路由到达主机” 

13 
由于过滤通信被强制禁止 
(忽略) 

14 
主机越权 
(忽略) 

15 
优先权中止生效 
(忽略) 


源站被抑制(quench) 
TCP由内核处理,UDP则忽略 


改变路由 



对网络改变路由 
内核更新路由表 


对主机改变路由 
内核更新路由表 


对服务类型和网络改变路由 
内核更新路由表 


对服务类型和主机改变路由 
内核更新路由表 


回显请求 



路由器通告 
用户进程 
10 

路由器请求 
用户进程 
11 

超时: 



传输期间生存时间为0 
用户进程 


在数据报组装期间生存时间为0 
用户进程 
12 

参数问题: 



坏的IP首部(包括各种差错) 
“协议不可用” 


缺少必需的选项 
“协议不可用” 
13 

时间戳请求 
内核产生回答 
14 

时间戳回答 
用户进程 
15 

信息请求(作废不用) 
(忽略) 
16 

信息回答(作废不用) 
用户进程 
17 

地址掩码请求 
内核产生回答 
18 

地址掩码回答 
用户进程 
图6.12 4.4BSD系统对ICMP报文的处理 

6.7 小结 
本章对每个系统都必须包括的Internet控制报文协议进行了讨论。图6.3列出了所有的ICMP报文类型,其中大多数我们都将在以后的章节中加以讨论。 
我们详细讨论了ICMP地址掩码请求和回答以及时间戳请求和回答。这些是典型的请求-回答报文。二者在ICMP报文中都标识符和序号。发送端应用程序在标识字段内存入一个唯一的数值,以区别于其它进程的回答。序号字段使得客户程序可以在回答和请求之间进行匹配。 
我们还讨论了ICMP端口不可到达差错,一种常见的ICMP差错。我们对返回的ICMP差错信息进行了分析:导致差错的IP数据报的首部及后序8个字节。这个信息对于ICMP差错的接收方来说是必要的,可以更多地了解导致差错的原因。这是因为TCP和UDP都在它们的首部前8个字节中存入源端口号和目的端口号。 
最后,我们第一次给出了按时间先后的tcpdump输出,这种表现方式的输出在本书后面的章节中会经常用到。 

习题 
6.1 在6.2节的末尾我们列出了5种不发送ICMP差错报文的特殊条件。如果这些条件不满足而我们又在局域网上向一个似乎不存在的端口号发送一份广播UDP数据报,这时会发生什么样的情况? 
6.2 阅读RFC [Braden 1989a],注意生成一个ICMP端口不可到达差错是否为“必须”,“应该”或者“可能”。这些信息所在的页码和章节是多少? 
6.3 阅读RFC 1349 [Almquist 1992],看看IP的服务类型字段(图3.2)是如何被ICMP设置的? 
6.4 如果你的系统提供netstat命令,请用它来查看接收和发送的ICMP报文类型。 

6-9 
7 Ping程序 

7.1 引言 
“ping”这个名字来自于声纳定位操作。Ping程序由Mike Muuss编写,目的是为了测试另一台主机是否可达。该程序发送一份ICMP回显请求报文给主机,并等待返回ICMP回显回答。(图6.3列出了所有的ICMP报文类型。) 
一般来说,如果你不能Ping到某台主机,那么你就不能Telnet或者FTP到那台主机。反过来,如果你不能Telnet到某台主机,那么通常可以用Ping程序来确定问题出在哪里。Ping程序还能测出到这台主机的往返时间,以表明该主机离我们有“多远”。 
在本章中,我们将使用Ping程序作为诊断工具来深入剖析ICMP。Ping还给我们提供了检测IP记录路由和时间戳选项的机会。文献[Stevens 1990]的第11章提供了Ping程序的源代码。 

(下面是原书p.85①的译文) 
几年前我们还可以作出这样没有限定的断言,如果我们不能Ping到某台主机,那么就不能Telnet或FTP那台主机。随着Internet安全意识的增强,出现了提供访问控制清单的路由器和防火墙,那么像这样没有限定的断言不再成立了。一台主机的可达性可能不只取决于IP层是否可达,还取决于使用何种协议以及端口号。Ping程序的运行结果可能显示某台主机不可达,但我们可以用Telnet远程登录到该台主机的25号端口(邮件服务器)。 

7.2 Ping程序 
我们称发送回显请求的ping程序为客户,而称被ping的主机为服务器。大多数的TCP/IP实现都在内核中直接支持Ping服务器——这种服务器不是一个用户进程。(我们在第6章中描述的两种ICMP查询服务,地址掩码和时间戳请求,也都是直接在内核中进行处理的。) 
ICMP回显请求和回显回答报文如图7.1所示。 

图7.1 ICMP回显请求和回显回答报文格式 

对于其他类型的ICMP查询报文,服务器必须响应标识符和序号字段。另外,客户发送的选项数据必须回显,假设客户对这些信息都会感兴趣。 
Unix系统在实现ping程序时是把ICMP报文中的标识符字段置成发送进程的ID号。这样即使在同一台主机上同时运行了多个ping程序实例,ping程序也可以识别出返回的信息。 
序号从0开始,每发送一次新的回显请求就加1。ping程序打印出返回的每个分组的序号,允许我们查看是否有分组丢失,失序或重复。IP是一种最好的数据报传递服务,因此这三个条件都有可能发生。 
旧版本的ping程序曾经以这种模式运行,即每秒发送一个回显请求,并打印出返回的每个回显回答。但是,新版本的实现需要加上-s参数才能以这种模式运行。默认情况下,新版本的ping程序只发送一个回显请求,如果收到回显回答则输出“host is alive”,否则在20秒内没有收到回答就输出“no answer”(没有回答)。 

LAN输出 
在局域网LAN上运行ping程序的结果输出一般有如下格式: 

(见原书p.86的①) 

当返回ICMP回显回答时,要打印出序号和TTL,并计算往返时间。(TTL位于IP首部中的生存时间字段。当前的BSD系统中的ping程序每次收到回显回答时都打印出收到的TTL----有些系统并不这样做。我们将在第8章中通过traceroute程序来介绍TTL的用法。) 
我们从上面的输出中可以看出,回显回答是以发送的次序返回的(0,1,2等等)。 
ping程序通过在ICMP报文数据中存放发送请求的时间值来计算往返时间。当回答返回时,用当前时间减去存放在ICMP报文中的时间值,即是往返时间。注意,在发送端bsdi上,往返时间的计算结果都为0 ms。这是因为程序使用的计时器分辨率低的原因。BSD/386版本0.9.4系统只能提供10 ms级的计时器。(我们在附录B中有更详细的介绍。)在后面的章节中,当我们在具有较高分辨率计时器的系统上(Sun)查看tcpdump输出时会发现,ICMP回显请求和回显回答的时间差在4 ms以下。 
输出的第一行包括目的主机的IP地址,尽管我们指定的是它的名字(svr4)。这说明名字已经经过解析器被转换成IP地址了。我们将在第14章介绍解析器和DNS。现在,我们发现,如果敲入ping命令,几秒钟过后会在第一行打印出IP地址,DNS就是利用这段时间来确定主机名所对应的IP地址。 
本例中的tcpdump输出如图7.2所示。 

图7.2 在LAN上运行ping程序的结果 

从发送回显请求到收到回显回答,时间间隔始终为3.7 ms。我们还可以看到,回显请求大约每隔1秒钟发送一次。 
通常,第一个往返时间值要比其他的大。这是由于目的端的硬件地址不在ARP高速缓存中的缘故。正如我们在第4章中看到的那样,在发送第一个回显请求之前要发送一个ARP请求并接收ARP回答,这需要花费几毫秒的时间。下面的例子说明了这一点: 

(见原书p.88的①) 

第一个RTT中多的3 ms很可能就是因为发送ARP请求和接收ARP回答所花费的时间。 
这个例子运行在sun主机上,它提供的是具有微秒级分辨率的计时器,但是ping程序只能打印出毫秒级的往返时间。在前面运行于BSD/386 0.9.4版上的例子中,打印出来的往返时间值为0 ms,这是因为计时器只能提供10 ms的误差。下面的例子是BSD/386 1.0版的输出,它提供的计时器也具有微秒级的分辨率,因此ping程序的输出结果也具有较高的分辨率。 

(见原书p.88的②) 

WAN输出 
在一个广域网WAN上,结果会有很大的不同。下面的例子是在某个工作日的下午即Internet具有正常通信量时的运行结果: 

(见原书p.88的③) 

这里,序号为1,2,3,4,6,10,11,12和13的回显请求或回显回答在某个地方丢失了。另外,我们注意到往返时间发生了很大的变化。(像52%这样高的分组丢失率是不正常的。即使是在工作日的下午,对于Internet来说也是不正常的,。) 
通过广域网还有可能看到重复的分组(即相同序号的分组被打印两次或更多次),失序的分组(序号为N + 1的分组在序号为N的分组之前被打印。) 

线路SLIP链接 
让我们再来看看SLIP链路上的往返时间,因为它们经常运行于低速的异步方式,如9600 b/s或更低。回想我们在2.10节计算的串行线路吞吐量。针对这个例子,我们把主机bsdi和slip之间的SLIP链路传输速率设置为1200 b/s。 
下面我们可以来估计往返时间。首先,我们从前面的Ping程序输出例子中可以注意到,默认情况下发送的ICMP报文有56个字节。再加上20个字节的IP首部和8个字节的ICMP首部,IP数据报的总长度为84字节。(我们可以运行tcpdump -e命令查看以太网数据帧来验证这一点。)另外,从2.4节我们可以知道,至少要增加两个额外的字节:在数据报的开始和结尾加上END字符。此外,SLIP帧还有可能再增加一些字节,但这取决于数据报中每个字节的值。对于1200 b/s这个速率来说,由于每个字节含有8 bit数据,1 bit起始位和1 bit结束位,因此传输速率是每秒120个字节,或者说每个字节8.33 ms。所以我们可以估计需要1433(86×8.33×2) ms 。(乘2是因为我们计算的是往返时间。) 
下面的输出证实了我们的计算: 

(见原书p.89的①) 

(对于SVR4来说,如果每秒钟发送一次请求则必须带-s参数。)往返时间大约是1.5秒,但是程序仍然每间隔1秒钟发送一次ICMP回显请求。这说明在第一个回显回答返回之前(1.480秒时刻)就已经发送了两次回显请求(分别在0秒和1秒时刻)。这就是为什么总结行指出丢失了一个分组。实际上分组并未丢失,很可能仍然在返回的途中。 
我们在第8章讨论traceroute程序时将回头再讨论这种低速的SLIP链路。 

拔号SLIP链路 
对于拔号SLIP链路来说,情况有些变化,因为在链路的两端增加了调制解调器。用在sun和netb系统之间的调制解调器提供的是V.32调制方式(9600 b/s),V.42错误控制方式(也称作LAP-M),以及V.42bis数据压缩方式。这表明我们针对线路链路参数进行的简单计算不再准确了。 
很多因素都有可能影响。调制解调器带来了时延。随着数据的压缩,分组长度可能会减小,但是由于使用了错误控制协议,分组长度又可能会增加。另外,接收端的调制解调器只能在验证了循环检验字符(检验和)后才能释放收到的数据。最后,我们还要处理每一端的计算机异步串行接口,许多操作系统只能在固定的时间间隔内,或者收到若干字符后者才去读这些接口。 
作为一个例子,我们在sun主机上ping主机gemini,输出结果如下: 

(见原书p.90的①) 

注意,第一个RTT不是10 ms的整数倍,但是其它行都是10 ms的整数倍。如果我们运行该程序若干次,发现每次结果都是这样。(这并不是由sun主机上的时钟分辨率造成的结果,因为根据附录B中的测试结果可以知道它的时钟能提供毫秒级的分辨率。) 
另外还要注意,第一个RTT要比其他的大,而且依次递减,然后徘徊在280至300 ms之间。我们让它运行一分钟到两分钟,RTT一直处于这个范围,不会低于260 ms。如果我们以9600 b/s的速率计算RTT(习题7.2),那么我们观察到的值应该大约是估计值的1.5倍。 
如果运行ping程序60秒钟并计算观察到的RTT的平均值,我们发现在V.42和V.42bis模式下平均值为277 ms。(这要比上个例子打印出来的平均值要好,因为运行时间较长,这样就把开始较长的时间平摊了。)如果我们关闭V.42bis数据压缩方式,平均值为330 ms。如果我们关闭V.42错误控制方式(它同时也关闭了V.42bis数据压缩方式),平均值为300 ms。这些调制解调器的参数对RTT的影响很大,使用错误控制和数据压缩方式似乎效果最好。 

7.3 IP记录路由选项 
ping程序为我们提供了查看IP记录路由(RR)选项的机会。大多数不同版本的ping程序都提供-R参数,以提供记录路由的功能。它使得ping程序在发送出去的IP数据报中设置IP RR选项(该IP数据报包含ICMP回显请求报文)。这样,每个处理该数据报的路由器都把它的IP地址放入选项字段中。当数据报到达目的端时,IP地址清单应该复制到ICMP回显回答中,这样返回途中所经过的路由器地址也被加入清单中。当ping程序收到回显回答时,它就打印出这份IP地址清单。 
这个过程听起来简单,但存在一些缺陷。源端主机生成RR选项,中间路由器对RR选项的处理,以及把ICMP回显请求中的RR清单复制到ICMP回显回答中,所有这些都是选项功能。幸运的是,现在的大多数系统都支持这些选项功能,只是有一些系统不把ICMP请求中的IP清单复制到ICMP回答中。 
但是,最大的问题是IP首部中只有有限的空间来存放IP地址。我们从图3.1可以看到,IP首部中的首部长度字段只有4 bit,因此整个IP首部最长只能包括15个32 bit长的字(即60个字节)。由于IP首部固定长度为20字节,RR选项用去3个字节(下面我们再讨论),这样只剩下37个字节(60 - 20 - 3)来存放IP地址清单,也就是说只能存放9个IP地址。对于早期的ARPANET来说,9个IP地址似乎是很多了,但是现在看来是非常有限的。(在第8章中,我们将用Traceroute工具来确定数据报的路由。)除了这些缺点,记录路由选项工作得很好,为详细查看如何处理IP选项提供了一个机会。 
IP数据报中的RR选项的一般格式如图7.3所示。 

图7.3 IP首部中的记录路由选项的一般格式 

code是一个字节,指明IP选项的类型。对于RR选项来说,它的值为7。len是RR选项总字节长度,在这种情况下为39。(尽管可以为RR选项设置比最大长度小的长度,但是ping程序总是提供39字节的选项字段,最多可以记录9个IP地址。由于IP首部中留给选项的空间有限,它一般情况都设置成最大长度。) 
ptr称作指针字段。它是一个基于1的指针,指向存放下一个IP地址的位置。它的最小值为4,指向存放第一个IP地址的位置。随着每个IP地址存入清单,ptr的值分别为8,12,16,最大到36。当记录下9个IP地址后,ptr的值为40,表示清单已满。 
当路由器(根据定义应该是多穴的)在清单中记录IP地址时,它应该记录哪个地址呢?是入口地址还是出口地址?为此,RFC 791 [Postel 1981a]指定路由器记录出口IP地址。我们在后面将看到,当原始主机(运行ping程序的主机)收到带有RR选项的ICMP回显回答时,它也要把它的入口IP地址放入清单中。 

正常的例子 
我们举一个用RR选项运行ping程序的例子。我们在主机svr4上运行ping程序到主机slip。一个中间路由器(bsdi)将处理这个数据报。下面是svr4的输出结果: 

(见原书p.92的①) 

分组所经过的四站如图7.4所示(每个方向各有两站),每一站都把自己的IP地址加入RR清单。 

图7.4 带有记录路由选项的ping程序 

路由器bsdi在不同方向上分别加入了不同的IP地址。它始终是把出口的IP地址加入清单。我们还可以看到,当ICMP回显回答到达原始系统(svr4)时,它把自己的入口IP地址也加入清单中。 
我们还可以通过运行带有-v参数的tcpdump命令来查看主机sun上进行的分组交换(参见IP选项)。输出如图7.5所示。 

图7.5 记录路由选项的tcpdump输出 

输出中optlen=40表示在IP首部中有40个字节的选项空间。(IP首部长度必须为4字节的整数倍。)RR{39}的意思是记录路由选项已被设置,它的长度字段是39。然后是9个IP地址,符号“#”用来标记RR选项中的ptr字段所指向的IP地址。由于我们是在主机sun上观察这些分组(参见图7.4),因此我们所能看到ICMP回显请求中的IP地址清单是空的,而ICMP回显回答中有3个IP地址。我们省略了tcpdump输出中的其它行,因为它们与图7.5基本一致。 
位于路由信息末尾的标记EOL表示IP选项“end of list”(清单结束)的值。EOL选项的值可以为0。这时表示39个字节的RR数据位于IP首部中的40字节空间中。由于在数据报发送之前空间选项被设置为0,因此跟在39个字节的RR数据之后的0字符就被解释为EOL。这正是我们所希望的结果。如果在IP首部中的选项字段中有多个选项,在开始下个选项之前必须填入空白字符,另外还可以用另一个值为1的特殊字符NOP(“no operation”)。 

(下面是原书p.93①的译文) 
在图7.5中,SVR4把回显请求中的TTL字段设为32,BSD/386设为255。(它打印出的值为254是因为路由器bsdi已经将其减去1。)新的系统都把ICMP报文中的TTL设为最大值(255)。 
在作者使用的三个TCP/IP系统中,BSD/386和SVR4都支持记录路由选项。这就是说,当转发数据报时,它们都能正确地更新RR清单,而且能正确地把接收到的ICMP回显请求中的RR清单复制到出口ICMP回显回答中。虽然SunOS 4.1.3在转发一个数据报时能正确更新RR清单,但是不能复制RR清单。Solaris 2.x对这个问题已作了修改。 

异常的输出 
下面的例子是作者观察到的,我们把它作为第9章讨论ICMP间接报文的起点。我们在子网140.252.1子网上ping主机aix(在主机sun上通过拔号SLIP连接可以访问),并带有记录路由选项。在slip主机上运行有如下输出结果: 

(见原书p.94的①) 

我们已经在主机bsdi上运行过这个例子。现在我们选择slip来运行它,观察RR清单中所有的9个IP地址。 
在输出中令人感到疑惑的是,为什么传出的数据报(ICMP回显请求)直接从netb传到aix,而返回的数据报(ICMP回显回答)却从aix开始经路由器gateway再到netb?这里看到的正是下面我们将要描述的IP路由选择的一个特点。数据报经过的路由如图7.6所示。 

图7.6 运行带有记录路由选项的ping程序,显示IP路由选择的特点 

问题是aix不知道要把目的地为子网140.252.13的IP数据报发到主机netb上。相反,aix在它的路由表中有一个默认项,它指明当没有明确某个目的主机的路由时,就把所有的数据报发往默认项指定的路由器gateway。路由器gateway比子网140.252.1上的任何主机都具备更强的路由选择能力。(在这个以太网上有超过150台主机,每台主机的路由表中都有一个默认项指向路由器gateway,这样就不用在每台主机上都运行一个路由选择守护程序。) 
这里没有回答的一个问题是为什么gateway不直接发送ICMP报文改变路由到aix(9.5节),以更新它的路由表?由于某种原因(很可能是由于数据报产生的改变路由是一份ICMP回显请求报文),改变路由并没有产生。但是如果我们用Telnet登录到aix上的daytime服务器,ICMP就会产生改变路由,因而它在aix上的路由表也随之更新。如果我们接着执行ping程序并带有记录路由选项,其路由显示表明数据报从netb到aix,然后返回netb,而不再经过路由器gateway。在9.5节中我们将更详细地讨论ICMP改变路由的问题。 

7.4 IP时间戳选项 
IP时间戳选项与记录路由选项类似。IP时间戳选项的格式如图7.7所示(请与图7.3进行比较)。 

图7.7 IP首部中时间戳选项的一般格式 

时间戳选项的代码为0x44。其它两个字段len和ptr与记录路由选项相同:选项的总长度(一般为36或40)和指向下一可用空间的指针(5,9,13,等)。 
接下来的两个字段是4 bit的值:OF表示溢出字段,FL表示标志字段。时间戳选项的操作根据标志字段来进行,如图7.8所示。 

(下面是图7.8的译文) 
标志 
描述 

只记录时间戳,正如我们在图7.7看到的那样。 

每台路由器都记录它的IP地址和时间戳。在选项列表中只有存放四对地址和时间戳的空间。 

发送端对选项列表进行初始化,存放了4个IP地址和四个取值为0的时间戳值。只有当列表中的下一个IP地址与当前路由器地址相匹配时,才记录它的时间戳。 
图7.8 时间戳选项不同标志字段值的意义 

如果路由器由于没有空间而不能增加时间戳选项,那么它将增加溢出字段的值。 
时间戳的取值一般为自午夜开始计的毫秒数,UTC,与ICMP时间戳请求和回答相类似。如果路由器不使用这种格式,它就可以插入任何它使用的时间表示格式,但是必须打开时间戳中的高位以表明为非标准值。 
与我们遇到的记录路由选项所受到的限制相比,时间戳选项遇到情况要更坏一些。如果我们要同时记录IP地址和时间戳(标志位为1),那么就可以同时存入其中的四对值。只记录时间戳是没有用处的,因为我们没有标明时间戳与路由器之间的对应关系(除非我们有一个永远不变的拓扑结构)。标志值取3会更好一些,因为我们可以插入时间戳的路由器。一个更为基本的问题是,你很可能无法控制任何给定路由器上时间戳的正确性。这使得试图用IP选项来计算路由器之间的跳站数是徒劳的。我们将看到(第8章)traceroute程序可以提供一种更好的方法来计算路由器之间的跳数。 

7.5 小结 
ping程序是对两个TCP/IP系统连通性进行测试的基本工具。它只利用ICMP回显请求和回显回答报文,而不用经过传输层(TCP/UDP)。Ping服务器一般在内核中实现ICMP的功能。 
我们分析了在LAN,WAN以及SLIP链路(拔号和线路)上运行ping程序的输出结果,并对串行线路上的SLIP链路吞吐量进行了计算。我们还讨论并使用了ping程序的IP记录路由选项。利用该IP选项,我们可以看到它是如何经常使用默认路由的。在第9章我们将再次回到这个讨论主题。另外,我们还讨论了IP 时间戳选项,但它在实际使用时有所限制。 

习题 
7.1 请画出7.2节中ping输出的时间线。 
7.2 若把bsdi和slip主机之间的SLIP链路设置为9600 b/s,请计算这时的RTT。假定默认的数据是56字节。 
7.3 当前BSD版中的ping程序允许我们为ICMP报文的数据部分指定一种模式。(数据部分的前8个字节不用来存放模式,因为它要存放发送报文的时间。)如果我们指定的模式为0xc0,请重新计算上一题中的答案。(提示:阅读2.4节。) 
7.4 使用压缩SLIP(CSLIP,见2.5节)是否会影响我们在7.2节中看到的ping输出中的时间值? 
7.5 在图2.4中,ping环回地址与ping主机以太网地址会出现什么不同? 




7-7 
8 Traceroute程序 

8.1 引言 
由Van Jacobson编写的Traceroute程序是一个能更深入探索TCP/IP协议的方便可用的工具。尽管不能保证从源端发往目的端的两份连续的IP数据报具有相同的路由,但是大多数情况下是这样的。Traceroute程序可以让我们看到IP数据报从一台主机传到另一台主机所经过的路由。Traceroute程序还可以让我们使用IP源路由选项。 

(下面是原书p.97①的译文) 
使用手册上说:“程序由Steve Deering提议,由Van Jacobson实现,并由许多其他人根据C. Philip Wood, Tim Seaver 及Ken Adelman等人提出的令人信服的建议或补充意见进行调试。” 

8.2 Traceroute程序的操作 
在7.3节中,我们描述了IP记录路由选项(RR)。为什么不使用这个选项而另外开发一个新的应用程序?有三个方面的原因。首先,原先并不是所有的路由器都支持记录路由选项,因此该选项在某些路径上不能使用。(Traceroute程序不需要中间路由器具备任何特殊的或可选的功能。) 
其次,记录路由一般是单向的选项。发送端设置了该选项,那么接收端不得不从收到的IP首部中提取出所有的信息然后全部返回给发送端。在7.3节中,我们看到大多数Ping服务器的实现(内核中的ICMP回显回答功能)把接收到的RR清单返回,但是这样使得记录下来的IP地址翻了一番(一来一回),这样会受到一些限制,这一点我们在下一段讨论。(Traceroute程序只需要目的端运行一个UDP模块----其他不需要任何特殊的服务器应用程序。) 
最后一个原因也是最主要的原因是,IP首部中留给选项的空间有限,不能存放当前大多数的路径。在IP首部选项字段中最多只能存放9个IP地址。在原先的ARPANET中这是足够的,但是对现在来说是远远不够的。 
Traceroute程序使用ICMP报文和IP首部中的TTL字段。TTL字段(生存周期)是由发送端初始设置一个8 bit字段。推荐的初始值由分配数字RFC指定,当前值为64。较老版本的系统经常初始化为15或32。我们从第7章中的一些ping程序例子中可以看出,发送ICMP回显回答时经常把TTL设为最大值255。 
每个处理数据报的路由器都需要把TTL的值减1或减去数据报在路由器中停留的秒数。由于大多数的路由器转发数据报的时延都小于1秒钟,因此TTL最终成为一个跳站的计数器,所经过的每个路由器都将其值减1。 

(下面是原书p.98①的译文) 
RFC 1009 [Braden and Postel 1987]指出,如果路由器转发数据报的时延超过1秒,那么它将把TTL值减去所消耗的时间(秒数)。但很少有路由器这么实现。新的路由器需求文档RFC [Almquist 1993]为此指定它为可选择功能,允许把TTL看成一个跳站计数器。 

TTL字段的目的是防止数据报在路由选择时无休止地在网络中流动。例如,当路由器瘫痪或者两个路由器之间的连接丢失时,路由选择协议有时会去检测丢失的路由并一直进行下去。在这段时间内,数据报可能在循环回路被终止。TTL字段就是在这些循环传递的数据报上加上一个生存上限。 
当路由器收到一份IP数据报,如果其TTL字段是0或1,则路由器不转发该数据报。(接收到这种数据报的目的主机可以将它交给应用程序,这是因为不需要转发该数据报。但是在通常情况下,系统不应该接收TTL字段为0的数据报。)相反地,路由器将该数据报丢弃并给信源机发一份ICMP“超时”信息。Traceroute程序的关键在于包含这份ICMP信息的IP报文的信源地址是该路由器的IP地址。 
我们现在可以猜想一下Traceroute程序的操作过程。它发送一份TTL字段为1的IP数据报给目的主机。处理这份数据报的第一个路由器将TTL值减1,丢弃该数据报,并发回一份超时ICMP报文。这样就得到了该路径中的第一个路由器的地址。然后Traceroute程序发送一份TTL值为2的数据报,这样我们就可以得到第二个路由器的地址。继续这个过程直至该数据报到达目的主机。但是目的主机哪怕接收到TTL值为1的IP数据报,也不会丢弃该数据报并产生一份超时ICMP报文,这是因为数据报已经到达其最终目的地。那么我们该如何判断已经到达目的主机了呢? 
Traceroute程序发送一份UDP数据报给目的主机,但它选择一个不可能的值作为UDP端口号(大于30,000),使目的主机的任何一个应用程序都不可能使用该端口。因为,当该数据报到达时,将使目的主机的UDP模块产生一份“端口不可到达”错误(见6.5节)的ICMP报文。这样,Traceroute程序所要做的就是区分接收到的ICMP信息是超时还是端口不可到达,以判断什么时候结束。 

(下面是原书p.99①的译文) 
Traceroute程序必须可以为发送的数据报设置TTL字段。并非所有与TCP/IP接口的程序都支持这项功能,同时并非所有的实现都支持这项能力,但目前大部分系统都支持这项功能,并可以运行Traceroute程序。这个程序界面通常要求用户具有超级用户权限,这意味着它可能需要特殊的权限以在你的主机上运行该程序。 

8.3 局域网输出 
我们现在已经做好运行Traceroute程序并观察其输出的准备了。我们将使用从svr4到slip,经路由器bsdi的简单互连网(见内封面)。 bsdi和slip之间是9600 b/s的SLIP链路。 

(见原书p.99的②) 

输出的第一个无标号行给出了目的主机名和其IP地址,指出traceroute程序最大的TTL字段值为30。40字节的数据报包含20字节IP首部,8字节的UDP首部和12字节的用户数据。(12字节的用户数据包含每发一个数据报就加1的序号,送出TTL的副本以及发送数据报的时间。) 
输出的后面两行以TTL开始,接下来是主机或路由器名,以及其IP地址。对于每个TTL值,发送3份数据报。每接收到一份ICMP报文,就计算并打印出往返时间。如果在5秒种内仍未收到3份数据报的任意一份的响应,则打印一个星号,并发送下一份数据报。在上述输出结果中,TTL字段为1的前三份数据报的ICMP报文分别在20,10和10 ms收到。TTL字段为2的3份数据报的ICMP报文则在120 ms后收到。由于TTL字段为2到达最终目的主机,因此程序就此停止。 
往返时间是由发送主机的traceroute程序计算的。它是指从traceroute程序到该路由器的总往返时间。如果我们对每段路径的时间感兴趣,可以用TTL字段为N+1所打印出来的时间减去TTL字段为N的时间。 
图8.1给出了tcpdump的运行输出结果。正如我们所预想的那样,第一个发往bsdi的探测数据报的往返时间是20 ms而后面两个数据报往返时间是10 ms的原因是发生了一次ARP交换。tcpdump结果证实了确实是这种情况。 
目的主机UDP端口号最开始设置为33435,且每发送一个数据报加1。可以通过命令行选项来改变开始的端口号。UDP数据报包含12个字节的用户数据,我们在前面traceroute程序输出的40字节数据报中已经对其进行了描述。 
后面tcpdump打印出了TTL字段为1的IP数据报的注释[ttl 1]。当TTL值为0或1时,tcpdump打印出这条信息,以提示我们数据报中有些不太寻常之处。在这里我们可以预见到TTL值为1,而在其它一些应用程序中,它可以警告我们数据报可能无法到达其最终目的主机。我们不可能看到路由器传送一个TTL值为0的数据报,除非发出该数据报的该路由器已经崩溃。 

图8.1 从svr4到slip的traceroute程序示例的tcpdump输出结果 

因为bsdi路由器将TTL值减到0,因此我们预计它将发回“传送超时”的ICMP报文。即使这份被丢弃的IP报文发送往slip,路由器也会发回ICMP报文。 
有两种不同的ICMP“超时”报文(见p.71页的图6.3),它们的ICMP报文中code字段不同。图8.2给出了这种ICMP错误报文的格式。 

图8.2 ICMP超时报文 

我们所讨论的ICMP报文是在TTL值等于0时产生的,其code字段为0。 
主机在组装分片时可能发生超时,这时,它将发送一份“组装报文超时”的ICMP报文。(我们将在11.5节讨论分片和组装。)这种错误报文将code字段置1。 
图8.1的第9-14行对应于TTL为2的3份数据报。这3份报文到达最终目的主机,并产生一份ICMP端口不可到达报文。 
计算出SLIP链路的往返时间是很有意义的,就象我们在7.2节中所举的Ping例子,将链路值设置为1200 b/s一样。发送出动的UDP数据报共42个字节,包括12字节的数据,8字节UDP首部,20字节的IP首部以及(至少)2字节的SLIP帧(2.4节)。但是与Ping不一样的是,返回的数据报大小是变化的。从图6.9可以看出,返回的ICMP报文包含发生差错的数据报的IP首部以及紧随该IP首部的8字节数据(在traceroute程序中,即UDP首部)。这样,总共就是20 + 8 + 20 + 8 + 2,即58字节。在数据速率为960 B/s的情况下,预计的RTT就是(42 + 58/960),即104 ms。这个值与svr4上所估算出来的110 ms是吻合的。 
图8.1中的源端口号(42804)看起来有些大。traceroute程序将其发送的UDP数据报的源端口号设置为Unix进程号与32768之间的逻辑或值。对于在同一台主机上多次运行traceroute程序的情况,每个进程都查看ICMP返回的UDP首部的源端口号,并且只处理那些对自己发送回答的报文。 
关于traceroute程序还有一些必须指出的事项。首先,并不能保证现在的路由也是将来所要采用的路由,甚至两份连续的IP数据报都可能采用不同的路由。如果在运行程序时,路由发生改变,你就会观察到这种变化,这是因为对于一个给定的TTL,如果其路由发生变化,traceroute程序将打印出新的IP地址。 
第二,不能保证ICMP报文的路由与traceroute程序发送的UDP数据报采用同一路由。这表明所打印出来的往返时间可能并不能真正体现数据报发出和返回的时间差。(如果UDP数据报从信源到路由器的时间是1秒,而ICMP报文用另一条路由返回信源用了3秒时间,则打印出来的往返时间是4秒。) 
第三,返回的ICMP报文中的信源IP地址是UDP数据报到达的路由器接口的IP地址。这与IP记录路由选项(7.3节)不同,记录的IP地址指的是发送接口地址。由于每个定义的路由器都有2个或更多的接口,因此,从A主机到B主机上运行traceroute程序和从B主机到A主机上运行traceroute程序所得到的结果可能是不同的。事实上,如果我们从slip主机到svr4上运行traceroute程序,其输出结果变成了: 

(见原书p.101的①) 

这次打印出来的bsdi主机的IP地址是140.252.13.66,对应于SLIP接口,而上次的地址是140.252.13.35,是以太网接口地址。由于traceroute程序同时也打印出与IP地址相关的主机名,因而主机名也可能变化。(在我们的例子中,bsdi上的两个接口都采用相同的名字。) 
考虑图8.3的情况。它给出了两个局域网通过一个路由器相连的情况。两个路由器通过一个点对点的链路相连。如果我们在左边LAN的一个主机上运行traceroute程序,那么它将发现路由器的IP地址为if1和if3。但在另一种情况下,就会发现打印出来的IP地址为if4和if2。if2和if3有着同样的网络号,而另两个接口则有着不同的网络号。 

图8.3 traceroute程序打印出的接口标识 

最后,在广域网情况下,如果traceroute程序的输出是可读的域名形式,而不是IP地址形式,那么会更好理解一些。但是由于traceroute程序接收到ICMP报文时,它所获得的唯一信息就是IP地址,因此,在给定IP地址的情况下,它做一个“反向域名查看”工作来获得域名。这就需要路由器或主机的管理员正确配置其反向域名查看功能(并非所有的情况下都是如此)。我们将在14.5节描述如何使用DNS将一个IP地址转换成域名。 

8.4 广域网输出 
我们前面所给出的小互连网的输出例子对于查看协议运行过程来说是足够了,但对于像全球互连网这样的大互连网来说,应用traceroute程序就需要一些更为实际的东西。 
图8.4是从sun主机到NIC (Network Information Center)的情况。 

图8.4 从sun主机到nic.ddn.mil的traceroute程序 

由于运行的这个例子包含文本,非DDN站点(如,非军方站点)的NIC已经从nic.ddn.mil转移到rs.internic.net,即新的“InterNIC"。 
一旦数据报离开tuc.noao.edu网,它们就进入了telcom.arizona.edu网络。然后这些数据报进入NASA Science Internet,nsn.nasa.gov。TTL字段为6和7的路由器位于JPL (Jet Propulsion Laboratory)上。TTL字段为11所输出的sura.net网络位于Southeastern Universities Research Association Network上。TTL字段为12的域名GSI是Government sys tems, Inc., NIC的运营者。 
TTL字段为6的第二个RTT(590)几乎是其它两个RTT值(234和262)的两倍 。它表明IP路由的动态变化。在发送主机和这个路由器之间发生了使该数据报速度变慢的事件。同样,我们不能区分是发出的数据报还是返回的ICMP差错报文被拦截。 
TTL字段为3的第一个RTT探测值(204)比TTL字段为2的第一个探测值(233)值还小。由于每个打印出来的RTT值是从发送主机到路由器的总时间,因此这种情况是可能发生的。 
图8.5的例子是从sun主机到作者出版商之间的运行例子。 

图8.5 从sun.tuc.noao.edu主机到aw.com的traceroute程序 

在这个例子中,数据报离开telcom.arizona.edu网络后就进行了地区性的网络westnet.net (TTL字段值为6和7)。然后进行了由Advanced Network & Services运营的NSFNET主干网,t3.ans.net,(T3是对于主干网采用的45 Mb/s电话线的一般缩写。)最后的网络是alter.net,即aw.com与互连网的连接点。 

8.5 IP源站选路选项 
通常IP路由是动态的,即每个路由器都要判断数据报下面该转发到哪个路由器。应用程序对此不进行控制,而且通常也并不关心路由。它采用类似traceroute程序的工具来发现实际的路由。 
源站选路(source routing)的思想是由发送者指定路由。它可以采用以下两种形式: 
•严格的源路由选择。发送端指定IP数据报所必须采用的确切路由。如果一个路由器发现源路由所指定的下一路由器不在其直接连接的网络上,那么它就返回一个“源站路由失败”的ICMP差错报文。 
宽松的源站选路。发送端指定一个数据报经过的IP地址清单,但是数据报在清单上指定的任意两个地址之间可以通过其它路由器。 
Traceroute程序为我们提供了一个查看源站选路的方法,我们可以在选项中指明源站路由,然后检查其运行情况。 

(原书p.104①的译文) 
一些公开的Traceroute程序源代码包中包含指明宽松的源站选路的补丁。但是在标准版中通常并不包含此项。这些补丁的解释是“Van Jacobson的原始Traceroute程序(1988年春)支持该特性,但他后来因为有人提出会使网关崩溃而将此功能去除。”对于本章中所给出的例子,作者将这些补丁安装上,并将它们设置成允许宽松的源站选路和严格的源站选路。 

图8.6给出了源站路由选项的格式。 

图8.6 IP首部源站路由选项的通用格式 

这个格式与我们在图7.3中所示的记录路由选项格式基本一致。但不同之处是,对于源站选路,我们必须在发送IP数据报前填充IP地址清单,而对于记录路由选项,我们需要为IP地址清单分配并清空一些空间,并让路由器填充该清单中的各项。同时,对于源站选路,我们只要为所需要的IP地址数分配空间并进行初始化,通常其数量小于9。而对于记录路由选项来说,我们必须尽可能地分配空间,以达到9个地址。 
对于宽松的源站选路来说,code字段的值是0x83,而对于严格的源站选路,其值为0x89。len和ptr字段与我们在7.3节中所描述的一样。 
源站路由选项的实际称呼为“源站及记录路由”(对于宽松的源站选路和严格的源站选路,分别用LSRR和SSRR表示),这是因为在数据报沿路由发送过程中,对IP地址清单进行更新。下面是其运行过程: 
•发送主机从应用程序接收源站路由清单,将第一个项去掉(它是数据报的最终目的地址),将剩余的项移到一个项中(如图8.6所示),并将原来的目的地址作为清单的最后一项。指针仍然指向清单的第一项(即,指针的值为4)。 
•每个处理数据报的路由器检查其是否为数据报的最终地址。如果不是的话,则正常转发数据报。(在这种情况下,必须指明宽松源站选路,否则我们就不能接收到该数据报。) 
•如果该路由器是最终目的,且指针不大于路径的长度,那么(1)由ptr所指定的清单中的下一个地址就是数据报的最终目的地址,(2)由出接口(outgoing interface)相对应的IP地址取代刚才使用的源地址,然后,(3)指针加4。 
可以用下面这个例子很好地解释上述过程。在图8.7中,我们假设主机S上的发送应用程序发送一份数据报给D,指定源路由为R1,R2和R3。 

图8.7 IP源路由示例 

在上图中,#表示指针字段,其值分别是4,8,12和16。长度字段恒为15(三个IP地址加上三个字节首部)。可以看出,每一跳IP数据报中的目的地址都发生改变。 
当一个应用程序接收到由信源指定路由的数据时,在发送回答时,应该读出接收路由值,并提供反向路由。 

(下面是原书p.105①的译文) 
Host Requirements RFC指明,TCP客户必须能指明源站路由选择,同时,TCP服务器必须能够接收源站路由选择,并且对于该TCP连接的所有报文段都能采用反向路由。如果TCP服务器下面接收到一个不同的源站路由选择,那么新的源站路由将取代旧的源站路由。 

宽松的源站选路的traceroute程序示例 
使用traceroute程序的 -g 选项,我们可以为宽松的源站选路指明一些中间结点。采用该选项可以最多指定8个中间路由。(其个数是8而不是9的原因是,所使用的编程接口要求最后的表目是目的主机。) 
在图8.4中,去往NIC,nic.ddn.mil的路由经过NASA Science Internet。在图8.8中,我们通过指定路由器 enss142.UT.westnet.net (192.31.39.21) 作为中间路由器来强制数据报通过NSFNET: 

图8.8 采用宽松源站选路通过NSFNET到达nic.ddn.mil的traceroute程序 

在这种情况下,看起来路径中共有16跳,其平均RTT大约是350 ms,而图8.4的通常路由选择则只有13跳,其平均RTT约为322 ms。默认路径看起来更好一些。(在建立路径时,还需要考虑其它的一些因素。其中一些必须考虑的因素是所包含网络的组织及政治因素。) 
前面我们说看起来有16跳,这是因为将其输出结果与我们前面的通过NSFNET(图8.5)的示例比较,发现在本例采用宽松源路由,选择了3个路由器。(这可能是因为路由器对源站选路数据报产生ICMP超时差错报文上存在一些差错。)在netb和butch路由器之间的gateway.tuc.noao.edu路由器丢失了,同时,位于Gabby和enss142.UT.west.net之间的Westgate.Telcom.Arizona.edu和uu-ua.AZ.westnet.net两个路由器也丢失了。在这些丢失的路由器上可能发生了与接收到宽松的源站选路选项数据报有关的程序问题。实际上,当采用NSFNET时,信源和NIC之间的路径有19跳。本章习题8.5继续对这些丢失路由器进行讨论。 
本例同时也指出了另一个问题。在命令行,我们必须指定路由器enss142.UT.westnet.net的点分十进制IP地址,而不能以其域名代替。这是因为,反向域名解析(14.5节中描述的通过IP地址返回域名)将域名与IP地址相关联,但是前向解析(即给出域名返回IP地址)则无法做到。在DNS(Domain Name sys tem,域名系统)中,前向映射和反向映射是两个独立的文件,而并非所有的管理者都同时拥有这两个文件。因此,在一个方向是工作正常而另一个方向失败的情况并不少见。 
还有一种我们以前没有碰到过的情况是在TTL字段为8的情况下,对于第一个RTT,打印一个星号(*)。这表明,发生超时,在5秒内未收到本次探查的回答信号。 
将本图与图8.4相比较,我们还可以得出一个结论,即路由器ns-FIX-pe.sura.net同时与NSFNET和NASA Science Internet相连。 

严格的源站选路的traceroute程序示例 
在作者的traceroute程序版本中,-G参数与前面所描述的-g参数是完全一样的,不过此时是严格的源站选路而不是宽松的源站选路。我们可以采用这个参数来观察在指明无效的严格的源站选路时其结果会是什么样的。从图8.5可以看出来,从作者的子网发往NSFNET的数据报的正常路由器顺序是netb,gateway,butch和gabby。(为了便于查看,我们后面所有的输出结果中,省略了域名后缀 .tuc.noao.edu和 .telcom.arizona.edu。)我们指定了一个严格源路由,使其试图将数据报从gateway直接发送到gabby,而省略了butch。我们可以猜测到其结果会是失败的,正如图8.9所给出的结果。 

图8.9 采用严格源路由失败的traceroute程序 

这里的关键是在于TTL字段为3的输出行中,RTT后面的!S。这表明traceroute程序接收到ICMP“源站路由失败”的差错报文:即图6.3中type字段为3,而code字段为5。TTL字段为3的第二个RTT位置的星号表示未收到这次探查的回答信号。这与我们所猜想的一样, gateway不可能直接发送数据报给gabby,这是因为它们之间没有直接的连接。 
TTL字段为2和3的结果都来自于gateway,对于TTL字段为2的回答来自gateway是因为gateway接收到TTL字段为1的数据报。在它查看到(无效的)严格的源站选路之前,就发现TTL已过期,因此发送回ICMP超时报文。TTL字段等于3的行,在进入gateway时其TTL字段为2,因此,它查看严格的源站选路,发现它是无效的,因此发送回ICMP源站选路失败的差错报文。 
图8.10给出了与本例相对应的tcpdump输出结果。该输出结果是在sun和netb之间的SLIP链路上惧到的。我们必须在tcpdump中指定-v选项以显示出源站路由信息。这样,会输出一些像数据报ID这样的我们不需要的结果,我们在给出结果中将这些不需要的结果删除掉。同样,我们用SSRR表示“严格的源站及记录路由”。 

图8.10 失败的严格的源站选路traceroute程序的tcpdump输出结果 

首先注意到,sun所发送的每个UDP数据报的目的地址都是netb,而不是目的主机(westgate)。这一点可以用图8.7的例子来解释。类似的,-G参数所指定的另外两个路由器(gateway和gabby)以及最终目的(westgate)成为第一跳的SSRR选项。 
从这个输出结果中,我们还可以看出,traceroute程序所采用的定时时间(第15行和16行之间的时间差)是5秒。 

宽松的源站选路traceroute程序的往返路由 
我们在前面已经说过,从A到B的路径并不一定与从B到A的路径完全一样。除非同时在两个系统中登录并在每个终端上运行traceroute程序,否则很难发现两条路径是否不同。但是,采用宽松的源站选路,我们就可以决定两个方向上的路径。 
这里的窍门就在于指定一个宽松的源站路由,该路由的目的端和宽松路径一样,但发送端为目的主机。例如,在sun主机上,我们可以查看到发往以及来自bruno.cs.colorado.edu的结果如图8.11所示。 

图8.11 显示非对称路径的traceroute程序 

发出路径(TTL字段为1-11)的结果与返回路径(TTL字段为11-21)不同,这很好地说明了在Internet 上,路由选择可能是不对称的。 
该输出同时还说明了我们在图8.3中所讨论的问题。比较TTL字段为2和19的输出结果:它们都是路由器gateway.tuc.noao.edu,但两个IP地址却是不同的。由于traceroute程序以进入接口作为其标识,而我们从两条不同的方向经过该路由器,一条是发出路径(TTL字段为2),另一条是返回路径(TTL字段为19),因此我们可以猜想到这个结果。通过比较TTL字段为3和18,4和17的结果,我们可以看到同样的结果。 

8.6 小结 
在一个TCP/IP网络中,traceroute程序是不可缺少的工具。其操作很简单:开始时发送一个TTL字段为1的UDP数据报,然后将TTL字段每次加1,以确定路径中的每个路由器。每个路由器在丢弃UDP数据报时都返回一个ICMP超时报文2,而最终目的主机则产生一个ICMP端口不可到达的报文。 
我们给出了在LAN和WAN上运行traceroute程序的例子,并用它来考察IP源站选路。我们用宽松的源站选路来检测发往目的主机的路由是否与从目的主机返回的路由一样。 

习题: 
8.1 当IP将接收到的TTL字段减1,发现它为0时,将会发生什么结果? 
8.2 traceroute程序是如何计算RTT的?将这种计算RTT的方法与ping相比较。 
8.3 (本习题与下一道习题是基于开发traceroute程序过程中遇到的实际问题,它们来自于traceroute程序源代码注释。)假设有源主机和目的主机之间有三个路由器(R1,R2和R3),而中间的路由器(R2)在进入TTL字段为1时,将TTL字段减1,但却错误地将该IP数据报发往下一个路由器。请描述会发生什么结果。在运行traceroute程序是你会看到什么样的现象? 
8.4 同样,假设源主机和目的主机之间有三个路由器。由于目的主机上存在错误,因此,它总是将进入TTL值作为外出ICMP报文的TTL值。请描述这将发生什么结果,你会看到什么现象。 
8.5 在图8.8运行例子中,我们可以在sun和netb之间的SLIP链路上运行tcpdump程序。如果我们指定-v参数,就可以看到返回ICMP报文的TTL值。这样,我们可以看到进入netb,butch,Gabby和enss142.UT.westnet.net的TTL值分别为255,253,252和249。这是否为我们判断是否存在丢失路由器提供了额外的信息? 
8.6 SunOS和SVR4都提供了带-l选项的ping版本,以提供松源路由选择。手册上说明,该选项可以与 -R 选项(指定记录路由选项)一起用的。如果你已经进入到这些系统中,请尝试同时用这两个选项。其结果是什么:如果你采用tcpdump来观测数据报,请描述其过程。 
8.7 比较ping和traceroute程序在处理同一台主机客户的多个实例上的不同点。 
8.8 比较ping和traceroute程序在计算往返时间上的不同点。 
8.9 我们已经说过,traceroute程序选取开始UDP目的主机端口号为33453,每发送一个数据报将此数加1。在1.9节中,我们说过暂时端口号通常是1024到5000之间的值,因此traceroute程序的目的主机端口号不可能是目的主机上所使用的端口号。在Solaris2.2系统中的情况也是如此吗?(提示:查看E.4节) 
8.10 RFC 1393 [Malkin 1993b]提出了另一种判断到目的主机路径的方法。请问其优缺点是什么? 
8-8 
9 IP路由选择 

9.1 引言 
路由选择是IP最重要的功能之一。图9.1是IP层处理过程的简单流程。需要进行路由选择的数据报可以由本地主机产生,也可以由其他主机产生。在后一种情况下,主机必须配置成一个路由器,否则通过网络接口接收到的数据报,如果目的地址不是本机就要被丢弃(例如,悄无声息地被丢弃)。 
在图9.1中,我们还描述了一个路由守护程序(daemon),一般来说是一个用户进程。在Unix系统中,大多数普通的守护程序都是路由程序和网关程序。(术语daemon指的是运行在后台的进程,它代表整个系统执行某些操作。daemon一般在系统引导时启动,在系统运行期间一直存在。)在某个给定主机上运行何种路由协议,如何在相邻路由器上交换选路信息,以及选路协议是如何工作的,所有这些问题都是非常复杂的,其本身就可以用整本书来加以讨论。(有兴趣的读者可以参考文献[Perlman 1992]以获得更详细的信息。)在第10章中,我们将简单讨论动态路由选择和选路信息协议RIP(Routing Information Protocol)。在本章我们主要的目的是了解单个IP层如何作出路由决策的。 
图9.1所示的路由表经常被IP访问(在一个繁忙的主机上,一秒钟内可能要访问几百次),但是它被路由守户程序更新的频度却要低得多(可能大约30秒种一次)。当接收到ICMP“改变路由(redirect)”报文时路由表也要被更新,这一点我们将在9.5节讨论route命令时加以介绍。在本章中,我们还将用netstat命令来显示路由表。 

图9.1 IP层工作流程 

9.2 路由选择的原理 
开始讨论IP路由选择之前,首先要理解内核是如何维护路由表的。路由表中包含的信息决定了IP层所做的所有决策。 
在3.3节中,我们列出了IP搜索路由表的几个步骤: 
1. 搜索匹配的主机地址; 
2. 搜索匹配的网络地址; 
3. 搜索默认表项。(默认表项一般在路由表中被指定为一个网络表项,其网络号为0。) 

匹配主机地址步骤始终发生在匹配网络地址步骤之前。 
IP层进行的路由选择实际上是一种路由选择机制,它搜索路由表并决定向哪个网络接口发送分组。这区别于路由选择策略,它只是一组决定把哪些路由放入路由表的规则。IP执行路由选择机制,而路由守护程序则一般提供路由选择策略。 

简单路由表 
首先让我们来看一看一些典型的主机路由表。在主机svr4上,我们先执行带-r参数的netstat命令列出路由表,然后以-n参数再次执行该命令,以数字格式打印出IP地址。(我们这样做是因为路由表中的一些表项是网络地址,而不是主机地址。如果没有-n参数,netstat命令将搜索文件/etc/networks并列出其中的网络名。这样会与另一种形式的名字——网络名加主机名相混淆。 

(见原书p.113的①) 

第一行说明,如果目的地是140.252.13.65(slip主机),那么网关(路由器)将把分组转发给140.252.13.35(bsdi)。这正是我们所期望的,因为主机slip通过SLIP链路与bsdi相连接,而bsdi与该主机在同一个以太网上。 
对于一个给定的路由器,可以打印出五种不同的标志(flag): 
U 该路由可以使用。 
G 该路由是到一个网关(路由器)。如果没有设置该标志,说明目的地是直接相连的。 
H 该路由是到一个主机,也就是说,目的地址是一个完整的主机地址。如果没有设置该标志,说明该路由是到一个网络,而目的地址是一个网络地址:一个网络号,或者网络号与子网号的组合。 
D 该路由是由改变路由(redirect)报文创建的(9.5节)。 
M 该路由已被改变路由报文修改(9.5节)。 

标志G是非常重要的,因为由它区分了间接路由和直接路由。(对于直接路由来说是不设置标志G的。)其区别在于,发往直接路由的分组中不但具有指明目的端的IP地址,还具有其链路层地址(图3.3)。当分组被发往一个间接路由时,IP地址指明的是最终的目的地,但是链路层地址指明的是网关(即下一站路由器)。我们在图3.4已看到这样的例子。在个路由表例子中,我们有一个间接路由(设置了标志G),因此采用这一项路由的分组其IP地址是最终的目的地(140.252.13.65),但是其链路层地址必须对应于路由器140.252.13.35。 
理解G和H标志之间的区别是很重要的。G标志区分了直接路由和间接路由,如上所述。但是H标志表明,目的地址(netstat命令输出第一行)是一个完整的主机地址。没有设置H标志说明目的地址是一个网络地址(主机号部分为0)。当为某个目的IP地址搜索路由表时,主机地址项必须与目的地址完全匹配,而网络地址项只需要匹配目的地址的网络号和子网号就可以了。另外,大多数版本的netstat命令首先打印出所有的主机路由表项,然后才是网络路由表项。 
参考记数Refcnt(“Reference count ”)列给出的是正在使用路由的活动进程个数。面向连接的协议如TCP在建立连接时要固定路由。如果在主机svr4和slip之间建立Telnet连接,我们可以看到参考记数值变为1。建立另一个Telnet连接时,它的值将增加为2,以此下去。 
下一列(“use")显示的是通过该路由发送的分组数。如果我们是这个路由的唯一分组,那么我们运行ping程序发送5个分组后,它的值将变为5。最后一列列出的(interface)是本地接口的名字。 
输出的第2行是环回接口(2.7节),它的名字始终为lo0。没有设置G标志,因为该路由不是一个网关。H标志说明目的地址(127.0.0.1)是一个主机地址,而不是一个网络地址。由于没有设置G标志,说明这是一个直接路由,网关列给出的是出口IP地址。 
输出的第3行是默认路由。每个主机都有一个或多个默认路由。这一项表明,如果在表中没有找到特定的路由,就把分组发送到路由器140.252.13.33(sun主机)。这说明当前主机(svr4)利用这一个路由表项就可以通过Internet经路由器sun(及其SLIP链路)访问其他的系统。建立默认路由是一个功能很强的概念。该路由标志(UG)表明它是一个网关,这是我们所期望的。 

(下面是原书p.114①的译文) 
这里,我们有目的地称sun为路由器而不是主机,因为它被当作默认路由器来使用,它发挥的是IP转发功能,而是主机功能。 
Host Requirements RFC文档特别说明,IP层必须支持多个默认路由。但是,许多实现系统并不支持这一点。当存在多个默认路由时,一般的技术就成为它们周围的知更鸟了,例如,Solaris 2.2就是这样做的。 

输出中的最后一行是所在的以太网。H标志没有设置,说明目的地址(140.252.13.32)是一个网络地址,其主机地址部分设为0。事实上,是它的低5位设为0(图3.11)。由于这是一个直接路由(G标志没有被设置),网关列指出的IP地址是出口地址。 
netstat命令输出的最后一项还隐含了另一个信息,那就是目的地址(140.252.13.32)的子网掩码。如果要把该目的地址与140.252.13.33进行比较,那么在比较之前首先要把它与目的地址掩码(0xffffffe0,3.7节)进行逻辑与。由于内核知道每个路由表项对应的接口,而且每个接口都有一个对应的子网掩码,因此每个路由表项都有一个隐含的子网掩码。 
主机路由表的复杂性取决于主机所在网络的拓扑结构。 
1. 最简单的(也是最不令人感兴趣的)情况是主机根本没有与任何网络相连。TCP/IP协议仍然能用于这样的主机,但是只能与自己本身通信!这种情况下的路由表只包含环回接口一项。 
2. 接下来的情况是主机连在一个局域网上,只能访问局域网上的主机。这时路由表包含两项:一项是环回接口,另一项是局域网(如以太网)。 
3. 如果主机能够通过单个路由器访问其他网络(如Internet)时,那么就要进行下一步。一般情况下增加一个默认表项指向该路由器。 
4. 如果要新增其他的特定主机或网络路由,那么就要进行最后一步。在我们的例子中,到主机slip的路由要通过路由器bsdi就是这样的例子。 
我们根据上述IP操作的步骤使用这个路由表为主机svr4上的一些例子分组选择路由。 
1. 假定目的地址是主机sun,140.252.13.33。首先进行主机地址的匹配。路由表中的两个主机地址表项(slip和localhost)均不匹配,接着进行网络地址匹配。这一次匹配成功,找到表项140.252.13.32(网络号和子网号都相同),因此使用emd0接口。这是一个直接路由,因此链路层地址将是目的端的地址。 
2. 假定目的地址是主机slip,140.252.13.65。首先在路由表搜索主机地址,并找到一个匹配地址。这是一个间接路由,因此目的端的IP地址仍然是140.252.13.65,但是链路层地址必须是网关140.252.13.65的链路层地址,其接口名为emd0。 
3. 这一次我们通过Internet给主机aw.com(192.207.117.2)发送一份数据报。首先在路由表中搜索主机地址,失败后进行网络地址匹配。最后成功地找到默认表项。该路由是一个间接路由,通过网关140.252.13.33并使用接口名为emd0。 
4. 在我们最后一个例子中,我们给本机发送一份数据报。有四种方法可以完成这件事,如用主机名,主机IP地址,环回名,或者环回IP地址: 

ftp svr4 
ftp 140.252.13.34 

ftp localhost 
ftp 127.0.0.1 

在前两种情况下,对路由表的第二次搜索得到一个匹配的网络地址140.252.13.32,并把IP报文传送给以太网驱动程序。正如图2.4所示的那样,IP报文中的目的地址为本机IP地址,因此报文被送给环回驱动程序,然后由驱动程序把报文放入IP输出队列中。 
在后两种情况下,由于指定了环回接口的名字或IP地址,第一次搜索就找到匹配的主机地址,因此报文直接被送给环回驱动程序,然后由驱动程序把报文放入IP输出队列中。 
上述四种情况报文都要被送给环回驱动程序,但是采用的两种路由决策是不相同的。 

初始化路由表 
我们从来没有说过这些路由表是如何被创建的。每当初始化一个接口时(通常是用 ifconfig命令设置接口地址时),就为接口自动创建一个直接路由。对于点对点链路和环回接口来说,路由是到达主机(例如,设置H标志)。对于广播接口来说,如以太网,路由是到达网络。 
到达主机或网络的路由如果不是直接相连的,那么就必须加入路由表。一个普通的方法在系统引导时显式地在初始化文件中运行route命令。在主机svr4上,我们运行下面两个命令来添加路由表中的表项: 

route add default sun 1 
route add slip bsdi 1 

第三个参数(default和slip)代表目的端,第四个参数代表网关(路由器),最后一个参数代表路由的度量(metric)。route命令在度量值大于0时要为该路由设置G标志,否则当耗费值为0时就不设置G标志。 

(下面是原书p.116①的译文) 
不幸的是,几乎没有系统愿意在启动文件中包含route命令。在4.4 BSD和BSD/386系统中,启动文件是/etc/netstart, 在SVR4系统中,启动文件是/etc/inet/rc.inet, 在Solaris 2.x中,启动文件是/etc/rc2.d/S69inet, 在SunOS 4.1.x中,启动文件是/etc/rc.local, 而AIX 3.2.2则使用文件/etc/rc.net。 
一些系统允许在某个文件中指定默认的路由器,如/etc/defaultrouter,于是在每次重新启动系统时都要在路由表中加入该默认项。 
初始化路由表的其它方法是运行路由守护程序(第10章)或者用较新的路由器发现协议(9.6节)。 

较复杂的路由表 
在我们的子网上,主机sun是所有主机的默认路由器,因为它有拔号SLIP链路连接到Internet上(参见封二上的图)。 

(见原书p.117的①) 

前两项与主机svr4的前两项一致:通过路由器bsdi到达slip的特定主机路由,以及环回路由。 
第三行是新加的。这是一个直接到达主机的路由(没有设置G标志,但设置了H标志),对应于点对点的链路,即SLIP接口。如果我们把它与ifconfig命令的输出进行比较: 

sun % ifconfig sl0 
sl0: flags=1051 
inet 140.252.1.29 -->; 140.252.1.183 netmask ffffff00 

我们发现路由表中的目的地址就是点对点链路的另一端(即路由器netb), 网关地址为本地出口IP地址(140.252.1.29)。(我们前面已经说过, netstat为直接路由打印出来的网关地址就是本地接口所用的IP地址。) 
默认的路由表项是一个到达网络的间接路由(设置了G标志,但没有设置H标志),这正是我们所希望的。网关地址是路由器的地址(140.252.1.183,SLIP链路的另一端), 而不是SLIP链路的本地IP地址(140.252.1.29)。其原因还是因为是间接路由,不是直接路由。 
我们还应该指出的是,netstat输出的第三和第四行(接口名为sl0)由SLIP软件在启动时创建,并在关闭时删除. 

没有到达目的地的路由 
我们所有的例子都假定对路由表的搜索都能找到匹配的表项,即使匹配的是默认项。如果路由表中没有默认项,而又没有找到匹配项,这时会发生什么情况呢? 
结果取决于该IP数据报是由主机产生的还是被转发的(例如,我们就充当一个路由器)。如果数据报是由本地主机产生的,那么就给发送该数据报的应用程序返回一个差错,或者是“主机不可达差错”或者是“网络不可达差错”。如果是被转发的数据报,那么就给原始发送端发送一份ICMP主机不可达差错的报文。在下一节我们将讨论这种差错。 

9.3 ICMP主机与网络不可达差错 
当路由器收到一份IP数据报但又不能转发时,就要发送一份ICMP“主机不可到达”差错报文。(ICMP主机不可达报文的格式如图6.10所示)。我们可以很容易发现,在我们的网络上把接在路由器sun上的拔号SLIP链路断开,然后试图通过该SLIP链路发送分组给任何指定sun为默认路由器的主机。 

(下面是原书p.118①的译文) 
较老版本的BSD产生一个主机不可达或者网络不可达差错,这取决于目的端是否处于一个局域子网上。4.4 BSD只产生主机不可达差错。 

我们在上一节通过在路由器sun上运行netstat命令可以看到,当接通SLIP链路启动时就要在路由表中增加一项使用SLIP链路的表项,而当断开SLIP链路时则删除该表项。这说明当SLIP链路断开时,sun的路由表中就没有默认项了。但是我们不想改变网络上其他主机的路由表,即同时删除它们的默认路由。相反,对于sun不能转发的分组我们对它产生的ICMP主机不可达差错报文进行计数。 
在主机svr4上运行ping程序就可以看到这一点,它在拔号SLIP链路的另一端(拔号链路已被断开): 

(见原书p.118的②) 

在主机bsdi上运行tcpdump命令的输出如图9.2所示。 

图9.2 响应ping命令ICMP主机不可达报文 

当路由器sun发现找不到能到达主机gemini的路由时,它就响应一个主机不可达的回响请求报文。 
如果我们把SLIP链路接到Internet上,然后试图ping一个与Internet没有连接的IP地址,那么应该会产生差错。但令人感兴趣的是,我们可以看到在返回差错报文之前,分组要在Internet上传送多远: 

(见原书p.118的③) 

从图8.5可以看出,在发现该IP地址是无效的之前,该分组已通过了6个路由器。只有当它到达NSFNET骨干网的边界时才检测到差错。这说明, 6个路由器之所以能转发分组是因为路由表中有默认项,只有当分组到达NSFNET骨干网时,路由器才能知道每个连接到Internet上的每个网络的信息。这说明许多路由器只能在局部范围内工作。 
参考文献[Ford, Rekhter, and Braun 1993]定义了顶层选路域(top-level routing domain),由它来维护大多数Internet网站的路由信息,而不使用默认路由。他们指出,在Internet上存在5个这样的顶层选路域:NSFNET主干网,商业互连网交换(Commercial Internet Exchange: CIX),NASA科学互连网(NASA Science Internet: NSI),SprintLink,以及欧洲IP主干网(EBONE)。 

9.4 转发或不转发 
前面我们已经提过几次,一般都假定主机不转发IP数据报,除非对它们进行特殊配置而作为路由器使用。如何进行这样的配置呢? 
大多数伯克利派生出来的系统都有一个内核变量ipforwarding,或其他类似的名字。(参见附录E。)一些系统(如BSD/386和SVR4)只有在该变量值不为0的情况下才转发数据报。SunOS 4.1.x允许该变量可以三个不同的值:-1表示始终不转发并且始终不改变它的值;0表示默认条件下不转发,但是当打开两个或更多个接口时就把该值设为1;1表示始终转发。Solaris 2.x把这三个值改为0(始终不转发),1(始终转发)和2(在打开两个或更多个接口时才转发)。 
较旧版本的4.2BSD主机在默认条件下可以转发数据报,这给没有进行正确配置的系统带来了许多问题。这就是内核选项为什么要设成默认的“始终不转发”的原因,除非系统管理员进行特殊设置。 

9.5 ICMP改变路由差错 
当IP数据报应该被发送到另一个路由器时,收到数据报的路由器就要发送ICMP改变路由(redirect)差错报文给IP数据报的发送端。这在概念上是很简单的,正如我们在图9.3中所示的那样。只有当主机可以选择路由器发送分组的情况下我们才可能看到ICMP改变路由报文。(回忆我们在图7.6中看过的例子。) 
1. 我们假定主机发送一份IP数据报给R1。这种路由选择决策经常发生,因为R1是该主机的默认路由。 
2. R1收到数据报并且检查它的路由表,发现R2是发送该数据报的下一站。当它把数据报发送给R2时,R1检测到它正在发送的接口与数据报到达接口是相同的(即主机和两个路由器所在的LAN)。这样就给路由器发送改变路由报文给原始发送端提供了线索。 
3. R1发送一份ICMP改变路由报文给主机,告诉它以后把数据报发送给R2而不是R1。 

图9.3 ICMP改变路由例子 

改变路由一般用来让具有很少路由选择信息的主机逐渐建立更完善的路由表。主机启动时路由表中可以只有一个默认表项(在图9.3的例子中,为R1或R2),一旦默认路由发生差错,默认路由器将通知它进行改变路由,允许主机对路由表作相应的改动。ICMP改变路由允许TCP/IP主机在进行路由选择时不需要具备智能特性,而把所有的智能特性放在路由器端。显然,在我们的例子中,R1和R2 必须知道有关相连网络的更多拓扑结构的信息,但是连在LAN上的所有主机在启动时只需一个默认路由,通过接收改变路由报文来逐步学习。 
一个例子 
我们可以在我们的网络上观察到ICMP改变路由的操作过程(见封二的图)。尽管我们在拓扑图中只画出了三台主机(aix, solaris和gemini)和两台路由器(gateway和netb),但是整个网络有超过150台主机和10台另外的路由器。大多数的主机都把gateway指定为默认路由器,因为它提供了Internet的入口。 
子网140.252.1上的主机是如何访问作者所在子网(图中底下的四台主机)的呢?首先,如果在SLIP链路的一端只有一台主机,那么就要使用代理ARP(4.6节)。这意味着位于拓扑图顶部的子网(140.252.1)中的主机不需要其他特殊条件就可以访问主机sun(140.252.1.29)。位于netb上的代理ARP软件处理这些事情。 
但是,当网络位于SLIP链路的另一端时,就要涉及到路由选择了。一个办法是让所有的主机和路由器都知道路由器netb是网络140.252.13的网关。这可以在每个主机的路由表中设置静态路由,或者在每个主机上运行守护程序来实现。另一个更简单的办法(也是实际采用的方法)是利用ICMP改变路由报文来实现。 
让我们在位于网络顶部的主机solaris上运行ping程序到主机bsdi(140.252.13.35)。由于子网号不相同,代理ARP不能使用。假定没有安装静态路由,发送的第一个分组将采用到路由器gateway的默认路由。下面是我们运行ping程序之前的路由表: 

(见原书p.121的①) 

(224.0.0.0所在的表项是IP广播地址。我们将在第12章讨论。)如果为ping程序指定-v选项,我们可以看到主机接收到的任何ICMP报文。我们需要指定该选项以观察发送的改变路由报文。 

(见原书p.121的②) 

在我们收到ping程序的第一个响应之前,主机先收到一份来自默认路由器gateway发来的ICMP改变路由报文。如果我们这时查看路由表,会发现已经插入了一个到主机bsdi的新路由。(该表项如下黑体字所示。) 

(见原书p.121的③) 

这是我们第一次看到D标志,表示该路由是被ICMP改变路由报文创建的。G标志说明这是一份到达gateway(netb)的间接路由,H标志则说明这是一个主机路由(正如我们期望的那样),而不是一个网络路由。 
由于这是一个被主机改变路由报文增加的主机路由,因此它只处理到达主机bsdi的报文。如果我们接着访问主机svr4,那么就要产生另一个ICMP改变路由报文,创建另一个主机路由。类似地,访问主机slip也创建另一个主机路由。位于子网上的三台主机(bsdi, svr4和slip)还可以由一个指向路由器sun的网络路由来进行处理。但是ICMP改变路由报文创建的是主机路由,而不是网络路由,这是因为在本例中,产生ICMP改变路由报文的路由器并不知道位于140.252.13网络上的子网信息。 

更多的细节 
ICMP改变路由报文的格式如图9.4所示。 

图9.4 ICMP改变路由报文 

有四种不同类型的改变路由报文,有不同的代码值,如图9.5所示。 

图9.5 ICMP改变路由报文的不同代码值 

ICMP改变路由报文的接收者必须查看三个IP地址:(1)导致改变路由的IP地址(即ICMP改变路由报文的数据位于IP数据报的首部);(2)发送改变路由报文的路由器的IP地址(包含改变路由信息的IP数据报中的源地址;(3)应该采用的路由器IP地址(在ICMP报文中的4-7字节)。 
关于ICMP改变路由报文有很多规则。首先,改变路由报文只能由路由器生成,而不能由主机生成。另外,改变路由报文是为主机而不是为路由器使用的。假定路由器和其他一些路由器共同参与某一种路由选择协议,则该协议就能消除改变路由的需要。(这意味着在图9.1中的路由表应该消除或者能被路由选择守护程序修改,或者能被改变路由报文修改,但不能同时被二者修改。) 
在4.4BSD系统中,当主机作为路由器使用时,要进行下列检查,在生成ICMP改变路由报文之前这些条件都要满足。 
1. 出接口必须等于入接口。 
2. 用于向外传送数据报的路由不能被ICMP改变路由报文创建或修改过,而且不能是路由器的默认路由。 
3. 数据报不能用源站选路来转发。 
4. 内核必须配置成可以发送改变路由报文。 

(下面是原书p.123①的译文) 
内核变量取名为ip_sendredirects或其他类似的名字。(参见附录E。)大多数当前的系统(例如BSD, SunOS 4.1.x, Solaris 2.x, 及AIX 3.2.2)在默认条件下都设置该变量使系统可以发送改变路由报文。其他系统如SVR4则关闭了该项功能。 

另外,一台4.4BSD主机收到ICMP改变路由报文后,在修改路由表之前要作一些检查。这是为了防止路由器或主机的误操作,以及恶意用户的破坏,导致差错地修改系统路由表。 
1. 新的路由器必须直接与网络相连接。 
2. 改变路由报文必须来自当前到目的地所选择的路由器。 
3. 改变路由报文不能让主机本身作为路由器。 
4. 被修改的路由必须是一个间接路由。 

关于改变路由最后要指出的是,路由器应该发送的只是对主机的改变路由(代码1或3,如图9.5所示),而不是对网络的改变路由。子网的存在使得难于准确指明何时应发送对网络的改变路由而不是对主机的改变路由。只当路由器发送了错误的类型时,一些主机才把收到的对网络的改变路由当作对主机的改变路由来处理。 

9.6 ICMP路由器发现报文 
我们在本章前面已提到过一种初始化路由表的方法,即在配置文件中指定静态路由。这种方法经常用来设置默认路由。另一种新的方法是利用ICMP路由器通告和请求报文。 
一般认为,主机在引导以后要广播或多播传送一份路由器请求报文。一台或更多台路由器响应一份路由器通告报文。另外,路由器定期地广播或多播传送它们的路由器通告报文,允许每个正在监听的主机相应地更新它们的路由表。 
RFC 1256 [Deering 1991]确定了这两种ICMP报文的格式。ICMP路由器请求报文的格式如图9.6所示。ICMP路由器通告报文的格式如图9.7所示。 
路由器在一份报文中可以通告多个地址。地址数指的是报文中所含的地址数。地址项大小指的是每个路由器地址32-bit字的数目,始终为2。生命周期指的是通告地址有效的时间(秒数)。 

图9.6 ICMP路由器请求报文格式 

图9.7 ICMP路由器通告报文格式 

接下来是一对或多对IP地址和优先级。IP地址必须是发送路由器的某个地址。优先级是一个有符号的32-bit整数,指出该IP地址作为默认路由器地址的优先等级,这是与子网上的其他路由器相比较而言的。值越大说明优先级越高。优先级为0x80000000说明对应的地址不能作为默认路由器地址使用,尽管它也包含中通告报文中。优先级的默认值一般为0。 

路由器操作 
当路由器启动时,它定期在所有广播或多播传送接口上发送通告报文。准确地说,这些通告报文不是定期发送的,而是随机传送的,以减小与子网上其他路由器发生冲突的概率。一般每两次通告间隔450和600秒。一份给定的通告报文默认生命周期是30分钟。 
使用生命周期域的另一个时机是当路由器上的某个接口被关闭时。在这种情况下,路由器可以大该接口上发送最后一份通告报文,并把生命周期值设为0。 
除了定期发送主动提供的通告报文以外,路由器还要监听来自主机的请求报文,并发送路由器通告报文以响应这些请求报文。 
如果子网上有多台路由器,由系统管理员为每个路由器设置优先等级。例如,主默认路由器就要比备份路由器具有更高的优先级。 

主机操作 
主机在引导期间一般发送三份路由器请求报文,每三秒钟发送一次。一旦接收到一个有效的通告报文,就停止发送请求报文。 
主机也监听来自相邻路由器的请求报文。这些通告报文可以改变主机的默认路由器。另外,如果没有接收到来自当前默认路由器的通告报文,那么默认路由器会超时。 
只要有一般的默认路由器,该路由器就会每隔10分钟发送通告报文,报文的生命周期是30分钟。这说明主机的默认表项是不会超时的,即使错过一份或两份通告报文。 

实现 
路由器发现报文一般由用户进程(守护程序)创建和处理。这样,在图9.1中就有另一个修改路由表的程序,尽管它只增加或删除默认表项。守护程序必须把它配置成一台路由器或主机来使用。 

(下面是原书 p.125①的译文) 
这两种ICMP报文是新加的,不是所有的系统都支持它们。在我们的网络中,只有Solaris 2.x支持这两种报文( in.rdisc守护程序)。尽管RFC建议用尽可能用IP多播传送,但是路由器发现还可以利用广播报文来实现。 

9 .7 小结 
IP路由操作对于运行TCP/IP的系统来说是最基本,不管是主机还是路由器。路由表项的内容很简单,它包括:5 bit标志,目的IP地址(主机,网络,或默认),下一站路由器的IP地址(间接路由)或者本地接口的IP地址(直接路由),指向本地接口的指针。主机表项比网络表项具有更高的优先级,而网络表项比默认项具有更高的优先级。 
系统产生的或转发的每份IP数据报都要搜索路由表,它可以被路由守护程序或ICMP改变路由报文修改。系统在默认情况下不转发数据报,除非进行特殊的配置。用route命令可以进入静态路由,可以利用新ICMP路由器发现报文来初始化默认表项,并进行动态修改。主机在启动时只有一个简单的路由表,它可以被来自默认路由器的ICMP改变路由报文动态修改。 
在本章,我们集中讨论了单个系统是如何利用路由表的。在下一章,我们将讨论路由器之间是如何交换路由信息的。 







原文链接:http://bbs.chinaunix.net/viewthread.php?tid=16062

转载请注明作者名及原文出处



加载中
返回顶部
顶部