1 ICMP協(xié)議概述
ICMP(Internet Control Message Protocol)協(xié)議是因特網(wǎng)控制報文協(xié)議,ICMP常被認為是網(wǎng)絡(luò)層協(xié)議,它的報文存在于IP數(shù)據(jù)報的數(shù)據(jù)部分,如圖接奈。
因為ICMP是基于IP數(shù)據(jù)報的网棍,所以跟TCP不同的是师骗,它是不需要指定端口的历等,更沒有建立連接一說。而且辟癌,通常來說ICMP協(xié)議都是內(nèi)核幫你實現(xiàn)的寒屯,系統(tǒng)自身就支持了,并不像TCP/HTTP等還要自己開個服務監(jiān)聽對應端口啥的黍少。 可能有人會有疑問了寡夹,既然沒有端口來標識了,那我有時候開多個ping進程厂置,這些響應消息是怎么對應到不同的ping進程的菩掏? 這個就是ICMP報文里面的標識符的作用了。標識符會在響應中帶回來昵济,這樣發(fā)送方就能根據(jù)標識符將請求和應答匹配了智绸。在ping中,這個標識符就是進程ID访忿。
ICMP報文有多種類型瞧栗,如地址掩碼請求和應答、時間戳請求和應答海铆、請求回顯和回顯應答等迹恐。ICMP報文通用格式如下,不同類型的報文內(nèi)容有所不同游添。ICMP協(xié)議在 ping系草,traceroute等工具中有典型應用通熄,下面都分析一下唆涝。
2 Ping 原理分析
ping使用的是 ICMP 的請求回顯/回顯應答類型的報文,格式如下唇辨。它的內(nèi)容包括標識符廊酣、序列號以及回顯數(shù)據(jù)3部分,報文大小默認為 64 字節(jié)(header的8字節(jié)+body的56字節(jié))赏枚。
- 請求回顯類型是8亡驰,回顯應答類型是0,他們代碼都是 0饿幅,校驗和是包內(nèi)容根據(jù)算法生成用于校驗數(shù)據(jù)完整性凡辱。
- 標識符在 Linux/macOS 中用的是進程ID。
- 序列號在 Linux/macOS 中是從0遞增的栗恩,每個進程獨立的透乾。
- 回顯數(shù)據(jù)包括發(fā)送ping請求的時間戳(在macOS占8字節(jié),在Linux占16字節(jié)),以及一串填充數(shù)據(jù)乳乌,在Linux這串數(shù)字默認是0x10...37捧韵,共40字節(jié)。在macOS中是0x08090a...37汉操,共48字節(jié)再来。填充數(shù)據(jù)你也可以通過
-p pattern
指定,比如ping -pff 192.168.33.10
磷瘤,則填充數(shù)據(jù)全部是 ff芒篷。 - 默認TTL是64,你可以通過
-t ttl
指定TTL值膀斋。 - ping請求時間 = 接收到回顯應答的時間 - 應答回顯數(shù)據(jù)中的時間
實例分析
在測試機ping我的虛擬機 ping -c2 192.168.33.10
梭伐,192.168.33.10是我測試用的虛擬機IP,wireshark抓包如下:
可以驗證前面的分析仰担。第2對請求和應答跟第一對類似糊识,只是序列號,校驗和等不同罷了摔蓝。
關(guān)于校驗和
ICMP報文頭部中的校驗和生成/校驗方式也比較簡單赂苗。
- 生成:先將校驗和置為0,然后將ICMP報文的header+body按16bit分組求和贮尉。如果結(jié)果溢出拌滋,則將高16位和低16位求和,直到高16位為0猜谚。最后求反就是檢驗和的值败砂。
- 校驗:將報文的header+body按16bit分組求和(包括校驗和字段),看看結(jié)果是否全是1魏铅,如果不是昌犹,則校驗失敗。
如何自己寫一個ping览芳?可以參考下這位朋友的ping工具的 python實現(xiàn)斜姥。 Lingerhk: icmp_ping_tool.py
3 Traceroute 原理分析
traceroute 用于查看IP數(shù)據(jù)報從一臺主機傳到另一臺主機所經(jīng)過的路由。其實沧竟,在IP數(shù)據(jù)報的頭部的選項字段有一個 IP記錄路由選項(RR)铸敏,它也可以記錄路由。為什么不直接用它而是另外弄出個traceroute工具悟泵,這是因為:
- 1)IP首部長度限制杈笔,導致記錄的IP地址最多9個 ,遠遠不夠糕非。
- 2)并不是所有路由器都支持記錄路由選項蒙具,因此某些路徑無法使用敦第。
traceroute 用到ICMP協(xié)議和TTL字段。TTL字段是數(shù)據(jù)報的生存周期店量,初始值通常默認是64芜果,每個處理數(shù)據(jù)報的路由器都需要把TTL值減去1或者數(shù)據(jù)報在路由器停留的秒數(shù)(因為絕大多數(shù)路由器轉(zhuǎn)發(fā)數(shù)據(jù)報時延都小于1秒,因此通常都是減去1融师,而且很多路由器的實現(xiàn)即便超過1秒也是減去1右钾,因此可以把TTL看做一個跳站計數(shù)器)。路由器接收到一份IP數(shù)據(jù)報時旱爆,如果TTL為0或者1舀射,則路由器不轉(zhuǎn)發(fā)該數(shù)據(jù)報,而是丟棄并給源機器發(fā)送一份ICMP超時報文怀伦,而ICMP信息中的IP報文中源地址正是路由器的IP地址脆烟。
traceroute的原理就是:
- 先發(fā)送一份TTL為1的報文,這樣第一個路由器會將TTL減1然后丟棄該報文房待,并發(fā)回一個ICMP超時報文邢羔,這樣就得到了第一個路由器的IP地址;接著發(fā)送一個TTL為2的報文桑孩,可以得到第二個路由器的IP地址拜鹤;繼續(xù)該過程直到目的主機。
- 但是目的主機即便收到TTL為1的報文流椒,它也不會丟棄該數(shù)據(jù)報并發(fā)回一份ICMP超時報文敏簿,因為此時數(shù)據(jù)報已經(jīng)到了目的地。為了判斷是否到達目的主機宣虾,traceroute發(fā)送的報文采用了UDP數(shù)據(jù)報惯裕,它選擇一個很大的端口值如30000以上的,以保證沒有其他應用程序使用該端口绣硝,然后目的主機會返回一個端口不可達的ICMP報文蜻势,這樣就可以知道什么時候結(jié)束。
- traceroute針對每個TTL會發(fā)3次UDP報文域那,并打印每次的往返時間咙边。如果5秒內(nèi)沒有收到3次報文中任何一個的響應次员,則打印*號繼續(xù)下一個TLL的報文發(fā)送。3次報文選擇的UDP目的端口分別是 33435王带,33436淑蔚,33437,UDP報文數(shù)據(jù)長度為24字節(jié)愕撰,內(nèi)容為全0(macOS環(huán)境)刹衫。
實例分析
運行 traceroute 119.75.217.109
醋寝,可以看到wireshark抓包的前幾跳信息,TTL最開始是1带迟,然后是2...音羞,端口是33435到33437,每個TTL發(fā)3次報文仓犬,在沒有達到目的主機前嗅绰,返回的是ICMP超時報文。到達主機后搀继,則會返回ICMP端口不可達報文窘面。
由于IP路由通常都是動態(tài)的,每個路由器都要判斷數(shù)據(jù)報接下來要轉(zhuǎn)發(fā)到哪個路由器叽躯,應用程序?qū)β酚刹呗圆⒉豢刂撇票摺6鴗raceroute程序的IP源站選路選項(-g gateway
)可以實現(xiàn)發(fā)送者指定路由,比如指定必須經(jīng)過哪些路由IP点骑,這里就不展開了酣难。有興趣的可以參見 《TCP/IP詳解 卷1:協(xié)議》的第8章。
參考資料
- 《TCP/IP詳解 卷1:協(xié)議》第6黑滴、7鲸鹦、8章
- https://zh.scribd.com/doc/7074846/ICMP-and-Checksum-Calc(注:本文中引用的ICMP報文結(jié)構(gòu)圖都來自這里)
- https://linux.die.net/man/8/ping
- https://github.com/Lingerhk/hacking_script/blob/master/net_attacking/icmp_ping_tool.py