P2P之UDP穿透NAT的原理與實現 – 增強篇(附修改過的原始碼)(ZZ)

來源:互聯網
上載者:User

P2P之UDP穿透NAT的原理與實現 - 增強篇(附修改過的原始碼)

關鍵詞: P2P UDP NAT 原理 穿透 Traveral Symmetric Cone
原始作者: Hwycheng Leo(FlashBT@Hotmail.com)
源碼下載: http://bbs.hwysoft.com/download/UDP-NAT-LEO.rar
參考:http://midcom-p2p.sourceforge.net/draft-ford-midcom-p2p-01.txt
      P2P之UDP穿透NAT的原理與實現(shootingstars)

文章說明:

關於UDP穿透NAT的中文資料在網路上是很少的,僅有<<P2P之UDP穿透NAT的原理與實現(shootingstars)>>這篇文章有實際的參考價值。本人近兩年來也一直從事P2P方面的開發工作,比較有代表性的是個人開發的BitTorrent下載軟體 - FlashBT(變態快車). 對P2P下載或者P2P的開發感興趣的朋友可以訪問軟體的官方首頁: http://www.hwysoft.com/chs/ 下載看看,說不定有收穫。寫這篇文章的主要目的是懶的再每次單獨回答一些網友的提問, 一次性寫下來, 即節省了自己的時間,也方便了對於P2P的UDP穿透感興趣的網友閱讀和理解。對此有興趣和經驗的朋友可以給我發郵件或者訪問我的個人Blog留言: http://hwycheng.blogchina.com. 您可以自由轉載此篇文章,但是請保留此說明。

再次感謝shootingstars網友的早期貢獻. 表示謝意。

----------------------------------------------------------------------------------------------------------------------------

NAT(The IP Network Address Translator) 的概念和意義是什麼?

NAT, 中文翻譯為網路位址轉譯。具體的詳細資料可以訪問RFC 1631 - http://www.faqs.org/rfcs/rfc1631.html, 這是對於NAT的定義和解釋的最權威的描述。網路術語都是很抽象和艱澀的,除非是專業人士,否則很難從字面中來準確理解NAT的含義。

要想完全明白NAT 的作用,我們必須理解IP地址的兩大分類,一類是私人IP地址,在這裡我們稱作內網IP地址。一類是非私人的IP地址,在這裡我們稱作公網IP地址。關於IP地址的概念和作用的介紹參見我的另一篇文章: http://hwycheng.blogchina.com/2402121.html

內網IP地址: 是指使用A/B/C類中的私人地址, 分配的IP地址在全球不懼有唯一性,也因此無法被其它外網主機直接存取。
公網IP地址: 是指具有全球唯一的IP地址,能夠直接被其它主機訪問的。

NAT 最初的目的是為使用內網IP地址的電腦提供通過少數幾台具有公網的IP地址的電腦訪問外部網路的功能。NAT 負責將某些內網IP地址的電腦向外部網路發出的IP資料包的源IP地址轉換為NAT自己的公網的IP地址,目的IP地址不變, 並將IP資料包轉寄給路由器,最終到達外部的電腦。同時負責將外部的電腦返回的IP資料包的目的IP地址轉換為內網的IP地址,源IP地址不變,並最終送達到內網中的電腦。
                                                
 ----------------------                           ----------------------              
 | 192.168.0.5        |  Internat host            | 192.168.0.6        |  Internat host
 ----------------------                           ----------------------              
         ^ port:2809                                      ^port: 1827                           
         |                                                |                           
         V                                                V                           
 ----------------------                           ----------------------              
 | 192.168.0.1        | NAT device                | 192.168.0.2        | NAT device   
 | 61.51.99.86        |                           | 61.51.77.66        |              
 ----------------------                           ----------------------              
         ^                                                ^                           
         |                                                |                           
         V port:80                                        V port: 80                          
 ----------------------                           ----------------------              
 | 61.51.202.88       | Internet host             | 61.51.76.102       | Internet host
 ----------------------                           ----------------------              
                                                           
                              圖一: NAT 實現了私人IP的電腦分享幾個公網IP地址訪問Internet的功能。
                             
隨著網路的普及,IPv4的局限性暴露出來。公網IP地址成為一種稀缺的資源,此時NAT 的功能局限也暴露出來,同一個公網的IP地址,某個時間只能由一台私人IP地址的電腦使用。於是NAPT(The IP Network Address/Port Translator)應運而生,NAPT實現了多台私人IP地址的電腦可以同時通過一個公網IP地址來訪問Internet的功能。這在很大程度上暫時緩解了IPv4地址資源的緊張。

