#TCP/IP# TCP IP详解 卷1:协议-第7章Ping程序

7.1 引言

“p i n g”这个名字源于声纳定位操作。P i n g程序由Mike Muuss编写,目的是为了测试另一台主机是否可达。该程序发送一份I C M P回显请求报文给主机,并等待返回I C M P回显应答(图6 - 3列出了所有的ICMP报文类型)。

一般来说,如果不能P i n g到某台主机,那么就不能Te l n e t或者F T P到那台主机。反过来,如果不能Te l n e t到某台主机,那么通常可以用P i n g程序来确定问题出在哪里。P i n g程序还能测出到这台主机的往返时间,以表明该主机离我们有“多远”。

在本章中,我们将使用P i n g程序作为诊断工具来深入剖析I C M P。P i n g还给我们提供了检测I P记录路由和时间戳选项的机会。文献[Stevens 1990]的第11章提供了P i n g程序的源代码。

几年前我们还可以作出这样没有限定的断言,如果不能P i n g到某台主机,那么就不能Te l n e t或F T P到那台主机。随着I n t e r n e t安全意识的增强,出现了提供访问控制清单的路由器和防火墙,那么像这样没有限定的断言就不再成立了。一台主机的可达性可能不只取决于I P层是否可达,还取决于使用何种协议以及端口号。P i n g程序的运行结果可能显示某台主机不可达,但我们可以用Te l n e t远程登录到该台主机的2 5号端口(邮件服务器)。


7.2 Ping程序

我们称发送回显请求的p i n g程序为客户,而称被p i n g的主机为服务器。大多数的T C P / I P实现都在内核中直接支持P i n g服务器—这种服务器不是一个用户进程(在第6章中描述的两种ICMP查询服务,地址掩码和时间戳请求,也都是直接在内核中进行处理的)。

ICMP回显请求和回显应答报文如图7 - 1所示。

对于其他类型的I C M P查询报文,服务器必须响应标识符和序列号字段。另外,客户发送的选项数据必须回显,假设客户对这些信息都会感兴趣。

U n i x系统在实现p i n g程序时是把I C M P报文中的标识符字段置成发送进程的I D号。这样即使在同一台主机上同时运行了多个p i n g程序实例,p i n g程序也可以识别出返回的信息。

序列号从0开始,每发送一次新的回显请求就加1。p i n g程序打印出返回的每个分组的序列号,允许我们查看是否有分组丢失、失序或重复。I P是一种最好的数据报传递服务,因此这三个条件都有可能发生。

旧版本的p i n g程序曾经以这种模式运行,即每秒发送一个回显请求,并打印出返回的每个回显应答。但是,新版本的实现需要加上- s选项才能以这种模式运行。默认情况下,新版本的p i n g程序只发送一个回显请求。如果收到回显应答,则输出“ host is alive”;否则,在2 0秒内没有收到应答就输出“ no answer(没有回答)”。


7.2.1 LAN输出

在局域网上运行p i n g程序的结果输出一般有如下格式:

cll@cll-linux:~ $ ping google.com.cn
PING google.com.cn (203.208.40.127) 56(84) bytes of data.
64 bytes from 203.208.40.127: icmp_seq=1 ttl=119 time=3.22 ms
64 bytes from 203.208.40.127: icmp_seq=2 ttl=119 time=1.85 ms
64 bytes from 203.208.40.127: icmp_seq=3 ttl=119 time=2.03 ms

当返回I C M P回显应答时,要打印出序列号和T T L,并计算往返时间( T T L位于I P首部中的生存时间字段。当前的B S D系统中的p i n g程序每次收到回显应答时都打印出收到的T T L—有些系统并不这样做。我们将在第8章中通过t r a c e r o u t e程序来介绍T T L的用法)。

从上面的输出中可以看出,回显应答是以发送的次序返回的( 0,1,2等)。p i n g程序通过在I C M P报文数据中存放发送请求的时间值来计算往返时间。当应答返回时,用当前时间减去存放在I C M P报文中的时间值,即是往返时间。注意,在发送端b s d i上,往返时间的计算结果都为0 ms。这是因为程序使用的计时器分辨率低的原因。B S D / 3 8 6版本0 . 9 . 4系统只能提供10 ms级的计时器(在附录B中有更详细的介绍)。在后面的章节中,当我们在具有较高分辨率计时器的系统上( S u n)查看t c p d u m p输出时会发现, I C M P回显请求和回显应答的时间差在4 ms以下。

