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

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

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

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

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

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

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

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

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

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

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

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

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