其實(shí)我早就知道騰訊云上有ALG,只是都想辦法繞過了,沒有進(jìn)一步核實(shí)。
欠下的債總是要還的,今天,又折騰了半天。
XSWITCH云平臺(tái)目前建設(shè)在騰訊云上。今天在調(diào)試Kamailio,收到SIP包后發(fā)到另一臺(tái)VM上的FreeSWITCH中,中間通過公網(wǎng)IP發(fā)送。然后遇到了pike模塊告警,說數(shù)據(jù)包太多。pike模塊是Kamailio里的限流模塊,將閾值調(diào)高了一倍還是不行,遂抓包找原因,最后發(fā)現(xiàn)是網(wǎng)絡(luò)層篡改了Route字段,將里面的公網(wǎng)IP改成了私網(wǎng)IP,造成了SIP消息在公網(wǎng)和私網(wǎng)IP間無限循環(huán),直到遇到限流(幸虧開了限流模塊)。
找到原因就好辦了,有無數(shù)的辦法可以繞過該問題:
- 用TCP
- 用TLS
- 不走公網(wǎng)IP,直接走私網(wǎng)IP
- 調(diào)整Kamailio腳本,接受私網(wǎng)IP為最終目的地
首先要核實(shí)問題,發(fā)現(xiàn)從我本地電腦發(fā)出的數(shù)據(jù)包也有此問題,但這也可能是由于我本地的路由器引起的。檢查本地路由器沒有開啟ALG功能。又重新核實(shí)。在兩臺(tái)騰訊云服務(wù)器上通過公網(wǎng)IP測試。
A上收:
ngrep -p -q -Wbyline port 1001
B上發(fā):
nc -u -p5060 A的IP 1001 < test.sip
其中,test.sip是純文本的INVITE消息,里面有個(gè)Route字段。
發(fā)現(xiàn),如果A的IP是公網(wǎng)IP,到達(dá)對方后Route字段會(huì)被改為私網(wǎng)IP,而如果用私網(wǎng)IP就不受影響。
進(jìn)一步可以發(fā)現(xiàn),TCP也不受影響,受影響的是UDP,但大多數(shù)人跑SIP還是用UDP。
給騰訊提了工單,響應(yīng)挺快,只是溝通了很多次,工程師說是騰訊云默認(rèn)沒有開ALG,然后定位到問題,聯(lián)系產(chǎn)品給我加了個(gè)ALG功能,然后讓我把公網(wǎng)IP遷移到EIP或買個(gè)EIP,在EIP上開啟ALG就可以了。
我直接就不懂了,然后詳細(xì)說明我認(rèn)為的ALG是“篡改”包的內(nèi)容的,如果沒開就不會(huì)篡改,何來再開啟一說?
最后經(jīng)過電話溝通才把問題說明白。騰訊云默認(rèn)確實(shí)是開了“篡改”功能的,如果想關(guān)掉,那就得再“開啟”另一個(gè)“ALG穿透”功能(實(shí)際上控制臺(tái)頁面上叫“設(shè)置ALG”),讓數(shù)據(jù)包透明的過。他們認(rèn)為這才叫“開啟”。
好吧,負(fù)負(fù)得正,反正能解決問題就行了。我相信應(yīng)該能解決問題,但是沒有驗(yàn)證,因?yàn)槟壳霸谏a(chǎn)環(huán)境上動(dòng)EIP有點(diǎn)風(fēng)險(xiǎn)。
這里關(guān)鍵的問題是認(rèn)知不同。我們先說說什么是ALG。
ALG的全稱是Application Layer Gateway,即應(yīng)用層網(wǎng)關(guān)。我們都知道,網(wǎng)絡(luò)有個(gè)OSI七層模型,網(wǎng)絡(luò)交換機(jī)和路由器其實(shí)是工作在2層和3層,即他們最多只知道IP包里的源IP地址和目的IP地址,而不知道數(shù)據(jù)包里具體傳的是什么。著名的Web服務(wù)器和反向代理軟件如Apache和Nginx工作在七層,理解HTTP協(xié)議,因而可以修改消息內(nèi)容,并轉(zhuǎn)發(fā)。所以,其實(shí)他們就是應(yīng)用層的網(wǎng)關(guān)。最近比較火的專門做API轉(zhuǎn)發(fā)的API網(wǎng)關(guān)也是工作在七層的。
其實(shí),路由器上也是有ALG功能的,但功能一般都比較弱。路由器上的ALG功能一般用于解決FTP和SIP這樣的奇葩協(xié)議。FTP協(xié)議需要兩個(gè)端口才能傳輸文件,有主動(dòng)模式和被動(dòng)模式等,在有的NAT網(wǎng)絡(luò)中不容易通過,因而,路由器上的ALG功能可以提供幫助,細(xì)節(jié)不多說。
SIP協(xié)議更奇葩,一個(gè)INVITE消息里有好幾個(gè)IP地址,在NAT網(wǎng)絡(luò)中有時(shí)候就不通了,甚至,有時(shí)候信令通了,通話建立了,卻沒有聲音,也多半是NAT惹得禍。因而,路由器上的SIP ALG也可以深度解析SIP包,企圖(注意這里用了貶義詞)修復(fù)里面的IP地址。但是很不幸,很多ALG實(shí)現(xiàn)都有Bug。即使ALG沒有Bug,SIP協(xié)議很復(fù)雜,ALG根本Cover不住,你無法預(yù)測它在什么情況下改哪個(gè)地方,所以,大多數(shù)時(shí)候,它帶來的幫助比帶來的問題多得多。除非,除非路由器上的ALG功能有很多配置選項(xiàng)來應(yīng)對各種問題,比如用Kamailio實(shí)現(xiàn)個(gè)ALG。但這是不現(xiàn)實(shí)的,所以,你應(yīng)該關(guān)掉它!
事實(shí)上,我在《FreeSWITCH權(quán)威》指南里也講到過,要關(guān)掉ALG。
好吧,到了這里,我們應(yīng)該可以明確,如果路由器上開啟了ALG功能,數(shù)據(jù)包有被“篡改”的風(fēng)險(xiǎn),所以我們需要關(guān)掉。
問題是,騰訊云上這一功能是默認(rèn)開啟的。所以,他們又在控制臺(tái)上實(shí)現(xiàn)了一個(gè)“ALG設(shè)置”功能,如果“開啟”以后,就關(guān)掉了。他們的技術(shù)支持工程師會(huì)告訴你“ALG默認(rèn)是不開啟的,你可以在EIP上開啟”,“開啟”后,就好用了……長時(shí)間無語中。
發(fā)了個(gè)朋友圈吐槽了一下(不要誤會(huì),我本身是騰訊云的TVP,吐槽是我的職責(zé)),很多人就建議我遷到阿里云或華為云。其實(shí),騰訊云本身非常不錯(cuò),他們的技術(shù)支持也很及時(shí),只是,在這一問題上,不同的人有不同的認(rèn)知。也許那個(gè)工程師并不懂SIP,也許他只是站在他們產(chǎn)品的角度,“設(shè)置ALG”這一功能就是沒有開啟嘛。所以,每個(gè)人都有自己看問題的角度。溝通,需要擺事實(shí)講道理才行。但無論如何,給騰訊提個(gè)建議,把這個(gè)功能改成“關(guān)閉ALG”,就沒有歧義了。因?yàn)樵谀J(rèn)情況下,數(shù)據(jù)包應(yīng)該是暢通無阻的,既然有人從中做梗,那就應(yīng)該“關(guān)閉”它,而不是要繞一圈搞個(gè)“負(fù)負(fù)得正”。
再說到SIP的ALG。除了上面說到功能很雞肋外,其實(shí)不管是FreeSWITCH還是Kamailio,都在NAT上做了大量的工作保證在NAT環(huán)境下可用。ALG不僅僅是雞肋功能,簡直是SIP公敵。所以,默認(rèn)在網(wǎng)絡(luò)環(huán)境下開啟這一功能是不負(fù)責(zé)任的。
如果你的SIP服務(wù)器運(yùn)行在騰訊云上,標(biāo)準(zhǔn)的做法是使用EIP并“開啟ALG”(再說一遍,實(shí)際上是關(guān)閉@#^&$@#$@?$x)。(如果你從未來穿越到現(xiàn)在看到這篇文章,現(xiàn)在是2020年)
XSWITCH用戶也注意,我們目前還沒有遷移到EIP,因?yàn)檫@可能會(huì)影響我們很多租戶。如果您有問題,請嘗試使用TCP,已知TCP的SIP消息不會(huì)被篡改。再有問題請與我們聯(lián)系,我們也會(huì)盡快完成EIP遷移。事實(shí)上,我們希望所有UDP用戶都遷移到TLS上。