NAT 指的是網絡地址轉換(Netword Address Translation)。這一技術使得大部分人可以在家里用多于一臺的計算機上網但只用一個IP地址。多半時間里,一臺有NAT功能的路由器支持從內部 網絡(帶有內部IP地址)中取得數據,并將其發送到Internet,同時將每一個包的內部IP地址替換為外部地址。如下圖所示:
SIP協議的NAT穿越技術" src="http://files.chinaaet.com/images/2012/04/27/063b2459-cdfe-4794-8dd6-469a278ba5d3.jpg" />
SIP協議的NAT穿越技術
什么是RTP?
RTP 指的是實時傳輸協議(Real-Time Transport Protocol),這個協議的目的是在主叫和被叫之間傳輸語音數據。問題是,當你試圖用RTP協議呼叫一個人的時候,你要事先知道他的IP地址和端口號 (PORT),這使得RTP協議單獨使用起來有相當的困難,因為呼叫的雙方沒有辦法事先知道彼此的IP和端口。這就是為什么人們還需要SIP。
什么是SIP?
SIP 也就是會話初始協議(Session Initiation Protocol),語法上很象HTTP協議,是可讀的文本。它的目的是讓主叫方可以找到被叫方的IP和端口,同時它也幫助雙方協商媒體的類型和格式。比 如,你想通過家里的一臺PC機上運行的Free World Diadup(它使用SIP協議)來呼叫你遠在羅馬尼亞的朋友,如下圖:
SIP協議的NAT穿越技術
SIP發送一個INVITE包到FWD SERVER,其中包含有主叫方的RTP的IP地址和端口,FWD將這個包轉到對應的被叫方,被叫方接受了呼叫并將它自己的RTP的IP地址和端口返回來。
SIP+NAT,一個不能解決的問題?
SIP的NAT的問題,其實不是SIP的問題,而是RTP的問題。SIP來聲明RTP的地址和端口,但是如果客戶端在NAT之后的話,它聲明的端口就會與NAT在外部分配的不同。如下圖:
SIP協議的NAT穿越技術
即使很多SIP的實現都基于NAT總是分配一個與內網端口相同的一個外部端口這樣一個假設,但這個假設是錯誤的。在產品環境下,你不能告訴奶奶說她不能與孫子說話是因為有些路由器分配了一個不同的端口號。
SIP協議的NAT穿越技術
如果你是一個carrier,解決辦法要簡單一點,因為你要代理所有的數據,就是用SIP會話邊界控制器(SIP Session Border Controller),簡稱SIP SBC。SIP SBC通常位于carrier的內部SIP網絡的前面,它來解決NAT穿越問題,同時也保護SIP網絡。
SIP協議的NAT穿越技術
這種情況下解決NAT穿越問題需要一些小技巧。
第一個小技巧是讓NAT上從客戶端到服務器的洞保持打開狀態,這通常是讓SIP客戶端至少每隔30發送一個兩個字節的包到服務器。一些路由器會將30秒內沒用的映射顯式的刪除掉,GNU/Linux通常是3分鐘后才刪除。
第二個小技巧是在我們在yate項目中用到的,就是從到達服務器本地的RTP IP和端口的第一個包中計算客戶端的RTP IP和端口,而不是用在SDP中聲明的那個IP和端口。這個技巧可以解決NAT的穿越問題,不論客戶端在多少層NAT之后。這個方法的主要缺點是,在一些 情況下,客戶端不能收到起初的媒體流(since at that point, it sends out no voice packets)并將聽不到振鈴音。
如果你不是一個carrier,你想實現一個Peer to Peer的呼叫,并且呼叫的雙方都在NAT之后,你必須用一個外部的SIP代理或網關來在兩點之間傳遞SIP,希望NAT們一個接一個的為RTP接連打開 合適的端口。然而,對于這種情況,沒有最終的解決方案。兩個建議的解決方案是STUN和ICE,但是當前每個解決方案有時都可能達到的你目的。Skype 發現了一種非常簡單好用的解決這個問題的方法:他們用沒在NAT內的客戶端來做在NAT內的客戶端的代理。
SIP協議的NAT穿越技術
這個解決方案從技術上講是非常好的。但是,有一些道義和政策上的原因不能用Skype的方法。原因之一是,如果你是一個在NAT外的客戶端,你不知道誰的數據從你這里傳遞過去了。另一個原因是,這會占用你的帶寬。最后,你不得不為代理語音流而為多余的帶寬付費。
我個人希望在不久的將來有更多的SIP實現用YATE現在用的這兩個小技巧來實現NAT的穿越。Skype或許在長時間內還會在家庭用戶中廣為流傳,但是企 業用戶會慢慢的移向Voip提供者,隨著大量的努力和一點運氣,他們將會像PSTN提供者一個可靠,因為技術會越來越好。