NAT內網穿透

qq早期在線聊天使用udp實現的且是P2P的,其中一點優勢就是P2P的udp的穿牆優勢,其他包括效率高,佔用資源少,速度快,但是其傳輸機制爲不可靠傳輸,必須依靠輔助算法來完成傳輸控制。

利用P2P點對點技術實現,需解決的兩個問題。
1.實現內網之間機器的網絡通信。
2.需要解決UDP出現的數據傳輸不穩定問題。

NAT英文全稱是“Network Address Translation”,中文意思是“網絡地址轉換”,它是一個IETF(Internet Engineering Task Force, Internet工程任務組)標準,允許一個整體機構以一個公用IP(Internet Protocol)地址出現在Internet上。顧名思義,它是一種把內部私有網絡地址(IP地址)翻譯成合法網絡IP地址的技術。

NAT三種實現方式

靜態地址轉換:一個公網IP對應一個內部IP,一對一轉換

動態地址轉換:N個公網IP對應M個內部Ip,不固定的一對一IP轉換關係.同一時間,有M-N個主機無法聯網.

端口多路複用:對外只有一個公網IP,通過端口來區別不同內部IP主機的數據.

IP轉換策略

對於靜態與動態地址轉換;其數據包出站的時候,進行源地址轉換.我們稱之爲SNAT[SOURCE ADDRESS].其內部源IP變公網源IP.數據包入站的時候,進行目標地址轉換DNAT[DESTINATION ADDRESS],其外部公網宿IP變內部宿IP.靜態與動態不進行端口轉換.而端口多路複用技術.不但要轉換其IP地址,還要進行其傳輸層的端口轉換.通過這唯一的端口號來區別不同的內部數據[在通信過程中會建立一張內部到外部映射表].我們稱之NATP[NAT PORT]技術.在我們家用網絡中,大部分用的是端口多路複用技術.在端口多路複用技術中,對數據的處理還分這麼兩類:錐形NAT與對稱型NAT.錐形NAT又分完全錐形NAT[FULL CONE]|受限錐形NAT[RESTRICTED CONE]|端口受限錐形NAT[PORT RESTRICTED CONE].

全完錐形NAT:將來自內部同一個IP地址同一個端口號的主機監聽/請求,映射到公網IP某個端口的監聽.任意外部IP地址與端口對其自己公網的IP這個映射後的端口訪問,都將重新定位到內部這個主機.個人認爲在內部發布服務器到外網,此技術原理完全否合該技術原理,當然某些P2P中也可能利用該技術.該技術中,基於C/S架構的應用可以在任何一端發起連接.

受限錐形NAT:與完全NAT不同的是,在公網映射端口後,並不允許所有IP進行對於該端口的訪問,要想通信必需內部主機對某個外部IP主機發起過連接,然後這個外部IP主機就可以與該內部主機通信了.但端口不做限制.如出站源IP爲A端口爲B,對於外部IP回覆,宿IP爲A宿端口可以是任意.NAPT設備都將成功轉發到內部主機.NAPT設備根據映射記錄做出判斷.該技術中只能內部主機先發起連接通信纔可成功.

端口受限錐形NAT:該技術與受限錐形NAT相比更爲嚴格.除具有受限錐形NAT特性.對於回覆主機的源端口也有要求.哪我用端口B訪問你,對於外部主機的回覆信宿端口也只能是B.否折通信失敗.該技術中只能內部主機先發起連接通信纔可成功.

對稱型NAT:內部主機用同一IP與同一端口與外部多IP通信.NAPT設備爲每個會話轉換了不同的源端口.不在轉換成相同的源端口.對於回覆的數據包,只有信宿IP地址與端口完全吻合纔可進入.當然源IP也是要檢測的,不可能隨意外部IP都能進入的.

參考文獻:
http://blog.csdn.net/fazhunchan/article/details/5394608
http://www.cnblogs.com/bo083/articles/2170189.html
http://blog.csdn.net/ustcgy/article/details/5652268

轉發

最可靠但又是最低效的點對點通信方法,莫過於將p2p網絡通信看作一個C/S結構,通過服務器來轉發信息.如下圖,兩個客戶端A和B,均與服務器S初始化了一個TCP或UDP連接,服務器S具有公網固定IP地址,兩個客戶端分佈在不同的私網中,這樣,他們各自的NAT代理服務器將不允許他們進行直連.

                            Server S
                               |
                               |
        +----------------------+----------------------+
        |                                             |
      NAT A                                         NAT B
        |                                             |
        |                                             |
     Client A                                      Client B

取而代之的方式是,兩個客戶端可以把服務器S當作信使來轉發消息.比如,爲了將消息發送到B,A先發送一條信息給服務器S,服務器S再利用初始化時已經建立的連接,將信息轉發給B.

