環信即時通訊雲技術博客——P2P實時音視頻之NAT穿越

在P2P實時音視頻領域,NAT穿越是一個非常重要的技術。NAT穿越技術使得客戶端和客戶端直接進行通訊,從而減少了端到端的延遲,並大大減輕了服務器的壓力,降低成本。

NAT是什麼

NAT的全稱Network Address Translation,通常指的是把內網地址轉換成外網地址。一般家用的無線路由器就用到了NAT技術。NAT技術的出現是爲了解決IPv4地址不夠的問題,而且還能夠避免來自網絡外部的攻擊,隱藏和保護網絡內部的計算機。凡事有利必有弊,NAT同樣帶來了新的問題。

NAT工作原理

我們先看一下NAT的工作過程

  • NAT維護一個地址映射表,記錄內容爲內網主機地址iAddr、映射地址eAddr和外網主機地址hAddr,表初始爲空
  • 內網主機主機A發送數據包給服務器A,10.0.1.10:1111 -> 203.22.22.22:6000;
  • NAT在映射表裏沒找到源地址等於10.0.1.10:1111的記錄,於是新建一條記錄1,分配外網端口2000
  • NAT修改數據包的源地址再發到外網,202.11.11.11:2000 -> 203.22.22.22:6000;
  • 後續所有源地址爲10.0.1.10:1111,目標地址爲203.22.22.22:6000都做同樣的修改
  • 服務器A發送數據包回給內網主機A,203.22.22.22:6000 -> 202.11.11.11:2000
  • NAT發現外網地址202.11.11.11:2000映射的內網地址爲10.0.1.10:1111
  • NAT修改數據包的目的地址再發到內網,203.22.22.22:6000 -> 10.0.1.10:1111
  • 內網主機B和服務器B通訊的過程也類似A,只是分配的外網端口是3000

從上面NAT的工作過程可以看出,NAT通過修改數據包的源地址或目的地址來實現地址映射的。NAT修改數據包對內網主機是透明的,不需要內網主機做任何配置,方便簡單。
NAT工作原理可以總結爲:

  1. 只有內網主機主動向外網發送數據,外網纔有可能發送數據給內網主機
  2. 內網發送到外網的數據包會被修改源地址,外網發送給內網的數據包會被修改目的地址

很顯然,第1條原理保護了內網主機免受外網的攻擊,但卻違背了網絡端到端的設計原則。如果兩臺主機在不同的NAT後面,是沒有辦法穿越NAT直接端到端(P2P))通訊的。幸運的是,在大部分情況下,我們可以在服務器的協助下實現NAT穿越。

NAT類型

在講NAT穿越之前,我們先來分析NAT的類型。由於沒有強制性的NAT標準,在實際應用中NAT有多種類型。根據內網地址到外網地址的映射是1對1,還是1對多,NAT可以分成兩大類:Cone NAT(錐型)和 Symmetric NAT(對稱型)

從圖中的淡紫色形狀應該可以看出來它們名字的來歷(嘔心瀝血獨家原創圖)。錐型NAT把一個內網地址固定的轉換成一個外網地址,即1對1映射;對稱型NAT的一個內網地址可以轉換成多個外網地址,即1對多映射。從錐型NAT和對稱型NAT的定義我們可以推測出他們的映射表內容。
錐型映射表應該是這樣的:


對稱型映射表應該是這樣的:

Cone NAT子類型

錐型NAT還可以再繼續細分類型。外網主機發送給內網主機的數據包在通過NAT時,NAT會根據映射表的外網主機地址限制條件來允許或限制數據包通過。根據這個限制條件,錐型NAT還可以分成三種子類型:

Full-cone NAT,全錐型
一旦某內網地址向外網發送過數據包,NAT允許任意外網地址發送數據給此內網地址。


(Address)-restricted-cone NAT,(地址)限制錐型
一旦某內網地址向某外網主機發送過數據包,NAT允許此外網主機發送數據給此內網地址。換句話說,只限制ip,不限制端口。


Port-restricted cone NAT,端口限制錐型
只有從內網地址發送過的外網地址,NAT才允許此外網地址發送數據給此內網地址。換句話說,同時限制ip和端口。

穿越NAT

