使用socks5将游戏的服务器连接通过本地SS服务器代理连接到加速服务器,实现游戏加速。
程序员文章站
2022-05-10 14:55:25
...
水平有限,简单记录下实现过程:
首先准备一个开源项目* https://sourceforge.net/p/*/code/ci/master/tree/ (c++ mfc *源码)。
*是一个本地代理服务器,*是一个Windows下C++版的*客户端. 相比其它的客户端更稳定更快速,不会出现其它版本中常现的接收数据错误。
通过*可以启动本地代理服务器。你可以让IE或其他需要软件通过SOCKS5访问的软件先连接到 *,*再将请求加密后再连接到服务器。服务器可以将请求转发到国外游戏服务器,实现网络游戏加速。
*界面:
*是开源的。本文将*的功能整合起来。实现对魔兽世界怀旧服LH网络加速的功能。
原理很简单:
1、先整合*的功能,将本地服务器启动起来。
// 加载ss服务器列表
CSSConfigInfo *pCfg = GetConfigInfo();
CSSNodeInfo* pNode = new CSSNodeInfo(0);
pNode->id = 0;
pNode->server = "140.0.0.00";
pNode->server_port = 65501;
pNode->password = "1234";
pNode->method = "aes-256-cfb";
pNode->enable = true;
pNode->Upload_traffic = 7450.00;
pNode->Download_traffic = 21477.00;
pNode->ConnectedTimes = 12;
pNode->lastStatus = -1;
pCfg->ssNodeInfo.clear();
pCfg->ssNodeInfo.push_back(pNode);
pCfg->localSocksUser = "local_user";
pCfg->localSocksPass = "local_pass";
pCfg->localPort = 1080;
pCfg->isPrivoxyRunned = RunPrivoxy( );
RestartLocalSocketService(FALSE);
那么本地服务器就启动好了。127.0.0.1:1080 登陆账号:local_user 登陆密码:local_pass
2、启动魔兽世界6.0。注入DLL,拦截ws2_32.dll的connect方法。
DetourRestoreAfterWith();//恢复原来的状态
DetourTransactionBegin();//拦截开始
DetourUpdateThread(GetCurrentThread());//刷新当前线程
//以下为hook connect内容
g_trueConnect = (_gconnect)DetourFindFunction("Ws2_32.dll", "connect");
g_trueWSAConnect = (_gWSAConnect)DetourFindFunction("Ws2_32.dll", "WSAConnect");
DetourAttach(&(PVOID&)g_trueConnect,hook_connect);
DetourAttach(&(PVOID&)g_trueWSAConnect,hook_WSAConnect);
if( DetourTransactionCommit() == NO_ERROR )//拦截生效
{
WriteLog(_T("hook success"));
}
else
WriteLog(_T("hook faild"));
int _stdcall hook_connect(SOCKET s, struct sockaddr *name, int namelen)
{
CString strDbgInfo;
strDbgInfo.Format(_T("Socket in hook connect:%d"),s);
//修改目的IP为VIP
SOCKADDR_IN* addr =(SOCKADDR_IN*)name;
//如果IP是指定要修改端口的IP,就改掉端口
char * ipaddr=NULL;
ipaddr = inet_ntoa(addr->sin_addr);
//原游戏连接信息
TCHAR temp[255];
memset(temp,0,255);
char* proxyserver = "127.0.0.1";
int proxyport = 1081;
char* proxyuser = "local_user";
char* proxypwd = "local_pass";
int iRet = ConnecToProxyServer(s,proxyserver,proxyport,proxyuser,proxypwd,3,ipaddr,ntohs(addr->sin_port));
if (iRet>=0)
{
WriteLog(_T("in connecta: connect socks5 success 1!"));
}
else
{
memset(temp,0,255);
wsprintf(temp,_T("Err connect ss5:%d"),iRet);
WriteLog(temp);
}
return iRet;
}
//代理服务器登录
//char* g_proxyserver = "140.1xx.1x.1xx";
//int g_proxyport = 65500;
//char* g_proxyuser = "";
//char* g_proxypwd = "";
//int g_proxyid = 3; //2 - sock4代理 3 - sock5代理
//char server_name[100]= {0}; //真正的服务器地址
//int server_port=8000; //真正的服务器端口
int ConnecToProxyServer(SOCKET m_hSocketpop,char* g_proxyserver,int g_proxyport,char* g_proxyuser,char* g_proxypwd,int g_proxyid,char* server_name,int server_port,int connectType)
{
//原游戏连接信息
SOCKADDR_IN ToAddr;
memset(&ToAddr, 0, sizeof(ToAddr));
ToAddr.sin_family = AF_INET;
ToAddr.sin_addr.s_addr = inet_addr(g_proxyserver);//这是我的SOCKS服务器
ToAddr.sin_port = htons(g_proxyport);
int retCt = -1;
if (connectType == 1)
retCt = g_trueWSAConnect(m_hSocketpop,(SOCKADDR*)&ToAddr,sizeof(ToAddr),NULL,NULL,NULL ,NULL);
else
retCt = g_trueConnect(m_hSocketpop,(SOCKADDR*)&ToAddr,sizeof(ToAddr));
if( SOCKET_ERROR == retCt )
{
int iErr = WSAGetLastError();
if (iErr==WSAEWOULDBLOCK)
{
fd_set fdWrite;
timeval tv;
FD_ZERO(&fdWrite);//初始化fd_set
FD_SET(m_hSocketpop,&fdWrite);
tv.tv_sec = 30;
tv.tv_usec = 0;
int nRet = select(0,NULL,&fdWrite,NULL,&tv);
if (nRet<=0)
{
closesocket(m_hSocketpop);
return -111;
}
}
else
{
closesocket(m_hSocketpop);
return -112;
}
}
char buf[100] = {0};
if(g_proxyid == 3) //sock5 代理方式
{
// 让PROXY选择认证方法
buf[0] = 0x05;
buf[1] = 0x02; //确认2种认证方式 无需认证和需要认证
buf[2] = 0x00; // 无需认证
buf[3] = 0x02; // 需要认证
WriteLog(_T("Send a request asking if authentication is required"));
if(send(m_hSocketpop,(const far char*)buf,4,0) == SOCKET_ERROR)
{
closesocket(m_hSocketpop);
return -12;
}
//查询是否有返回
fd_set fdread;
timeval tv;
FD_ZERO(&fdread);//初始化fd_set
FD_SET(m_hSocketpop,&fdread);
tv.tv_sec = 30;
tv.tv_usec = 0;
int nRet;
nRet = select(0,&fdread,NULL,NULL,&tv);
if (nRet<=0)
{
return -122;
}
//接收返回
if(recv(m_hSocketpop,buf,10,0) == SOCKET_ERROR)
{
closesocket(m_hSocketpop);
return -13;
}
if(buf[1] == 0x02)
{
//需要认证
WriteLog(_T("need auth"));
char userStr[128] = {0};
userStr[0]=0x01;
userStr[1]=strlen(g_proxyuser);
strcpy(userStr+2,g_proxyuser);
userStr[2+ strlen(g_proxyuser)]= strlen(g_proxypwd);
strcpy(userStr+3+ strlen(g_proxyuser),g_proxypwd);
int result=send(m_hSocketpop,userStr,strlen(userStr), 0);
if(result == SOCKET_ERROR)
{
closesocket(m_hSocketpop);
return -1;
}
Sleep(100);
char validateChar[2] = {1};
result=recv(m_hSocketpop,validateChar,2, 0);
if(result == SOCKET_ERROR)
{
closesocket(m_hSocketpop);
return -1;
}
if(validateChar[1]!='\x00')
{//认证失败
closesocket(m_hSocketpop);
return -1;
}
}
// 向PROXY服务器发送CONNECT 请求,
WriteLog(_T("Send connect request to PROXY server!"));
memset(buf, 0, 100);
buf[0] = 0x05;
buf[1] = 0x01; // connection request.
buf[2] = 0x00; // reserved!
buf[3] = 0x01; // address type:Ip V4 ;
*((ULONG*)(buf+4))=inet_addr(server_name);
*((USHORT*)(buf+8))=htons(server_port);
if(send(m_hSocketpop,(const far char*)buf,10,0) == SOCKET_ERROR)
{
closesocket(m_hSocketpop);
return -14;
}
//Sleep(100);
FD_ZERO(&fdread);//初始化fd_set
FD_SET(m_hSocketpop,&fdread);
tv.tv_sec = 30;
tv.tv_usec = 0;
nRet = select(0,&fdread,NULL,NULL,&tv);
if (nRet<=0)
{
return -141;
}
// 接收PROXY服务器返回的REPLY
memset(buf, 1, 100);
if(recv(m_hSocketpop,buf, 20,0) == SOCKET_ERROR)
{
closesocket(m_hSocketpop);
return -15;
}
if(buf[1] != 0) // 只有当第二个字节为0时,才表示成功。
{
// printf("Cannot connect to the remote server!\n");
closesocket(m_hSocketpop);
return -16;
}
// theApp.m_ClientSocket.Attach(m_hSocketpop);
}
if(g_proxyid == 2) //sock4 代理方式
{
int result;
memset(buf, 0, 100);
buf[0] = 0x04;
buf[1] = 0x01; // connection request.
*((USHORT*)(buf+2))=htons(server_port);
*((ULONG*)(buf+4))=inet_addr(server_name);
buf[8] = 0x00;
result = send(m_hSocketpop, (const far char*)buf, 9, 0);
if(result == SOCKET_ERROR)
{
closesocket(m_hSocketpop);
return -1;
}
Sleep(100);
char EchoStr[10];
memset(EchoStr,0,10);
result=recv(m_hSocketpop,EchoStr,8, 0);
if(result == SOCKET_ERROR)
{
closesocket(m_hSocketpop);
return -1;
}
if(EchoStr[1] != 90)
{
closesocket(m_hSocketpop);
return -1;
}
// theApp.m_ClientSocket.Attach(m_hSocketpop);
}
return 0;
}
游戏会建立与本地服务器的连接,本地服务器会将游戏请求通过sock5发送到服务器上。实现游戏加速。
服务端架设参考:
用*-libev架设服务器端:
https://blog.csdn.net/wwzuizz/article/details/78194159