NAPT 負責將某些內網IP地址的電腦向外部網路發出的TCP/UDP資料包的源IP地址轉換為NAPT自己的公網的IP地址,源連接埠轉為NAPT自己的一個連接埠。目的IP地址和連接埠不變, 並將IP資料包發給路由器,最終到達外部的電腦。同時負責將外部的電腦返回的IP資料包的目的IP地址轉換內網的IP地址,目的連接埠轉為內網電腦的連接埠,源IP地址和源連接埠不變,並最終送達到內網中的電腦。

                                                
  ----------------------                           ----------------------              
  | 192.168.0.5        |  Internat host            | 192.168.0.6        |  Internat host
  ----------------------                           ----------------------              
   port: 2809 ^                   ^ port: 1827
      /                 /
       v               v    
     ----------------------           
     | 192.168.0.1        | NAT device
     | 61.51.99.86        |           
     ----------------------      
 map port:9882 to 192.168.0.5:2809 ^              ^ map port: 9881 to 192.168.0.6:1827
      /                /
        port:80 v                  v port:80    
  ----------------------                           ----------------------              
  | 61.51.202.88       | Internet host             | 61.51.76.102       | Internet host
  ----------------------                           ----------------------       
    
                              圖二: NAPT 實現了私人IP的電腦分享一個公網IP地址訪問Internet的功能。      
 
在我們的工作和生活中, NAPT的作用隨處可見,絕大部分公司的網路架構,都是通過1至N台支援NAPT的路由器來實現公司的所有電腦串連外部的Internet網路的。包括本人在寫這篇文章的時候,也是在家中使用一台IBM筆記本通過一台寬頻連線的台式機來訪問Internet的。我們本篇文章主要討論的NAPT的問題。

NAPT(The IP Network Address/Port Translator) 為何阻礙了P2P軟體的應用?

通過NAPT 上網的特點決定了只能由NAPT內的電腦主動向NAPT外部的主機發起串連,外部的主機想直接和NAPT內的電腦直接建立串連是不被允許的。IM(即時通訊)而言,這意味著由於NAPT內的電腦和NAPT外的電腦只能通過伺服器中轉資料來進行通訊。對於P2P方式的下載程式而言,意味著NAPT內的電腦不能接收到NAPT外部的串連,導致串連數用過少,下載速度很難上去。因此P2P軟體必須要解決的一個問題就是要能夠在一定的程度上解決NAPT內的電腦不能被外部串連的問題。

NAT(The IP Network Address Translator) 進行UDP穿透的原理是什麼?

TCP/IP傳輸時主要用到TCP和UDP協議。TCP協議是可靠的,連線導向的傳輸協議。UDP是不可靠的,不需連線的協議。根據TCP和UDP協議的實現原理,對於NAPT來進行穿透,主要是指的UDP協議。TCP協議也有可能,但是可行性非常小,要求更高,我們此處不作討論,如果感興趣可以到Google上搜尋,有些文章對這個問題做了探討性的描述。下面我們來看看利用UDP協議來穿透NAPT的原理是什麼:

   ----------------------                           ----------------------              
   | 192.168.0.5        |  Internat host            | 192.168.0.6        |  Internat host
   ----------------------                           ----------------------              
     UDP port: 2809 ^                   ^ UDP port: 1827
       /                 /
        v               v    
      ----------------------           
      | 192.168.0.1        | NAT device
      | 61.51.99.86        |           
      ----------------------      
  Session(192.168.0.6:1827 <-> 61.51.76.102:8098) ^              ^ Session(192.168.0.6:1827 <-> 61.51.76.102:8098)
               map port:9882 to 192.168.0.5:2809 /                /map port: 9881 to 192.168.0.6:1827
      UDP port:8098 v                  v UDP port:8098    
   ----------------------                           ----------------------              
   | 61.51.202.88       | Internet host             | 61.51.76.102       | Internet host
   ----------------------                           ----------------------   
       
     
                        圖三: NAPT 是如何將私人IP地址的UDP資料包與公網主機進行透明傳輸的。

UDP協議包經NAPT透明傳輸的說明:

