ICMP协议

 

在整个 TCP/IP 协定家族中,对 “使用者” 来说,ICMP 恐怕是易忽略的协定了。关于前面所讨论的协定,真要能发挥工作的前提条件是:”假设一切都没问题” 。然而,在当今如此复杂的网路环境中,前述条件恐怕是没办法保证的:设定可能有误、线路有可能会断、设备可能挂点、router 可能负载太高、 …. 等等又等等的状况,都是我们没办法确保的。那么,我们必需有一套机制来侦测或通知各种各样可能发生的状况,这就是 ICMP 协定的目的了。

之所以说 ICMP 最容易被忽略,是因为,大部份的情况下,ICMP 只给底层的网路设备参考且被解决了。真要劳架使用者执行的话,恐怕不多,最具代表的,算是 ping 与 traceroute 这两个工具了。下面,让我们一起揭开 ICMP 的神祕面纱…

ICMP 协议之內容

ICMP 的全称是 Internet Control Message Protocol 。从技术角度来说,ICMP 就是一个 “错误侦测与回报机制”,其目的就是让我们能够检测网路的连线状况﹐也能确保连线的准确性﹐其功能主要有﹕

  • 侦测远端主机是否存在。
  • 建立及维护路由资料。
  • 重导资料传送路径。
  • 资料流量控制。

ICMP 在沟通之中,主要是透过不同的类别( Type )与代码( Code ) 让机器来识别不同的连线状况。常用的类别如下表所列﹕

類別 名稱 代表意思
0 Echo Reply 是一个回应信息。
3 Distination Unreachable 表示目的地不可到达。
4 Source Quench 当 router 负载过时﹐用来竭止来源继续发送讯息。
5 Redirect 用来重新导向路由路径。
8 Echo Request 请求回应讯息。
11 Time Exeeded for a Datagram 当资料封包在某些路由现象中逾时﹐告知来源该封包已被忽略忽略。
12 Parameter Problem on a Datagram 当一个 ICMP 封包重複著之前的错误时﹐会回覆来源主机关于参数错误的讯息。
13 Timestamp Request 要求对方送出时间讯息﹐用以计算路由时间的差异﹐以满足同步性协定的要求。
14 Timestamp Replay 此讯息纯粹是回应 Timestamp Request 用的。
15 Information Request 在 RARP 协定应用之前﹐此讯息是用来在开机时取得网路信息。
16 Information Reply 用以回应 Infromation Request 讯息。
17 Address Mask Request 这讯息是用来查询子网路 mask 设定信息。
18 Address Mask Reply 回应子网路 mask 查询讯息的。

在 ICMP 使用中﹐不同的类别会以不同的代码来描述具体的状况。以 Type 3 ( Distination Unreachable ) 为例,其下的代码如下所列﹕

代碼 代表意思
0 Network Unreachable
1 Host Unreachable
2 Protocol Unreachable
3 Port Unreachable
4 Fragmentation Needed and DF set
5 Source Route Failed
6 Destination network unknown
7 Destination host unknown
8 Source host isolated
9 Communication with destination network administraively prohibited
10 Communication with destination host administraively prohibited
11 Network unreachable for type of service
12 host unreachable for type of service

ICMP 是個非常有用的協定﹐尤其是當我們要對網路連接狀況進行判斷的時候。下面讓我們看看常用的 ICMP 實例,以更好了解 ICMP 的功能與作用。

關於 PING

當關於這個命令應該很多人都用過了吧﹖它就是用來測試兩台主機是否能夠順利連線的最簡單的工具﹕

ping -c 4 10.0.1.131
PING 10.0.1.130 (10.0.1.130) from 10.0.1.130 : 56(84) bytes of data.
64 bytes from 10.0.1.130: icmp_seq=0 ttl=255 time=116 usec
64 bytes from 10.0.1.130: icmp_seq=1 ttl=255 time=45 usec
64 bytes from 10.0.1.130: icmp_seq=2 ttl=255 time=42 usec
64 bytes from 10.0.1.130: icmp_seq=3 ttl=255 time=42 usec— 10.0.1.130 ping statistics —
4 packets transmitted, 4 packets received, 0% packet loss
round-trip min/avg/max/mdev = 0.042/0.061/0.116/0.032 ms

