
此圖例以及以下圖例均來(lái)自于互聯(lián)網(wǎng)資源
就像kamailio創(chuàng)始人說(shuō)的,cfg文件配置是一種藝術(shù),通過(guò)各種配置可以實(shí)現(xiàn)SIP路由中很多非常復(fù)雜的功能。今天,我們通過(guò)OpenSIPS的實(shí)踐場(chǎng)景和大家分享NAT traversal的詳情介紹,如何通過(guò)OpenSIPS來(lái)解決NAT問(wèn)題,以及OpenSIPS結(jié)合RTP Proxy通過(guò)一定的NAT穿越檢測(cè)手段來(lái)支持NAT穿越示例。
1、四種NAT類(lèi)型的背景介紹
NAT traversal是互聯(lián)網(wǎng)中天然一直存在的問(wèn)題,因?yàn)楣W(wǎng)IP地址的短缺(IPv4),內(nèi)網(wǎng)安全考慮和網(wǎng)絡(luò)設(shè)計(jì)的考慮,大部分的企業(yè)內(nèi)網(wǎng)終端需要通過(guò)公網(wǎng)地址來(lái)映射到每個(gè)內(nèi)網(wǎng)地址。在歐洲,大約80%的用戶(hù)是在NAT環(huán)境下的用戶(hù)。經(jīng)過(guò)幾十年的發(fā)展,我們所面對(duì)的問(wèn)題是,在NAT環(huán)境的VoIP網(wǎng)絡(luò)業(yè)務(wù),除了SBC以外,始終沒(méi)有特別的設(shè)備來(lái)專(zhuān)門(mén)處理NAT穿越問(wèn)題。因此,NAT穿越問(wèn)題始終存在于企業(yè)網(wǎng)絡(luò)環(huán)境中,特別是在向云平臺(tái)遷移到過(guò)程中,SIP終端網(wǎng)絡(luò)安全,SIP服務(wù)器公網(wǎng)的安全問(wèn)題更加突出。完整地解決NAT穿越是一個(gè)迫在眉睫的挑戰(zhàn)。

網(wǎng)絡(luò)上有很多關(guān)于NAT的原因,讀者可以查閱資料中進(jìn)一步學(xué)習(xí)。在我們的SIP網(wǎng)絡(luò)中,大概存在4種NAT 類(lèi)型,其具體四種類(lèi)型包括:
- Full Cone
- Restricted Cone
- Port Restricted Cone
- Symmetric
關(guān)于NAT類(lèi)型的具體的詳解,筆者在下面的文檔中有非常詳細(xì)介紹,讀者可以閱讀這些歷史文檔來(lái)學(xué)習(xí),四種NAT的種類(lèi)結(jié)合IP地址匹配可以簡(jiǎn)單總結(jié)為以下示例:

在這具體的四種NAT類(lèi)型中,前三種NAT類(lèi)型解決方式非常簡(jiǎn)單,利用Stun通過(guò)IP地址和端口都可以實(shí)現(xiàn)映射處理,并且處理NAT映射到方式也非常容易實(shí)現(xiàn)。筆者在以前發(fā)布的歷史文檔中有很多文章討論了各種手段來(lái)實(shí)現(xiàn)NAT穿越到解決方案,讀者可以參考閱讀:
在以上文章中筆者已經(jīng)非常完整地介紹了使用STUN,ALG設(shè)置,防火墻打洞的各種方式。特別是SBC的部署方式更加使得NAT問(wèn)題已不再是一個(gè)非常難解決的問(wèn)題。

