1. 程式人生 > >CCNA - Part7:網路層 - ICMP 應該是你最熟悉的協議了

CCNA - Part7:網路層 - ICMP 應該是你最熟悉的協議了

## ICMP 協議 在之前[網路層](https://www.cnblogs.com/michael9/p/13259415.html)的介紹中,我們知道 IP 提供一種無連線的、盡力而為的服務。這就意味著無法進行流量控制與差錯控制。因此在 IP 資料報的傳輸過程中,出現各種的錯誤是在所難免的,為了通知源主機 IP 資料報傳輸過程中遇到的問題,因此設計了因特網控制報文協議(ICMP)。 雖然說 ICMP 協議將 IP 協議封裝在內部,所以大多數人將 ICMP 視為傳輸層的協議,但實際上 ICMP 是 IP 協議的重要組成部分,所以將其放在網路層更為合適。 ICMP 的報文一般有兩種,**查詢報文和查詢報文**。 查詢報文:例如我們在使用 ping 命令,子網掩碼查詢,時間戳查詢等情況時,都會發送查詢報文。 差錯報文:而差錯報文是在當對應的路由器或者終端裝置收到查詢報文後,產生了一系列問題。把出現的問題,回覆給發起者的報文就是差錯報文。 但考慮到整體網路資源的佔用上,在如下情況下,是不會產生差錯報文的: 1. 差錯報文不會產生差錯報文 - 防止 ICMP 無限產生和傳送差錯報文 2. 目的地址是廣播或多播的 IP 資料包 3. 鏈路層廣播的資料包 4. 不是 IP 分片的第一片 - IP 是盡力而為,自然不需要可靠性 5. 源地址不是某個主機的資料包 ## ICMP 型別 由於 ICMP 本身就是為了彌補 IP 協議不可靠的特性,起到排錯目的,所以它的 Header 並不複雜。 ![](https://img2020.cnblogs.com/blog/1861307/202007/1861307-20200716154246570-423249339.png) 正如圖中所示的,對於 ICMP Header 來說,比較重要的就是 Type (8 bit)和 Code (8 bit) 欄位,用來表示各種錯誤的情況。 其中完整的介紹可以參考這篇 [wiki](https://en.wikipedia.org/wiki/Internet_Control_Message_Protocol),下面就介紹上常用的部分。 | Type | code | Description | | ---- | ---- | --------------------------------------- | | 0 | 0 | Echo 回覆報文,如 Ping 命令的回覆報文。 | | 3 | 0 | 網路不可達 | | 3 | 1 | 主機不可達 | | 3 | 3 | 協議不可達 | | 3 | 4 | 埠不可達 | | 3 | 6 | 網路不知道 | | 3 | 7 | 主機不知道 | | 8 | 0 | Echo 請求報文,如 Ping 命令的請求報文。 | | 13 | 0 | 時間戳請求報文 | 下面我們抓個包,來看一下。 ## Ping 命令測試網路連通性 這裡在主機上 Ping 下百度,通過 Wireshark 抓到的資料包如下: ![](https://img2020.cnblogs.com/blog/1861307/202007/1861307-20200716154305316-182990929.png) 先看一下 Echo Request 包,對應 Type 為8,Code 為0: ![](https://img2020.cnblogs.com/blog/1861307/202007/1861307-20200716154326528-2044007199.png) Echo Reply 包 - Type 為 0,Code 為 0: ![](https://img2020.cnblogs.com/blog/1861307/202007/1861307-20200716154352939-1508390630.png) ## Traceroute 測試網路連通性 在 IP 協議中,為了防止出現環路而設定了 TTL 欄位。該欄位也在 traceroute 中起到了很大的作用,通過設定 TTL 的數值,來獲取資料報的傳遞過程。 > TTL:當 IP 資料包進行傳送時,每經過一個路由器,TTL 指就會減一,當 TTL = 0 時,該 IP 資料報會被丟棄。 下面就來了解下 Traceroute 的通訊過程,用到的拓撲如下: ![](https://img2020.cnblogs.com/blog/1861307/202007/1861307-20200716154446428-1213309980.png) 當主機收到目的主機的 IP 後,會給目的主機發送一個 TTL = 1 的 UDP 資料包。 ![](https://img2020.cnblogs.com/blog/1861307/202007/1861307-20200716154546663-1381852438.png) 而經過第一個路由器後,TTL - 1 變成 0.這時路由器會把資料報丟棄,然後把丟棄的資料包的 IP 頭部封裝起來,回覆主機一個差錯報文。如下: ![](https://img2020.cnblogs.com/blog/1861307/202007/1861307-20200716154610905-797631083.png) 這個過程主機會發三次,也就是說會產生 3 個 TTL =1 的 UDP,如下 ![](https://img2020.cnblogs.com/blog/1861307/202007/1861307-20200716154641368-1512477808.png) 接著會在再次傳送 3 個 TTL = 2 的 UDP 報文,如下 ![](https://img2020.cnblogs.com/blog/1861307/202007/1861307-20200716154722014-1930170604.png) 第二個路由器,會再次向主機發送一個差錯報文,如下: ![](https://img2020.cnblogs.com/blog/1861307/202007/1861307-20200716154756786-1822648394.png) 這裡需要注意的:**由於第二臺路由器已經相當於是目的地,所以將資料包拆到傳輸層,但由於傳輸層上的埠標識了應用層的應用,而在該路由器上不在該應用,進而回復了埠不可達的報文。** 由於圖中只經過 2 個路由器,所以截止傳送到 TTL = 2 ![](https://img2020.cnblogs.com/blog/1861307/202007/1861307-20200716154820935-136147950.png) **並且我們可以從 TTL = 2 的回覆差錯報文看出,只有兩個差錯報文。其中有個差錯報文出現了丟失,並且沒有給主機回覆差錯報文丟失的