NAT211.133.和NAT211.134.之間需要進行通信,但開始不能直接就發數據包,我們需要一箇中間人,這個就是外部索引服務器(我們假設是211.135.:7000),當NAT211.133.向211.135.:7000發送數據包,211.135.:7000是可以正常接收到數據,因爲它是屬於對外型開放的服務端口。當211.135.:7000收到數據包後可以獲知NAT211.133.對外通信的臨時SESSION信息(這個臨時的端口,假設是6000會過期,具體的時間不同,但我個人的測試是每30秒發送一個心跳包keep住連接以保證端口維持住通信連接不斷開),索引服務器此時應將此信息保存起來。而同時,NAT211.134.也在時刻向索引服務器發送心跳包,索引服務器就向NAT211.134.發送一個通知,讓它向NAT211.133.:6000發送探測包(這個數據包最好多發幾個),NAT211.134.在收到通知包之後再向索引服務器發送反饋包,說明自己已經向NAT211.133.:6000發送了探測包,索引服務器在接收到反饋包之後再向NAT211.133.轉發反饋包,NAT211.133.在接收到數據包之後再向原本要請求的NAT211.134.發送數據包,此時連接已經打通,實現穿透,NAT211.134.*會將信息轉發給192.168.1.88的9000端口。

此處輸入圖片的描述

這個方法的優勢是:它適合於任何NAT包括Symmetric NAT.但是它的劣勢也很明顯:它將全面依賴並消耗服務器的資源和網絡帶寬.名爲 TURN 的協議定義了一個利用轉發技術進行可靠通信的模型.

反向連接

這裏介紹第二種技術,但是它只能在通信的兩端只有一端處於NAT之後的情況下.舉例來說,假設客戶端A處於NAT之後,而客戶端B有一個公網IP地址,如下圖所示.

                            Server S
                        18.181.0.31:1235
                               |
                               |
        +----------------------+----------------------+
        |                                             |
      NAT A                                           |
155.99.25.11:62000                                    |
        |                                             |
        |                                             |
     Client A                                     Client B
  10.0.0.1:1234                               138.76.29.7:1234

現在我們假設客戶端B將會與客戶端A初始化一個端對端連接會話.B將首先試圖連接A的一個地址—客戶端A認爲是它自己的地址10.0.0.1:1234或者是從服務器S觀察到的地址155.99.25.11:62000.然而不論是連接哪一個,都不可能成功.第一種情況:試圖直接連到10.0.0.1肯定會失敗,因爲10.0.0.1根本就不是一個可以在公網上路由的IP地址;第二種情況,從B傳來的請求將能夠到達端口NAT A的端口62000,但NAT A卻會拒絕這個連接請求,因爲只有外出的連接才允許進入. 在所有的嘗試都失敗之後,客戶端B就只能通過服務器S來請求A做一個”反向”連接到客戶端B,客戶端A將打開一個與客戶端B通訊的連接(在B的公網IP地址和端口號上).NAT A允許這個連接通過,因爲這個連接起源於NAT A的內部,並且同時客戶端B能夠受這個連接因爲B並不位於NAT之後.

這個方法的優勢是:它也適合於任何NAT包括Symmetric NAT.它的主要限制在於,只能有一端位於NAT之後.

UDP打洞

第三種技術,也是這篇文章主要要介紹的,就是非常有名的”UDP打洞技術”.這裏將考慮兩種典型場景,來介紹連接的雙方應用程序如何按照計劃的進行通信的,第一種場景,我們假設兩個客戶端都處於不同的NAT之後;第二種場景,我們假設兩個客戶端處於同一個NAT之後,但是它們彼此都不知道(他們在同一個NAT中).

處於不同NAT之後的客戶端通信

我們假設 Client A和Client B都擁有自己的私有IP地址,並且都處在不同的NAT之後,端對端的程序運行於 CLIENT A,CLIENT B,S之間,並且它們都開放了UDP端口1234. CLIENT A和CLIENT B首先分別與S建立通信會話,這時NAT A把它自己的UDP端口62000分配給CLIENT A與S的會話,NAT B也把自己的UDP端口31000分配給CLIENT B與S的會話.如下圖所示:

                            Server S
                        18.181.0.31:1234
                               |
                               |
        +----------------------+----------------------+
        |                                             |
      NAT A                                         NAT B
155.99.25.11:62000                            138.76.29.7:31000
        |                                             |
        |                                             |
     Client A                                     Client B
  10.0.0.1:1234                                 10.1.1.3:1234

假如這個時候 CLIENT A 想與 CLIENT B建立一條UDP通信直連,如果 CLIENT A只是簡單的發送一個UDP信息到CLIENT B的公網地址
138.76.29.7:31000的話,NAT B會不加考慮的將這個信息丟棄(除非NAT B是一個 full cone NAT),因爲這個UDP信息中所包含的地址信息,與CLIENT B和服務器S建立連接時存儲在NAT B中的服務器S的地址信息不符.同樣的,CLIENT B如果做同樣的事情,發送的UDP信息也會被NAT A丟棄.