但是,相當(dāng)于其他三種NAT穿越方式來(lái)說(shuō),因?yàn)镾ymmetric NAT的NAT網(wǎng)絡(luò)處理機(jī)制具有非常大的不確定性,端口開(kāi)放和內(nèi)網(wǎng)IP地址綁定相對(duì)比較隨意,所以穿越方式則相對(duì)比較復(fù)雜,因此解決這個(gè)問(wèn)題的話需要STUN服務(wù)器結(jié)合一個(gè)RTP proxy來(lái)配合實(shí)現(xiàn)。通過(guò)這種方式基本上可以解決99%的NAT 穿越問(wèn)題。在OpenSIPS中,解決Symmetric NAT的思路可以通過(guò)OpenSIPS服務(wù)器結(jié)合RTP proxy實(shí)現(xiàn)Symmetric NAT處理。
2、NAT對(duì)SIP頭的影響
在NAT環(huán)境中,因?yàn)镹AT后的網(wǎng)絡(luò)對(duì)IP地址會(huì)進(jìn)行處理,因此,NAT網(wǎng)絡(luò)中SIP的一些業(yè)務(wù)也會(huì)受到影響。解決NAT問(wèn)題可以通過(guò)SIP終端網(wǎng)絡(luò)來(lái)解決,也可以通過(guò)SIP服務(wù)器端來(lái)解決。一般來(lái)說(shuō),如果通過(guò)SIP 客戶(hù)端來(lái)解決的話,用戶(hù)可以配置防火墻端口,ALG設(shè)置,STUN方式來(lái)實(shí)現(xiàn)。通過(guò)SIP服務(wù)器端處理的話,我們需要借助RTP Proxy來(lái)進(jìn)行處理。網(wǎng)絡(luò)何種處理方式,在NAT穿越以后,我們經(jīng)常使用的一些比較重要的地址可能會(huì)發(fā)生變化,這樣就會(huì)導(dǎo)致語(yǔ)音單通等問(wèn)題。受到NAT影響到SIP頭和SDP payload的 c行地址端口包括:
Via 頭
Contact 頭
Record Route
Route
SDP中的RTP 監(jiān)聽(tīng)地址
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
……
因此,我們?cè)谑褂肙penSIPS實(shí)現(xiàn)NAT穿越時(shí)需要根據(jù)一定的業(yè)務(wù)流程和呼叫來(lái)修改相應(yīng)的地址實(shí)現(xiàn)呼叫的完整性。通過(guò)SIP信令和RTP 流調(diào)整來(lái)保證呼叫雙方的互通。
3、STUN-OpenSIPS和TURN和RTP Proxy的使用討論
前面我們已經(jīng)討論過(guò),使用STUN和SIP 服務(wù)器可以解決大部分的NAT穿越問(wèn)題(前三種NAT類(lèi)型),通過(guò)STUN服務(wù)器端可以對(duì)在NAT后面的SIP終端進(jìn)行廣播偵測(cè)查詢(xún),SIP終端獲得NAT后的公網(wǎng)地址以后,SIP終端然后在進(jìn)行INVITE呼叫,SIP終端呼叫時(shí)使用NAT公網(wǎng)地址對(duì)SIP服務(wù)器端進(jìn)行呼叫。這樣就解決了NAT穿越的問(wèn)題。

通過(guò)以上的幾個(gè)步驟可以解決前三種NAT穿越的問(wèn)題。但是,因?yàn)镾ymmetric NAT本身的屬性問(wèn)題,Symmetric NAT本身可能開(kāi)放不同的端口,STUN的局限性就很難滿(mǎn)足對(duì)稱(chēng)NAT環(huán)境的要求,所以借助STUN結(jié)合OpenSIPS的方式進(jìn)行NAT穿越的話,NAT穿越就可能失敗。因?yàn),Symmetric NAT環(huán)境下,在NAT網(wǎng)絡(luò)環(huán)境下,不同終端可能會(huì)通過(guò)不同的端口來(lái)進(jìn)行呼叫。端口不同,SIP信令和RTP流可能產(chǎn)生錯(cuò)誤的流向,RTP流可能會(huì)流向錯(cuò)誤的地址。因此,在Symmetric NAT環(huán)境中,我們不僅僅需要解決SIP 信令的問(wèn)題,我們還要解決Symmetric 媒體的流向管理。Symmetric 媒體的處理原則目前采取了一種比較“聰明”的辦法來(lái)解決這個(gè)問(wèn)題,公網(wǎng)服務(wù)器端收到一個(gè)帶內(nèi)網(wǎng)IP的SDP的時(shí)候,其基本思路如下(其中一側(cè)處于公網(wǎng)地址):
- 忽略這個(gè)內(nèi)網(wǎng)IP地址和端口(因?yàn)槭莾?nèi)網(wǎng)地址,屬于無(wú)效地址和端口)
- 繼續(xù)等待,收到RTP語(yǔ)音流以后,通過(guò)RTP語(yǔ)音流的地址和端口確定真正的初始IP和端口
- 根據(jù)以上收到的RTP流的IP地址和端口,把此IP地址和端口作為未來(lái)發(fā)送RTP語(yǔ)音流的目的地地址和端口
這種Symmetric 媒體的處理方式可以解決Symmetric NAT環(huán)境媒體的問(wèn)題。但是,Symmetric NAT環(huán)境中必須要求一方是在公網(wǎng)環(huán)境中。

