1. 程式人生 > >網路協議 5 - ICMP 與 ping:投石問路的偵察兵

網路協議 5 - ICMP 與 ping:投石問路的偵察兵

    日常開發中,我們經常會碰到查詢網路是否暢通以及域名對應 IP 地址等小需求,這時候用的最多的應該就是 ping 命令了。 那你知道 ping 命令是怎麼工作的嗎?今天,我們就來一起認識下 ping 命令及其對應的 ICMP 協議。

ICMP 協議

    ICMP 全稱 Internet Control Message Protocol,指網際網路控制報文協議

    網路本身是不可靠的,資料包在傳輸過程中,可能會發生很多突發事件並導致資料傳輸失敗。而網路層的 IP 協議是一個無連線的協議,它不會處理網路層的故障,因此,我們需要其它的協議,在資料包傳輸出現故障時,能將故障資訊傳回來,這樣才能對應處理相關問題。

    就像在電視劇裡看到的古代戰爭一樣,打仗的時候需要通過斥候來傳遞戰局情況,進而更好的控制戰局。而 ICMP 報文在網路世界中就充當“斥候”這樣的角色。

    ICMP 報文是封裝在 IP 包裡面的。因為傳輸指令的時候,肯定需要源地址和目標地址。它本身格式非常簡單,如下圖:

    ICMP 報文有很多的型別,不同的型別有不同的程式碼,最常用的型別是主動請求,程式碼為 8,主動請求的應答,程式碼為 0。從大的方面看可以分為 查詢報文型別差錯報文型別

查詢報文型別

    我們經常在電視劇裡聽到這樣的話:來人,前方戰事如何?斥候回來沒?一有情況,立刻通報。

    類似這種主帥發起,主動檢視敵情的情況,就對應著 ICMP的查詢報文型別

。例如,常見的 ping 命令就是查詢報文,是一種主動請求,並且獲得主動應答的 ICMP 協議。因此,ping 命令發出的包也是符合 ICMP 協議格式的,只不過它在後面增加了自己的格式。

    對 ping 的主動請求,進行網路抓包,稱為 ICMP ECHO REQUEST。同理,主動請求的回覆,稱為ICMP ECHO REPLY。比起原生的 ICMP,這裡面多了兩個欄位,一個是識別符號,另一個是序號。這不難理解,大帥派出去兩隊斥候,一隊是找誰要的,一隊是偵查戰況的,要有個標識才能區分。

    另一方面,派出去的斥候,都要編個號。如果派出去 10 個,回來 10 個,就說明前方戰況不錯。如果派出去 10 個,回來 2 個,就說明情況可能不妙。

    在選項資料中,ping 還會存放傳送請求的時間值,來計算往返時間,說明路程的長短。

差錯報文型別

    差錯報文主要是用來將傳送的出錯報文相關資訊返回到源裝置,以供源裝置確定如果更好的重發失敗的資料包

    還是拿我們的“大帥”舉例。

    當主帥正在大帳中看地圖,思考戰事時,外面的小兵突然喊到:大帥,不好啦,張將軍遭遇埋伏,全軍覆沒了。

    這種是異常情況發起的,來報告發生了不好的事情,對應 ICMP 的差錯報文。

    差錯報文有以下常用的型別:

  • 3:終點不可達
  • 4:源抑制
  • 5:重定向
  • 11:超時

    第一種情況終點不可達。小兵報告,大帥,送給張將軍的糧草沒有送到。

    那大帥肯定會問,為啥沒有送到?這就對應 ICMP 中的以下程式碼了。

  • 網路不可達程式碼:0
  • 主機不可達程式碼:1
  • 協議不可達:2
  • 埠不可達:3
  • 需要進行分片但設定了不分片:4

    具體的場景就像這樣:

  • 網路不可達:大帥,找不到地方
  • 主機不可達:大帥,找到地方,沒找到張將軍
  • 協議不可達:大帥,找到地方,也找到人了,但是口令沒對上。
  • 埠不可達:大帥,找到地方,找到了人,也對上了口令,但事情沒對上。我去送糧草,人家說在等救兵。
  • 需要進行分片但設定不分片:大帥,走到一半,山路狹窄,想換瞎扯,但是出發前你下令嚴禁換小車,就沒辦法送到了。

    第二種是源站抑制。也就是讓源站放慢傳送速度(小兵:大帥,糧草送的太多了吃不完,你可以慢點送)。

    第三種是時間超時。也就是超過網路包的生存時間還是沒到目的地(大帥,送糧草的人都把糧食吃完了,還沒到地方,已經餓死了)。

    第四種是路由重定向。也就是下次發給另一個路由器(大帥,上次送糧草的人本來只要走大王村,一公里就到了,結果非要繞道張家界,多了五公里,下次記得走大王村)。

    差錯報文的結構相對複雜一些。除了前面還是 IP,ICMP 的前 8 個位元組不變,後面則跟上出錯的那個 IP 包的 IP 頭和 IP 正文的前 8 個位元組。

    而且這類斥候特別盡責,不但位元組返回來報信,還把一部分遺物帶回來。

  • 斥候:大帥,張將軍已經戰死沙場,這是他的印信和佩劍。
  • 大帥:張將軍是怎麼死的(可以檢視 ICMP 的前 8 位元組)?沒錯,這是張將軍的劍(IP 資料包的頭及正文前 8 位元組)。

