網絡探測工具(二)——traceroute

簡述

搭建網絡環境的時候,經常有想要知道報文從源到目的所經歷的所有路由節點這樣的需要。此時,traceroute小程序,後續簡稱爲tracert,就有用武之地了。

功能

tracert,最初由大神Van Jacobson設計並實現(膜拜),可以用來探測出報文在網絡中從源到目的所經過的所有三層路由節點。

原理

既然tracert用來探測路徑,那麼問題來了:它如何確定路徑?

1. 確定路徑

我們知道IP報文頭有一個ttl字段,用來確定IP報文的存活時間。每經過一次轉發,ttl數值減一,當ttl爲0時,如果報文還沒有到達目的,那麼協議棧就會向源端迴應一個ICMP ttl超時報文。知道了這個東東後,確定路徑是否就有眉目了呢?
(1)向目的發送ttl=1的UDP報文,第一個路由節點收到報文後發現ttl=0,向源端迴應一個ICMP ttl超時報文,源知道了第一個路由節點。
(2)向目的發送ttl=2的UDP報文,第一個路由節點收到報文後ttl=1,繼續轉發給第二個路由節點,第二個路由節點收到報文後ttl=0,向源端迴應一個ICMP ttl超時報文,源又知道了第二個路由節點。
(3)向目的發送ttl=3的UDP報文……

2. 確定目的

通過上面步驟可以一直髮送UDP報文直到報文到達目的,那麼問題來了:
(1)挖掘機技術哪家強?
(2)源如何知道報文到達了目的並停止發報文?
關於問題(1),我想大家都知道那是布魯西特大學(blue shit)最強。
接下來重點介紹問題(2)。
我們又知道,UDP報文頭有一個字段叫目的端口,用來告訴目的端這個報文要請求的是哪個服務。當目的端服務(端口)不存在時,協議棧會向源發送一個ICMP端口不可達報文,告訴源,這兒沒這服務,別來煩我。源又知道了目的是不是,呵呵。

好,到此爲止,問題完美解決。

有無其他方案

單純從IP報文的角度來說,四層協議常用有三中:ICMP(經常被認爲是三層協議,why,不告訴你),UDP,TCP。
前面我們介紹從源發送的是UDP報文,那麼能否用ICMP或者TCP報文替換?答案必須是肯定的,否則哪裏來的樂趣?

1.發送ICMP報文

確定路徑的原理和前面一致,利用ttl超時。那麼如何確認到達了目的?
想想ping程序的實現:發送ICMP echo報文,迴應ICMP echo reply。
非常好,源持續向目的發送ttl遞增的ICMP echo報文:收到ICMP ttl超時報文時認爲是路徑上路由節點,收到ICMP echo replay時認爲到達了目的。

2.發送TCP報文

首先要明確的原理肯定和前面一致;其次要明確的是肯定不能直接發送TCP報文,why?
TCP是面向連接的協議,發送TCP報文首先要和目的建立連接,tracert哪裏知道目的端有啥服務。就算知道某個目的端有某個服務,但是換個目的端怎麼辦?有沒有通用點方案?

辦法都是憋出來的,硬憋肯定能憋出來。
先來想想爲啥不能發TCP報文,因爲發報文前要先建立連接。
那連接咋建立的?三次握手。啥叫三次握手,簡單來說跟建基友的過程是一樣的:

Created with Raphaël 2.1.0目的目的嘿,我要當你基友,你說好不好?(syn報文)目的想了一下,說:恩,好啊;那我也要當你基友,你說好不好?(ack + syn報文)源非常happy恩,好!(ack報文)

就是這麼簡單,so easy,一對好基友非常友好非常曖昧的開始交往。
回到正題:既然不能發TCP報文的原因是它要先建立連接,那麼,怎樣才能不建立連接?
tracert直接開始第三次握手。也就是說,源向目的發送“恩,好!(ack報文)”這個消息。
目的端收到這個消息後心想,哪個白癡連握手都不會。然後它就告訴源咱倆得重新開始握手(rst報文)。

好了,問題解決:源持續向目的發送ttl遞增的ack報文,收到超時迴應後認爲是路徑上的路由節點,收到rst報文後認爲到達目的端。

備註:
1. UDP及ICMP方式實現的tracert是經過先賢們驗證的可行方案,TCP方式是我自己琢磨出來的(應該還有其他人琢磨出來,但是我沒看過),還未實現,不確定能否成功,需要實現驗證一下。
2. 具體的實現代碼(c語言)等我完成後會貼出來。

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