ICMP 協議
定義
網際控制訊息協定,全稱 Internet Control Message Protocol。主要功能是用來 偵測網路當前的狀況,因為透過 IP 在網路傳遞資料不怎麼可靠,傳遞過程必須經過 多個路由器 轉發才能夠送達目的地,那麼為了確保轉發前能夠安全送達,所以就有了 ICMP 協議。
在網路上,每一個 Node 或是 路由器 都會支援 ICMP 協議,在 彼此的傳遞過程 就可以來互相交換目前網路的狀況資訊,一旦在傳遞的過程中發生錯誤 (例如:主機不可達、路由不可達、網路中斷等),ICMP 協議就會將這些 錯誤資訊的封包傳回主機 進行 錯誤處理。
其中,ICMP 所產生的報文有兩種,分別是 障礙通知 和 狀況查詢:
障礙通知:當主機封包傳送至一半發生問題而無法繼續傳遞,ICMP 就會將原因回傳原主機。

狀況查詢:透過發送 ICMP 來查詢目前網路狀況。

圖片中的不論是
路由器 (1、2)還是Host B (3),都有可能回傳 ICMP,畢竟我們不知道經過的這些路徑中,是否每個能夠正常運作。
ICMP 格式
ICMP 的報文則是 被嵌入在 IP 報文 內,但是 ICMP 的長度不是固定的,會根據 訊息的類型 而異。

內部 ICMP 格式:
- Message Type:表示
ICMP 的訊息類型,總共有13 種的類型,請參考下表。 - Code:
編碼,對各種訊息類型進一步說明工作內容,通常都會是0,類似於HTTP Status Code。 - Checksum:
錯誤檢查,用於封包進行錯誤檢查,該校驗和是從ICMP Header 和 Data替換為 0 的數據計算得出的,Checksum 的演算法則是明確被定義於 RFC 1071 。 - Message Description:
訊息說明。 - Message Data:
訊息資料。

| Message Type | ICMP 訊息功能 |
|---|---|
| 0 | Echo Reply(回應答覆) |
| 3 | Destination Unreachable(目的地無法到達) |
| 4 | Source Quench(來源抑制) |
| 5 | Redirect(改變傳輸路徑) |
| 8 | Echo Request(回應要求) |
| 9 | Router Advertisement(路由器宣傳) |
| 10 | Router Solicitation(路由器懇請) |
| 11 | Time Exceeded for a Datagram(溢時傳輸) |
| 12 | Parameter Problem on a Datagram(參數問題) |
| 13 | Timestamp Request(時間標籤要求) |
| 14 | Timestamp Reply(時間標籤回覆) |
| 15 | Information Request(資訊要求)(停用) |
| 16 | Information Reply(資訊回覆)(停用) |
| 17 | Address Mask Request(位址遮罩要求) |
| 18 | Address Mask Reply(位址遮罩回覆) |
Ping
Ping 是一個簡單的網路工具,用於測試與驗證 目標的 IP Address 是否可用,或是評估彼此之間的往返的時間 (RTT,Round Trip Time),而 Ping 就是使用 ICMP 協議的 Echo Request 向需要評估的網路介面傳遞封包並等待 Echo Reply。
使用範例
1 | # 設定 ping 的間隔秒數 |
Traceroute
在 IP Header 中的 Options 欄位佔用了 0-40 bytes (Padding 則是為了讓 IP Header 能夠 以 32位元為倍數,補足 Options 的長度),其中這個位置就是 ping 用來 存放經過的路由 IP。
不過在 Options 內又會有 3 bytes 用來儲存欄位資訊,所以最後只會剩下 37 bytes 能夠儲存 IP Address,以 IPv4 的格式計算的話,每個 IP Address 佔用 4 bytes,最多只能存放 9 個路由 的 IP 位址。

由於這樣的限制,而 traceroute 有了迫切的需求,traceroute 的運作原理則是透過 UDP 協議和 TTL (Time to Live) 去作為 每個路由器的計數器,每次到達一個路由時,就會讓其 TTL 減 1 ,若是 TTL 歸 0 則就會用 ICMP 的超時報文 (Time to live exceed in-transit) 返回原本的主機。
然後再次使用 UDP 協議,但 TTL 會隨著每次經過的路由器而疊加,直到抵達目的 IP Address 後返回 ICMP 端口不可達報文 (Port unreachable)。
透過每次 TTL 的疊加計算,就可以突破 IP Header 中的 9 個 IP 位址的上限。

每個 TTL 都會
發送 3 個封包,並且會計算來回的時間。若是5 秒內沒有收到任一份回應,就會打印星號 (*)。
使用場景
通常 Ping 是用來去判斷 兩者之間的網路運作是否正常 和 整體的回應時間,而使用 traceroute 則是針對了解 所經過路由器的延遲時間 進而分析更細部的問題。
使用範例
1 | $ traceroute google.com |
ICMP 排查
本篇文章將會使用本機的環境 (Macbook) 向 8.8.8.8 Google 的 DNS Server 使用 ping 與 traceroute 工具發送請求,並且透過 Wireshark 對其封包進行解析。
Ping
- 開啟 Wireshark,並在篩選輸入
ip.addr == 8.8.8.8來查找與該位址一樣的封包,選擇WiFi en0 的網路介面(網路介面依電腦環境而異,如果是使用乙太網路,可以選擇乙太網路的選項),並且網路介面上的 filter 輸入host 8.8.8.8。

- 開啟 command line,輸入 ping 指令,執行 4 次,並可以從 Wireshark 看到封包的動向。
1 | $ ping -c 4 8.8.8.8 |

- ICMP Echo Request 排查。

- Type:
8 (Echo request) - Code:0
- Checksum:0x97d6
- Identifier:(0xbcf1)(0xf1bc)
- Sequence number:(0x0000)(0x0000)

- ICMP Echo Reply 排查。

- Type:
0 (Echo reply) - Code:0
- Checksum:0x9fd6
Traceroute
- 操作如 Ping 的
步驟一。 - 使用 command line,執行 traceroute。
1 | $ traceroute 8.8.8.8 |

可以觀察到,從我的 Macbook 到 8.8.8.8,會經過 9 個 hops (包含 8.8.8.8),總共有 30 個封包,對應每筆請求都會 傳遞 3 個封包的規則,最後目的位址則是返回 Destintantion unreachable (Port unreachable) 的 ICMP 報文收尾。

如果從 第 3、6 筆 封包也確實有根據 TTL 經過的 路由器數量 來遞增。

這邊其實使用
host 8.8.8.8將 IP 地址進行過濾,所以可能有人會發現沒有Time to live exceed in-transit報文,只要不過濾 8.8.8.8 就可以看到相對應資訊,如下圖所示。

參考資料
- https://www.tsnien.idv.tw/Manager_WebBook/chap4/4-5 ICMP 協定與分析.html
- https://sdn.feisky.xyz/wang-luo-ji-chu/index/icmp
- https://www.scaler.com/topics/difference-between-ping-and-traceroute/
- https://youtu.be/yihwHXom_ek