TCP/IP協議筆記5-ICMP協議及其應用 1 ICMP協議概述 2 Ping 原理分析 3 Traceroute 原理分析 參考資料

1 ICMP協議概述

ICMP(Internet Control Message Protocol)協議是因特網控制報文協議,ICMP常被認爲是網絡層協議,它的報文存在於IP數據報的數據部分,如圖。

因爲ICMP是基於IP數據報的,所以跟TCP不同的是,它是不需要指定端口的,更沒有建立連接一說。而且,通常來說ICMP協議都是內核幫你實現的,系統自身就支持了,並不像TCP/HTTP等還要自己開個服務監聽對應端口啥的。 可能有人會有疑問了,既然沒有端口來標識了,那我有時候開多個ping進程,這些響應消息是怎麼對應到不同的ping進程的? 這個就是ICMP報文裏面的標識符的作用了。標識符會在響應中帶回來,這樣發送方就能根據標識符將請求和應答匹配了。在ping中,這個標識符就是進程ID。

ICMP報文有多種類型,如地址掩碼請求和應答、時間戳請求和應答、請求回顯和回顯應答等。ICMP報文通用格式如下,不同類型的報文內容有所不同。ICMP協議在 ping,traceroute等工具中有典型應用,下面都分析一下。

2 Ping 原理分析

ping使用的是 ICMP 的請求回顯/回顯應答類型的報文,格式如下。它的內容包括標識符、序列號以及回顯數據3部分,報文大小默認爲 64 字節(header的8字節+body的56字節)。

  • 請求回顯類型是8,回顯應答類型是0,他們代碼都是 0,校驗和是包內容根據算法生成用於校驗數據完整性。
  • 標識符在 Linux/macOS 中用的是進程ID。
  • 序列號在 Linux/macOS 中是從0遞增的,每個進程獨立的。
  • 回顯數據包括髮送ping請求的時間戳(在macOS佔8字節,在Linux佔16字節),以及一串填充數據,在Linux這串數字默認是0x10...37,共40字節。在macOS中是0x08090a...37,共48字節。填充數據你也可以通過 -p pattern指定,比如 ping -pff 192.168.33.10,則填充數據全部是 ff。
  • 默認TTL是64,你可以通過 -t ttl 指定TTL值。
  • ping請求時間 = 接收到回顯應答的時間 - 應答回顯數據中的時間

實例分析

在測試機ping我的虛擬機 ping -c2 192.168.33.10,192.168.33.10是我測試用的虛擬機IP,wireshark抓包如下:

可以驗證前面的分析。第2對請求和應答跟第一對類似,只是序列號,校驗和等不同罷了。

關於校驗和

ICMP報文頭部中的校驗和生成/校驗方式也比較簡單。

  • 生成:先將校驗和置爲0,然後將ICMP報文的header+body按16bit分組求和。如果結果溢出,則將高16位和低16位求和,直到高16位爲0。最後求反就是檢驗和的值。
  • 校驗:將報文的header+body按16bit分組求和(包括校驗和字段),看看結果是否全是1,如果不是,則校驗失敗。

如何自己寫一個ping?可以參考下這位朋友的ping工具的 python實現。 Lingerhk: icmp_ping_tool.py

3 Traceroute 原理分析

traceroute 用於查看IP數據報從一臺主機傳到另一臺主機所經過的路由。其實,在IP數據報的頭部的選項字段有一個 IP記錄路由選項(RR),它也可以記錄路由。爲什麼不直接用它而是另外弄出個traceroute工具,這是因爲:

  • 1)IP首部長度限制,導致記錄的IP地址最多9個 ,遠遠不夠。
  • 2)並不是所有路由器都支持記錄路由選項,因此某些路徑無法使用。

traceroute 用到ICMP協議和TTL字段。TTL字段是數據報的生存週期,初始值通常默認是64,每個處理數據報的路由器都需要把TTL值減去1或者數據報在路由器停留的秒數(因爲絕大多數路由器轉發數據報時延都小於1秒,因此通常都是減去1,而且很多路由器的實現即便超過1秒也是減去1,因此可以把TTL看做一個跳站計數器)。路由器接收到一份IP數據報時,如果TTL爲0或者1,則路由器不轉發該數據報,而是丟棄並給源機器發送一份ICMP超時報文,而ICMP信息中的IP報文中源地址正是路由器的IP地址。

traceroute的原理就是:

  • 先發送一份TTL爲1的報文,這樣第一個路由器會將TTL減1然後丟棄該報文,併發回一個ICMP超時報文,這樣就得到了第一個路由器的IP地址;接着發送一個TTL爲2的報文,可以得到第二個路由器的IP地址;繼續該過程直到目的主機。
  • 但是目的主機即便收到TTL爲1的報文,它也不會丟棄該數據報併發回一份ICMP超時報文,因爲此時數據報已經到了目的地。爲了判斷是否到達目的主機,traceroute發送的報文采用了UDP數據報,它選擇一個很大的端口值如30000以上的,以保證沒有其他應用程序使用該端口,然後目的主機會返回一個端口不可達的ICMP報文,這樣就可以知道什麼時候結束。
  • traceroute針對每個TTL會發3次UDP報文,並打印每次的往返時間。如果5秒內沒有收到3次報文中任何一個的響應,則打印*號繼續下一個TLL的報文發送。3次報文選擇的UDP目的端口分別是 33435,33436,33437,UDP報文數據長度爲24字節,內容爲全0(macOS環境)。

實例分析

運行 traceroute 119.75.217.109,可以看到wireshark抓包的前幾跳信息,TTL最開始是1,然後是2...,端口是33435到33437,每個TTL發3次報文,在沒有達到目的主機前,返回的是ICMP超時報文。到達主機後,則會返回ICMP端口不可達報文。

由於IP路由通常都是動態的,每個路由器都要判斷數據報接下來要轉發到哪個路由器,應用程序對路由策略並不控制。而traceroute程序的IP源站選路選項(-g gateway)可以實現發送者指定路由,比如指定必須經過哪些路由IP,這裏就不展開了。有興趣的可以參見 《TCP/IP詳解 卷1:協議》的第8章。

參考資料

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章