網際網路控制訊息協議

網際網路控制訊息協議（Internet Control Message Protocol，縮寫：ICMP）是網際網路協議族的核心協議之一。它用於網際協議（IP）中傳送控制訊息，提供可能發生在通訊環境中的各種問題反饋。透過這些資訊，使管理者可以對所發生的問題作出診斷，然後採取適當的措施解決。

ICMP 依靠 IP 來完成它的任務，它是 IP 的主要部分。它與傳輸協議（如 TCP 和 UDP）顯著不同：它一般不用於在兩點間傳輸資料。它通常不由網路程式直接使用，除了 ping 和 traceroute 這兩個特別的例子。

IPv4 中的 ICMP 被稱作 ICMPv4，IPv6 中的 ICMP 則被稱作 ICMPv6。

技術細節

ICMP 是在 RFC 792 中定義的網際網路協議族之一。通常用於返回的錯誤資訊或是分析路由。ICMP 錯誤訊息總是包括了源資料並返回給傳送者。

ICMP 錯誤訊息的例子之一是 TTL 值過期。每個路由器在轉發資料報的時候都會把 IP 包頭中的 TTL 值減 1。如果 TTL 值為 0，“TTL 在傳輸中過期” 的訊息將會回報給源地址。

每個 ICMP 訊息都是直接封裝在一個 IP 資料包中的，因此，和 UDP 一樣，ICMP 是不可靠的。

雖然 ICMP 是包含在 IP 資料包中的，但是對 ICMP 訊息通常會特殊處理，會和一般 IP 資料包的處理不同，而不是作為 IP 的一個子協議來處理。在很多時候，需要去檢視 ICMP 訊息的內容，然後傳送適當的錯誤訊息到那個原來產生 IP 資料包的程式，即那個導致 ICMP 訊息被傳送的 IP 資料包。

很多常用的工具是基於 ICMP 訊息的。traceroute 是透過傳送包含有特殊的 TTL 的包，然後接收 ICMP 超時訊息和目標不可達訊息來實現的。 ping 則是用 ICMP 的 "Echo request"（類別程式碼：8）和 "Echo reply"（類別程式碼：0）訊息來實現的。

ICMP 報文結構

2.1 報頭

ICMP 報頭從 IP 報頭的第 160 位開始（IP 首部 20 位元組）（除非使用了 IP 報頭的可選部分）。

Type - ICMP 的型別，標識生成的錯誤報文；
Code - 進一步劃分 ICMP 的型別，該欄位用來查詢產生錯誤的原因.；例如，ICMP 的目標不可達型別可以把這個位設為 1 至 15 等來表示不同的意思。
Checksum - Internet 校驗和（RFC 1071），用於進行錯誤檢查，該校驗和是從 ICMP 頭和以該欄位替換為 0 的資料計算得出的。
Rest of Header - 報頭的其餘部分，四位元組欄位，內容根據 ICMP 型別和程式碼而有所不同。

2.2 填充資料

填充的資料緊接在 ICMP 報頭的後面（以 8 位為一組）：

Linux 的 "ping" 工具填充的 ICMP 除了 8 個 8 位元組的報頭以外，預設情況下還另外填充資料使得總大小為 64 位元組。
Windows 的 "ping.exe" 填充的 ICMP 除了 8 個 8 位元組的報頭以外，預設情況下還另外填充資料使得總大小為 40 位元組。

報文型別

3.1 源站抑制

源站抑制報文旨在請求傳送方降低發往路由器或主機的報文傳送速率。在接收的過程中，當接收方沒有足夠的接收緩衝區來處理接收到的報文，或者接收這個報文會導致臨近其本身的緩衝區限制時，就會觸發源站抑制報文。

資料被從一個或一群主機高速地發往網路上的一個路由器，雖然路由器有緩衝機制，但是路由器的緩衝區大小通常（由於物理記憶體有限的原因）被限制。因此，如果路由器的通訊量過大，路由器最終會（由於記憶體耗盡，導致必須丟棄掉接收到的資料報）無法繼續處理超過輸入緩衝區限制的部分資料，直到路由器緩衝佇列有空餘空間可以存放新的資料報。但是由於網路層（Network Layer）缺乏確認訊息（ACK）機制，因此客戶端無法獲知資料是否成功抵達接收方。所以研究者提出了源站抑制這一補救措施來解決這一問題：當路由器發現流入資料速率遠遠高於流出資料速率時，會發送 ICMP 源站抑制報文給源站，通知源站應該降低其資料傳輸速度或等待一定時間後再嘗試傳送更多資料。當源站接收到 ICMP 源站抑制報文時會減慢資料傳送的速度，或者在再次嘗試傳送資料前等待一定的時間，使得路由器能夠（在處理完當前接收到的資料之後）清空輸入緩衝佇列。

但是因為有研究表明 “源站抑制是一種無效的（不公平的）補救措施 “，所以路由的源站抑制報文已在 1995 年被 RFC 1812 棄用。此外，（路由）轉發和回應任何形式的源站抑制報文已在 2012 年被 RFC 6633 棄用

其中:

型別（Type） 必須設定為 4

程式碼（Code） 必須設定為 0

IP 資料報頭部 和其附加的資料用於傳送端根據回應報文匹配對應的請求報文

3.2 重定向