但是,如果呼叫方和被呼叫方都在NAT后的話,Symmetric NAT方式仍然不能獲得完美的支持。在實(shí)際生產(chǎn)環(huán)境中,雙方SIP終端都在NAT后的可能性也非常大,因此,為了徹底解決SIP終端在NAT后的穿越問(wèn)題,Symmetric NAT需要借助于TURN媒體轉(zhuǎn)發(fā)的能力來(lái)解決。
通過(guò)以上介紹,結(jié)合歷史文檔介紹,我們知道,事實(shí)上,目前市場(chǎng)上沒(méi)有一個(gè)完整的解決方案來(lái)滿(mǎn)足所有的NAT類(lèi)型,它們都有各自的優(yōu)缺點(diǎn)和其局限性:
- ALG方式-通過(guò)終端路由器防火墻來(lái)處理,相對(duì)比較有效率,可以支持各種設(shè)備的分布式處理,但是因?yàn)镾IP終端的路由器具備良好的的NAT支持
- STUN方式-非常高效,具備分布式部署方式,但是不能支持所有的NAT類(lèi)型
- Symmetric 信令和媒體的處理方式,此僅僅方案可以支持所有的NAT類(lèi)型,不依賴(lài)于客戶(hù)端配置,但是要求一方必須是公網(wǎng)地址
- Symmetric 信令加TURN方式,可以支持所有的NAT類(lèi)型,雙方都可以在NAT后,但是,因?yàn)橐蕾?lài)于TURN 轉(zhuǎn)發(fā)處理,因此,這種處理方式缺乏良好的擴(kuò)展性。目前看,這種方式是相對(duì)比較完整的解決方案。
在第四種方案中,通過(guò)OpenSIPS平臺(tái),OpenSIPS借助于媒體轉(zhuǎn)發(fā)TURN可以實(shí)現(xiàn)SIP終端都在NAT環(huán)境的呼叫流程。這里,媒體轉(zhuǎn)發(fā)的處理機(jī)制實(shí)際上是通過(guò)公網(wǎng)的RTP Proxy來(lái)實(shí)現(xiàn)。RTP Proxy作為一個(gè)B2B引擎,雙方SIP呼叫通過(guò)RTP proxy轉(zhuǎn)發(fā)來(lái)建立一個(gè)橋接流程,保證RTP流正常處理;贠penSIPS實(shí)現(xiàn)NAT穿越到基本處理流程包括:
- 通過(guò)OpenSIPS cfg 腳本檢測(cè)NAT環(huán)境,管理SIP信令
- 在SIP注冊(cè)方面,通過(guò)OpenSIPS 模塊實(shí)現(xiàn)打洞或者Keepalive方式保持SIP的注冊(cè)狀態(tài)
- OpenSIPS協(xié)同媒體轉(zhuǎn)發(fā)實(shí)現(xiàn)RTP 流的流向處理
4、OpenSIPS結(jié)合RTP引擎實(shí)現(xiàn)SIP注冊(cè)和呼叫的NAT穿越
上一個(gè)章節(jié)筆者介紹了關(guān)于在OpenSIPS環(huán)境下結(jié)合RTP引擎實(shí)現(xiàn)NAT穿越的基本思路。但是,在實(shí)際部署中,筆者仍然需要考慮OpenSIPS本身所扮演的功能角色。因?yàn)镺penSIPS本身支持的功能比較復(fù)雜,而且處理流程也非常靈活。用戶(hù)如果沒(méi)有考慮的不全面的話,OpenSIPS可能會(huì)充當(dāng)太多的角色,最終OpenSIPS的腳本就會(huì)非常復(fù)雜,不利于維護(hù)和拓展。因此,我們有必要針對(duì)OpenSIPS的角色做一點(diǎn)補(bǔ)充討論。用戶(hù)在穿越處理中使用的比較多的是注冊(cè)穿越處理和呼叫穿越處理流程。我們將重點(diǎn)介紹這兩種NAT穿越的具體邏輯處理流程。