输出的第一行包括目的主机的I P地址,尽管指定的是它的名字( s v r 4)。这说明名字已经经过解析器被转换成I P地址了。我们将在第1 4章介绍解析器和D N S。现在,我们发现,如果敲入p i n g命令,几秒钟过后会在第1行打印出I P地址, D N S就是利用这段时间来确定主机名所对应的I P地址。

本例中的t c p d u m p输出如图7 - 2所示。

从发送回显请求到收到回显应答,时间间隔始终为3.7 ms。还可以看到,回显请求大约每隔1秒钟发送一次。

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

cll@cll-linux:~ $ arp -a
? (192.168.4.127) at 00:00:c0:1d:12:6c [ether] on enp0s31f6
? (192.168.166.128) at 00:0c:29:3a:b9:cd [ether] on vmnet8
? (192.168.4.106) at 00:00:c0:1d:8e:8c [ether] on enp0s31f6
? (192.168.4.112) at e4:b9:7a:66:2a:d6 [ether] on enp0s31f6
? (192.168.5.177) at 54:bf:64:9a:71:e9 [ether] on enp0s31f6
? (192.168.4.125) at 8c:ec:4b:e3:b0:a3 [ether] on enp0s31f6
arvinchen.cn.zmt.local (192.168.5.1) at 50:da:00:d8:79:ad [ether] on enp0s31f6
? (192.168.5.91) at 64:00:6a:1d:18:b2 [ether] on enp0s31f6
? (192.168.4.62) at 8c:ec:4b:fd:23:ce [ether] on enp0s31f6
? (192.168.4.101) at 70:b3:d5:5e:23:98 [ether] on enp0s31f6
? (192.168.4.147) at 74:e6:e2:f4:72:a9 [ether] on enp0s31f6
? (192.168.5.137) at d4:81:d7:db:13:e9 [ether] on enp0s31f6
? (192.168.4.77) at 64:00:6a:3d:03:a4 [ether] on enp0s31f6

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


7.2.2 WAN输出

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

这里,序列号为1、2、3、4、6、1 0、11、1 2和1 3的回显请求或回显应答在某个地方丢失了。另外,我们注意到往返时间发生了很大的变化(像5 2 %这样高的分组丢失率是不正常的。即使是在工作日的下午,对于I n t e r n e t来说也是不正常的)。

通过广域网还有可能看到重复的分组(即相同序列号的分组被打印两次或更多次),失序的分组(序列号为N + 1的分组在序列号为N的分组之前被打印)。


7.2.3 线路SLIP链接

让我们再来看看S L I P链路上的往返时间,因为它们经常运行于低速的异步方式,如9 6 0 0b / s或更低。回想我们在2 . 1 0节计算的串行线路吞吐量。针对这个例子,我们把主机b s d i和s l i p之间的S L I P链路传输速率设置为1200 b/s。

下面我们可以来估计往返时间。首先,从前面的P i n g程序输出例子中可以注意到,默认情况下发送的I C M P报文有5 6个字节。再加上2 0个字节的I P首部和8个字节的I C M P首部,I P数据报的总长度为8 4字节(我们可以运行t c p d u m p-e命令查看以太网数据帧来验证这一点)。另外,从2 . 4节可以知道,至少要增加两个额外的字节:在数据报的开始和结尾加上E N D字符。此外,S L I P帧还有可能再增加一些字节,但这取决于数据报中每个字节的值。对于1200 b/s这个速率来说,由于每个字节含有8 bit数据、1 bit起始位和1 bit结束位,因此传输速率是每秒1 2 0个字节,或者说每个字节8.33 ms。所以我们可以估计需要1 4 3 3(8 6×8 . 3 3×2)m s(乘2是因为我们计算的是往返时间)。

下面的输出证实了我们的计算:

(对于S V R 4来说,如果每秒钟发送一次请求则必须带- s选项)。往返时间大约是1 . 5秒,但是程序仍然每间隔1秒钟发送一次I C M P回显请求。这说明在第1个回显应答返回之前(1 . 4 8 0秒时刻)就已经发送了两次回显请求(分别在0秒和1秒时刻)。这就是为什么总结行指出丢失了一个分组。实际上分组并未丢失,很可能仍然在返回的途中。

我们在第8章讨论t r a c e r o u t e程序时将回头再讨论这种低速的S L I P链路。


7.2.4 拨号SLIP链路

对于拔号S L I P链路来说,情况有些变化,因为在链路的两端增加了调制解调器。用在s u n和n e t b系统之间的调制解调器提供的是V. 3 2调制方式( 9600 b/s)、V. 4 2错误控制方式(也称作L A P - M)以及V. 4 2 b i s数据压缩方式。这表明我们针对线路链路参数进行的简单计算不再准确了。

多因素都有可能影响。调制解调器带来了时延。随着数据的压缩,分组长度可能会减小,但是由于使用了错误控制协议,分组长度又可能会增加。另外,接收端的调制解调器只能在验证了循环检验字符(检验和)后才能释放收到的数据。最后,我们还要处理每一端的计算机异步串行接口,许多操作系统只能在固定的时间间隔内,或者收到若干字符后才去读这些接口。

作为一个例子,我们在s u n主机上p i n g主机g e m i n i,输出结果如下:

注意,第1个RT T不是10 ms的整数倍,但是其他行都是10 ms的整数倍。如果我们运行该程序若干次,发现每次结果都是这样(这并不是由s u n主机上的时钟分辨率造成的结果,因为根据附录B中的测试结果可以知道它的时钟能提供毫秒级的分辨率)。

另外还要注意,第1个RT T要比其他的大,而且依次递减,然后徘徊在2 8 0~300 ms之间。我们让它运行1 ~ 2分钟,RT T一直处于这个范围,不会低于260 ms。如果我们以9600 b/s的速率计算RT T(习题7 . 2),那么观察到的值应该大约是估计值的1 . 5倍。

如果运行p i n g程序6 0秒钟并计算观察到的RT T的平均值,我们发现在V. 4 2和V. 4 2 b i s模式下平均值为277 ms(这比上个例子打印出来的平均值要好,因为运行时间较长,这样就把开始较长的时间平摊了)。如果我们关闭V. 4 2 b i s数据压缩方式,平均值为330 ms。如果我们关闭V. 4 2错误控制方式(它同时也关闭了V. 4 2 b i s数据压缩方式),平均值为300 ms。这些调制解调器的参数对RT T的影响很大,使用错误控制和数据压缩方式似乎效果最好。


7.3 IP记录路由选项

p i n g程序为我们提供了查看I P记录路由( R R)选项的机会。大多数不同版本的p i n g程第7章Ping程序使用65序都提供-R选项,以提供记录路由的功能。它使得p i n g程序在发送出去的I P数据报中设置I PR R选项(该I P数据报包含I C M P回显请求报文)。这样,每个处理该数据报的路由器都把它的I P地址放入选项字段中。当数据报到达目的端时, I P地址清单应该复制到I C M P回显应答中,这样返回途中所经过的路由器地址也被加入清单中。当p i n g程序收到回显应答时,它就打印出这份I P地址清单。

这个过程听起来简单,但存在一些缺陷。源端主机生成R R选项,中间路由器对R R选项的处理,以及把I C M P回显请求中的R R清单复制到I C M P回显应答中,所有这些都是选项功能。幸运的是,现在的大多数系统都支持这些选项功能,只是有一些系统不把I C M P请求中的I P清单复制到ICMP应答中。但是,最大的问题是I P首部中只有有限的空间来存放I P地址。我们从图3 - 1可以看到, I P首部中的首部长度字段只有4 bit,因此整个I P首部最长只能包括1 5个32 bit长的字(即6 0个字节)。由于I P首部固定长度为2 0字节, R R选项用去3个字节(下面我们再讨论),这样只剩下3 7个字节( 6 0-2 0-3)来存放I P地址清单,也就是说只能存放9个I P地址。对于早期的ARPANET来说,9个I P地址似乎是很多了,但是现在看来是非常有限的(在第8章中,我们将用Tr a c e r o u t e工具来确定数据报的路由)。除了这些缺点,记录路由选项工作得很好,为详细查看如何处理I P选项提供了一个机会。

