此圖例以及以下圖例均來自于互聯(lián)網(wǎng)資源
就像kamailio創(chuàng)始人說的,cfg文件配置是一種藝術,通過各種配置可以實現(xiàn)SIP路由中很多非常復雜的功能。今天,我們通過OpenSIPS的實踐場景和大家分享NAT traversal的詳情介紹,如何通過OpenSIPS來解決NAT問題,以及OpenSIPS結(jié)合RTP Proxy通過一定的NAT穿越檢測手段來支持NAT穿越示例。
1、四種NAT類型的背景介紹
NAT traversal是互聯(lián)網(wǎng)中天然一直存在的問題,因為公網(wǎng)IP地址的短缺(IPv4),內(nèi)網(wǎng)安全考慮和網(wǎng)絡設計的考慮,大部分的企業(yè)內(nèi)網(wǎng)終端需要通過公網(wǎng)地址來映射到每個內(nèi)網(wǎng)地址。在歐洲,大約80%的用戶是在NAT環(huán)境下的用戶。經(jīng)過幾十年的發(fā)展,我們所面對的問題是,在NAT環(huán)境的VoIP網(wǎng)絡業(yè)務,除了SBC以外,始終沒有特別的設備來專門處理NAT穿越問題。因此,NAT穿越問題始終存在于企業(yè)網(wǎng)絡環(huán)境中,特別是在向云平臺遷移到過程中,SIP終端網(wǎng)絡安全,SIP服務器公網(wǎng)的安全問題更加突出。完整地解決NAT穿越是一個迫在眉睫的挑戰(zhàn)。
網(wǎng)絡上有很多關于NAT的原因,讀者可以查閱資料中進一步學習。在我們的SIP網(wǎng)絡中,大概存在4種NAT 類型,其具體四種類型包括:
- Full Cone
- Restricted Cone
- Port Restricted Cone
- Symmetric
關于NAT類型的具體的詳解,筆者在下面的文檔中有非常詳細介紹,讀者可以閱讀這些歷史文檔來學習,四種NAT的種類結(jié)合IP地址匹配可以簡單總結(jié)為以下示例:
在這具體的四種NAT類型中,前三種NAT類型解決方式非常簡單,利用Stun通過IP地址和端口都可以實現(xiàn)映射處理,并且處理NAT映射到方式也非常容易實現(xiàn)。筆者在以前發(fā)布的歷史文檔中有很多文章討論了各種手段來實現(xiàn)NAT穿越到解決方案,讀者可以參考閱讀:
在以上文章中筆者已經(jīng)非常完整地介紹了使用STUN,ALG設置,防火墻打洞的各種方式。特別是SBC的部署方式更加使得NAT問題已不再是一個非常難解決的問題。
但是,相當于其他三種NAT穿越方式來說,因為Symmetric NAT的NAT網(wǎng)絡處理機制具有非常大的不確定性,端口開放和內(nèi)網(wǎng)IP地址綁定相對比較隨意,所以穿越方式則相對比較復雜,因此解決這個問題的話需要STUN服務器結(jié)合一個RTP proxy來配合實現(xiàn)。通過這種方式基本上可以解決99%的NAT 穿越問題。在OpenSIPS中,解決Symmetric NAT的思路可以通過OpenSIPS服務器結(jié)合RTP proxy實現(xiàn)Symmetric NAT處理。
2、NAT對SIP頭的影響
在NAT環(huán)境中,因為NAT后的網(wǎng)絡對IP地址會進行處理,因此,NAT網(wǎng)絡中SIP的一些業(yè)務也會受到影響。解決NAT問題可以通過SIP終端網(wǎng)絡來解決,也可以通過SIP服務器端來解決。一般來說,如果通過SIP 客戶端來解決的話,用戶可以配置防火墻端口,ALG設置,STUN方式來實現(xiàn)。通過SIP服務器端處理的話,我們需要借助RTP Proxy來進行處理。網(wǎng)絡何種處理方式,在NAT穿越以后,我們經(jīng)常使用的一些比較重要的地址可能會發(fā)生變化,這樣就會導致語音單通等問題。受到NAT影響到SIP頭和SDP payload的 c行地址端口包括:
Via 頭
Contact 頭
Record Route
Route
SDP中的RTP 監(jiān)聽地址
INVITE sip:bob@slp.com SIP/2.0
Via: SIP/2.0/UDP 100.013:5060 //1
From: Alice <sip:alice@sip.com>
To: Bob <sip:bob@sip.com>
Call-lD: 12345600@10.0.0.13
CSeq: 1 INVITE
Contact: <sip:alice01000135060> // 2
Content-Type application/sdp
Content-Length:147
c=IN IP4 10.0.0.13 // 5
t=o o
……
因此,我們在使用OpenSIPS實現(xiàn)NAT穿越時需要根據(jù)一定的業(yè)務流程和呼叫來修改相應的地址實現(xiàn)呼叫的完整性。通過SIP信令和RTP 流調(diào)整來保證呼叫雙方的互通。
3、STUN-OpenSIPS和TURN和RTP Proxy的使用討論
前面我們已經(jīng)討論過,使用STUN和SIP 服務器可以解決大部分的NAT穿越問題(前三種NAT類型),通過STUN服務器端可以對在NAT后面的SIP終端進行廣播偵測查詢,SIP終端獲得NAT后的公網(wǎng)地址以后,SIP終端然后在進行INVITE呼叫,SIP終端呼叫時使用NAT公網(wǎng)地址對SIP服務器端進行呼叫。這樣就解決了NAT穿越的問題。
通過以上的幾個步驟可以解決前三種NAT穿越的問題。但是,因為Symmetric NAT本身的屬性問題,Symmetric NAT本身可能開放不同的端口,STUN的局限性就很難滿足對稱NAT環(huán)境的要求,所以借助STUN結(jié)合OpenSIPS的方式進行NAT穿越的話,NAT穿越就可能失敗。因為,Symmetric NAT環(huán)境下,在NAT網(wǎng)絡環(huán)境下,不同終端可能會通過不同的端口來進行呼叫。端口不同,SIP信令和RTP流可能產(chǎn)生錯誤的流向,RTP流可能會流向錯誤的地址。因此,在Symmetric NAT環(huán)境中,我們不僅僅需要解決SIP 信令的問題,我們還要解決Symmetric 媒體的流向管理。Symmetric 媒體的處理原則目前采取了一種比較“聰明”的辦法來解決這個問題,公網(wǎng)服務器端收到一個帶內(nèi)網(wǎng)IP的SDP的時候,其基本思路如下(其中一側(cè)處于公網(wǎng)地址):
- 忽略這個內(nèi)網(wǎng)IP地址和端口(因為是內(nèi)網(wǎng)地址,屬于無效地址和端口)
- 繼續(xù)等待,收到RTP語音流以后,通過RTP語音流的地址和端口確定真正的初始IP和端口
- 根據(jù)以上收到的RTP流的IP地址和端口,把此IP地址和端口作為未來發(fā)送RTP語音流的目的地地址和端口
這種Symmetric 媒體的處理方式可以解決Symmetric NAT環(huán)境媒體的問題。但是,Symmetric NAT環(huán)境中必須要求一方是在公網(wǎng)環(huán)境中。
但是,如果呼叫方和被呼叫方都在NAT后的話,Symmetric NAT方式仍然不能獲得完美的支持。在實際生產(chǎn)環(huán)境中,雙方SIP終端都在NAT后的可能性也非常大,因此,為了徹底解決SIP終端在NAT后的穿越問題,Symmetric NAT需要借助于TURN媒體轉(zhuǎn)發(fā)的能力來解決。
通過以上介紹,結(jié)合歷史文檔介紹,我們知道,事實上,目前市場上沒有一個完整的解決方案來滿足所有的NAT類型,它們都有各自的優(yōu)缺點和其局限性:
- ALG方式-通過終端路由器防火墻來處理,相對比較有效率,可以支持各種設備的分布式處理,但是因為SIP終端的路由器具備良好的的NAT支持
- STUN方式-非常高效,具備分布式部署方式,但是不能支持所有的NAT類型
- Symmetric 信令和媒體的處理方式,此僅僅方案可以支持所有的NAT類型,不依賴于客戶端配置,但是要求一方必須是公網(wǎng)地址
- Symmetric 信令加TURN方式,可以支持所有的NAT類型,雙方都可以在NAT后,但是,因為依賴于TURN 轉(zhuǎn)發(fā)處理,因此,這種處理方式缺乏良好的擴展性。目前看,這種方式是相對比較完整的解決方案。
在第四種方案中,通過OpenSIPS平臺,OpenSIPS借助于媒體轉(zhuǎn)發(fā)TURN可以實現(xiàn)SIP終端都在NAT環(huán)境的呼叫流程。這里,媒體轉(zhuǎn)發(fā)的處理機制實際上是通過公網(wǎng)的RTP Proxy來實現(xiàn)。RTP Proxy作為一個B2B引擎,雙方SIP呼叫通過RTP proxy轉(zhuǎn)發(fā)來建立一個橋接流程,保證RTP流正常處理;贠penSIPS實現(xiàn)NAT穿越到基本處理流程包括:
- 通過OpenSIPS cfg 腳本檢測NAT環(huán)境,管理SIP信令
- 在SIP注冊方面,通過OpenSIPS 模塊實現(xiàn)打洞或者Keepalive方式保持SIP的注冊狀態(tài)
- OpenSIPS協(xié)同媒體轉(zhuǎn)發(fā)實現(xiàn)RTP 流的流向處理
4、OpenSIPS結(jié)合RTP引擎實現(xiàn)SIP注冊和呼叫的NAT穿越
上一個章節(jié)筆者介紹了關于在OpenSIPS環(huán)境下結(jié)合RTP引擎實現(xiàn)NAT穿越的基本思路。但是,在實際部署中,筆者仍然需要考慮OpenSIPS本身所扮演的功能角色。因為OpenSIPS本身支持的功能比較復雜,而且處理流程也非常靈活。用戶如果沒有考慮的不全面的話,OpenSIPS可能會充當太多的角色,最終OpenSIPS的腳本就會非常復雜,不利于維護和拓展。因此,我們有必要針對OpenSIPS的角色做一點補充討論。用戶在穿越處理中使用的比較多的是注冊穿越處理和呼叫穿越處理流程。我們將重點介紹這兩種NAT穿越的具體邏輯處理流程。
筆者建議用戶在考慮OpenSIPS作為NAT穿越方案部署時,可以通過兩種方式的部署來評價解決方案的可行性:
OpenSIPS作為一個Proxy實現(xiàn)SBC功能,實現(xiàn)其他業(yè)務功能。這樣的處理方式非常緊湊,高效,可實現(xiàn)一定的擴展。但是,這種方式會增加cfg腳本的復雜程度。
在OpenSIPS前端部署一個SBC,專門處理NAT穿越。SBC作為一個專門的NAT穿越工具,降低了Proxy的腳本復雜程度,同時可以支持多地云分布式部署方式。這樣的部署方式會增加前端的部署成本,需要更多的數(shù)據(jù)備份容災的解決方案。目前,基于云平臺的SBC越來越受到青睞,很多解決方案提供商提供前端SBC實現(xiàn)SIP trunk均衡負載,NAT穿越和SIP注冊等問題,極大降低了后端業(yè)務系統(tǒng)的負載和復雜程度。
OpenSIPS平臺可以通過SIP NAT穿越模塊和RTP引擎模塊實現(xiàn)NAT穿越,其模塊包括:
- nathelper和rtpproxy
- nat_traversal和mediaproxy
通過NAT模塊和媒體模塊實現(xiàn)SIP頭,SDP的管理,并且可以實現(xiàn)和外部RTP轉(zhuǎn)發(fā)處理。以上兩種方式非固定的搭配模式,它們可以任意組合。更多關于以上模塊的詳解說明,讀者可以參考官方文檔做進一步了解。接下來,我們具體介紹OpenSIPS實現(xiàn)NAT穿越到基本步驟。
首先,OpenSIPS需要檢測NAT環(huán)境。通常情況下,NAT檢測是在初始SIP請求中進行檢測。后續(xù)的其他請求依賴于初始請求的檢測結(jié)果。測試發(fā)送方是否在NAT環(huán)境中,OpenSIPS可以根據(jù):
- Contact URL,IP地址部分
- Via地址和端口相對于收到的請求中的地址和端口
- SDP中IP地址類別
OpenSIPS具體的實現(xiàn)腳本如下:
# 使用bitmask檢查,檢查 VIA 是否是一個內(nèi)網(wǎng) (4)或者VIA端口不同
# 網(wǎng)絡層級的端口(16-Via port 和源地址端口的不同),設置總值為(20=1+4)
if (nat uac_ test(20)) {setflag("NATED_ SRC' '); }
# 標識為帶NAT的地址
另外一個需要檢測到是NAT環(huán)境中的SIP終端注冊狀態(tài)。OpenSIPS檢測如果發(fā)送方注冊是一個NAT網(wǎng)絡的話,OpenSIPS將會通過用戶位置模塊保存注冊信息(usrloc):
- 保存Contact 中的地址信息作為候選溝通的IP地址,事實上是一個內(nèi)網(wǎng)的IP地址。
- 保存注冊方的公網(wǎng)IP地址和端口,如果是NAT環(huán)境中的客戶端,注冊服務器需要知道從何公網(wǎng)地址進入注冊。
- 如果判斷出注冊用戶是一個NAT用戶的話,需要保存其標識狀態(tài)。
當OpenSIPS對注冊方發(fā)送請求時,前面收到的Contact URL將作為一個RURI來處理,已保存的公網(wǎng)源地址和端口作為outbound proxy地址來處理。具體的腳本處理流程如下:
modparam("usrloc", "nat_ bflag", "NATED_ DST")
if(is_ method("REGISTER")){
if(nat_uac_test(20) ){
fix_nated_register(); # 保存注冊源地址和端口(IP和port)
setbflag("NATED_ DST"); # 標識為NAT網(wǎng)絡,branch flag(b flag)
}
save("location");
}
我們已經(jīng)通過以上腳本對SIP 注冊狀態(tài)執(zhí)行了保存。但是,大家都知道,注冊狀態(tài)不是一個一次性處理的過程,維持注冊狀態(tài)需要SIP客戶端不斷向SIP服務器端發(fā)送ping消息,以便讓服務器端獲悉其存活狀態(tài)實現(xiàn)NAT keepalive。另外,因為SIP用戶是在NAT網(wǎng)絡環(huán)境中,SIP終端需要對NAT網(wǎng)絡環(huán)境進行打洞處理,需要保持其端口持續(xù)開放活動狀態(tài)。SIP客戶端和服務器端需要周期性地執(zhí)行NAT打洞處理,發(fā)送數(shù)據(jù)來保持端口的活動狀態(tài),避免讓NAT打洞的狀態(tài)關閉。如果SIP狀態(tài)沒有偵測到的話,可能出現(xiàn)SIP呼叫超時等問題。在OpenSIPS環(huán)境中,我們可以使用兩種方式實現(xiàn)打洞處理:
使用UDP ping方式,使用一個偽裝的UDP數(shù)據(jù)包作為一個偵測數(shù)據(jù)包,生成方式相對比較簡單,但是這是一種僅支持呼入方向的單向(服務器端到客戶端)數(shù)據(jù)包偵測方式。偵測方向數(shù)據(jù)僅從公網(wǎng)到了內(nèi)網(wǎng)終端。但是,通常情況下,內(nèi)網(wǎng)終端執(zhí)行狀態(tài)更新時僅是通過內(nèi)網(wǎng)到公網(wǎng)發(fā)送數(shù)據(jù)時才更新,因此,這種方式缺乏可靠性支持。
使用SIP ping方式,使用SIP options消息數(shù)據(jù)包作為一個偵測數(shù)據(jù)包,生成方式相對比較復雜,但是,SIP客戶端可以生成一個返回的消息,偵測數(shù)據(jù)包流向是雙向的,因此,可靠性更好,并且會生成大量的options消息數(shù)據(jù)。
OpenSIPS對SIP注冊執(zhí)行偵測的邏輯腳本如下:
modparam("usrloc", "nat_ bflag", "NATED_ SRC")
# 每20 秒,ping一次
modparam(" nathelper", "natping_ interval", 20)
# 僅對contacts 標識為NAT的終端執(zhí)行ping 偵測
modparam(" nathelper", "ping_ nated_ only", 1)
# 執(zhí)行 SIP pinging (with OPTIONS)
modparam(' 'nathelper", "sipping_ bflag", "NATED_ DST")
除了檢測SIP注冊穿越到處理方式以外,SIP用戶也同樣需要檢測在SIP呼叫過程中的NAT穿越問題處理。如果沒有檢測到NAT穿越到身份,SIP INVITE呼叫同樣也會面臨呼叫失敗的可能。現(xiàn)在,我們討論一下在OpenSIPS中如何檢測和處理INVITE的NAT穿越問題。在SIP INVITE呼叫過程中,我們需要針對呼叫方和被呼叫方根據(jù)注冊標識保存的信息進行NAT穿越的檢測。OpenSIPS分別通過各自的檢測方式對其身份進行檢查,然后執(zhí)行呼叫:
檢測呼叫方是否在NAT環(huán)境中,如果在的話,使用源公網(wǎng)地址IP和端口修改其內(nèi)網(wǎng)conatct URL地址,保證其呼叫路由可以正常執(zhí)行。因為Contact URL是一個來自于內(nèi)網(wǎng)的地址,如果沒有修改contact URL的話,可能造成后續(xù)請求路由失敗,例如ACK返回失敗等問題。
檢測被呼叫方是否在NAT環(huán)境中,這里需要注意,因為被呼叫方可能是一個NAT環(huán)境的SIP賬號,也可能是第三方其他服務器端設備,所以執(zhí)行INVITE流程時可以通過兩種方式處理。如果被呼叫方不是NAT標識用戶,則可以通過其他路由方式進行INVITE處理。
在進行INVITE前轉(zhuǎn)之前,至少確認其中一個SIP終端是一個NAT環(huán)境中的設備,這樣就可以觸發(fā)RTP proxy代理工作流程,把SDP中的內(nèi)網(wǎng)地址IP和端口替換為一個公網(wǎng)IP地址和端口實現(xiàn)媒體代理轉(zhuǎn)發(fā)。
在INVITE執(zhí)行以后,OpenSIPS仍然需要檢測INVITE返回的信息,例如失敗消息或者200 OK等成功返回的信息。如果是INVITE呼叫返回了失敗的消息的話,OpenSIPS將關閉RTP 轉(zhuǎn)發(fā)的處理流程,不再繼續(xù)RTP 轉(zhuǎn)發(fā)處理。如果INVITE呼叫返回了 200 OK消息的話,表示媒體轉(zhuǎn)發(fā)處理是確認狀態(tài)。OpenSIPS在確認了媒體轉(zhuǎn)發(fā)處理以后,它將會更新SDP中的內(nèi)網(wǎng)地址和端口,使用源公網(wǎng)地址IP和端口來替換SDP內(nèi)網(wǎng)地址以便雙方通過RTP媒體轉(zhuǎn)發(fā)服務器進行RTP交互或者B2B 媒體處理。如果目的地地址檢測到是一個NAT環(huán)境終端的話,根據(jù)標識進行處理,使用其公網(wǎng)地址替換Contact URL中的內(nèi)網(wǎng)地址。關于OpenSIPS在INVITE呼叫中NAT穿越的處理方式如下:
注意,在以上關于INVITE呼叫的NAT標識中,OpenSIPS必須同時對呼叫源地址和目的地地址進行NAT標識,另外在呼叫目的地的標識中需要使用“b”flag進行標識。因為通常情況下,一些呼叫是一個fork呼叫,可能出現(xiàn)很多分叉呼叫,呼叫目的地可能是幾個目的地地址,因此使用“b”-branch 的flag做標識處理,否則可能出現(xiàn)分叉呼叫返回的消息失敗,或者無法處理后續(xù)dialog流程。關于OpenSIPS實現(xiàn)INVITE 呼叫NAT穿越的示例如下:
在以上示例中,筆者簡單介紹了關于OpenSIPS結(jié)合媒體轉(zhuǎn)發(fā)服務器的處理流程,其流程大概經(jīng)過五個步驟的處理(SIP終端分別在各自的NAT環(huán)境中,通過RTP 轉(zhuǎn)發(fā)實現(xiàn)語音通信):
- 首先,帶NAT的呼叫方呼叫OpenSIPS服務器端,OpenSIPS服務器檢測NAT,修改Contact URL為NAT公網(wǎng)地址,然后修改SDP地址為RTP 媒體轉(zhuǎn)發(fā)服務器地址。
- OpenSIPS服務器繼續(xù)對對端Bob進行呼叫,并且攜帶更新后的Contact地址和SDP地址。
- Bob對INVITE返回200 OK,攜帶自己的內(nèi)網(wǎng)地址和SDP內(nèi)網(wǎng)地址。
- OpenSIPS經(jīng)過NAT處理檢測,然后返回到Alice 端,并且修改了Contact 地址和SDP的媒體轉(zhuǎn)發(fā)服務器地址,通知Alice,BobContact地址是NAT的公網(wǎng)地址,SDP地址更新為RTP 媒體轉(zhuǎn)發(fā)服務器地址。RTP語音流將通過RTP 轉(zhuǎn)發(fā)服務器進行B2B轉(zhuǎn)發(fā)處理
- Alice和Bob雙方通過RTP 轉(zhuǎn)發(fā)媒體服務器進行RTP的流程處理,雙方通過RTP服務器進行語音創(chuàng)建和通信。
以上是一個完整的OpenSIPS結(jié)合RTP轉(zhuǎn)發(fā)服務器處理INVITE NAT穿越的流程示例。但是,很多時候,我們僅僅關注了INVITE的處理,可能會忽略一些其他的業(yè)務處理,例如,有時SIP用戶可能重新發(fā)起re-INVITE 流程(例如SIP鍵盤的HOLD功能)。在re-INVITE的處理流程中,其處理邏輯和INVITE流程非常相似,一個比較大的區(qū)別就是無需在呼叫方和被呼叫方之間再進行NAT檢測,可以通過dialog進行記錄或者通過contact標識標志其SIP終端是一個NAT的終端。無論采取何種方式實現(xiàn)其標識的重新認證,OpenSIPS必須確保在re-INVITE以后,RTP轉(zhuǎn)發(fā)代理必須強制使用新的SDP更新的地址和端口,否則,SIP發(fā)起re-INVITE以后可能導致雙方無語音的問題。
前面,我們介紹了注冊的NAT穿越解決思路和INVITE NAT穿越的解決辦法,對于其他的非INVITE處理,NAT穿越的處理流程和INVITE基本一致,但是,OpenSIPS需要忽略媒體部分的處理。
另外,在我們的示例中,我們列舉了在UDP的檢測環(huán)境。以上的討論目前沒有針對TCP的SIP檢測。如果SIP端是通過TCP注冊的話,在OpenSIPS腳本中需要忽略TCP檢測,使用UDP檢測方式。
介紹了注冊業(yè)務中使用NAT穿越的方式和呼叫流程中使用NAT穿越的細節(jié)以外,筆者將通過一個OpenSIPS配置示例說明其完整的NAT穿越流程。
5、OpenSIPS結(jié)合RTP媒體轉(zhuǎn)發(fā)服務器配置示例
在本章節(jié)中,筆者將通過OpenSIPS結(jié)合RTP Proxy配置示例說明如何實現(xiàn)SIP注冊的NAT穿越和呼叫的NAT穿越。配置NAT穿越需要經(jīng)過以下幾個步驟:
首先,用戶需要開啟防火墻配置,保證需要的端口都在開啟狀態(tài):
- ufw allow 5060
- ufw allow 9999 // 避免ALG 過濾,使用了9999端口
- 然后在cfg配置腳本中監(jiān)聽此端口
- ocket=udp:eth0:9999
檢查RTP proxy配置。筆者已經(jīng)在同一OpenSIPS服務器安裝了RTPProxy,用戶通過配置文件檢查rtpproxy配置,默認路徑是:
etc/default/rtpproxy, OpenSIPS通過127.0.0.1 端口 7899 監(jiān)聽socket事件
然后確認RTPProxy啟動,或者使用以下命令檢查:
netstat -ulnp | grep rtpproxy
service rtpproxy start
啟動了rtpproxy以后,用戶可以修改opensips的cfg配置文件注冊NAT穿越,增加相應的模塊和參數(shù)配置:
modparam("usrloc","nat_bflag","NATED_CALLEE")
modparam("registrar", "received_avp", "$avp(rcv)")
#加載NAT模塊配置:
loadmodule "nathelper.so"
modparam("nathelper", "received_avp", "$avp(rcv)")
modparam("nathelper", "natping_interval", 30)
modparam("nathelper", "ping_nated_only", 1)
modparam("nathelper", "sipping_bflag", "SIPPING_FLAG")
modparam("nathelper", "sipping_from", "sip:pinger@sip.domain.com")
#加載RTPproxy配置:
loadmodule "rtpproxy.so"
modparam("rtpproxy", "db_url",
"mysql://opensips:opensipsrw@localhost/opensips")
modparam("rtpproxy", "default_set", 1)
在腳本流程中增加NAT檢測:
force_rport();
if (nat_uac_test(18))
setflag('NATED_CALLER');
在注冊和呼叫的邏輯中增加NAT處理流程:
route(handle_nat);
針對呼叫目的地進行NAT檢測:
if (ruri_has_param("nat","yes")) // Contact URL檢測
setbflag('NATED_CALLEE');
增加注冊NAT穿越的檢測和保存其狀態(tài),并且執(zhí)行ping命令:
if (isflagset('NATED_CALLER')) {
fix_nated_register();
setbflag('NATED_CALLEE');
setbflag('SIPPING_FLAG');
}
如果呼叫方或被呼叫方在NAT后的話,啟動RTPProxy:
if (isflagset('NATED_CALLER') || isbflagset('NATED_CALLEE')) {
if (has_body("application/sdp"))
rtpproxy_answer("co");
}
# if callee (sender or this reply) is nated, fix it
if ( isbflagset('NATED_CALLEE') )
fix_nated_contact(";nat=yes");
配置好以上腳本邏輯以后,用戶需要通過GUI控制界面添加RTPProxy配置設置:
點擊“Reload on Server”按鈕,重新加載RTP代理服務器,確保成功加載。通過控制界面,查看SIP 用戶的注冊狀態(tài)(Users -> User Management),點擊user,會顯示contact地址和收到的地址消息。使用OpenSIPS 服務器地址作為outbound proxy地址,關閉STUN設置。
兩個都在NAT后的SIP可以進行呼叫來觀察其IP地址的變化。另外,用戶通過按鍵HOLD重新啟動可以觀察經(jīng)過re-INVITE呼叫以后,檢查雙方語音是否丟,SDP是否更新等規(guī)則數(shù)據(jù)。如果reINVITE正常的話,SDP的數(shù)據(jù)應該也是得到了相應的更新。
在進一步的測試中,用戶可以使用sngrep 跟蹤INVITE的Contact URL地址和SDP中的RTP地址流向來判斷是否通過OpenSIPS執(zhí)行了NAT穿越處理。
200 OK的返回消息跟蹤數(shù)據(jù),注意其Contact URL和SDP中的c=行地址。
在200 OK返回的消息中,我們可以看到SDP的地址修改為RTPProxy或者OpenSIPS的地址(同一臺服務器)。Contact URL修改為NAT公網(wǎng)地址。再次說明,在針對INVITE 呼叫的NAT穿越的排查過程中,為了簡單方便,用戶應該實現(xiàn)注意是否返回了200 OK,并且一定要檢查 200 OK中的Contact URL和SDP中的地址是否是RTPProxy地址。通過 200 OK返回消息可以快速排查問題。
為了避免終端的ALG問題,因為我們在cfg文件中監(jiān)聽了9999端口,用戶可以通過抓包根據(jù)查看端口9999的數(shù)據(jù)流狀態(tài)判斷ALG的設置和RTPproxy的流向。
6、總結(jié)
筆者在本文章中完整介紹了NAT穿越到基本原理,NAT穿越中所面對的挑戰(zhàn)和一些NAT穿越到局限性。通過SIP代理加RTPProxy可以完美解決了大部分的NAT穿越問題,通過OpenSIPS的配置示例說明了配置的具體操作流程。
在文章中,筆者首先介紹了NAT的背景知識和目前各種NAT穿越所面對的問題。然后筆者介紹了通過對稱網(wǎng)絡方式結(jié)合TRUN服務器來解決SIP終端雙方都在NAT后的思路。在進一步的討論中,通過OpenSIPS結(jié)合RTPProxy實現(xiàn)雙方SIP都在NAT后的SIP注冊處理,SIP呼叫處理。在NAT檢測過程中,OpenSIPS經(jīng)過三個步驟對NAT后設備進行檢查,保存和標識。
在最后,筆者通過OpenSIPS結(jié)合RTPProxy的配置示例說明如何實現(xiàn)NAT穿越和NAT穿越到測試。
因為資源和環(huán)境有限,筆者沒有繼續(xù)討論關于SIP在TCP注冊方式的進一步處理和非INVITE業(yè)務場景中NAT穿越到討論。希望在未來的討論中能夠增加這些知識點的分享。另外,因為不同業(yè)務場景中的OpenSIPS cfg配置文件可能有所不同,用戶在配置cfg文件時需要根據(jù)自己的具體情況加以調(diào)整,這里沒有一個統(tǒng)一的處理流程,需要讀者自己不斷實踐。
參考資料:
https://docs.telcobridges.com/tbwiki/Toolpack:SIP_Configuration_For_Remote_Symmetric_NAT_Traversal_A
www.freesbc.cn
www.rbbn.cn Ribbon SBC
- 融合通信/IPPBX/FreePBX商業(yè)解決方案:www.hiastar.com
- 最新Asterisk完整中文用戶手冊詳解:www.asterisk.org.cn
- Freepbx/FreeSBC技術文檔: www.freepbx.org.cn
- 如何使用免費會話邊界控制器-FreeSBC,qq技術分享群:334023047
- 關注微信公眾號:asterisk-cn,獲得有價值的通信行業(yè)技術分享