筆者建議用戶(hù)在考慮OpenSIPS作為NAT穿越方案部署時(shí),可以通過(guò)兩種方式的部署來(lái)評(píng)價(jià)解決方案的可行性:
OpenSIPS作為一個(gè)Proxy實(shí)現(xiàn)SBC功能,實(shí)現(xiàn)其他業(yè)務(wù)功能。這樣的處理方式非常緊湊,高效,可實(shí)現(xiàn)一定的擴(kuò)展。但是,這種方式會(huì)增加cfg腳本的復(fù)雜程度。
在OpenSIPS前端部署一個(gè)SBC,專(zhuān)門(mén)處理NAT穿越。SBC作為一個(gè)專(zhuān)門(mén)的NAT穿越工具,降低了Proxy的腳本復(fù)雜程度,同時(shí)可以支持多地云分布式部署方式。這樣的部署方式會(huì)增加前端的部署成本,需要更多的數(shù)據(jù)備份容災(zāi)的解決方案。目前,基于云平臺(tái)的SBC越來(lái)越受到青睞,很多解決方案提供商提供前端SBC實(shí)現(xiàn)SIP trunk均衡負(fù)載,NAT穿越和SIP注冊(cè)等問(wèn)題,極大降低了后端業(yè)務(wù)系統(tǒng)的負(fù)載和復(fù)雜程度。
OpenSIPS平臺(tái)可以通過(guò)SIP NAT穿越模塊和RTP引擎模塊實(shí)現(xiàn)NAT穿越,其模塊包括:
- nathelper和rtpproxy
- nat_traversal和mediaproxy
通過(guò)NAT模塊和媒體模塊實(shí)現(xiàn)SIP頭,SDP的管理,并且可以實(shí)現(xiàn)和外部RTP轉(zhuǎn)發(fā)處理。以上兩種方式非固定的搭配模式,它們可以任意組合。更多關(guān)于以上模塊的詳解說(shuō)明,讀者可以參考官方文檔做進(jìn)一步了解。接下來(lái),我們具體介紹OpenSIPS實(shí)現(xiàn)NAT穿越到基本步驟。
首先,OpenSIPS需要檢測(cè)NAT環(huán)境。通常情況下,NAT檢測(cè)是在初始SIP請(qǐng)求中進(jìn)行檢測(cè)。后續(xù)的其他請(qǐng)求依賴(lài)于初始請(qǐng)求的檢測(cè)結(jié)果。測(cè)試發(fā)送方是否在NAT環(huán)境中,OpenSIPS可以根據(jù):
- Contact URL,IP地址部分
- Via地址和端口相對(duì)于收到的請(qǐng)求中的地址和端口
- SDP中IP地址類(lèi)別
OpenSIPS具體的實(shí)現(xiàn)腳本如下:
# 使用bitmask檢查,檢查 VIA 是否是一個(gè)內(nèi)網(wǎng) (4)或者VIA端口不同
# 網(wǎng)絡(luò)層級(jí)的端口(16-Via port 和源地址端口的不同),設(shè)置總值為(20=1+4)
if (nat uac_ test(20)) {setflag("NATED_ SRC' '); }
# 標(biāo)識(shí)為帶NAT的地址
另外一個(gè)需要檢測(cè)到是NAT環(huán)境中的SIP終端注冊(cè)狀態(tài)。OpenSIPS檢測(cè)如果發(fā)送方注冊(cè)是一個(gè)NAT網(wǎng)絡(luò)的話,OpenSIPS將會(huì)通過(guò)用戶(hù)位置模塊保存注冊(cè)信息(usrloc):
- 保存Contact 中的地址信息作為候選溝通的IP地址,事實(shí)上是一個(gè)內(nèi)網(wǎng)的IP地址。
- 保存注冊(cè)方的公網(wǎng)IP地址和端口,如果是NAT環(huán)境中的客戶(hù)端,注冊(cè)服務(wù)器需要知道從何公網(wǎng)地址進(jìn)入注冊(cè)。
- 如果判斷出注冊(cè)用戶(hù)是一個(gè)NAT用戶(hù)的話,需要保存其標(biāo)識(shí)狀態(tài)。
當(dāng)OpenSIPS對(duì)注冊(cè)方發(fā)送請(qǐng)求時(shí),前面收到的Contact URL將作為一個(gè)RURI來(lái)處理,已保存的公網(wǎng)源地址和端口作為outbound proxy地址來(lái)處理。具體的腳本處理流程如下:
modparam("usrloc", "nat_ bflag", "NATED_ DST")
if(is_ method("REGISTER")){
if(nat_uac_test(20) ){
fix_nated_register(); # 保存注冊(cè)源地址和端口(IP和port)
setbflag("NATED_ DST"); # 標(biāo)識(shí)為NAT網(wǎng)絡(luò),branch flag(b flag)
}
save("location");
}
我們已經(jīng)通過(guò)以上腳本對(duì)SIP 注冊(cè)狀態(tài)執(zhí)行了保存。但是,大家都知道,注冊(cè)狀態(tài)不是一個(gè)一次性處理的過(guò)程,維持注冊(cè)狀態(tài)需要SIP客戶(hù)端不斷向SIP服務(wù)器端發(fā)送ping消息,以便讓服務(wù)器端獲悉其存活狀態(tài)實(shí)現(xiàn)NAT keepalive。另外,因?yàn)镾IP用戶(hù)是在NAT網(wǎng)絡(luò)環(huán)境中,SIP終端需要對(duì)NAT網(wǎng)絡(luò)環(huán)境進(jìn)行打洞處理,需要保持其端口持續(xù)開(kāi)放活動(dòng)狀態(tài)。SIP客戶(hù)端和服務(wù)器端需要周期性地執(zhí)行NAT打洞處理,發(fā)送數(shù)據(jù)來(lái)保持端口的活動(dòng)狀態(tài),避免讓NAT打洞的狀態(tài)關(guān)閉。如果SIP狀態(tài)沒(méi)有偵測(cè)到的話,可能出現(xiàn)SIP呼叫超時(shí)等問(wèn)題。在OpenSIPS環(huán)境中,我們可以使用兩種方式實(shí)現(xiàn)打洞處理:
使用UDP ping方式,使用一個(gè)偽裝的UDP數(shù)據(jù)包作為一個(gè)偵測(cè)數(shù)據(jù)包,生成方式相對(duì)比較簡(jiǎn)單,但是這是一種僅支持呼入方向的單向(服務(wù)器端到客戶(hù)端)數(shù)據(jù)包偵測(cè)方式。偵測(cè)方向數(shù)據(jù)僅從公網(wǎng)到了內(nèi)網(wǎng)終端。但是,通常情況下,內(nèi)網(wǎng)終端執(zhí)行狀態(tài)更新時(shí)僅是通過(guò)內(nèi)網(wǎng)到公網(wǎng)發(fā)送數(shù)據(jù)時(shí)才更新,因此,這種方式缺乏可靠性支持。
使用SIP ping方式,使用SIP options消息數(shù)據(jù)包作為一個(gè)偵測(cè)數(shù)據(jù)包,生成方式相對(duì)比較復(fù)雜,但是,SIP客戶(hù)端可以生成一個(gè)返回的消息,偵測(cè)數(shù)據(jù)包流向是雙向的,因此,可靠性更好,并且會(huì)生成大量的options消息數(shù)據(jù)。
OpenSIPS對(duì)SIP注冊(cè)執(zhí)行偵測(cè)的邏輯腳本如下:
modparam("usrloc", "nat_ bflag", "NATED_ SRC")
# 每20 秒,ping一次
modparam(" nathelper", "natping_ interval", 20)
# 僅對(duì)contacts 標(biāo)識(shí)為NAT的終端執(zhí)行ping 偵測(cè)
modparam(" nathelper", "ping_ nated_ only", 1)
# 執(zhí)行 SIP pinging (with OPTIONS)
modparam(' 'nathelper", "sipping_ bflag", "NATED_ DST")
除了檢測(cè)SIP注冊(cè)穿越到處理方式以外,SIP用戶(hù)也同樣需要檢測(cè)在SIP呼叫過(guò)程中的NAT穿越問(wèn)題處理。如果沒(méi)有檢測(cè)到NAT穿越到身份,SIP INVITE呼叫同樣也會(huì)面臨呼叫失敗的可能。現(xiàn)在,我們討論一下在OpenSIPS中如何檢測(cè)和處理INVITE的NAT穿越問(wèn)題。在SIP INVITE呼叫過(guò)程中,我們需要針對(duì)呼叫方和被呼叫方根據(jù)注冊(cè)標(biāo)識(shí)保存的信息進(jìn)行NAT穿越的檢測(cè)。OpenSIPS分別通過(guò)各自的檢測(cè)方式對(duì)其身份進(jìn)行檢查,然后執(zhí)行呼叫:
檢測(cè)呼叫方是否在NAT環(huán)境中,如果在的話,使用源公網(wǎng)地址IP和端口修改其內(nèi)網(wǎng)conatct URL地址,保證其呼叫路由可以正常執(zhí)行。因?yàn)镃ontact URL是一個(gè)來(lái)自于內(nèi)網(wǎng)的地址,如果沒(méi)有修改contact URL的話,可能造成后續(xù)請(qǐng)求路由失敗,例如ACK返回失敗等問(wèn)題。
檢測(cè)被呼叫方是否在NAT環(huán)境中,這里需要注意,因?yàn)楸缓艚蟹娇赡苁且粋(gè)NAT環(huán)境的SIP賬號(hào),也可能是第三方其他服務(wù)器端設(shè)備,所以執(zhí)行INVITE流程時(shí)可以通過(guò)兩種方式處理。如果被呼叫方不是NAT標(biāo)識(shí)用戶(hù),則可以通過(guò)其他路由方式進(jìn)行INVITE處理。
在進(jìn)行INVITE前轉(zhuǎn)之前,至少確認(rèn)其中一個(gè)SIP終端是一個(gè)NAT環(huán)境中的設(shè)備,這樣就可以觸發(fā)RTP proxy代理工作流程,把SDP中的內(nèi)網(wǎng)地址IP和端口替換為一個(gè)公網(wǎng)IP地址和端口實(shí)現(xiàn)媒體代理轉(zhuǎn)發(fā)。
在INVITE執(zhí)行以后,OpenSIPS仍然需要檢測(cè)INVITE返回的信息,例如失敗消息或者200 OK等成功返回的信息。如果是INVITE呼叫返回了失敗的消息的話,OpenSIPS將關(guān)閉RTP 轉(zhuǎn)發(fā)的處理流程,不再繼續(xù)RTP 轉(zhuǎn)發(fā)處理。如果INVITE呼叫返回了 200 OK消息的話,表示媒體轉(zhuǎn)發(fā)處理是確認(rèn)狀態(tài)。OpenSIPS在確認(rèn)了媒體轉(zhuǎn)發(fā)處理以后,它將會(huì)更新SDP中的內(nèi)網(wǎng)地址和端口,使用源公網(wǎng)地址IP和端口來(lái)替換SDP內(nèi)網(wǎng)地址以便雙方通過(guò)RTP媒體轉(zhuǎn)發(fā)服務(wù)器進(jìn)行RTP交互或者B2B 媒體處理。如果目的地地址檢測(cè)到是一個(gè)NAT環(huán)境終端的話,根據(jù)標(biāo)識(shí)進(jìn)行處理,使用其公網(wǎng)地址替換Contact URL中的內(nèi)網(wǎng)地址。關(guān)于OpenSIPS在INVITE呼叫中NAT穿越的處理方式如下:

注意,在以上關(guān)于INVITE呼叫的NAT標(biāo)識(shí)中,OpenSIPS必須同時(shí)對(duì)呼叫源地址和目的地地址進(jìn)行NAT標(biāo)識(shí),另外在呼叫目的地的標(biāo)識(shí)中需要使用“b”flag進(jìn)行標(biāo)識(shí)。因?yàn)橥ǔG闆r下,一些呼叫是一個(gè)fork呼叫,可能出現(xiàn)很多分叉呼叫,呼叫目的地可能是幾個(gè)目的地地址,因此使用“b”-branch 的flag做標(biāo)識(shí)處理,否則可能出現(xiàn)分叉呼叫返回的消息失敗,或者無(wú)法處理后續(xù)dialog流程。關(guān)于OpenSIPS實(shí)現(xiàn)INVITE 呼叫NAT穿越的示例如下:

在以上示例中,筆者簡(jiǎn)單介紹了關(guān)于OpenSIPS結(jié)合媒體轉(zhuǎn)發(fā)服務(wù)器的處理流程,其流程大概經(jīng)過(guò)五個(gè)步驟的處理(SIP終端分別在各自的NAT環(huán)境中,通過(guò)RTP 轉(zhuǎn)發(fā)實(shí)現(xiàn)語(yǔ)音通信):
- 首先,帶NAT的呼叫方呼叫OpenSIPS服務(wù)器端,OpenSIPS服務(wù)器檢測(cè)NAT,修改Contact URL為NAT公網(wǎng)地址,然后修改SDP地址為RTP 媒體轉(zhuǎn)發(fā)服務(wù)器地址。
- OpenSIPS服務(wù)器繼續(xù)對(duì)對(duì)端Bob進(jìn)行呼叫,并且攜帶更新后的Contact地址和SDP地址。
- Bob對(duì)INVITE返回200 OK,攜帶自己的內(nèi)網(wǎng)地址和SDP內(nèi)網(wǎng)地址。
- OpenSIPS經(jīng)過(guò)NAT處理檢測(cè),然后返回到Alice 端,并且修改了Contact 地址和SDP的媒體轉(zhuǎn)發(fā)服務(wù)器地址,通知Alice,BobContact地址是NAT的公網(wǎng)地址,SDP地址更新為RTP 媒體轉(zhuǎn)發(fā)服務(wù)器地址。RTP語(yǔ)音流將通過(guò)RTP 轉(zhuǎn)發(fā)服務(wù)器進(jìn)行B2B轉(zhuǎn)發(fā)處理
- Alice和Bob雙方通過(guò)RTP 轉(zhuǎn)發(fā)媒體服務(wù)器進(jìn)行RTP的流程處理,雙方通過(guò)RTP服務(wù)器進(jìn)行語(yǔ)音創(chuàng)建和通信。
以上是一個(gè)完整的OpenSIPS結(jié)合RTP轉(zhuǎn)發(fā)服務(wù)器處理INVITE NAT穿越的流程示例。但是,很多時(shí)候,我們僅僅關(guān)注了INVITE的處理,可能會(huì)忽略一些其他的業(yè)務(wù)處理,例如,有時(shí)SIP用戶(hù)可能重新發(fā)起re-INVITE 流程(例如SIP鍵盤(pán)的HOLD功能)。在re-INVITE的處理流程中,其處理邏輯和INVITE流程非常相似,一個(gè)比較大的區(qū)別就是無(wú)需在呼叫方和被呼叫方之間再進(jìn)行NAT檢測(cè),可以通過(guò)dialog進(jìn)行記錄或者通過(guò)contact標(biāo)識(shí)標(biāo)志其SIP終端是一個(gè)NAT的終端。無(wú)論采取何種方式實(shí)現(xiàn)其標(biāo)識(shí)的重新認(rèn)證,OpenSIPS必須確保在re-INVITE以后,RTP轉(zhuǎn)發(fā)代理必須強(qiáng)制使用新的SDP更新的地址和端口,否則,SIP發(fā)起re-INVITE以后可能導(dǎo)致雙方無(wú)語(yǔ)音的問(wèn)題。
前面,我們介紹了注冊(cè)的NAT穿越解決思路和INVITE NAT穿越的解決辦法,對(duì)于其他的非INVITE處理,NAT穿越的處理流程和INVITE基本一致,但是,OpenSIPS需要忽略媒體部分的處理。
另外,在我們的示例中,我們列舉了在UDP的檢測(cè)環(huán)境。以上的討論目前沒(méi)有針對(duì)TCP的SIP檢測(cè)。如果SIP端是通過(guò)TCP注冊(cè)的話,在OpenSIPS腳本中需要忽略TCP檢測(cè),使用UDP檢測(cè)方式。
介紹了注冊(cè)業(yè)務(wù)中使用NAT穿越的方式和呼叫流程中使用NAT穿越的細(xì)節(jié)以外,筆者將通過(guò)一個(gè)OpenSIPS配置示例說(shuō)明其完整的NAT穿越流程。
5、OpenSIPS結(jié)合RTP媒體轉(zhuǎn)發(fā)服務(wù)器配置示例
在本章節(jié)中,筆者將通過(guò)OpenSIPS結(jié)合RTP Proxy配置示例說(shuō)明如何實(shí)現(xiàn)SIP注冊(cè)的NAT穿越和呼叫的NAT穿越。配置NAT穿越需要經(jīng)過(guò)以下幾個(gè)步驟:
首先,用戶(hù)需要開(kāi)啟防火墻配置,保證需要的端口都在開(kāi)啟狀態(tài):
- ufw allow 5060
- ufw allow 9999 // 避免ALG 過(guò)濾,使用了9999端口
- 然后在cfg配置腳本中監(jiān)聽(tīng)此端口
- ocket=udp:eth0:9999