假如 CLIENT A 開始發送一個UDP信息到CLIENT B的公網地址上,與此同時,他又通過S中轉發送了一個邀請信息給CLIENT B,請求CLIENT B也給CLIENT A發送一個UDP信息到 CLIENT A的公網地址上.這時CLIENT A向CLIENT B的公網IP(138.76.29.7:31000)發送的信息導致 NAT A 打開一個處於CLIENT A的私有地址和CLIENT B的公網地址之間的新的通信會話,與此同時NAT B也打開了一個處於CLIENT B的私有地址和CLIENT A的公網地址(155.99.25.11:62000)之間的新的通信會話.一旦這個新的UDP會話各自向對方打開了,CLIENT A和CLIENT B之間就可以直接通信,而無需S來牽線搭橋了.這就是所謂的打洞技術.
一旦這種處於NAT之後的端對端的直連建立之後,連接的雙方可以輪流擔任對方的”媒人”,把對方介紹給其他的客戶端,這樣就極大的降低了服務器S的工作量.

處於相同NAT之後的客戶端通信

我們假設 Client A和Client B都擁有自己的私有IP地址,並且都處在相同的NAT之後,端對端的程序運行於 CLIENT A,CLIENT B,S之間,
CLIENT A和CLIENT B分別與S建立通信會話,經過NAT轉換後,A的公網端口被映射爲62000,B的公網端口映射爲62001.如下圖所示:

                           Server S
                        18.181.0.31:1234
                               |
                               |
                              NAT
                     A-S 155.99.25.11:62000
                     B-S 155.99.25.11:62001
                               |
        +----------------------+----------------------+
        |                                             |
     Client A                                      Client B
  10.0.0.1:1234                                 10.1.1.3:1234

根據前面介紹的”打洞”技術,CLIENT A將發送一個UDP信息到CLIENT B的公網地址上,數據包源端爲(10.0.0.1:124),目的端爲(155.99.25.11:62001).該數據包能否被B收到,取決於當前的NAT是否支持”髮夾”轉換(hairpin轉換,也就是同一臺設備不同端口之間的UDP數據包能否到達).
首先,支持”髮夾”轉換的NAT設備還遠沒有支持”打洞”技術的NAT設備多,其次,即使NAT設備支持”髮夾”轉換,在這種情況下也應該通過網內端到端實現,而不是將數據包無謂 地經過NAT設備,這是一種對資源的浪費.

一般”打洞”過程

綜合上面介紹的客戶端處於不同NAT之後和處於同一NAT之後,我們說下一般的”打洞”過程.

  1. 打洞技術假定客戶端A和B可以與公網內的已知的集中服務器建立UDP連接(可以互發UDP數據包).當一個客戶端在S上登陸的時候,服務器記錄下該客戶端的兩個endpoints(IP地址,UDP端口),一個是該客戶端確信自己是通過該ip和端口與服務器S進行通信的,另一個是服務器S記錄下的由服務器”觀察”到的該客戶端實際與自己通信所使用的ip和端口.我們可以把前一個endpoint看作是客戶端的內網ip和端口,把後一個endpoint看作是客戶端的內網ip和端口經過NAT轉換後的公網ip和端口.服務器可以從客戶端的登陸消息的消息體中得到該客戶端的內網endpoint相關信息,可以通過對登陸消息的IP或UDP頭得到該客戶端的公網endpoint.

  2. 假設Client A想向B發起連接,於是A向服務器S發送消息,請求S幫助建立與B的UDP連接.這時,S將B的公網和內網的endpoint發給A.可知,A與B通過與S的一次通信就可以知道對方的公網和內網的endpoint.

  3. Client A通過B的內網endpoint發送UDP數據包.針對5.3.2節問題的解決方案.如果B和A在同一NAT後,則很快收到響應.如果B和A不在同一NAT後,則超時.

  4. Client A通過B的外網endpoint發送UDP數據包.
    回到5.3.1節介紹的具體方法.CLIENT A發出UDP包(10.0.0.1:1234,138.76.29.7:31000),經NAT A轉換爲(155.99.25.11:62000,138.76.29.7:31000),經NAT B轉換爲(155.99.25.11:62000,10.1.1.3:1234).如果在此數據包到達NAT B前,B發送過UDP包到A的公網endpoint,則NAT B允許此包到達B機.在5.3.2節下,A發出UDP包(10.0.0.1:1234,155.99.25.11:62001),NAT 先轉換爲(155.99.25.11:62000,155.99.25.11:62001),再轉換爲(155.99.25.11:62000,10.1.1.3:1234).

  5. 步驟3,4發送的數據包是爲了”打洞”,打洞成功後,就進入真正的P2P傳輸了.
    還有一種情況,B和A不在同一NAT後,C和A在同一NAT後,且B和C的內網endpoint一致,這個時候A從S拿到的目的端應該有2個.所以針對3,4步驟取先有迴應的目的端不可取,應該先做步驟3,有迴應直接到步驟5,沒有迴應到步驟4.

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