可能是目前最全的講 ICMP 的文章了
對于 ICMP 協議,你想知道的,可能包括以下幾點:
- ICMP 是啥
- 為啥需要 ICMP
- ICMP 有哪些報文類型
- ICMP 報文格式長啥樣
- 有哪些命令用了 ICMP
- ICMP 有哪些內核參數
- ICMP 的問題
帶著這些問題,下面我們就來一一解答。
1. ICMP 是啥
ICMP,全稱是 Internet Control Message Protocol,即互聯網控制報文協議,所謂控制,就是通過下發指令來感知和控制網絡環境,所以它一定是配合一個無法感知網絡環境的協議來工作的,這個協議就是 IP(包括 IPv4 和 IPv6)。
所以,ICMP 通常被認為是 IP 協議的一部分,它封裝在 IP 層中,使用 IP 協議進行傳輸。因此,嚴格來說,ICMP 既不是一個網絡層協議,也不是一個傳輸層協議,而是介于兩者之間的一個協議。
它的主要功能是傳輸網絡診斷信息,信息主要包括兩類:
- 一類是 查詢類報文 :主要用于信息的查詢和采集,比如采集傳輸路徑上的每個路由器都是誰,本次傳輸的報文是否達到目的地等等。
- 另一類是 差錯診斷類報文 :主要用于診斷網絡故障,比如傳輸報文被丟棄的原因是什么等等。
2. 為啥需要 ICMP
我們都知道,IP 協議是一個不可靠協議,如果 IP 包在傳輸過程中出現錯誤,比如 checksum 對不上,擁塞,超時等等,那么 IP 包是會直接被丟棄的,之后也不會有進一步的努力來修正。
這是 IP 協議的一個設計準則決定的,也就是 best effort,盡力而為,這樣的好處是讓 IP 協議盡量保持簡單的形態,只負責有效率的數據傳輸,而更多的質量控制交給高層的協議去處理(比如 TCP)。
但高層能提供質量控制的協議畢竟在少數,所以就需要在下層有協議來輔助 IP 完成必要的網絡質量管理。ICMP 協議自然就被提出來了。
通過 ICMP 協議,當 IP 包發生錯誤的時候,上層發送 IP 包的主機或路由器并不知道下層發生了錯誤,這個時候,下層的主機或路由器就可以通過發送 ICMP 包,將錯誤信息匯報給上層,從而讓上層的主機或路由器進行調整。
不過需要注意的是,ICMP 僅僅只能提供某些特定類型的錯誤信息匯報,并不能幫助 IP 協議成為可靠的協議。它能做的事還是有限,但用于基本的網絡質量管理是足夠了。
3. ICMP 報文格式長啥樣
如下圖所示,ICMP 報文是被封裝在 IP 數據報中傳輸的。
IP 報頭中的 Protocol 字段為 1 即表示該報文攜帶的是 ICMP 報文。(此處只是為了說明問題,因此 IP 報頭是簡化了的)
進一步看,ICMP 報頭為 4 個字節:
- 類型 type:占 1 個字節,表示較大范圍類型分類的 ICMP 報文
- 代碼 code:占 1 個字節,表示較小范圍類型分類的 ICMP 報文(type的細分)
- 校驗和 checksum:占 2 個字節,ICMP checksum 的計算方法類似于 IP checksum,但是不同的是 IP 只校驗頭部,ICMP 校驗頭部+數據部分
后面緊接的 ICMP 數據部分,根據前面的類型和代碼字段的不同,具有不同的內容。
4. ICMP 有哪些報文類型
ICMP 支持的報文類型非常多,詳細看下表:
類型字段指代了一大類,代碼字段又細分了幾大小類。
上面可能不夠明確,我們通過下面這兩張表來列舉一下,由于類型太多了,而且有些平時非常少見,因此,這里我們只列舉常見的一些類型。
第一張表:類型表
注:R表示查詢報文,E表示差錯報文
進一步,對于每種類型,又可以根據代碼字段細分多種子類型,請看第二張表:
第二張表:類型細分表
通過這兩張表,每一種類型的 ICMP 包的意思應該都比較清楚了。
有一種可能不太好理解,這里再重點講解一下:
(1) 源端抑制
屬于差錯信息。如果某個源主機向目的主機快速地發送數據包,但目的主機來不及處理,就會向源主機發出該類型的 ICMP 包,提醒源主機放慢發送速度。
(2) 重定向
屬于差錯信息。如果某個源主機向網絡中發送一個 IP 包,路徑中某個路由器收到這個 IP 包,對照其路由表,發現自己不應該接收該包(包需要原路返回,或者不是最佳路由路徑),就會向源主機發送該類型的 ICMP 包,提醒源主機修改自己的路由表,下次路由到另外一個更好的路由器。
(3) 需要分片但設置了不分片位
屬于差錯信息。如果某個源主機在發送一個 IP 包之前,對該 IP 包中的首部字段 DF 位設為 1,也就是“分片禁止位=1”,表示該包在傳輸的過程中不允許分片,但是中間某個路由器允許傳輸的最大路徑 MTU 小于該包大小,需要分片才能傳輸,但是由于設置不分片位,路由器會將該包丟棄,并向源主機發送一個攜帶 MTU 信息的 ICMP 包,提醒源主機下次發包的大小不應超過該 MTU 的值。
這種類型的 ICMP 包通常用來發現傳輸路徑上的 MTU 值。
(4) TTL超時
屬于差錯信息。超時定義了數據包在網絡中存活的最長時間,IPv4 中的 TTL 字段和 IPv6 中的 Hop Limit 字段都表示了這層意思,它們是一個整數值,會隨著經過的路由器而遞減,當減為 0 時,就認為該 IP 包超時,然后當前減為 0 的路由器會向源主機發送 ICMP 包,通知它發生了超時錯誤。
5. 有哪些命令體現了 ICMP
ICMP 的這些包的類型,用戶可以充分用來診斷網絡的故障情況。
因此誕生了一些利用 ICMP 協議的網絡診斷工具,其中比較知名的就是 ping 和 traceroute。這兩工具分別利用兩種類型的 ICMP 報文:
- ping 使用查詢類型報文
- traceroute 使用差錯類型報文
(1) ping
ping 使用了查詢報文中的請求報文(類型為 8)和應答報文(類型為 0),主要查詢某個網絡節點的連通性,如果出現網絡不連通的情況,具體是什么問題,會在應答報文中附帶相關的差錯信息予以告知。比如網絡不可達(Network Unreacheable)、主機不可達(Host Unreachable)等等,然后用戶就可以根據這些信息來分析具體是哪個環節出現問題。
下面一張圖,顯示了一個 ping 包的完整流程:
可以看到,通過各層協議棧的層層封裝和解封裝,一個 ping 包從一臺主機發送到另一臺主機,包括請求包和應答包。其中,如果目標 MAC 地址未知的話,需要先發出 ARP 請求拿到,然后再進行封裝。
關于 ping 命令的使用案例可以參考這篇文章:ping容易忽略的10點用法和排查問題技巧。
(2) traceroute
traceroute 是類 Linux 系統自帶的工具,Windows 上類似的工具是 tracert,兩者有些許不同,tracert 默認使用 ICMP 報文探測,而 traceroute 默認使用 UDP,但是也可以使用 TCP/ICMP 三種報文探測。
traceroute 利用 ICMP 差錯報文,主要用來確定這幾件事:
- 確定通信雙方路徑上經過的路由器設備
- 確定 UDP 包是否成功達到目的地
- 發現路徑 MTU
確定通信雙方路徑上經過的路由器設備 。就是利用上面提到的超時類型的 ICMP 報文來實現。traceroute 向目的地發送 IP 包,剛開始的時候,將 TTL 設置為 1,當經過第一個路由器時,TTL -1 = 0 引發超時錯誤,第一個路由器回復 ICMP 超時報文,源主機就可以知道路徑第一個路由器的信息,隨后 TTL 被設置為 2、3、4, ...,直到到達目的地,這樣,沿途每個路由器都會向源主機回復 ICMP 超時報文,traceroute 就可以拿到所有的路由器信息了。
不過這里要 注意 ,并不是所有路由器都會返回 ICMP 報文,因為出于安全性考慮,大多數防火墻以及啟用了防火墻功能的路由器都默認配置為不返回任何 ICMP 報文,管理員也會主動配置,所以這時使用 traceroute 就不一定能拿到所有路由器信息了。
確定 UDP 包是否成功達到目的地 。使用上面的方法能拿到路由器信息,但并不能確定發的包是否到達目的地。traceroute 通過發送 UDP 包來解決了這個問題,因為 UDP 包的可用端口號范圍 <3000,所以就可以在發送 UDP 包的時候填入一個 >3000 的端口號,這樣,如果當包確實到達了目的地,由于端口不匹配,就會返回一個端口不可達的 ICMP 報文,源主機就可以確定包確實到了目的地了。
發現路徑 MTU 。這塊在上面講 “需要分片但設置了不分片位” 類型報文的時候已經講過,traceroute 就是利用這種類型報文來逐一地確認傳輸路徑上各個路由器之間的 MTU 值。
關于 traceroute 命令的使用案例可以參考這篇文章:排查網絡問題,請務必掌握這款工具。
(3) MTR
MTR 全稱 my traceroute,相對以上兩個其實是更好的網絡排障工具,只是用的人不多,導致它不太出名。之所以說它好,是因為它結合了 ping 、nslookup、traceroute 三款工具的特性。
關于 MTR 的安裝和使用分析詳見這篇文章:這款網絡排查工具,堪稱神器!
(4) tcptraceroute
這塊工具從名稱就可以看出,是基于 TCP 的 traceroute,也就是它使用 TCP 包(具體是 TCP 的 SYN 包)來進行網絡探測,而不是 ICMP 包。
從上面我們已經知道,traceroute -T 就是使用 TCP 包進行探測,所以 tcptraceroute 其實等效于 traceroute -T 。
使用 TCP 包進行探測的原因,主要是因為現代廣泛使用的防火墻,出于安全的考慮,都會攔截 UDP 包和 ICMP 包,而通常不會攔截 TCP SYN 包。所以使用 TCP 包探測能夠通過大多數的網絡設備,使探測結果更加精確。
6. ICMP 有哪些內核參數
總結了下面一幅圖,其中比較常用的是 net.ipv4.icmp_echo_ignore_all,這是禁 ping 的一個參數,禁 ping 有幾種方法,可以參考這篇文章:Linux禁止ping以及開啟ping的方法。
其他的參數大家有興趣也可以看看,遇到不懂的直接查這個圖即可。
7. ICMP 的問題
ICMP 協議是 IP 協議的助手,能夠為 IP 協議提供相關的故障診斷和控制信息,但 ICMP 仍然不能為 IP 提供可靠性,最常見的丟包(路由器緩沖區溢出)并不會觸發任何的 ICMP 信息,只能由其他協議如 TCP 來處理這種情況。
此外,正因為 ICMP 能夠查詢網絡設備相關的配置信息,并且使用簡單,黑客們都比較青睞使用 ICMP 報文來構建攻擊報文。所以很多的網絡設備都會用防火墻來阻止 ICMP 報文,這讓很多診斷工具,比如上面介紹的幾種,都很難發揮用武之地。
常見的 ICMP 攻擊是 ICMP 泛洪攻擊,這是一種 DDoS 攻擊。簡單說就是攻擊者向一個子網的的廣播地址發送多個 ICMP echo 包,包的源地址偽裝成他想要攻擊的目的主機的 IP,然后該子網的所有主機的 ICMP reply 包都會送到被攻擊主機,該主機瞬時收到大量的 ICMP 回復包,消耗大量資源,來不及處理,便會進入癱瘓或無法提供正常服務。
解決 ICMP 泛洪攻擊最簡單的方法就是禁 ping 了。只要禁 ping,不管黑客有多少肉機,他都無可奈何了。