在整个 TCP/IP 协定家族中,对使用者来说,ICMP 恐怕是易忽略的协定了。关于前面所讨论的协定,真要能发挥工作的前提条件是:假设一切都没问题。然而,在当今如此复杂的网路环境中,前述条件恐怕是没办法保证的:设定可能有误、线路有可能会断、设备可能挂点、router 可能负载太高等等状况,都是我们没办法确保的。那么,我们必需有一套机制来侦测或通知各种各样可能发生的状况,这就是 ICMP 协定的目的了。之所以说 ICMP 最容易被忽略,是因为,大部份的情况下,ICMP 只给底层的网路设备参考且被解决了。真要劳架使用者执行的话,恐怕不多,最具代表的,算是 ping traceroute 这两个工具了。下面,让我们一起揭开 ICMP 的神秘面纱...
  ICMP 协定之内容
  ICMP 的全称是 Internet Control Message Protocol 。从技术教度来说,ICMP 就是一个 "错误侦测与回报机制",其目的就是让我们能够检测网路的连线状况﹐也能确保连线的准确性﹐其功能主要有:
  · 侦测远端主机是否存在。
  · 建立及维护路由资料。
  · 重导资料传送路径。
  · 资料流量控制。
  ICMP 在沟通之中,主要是透过不同的类别( Type )与代码( Code ) 让机器来识别不同的连线状况。常用的类别如下表所列:
ICMP 协议_休闲
  ICMP 协议_职场_02   
  ICMP 是个非常有用的协定﹐尤其是当我们要对网路连接状况进行判断的时候。下面让我们看看常用的 ICMP 实例,以更好了解 ICMP 的功能与作用。
  关于 PING
  当关于这个命令应该很多人都用过了吧﹖它就是用来测试两台主机是否能够顺利连线的最简单的工具:
ICMP 协议_职场_03   
  在 Linux 使用 ping 命令﹐如果您不使用 -c N 参数来指定送出多少个 ICMP 封包的话﹐ping 命令会一直持续下去﹐直到您按 Ctrl + C 为止。从上面的命令结果我们可以确定连线是否成功之外﹐还可以根据它的 time 来判断当前的连线速度﹐数值越低速度越快﹔在命令结束的两行﹐还有一个总结﹐如果发现您的 packet loss 很严重的话﹐那就要检察您的线路品质﹐或是上游的服务品质了﹔最后一行是 round-trip (来回)时间的最小值﹑平均值﹑最大值﹐它们的时间单位都是微秒 (ms)。如果运用得当﹐ping 可以帮我们判断出许多状况。例如﹐我们要看一下跟远方的机器是否连接得上﹐先可以 ping 一下对方的机器名称﹔如果连接不上的话﹐我们可以 ping 对方的 ip ﹐如果 ip 可以 ping 得到﹐那么﹐很可能是 dns 不工作了﹔那么我们可以检查本身主机的 dns 伺服器是否指定正确、以及 dns 伺服器是否设定正确。如果连 IP ping 不了﹐那么﹐很可能是 IP 设定的问题了﹐也可能是网路的连线问题。检查的步骤也有很多种﹐下面是方法之一:
  1. ping 对方的 router (如过您知道其位址的话)﹐假如 ping 得上﹐那可能是对方机器和其相连网路的问题﹔
  2. 如果 ping 不到对方的 router ﹐那么可以 ping 自己的 router。如果 ping 得上﹐那么好可能是 router router 之间的问题﹔
  3. 如果自己的 router ping 不到﹐那么可能是自己的机器和 router 之间的问题﹐我们可以 ping 一下自己的 IP 。如果自己的 IP 可以 ping 得到﹐那么﹐可能是连线的问题﹐我们可以检查一下网线、hub、等设备﹐看看有没有损毁的状况。
  4. 同时﹐我们也可以 pin g一下网路上面其它的机器﹐也可以用其它机器 ping 一下 router ﹐来判别一下问题来自自己机器、还是网路、还是 router、等等。
  5. 如果自己的 IP ping 不到﹐那么可能是网路卡坏掉了或没有正确设定﹐可以看看设备资源有没有冲突﹐也可以看看设备有没有被系统启动。
  6. 如果看来都没问题﹐那么可以 ping 一下回圈位址 127.0.0.1 ﹐如果连这个都 ping 不了的话﹐这台机器的 IP 功能根本就没被启动﹗那么﹐您就要先检查一下网路功能有没有选择、IP 协定有没有被绑定( bind )、等基本网路设定了。
  从上面的过程中﹐我们不难看出 ping 这个命令真是非常有用的。然而,我们能 ping 一台机器的时候﹐我们就可以确定连线是成功的﹐但如果不能 ping 的话﹐未必是连不上哦。嗯﹖怎么说呢﹖且听我道来﹕使用 ping 命令的时候﹐事实上是送出一个 echo-request( type 8 ) ICMP 封包﹐如果对方的机器能接收到这个请求﹐而且愿意作出回应﹐则送回一个 echo-reply( type 0 ) ICMP 封包﹐当这个回应能顺利抵达的时候﹐那就完成一个 ping 的动作。
  很显然﹐如果这个 echo-request 不能到达对方的机器﹐或是对方回应的 echo-reply 不能顺利送回来﹐那 ping 就失败。这情形在许多有防火墙的环境中都会碰到﹐如果防火墙随便将 request reply 拦下来就会导致 ping 失败﹐但并不代表其它连线不能建立。另外﹐就算没有防火墙作怪﹐对方也可以将机器设定为不回应任何 echo-request 封包﹐若在 Linux 上,只要用下面命令就可以了:
  echo "1" > /proc/sys/net/ipv4/icmp_echo_ignore_all
  如果您不想别人 ping 您的机器﹐也可以如法泡制。但真的当您需要用 ping 命令来测试网路连线的时候﹐就做不到了。
  关于 TRACEROUTE
  除了用 ping 命令来检查连线之外﹐还有另外一个非常厉害的工具我们可以使用的﹐就是 traceroute 命令了( windows 上面则称为 tracert 命令)
