2005-7-22 21:47
无双
作者: 无双 花了半天时间<br /><br />可以当成学习socks协议的一个例子 或是当成练习多线程的例子 或是当成学习c++的例子<br /><br />功能:<br />自动把socks5协议转换成socks4协议 支持多个连接<br />因为现在有些只支持socks4协议(想修改成使用http协议的 不过公司内的http不支持connect请求 )<br /><br /><!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1--><br />#include <winsock2.h><br />#include <windows.h><br />#include <stdio.h><br /><br />#include <vector><br />#include <iterator><br />using namespace std;<br /><br />#include "log.h"<br /><br />#define CLOSE_SOCKET(x) closesocket(x)<br /><br />struct TS5Info{<br /> private:<br /> struct TSockPair{<br /> int insd;<br /> int outsd;<br /> };<br /><br /> bool isinit;<br /><br /> int s4_connect(char *dstinfo,int &port);<br /> static DWORD WINAPI recv_thread(void* );<br /> static DWORD WINAPI send_thread(void* );<br /> bool create_threads(int outsd);<br /> public:<br /><br /> enum EParseRet{<br /> EERR, // have error,should terminate<br /> EWAIT, // not finish connect,continue waiting<br /> EFINISH // finish connect,the manager can remove this item<br /> };<br /><br /> int sd;<br /><br /> TS5Info(int socketid = -1){<br /> sd = socketid;<br /> isinit = false;<br /> }<br /><br /> TS5Info(const TS5Info& info){<br /> sd = info.sd;<br /> isinit = info.isinit;<br /> }<br /><br /> EParseRet parse_connect();<br />};<br /><br />static struct sockaddr_in s_proxyaddr;<br /><br />static int start_listen(int port);<br />static void start_accept(int ld);<br /><br />int main()<br />{<br /> WSADATA wsaData;<br /> WSAStartup( MAKEWORD(2,2), &wsaData );<br /><br /> InitDebugLog("./log.txt");<br /> memset(&s_proxyaddr,0,sizeof(s_proxyaddr));<br /> s_proxyaddr.sin_addr.s_addr = inet_addr("218.104.127.157");<br /> s_proxyaddr.sin_family = AF_INET;<br /> s_proxyaddr.sin_port = htons(9190);<br /><br /> int ld = start_listen(1080);<br /> if( ld > -1 )<br /> start_accept(ld);<br /><br /> CloseDebugLog();<br /> WSACleanup();<br /> printf("finish\n");<br /><br /> return 0;<br />}<br /><br /><br />static int start_listen(int port)<br />{<br /> int sd = socket(AF_INET,SOCK_STREAM,0);<br /> if( sd == -1 )<br /> return -1;<br /><br /> int option = 1;<br /> setsockopt ( sd, SOL_SOCKET, SO_REUSEADDR,<br /> (const char*)&option,<br /> sizeof( option ) );<br /><br /> struct sockaddr_in dstaddr;<br /> memset(&dstaddr,0,sizeof(dstaddr));<br /><br /> dstaddr.sin_port = htons(port);<br /> dstaddr.sin_family = AF_INET;<br /><br /> if( bind( sd,(struct sockaddr*)&dstaddr,sizeof(dstaddr))<br /> || listen(sd,SOMAXCONN)){<br /> CLOSE_SOCKET(sd);<br /> return -1;<br /> }<br /><br /> return sd;<br />}<br /><br /><br />static void start_accept(int ld)<br />{<br /> vector<TS5Info> conn_list;<br /> while(1){<br /> fd_set sset;<br /> FD_ZERO(&sset);<br /><br /> FD_SET(ld,&sset);<br /> vector<TS5Info>::iterator iter = conn_list.begin();<br /><br /> for(;iter != conn_list.end();iter++)<br /> FD_SET(iter->sd,&sset);<br /><br /> int ret = select(0,&sset,NULL,NULL,NULL);<br /> if( ret < 1 ){<br /> printf("select error,%d\n",WSAGetLastError());<br /> break;<br /> }<br /><br /> if(FD_ISSET(ld,&sset)){<br /> ret --;<br /> struct sockaddr_in peeraddr;<br /> int peersize = sizeof(peeraddr);<br /> int sd = accept(ld,(struct sockaddr*)&peeraddr,&peersize);<br /> if( sd > -1 ){<br /> printf("accept a client connect,peer info:%s:%d\n",<br /> inet_ntoa(peeraddr.sin_addr),ntohs(peeraddr.sin_port));<br /> TS5Info info(sd);<br /> conn_list.push_back(info);<br /> }<br /> }<br /><br /> iter = conn_list.begin();<br /> int i= 0;<br /> while( ret > 0 && iter != conn_list.end() ){<br /> if(FD_ISSET(iter->sd,&sset)){<br /> ret --;<br /> TS5Info::EParseRet parseret = iter->parse_connect();<br /> if( parseret != TS5Info::EWAIT ){<br /> if(parseret == TS5Info::EERR )<br /> CLOSE_SOCKET(iter->sd);<br /><br /> conn_list.erase(iter);<br /> iter = conn_list.begin();<br /> advance(iter,i);<br /> }<br /> else{<br /> iter++;<br /> i++;<br /> }<br /> }<br /> else{<br /> iter++;<br /> i++;<br /> }<br /> }<br /> }<br />}<br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br />int TS5Info::s4_connect(char *dstinfo,int &port )<br />{<br /> int sd = socket(AF_INET,SOCK_STREAM,0);<br /> if( sd < 0 )<br /> return -1;<br /><br /> if(connect(sd,(struct sockaddr*)&s_proxyaddr,sizeof(s_proxyaddr))){<br /> CLOSE_SOCKET(sd);<br /> return -1;<br /> }<br /><br /> char buf[20];<br /> memset(buf,0,sizeof(buf));<br /> buf[0] = 4;<br /> buf[1] = 1;<br /> *(unsigned short*)(buf+2) = port;<br /> memcpy(buf+4,dstinfo,4);<br /><br /> if( send(sd,buf,9,0) != 9){<br /> CLOSE_SOCKET(sd);<br /> return -1;<br /> }<br /><br /> timeval wait={30,0};<br /> fd_set sset;<br /><br /> FD_ZERO(&sset);<br /> FD_SET(sd,&sset);<br /><br /> int ret = select(sd+1,&sset,NULL,NULL,&wait);<br /> if( ret == 1 && recv(sd,buf,8,0) == 8 ){<br /> memcpy(dstinfo,buf+4,4);<br /> port = *(unsigned short*)(buf+2);<br /> return sd;<br /> }<br /><br /> CLOSE_SOCKET(sd);<br /> return -1;<br />}<br /><br />TS5Info::EParseRet TS5Info::parse_connect()<br />{<br /> char buf[320];<br /> memset(buf,0,sizeof(buf));<br /><br /> int bufsize = recv(sd,buf,sizeof(buf),0);<br /> if( bufsize < 1 )<br /> return EERR;<br /><br /> if( buf[0] != 0x5){<br /> LogDebugInfo("wrong socks5 package,pkg head:0x%02x\n",buf[0]);<br /> return EERR;<br /> }<br /><br /> if( !isinit ){<br /> if( bufsize < 3 || bufsize != 2+ buf[1] ){<br /> LogDebugInfo("wrong socks5 negrate package,size:%d,pkg:0x%02x%02x%02x\n",bufsize,buf[0],buf[1],buf[2]);<br /> return EERR;<br /> }<br /><br /> buf[1] = 0;<br /> if( send(sd,buf,2,0) != 2)<br /> return EERR;<br /><br /> isinit = true;<br /> bufsize = 0;<br /> return EWAIT;<br /> }<br /><br /> if( bufsize < 6 || buf[1] != 0x1 || buf[2] != 0 || (buf[3] != 0x1 && buf[3] != 0x3) <br /> || (buf[3] == 0x1 && bufsize != 10 ) // is ip connect mode,but length error<br /> || buf[3] == 0x3 && bufsize != 7+buf[4]){<br /> LogDebugInfo("wrong socks5 command package,size:%d,pkg:0x%02x%02x%02x%02x%02x\n",<br /> bufsize,buf[0],buf[1],buf[2],buf[3],buf[4]);<br /> return EERR;<br /> }<br /><br /> int port = *(unsigned short*)(buf+bufsize-2);<br /> char dstinfo[4];<br /> memset(&dstinfo,0,sizeof(dstinfo));<br /><br /> if( buf[3] == 0x1 )<br /> memcpy(dstinfo,buf+4,4);<br /> else{<br /> char tmp[260];<br /> memset(tmp,0,sizeof(tmp));<br /> memcpy( tmp ,buf+5,buf[4] );<br /> hostent *ent = gethostbyname( tmp );<br /> if( ent && AF_INET == ent->h_addrtype && ent->h_addr )<br /> memcpy(dstinfo,ent->h_addr,4);<br /> else{<br /> printf("DNS(%s) fail\n",tmp);<br /> return EERR;<br /> }<br /> }<br /><br /> int outsd = s4_connect(dstinfo,port);<br /> if( outsd > 0 ){<br /> memset(buf,0,sizeof(buf));<br /> buf[0] = 5;<br /> buf[1] = 0;<br /> buf[3] = 1;<br /> memcpy(buf+4,dstinfo,4);<br /> memcpy(buf+8,&port,2);<br /> if( send(sd,buf,10,0) != 10 ){<br /> CLOSE_SOCKET(outsd);<br /> return EERR;<br /> }<br /> if( create_threads(outsd) )<br /> return EFINISH;<br /> }<br /><br /> CLOSE_SOCKET(outsd);<br /> return EERR;<br />}<br /><br />DWORD WINAPI TS5Info::recv_thread(void* param)<br />{<br /> if( !param )<br /> return 0;<br /><br /> TSockPair* p = (TSockPair*)param;<br /> int insd = p->insd;<br /> int outsd = p->outsd;<br /> delete p;<br /> while(1){<br /> char buf[4096];<br /> memset(buf,0,sizeof(buf));<br /> int size = recv(outsd,buf,sizeof(buf)-1,0);<br /> LogDebugInfo("send_thread<%d:%s>",buf,size);<br /> if( size <= 0 )<br /> break;<br /><br /> const char* pbuf = buf;<br /> while( size > 0 ){<br /> int ret = send(insd,pbuf,size,0);<br /> if( ret <= 0 )<br /> goto end;<br /><br /> size -= ret;<br /> pbuf += ret;<br /> }<br /> }<br /><br />end:<br /> CLOSE_SOCKET(insd);<br /> CLOSE_SOCKET(outsd);<br /> return 0;<br />}<br /><br />DWORD WINAPI TS5Info::send_thread(void* param)<br />{<br /> if( !param )<br /> return 0;<br /><br /> TSockPair* p = (TSockPair*)param;<br /> int insd = p->insd;<br /> int outsd = p->outsd;<br /> delete p;<br /> while(1){<br /> char buf[4096];<br /> memset(buf,0,sizeof(buf));<br /> int size = recv(insd,buf,sizeof(buf)-1,0);<br /> LogDebugInfo("send_thread<%d:%s>",buf,size);<br /> if( size <= 0 )<br /> break;<br /><br /> const char* pbuf = buf;<br /> while( size > 0 ){<br /> int ret = send(outsd,pbuf,size,0);<br /> if( ret <= 0 )<br /> goto end;<br /><br /> size -= ret;<br /> pbuf += ret;<br /> }<br /> }<br /><br />end:<br /> CLOSE_SOCKET(insd);<br /> CLOSE_SOCKET(outsd);<br /> return 0;<br />}<br /><br />bool TS5Info::create_threads(int outsd)<br />{<br /> TSockPair* p1 = new TSockPair;<br /> TSockPair* p2 = new TSockPair;<br /><br /> if( p1 && p2 ){<br /> p1->insd = sd;<br /> p1->outsd = outsd;<br /> memcpy(p2,p1,sizeof(TSockPair));<br /><br /> DWORD threadid;<br /> HANDLE hthreadsend = CreateThread(NULL,0,TS5Info::send_thread,(void*)p1,0,&threadid);<br /> if( hthreadsend ){<br /> HANDLE hthreadrecv = CreateThread(NULL,0,TS5Info::recv_thread,(void*)p2,0,&threadid);<br /> if( hthreadrecv ){<br /> CloseHandle(hthreadrecv);<br /> CloseHandle(hthreadsend);<br /> return true;<br /> }<br /> else{<br /> TerminateThread(hthreadsend,0);<br /> CloseHandle(hthreadsend);<br /> }<br /> }<br /> }<br /><br /> delete p1;<br /> delete p2;<br /> return false;<br />}<br /><br /><br /><br /><br /><!--c2--></div><!--ec2-->