通過上面對NAT的分析可以看出,在不同NAT後面的兩個客戶端A和B,如果知道對方的NAT映射後的外網地址,就有可能直接發送UDP包給對方外網地址進行通訊。但是這裏有一個問題,客戶端不能直接獲取自身的NAT外網地址,解決的辦法就是引入一個服務器S來協助客戶端獲取自身的外網地址。NAT的類型有多種,類型兩兩組合有很多種,不是每種組合都可以被穿越的,我們來分析兩個典型的組合。

錐型 vs 錐型

  1. A發送數據包給S詢問自身地址,S把A的外網地址eA返回給A
  2. B發送數據包給S詢問自身地址,S把B的外網地址eB返回給B
  3. S把B的外網地址eB發送給A
  4. S把A的外網地址eA發送給B
  5. A發送數據包給eB,B發送數據包給eA,建立P2P通道

端口限制錐型 vs 對稱型

  1. A發送數據包給S詢問自身地址,S把A的外網地址eA返回給A
  2. B發送數據包給S詢問自身地址,S把B的外網地址eB1返回給B
  3. S把B的外網地址eB1發送給A
  4. S把A的外網地址eA發送給B
  5. A發送數據包給eB1,因爲eB1只接受來自S的數據,所以A的數據被NATB丟棄
  6. B通過發送數據包給eA,因爲eA是新的目標地址,NATB 創建新的映射地址eB2,而eA只接受來自S和eB1的數據,所以B的數據被NATA丟棄,無法建立P2P通道

這裏就不一一分析其他組合,各位看官可以自行分析,這裏直接給出結論:

現實中的NAT

在穿越NAT的結論裏,只有兩種組合不能穿越,即對稱型vs對稱型端口限制錐型vs對稱型,佔比並不高,看起來結論還不錯。但是,理論是美好的,現實是殘酷的,生活中對稱型NAT的數量並不少。只要是大型組織的網絡,一般都採用對稱型NAT,因爲這類NAT安全性最好。我們團隊曾經對常用的網絡做過調查研究,以下是調研結果:

  • 有公網IP的寬帶:比如聯通的ADSL,這類寬帶會給每個用戶分配一個公網IP,所以其NAT類型取決於用戶所選用的路由器,大部分家用路由器都是端口限制錐型NAT;
  • 無公網IP的寬帶:比如寬帶通,這類寬帶給用戶分配的是局域網IP,連接公網的NAT是運營商的,一般都是對稱型NAT;
  • 移動互聯網:跟“無公網IP的寬帶”類似,分配給手機的是局域網IP,出口基本都是對稱型NAT;
  • 大公司路由器:大部分都把路由器配置成對稱型NAT;

比較可惜的是移動互聯網也是對稱型NAT,也就是說,如果通訊雙方都走3G或4G的話,是很難直接P2P通訊的。我們的產品可以穿越部分對稱型NAT,當碰到無法穿越的NAT時,爲用戶提供relay服務,保證接通率。

奇葩的NAT

我們現在知道NAT分爲1種對稱型和3種錐型,那還有沒有其他類型的NAT呢?答案是YES。這個NAT各位看官應該並不陌生,它就是大名鼎鼎的netfilter/iptables。大家接觸最多的iptables,是運行在ring3層用戶態的配置程序,而運行在ring0內核態的netfilter纔是真正實現NAT功能的程序。在大部分情況下,netfilter表現出來的是人見人愛的錐型NAT,但是在某種條件刺激下,它就華麗麗地變身成高貴冷漠的對稱型NAT!
先上圖:


在穿越時,假如右邊B發給A的包比左邊A發給B的包先到達netfilter,netfilter會用之前的映射地址eB把B的包發出去,這時候netfilter表現出來的是錐型NAT,穿越成功。反過來,假如A發給B的包先到達netfilter,那麼B發給A的包就會被netfilter映射成新的地址eB’,這時候netfilter表現出來的是對稱型NAT,導致穿越失敗。見下圖。

netfilter不分內網和外網,它會跟蹤內網和外網所有協議的連接(conntrack),包括tcp和udp。當外網的數據先到達netfilter時,netfilter創建一條conntrack,內網的數據後到達netfilter,netfilter發現conntrack1已經佔用了端口,就會選擇另外一個外網端口作爲映射端口。看官如果想了解詳細情況,請閱讀博大精深的netfilter源碼,這裏提示一下,看get_unique_tuple函數就可以了。雖然netfilter很奇葩,但我們的產品依然能夠輕鬆的穿越它。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章