在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條原理保護了內網主機免受外網的攻擊,但卻違背了網絡端到端的設計原則。如果兩臺主機在不同的NAT後面,是沒有辦法穿越NAT直接端到端(P2P))通訊的。幸運的是,在大部分情況下,我們可以在服務器的協助下實現NAT穿越。
NAT類型
在講NAT穿越之前,我們先來分析NAT的類型。由於沒有強制性的NAT標準,在實際應用中NAT有多種類型。根據內網地址到外網地址的映射是1對1,還是1對多,NAT可以分成兩大類:Cone NAT(錐型)和 Symmetric 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 錐型
- A發送數據包給S詢問自身地址,S把A的外網地址eA返回給A
- B發送數據包給S詢問自身地址,S把B的外網地址eB返回給B
- S把B的外網地址eB發送給A
- S把A的外網地址eA發送給B
- A發送數據包給eB,B發送數據包給eA,建立P2P通道
端口限制錐型 vs 對稱型
- A發送數據包給S詢問自身地址,S把A的外網地址eA返回給A
- B發送數據包給S詢問自身地址,S把B的外網地址eB1返回給B
- S把B的外網地址eB1發送給A
- S把A的外網地址eA發送給B
- A發送數據包給eB1,因爲eB1只接受來自S的數據,所以A的數據被NATB丟棄
- 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,導致穿越失敗。見下圖。