http://blog.csdn.net/kidwei/article/details/8559842
1. 前言
網游加速器是針對個人用戶快速連接網游服務器的一種服務。為了解決國內南北網絡互聯瓶頸的問題,“網絡加速器”廠商通過搭建多個高帶寬的雙線機房(或通過租用雙線VPS主機),並在這些機房的兩大線路中架設多個節點服務器,然后為其編寫“網絡加速器客戶端”,通過客戶端判斷用戶的網絡線路類型,並將用戶應用客戶端的網絡數據轉發到指定的節點服務器,由節點服務器轉發給用戶應用客戶端請求的真正服務器。“網絡加速器客戶端”通過自動選擇速度最快的節點服務器進行數據轉發,以達到數據加速作用。優秀的網絡加速器可以有效減少網絡丟包和網絡延遲。
本文基於前期對各種加速器的分析以及對其中的關鍵技術進行試驗。文章首先對互聯網上流行的網游加速器分析結果進行簡要匯總,然后針對各種不同的加速器實現方式進行詳細實現細節的介紹。
2. 流行加速器分析
本文前期對目前流行的網游加速器(或網絡加速器)客戶端進行了一定的深度分析,了解了這些網絡加速器的使用特點、應用領域以及所采用的關鍵技術。目前網絡上流行的網絡加速器主要有:迅游加速器、迅雷網游加速器、盛大ET加速器、LavaVPN、NetPas等。
迅游加速器(http://www.xunyou.com)和迅雷網絡加速器迅游版(http://jaisuqi.xunlei.com)是專門針對網游的加速器。迅雷共有兩款加速器,自研的“給力加速器”提供免費加速服務,“迅游版加速器”是與迅游合作的產品。它們在軟件UI設計和功能大致相同,使用流程也如出一轍:啟動加速功能前需要選擇指定的游戲及其區服,注意:待加速游戲必須是其客戶端列表中指定的游戲,對於未指定的游戲不能被加速。
啟動加速后加速客戶端對其全部節點服務器進行測速(迅游加速器部署了82個節點服務器),然后選擇速度最快的服務器作為轉發服務器,並在本地建立IP地址以172開頭的虛擬網卡(局域網地址)。啟動后通過抓包工具分析,所有發送到該游戲服務器的數據都是從該172開頭的虛擬網卡地址發出的(VPN技術?),而不是從物理網卡地址發出。通過查看路由表,被加速的游戲當前所使用的服務器被增加到了路由表中,並指向了該172開頭的虛擬網卡地址。
在對迅游加速器分析過程中還發現,迅游加速器在加速過程中使用了LSP技術(一種通過在TCP/IP協議上層安裝一層用戶自定義協議,可以對WinSock2 API進行攔截的技術),並對WSAConnnect函數進行了攔截。
迅雷給力加速器也提供了四種加速模式,模式一采用的是基於LSP的代理加速方式,通過LSP技術,將用戶的網絡數據直接轉發給代理服務器,再由代理服務器將數據轉發給真正的游戲服務器;模式二采用的是基於L2TP協議的VPN技術;模式三采用的是基於PPTP協議的VPN技術;模式四采用的是基於基於OpenVPN的VPN技術。這三種模式在啟動加速后都需要修改路由表,以實現針對指定目的IP的加速功能。
VPN顧名思義,虛擬專網,你接入VPN就是接入了一個專有網絡,那么你訪問網絡都是從這個專有網絡的出口出去,好比你在家,你家路由器后面的網絡設備是在同一個網絡,而VPN則是讓你的設備進入了另一個網絡。同時你的IP地址也變成了由VPN分配的一個IP地址。通常是一個私網地址。你和VPN服務器之間的通信是否加密取決於連接VPN的具體方式/協議。
代理服務器則是把你的網絡數據請求通過一條連接你和代理服務器之間的通道,由服務器轉發到目的地。你沒有加入任何新的網絡,只是http/socks數據經過代理服務器的轉發送出,並從代理服務器接收回應。你與代理服務器通信過程不會被額外處理,如果你用https,那本身就是加密的。
LavaVPN(http://www.lavajsq.com,已經改名為LavaJSQ)是一款可以針對所有網絡應用進行加速的網絡加速器。它采用了VPN技術對網絡進行加速,並提供四種VPN協議模型進行加速:PPTP、L2TP、OpenVPN(SSL_TCP)、OpenVPN(SSL_UDP),並可以通過增刪路由表的形式,針對不同的應用進行加速:僅加速國外訪問、僅加速對網通(電信)的網絡訪問、僅加速某些進程的網絡訪問等等。
對LavaVPN的分析過程中未發現其有使用到LSP技術的跡象。
盛大ET加速器(http://etspeed.sdo.com)是一款可以針對網絡游戲加速以及語音加速的工具。ET加速器在結構設計上與迅游加速器有明顯區別,但是功能類似:僅支持對其游戲列表中的游戲加速、啟動加速功能后在本機建立了虛擬網卡,並添加了指向虛擬網卡地址的路由、在本機安裝了LSP協議。ET加速器啟動加速后,在“我的連接”面板里新增出現了一個名為“etaaaaaa”的網絡連接。
3. 加速器實現方式概要
通過對以上加速器的分析進行參考,並查閱相關資料,目前主流的加速技術可以采用兩種方式來實現:“代理服務器方式”和“VPN方式”。
代理服務器方式通過部署SOCKS5代理服務器作為加速節點,加速客戶端自動選擇最快的代理服務器作為當前的轉發節點。在客戶端主要采用LSP技術,在用戶的主機安裝分層協議,在游戲客戶端調用connect函數(或WSAConnect函數)試圖連接游戲服務器時,將連接重定向到代理服務器,並采用SOCKS5協議規范與代理服務器進行數據協商,由代理服務器來連接真正的游戲服務器,並將游戲服務器的數據原封不動轉發給用戶、將用戶的數據原封不動轉發給游戲服務器。
VPN方式需要部署雙線VPN服務器作為加速節點,加速客戶端自動選擇速度最快的VPN服務器,並通過VPN撥號連接到VPN服務器並獲取一個虛擬IP地址,同時通過修改路由表的方式,將指定進程的網絡訪問路由到虛擬IP上,而其余地址仍經過原默認路由途徑訪問。
下面就這兩種加速方式的具體實現以及重要的技術難點進行詳細分析。另外,報告中的所有代碼截圖均來自之前寫的測試程序,並測試通過;VPN加速方式由主要進行了原理的詳細介紹,並編寫了支持PPTP協議的VPN客戶端和服務器進行了測試。
4. VPN加速方式
4.1. VPN加速概述
VPN技術常常被廣泛應用於“網游加速技術”和“翻牆技術”中。如前面提到的迅游加速器、迅雷網游加速器、LavaVPN都采用到了VPN技術進行加速,而且目前主流的網游加速器都主要是采用的VPN技術。由於VPN環境的測試需要建立VPN服務器,本人的測試環境有限,所以只是進行了客戶端的代碼編寫並連接通過,無法做相關的代理效果的測試。下面只針對實現的流程和原理給以介紹。
4.2. VPN加速實現步驟
通過建立如下步驟,可以采用VPN技術來實現網絡加速:
1. 部署雙線VPN服務器節點;
2. 加速器客戶端啟動后選擇網絡性能最好的VPN服務器,並在客戶端進行RAS撥號,與該VPN服務器建立隧道連接,連接建立后將會自動在本機生成一個虛擬網絡地址,同時客戶端的默認路由會被修改成指向該虛擬網絡地址,如果此時不進行特殊處理,客戶端的所有網絡訪問將都會通過該VPN通道出去;
3. 因為網游加速器的功能需求是僅僅針對某款游戲進行加速,即:在知道這款游戲連接的服務器IP的前提下,只有發送到該服務器IP的數據才被加速,其他網絡數據應該不受影響。因此加速客戶端在建立完VPN通道以后,需要立即修改路由表:在撥號前通過修改撥號參數,使其不修改本機的默認路由表;其次,將游戲服務器IP增加到路由表中,並讓其指向VPN撥號建立的虛擬網絡地址上。這樣,與游戲服務器之間的通信都走VPN通道,而其他網絡數據都不受影響。
4.3 VPN加速使用的三種協議介紹
目前網絡上現有的網游加速器(或網絡加速器)都使用到了三種VPN協議:PPTP、L2TP和OpenVPN。各種不同的協議在使用時可能受用戶的網絡狀況的限制而無法使用,因此一般的網絡加速器都會提供不同的加速模式供用戶選擇。或在啟動加速過程中根據用戶當前的網絡狀況自動選擇可用的加速模式。
PPTP協議:PPTP協議是在PPP協議基礎上開發的增強型安全協議。PPTP協議中有兩個流:控制流和數據流。PPTP協議的數據流采用了GRE協議,由於該協議的特殊性,如果同一個NAT中有兩個或以上的主機同時在發送PPTP協議數據包,當數據包從外部達到NAT時,NAT將無法通過端口將數據轉發到不同的主機,因此,當使用PPTP協議時,如果用戶所在的NAT網關不支持VPN穿透功能(即支持PPTP協議的NAT編輯器,該編輯器在GRE協議的報頭使用了一個CallId用來表示NAT下的一個會話,通過CallId來模擬端口,做NAT映射),那么內部主機只能與同一個服務器中間建立一個會話,不能有第二個客戶端。目前,大多數NAT網關都具有PPTP NAT編輯器,能很好的支持PPTP協議。
L2TP協議:第二層隧道協議,該協議是PPTP協議和Cisco第二層轉發協議L2F的結合體。在windows建立的基於L2TP協議的VPN連接中,默認是啟用了證書方式的IPSec協議作為安全傳輸協議,IPSec協議為了保護IP數據包的完整性,會禁止任何對數據包的修改,否則修改后的數據包達到目的主機后其解密和完整性認證就會失敗,從而導致這個報文被認為是非法數據而被丟棄。而當加速器客戶端位於NAT后時,數據包在通過NAT時,NAT會對IP頭數據等進行修改,導致數據到達VPN服務器時被認為是非法數據而丟棄。
解決該問題的一種方式是通過硬件方式:要求通信的雙方的邊界路由都支持NAT-T,基本原理是在IPSec封裝好的數據包外再進行一次UDP的數據封裝,因此,當數據包穿過NAT網關時,被修改的只是外層IP/UDP頭,而真正的IPSec數據未被修改;到目的主機時再將IP/UDP封裝去除,這樣就可以得到未被修改的IPSec數據包。
另一種方式是在L2TP協議中禁用IPSec。對於我們制作網絡加速器應用來講,IPSec協議並非必須的,因此,我們可以在加速器連接中去除IPSec協議,而不影響加速功能。在Windows系統下采用RAS進行VPN連接時,若要去除IPSec協議,需要修改注冊表並重啟機器使之生效。迅游的給力加速器中就是采用這種方式。
OpenVPN模式:OpenVPN是一個基於OpenSSL加密和驗證的應用層VPN實現,能夠在NAT環境下很好的工作,是今年來新出現的一個基於開源軟件體系的VPN項目。使用OpenVPN進行連接前,需要在客戶端機器上安裝一個虛擬網卡設備,並需要客戶端修改路由表。
以上VPN協議中,除了OpenVPN的使用可以不受用戶當前網絡的限制外,其他兩種方式都可能收到用戶的NAT情況影響而導致加速失敗,因此在實際應用中,各種加速器都會把這幾種模式都提供給用戶,並根據用戶的網絡情況進行選擇。
4.4 VPN撥號客戶端的實現
試驗過程中對RAS撥號建立VPN連接功能進行了測試。如下客戶端實現了連接到VPN服務器,並同時客戶端用戶輸入的“待加速地址”列表,修改路由表,已達到“僅指定IP走VPN通道”的功能,而用戶的其他網絡訪問完全不受影響。
4.5 VPN方式尚存在的問題
1. 與采用代理方式一樣,判斷與當前啟動的游戲通訊的是哪個服務器是個問題(原因如前所述),這里可以用到前面描述的LSP技術,通過在connect函數中判斷欲建立連接的IP是否在當前游戲的服務器列表中。此時用到LSP技術並不是用於轉發,僅僅用於判斷是否加速。
2. 采用VPN方式有一個問題:如果用戶修改路由表,讓其他進程的服務器IP(如p2p下載軟件)或默認路由表經過VPN通道的話,可能會造成VPN通道中的數據量增大,可能會影響正常的游戲。迅游加速器也沒有對該問題進行很好的解決,早前的測試發現迅游加速功能啟動后,通過修改路由表,可以使任意客戶端進程都使用迅游的加速通道來訪問網絡。
該問題的也許可以通過兩種方式來解決:一種是在客戶端限制用戶修改路由表,另一種是通過在服務器端進行限制非游戲服務器相關的數據。具體實現方式有待研究。
5. 代理加速方式
5.1. 代理加速的基本原理
采用代理服務器進行網絡加速是一類使用較早的技術。目前某些網游客戶端和網絡應用程序都直接支持SOCKS5代理協議來連接其客戶端,客戶端提供設置代理服務器IP和端口的方式供玩家來設置。然而大部分網游客戶端並不直接支持SOCKS5代理技術。此處介紹的代理加速模式不僅支持那些無法設置SOCKS5代理的網絡游戲,即使那些可以設置SOCKS5代理的游戲,玩家也可以不用手動去設置,而自動采用下面介紹的代理加速技術進行代理加速。
代理加速方式可以直接采用SOCKS5協議,由於SOCKS5協議有現成的服務器程序可用,可以節省服務器編寫時間;但是也可以自己定義一個“類SOCKS5”的代理協議,自行實現代理協商和身份驗證功能。下面的介紹將會基於自己定義代理協議的模式。
在使用代理方式加速時,LSP技術的使用是關鍵。Microsoft在Winsock2中提供了Winsock服務器提供者(SPI),允許用戶在基礎TCP/IP協議上層插入自己定義的分層協議(LSP),當用戶通過Winsock2 API連接網絡或發送網絡數據時,如調用WSAConnect函數,將會首先執行到LSP協議的dll中我們定義的函數,這樣我們可以先進行處理,然后再交給真正的WSAConnect函數,這樣就會起到API Hook的作用。
要使用LSP技術,必須要將寫好的LSP協議安裝到用戶的機器上,安裝過程實際就是將DLL放入系統目錄,並在注冊表中寫入該DLL位置信息的過程。注意:安裝未簽名的LSP時,安裝過程中一般防火牆都會有警告提示。
5.2. 代理加速方式的實現概要
采用LSP方式進行網絡加速需要部署SOCKS5代理服務器作為加速節點,加速客戶端自動選擇最快的代理服務器作為當前的轉發節點。
開發人員在客戶端需要完成的動作有:
1. 編寫我們自己的LSP協議動態庫,重新實現我們需要的相關socket函數,如connect;
2. 在用戶的主機安裝我們自己的LSP協議,這一操作可以放入我們的應用程序部署的時候完成,也可以在我們的加速器每次啟動的時候進行部署;
3. 當游戲客戶端調用connect函數(或WSAConnect函數)試圖連接游戲服務器時,通過LSP將連接重定向到代理服務器,並采用SOCKS5協議規范與代理服務器進行數據協商,由代理服務器來連接真正的游戲服務器,並將游戲服務器的數據原封不動轉發給用戶、同時將用戶的數據原封不動轉發給游戲服務器。
由於Socks5協議並不涉及協議加密,而且Socks5協議本身協商過程較長,實際在開發中,網絡加速器開發商一般都不會直接采用socks協議,而是對該協議進行改造,定義自己的代理協議。
5.3. Socks5協議與LSP結合
通過LSP技術Hook到相應的套接字函數進行數據轉發之前,需要進行Socks5代理協商,即將鑒權信息告訴代理服務器,以及告訴代理服務器自己想連接的真正游戲服務器地址。代理協商完成后才能進行數據的收發。
針對不同的網絡連接方式,代理協商的方式有所不同:
1. 普通阻塞方式的TCP連接最簡單,可以在hook到connect函數后直接在內部進行阻塞式的代理協商,直到協商完畢后才將connect函數返回給用戶,這時候用戶拿到的socket實際上是連接到代理服務器的socket,當應用程序通過這個socket收發數據時,實際上是在和代理服務器交互,而這一過程對應用程序來說是透明的,應用程序以為自己是直接在和游戲服務器通信。
目前的網絡應用程序很少會采用阻塞方式進行TCP連接,所以這種情況應用場景比較少。
2. 非阻塞方式的TCP連接情況比較復雜,有的TCP連接的socket是可以修改阻塞選項,這樣,我們可以在connect函數的入口處判斷一下當前socket是否是非阻塞,如果是則將其改為阻塞方式,修改后以阻塞方式進行socks5代理協商,協商完畢后再將socket的阻塞方式修改為非阻塞。
3. 另一種更為復雜的非阻塞TCP連接是基於Windows異步消息的連接,這種連接采用了WSAAsynSelect方式設置了網絡消息到來時的Windows接收窗口,所有的網絡數據都需要在這個窗口的消息處理函數中處理(QQ飛車的TCP連接就是采用的這種方式)。這類網絡模型不能簡單采用修改socket阻塞方式的方法來解決。
解決這一問題的唯一辦法是在LSP中hook住WSAAsynSelect,在該函數中創建一個我們自己的隱藏窗口,讓網絡應用程序的所有數據都轉發我們自己的窗口上來,在我們的窗口的消息處理函數中進行代理協商和網絡數據轉發。
4. 對於UDP網絡數據的socks5代理轉發比TCP又要稍微復雜一些,TCP只需要hook到connect和WSAAsynSelect,對於網絡收發數據的send和recv函數是不需要我們自己來實現的。UDP由於是不保持連接的,因此每次發送和接收的UDP包都要包含代理協商信息,因此我們需要把RecvFrom函數和SendTo函數都hook住。
對於UDP連接,需要在應用程序發送第一個UDP包的時候進行代理協商,以后發送數據的時候按照socks5協議的規定,加上socks5頭部;收到的信息去除socks5頭部再交給應用程序。
5.4. 代理加速方式詳細實現
下面就詳細介紹每一步的具體實現方式,為了方便流程分析,這里從LSP實現數據包轉發開始介紹,最后介紹代理服務器的實現。
1. 利用LSP編寫DLL,實現客戶端數據包轉發功能:
編寫LSP協議並安裝到現有協議之上,需要建立基於DLL的工程,並導出WSPStartup函數,這樣當有應用程序創建套接字時,會自動執行到該WSPStartup函數。在WSPStartup函數函數中,參數信息指明了應用程序期望采用哪種協議來創建套接字(所有的協議存在於一個協議鏈中,該協議鏈也包含了我們安裝的LSP協議),我們需要在該函數中加載下層協議,並調用下層協議提供者的WSPStartup函數初始化,並修改傳遞給上層的函數表,將我們需要Hook的Winsock2函數指針的地址指向我們自己的函數。關鍵代碼如下:
如果測試程序只針對TCP數據包的轉發,只需要實現WSPConnect函數就可以了,其余函數只需要直接調用g_NextProcTable中的默認函數就可以了。
當用戶應用程序調用connect函數或WSAConnect函數試圖進行TCP連接時,將會先進入LSP的DLL中定義的WSPConnect函數,該函數進入后我們會判斷應用程序試圖連接的服務器IP和端口是不是我們待加速的服務器,如果是,會執行到socksProxy函數與代理服務器連接,並進行代理協商;如果不是待加速服務器,則執行g_NextProcTable中原有的連接函數,此時LSP就沒有起作用,流程與不安裝LSP前的流程是一致的。
2. 安裝LSP。
要使我們上一步實現的轉發協議生效,還必須將上一步生成的DLL安裝到用戶的系統上。只有安裝了LSP,應用程序在調用ws2_32.dll中的函數時就會執行到我們的LSP的DLL中。一般來講,生成的DLL需要放入Windows/System32目錄下,一個原因是DLL路徑不能有中文等特殊字符,另一方面,如果有其他程序誤刪了該DLL,會導致整個系統無法上網的現象,還可能導致整個系統崩潰。
安裝LSP首先需要安裝協議鏈,需要將下層協議的信息拷貝過來,修改成我們需要的協議特點,並進行安裝;然后對協議鏈進行排序,將我們的協議放在協議鏈的最上層,以保證ws2_32.dll調用到的第一個協議是我們的協議。
這里需要注意的是,當安裝了“迅游加速器”后,系統上原有安裝的分層協議將會被移到最下層,導致原有的協議無效。因此,我們在開發自己的網游加速器時需要考慮該問題,並予以避免。
5.4. 代理方式尚存在的問題
1. 不同網絡加速器廠商的LSP安裝程序相互之間可能會出現不兼容的情況,所以我們實現自己的加速LSP的時候,其他網絡加速器廠商可能對我們安裝的協議干擾,如迅游在安裝和每次啟動的時候會刪除其他廠商的LSP協議;
2. 如前所述,LSP在Hook到connect函數后,在WSPConnect函數中會判斷當前連接的服務器是否是需要被加速的目的地址。如何獲得用戶當前啟動的游戲的IP和端口是多少是一個難點,因為一個游戲可能連接了多個服務器並開啟了多個端口,而真正進行通訊的只是其中一個;另一方面,通過加速客戶端啟動的進行可能並不是真正的游戲進程(可能只是一個升級程序)。
迅游加速器可能收集了每款待加速游戲的服務器ip和端口,如果客戶端發送網絡包的目的地址是這些ip的時候,才會針對這些目的ip地址進行加速。本人有過測試:首先獲取迅游加速器支持的某款游戲的某個服務器IP和端口,然后自己編寫一個客戶端不斷給該服務器的端口發送數據,當該exe替換游戲的exe並啟動后,從抓包結果來看,加速功能仍然有效;當從迅游列表中選擇另一款游戲,啟動exe時仍啟動我們剛剛編寫的exe時,加速功能就失效了。因此可以推測:迅游加速器並不是通過判斷進程信息來獲取目的服務器的(況且通過判斷進程信息來獲取目的服務器IP並不容易實現,如前所述),而是通過用戶從列表中選擇的游戲的名稱。
6. 總結
本文主要介紹了兩種實現網游加速的可行的技術方案,其中提到的對其他網絡游戲加速器的分析以及具體實現細節可能會有一些不完善之處。
加速器實際實現過程中,還有關鍵一步就是判斷當前用戶的網絡環境。比如用戶當前連接的服務器是網通服務器,更智能的做法是在加速之前提前判斷當前用戶的網絡情況,如果用戶是網通用戶,則不必啟用加速功能,如果用戶是電信或其他網絡,則需要給用戶提示可以啟動加速功能,並由用戶來決定是否啟用加速。
當前游戲如果采用了P2P通信,用戶網絡環境的判斷仍然需要被考慮。如QQ飛車和CF等對戰游戲,啟動游戲后建立了P2P連接,是否需要對這些P2P連接進行加速呢?這種情況也需要考慮用戶的當前網絡環境:如果P2P雙方處於同一個NAT下,則不需要加速,如果一方是電信用戶,而另一方是網通用戶,就需要加速功能。
用戶網絡環境的判斷(包括是否處於同一個NAT下的判斷)是進行網絡加速器的具體實現前需要解決的技術問題。