1. 問題現象
前幾天線上設備出現奇怪的現象,部分終端使用UC瀏覽器訪問部分網站無法彈出portal或彈出portal比較慢,但是其他大部分終端訪問卻可以正常彈出portal,真是莫名其妙,到底是怎麼回事?
2. 現象分析
剛開始本地嘗試復現,但是一直沒有出來,線上又不好分析,一度陷入了死局。
後來想起之前有遇到過瀏覽器雲端加速導致訪問異常的情況,所以就懷疑是瀏覽器雲端加速導致的,所以立即進行測試
a. 使用UC瀏覽器,開啓雲端加速,果然portal無法彈出或彈出很慢,關閉後正常。通過抓包發現開啓時,打開網站時,瀏覽器會主動向某些地址發送請求,端口是8081(我們是監控80端口進行彈portal的,8081請求,如果訪問的域名或IP不在白名單中直接丟棄)。
b. 開啓雲端加速,將瀏覽器主動請求的地址加入白名單中,彈出portal正常。
這應該就確定跟雲端加速時,主動訪問其他域名非80端口時,報文被丟棄了,所以就讓測試去搜集不同瀏覽器雲端加速的域名了。
難道真的是這個原因嗎?,如果你也這麼想,那我們都是too young了!
另外一個同事,一直覺得不是這麼簡單,所以他後來又進行了深度的測試,詳細分析了portal彈出失敗時的報文,果然發現真的不是那麼簡單!
通過分析報文發現有兩種情況:
1)將雲端加速訪問的域名加入白名單後,訪問時直接可以上網,不會彈portal
2)關閉雲端加速時,訪問某個網站時,死活不彈portal
3. 解決方案
看到這裏,你應該也會納悶,怎麼回事?
第一種情況:
之前我們測試只是加了一個IP,可能這個IP就只是用來探測連接的,真正數據通信使用的是另外的IP,所以加入後可以正常彈portal(這個需要具體分析下,Mark)。當把域名加進去後,域名對應的所有IP都正常訪問,當你訪問某個域名時,瀏覽器先向雲服務器請求,雲服務器再向這個域名請求,然後將返回的數據,返回給瀏覽器。因爲雲服務器都放行了,這時雲服務器就像代理一樣,你雖然沒有認證過,但是數據都是走雲服務器代理出去的,所以你就可以直接上網了。
針對這種情況該怎麼做呢,這個暫時還沒有方案,待詳細分析下瀏覽器雲端加速原理再說吧!
第二種情況:
通過仔細分析報文,終於發現原來是請求報文分片了,並且第一片數據是在ACK報文中的!代碼中沒有針對ACK攜帶數據進行處理,因爲一般都是PUSH中才會攜帶數據。真是漲了見識,不過也暴露了自己對網絡協議這塊的生疏。
這種情況就比較好解決了,只需要添加針對ACK報文的處理了,但是總不能所有的ACK都處理吧!如果ACK沒有攜帶數據,根本就沒必要處理。
那怎麼判斷ACK中有沒有數據呢?
其實很簡單,暴力點,就判斷ip頭總長度是不是大於40,如果是,就判斷ACK攜帶有數據,如果不是,那肯定沒有攜帶數據。修改後,測試,完美解決,搞定!
if (1==tcph->psh
|| (1==tcph->ack && iph->tot_len > 40)) //判斷IP頭大於40,就斷定ACK中攜帶有數據
{
int ret = -1;
struct httphdr* http=NULL;
DCINFO("Reply ack.\n");
dc_reply_ack(skb,iph,tcph);
http = kmalloc(sizeof(struct httphdr),GFP_ATOMIC);
if(!http)
{
DCERR("Malloc failed.");
return NF_ACCEPT;
}
...
}
至於第一種情況,後面詳細分析下,再好好談論下方案!
這種情況下不解決,會嚴重影響使用雲端加速瀏覽器的用戶體驗!