I P数据报中的R R选项的一般格式如图7 - 3所示。


 

c o d e是一个字节,指明I P选项的类型。对于R R选项来说,它的值为7。l e n是R R选项总字节长度,在这种情况下为3 9(尽管可以为R R选项设置比最大长度小的长度,但是p i n g程序总是提供3 9字节的选项字段,最多可以记录9个I P地址。由于I P首部中留给选项的空间有限,它一般情况都设置成最大长度)。

p t r称作指针字段。它是一个基于1的指针,指向存放下一个I P地址的位置。它的最小值为4,指向存放第一个I P地址的位置。随着每个I P地址存入清单, p t r的值分别为8,1 2,1 6,最大到3 6。当记录下9个I P地址后,p t r的值为4 0,表示清单已满。

当路由器(根据定义应该是多穴的)在清单中记录I P地址时,它应该记录哪个地址呢?是入口地址还是出口地址?为此, RFC 791 [Postel 1981a]指定路由器记录出口I P地址。我们在后面将看到,当原始主机(运行p i n g程序的主机)收到带有R R选项的I C M P回显应答时,它也要把它的入口I P地址放入清单中。

 

7.3.1 通常的例子

我们举一个用R R选项运行p i n g程序的例子,在主机s v r 4上运行p i n g程序到主机s l i p。一个中间路由器( b s d i )将处理这个数据报。下面是s v r 4的输出结果:

分组所经过的四站如图7 - 4所示(每个方向各有两站),每一站都把自己的I P地址加入R R清单。

路由器b s d i在不同方向上分别加入了不同的I P地址。它始终是把出口的I P地址加入清单。我们还可以看到,当I C M P回显应答到达原始系统( s v r 4)时,它把自己的入口I P地址也加入清单中。

还可以通过运行带有- v选项的t c p d u m p命令来查看主机s u n上进行的分组交换(参见I P选项)。输出如图7 - 5所示。

输出中o p t l e n = 4 0表示在I P首部中有4 0个字节的选项空间( I P首部长度必须为4字节的整数倍)。R R { 3 9 }的意思是记录路由选项已被设置,它的长度字段是3 9。然后是9个I P地址,符号“#”用来标记R R选项中的p t r字段所指向的I P地址。由于我们是在主机s u n上观察这些分组(参见图7 - 4),因此所能看到I C M P回显请求中的I P地址清单是空的,而I C M P回显应答中有3个I P地址。我们省略了t c p d u m p输出中的其他行,因为它们与图7 - 5基本一致。

位于路由信息末尾的标记E O L表示I P选项“end of list(清单结束)”的值。E O L选项的值可以为0。这时表示3 9个字节的R R数据位于I P首部中的4 0字节空间中。由于在数据报发送之前空间选项被设置为0,因此跟在3 9个字节的R R数据之后的0字符就被解释为E O L。这正是我们所希望的结果。如果在I P首部中的选项字段中有多个选项,在开始下一个选项之前必须填入空白字符,另外还可以用另一个值为1的特殊字符NOP(“no operation”)。

在图7 - 5中,SVR4把回显请求中的T T L字段设为3 2,B S D / 3 8 6设为2 5 5(它打印出的值为2 5 4是因为路由器bsdi已经将其减去1)。新的系统都把ICMP报文中的T T L设为最大值(255)。

在作者使用的三个T C P / I P系统中,B S D / 3 8 6和SVR4都支持记录路由选项。这就是说,当转发数据报时,它们都能正确地更新R R清单,而且能正确地把接收到的ICMP回显请求中的R R清单复制到出口ICMP回显应答中。虽然SunOS 4.1.3在转发一个数据报时能正确更新RR清单,但是不能复制RR清单。Solaris 2.x对这个问题已作了修改。


7.3.2 异常的输出

下面的例子是作者观察到的,把它作为第9 章讨论I C M P间接报文的起点。在子网1 4 0 . 2 5 2 . 1上p i n g主机a i x(在主机s u n上通过拨号S L I P连接可以访问),并带有记录路由选项。

在s l i p主机上运行有如下输出结果:

