為什麼說 ICMP 協定是網路最強輔助

2023-03-27 12:01:33

大家好,我是風箏

輕解網路系列又來了。已有高清 PDF 版本可以離線閱讀了,全冊 65 頁,如果有需要離線版的高清 PDF 可以直接下載

今天咱們說說 ICMP 協定。ICMP 可謂是網路世界中的最強輔助了,IP封包如果在途中遭遇不測的話,全靠 ICMP 來通知,要不然丟掉的IP封包就有如石沉大海,從此杳無音信,傳送方也不知道這個包有沒有傳輸成功,倘若沒有成功,那失敗原因是什麼?這些,全靠 ICMP 協定來通知。

ICMP 全稱網際網路控制報文協定(Internet Cntrol Message Protocol),是網路層的重要協定。

ICMP 是幹啥用的

它到底是用來幹啥的呢?為啥叫控制報文協定,控制的是什麼?

ICMP 分為查詢報文和差錯報文兩大類。查詢報文是我們主動發起的,比如ping命令;而差錯報文是在發生差錯之後要發給源端的,這都是網際網路協定模型約定好的。

ICMP的差錯報文反饋發生在通訊環境中的遇到的各種問題。通過這些資訊,使管理者可以對所發生的問題作出診斷,然後採取適當的措施解決。

ICMP的差錯報文是整個資料傳輸鏈路中非常重要的一個環節。打個比喻,差錯報文就是一個只報告壞訊息的信使,當封包在網路中一路暢通的時候,ICMP 差錯報文就像隱身了一樣,你根本不會知道它的存在,一旦封包在網路中碰到了各種各樣的障礙,這個信使就出來活動了,它的目的只有一個,就是把這個封包遭遇的不測通知給傳送端,但是話術就那麼20多種(對應差錯程式碼)。

比如下面兩個場景,想必你也有點熟悉吧。

  • 當路由器收到一份IP資料包但又不能轉發時,就要傳送一份 ICMP「主機不可達」差錯報文。

  • 當IP資料包應該被傳送到另一個路由器時,收到資料包的路由器就要傳送 ICMP「重定向」差錯報文給IP資料包的傳送端。

ICMP 協定說明

雖然工作在網路層,看上去和 IP 協定是並列的,但是 ICMP 報文要附加 IP 頭,一般被 IP 層或者更高層的協定(例如TCP或UDP)使用。很少有應用程式直接使用 ICMP 協定,除了 pingtraceroute

ICMP 協定格式

ICMP 協定格式和 IP 協定、TCP 協定這些比起來,那還是非常簡單的。

型別

型別欄位佔用 8 位,主要定義報文的大類,比如型別為 3 統一表示的是不可達,而具體原因是什麼則要由程式碼欄位決定。

程式碼

程式碼欄位同樣佔用 8 位,程式碼欄位其實就是型別下的子型別,比如上面說了型別為 3 是不可達,程式碼為 0 表示網路不可達,程式碼為 1 表示主機不可達。

檢驗和

用於錯誤檢查,和 IP 協定的檢驗和的作用一致。

內容

因為型別和程式碼不同,表示產生差錯的原因不同,不同的原因都要有對應的描述,內容這部分就是用來描述產生差錯的原因的。

接下來會舉幾個例子說明。

下面這張圖是 ICMP 的分類,包括查詢報文和差錯報文,需要原始 Excel 的同學可以回覆 ICMP獲取原始檔。

目的不可達差錯報文

目的不可達是網路傳輸中經常遇到的問題,各位在開發的過程中可能也碰到過,尤其是做網路程式設計的時候,經常會碰到,比如連錯IP了,比如埠設定錯了。

通過上表可知,當型別為 3 的時候,都是不可達的錯誤,而程式碼可以從 0 -15,也就是說有16種不可達的具體原因。這種情況下的協定格式是下面這樣的。

型別為 3 ,程式碼 0 - 15。檢驗和後面有 4 個位元組的空間是不使用的,但是必須為0 ,沒理由,就這樣。