檢查RTP proxy配置。筆者已經(jīng)在同一OpenSIPS服務(wù)器安裝了RTPProxy,用戶(hù)通過(guò)配置文件檢查rtpproxy配置,默認(rèn)路徑是:
etc/default/rtpproxy, OpenSIPS通過(guò)127.0.0.1 端口 7899 監(jiān)聽(tīng)socket事件
然后確認(rèn)RTPProxy啟動(dòng),或者使用以下命令檢查:
netstat -ulnp | grep rtpproxy
service rtpproxy start
啟動(dòng)了rtpproxy以后,用戶(hù)可以修改opensips的cfg配置文件注冊(cè)NAT穿越,增加相應(yīng)的模塊和參數(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檢測(cè):
force_rport();
if (nat_uac_test(18))
setflag('NATED_CALLER');
在注冊(cè)和呼叫的邏輯中增加NAT處理流程:
route(handle_nat);
針對(duì)呼叫目的地進(jìn)行NAT檢測(cè):
if (ruri_has_param("nat","yes")) // Contact URL檢測(cè)
setbflag('NATED_CALLEE');
增加注冊(cè)NAT穿越的檢測(cè)和保存其狀態(tài),并且執(zhí)行ping命令:
if (isflagset('NATED_CALLER')) {
fix_nated_register();
setbflag('NATED_CALLEE');
setbflag('SIPPING_FLAG');
}
如果呼叫方或被呼叫方在NAT后的話,啟動(dòng)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");
配置好以上腳本邏輯以后,用戶(hù)需要通過(guò)GUI控制界面添加RTPProxy配置設(shè)置:

點(diǎn)擊“Reload on Server”按鈕,重新加載RTP代理服務(wù)器,確保成功加載。通過(guò)控制界面,查看SIP 用戶(hù)的注冊(cè)狀態(tài)(Users -> User Management),點(diǎn)擊user,會(huì)顯示contact地址和收到的地址消息。使用OpenSIPS 服務(wù)器地址作為outbound proxy地址,關(guān)閉STUN設(shè)置。
兩個(gè)都在NAT后的SIP可以進(jìn)行呼叫來(lái)觀察其IP地址的變化。另外,用戶(hù)通過(guò)按鍵HOLD重新啟動(dòng)可以觀察經(jīng)過(guò)re-INVITE呼叫以后,檢查雙方語(yǔ)音是否丟,SDP是否更新等規(guī)則數(shù)據(jù)。如果reINVITE正常的話,SDP的數(shù)據(jù)應(yīng)該也是得到了相應(yīng)的更新。
在進(jìn)一步的測(cè)試中,用戶(hù)可以使用sngrep 跟蹤INVITE的Contact URL地址和SDP中的RTP地址流向來(lái)判斷是否通過(guò)OpenSIPS執(zhí)行了NAT穿越處理。

200 OK的返回消息跟蹤數(shù)據(jù),注意其Contact URL和SDP中的c=行地址。

在200 OK返回的消息中,我們可以看到SDP的地址修改為RTPProxy或者OpenSIPS的地址(同一臺(tái)服務(wù)器)。Contact URL修改為NAT公網(wǎng)地址。再次說(shuō)明,在針對(duì)INVITE 呼叫的NAT穿越的排查過(guò)程中,為了簡(jiǎn)單方便,用戶(hù)應(yīng)該實(shí)現(xiàn)注意是否返回了200 OK,并且一定要檢查 200 OK中的Contact URL和SDP中的地址是否是RTPProxy地址。通過(guò) 200 OK返回消息可以快速排查問(wèn)題。
為了避免終端的ALG問(wèn)題,因?yàn)槲覀冊(cè)赾fg文件中監(jiān)聽(tīng)了9999端口,用戶(hù)可以通過(guò)抓包根據(jù)查看端口9999的數(shù)據(jù)流狀態(tài)判斷ALG的設(shè)置和RTPproxy的流向。
6、總結(jié)
筆者在本文章中完整介紹了NAT穿越到基本原理,NAT穿越中所面對(duì)的挑戰(zhàn)和一些NAT穿越到局限性。通過(guò)SIP代理加RTPProxy可以完美解決了大部分的NAT穿越問(wèn)題,通過(guò)OpenSIPS的配置示例說(shuō)明了配置的具體操作流程。
在文章中,筆者首先介紹了NAT的背景知識(shí)和目前各種NAT穿越所面對(duì)的問(wèn)題。然后筆者介紹了通過(guò)對(duì)稱(chēng)網(wǎng)絡(luò)方式結(jié)合TRUN服務(wù)器來(lái)解決SIP終端雙方都在NAT后的思路。在進(jìn)一步的討論中,通過(guò)OpenSIPS結(jié)合RTPProxy實(shí)現(xiàn)雙方SIP都在NAT后的SIP注冊(cè)處理,SIP呼叫處理。在NAT檢測(cè)過(guò)程中,OpenSIPS經(jīng)過(guò)三個(gè)步驟對(duì)NAT后設(shè)備進(jìn)行檢查,保存和標(biāo)識(shí)。
在最后,筆者通過(guò)OpenSIPS結(jié)合RTPProxy的配置示例說(shuō)明如何實(shí)現(xiàn)NAT穿越和NAT穿越到測(cè)試。
因?yàn)橘Y源和環(huán)境有限,筆者沒(méi)有繼續(xù)討論關(guān)于SIP在TCP注冊(cè)方式的進(jìn)一步處理和非INVITE業(yè)務(wù)場(chǎng)景中NAT穿越到討論。希望在未來(lái)的討論中能夠增加這些知識(shí)點(diǎn)的分享。另外,因?yàn)椴煌瑯I(yè)務(wù)場(chǎng)景中的OpenSIPS cfg配置文件可能有所不同,用戶(hù)在配置cfg文件時(shí)需要根據(jù)自己的具體情況加以調(diào)整,這里沒(méi)有一個(gè)統(tǒng)一的處理流程,需要讀者自己不斷實(shí)踐。
參考資料:
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完整中文用戶(hù)手冊(cè)詳解:www.asterisk.org.cn
- Freepbx/FreeSBC技術(shù)文檔: www.freepbx.org.cn
- 如何使用免費(fèi)會(huì)話邊界控制器-FreeSBC,qq技術(shù)分享群:334023047
- 關(guān)注微信公眾號(hào):asterisk-cn,獲得有價(jià)值的通信行業(yè)技術(shù)分享