NAPT為每一個Session分配一個NAPT自己的連接埠號碼,依據此連接埠號碼來判斷將收到的公網IP主機返回的TCP/IP資料包轉寄給那台內網IP地址的電腦。在這裡Session是虛擬,UDP通訊並不需要建立串連,但是對於NAPT而言,的確要有一個Session的概念存在。NAPT對於UDP協議包的透明傳輸面臨的一個重要的問題就是如何處理這個虛擬Session。我們都知道TCP串連的Session以SYN包開始,以FIN包結束,NAPT可以很容易的擷取到TCP Session的生命週期,並進行處理。但是對於UDP而言,就麻煩了,NAPT並不知道轉寄出去的UDP協議包是否到達了目的主機,也沒有辦法知道。而且鑒於UDP協議的特點,可靠很差,因此NAPT必須強制維持Session的存在,以便等待將外部送回來的資料並轉寄給曾經發起請求的內網IP地址的電腦。NAPT具體如何處理UDP Session的逾時呢?不同的廠商提供的裝置對於NAPT的實現不近相同,也許幾分鐘,也許幾個小時,些NAPT的實現還會根據裝置的忙碌狀態進行智能計算逾時時間的長短。

    [192.168.0.6:1827]
                            | UDP Packet[src ip:192.168.0.6 src port:1827 dst ip:61.51.76.102 dst port 8098]
                            v
 [pub ip: 61.51.99.86]NAT[priv ip: 192.168.0.1]
                            | UDP Packet[src ip:61.51.99.86 src port:9881 dst ip:61.51.76.102 dst port 8098]
                            v   
    [61.51.76.102:8098]
   
          圖四: NAPT 將內部發出的UDP協議包的源地址和源連接埠改變傳輸給公網IP主機。
         
         
    [192.168.0.6:1827]
              ^
                            | UDP Packet[src ip:61.51.76.102 src port:8098 dst ip:192.168.0.6 dst port 1827]
 [pub ip: 61.51.99.86]NAT[priv ip: 192.168.0.1]
              ^ 
                            | UDP Packet[src ip:61.51.76.102 src port:8098 dst ip:61.51.99.86 dst port 9881] 
    [61.51.76.102:8098]
   
          圖五: NAPT 將收到的公網IP主機返回的UDP協議包的目的地址和目的連接埠改變傳輸給內網IP電腦。         
現在我們大概明白了NAPT如何?內網電腦和外網主機間的透明通訊。現在來看一下我們最關心的問題,就是NAPT是依據什麼策略來判斷是否要為一個請求發出的UDP資料包建立Session的呢?主要有一下幾個策略:

A. 源地址(內網IP地址)不同,忽略其它因素, 在NAPT上肯定對應不同的Session
B. 源地址(內網IP地址)相同,源連接埠不同,忽略其它的因素,則在NAPT上也肯定對應不同的Session
C. 源地址(內網IP地址)相同,源連接埠相同,目的地址(公網IP地址)相同,目的連接埠不同,則在NAPT上肯定對應同一個Session
D. 源地址(內網IP地址)相同,源連接埠相同,目的地址(公網IP地址)不同,忽略目的連接埠,則在NAPT上是如何處理Session的呢?

D的情況正式我們關心和要討論的問題。依據目的地址(公網IP地址)對於Session的建立的決定方式我們將NAPT裝置劃分為兩大類:

Symmetric NAPT:
對於到同一個IP地址,任意連接埠的串連分配使用同一個Session; 對於到不同的IP地址, 任意連接埠的串連使用不同的Session.
我們稱此種NAPT為 Symmetric NAPT. 也就是只要本地綁定的UDP連接埠相同, 發出的目的IP地址不同,則會建立不同的Session.

 [202.223.98.78:9696] [202.223.98.78:9696] [202.223.98.78:9696]
  ^  ^   ^
  |  |   |
  v  v   v
        9883        9882         9881
                   |
        / [NAT] /
            ^
            |
            v    
     [192.168.0.6:1827]
    
     圖六: Symmetric 的英文意思是對稱。多個連接埠對應多個主機,平行的,對稱的!
   
Cone NAPT:
對於到同一個IP地址,任意連接埠的串連分配使用同一個Session; 對於到不同的IP地址,任意連接埠的串連也使用同一個Session.
我們稱此種NAPT為 Cone NAPT. 也就是只要本地綁定的UDP連接埠相同, 發出的目的地址不管是否相同, 都使用同一個Session.

 [202.223.98.78:9696] [202.223.98.78:9696] [202.223.98.78:9696]

   ^    ^      ^
    /    |     /
     v    v    v
            9881
                                 [NAT]
       ^
       |
       v    
     [192.168.0.6:1827]
    
     圖七: Cone 的英文意思是錐。一個連接埠對應多個主機,是不是像個錐子?

