ICE協議下NAT穿越的實現(STUN&TURN)

正文:

一. 首先來簡單講講什麼是NAT?

原來這是由於IPV4引發的,咱們上網極可能會處在一個NAT設備(無線路由器之類)以後。
NAT設備會在IP封包經過設備時修改源/目的IP地址. 對於家用路由器來講, 使用的是網絡地址端口轉換(NAPT), 它不只改IP, 還修改TCP和UDP協議的端口號, 這樣就能讓內網中的設備共用同一個外網IP. 舉個例子, NAPT維護一個相似下表的NAT表:安全

 
NAT映射


NAT設備會根據NAT表對出去和進來的數據作修改, 好比將192.168.0.3:8888發出去的封包改爲120.132.92.21:9202, 外部就認爲他們是在和120.132.92.21:9202通訊. 同時NAT設備會將120.132.92.21:9202收到的封包的IP和端口改爲192.168.0.3:8888, 再發給內網的主機, 這樣內部和外部就能雙向通訊了, 但若是其中192.168.0.3:8888 == 120.132.92.21:9202這一映射由於某些緣由被NAT設備淘汰了, 那麼外部設備就沒法直接與192.168.0.3:8888通訊了。服務器

 

咱們的設備常常是處在NAT設備的後面, 好比在大學裏的校園網, 查一下本身分配到的IP, 實際上是內網IP, 代表咱們在NAT設備後面, 若是咱們在寢室再接個路由器, 那麼咱們發出的數據包會多通過一次NAT.網絡

二. NAT的反作用以及解決方案

國內移動無線網絡運營商在鏈路上一段時間內沒有數據通信後, 會淘汰NAT表中的對應項, 形成鏈路中斷。架構

這是NAT帶來的第一個反作用:NAT超時:

而國內的運營商通常NAT超時的時間爲5分鐘,因此一般咱們TCP長鏈接的心跳設置的時間間隔爲3-5分鐘。**rest

而第二個反作用就是:咱們這邊文章要提到的NAT牆。

NAT會有一個機制,全部外界對內網的請求,到達NAT的時候,都會被NAT所丟棄,這樣若是咱們處於一個NAT設備後面,咱們將沒法獲得任何外界的數據。code

可是這種機制有一個解決方案:就是若是咱們A主動往B發送一條信息,這樣A就在本身的NAT上打了一個B的洞。這樣A的這條消息到達B的NAT的時候,雖然被丟掉了,可是若是B這個時候在給A發信息,到達A的NAT的時候,就能夠從A以前打的那個洞中,發送給到A手上了。orm

簡單來說,就是若是A和B要進行通訊,那麼得事先A發一條信息給B,B發一條信息給A。這樣提早在各自的NAT上打了對方的洞,這樣下一次A和B之間就能夠進行通訊了。路由

三. 四種NAT類型:

RFC3489 中將 NAT 的實現分爲四大類:io

  1. Full Cone NAT (徹底錐形 NAT)form

  2. Restricted Cone NAT (限制錐形 NAT ,能夠理解爲 IP 限制,Port不限制)

  3. Port Restricted Cone NAT (端口限制錐形 NAT,IP+Port 限制)

  4. Symmetric NAT (對稱 NAT)

其中徹底最上層的徹底錐形NAT的穿透性最好,而最下層的對稱形NAT的安全性最高。

簡單來說講這4種類型的NAT表明什麼:

  • 若是一個NAT是Full Cone NAT,那麼不管什麼IP地址訪問,都不會被NAT牆掉(這種基本不多)。
  • Restricted Cone NAT,僅僅是通過打洞的IP能穿越NAT,可是不限於Port。
  • Port Restricted Cone NAT,僅僅是通過打洞的IP+端口號能穿越NAT。
  • Symmetric NAT 這種也是僅僅是通過打洞的IP+端口號能穿越NAT,可是它有一個最大的和Cone類型的NAT的區別,它對外的公網Port是不停的變化的:
    好比A是一個對稱NAT,那麼A給B發信息,通過NAT映射到一個Port:10000,A給C發信息,通過NAT映射到一個Port:10001,這樣會致使一個問題,咱們服務器根本沒法協調進行NAT打洞。

至於爲何沒法協調打洞,下面咱們會從STUN和TURN的工做原理來說。

四. STUN和TURN的實現:

1.STUN Server主要作了兩件事:
  • 接受客戶端的請求,而且把客戶端的公網IP、Port封裝到ICE Candidate中。
  1. 經過一個複雜的機制,獲得客戶端的NAT類型。

完成了這些STUN Server就會這些基本信息發送回客戶端,而後根據NAT類型,來判斷是否須要TURN服務器協調進行下一步工做。

咱們來說講這兩步具體作了什麼吧:
第一件事就不用說了,其實就是獲得客戶端的請求,把源IP和Port拿到,添加到ICE Candidate中。

來說講第二件事,STUN是如何判斷NAT的類型的:

假設B是客戶端,C是STUN服務器,C有兩個IP分別爲IP1和IP2(至於爲何要兩個IP,接着往下看):

STEP1.判斷客戶端是否在NAT後:

B向C的IP1的pot1端口發送一個UDP 包。C收到這個包後,會把它收到包的源IP和port寫到UDP包中,而後把此包經過IP1和port1發還給B。這個IP和port也就是NAT的外網 IP和port(若是你不理解,那麼請你去看個人BLOG裏面的NAT的原理和分類),也就是說你在STEP1中就獲得了NAT的外網IP。

熟悉NAT工做原理的朋友能夠知道,C返回給B的這個UDP包B必定收到。若是在你的應用中,向一個STUN服務器發送數據包後,你沒有收到STUN的任何迴應包,那只有兩種可能:一、STUN服務器不存在,或者你弄錯了port。二、你的NAT拒絕一切UDP包從外部向內部經過。

當B收到此UDP後,把此UDP中的IP和本身的IP作比較,若是是同樣的,就說明本身是在公網,下步NAT將去探測防火牆類型,我不想多說。若是不同,說明有NAT的存在,系統進行STEP2的操做。

STEP2.判斷是否處於Full Cone Nat下:

B向C的IP1發送一個UDP包,請求C經過另一個IP2和PORT(不一樣與SETP1的IP1)向B返回一個UDP數據包(如今知道爲何C要有兩個IP了吧,雖然還不理解爲何,呵呵)。

咱們來分析一下,若是B收到了這個數據包,那說明什麼?說明NAT來着不拒,不對數據包進行任何過濾,這也就是STUN標準中的full cone NAT。遺憾的是,Full Cone Nat太少了,這也意味着你能收到這個數據包的可能性不大。若是沒收到,那麼系統進行STEP3的操做。

STEP3.判斷是否處於對稱NAT下:

B向C的IP2的port2發送一個數據包,C收到數據包後,把它收到包的源IP和port寫到UDP包中,而後經過本身的IP2和port2把此包發還給B。

和step1同樣,B確定能收到這個迴應UDP包。此包中的port是咱們最關心的數據,下面咱們來分析:
若是這個port和step1中的port同樣,那麼能夠確定這個NAT是個CONE NAT,不然是對稱NAT。道理很簡單:根據對稱NAT的規則,當目的地址的IP和port有任何一個改變,那麼NAT都會從新分配一個port使用,而在step3中,和step1對應,咱們改變了IP和port。所以,若是是對稱NAT,那這兩個port確定是不一樣的。

若是在你的應用中,到此步的時候PORT是不一樣的,那麼這個它就是處在一個對稱NAT下了。若是相同,那麼只剩下了restrict cone 和port restrict cone。系統用step4探測是是那一種。

STEP4.判斷是處於Restrict Cone NAT仍是Port Restrict NAT之下:

B向C的IP2的一個端口PD發送一個數據請求包,要求C用IP2和不一樣於PD的port返回一個數據包給B。

咱們來分析結果:若是B收到了,那也就意味着只要IP相同,即便port不一樣,NAT也容許UDP包經過。顯然這是Restrict Cone NAT。若是沒收到,沒別的好說,Port Restrict NAT.

到這裏STUN Server一共經過這4步,判斷出客戶端處於什麼類型的NAT下,而後去作後續的處理:

這4步都會返回給客戶端它的公網IP、Port和NAT類型,除此以外:

  1. 若是A處於公網或者Full Cone Nat下,STUN不作其餘的了,由於其餘客戶端能夠直接和A進行通訊。

     
  2. 若是A處於Restrict Cone或者Port Restrict NAT下,STUN還會協調TURN進行NAT打洞。

  3. 若是A處於對稱NAT下,那麼點對點鏈接下,NAT是沒法進行打洞的。因此爲了通訊,只能採起最後的手段了,就是轉成C/S架構了,STUN會協調TURN進行消息轉發。

2.TURN Server也主要作了兩件事:
  • 爲NAT打洞:

若是A和B要互相通訊,那麼TURN Server,會命令A和B互相發一條信息,這樣各自的NAT就留下了對方的洞,下次他們就能夠之間進行通訊了。

  • 爲對稱NAT提供消息轉發:

當A或者B其中一方是對稱NAT時,那麼給這一方發信息,就只能經過TURN Server來轉發了。

最後補充一下,爲何對稱NAT沒法打洞:

假如A、B進行通訊,而B處於對稱NAT之下,那麼A與B通訊,STUN拿到A,B的公網地址和端口號都爲10000,而後去協調TURN打洞,那麼TURN去命令A發信息給B,則A就在NAT打了個B的洞,可是這個B的洞是端口號爲10000的洞,可是下次B若是給A發信息,由於B是對稱NAT,它給每一個新的IP發送信息時,都從新對應一個公網端口,因此給A發送請求多是公網10001端口,可是A只有B的10000端口被打洞過,因此B的請求就被丟棄了。
顯然Server是沒法協調客戶端打洞的,由於協調客戶端打得洞僅僅是上次對端爲Server發送端口的洞,並不適用於另外一個請求。

最後的最後再補充一點,就是NAT打的洞也是具備時效性的,若是NAT超時了,那麼仍是須要從新打洞的。
相關文章
相關標籤/搜索