ping:查詢報文型別的使用

    接下來,我們重點來看 ping 命令的傳送和接收過程。

    假定主機 A 的 IP 地址是 192.168.1.1,主機 B 的 IP 地址是 192.168.1.2,它們都在同一個子網。那麼,當在主機 A 上執行“ping 192.168.1.2” 後,會發生什麼呢?

  1. 源主機構建 ICMP 請求資料包。這個資料包內包含多個欄位。最重要的有兩個,一個是型別欄位,對應請求資料包而言,該欄位為 8。另一個是順序號,主要用於區分連續 ping 的時候發出的多個數據包。每發出一個請求資料包,順序號會自動加 1.為了能夠計算往返時間 RTT,它會在報文的資料部分插入傳送時間。
  2. IP 層構建 IP 資料包。ICMP 協議將資料包連同目標 IP 一起交給 IP 層,IP 層將以 192.168.1.2 作為目的地址,本機 IP 地址作為源地址,加上其他控制資訊,構建一個 IP 資料包。
  3. 加入 MAC 頭。找到 192.168.1.2 對應的 MAC 地址,附加上一些控制資訊,依據乙太網的介質訪問規則,將它們傳送出去。

    主機 B 收到資料幀後,會進行如下步驟:

  1. 檢查 MAC 地址,丟棄或接收資料幀,提取 IP 資料包。檢查資料包目的 MAC 地址,並與本機 MAC 地址對比。如符合,就接收資料幀,否則就丟棄。接收後檢查資料幀,將 IP 資料包從幀中提取處理,交給本機的 IP 層。
  2. IP 層檢查IP。檢查完成後,提取有用的資訊交給 ICMP 協議。
  3. 構建 ICMP 應答包。應答資料包的型別欄位為 0,順序號為接收到的請求資料包中的順序號。
  4. 將應答資料包發給主機 A。

    在規定的時間內,源主機如果沒有接到 ICMP 的應答包,則說明目標主機不可達。

    如果接收到了應打包,則說明目標主機可達。此時,源主機會檢測時間延遲。就是用當前時刻減該資料包從源主機發出去的時刻。

    當然,這只是最簡單的,同個區域網的情況。如果跨網段的話,還會涉及閘道器的轉發、路由器的轉發等。

    可以看出,ping 命令是使用了 ICMP 裡面的 ECHO REQUEST 和 ECHO REPLY 型別。

    那其它型別呢?是不是隻有真正遇到錯誤的時候,才能收到?答案是否定的。有一個 Traceroute 命令,它會使用 ICMP 的規則,故意製造一些能夠產生錯誤的場景。

Traceroute:差錯報文型別的使用

    Traceroute 命令有兩個比較常用的功能。

    第一個功能:

    通過設定特殊的 TTL,追蹤去往目的地時經過的路由器

    Traceroute 的引數執行某個目的 IP 地址,會發送一個 UDP 的資料包。

    將 TTL 設定成 1 時,表示這個資料包的 MP 為 1,碰到第一個“攔路虎”(通常是路由器或一個其它型別的關卡)就會陣亡了,然後就會返回一個 ICMP 包,這個包就是 網路差錯包,型別是時間超時

    通過差錯包,我們就能得到資料包到第一個關卡時花費的時間及其每個關卡的 IP 地址(有的主機不會響應 ICMP,所以會出現請求時全是 * 的情況)。

    那怎麼知道 UDP 有沒有到達目的主機呢?Traceroute 程式會發送一份 UDP 資料包給目的主機,但它會選擇一個不可能的值作為 UDP 埠號(大於30000)。當該資料報到達目的主機時,由於找不到對應埠號,所以會返回一個“埠不可達”的錯誤報文。這樣,我們就知道 UDP 是否到達主機了。

    第二個功能:

    設定資料包不分片,確定路徑的 MTU

    傳送分組,並設定“不分片”標誌。傳送的第一個分組的長度正好與出口的 MTU 相等。如果中間遇到窄的關卡就會被卡主,返回 ICMP 網路差錯包,型別是“需要進行分片但設定了不分片”。就這樣,每次收到ICMP“不能分片”差錯時就減小分組的長度,從而確定整個路徑中的 MTU。

總結

  • ICMP 相當於網路世界的偵察兵。常用的有兩種型別,主動探查的查詢報文和異常報告的差錯報文。
  • ping 命令使用查詢報文,Traceroute 命令使用差錯報文。

參考:

  1. 劉超-趣談網路協議系列課;