ICMP 协议_职场_04
  透过 traceroute 命令﹐我们可以找出通往目的地的所有经过的路由节点﹐并以数字将路由顺序标识出来。若是您觉得回应很慢,那可加上 -n 参数﹐节点名称将会以 IP 位址显示﹐因为不需要进行名称解析﹐回应速度当然会快一些。
  从上面的 traceroute 结果﹐我们可以看到每一个节点都返回 3 round-trip 时间作参考。这样﹐您就能够判断整个连线路由中﹐交通瓶颈所在的位置在哪里。您或许奇怪 traceroute 是如何揪出所有路由节点的呢﹖且听我细说:
  您是否有留意到 ping 命令的结果有一个 TTL 值﹖通常来说﹐Time To Live 都是以时间为单位的﹐但是在路由上面却是以跳站数目为单位的。为了防止一个封包无限期呆在网路上路由﹐每一个封包都会被赋予一个 TTL 值﹐告诉它最多能经过多少个跳站。当封包被一个路由节点处理之后﹐它原来的 TTL 值就会被扣掉 1 ﹐这样﹐如果封包的 TTL 降到 0 的时候﹐路由器就会丢弃这个封包﹐并且同时向来源地送出一个 time_exceeded( type 11 ) ICMP 封包﹐以告知其封包的命运。
  聪明的 traceroute 程式设计者正是利用了 ICMP 这个特殊功能﹐来找出每一个路由节点的:
  1. 首先﹐traceroute 命令会向目标位址送出 UDP 侦测封包( Linux 中,可用 -I 改为 ICMP 封包)﹐但将第一个送出的封包之 TTL 设为 1 。这样﹐第一个路由节点在处理这个封包的时候﹐减掉 1 ,并发现 TTL 0 ﹐于是就不处理这个封包﹐并同时送回一个 ICMP 封包。这样﹐发送端就知道第一个路由节点在哪里了。
  2. 当接得到第一个 ICMP 返回的时候﹐程式会检查返回主机是否就是目标主机﹐如果不是﹐则再送出第二个封包﹐但 TTL 比上次增加 1
  3. 这样﹐第一路由节点接到的封包之 TTL 就不是 0 ﹐那么处理完毕后送给下一个节点﹐同时将 TTL 扣除 1 。这样,当下一个站收到这个封包,再扣掉 TTL 0 ﹐也会送回 ICMP 封包﹐这样﹐程式就知道第二个路由节点在哪里了。
  4. 然后重复上一个动作﹐直到找到目标主机为止﹐或是封包的最大 TTL (通常为 30) 都用光为止﹐但您可以用 -m 参数来指定最大的 TTL 值。
  但是﹐在实作中﹐未必是所有路由设备都会﹑或愿意送回 ICMP 封包的。碰到这样的情况﹐您就会看到第 8 个跳站的情形了(以星号显示)。假如 traceroute 最后的结果一直维持着 * 符号﹐那可能是因为 ICMP 被对方的防火墙拦下来的结果。这样的话﹐您可能无法完成防火墙后的路由追踪了。
  从上面的例子来观察﹐由第 6 个跳站开始明显降慢下来﹐而根据名称看来﹐应该就是 ISP 连出 backbond 的节点。假如您发现从内部网路到自己的 router 之间的连线都很快﹐过了 router 之后就很慢﹐如果不是专线的线路出现了问题﹐那很可能到了要升级专线的时候了﹐或是这时候刚好碰到有人大量使用频宽﹔假如速度过了 router 连到对方的机房还很快﹐然后就开始降下来﹐那您要好好审查一下当初和 ISP 签订的合约上﹐关于频宽的保证问题是如何说的﹔但如果您发现连线到国外的网站﹐而速度是从进入对方国家之后才降下来的﹐那就没什么办法了。
  其实 ICMP 协定还有许多实在上面的例子﹐这里不一一介绍了。能灵活运用 ICMP 协定﹐对我们了解和测试网路情况非常有帮助。
  ICMP 封包格式
  由于 ICMP 的类别翻多,且各自又有各自的代码,因此,ICMP 并没有一个统一的封包格式以供全部 ICMP 讯息使用,不同的 ICMP 类别分别有不同的封包栏位。以 echo-request echo-reply 为例,它们的 ICMP 封包内容如下:
ICMP 协议_职场_05  
  因此,只要网路之间能支援 IP ,那就可透过 ICMP 进行错误侦测与回报。
  ICMP 协定之 RFC 文件RFC-792RFC-896RFC-950RFC-956RFC-957RFC-1016RFC-1122RFC-1305