現在絕大多數的NAPT屬於後者,即Cone NAT。本人在測試的過程中,只好使用了一台日本的Symmetric NAT。還好不是自己的買的,我從不買日貨, 希望看這篇文章的朋友也自覺的不要購買日本的東西。Win9x/2K/XP/2003系統內建的NAPT也是屬於 Cone NAT的。這是值的慶幸的,因為我們要做的UDP穿透只能在Cone NAT間進行,只要有一台不是Cone NAT,對不起,UDP穿透沒有希望了,伺服器轉寄吧。後面會做詳細分析!

下面我們再來分析一下NAPT 工作時的一些資料結構,在這裡我們將真正說明UDP可以穿透Cone NAT的依據。這裡描述的資料結構只是為了說明原理,不具有實際參考價值,真正感興趣可以閱讀Linux的中關於NAT實現部分的源碼。真正的NAT實現也沒有利用資料庫的,呵呵,為了速度!

Symmetric NAPT 工作時的連接埠映射資料結構如下:

內網資訊表:

[NAPT 分配連接埠] [ 內網IP地址 ] [ 內網連接埠 ] [ 外網IP地址 ] [ SessionTime 開始時間 ]

PRIMARY KEY( [NAPT 分配連接埠] ) -> 表示依據[NAPT 分配連接埠]建立主鍵,必須唯一且建立索引,加快尋找.
UNIQUE( [ 內網IP地址 ], [ 內網連接埠 ] ) -> 表示這兩個欄位聯合起來不能重複.
UNIQUE( [ 內網IP地址 ], [ 內網連接埠 ], [ 外網IP地址 ] ) -> 表示這三個欄位聯合起來不能重複.

映射表:

[NAPT 分配連接埠] [ 外網連接埠 ]

UNIQUE( [NAPT 分配連接埠], [ 外網連接埠 ] ) -> 表示這兩個欄位聯合起來不能重複.

Cone NAPT 工作時的連接埠映射資料結構如下:

內網資訊表:

[NAPT 分配連接埠] [ 內網IP地址 ] [ 內網連接埠 ] [ SessionTime 開始時間 ]

PRIMARY KEY( [NAPT 分配連接埠] ) -> 表示依據[NAPT 分配連接埠]建立主鍵,必須唯一且建立索引,加快尋找.
UNIQUE( [ 內網IP地址 ], [ 內網連接埠 ] ) -> 表示這兩個欄位聯合起來不能重複.

外網資訊表:

[ wid 主鍵標識 ] [ 外網IP地址 ] [ 外網連接埠 ]

PRIMARY KEY( [ wid 主鍵標識 ] ) -> 表示依據[ wid 主鍵標識 ]建立主鍵,必須唯一且建立索引,加快尋找.
UNIQUE( [ 外網IP地址 ], [ 外網連接埠 ] ) -> 表示這兩個欄位聯合起來不能重複.

映射表: 實現一對多,的

[NAPT 分配連接埠] [ wid 主鍵標識 ]

UNIQUE( [NAPT 分配連接埠], [ wid 主鍵標識 ] ) -> 表示這兩個欄位聯合起來不能重複.
UNIQUE( [ wid 主鍵標識 ] ) -> 標識此欄位不能重複.

看完了上面的資料結構是更明白了還是更暈了? 呵呵! 多想一會兒就會明白了。通過NAT,內網電腦電腦向外連結是很容易的,NAPT會自動處理,我們的應用程式根本不必關心它是如何處理的。那麼外部的電腦想訪問內網中的電腦如何?呢?我們來看一下下面的流程:

c 是一台在NAPT後面的內網電腦,s是一台有外網IP地址的電腦。c 主動向 s 發起串連請求,NAPT依據上面描述的規則在自己的資料結構中記錄下來,建立一個Session. 然後 c 和 s 之間就可以實現雙向的透明的資料轉送了。如下面所示:

   c[192.168.0.6:1827] <-> [priv ip: 192.168.0.1]NAPT[pub ip: 61.51.99.86:9881] <-> s[61.51.76.102:8098]

由此可見,一台外網IP地址的電腦想和NAPT後面的內網電腦通訊的條件就是要求NAPT後面的內網電腦主動向外網IP地址的電腦發起一個UDP資料包。外網IP地址的電腦利用收到的UDP資料包擷取到NAPT的外網IP地址和映射的連接埠,以後就可以和內網IP的電腦透明的進行通訊了。
   