前面說到了內容部分是根據型別和程式碼不同而不同的。如果是目的不可達,也就是型別是 3 的情況下,內容分為兩部分,IP首部和原始IP資料包中資料部分的前 8 個位元組。

原始IP資料包中資料部分指的就是TCP或者UDP這些網路層之上的協定,拿 TCP 來說,TCP 是傳輸層的,當 TCP 資料包到達網路層,會加上 IP 首部,變成一個 IP 封包。所以這裡說的資料部分就是 TCP 資料包,但是這個資料包可能很大,所以只用前 8 個位元組就夠了,因為前8個位元組包含的資訊已經足夠用了。

回想一下 TCP 協定的格式,前 8 個位元組就是下圖紅框部分,包含源埠和目的埠以及序號。

例如程式碼為 3 的時候,差錯資訊是埠不可達,那有了 TCP 協定的前8個位元組就能知道導致這個錯誤的原始資料包文中的目的埠是多少,不可達的埠也就是這個埠。也可以知道原始報文的源埠是多少,有了源埠號就知道這個封包是哪個使用者程序發出來的,就可以交給這個程序對這個差錯及時進行處理了。

源埠號是關聯使用者程序的重要標示,比如我們開發了一個應用,這個應用佔用了 8888和8898兩個埠,如果安裝了這個應用的機器收到了一個差錯報文,而差錯報文中的內容部分的原始封包前8個位元組拆解後,發現源埠是8898,那就知道這個要交給我們開發的這個應用去處理了。

下面是一個埠不可達的差錯報文,用 WireSharek 監測到的格式。

telnet 一個沒有開放的埠即可獲得 ICMP 埠不可達的差錯報文。

查詢報文

將 ICMP 用作查詢報文的場景比較少,用作查詢報文的意思就像是使用 ARP 協定或者 TCP 協定這種,是我們主動發起的,只不過選了 ICMP 協定。

比如 pingtraceroute這兩個,之後我們再講,這兩個比較有意思,對 ICMP 應用很巧妙。

另外,可以用作無盤系統啟動過程中來獲取自身的子網掩碼。還可以用作向第三方系統查詢當前的時間戳。

瞭解一下就可以了。

有一些場景不傳送差錯報文

有些場景下是不傳送差錯報文的,這樣做的目的是為了防止ICMP差錯報文帶來廣播風暴。

  1. ICMP差錯報文字身發生差錯,是不會對差錯報文再傳送差錯報文的。是不是讀起來有點繞,TCP 、UDP 出錯會傳送差錯報文,但是 ICMP差錯報文在通知源端的過程出錯了,那就不管了,要不然可能就沒玩沒了的發了,比如源端的網線斷了。但是, ICMP查詢報文可能會產生ICMP差錯報文,比如ping命令在傳輸過程中出錯了,源端會收到差錯報文。

  2. 目的地址是廣播地址或多播地址(D類地址)的IP資料包,不傳送差錯報文。

  3. 作為鏈路層廣播的資料包,不傳送差錯報文,ARP 就是典型的鏈路層廣播資料包。

  4. 不是IP分片的第一片,不傳送差錯報文。資料如果過長,網路層是會進行分片的,這些分片實際上還是同一個封包的,這種情況下只對第一片傳送差錯報文,其他分片不管。

  5. 源地址不是單個主機的資料包,不傳送差錯報文。 源地址不能為零地址、環回地址、廣播地址或多播地址。

總結

1、 ICMP 在網路層,但要加上 IP 首部;

2、ICMP 分為查詢報文和差錯報文,主要用到的還是差錯報文;

3、ICMP 的差錯報文就好像一個只通知壞訊息的資訊,當資料包在網路中出現問題的時候,及時告知源端,告知的內容包括原因以及產生錯誤的原始資料包的必要部分;

4、有一些情況是不會傳送 ICMP 差錯報文的,這樣做是為了防止網路風暴;


如果覺得還不錯的話,給個推薦吧!

公眾號「古時的風箏」,Java 開發者,專注 Java 及周邊生態。堅持原創乾貨輸出,你可選擇現在就關注我,或者看看歷史文章再關注也不遲。長按二維條碼關注,跟我一起變優秀!