通过spi实现socks5代理(含错误代码)
代理客户端开发,截获某些应用的网络通讯,对网络数据进行socks5封包,然后通过支持socks5的通用代理服务器中转。
我现在对整个流程的技术如何实现感觉很糊涂,希望有高手能指点迷津。
首先我与代理服务器进行连接、协商、验证身份及获取代理服务器上传输端口应该在哪里来实现?是在WSPConnect里吗?
如果我在WSPConnect里实现是不是就不能用connect连接服务器,必须调用下一层lpWSPConnect来连接代理服务器。
还有如果获取到代理服务器上的传输端口,如何告知WSPSendTo服务器的端口是什么,因为一次可能不止一个网络应用在运行,如何保证每个应用发送数据时都能正确的发送到指定的代理服务器端口?是否需要在内存中建个列表,针对每个应用存储对应的端口?
我调试IE发现,即使在同一IE窗口、同一网站,每次打开一个网页都有2次WSPConnect过程,一个连接域名服务器,一次连接相应的网站服务器。
如果我要实现代理,是否每次WSPConnect过程都要实现与代理服务器连接、协商、验证身份及获取代理服务器上传输端口过程?
我现在对spi和socks5有一些了解(不是很深入),但是如何把这两个技术糅合到一起感觉非常迷惑,希望有过这方面开发经验的同志,能给我些提示,如果有例子源码更好。
在此十分感谢,下边是WSPConnect里实现与代理服务器进行连接、协商、验证身份及获取代理服务器上传输端口源码,感觉应该是错误的,我也是抄别人后自己瞎改的,大家看一下。
int WSPAPI WSPConnect(
SOCKET s,
const struct sockaddr FAR * name,
int namelen,
LPWSABUF lpCallerData,
LPWSABUF lpCalleeData,
LPQOS lpSQOS,
LPQOS lpGQOS,
LPINT lpErrno
)
{
ODS(_T("XFILTER.DLL: WSPConnect ..."));
if(m_CheckAcl.CheckConnect(s, name, namelen) != XF_PASS)
{
ODS2(_T("Deny the application "), m_sProcessName);
*lpErrno = WSAECONNREFUSED;
return SOCKET_ERROR;
}
//socks5代理
SOCKET tcp;
u_short m_n_port;
char buf[1024];
tcp = socket(AF_INET,SOCK_STREAM,0);
sockaddr_in addr,mAddr;
addr.sin_family= AF_INET;
addr.sin_addr.s_addr= inet_addr("159.226.26.71"); //代理服务地址(SuperProXY)
addr.sin_port= htons(8080);
if(connect(tcp,(sockaddr*)&addr,sizeof(addr))==SOCKET_ERROR)
{
closesocket(tcp);
return false;
}
memset(buf,0,1024);
buf[0]=0x05;
buf[1]=0x02;
buf[2]=0x00;
buf[3]=0x02;
send(tcp,buf,4,0);
memset(buf,0,1024);
if(recv(tcp,buf,1024,0)==SOCKET_ERROR)
{
closesocket(tcp);
return false;
}
//分析第一个接收数据
if(buf[0]==0x05 && buf[1]==0x02)
{
AfxMessageBox("需要验证密码!");
}
else if(buf[0]!=0x05 || buf[1]!=0x00)
{
closesocket(tcp);
return false;
}
//第二步操作(我的代理服务不需要验证所以直接到了下一步)
memset(buf,0,1024);
buf[0]=0x05;
buf[1]=0x03; //0x03 UDP命令
buf[2]=0x00;//保留字节
buf[3]=0x01;//地址类型 1表示 IPV4
mAddr.sin_family= AF_INET;
mAddr.sin_addr.s_addr= inet_addr("1.1.51.227"); //远程服务地址(演示需要就在本机运行的)
mAddr.sin_port= htons(8001);
*((int *)(&buf[4])) = mAddr.sin_addr.s_addr;
*((short *)(&(buf[8]))) = (short)mAddr.sin_port;
send(tcp,buf,10,0);
memset(buf,0,1024);
if(recv(tcp,buf,1024,0)==SOCKET_ERROR)
{
closesocket(tcp);
return false;
}
//回答信息:版本 | 代理的应答 | 保留1字节 | 地址类型 | 绑定的地址 | 绑定的代理端口
if(buf[0]!=0x05 || buf[1]!=0x00) //00表示成功
{
closesocket(tcp);
return false;
}
if(buf[3]==0x01) //已经执行到该步了
{
char m_sz_udp_srv[1024];
int n_ip = *((int *)&buf[4]);
memset((void *)m_sz_udp_srv,0,sizeof(m_sz_udp_srv));
in_addr in;
in.S_un.S_addr = n_ip;
strcpy(m_sz_udp_srv,inet_ntoa(in)); //得到值为1.1.51.227
m_n_port = htons(*((short *)&(buf[8]))); //端口1328
}
else
{
closesocket(tcp);
return false;
}
//发送数据了
addr.sin_family= AF_INET;
addr.sin_addr.s_addr= inet_addr("1.1.51.227"); //点分地址
addr.sin_port= htons(8001);//这个ip是服务器端的ip
buf[0] = 0x00;
buf[1] = 0x00; //RSV 保留 0000
buf[2] = 0x00; //FRAH 分段号 00表示独立
buf[3] = 0x01; //ATYP IPV4 01
buf[4]=(char)addr.sin_addr.S_un.S_un_b.s_b1;
buf[5]=(char)addr.sin_addr.S_un.S_un_b.s_b2;
buf[6]=(char)addr.sin_addr.S_un.S_un_b.s_b3;
buf[7]=(char)addr.sin_addr.S_un.S_un_b.s_b4;
*((SHORT*)(&(buf[8])))=addr.sin_port;
buf[10] = 18;
struct sockaddr_in bndaddr;
bndaddr.sin_family = AF_INET;
bndaddr.sin_addr.s_addr = inet_addr("1.1.51.227");//返回时绑定的IP
bndaddr.sin_port = htons(m_n_port);//发送请求的时返回的代理绑定的端口
int addr_len;
addr_len=sizeof(struct sockaddr);
int returndatalen=sendto(s,(char *)buf,strlen(buf),0,(struct sockaddr *)&bndaddr,addr_len);
//return NextProcTable.lpWSPConnect(s, name, namelen, lpCallerData, lpCalleeData, lpSQOS, lpGQOS, lpErrno);
}