我们已经在主机b s d i上运行过这个例子。现在选择s l i p来运行它,观察R R清单中所有的9个I P地址。
在输出中令人感到疑惑的是,为什么传出的数据报( I C M P回显请求)直接从n e t b传到a i x,而返回的数据报( I C M P回显应答)却从a i x开始经路由器g a t e w a y再到n e t b?这里看到的正是下面将要描述的I P选路的一个特点。数据报经过的路由如图7 - 6所示。

问题是a i x不知道要把目的地为子网1 4 0 . 2 5 2 . 1 3的I P数据报发到主机n e t b上。相反,a i x在它的路由表中有一个默认项,它指明当没有明确某个目的主机的路由时,就把所有的数据报发往默认项指定的路由器g a t e w a y。路由器g a t e w a y比子网1 4 0 . 2 5 2 . 1上的任何主机都具备更强的选路能力(在这个以太网上有超过1 5 0台主机,每台主机的路由表中都有一个默认项指向路由器g a t e w a y,这样就不用在每台主机上都运行一个选路守护程序)。

这里没有应答的一个问题是为什么g a t e w a y不直接发送ICMP报文重定向到a i x(9 . 5节),以更新它的路由表?由于某种原因(很可能是由于数据报产生的重定向是一份I C M P回显请求报文),重定向并没有产生。但是如果我们用Te l n e t登录到a i x上的d a y t i m e服务器, ICMP就会68使用产生重定向,因而它在a i x上的路由表也随之更新。如果接着执行p i n g程序并带有记录路由选项,其路由显示表明数据报从n e t b到a i x,然后返回n e t b,而不再经过路由器g a t e w a y。

在9 . 5节中将更详细地讨论ICMP重定向的问题。



7.4 IP时间戳选项

I P时间戳选项与记录路由选项类似。I P时间戳选项的格式如图7 - 7所示(请与图7 - 3进行比较)。

        

时间戳选项的代码为0 x 4 4。其他两个字段l e n和p t r与记录路由选项相同:选项的总长度(一般为3 6或4 0)和指向下一个可用空间的指针( 5,9,1 3等)。

接下来的两个字段是4 bit的值:O F表示溢出字段, F L表示标志字段。时间戳选项的操作根据标志字段来进行,如图7 - 8所示。 

如果路由器由于没有空间而不能增加时间戳选项,那么它将增加溢出字段的值。
第7章Ping程序使用69

时间戳的取值一般为自U T C午夜开始计的毫秒数,与I C M P时间戳请求和应答相类似。如果路由器不使用这种格式,它就可以插入任何它使用的时间表示格式,但是必须打开时间戳中的高位以表明为非标准值。

与我们遇到的记录路由选项所受到的限制相比,时间戳选项遇到情况要更坏一些。如果我们要同时记录I P地址和时间戳(标志位为1),那么就可以同时存入其中的四对值。只记录时间戳是没有用处的,因为我们没有标明时间戳与路由器之间的对应关系(除非有一个永远不变的拓扑结构)。标志值取3会更好一些,因为我们可以插入时间戳的路由器。一个更为基本的问题是,很可能无法控制任何给定路由器上时间戳的正确性。这使得试图用I P选项来计算路由器之间的跳站数是徒劳的。我们将看到(第8章)t r a c e r o u t e程序可以提供一种更好的方法来计算路由器之间的跳站数。


7.5 小结

p i n g程序是对两个T C P / I P系统连通性进行测试的基本工具。它只利用I C M P回显请求和回显应答报文,而不用经过传输层( T C P / U D P)。P i n g服务器一般在内核中实现ICMP的功能。

我们分析了在L A N、WA N以及S L I P链路(拨号和线路)上运行p i n g程序的输出结果,并对串行线路上的S L I P链路吞吐量进行了计算。我们还讨论并使用了p i n g程序的I P记录路由选项。利用该I P选项,可以看到它是如何频繁使用默认路由的。在第9章我们将再次回到这个讨论主题。另外,还讨论了IP 时间戳选项,但它在实际使用时有所限制。

发布了170 篇原创文章 · 获赞 207 · 访问量 459万+

猜你喜欢

转载自blog.csdn.net/xiaoting451292510/article/details/103293075
今日推荐