現在我們再來分析一下我們最關心的兩個NAPT後面的內網電腦如何?直接通訊呢? 兩者都無法主動發出串連請求,誰也不知道對方的NAPT的公網IP地址和NAPT上面映射的連接埠號碼。所以我們要靠一個公網IP地址的伺服器協助兩者來建立串連。當兩個NAPT後面的內網電腦分別串連了公網IP地址的伺服器後,伺服器可以從收到的UDP資料包中擷取到這兩個NAPT裝置的公網IP地址和這兩個串連建立的Session的映射連接埠。
兩個內網電腦可以從伺服器上擷取到對方的NAPT裝置公網IP地址和映射的連接埠了。

我們假設兩個內網電腦分別為A和B,對應的NAPT分別為AN和BN, 如果A在擷取到B對應的BN的IP地址和映射的連接埠後,迫不急待的向這個IP地址和映射的連接埠發送了個UDP資料包,會有什麼情況發生呢?依據上面的原理和資料結構我們會知道,AN會在自己的資料結構中產生一條記錄,標識一個新Session的存在。BN在收到資料包後,從自己的資料結構中查詢,沒有找到相關記錄,因此將包丟棄。B是個慢性子,此時才慢吞吞的向著AN的IP地址和映射的連接埠發送了一個UDP資料包,結果如何呢?當然是我們期望的結構了,AN在收到資料包後,從自己的資料結構中尋找到了記錄,所以將資料包進行處理髮送給了A。A 再次向B發送資料包時,一切都時暢通無阻了。OK, 大工告成!且慢,這時對於Cone NAPT而言,對於Symmetric NAPT呢?呵呵,自己分析一下吧...

NAPT(The IP Network Address/Port Translator) 進行UDP穿透的具體情況分析!

首先明確的將NAPT裝置按照上面的說明分為: Symmetric NAPT 和 Cone NAPT, Cone NAPT 是我們需要的。Win9x/2K/XP/2003 內建的NAPT也為Cone NAPT。

第一種情況, 雙方都是Symmetric NAPT:

此情況應給不存在什麼問題,肯定是不支援UDP穿透。

第二種情況, 雙方都是Cone NAPT:

此情況是我們需要的,可以進行UDP穿透。

第三種情況, 一個是Symmetric NAPT, 一個是Cone NAPT:

此情況比較複雜,但我們按照上面的描述和資料機構進行一下分析也很容易就會明白了, 分析如下,

假設: A -> Symmetric NAT, B -> Cone NAT

1. A 想串連 B, A 從伺服器那兒擷取到 B 的NAT地址和映射連接埠, A 通知伺服器,伺服器告知 B A的NAT地址和映射連接埠, B 向 A 發起串連,A 肯定無法接收到。此時 A 向 B 發起串連, A 對應的NAT建立了一個新的Session,分配了一個新的映射連接埠, B 的 NAT 接收到UDP包後,在自己的映射表中查詢,無法找到映射項,因此將包丟棄了。

2. B 想串連 A, B 從伺服器那兒擷取到 A 的NAT地址和映射連接埠, B 通知伺服器, 伺服器告知 A B的NAT地址和映射連接埠,A 向 B 發起串連, A 對應的NAT建立了一個新的Session,分配了一個新的映射連接埠B肯定無法接收到。此時 B 向 A 發起串連, 由於 B 無法擷取 A 建立的新的Session的映射連接埠,仍是使用伺服器上擷取的映射連接埠進行串連, 因此 A 的NAT在接收到UDP包後,在自己的映射表中查詢,無法找到映射項, 因此將包丟棄了。

根據以上分析,只有當串連的兩端的NAT都為Cone NAT的情況下,才能進行UDP的內網穿透互聯。

NAPT(The IP Network Address/Port Translator) 進行UDP穿透如何進行現實的驗證和分析!

需要的網路結構如下:

三個NAT後面的內網機器,兩個外網伺服器。其中兩台Cone NAPT,一台 Symmetric NAPT。

驗證方法:

可以使用本程式提供的源碼,編譯,然後分別運行伺服器程式和用戶端。修改過後的源碼增加了用戶端之間直接通過IP地址和連接埠發送訊息的命令,利用此命令,你可以手動的驗證NAPT的穿透情況。為了方便操作,推薦你使用一個遠程登陸軟體,可以直接在一台機器上操作所有的相關的電腦,這樣很方便,一個人就可以完成所有的工作了。呵呵,本人就是這麼完成的。歡迎有興趣和經驗的朋友來信批評指正,共同進步。

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.