重定向 報文是閘道器發出的，用於要求主機或路由器改變資料報的傳輸路徑的 ICMP 報文。ICMP 重定向是路由器將路由資訊傳達給主機的機制。這種型別的報文通知主機更新它的路由資訊（請求主機改變其路由）。如果一個主機在通訊時將資料報傳送給了路由器 R1，而 R1 將這個資料報轉發給了另一個路由器 R2，且主機到路由器 R2 之間有一條直連的路徑（也就是說，此主機和路由器 R2 處於同一乙太網段上），那麼路由器 R1 會發送一條重定向報文給主機，來通知它到路由器 R2 可用路徑裡有一條更短、更最佳化的路徑。這個主機在接收到這個重定向報文之後應該改變其路由至這個最佳化版本的路由資訊，來將抵達這個目的地的資料報直接傳送到路由器 R2，並且路由器仍將原始資料報傳送到預期目的地。但是，如果一個數據報攜帶有路由資訊，那麼即使有更加最佳化的路徑，路由器也不會發送重定向報文。並且，RFC 1122 指出，重定向報文應該只由閘道器傳送，而不應該由網際網路主機發送。

其中:

型別（Type） 必須設定為 5.

程式碼（Code） 指定重定向的原因，見下表

路由器的 IP 地址（IP address） 是一個 32 位的閘道器 IP 地址，該地址指明瞭該資料報應該被重定向到的路由器地址。

激發重定向報文的資料報 IP 首部及其資料的前 8 位元組（IP header） 用於收到重定向報文的主機根據回應報文匹配對應的請求報文，來確定該資料報的目的站地址。

3.3 超時

超時 報文是閘道器產生併發送給源站的 ICMP 報文，用於通知源站有資料報因為存活時間遞減至 0 而被此閘道器丟棄。當主機等待資料報分片的過程中超時而無法重新組裝資料報分片時也會產生該報文。

超時報文也用於 traceroute 工具來識別兩個主機之間的路徑上的閘道器。

其中:

型別（Type） 必須設定為 11

程式碼（Code） 指定重超時的原因，見下表

激發超時報文的資料報 IP 首部及其資料的前 8 位元組 這些資訊用於源站根據收到的超時報文來確定具體哪個資料報已被丟棄。對於高層協議，比如使用者資料報協議 和 傳輸控制協議而言，額外的 8 位元組資料指明瞭已被丟棄的資料報中的源埠與目的埠。

3.4 時間戳請求

時間戳請求 報文主要用於網際網路機器（包括路由器和主機）之間同步時鐘。起始時間戳是傳送端最後一次改動該資料報的時間戳 (為世界標準時午夜開始計算的毫秒數)。在該型別的報文中，接收時間戳和傳輸時間戳未被使用。

其中:

型別（Type） 必須設定為 13

程式碼（Code） 必須設定為 0

識別符號（Identifier） and 序號（Sequence） 用於在時間戳請求報文和時間戳回答報文之間建立關聯

起始時間戳（Originate timestamp） 為世界標準時午夜開始計算的毫秒數。 如果沒有可用的世界標準時參考，則可以將最高有效位設定為 1 以指示這是一個非標準時間值。

3.5 時間戳回答

時間戳回答 報文是對時間戳請求報文的回答報文。 時間戳回答報文由接收到的時間戳請求報文其中的起始時間戳和接收時間戳（回應端主機接收到請求報文並建立時間戳回應報文的時間，單位為毫秒）、傳輸時間戳（時間戳回答報文被髮送出去的時間，單位為毫秒）組成。

其中:

型別（Type） 必須設定為 14

程式碼（Code） 必須設定為 0

識別符號（Identifier） 和 序號（Sequence number） 用於在時間戳請求報文和時間戳回答報文之間建立關聯。

起始時間戳（Originate timestamp） 是傳送端最後一次改動該資料報的時間戳。

接收時間戳（Receive timestamp） 是回應端主機接收到請求報文並建立時間戳回應報文的時間，單位為毫秒。

傳輸時間戳（Transmit timestamp） 是最後一次修改回應報文並將其傳送出去的時間，單位為毫秒。

所有的時間戳都是世界標準時午夜起始的毫秒數。如果這個時間不能表示為毫秒或者沒有可用的世界標準時參考值，則可以使用任何格式的時間值並將最高有效位設定為 1 以指示這是一個非標準時間值。

3.6 地址掩碼請求

地址掩碼請求 報文是主機為了得到一個合適的子網掩碼而傳送到路由器的 ICMP 請求報文。

接收到此請求報文的機器應當傳送一個地址掩碼回答報文給源站。

其中:

型別（Type） 必須設定為 17

程式碼（Code） 必須設定為 0

地址掩碼（Address mask） 可以為 0

由於 ICMP 地址掩碼請求可能會被用於嗅探攻擊來收集特定網路的資訊，因此該報文預設情況下被 Cisco IOS 停用。

3.7 地址掩碼回答

地址掩碼回答 報文攜帶有地址掩碼資訊，用於回答地址掩碼請求報文。

其中:

型別（Type） 必須設定為 18

程式碼（Code） 必須設定為 0

地址掩碼（Address mask） 為待回答的地址掩碼

3.8 源站不可達

源站不可達 報文是由主機或入站閘道器用於通知客戶端出於目的站無法連線的報文。這些原因可能包括：物理連線失效（也即網路距離無限大），或指定的地址或埠處於非啟用狀態，或者資料報長度過長而導致必須分片但是 IP 首部指定了 “不分片” 選項導致無法分片。如果是 TCP 埠不可達，則會返回 TCP RST，而不會返回此報文。如果是 IP 多播的情況，也不會返回此報文。

其中:

型別（Type） 必須設定為 3

程式碼（Code） 欄位用於指示具體導致源站不可達的原因。見下表。

Next-hop MTU 當需要分片但是 DF (Do not Fragment) 置位的錯誤發生時，包含了下一跳網路的 MTU 的值。

IP header 用於源站根據收到的源站不可達報文來確定具體哪個資料報引起了源站不可達錯誤。