在 Linux 使用 ping 命令﹐如果您不使用 -c N 參數來指定送出多少個 ICMP 封包的話﹐ping 命令會一直持續下去﹐直到您按Ctrl + C 為止。從上面的命令結果我們可以確定連線是否成功之外﹐還可以根據它的 time 來判斷當前的連線速度﹐數值越低速度越快﹔在命令結束的兩行﹐還有一個總結﹐如果發現您的 packet loss 很嚴重的話﹐那就要檢察您的線路品質﹐或是上游的服務品質了﹔最後一行是 round-trip (來回)時間的最小值﹑平均值﹑最大值﹐它們的時間單位都是微秒 (ms)。不過﹐那個 mdev 是什麼意思我也不知道~~

如果運用得當﹐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 命令)﹕

traceroute www.yahoo.com
traceroute: Warning: www.yahoo.com has multiple addresses; using 216.115.102.78
traceroute to www.yahoo.akadns.net (216.115.102.78), 30 hops max, 38 byte packets
1 swtn184-1.adsl.seed.net.tw (211.74.184.1) 61.209 ms 63.117 ms 59.422 ms
2 139.175.169.1 (139.175.169.1) 60.172 ms 64.253 ms 60.136 ms
3 R58-38.seed.net.tw (139.175.58.38) 61.669 ms 59.185 ms 60.218 ms
4 R58-201.seed.net.tw (139.175.58.201) 68.353 ms 70.353 ms 71.605 ms
5 R57-99.seed.net.tw (139.175.57.99) 71.593 ms 70.570 ms 71.657 ms
6 R58-166.seed.net.tw (139.175.58.166) 367.829 ms 350.511 ms 355.516 ms
7 64.124.33.168.available.above.net (64.124.33.168) 218.493 ms 218.259 ms 219.996 ms
8 * * *
9 ge-2-3-0.msr1.pao.yahoo.com (216.115.101.34) 370.618 ms ge-3-3-0.msr2.pao.yahoo.com (216.115.101.38) 337.389 ms 349.591 ms
10 vl21.bas2.snv.yahoo.com (216.115.100.229) 218.355 ms 217.388 ms vl20.bas1.snv.yahoo.com (216.115.100.225) 221.096 ms
11 w6.snv.yahoo.com (216.115.102.78) 370.140 ms 339.934 ms 340.845 ms

透過 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 封包內容如下:

0 8 16

31

Type Code Checksum
Identifier Sequence Number
OPTIONAL DATA

 

ICMP 與 IP 的關係

在 OSI 模型中,ICMP 協定雖然與 IP 協定同為第三層協定,但 ICMP 本身是不具備傳送能力的。實實上,它跟 TCP/UDP 一樣,也是考 IP 幫忙進行傳送。其封包結構如下:

IP 表頭

ICMP 表頭

ICMP 資訊

因此,只要網路之間能支援 IP ,那就可透過 ICMP 進行錯誤偵測與回報。

ICMP 協定之 RFC 文件

RFC-792﹑RFC-896﹑RFC-950﹑RFC-956﹑RFC-957﹑RFC-1016﹑RFC-1122﹑RFC-1305

習題﹕

  1. 請問為何要有 ICMP ?其功能是甚麼?
  2. 請列舉常見的 ICMP TYPE 有哪些。
  3. 請列舉 Distination Unreachable 的 ICMP CODE 有哪些。
  4. 請描述 ping 是如何運用 ICMP 機制的。
  5. 請描述 traceroute 是如何運用 ICMP 機制的。
  6. 請繪制其中一種 ICMP 的封包結構。
  7. 請說明 ICMP 與 IP 的關係

ICMP协议》有1个想法

评论已关闭。