2004-6-5 10:36
无双
socks5代理可以看rfc 1928<br />socks5的用户名口令认证方法看rfc 1929<br /><br />http代理可以看 rfc2616<br />socks5代理可以支持tcp和udp 而http只支持tcp<br /><br />所以这个代理转换器只支持tcp<br /><br /><br />写作原因<br />很多软件都有socks5认证方法 但是它们不支持http认证方法<br />而从原理上可以使用http认证方法(因为它们没有使用udp)<br />所以写这个软件可以方便的使其它程序可以使用http代理<br /><br />如联众 或是foxmail<br /><br /><!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1--><br />#include <winsock2.h><br />#include <stdio.h><br />#include <stdlib.h><br />#define INIT_SOCKET(){WSADATA wsadata;WSAStartup(MAKEWORD(2,2),&wsadata);}<br />#define CLOSESOCKET(x) closesocket(x)<br />#define CLEAN_SOCKET() {WSACleanup();}<br />// http.c 实现http代理功能<br /><br />#define PROTO_EXCHANGE_TIMEOUT 15<br />#define PROTO_RECVRESP_TIMEOUT 75<br />#define PROTO_SENDRESP_TIMEOUT 10<br /><br />#define WAIT_AND_RECV(sd,buf,len,waittime,recvflags) do{\<br /> struct fd_set sset;\<br /> struct timeval waited;\<br /> waited.tv_sec = waittime;waited.tv_usec = 0;\<br /> FD_ZERO(&sset);FD_SET(sd,&sset);\<br /> if(select(sd+1,&sset,NULL,NULL,&waited) != 1 || (len = recv(sd,buf,len,recvflags)) == -1 )\<br /> len = -1;\<br />}while(0);<br /><br />#define DEBUG_DUMP printf<br /><br />static int httpproxy_connect(const char*proxyaddr,int proxyport,<br /> const char*dstaddr,int dstport)<br />{<br /> int proxysd = -1;<br /> char buf[2048];<br /> int len;<br /> char *ptoken;<br /> int status;<br /><br /> struct sockaddr_in inaddr;<br /><br /> if( !proxyaddr || !proxyaddr[0] || proxyport < 1<br /> ||!dstaddr || !dstaddr[0] )<br /> return -1;<br /><br /> DEBUG_DUMP("代理:%s:%d,目标:%s:%d\n",proxyaddr,proxyport,dstaddr,dstport);<br /><br /> len = sizeof(inaddr);<br /> memset(&inaddr,0,len);<br /> if( (inaddr.sin_addr.s_addr = inet_addr(proxyaddr) ) == INADDR_NONE )<br /> return -1;<br /><br /> inaddr.sin_family = AF_INET;<br /> inaddr.sin_port = htons(proxyport);<br /><br /> // connect to proxy<br /> if((proxysd = socket(AF_INET,SOCK_STREAM,0)) == -1 )<br /> return -1;<br /> if( connect(proxysd,(struct sockaddr*)&inaddr,len))<br /> goto errorparse;<br /><br /> // 发送connect请求并判断返回,根据HTTP协议说明,详细内容请看RFC2616<br /> // HTTP代理使用CONNECT指令实现,CONNECT时指定选端的地址与端口号,<br /> // 当代理服务器返回成功后(状态值是2xx),后面的代理服务器不再对此连接的数据<br /> // 进行HTTP协议处理<br /> if( dstport > 0 )<br /> len = sprintf(buf,"CONNECT %s:%d HTTP/1.1\r\n\r\n",dstaddr,dstport);<br /> else<br /> len = sprintf(buf,"CONNECT %s HTTP/1.1\r\n\r\n",dstaddr);<br /><br /> if( send(proxysd,buf,len,0) != len ){<br /> DEBUG_DUMP("发送CONNECT请求失败:包内容:%s\n",buf);<br /> goto errorparse;<br /> }<br /><br /> len = sizeof(buf)-1;<br /> WAIT_AND_RECV(proxysd,buf,len,PROTO_RECVRESP_TIMEOUT,MSG_PEEK);<br /> if( len == -1){<br /> DEBUG_DUMP("接收CONNECT响应失败\n");<br /> goto errorparse;<br /> }<br /><br /> buf[len] = 0;<br /> DEBUG_DUMP("CONNECT响应为:%s|\n",buf);<br /> if( strnicmp(buf,"HTTP/1.",7)<br /> || (!strstr(buf,"\r\n\r\n") && !strstr(buf,"\n\n")))<br /> goto errorparse;<br /><br /> ptoken = buf;<br /> while(!isspace(*ptoken) && *ptoken) ptoken ++;<br /> status = atoi(ptoken);<br /> if( status < 300 && status > 199 ){<br /> ptoken = strstr(buf,"\r\n\r\n");<br /> if( ptoken )<br /> len = ptoken - buf +4;<br /> else{<br /> ptoken = strstr(buf,"\n\n");<br /> len = ptoken - buf +2;<br /> }<br /> WAIT_AND_RECV(proxysd,buf,len,PROTO_RECVRESP_TIMEOUT,0);<br /> return proxysd;<br /> }<br /><br />errorparse:<br /> CLOSESOCKET(proxysd);<br /> return -1;<br />}<br /><br />// sd [in] 使用socks5的客户端的连接id<br />// proxyaddr [in] http代理地址<br />// proxyport [in] http代理端口<br />// return:<br />// -1 失败<br />// >=0 与http代理的连接id<br />static int socks5_accept(int sd,const char *proxyaddr,int proxyport)<br />{<br /> unsigned char buf[512];<br /> int len = 2;<br /> int i = 0;<br /> char dstaddr[260];<br /> int dstport;<br /><br /> if( !proxyaddr || !proxyaddr[0] || proxyport <1 )<br /> return -1;<br /><br /> // 处理协商,现在只处理无认证情况,无论对方会不会处理这种情况<br /> // 没有要求无认证方式,sorry,那我就不理它<br /> // 另外只处理SOCKS5的CONNECT命令,其它不处理<br /> WAIT_AND_RECV(sd,(char*)buf,len,PROTO_EXCHANGE_TIMEOUT,0);<br /> if( len != 2 || buf[0] != 5 ){<br /> DEBUG_DUMP("接收socks5协商包失败,len:%d,buf[0]:%d\n",len,buf[0]);<br /> return -1;<br /> }<br /> len = buf[1];<br /> i = len;<br /> WAIT_AND_RECV(sd,(char*)buf,i,PROTO_EXCHANGE_TIMEOUT,0);<br /> if( len != i ){<br /> DEBUG_DUMP("接收socks5协商包失败,想接收%d,收到:%d\n",len,i);<br /> return -1;<br /> }<br /><br /> for( i = 0;i< len && buf[i];i++ );<br /><br /> if( i == len ){<br /> DEBUG_DUMP("用户没有请求socks5无认证方法:\n");<br /> return -1;<br /> }<br /><br /> buf[0] = 5;<br /> buf[1] = 0;<br /> if( send(sd,(char*)buf,2,0) != 2)<br /> return -1;<br /><br /> len = 5;<br /> WAIT_AND_RECV(sd,(char*)buf,len,PROTO_RECVRESP_TIMEOUT,0);<br /> if( len != 5 || buf[0] != 5 || buf[1] != 1 ){<br /> DEBUG_DUMP("处理socks5CONNECT命令失败:len:%d,buf[0]:0x%x,buf[1]:0x%x\n",len,buf[0],buf[1]);<br /> return -1;<br /> }<br /><br /> switch( buf[3] ){<br /> case 1: // 是IP地址<br /> len = 5;<br /> WAIT_AND_RECV(sd,(char*)buf+5,len,PROTO_RECVRESP_TIMEOUT,0);<br /> if( len != 5 ){<br /> DEBUG_DUMP("处理socks5CONNECT命令[IP方式]失败:len:%d\n",len);<br /> return -1;<br /> }<br /> {<br /> struct in_addr addr;<br /> memcpy((char*)&addr.s_addr,buf+4,4);<br /> strcpy(dstaddr,inet_ntoa(addr));<br /> dstport = ntohs(*(unsigned short*)(buf+8));<br /> }<br /> break;<br /> case 3: // 是域方式<br /> len = buf[4]+2;<br /> WAIT_AND_RECV(sd,(char*)buf+5,len,PROTO_RECVRESP_TIMEOUT,0);<br /> if( len != buf[4]+2 ){<br /> DEBUG_DUMP("处理socks5CONNECT命令[域方式]失败:len:%d\n",len);<br /> return -1;<br /> }<br /> memcpy(dstaddr,buf+5,buf[4]);<br /> dstaddr[buf[4]] = 0;<br /> dstport = ntohs(*(unsigned short*)(buf+5+buf[4]));<br /> break;<br /> default:<br /> DEBUG_DUMP("处理socks5CONNECT命令[]失败:未知方式:type:0x%x\n",buf[3]);<br /> return -1;<br /> }<br /><br /> return httpproxy_connect(proxyaddr,proxyport,dstaddr,dstport);<br />}<br /><br />int listenport(int port,const char*addr)<br />{<br /> int len = sizeof(struct sockaddr_in);<br /> struct sockaddr_in bindaddr;<br /><br /> int sd = socket(AF_INET,SOCK_STREAM,0);<br /> if( sd == -1)<br /> return -1;<br /><br /> memset(&bindaddr,0,len);<br /> bindaddr.sin_family = AF_INET;<br /> bindaddr.sin_port = htons(port);<br /> if( addr && addr[0] )<br /> bindaddr.sin_addr.s_addr = inet_addr(addr);<br /><br /> if( bind ( sd,(struct sockaddr*)&bindaddr,&len) || listen(sd,100 )){<br /> DEBUG_DUMP("打开端口失败,port:%d\n",port);<br /> CLOSESOCKET(sd);<br /> return -1;<br /> }<br /><br /> return sd;<br />}<br /><br />void running(int sd){<br /> int ad;<br /> if( sd == -1 )<br /> return;<br /><br /> while(1){<br /> int proxyid;<br /> char buf[10240];<br /> int len;<br /> int maxid;<br /> int actcount;<br /><br /> ad = accept(sd,NULL,NULL);<br /> if( ad == -1 )<br /> break;<br /><br /> DEBUG_DUMP("有客户连接,id:%d\n",ad);<br /> if((proxyid = socks5_accept(ad,"172.16.68.21",80)) == -1 ){<br /> CLOSESOCKET(ad);<br /> continue;<br /> }<br /><br /> // 进行代理转发工作<br /> maxid = ad > proxyid? ad:proxyid;<br /> while( ad > -1 ){<br /> struct timeval waittime = {10,0};<br /> struct fd_set sset;<br /> FD_ZERO(&sset);<br /> FD_SET(ad,&sset);<br /> FD_SET(proxyid,&sset);<br /><br /> actcount = select(maxid+1,&sset,NULL,NULL,&waittime);<br /> while(actcount > 0 ){<br /> int actid = FD_ISSET(proxyid,&sset)?proxyid:ad;<br /> int sendid = actid == ad? proxyid:ad;<br /><br /> FD_CLR(actid,&sset);<br /> len = sizeof(buf)-1;<br /> WAIT_AND_RECV(actid,buf,len,10,0);<br /> if( len > 0 ){<br /> buf[len] = 0;<br /> send(sendid,buf,len,0);<br /> DEBUG_DUMP("%d接口活动,内容为:%s\n",actid,buf);<br /> }<br /> else{<br /> DEBUG_DUMP("接收失败,id:%d\n",actid);<br /> CLOSESOCKET(ad);<br /> ad = -1;<br /> break;<br /> }<br /> actcount --;<br /> }<br /> }<br /> // 某一方已经关闭,继续下一组转发<br /> CLOSESOCKET(proxyid);<br /> }<br /> CLOSESOCKET(sd);<br />}<br /><br />main(){<br /> int ld;<br /> INIT_SOCKET();<br /> ld = listenport(1080,NULL);<br /> if( ld != -1)<br /> running(ld);<br /> else<br /> DEBUG_DUMP("监听失败\n");<br /> CLEAN_SOCKET();<br />}<br /><br /><!--c2--></div><!--ec2-->