C语言写的linux socks Proxy
C语言写的Linux平台socks5代理程序
信息来源:邪恶八进制信息安全团队(www.eviloctal.com)
前几天MSN老上不去,我还以为是公司做了防火墙限制。于是把去年这个时候写得一个代理程序改了改,拿出来用。结果发现MSN是因为微软的问题,鄙视啊……
因为写得比较急,这个只支持TCP代理,UDP的我没写,因为MSN用不上。这个代码可以随意修改分发,不过最好能给我一份。
这是头文件:
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Socks5代理头文件,定义协议相关数据包结构
//版本0.1,作者云舒
//2007年1月9日凌晨1点15分,GF回家已经11天了。
//2008年1月25日修改,今年GF一直在我身边,哈哈
//
//参考:
//http://www.rfc-editor.org/rfc/rfc1928.txt
//http://www.rfc-editor.org/rfc/rfc1929.txt
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
#ifndefSOCKS5_H
#defineSOCKS5_H
#defineVERSION0x05
#defineCONNECT0x01
#defineIPV40x01
#defineDOMAIN0x03
#defineIPV60x04
typedefstruct_method_select_response//协商方法服务器响应
{
charversion;//服务器支持的Socks版本,0x04或者0x05
charselect_method;//服务器选择的方法,0x00为匿名,0x02为密码认证
}METHOD_SELECT_RESPONSE;
typedefstruct_method_select_request//协商方法服务端请求
{
charversion;//客户端支持的版本,0x04或者0x05
charnumber_methods;//客户端支持的方法的数量
charmethods[255];//客户端支持的方法类型,最多255个,0x00为匿名,0x02为密码认证
}METHOD_SELECT_REQUEST;
typedefstruct_AUTH_RESPONSE//用户密码认证服务端响应
{
charversion;//版本,此处恒定为0x01
charresult;//服务端认证结果,0x00为成功,其他均为失败
}AUTH_RESPONSE;
typedefstruct_AUTH_REQUEST//用户密码认证客户端请求
{
charversion;//版本,此处恒定为0x01
charname_len;//第三个字段用户名的长度,一个字节,最长为0xff
charname[255];//用户名
charpwd_len;//第四个字段密码的长度,一个字节,最长为0xff
charpwd[255];//密码
}AUTH_REQUEST;
typedefstruct_SOCKS5_RESPONSE//连接真实主机,Socks代理服务器响应
{
charversion;//服务器支持的Socks版本,0x04或者0x05
charreply;//代理服务器连接真实主机的结果,0x00成功
charreserved;//保留位,恒定位0x00
charaddress_type;//Socks代理服务器绑定的地址类型,IPV4为0x01,IPV6为0x04,域名为0x03
charaddress_port[1];//如果address_type为域名,此处第一字节为域名长度,其后为域名本身,无0字符结尾,域名后为Socks代理服务器绑定端口
}SOCKS5_RESPONSE;
typedefstruct_SOCKS5_REQUEST//客户端请求连接真实主机
{
charversion;//客户端支持的Socks版本,0x04或者0x05
charcmd;//客户端命令,CONNECT为0x01,BIND为0x02,UDP为0x03,一般为0x01
charreserved;//保留位,恒定位0x00
charaddress_type;//客户端请求的真实主机的地址类型,IPV4为0x00,IPV6为0x04,域名为0x03charaddress_port[1];//如果address_type为域名,此处第一字节为域名长度,其后为域名本身,无0字符结尾,域名后为真实主机绑定端口
}SOCKS5_REQUEST;
#endif
主程序来了:
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Socks5程序,只支持TCP代理
//版本0.1,作者云舒
//2007年1月9日凌晨1点15分,GF回家已经11天了。
//2008年1月25日修改,今年GF一直在我身边,哈哈
//
//参考:
//http://www.rfc-editor.org/rfc/rfc1928.txt
//http://www.rfc-editor.org/rfc/rfc1929.txt
//编译:
//gcc-osocks5-O2Socks5.c-lpthread(RedHatAS5测试)
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
#include<stdio.h>
#include<netinet/in.h>
#include<netdb.h>
#include<sys/time.h>
#include<sys/types.h>
#include<unistd.h>
#include<stdlib.h>
#include<signal.h>
#include<pthread.h>
#include<errno.h>
#include<string.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include"Socks5.h"
#defineMAX_USER10
#defineBUFF_SIZE1024
#defineAUTH_CODE0x02
#defineTIME_OUT6000000
#defineUSER_NAME"yunshu"
#definePASS_WORD"ph4nt0m"
//Selectauthmethod,return0ifsuccess,-1iffailed
intSelectMethod(intsock)
{
charrecv_buffer[BUFF_SIZE]={0};
charreply_buffer[2]={0};
METHOD_SELECT_REQUEST*method_request;
METHOD_SELECT_RESPONSE*method_response;
//recvMETHOD_SELECT_REQUEST
intret=recv(sock,recv_buffer,BUFF_SIZE,0);
if(ret<=0)
{
perror("recverror");
close(sock);
return-1;
}
//printf("SelectMethod:recv%dbytes\n",ret);
//ifclientrequestawrongversionorawrongnumber_method
method_request=(METHOD_SELECT_REQUEST*)recv_buffer;
method_response=(METHOD_SELECT_RESPONSE*)reply_buffer;
method_response->version=VERSION;
//ifnotsocks5
if((int)method_request->version!=VERSION)
{
method_response->select_method=0xff;
send(sock,method_response,sizeof(METHOD_SELECT_RESPONSE),0);
close(sock);
return-1;
}
method_response->select_method=AUTH_CODE;
if(-1==send(sock,method_response,sizeof(METHOD_SELECT_RESPONSE),0))
{
close(sock);
return-1;
}
return0;
}
//testpassword,return0forsuccess.
intAuthPassword(intsock)
{
charrecv_buffer[BUFF_SIZE]={0};
charreply_buffer[BUFF_SIZE]={0};
AUTH_REQUEST*auth_request;
AUTH_RESPONSE*auth_response;
//authusernameandpassword
intret=recv(sock,recv_buffer,BUFF_SIZE,0);
if(ret<=0)
{
perror("recvusernameandpassworderror");
close(sock);
return-1;
}
//printf("AuthPass:recv%dbytes\n",ret);
auth_request=(AUTH_REQUEST*)recv_buffer;
memset(reply_buffer,0,BUFF_SIZE);
auth_response=(AUTH_RESPONSE*)reply_buffer;
auth_response->version=0x01;
charrecv_name[256]={0};
charrecv_pass[256]={0};
//auth_request->name_lenisachar,maxnumberis0xff
charpwd_str[2]={0};
strncpy(pwd_str,auth_request->name+auth_request->name_len,1);
intpwd_len=(int)pwd_str[0];
strncpy(recv_name,auth_request->name,auth_request->name_len);
strncpy(recv_pass,auth_request->name+auth_request->name_len+sizeof(auth_request->pwd_len),pwd_len);
//printf("username:%s\npassword:%s\n",recv_name,recv_pass);
//checkusernameandpassword
if((strncmp(recv_name,USER_NAME,strlen(USER_NAME))==0)&&
(strncmp(recv_pass,PASS_WORD,strlen(PASS_WORD))==0)
)
{
auth_response->result=0x00;
if(-1==send(sock,auth_response,sizeof(AUTH_RESPONSE),0))
{
close(sock);
return-1;
}
else
{
return0;
}
}
else
{
auth_response->result=0x01;
send(sock,auth_response,sizeof(AUTH_RESPONSE),0);
close(sock);
return-1;
}
}
//parsecommand,andtrytoconnectrealserver.
//returnsocketforsuccess,-1forfailed.
intParseCommand(intsock)
{
charrecv_buffer[BUFF_SIZE]={0};
charreply_buffer[BUFF_SIZE]={0};
SOCKS5_REQUEST*socks5_request;
SOCKS5_RESPONSE*socks5_response;
//recvcommand
intret=recv(sock,recv_buffer,BUFF_SIZE,0);
if(ret<=0)
{
perror("recvconnectcommanderror");
close(sock);
return-1;
}
socks5_request=(SOCKS5_REQUEST*)recv_buffer;
if((socks5_request->version!=VERSION)||(socks5_request->cmd!=CONNECT)||
(socks5_request->address_type==IPV6))
{
//printf("connectcommanderror.\n");
close(sock);
return-1;
}
//begainprocessconnectrequest
structsockaddr_insin;
memset((void*)&sin,0,sizeof(structsockaddr_in));
sin.sin_family=AF_INET;
//getrealserver'sipaddress
if(socks5_request->address_type==IPV4)
{
memcpy(&sin.sin_addr.s_addr,&socks5_request->address_type+sizeof(socks5_request->address_type),4);
memcpy(&sin.sin_port,&socks5_request->address_type+sizeof(socks5_request->address_type)+4,2);
//printf("RealServer:%s%d\n",inet_ntoa(sin.sin_addr),ntohs(sin.sin_port));
}
elseif(socks5_request->address_type==DOMAIN)
{
chardomain_length=*(&socks5_request->address_type+sizeof(socks5_request->address_type));
chartarget_domain[256]={0};
strncpy(target_domain,&socks5_request->address_type+2,(unsignedint)domain_length);
//printf("target:%s\n",target_domain);
structhostent*phost=gethostbyname(target_domain);
if(phost==NULL)
{
//printf("Resolve%serror!\n",target_domain);
close(sock);
return-1;
}
memcpy(&sin.sin_addr,phost->h_addr_list[0],phost->h_length);
memcpy(&sin.sin_port,&socks5_request->address_type+sizeof(socks5_request->address_type)+
sizeof(domain_length)+domain_length,2);
}
//trytoconnecttorealserver
intreal_server_sock=socket(AF_INET,SOCK_STREAM,0);
if(real_server_sock<0)
{
perror("Socketcreationfailed\n");
close(sock);
return-1;
}
memset(reply_buffer,0,sizeof(BUFF_SIZE));
socks5_response=(SOCKS5_RESPONSE*)reply_buffer;
socks5_response->version=VERSION;
socks5_response->reserved=0x00;
socks5_response->address_type=0x01;
memset(socks5_response+4,0,6);
ret=connect(real_server_sock,(structsockaddr*)&sin,sizeof(structsockaddr_in));
if(ret==0)
{
socks5_response->reply=0x00;
if(-1==send(sock,socks5_response,10,0))
{
close(sock);
return-1;
}
}
else
{
perror("Connecttorealservererror");
socks5_response->reply=0x01;
send(sock,socks5_response,10,0);
close(sock);
return-1;
}
returnreal_server_sock;
}
intForwardData(intsock,intreal_server_sock)
{
charrecv_buffer[BUFF_SIZE]={0};
fd_setfd_read;
structtimevaltime_out;
time_out.tv_sec=0;
time_out.tv_usec=TIME_OUT;
intret=0;
while(1)
{
FD_ZERO(&fd_read);
FD_SET(sock,&fd_read);
FD_SET(real_server_sock,&fd_read);
ret=select((sock>real_server_sock?sock:real_server_sock)+1,&fd_read,NULL,NULL,&time_out);
if(-1==ret)
{
perror("selectsocketerror");
break;
}
elseif(0==ret)
{
//perror("selecttimeout");
continue;
}
//printf("[DEBUG]testingreadable!\n");
if(FD_ISSET(sock,&fd_read))
{
//printf("clientcanread!\n");
memset(recv_buffer,0,BUFF_SIZE);
ret=recv(sock,recv_buffer,BUFF_SIZE,0);
if(ret>0)
{
//printf("%s",recv_buffer);
//printf("recv%dbytesfromclient.\n",ret);
ret=send(real_server_sock,recv_buffer,ret,0);
if(ret==-1)
{
perror("senddatatorealservererror");
break;
}
//printf("send%dbytestoclient!\n",ret);
}
elseif(ret==0)
{
//printf("clientclosesocket.\n");
break;
}
else
{
//perror("recvfromclienterror");
break;
}
}
elseif(FD_ISSET(real_server_sock,&fd_read))
{
//printf("realservercanread!\n");
memset(recv_buffer,0,BUFF_SIZE);
ret=recv(real_server_sock,recv_buffer,BUFF_SIZE,0);
if(ret>0)
{
//printf("%s",recv_buffer);
//printf("recv%dbytesfromrealserver.\n",ret);
ret=send(sock,recv_buffer,ret,0);
if(ret==-1)
{
perror("senddatatoclienterror");
break;
}
}
elseif(ret==0)
{
//printf("realserverclosesocket.\n");
break;
}
else
{
perror("recvfromrealservererror");
break;
}
}
}
return0;
}
intSocks5(void*client_sock)
{
intsock=*(int*)client_sock;
if(SelectMethod(sock)==-1)
{
//printf("socksversionerror\n");
return-1;
}
if(AuthPassword(sock)==-1)
{
//printf("authpassworderror\n");
return-1;
}
intreal_server_sock=ParseCommand(sock);
if(real_server_sock==-1)
{
//printf("parsecommanderror.\n");
return-1;
}
ForwardData(sock,real_server_sock);
close(sock);
close(real_server_sock);
return0;
}
intmain(intargc,char*argv[])
{
if(argc!=2)
{
printf("Socks5proxyfortest,codebyYunShu\n");
printf("Usage:%s<proxy_port>\n",argv[0]);
printf("Options:\n");
printf("<proxy_port>---whichportofthisproxyserverwilllisten.\n");
return1;
}
structsockaddr_insin;
memset((void*)&sin,0,sizeof(structsockaddr_in));
sin.sin_family=AF_INET;
sin.sin_port=htons(atoi(argv[1]));
sin.sin_addr.s_addr=htonl(INADDR_ANY);
intlisten_sock=socket(AF_INET,SOCK_STREAM,0);
if(listen_sock<0)
{
perror("Socketcreationfailed\n");
return-1;
}
intopt=SO_REUSEADDR;
setsockopt(listen_sock,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));
if(bind(listen_sock,(structsockaddr*)&sin,sizeof(structsockaddr_in))<0)
{
perror("Binderror");
return-1;
}
if(listen(listen_sock,MAX_USER)<0)
{
perror("Listenerror");
return-1;
}
structsockaddr_incin;
intclient_sock;
intclient_len=sizeof(structsockaddr_in);
while(client_sock=accept(listen_sock,(structsockaddr*)&cin,(socklen_t*)&client_len))
{
printf("Connectedfrom%s,processing......\n",inet_ntoa(cin.sin_addr));
pthread_twork_thread;
if(pthread_create(&work_thread,NULL,(void*)Socks5,(void*)&client_sock))
{
perror("Createthreaderror...");
close(client_sock);
}
else
{
pthread_detach(work_thread);
}
}
}