我写的只支持tcp的connect方法的简单Socks5 proxy的问题

yunshu 2007-05-31 11:50:43
我前些时候,过年那段时间开始写个简单的socks5代理,空余时间慢慢做完了。但是测试的时候遇到一些bug,很多网页显示不全,显示一半就停止了,不知道是哪里不对。代码如下,一个头文件,一个cpp文件:


///////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Socks5代理头文件,定义协议相关数据包结构
// 版本 0.1,作者 云舒
// 2007年1月9日凌晨1点15分,GF回家已经11天了。
//
// 参考:
// http://www.rfc-editor.org/rfc/rfc1928.txt
// http://www.rfc-editor.org/rfc/rfc1929.txt
///////////////////////////////////////////////////////////////////////////////////////////////////////////////

#ifndef SOCKS5_H
#define SOCKS5_H

#define VERSION 0x05 // 代理协议版本
#define CONNECT 0x01 // connect方法
#define IPV4 0x01
#define DOMAIN 0x03
#define IPV6 0x04

typedef struct _method_select_response // 协商方法服务器响应
{
char version; // 服务器支持的Socks版本,0x04或者0x05
unsigned char select_method; // 服务器选择的方法,0x00为匿名,0x02为密码认证
} METHOD_SELECT_RESPONSE;

typedef struct _method_select_request // 协商方法服务端请求
{
char version; // 客户端支持的版本,0x04或者0x05
char number_methods; // 客户端支持的方法的数量
char methods[255]; // 客户端支持的方法类型,最多255个,0x00为匿名,0x02为密码认证
} METHOD_SELECT_REQUEST;

typedef struct _AUTH_RESPONSE // 用户密码认证服务端响应
{
char version; // 版本,此处恒定为0x01
char result; // 服务端认证结果,0x00为成功,其他均为失败
} AUTH_RESPONSE;

typedef struct _AUTH_REQUEST // 用户密码认证客户端请求
{
char version; // 版本,此处恒定为0x01
char name_len; // 第三个字段用户名的长度,一个字节,最长为0xff
char name[255]; // 用户名
char pwd_len; // 第四个字段密码的长度,一个字节,最长为0xff
char pwd[255]; // 密码
} AUTH_REQUEST;

typedef struct _SOCKS5_RESPONSE // 连接真实主机,Socks代理服务器响应
{
char version; // 服务器支持的Socks版本,0x04或者0x05
char reply; // 代理服务器连接真实主机的结果,0x00成功
char reserved; // 保留位,恒定位0x00
char address_type; // Socks代理服务器绑定的地址类型,IP V4为0x00,IP V6为0x04,域名 //为0x03
char address_port[1]; // 如果address_type为域名,此处第一字节为域名长度,其后为域名本 //身,无0字符结尾
}SOCKS5_RESPONSE; // 身,域名后为Socks代理服务器绑定端口

typedef struct _SOCKS5_REQUEST // 客户端请求连接真实主机
{
char version; // 客户端支持的Socks版本,0x04或者0x05
char cmd; // 客户端命令,CONNECT为0x01,BIND为0x02,UDP为0x03,一般为0x01
char reserved; // 保留位,恒定位0x00
char address_type; // 客户端请求的真实主机的地址类型,IP V4为0x00,IP V6为0x04,域名 //为0x03
char address_port[1]; // 如果address_type为域名,此处第一字节为域名长度,其后为域名本 //身,无0字符结尾
}SOCKS5_REQUEST; // 身,域名后为真实主机绑定端口

#endif

...全文
593 8 打赏 收藏 转发到动态 举报
写回复
用AI写文章
8 条回复
切换为时间正序
请发表友善的回复…
发表回复
cattycat 2010-04-20
  • 打赏
  • 举报
回复
印象中代理服务器只是转发报文,还有其他的协议吗
findcsdn 2010-04-20
  • 打赏
  • 举报
回复
留脚印,有空看看。
ForestDB 2010-04-20
  • 打赏
  • 举报
回复
帮顶。
大熊来了 2010-04-19
  • 打赏
  • 举报
回复
你好,请问楼主,我把你的Linux下的版本拿去测试了下,不知道问题出现在哪,希望能得到你的指点,谢谢!
源代码:http://forum.eviloctal.com/thread-32066-1-1.html

我是在虚拟机里实现的,网络连接如下:
pc(实际的机器)<---->虚拟机1(socks5服务器)<----->另一个想通过socks5上网的虚拟机(2)

我在虚拟机2里的浏览器里设置了socks5代理,端口号为1080,并在浏览器里输入网址,如http://http://220.181.6.19/,百度首页
编译程序,运行:./socks5 1080

能够连接成功,但是
运行老是出现错误:recv username and password error
在int SelectMethod( int sock )函数中的
// recv METHOD_SELECT_REQUEST
int ret = recv( sock, recv_buffer, BUFF_SIZE, 0 );
if( ret <= 0 )
{
perror( "recv error" );
close( sock );

return -1;
}
recv_buffer[0]=5, recv_buffer[0]=1, recv_buffer[0]=0;

但是当运行到函数int AuthPassword( int sock )时,sock为啥就收不到数据了
// auth username and password
int ret = recv( sock, recv_buffer, BUFF_SIZE, 0 );
if( ret <= 0 )
{
perror( "recv username and password error" );
close( sock );
return -1;
}

请问:
1.认证的时候的用户名和密码是怎么回事?是虚拟机2登陆时候的用户名和密码吗?
2.测试的时候是直接在虚拟机2的浏览器里输入网址就行吗?
3.我觉得int ForwardData( int sock, int real_server_sock )函数中,这个
if( FD_ISSET(sock, &fd_read) )
……
else if( FD_ISSET(real_server_sock, &fd_read) )
……
第二个else if是不是应该是if啊,要不然的话从real_sever处接受的数据就传不到client了吧

非常感谢!
Eluwoniu 2007-12-05
  • 打赏
  • 举报
回复
顶一下,
我拷回去试试。
yunshu 2007-05-31
  • 打赏
  • 举报
回复
浠€涔堢牬璁哄潧锛屽彂涓唬鐮佽繕璇村お闀夸簡~
yunshu 2007-05-31
  • 打赏
  • 举报
回复
int Socks5( LPVOID client_sock )
{
SOCKET sock = *(int *)client_sock;

char recv_buffer[BUFF_SIZE] = { 0 };
char reply_buffer[BUFF_SIZE] = { 0 };

METHOD_SELECT_REQUEST *method_request;
METHOD_SELECT_RESPONSE *method_response;
AUTH_REQUEST *auth_request;
AUTH_RESPONSE *auth_response;
SOCKS5_REQUEST *socks5_request;
SOCKS5_RESPONSE *socks5_response;

// 鎺ユ敹鏉ヨ嚜瀹㈡埛绔殑鏂规硶鍗忓晢璇锋眰
int ret = recv( sock, recv_buffer, BUFF_SIZE, 0 );
if( ret < 0 )
{
printf( "recv error: %d\n", GetLastError() );
closesocket( sock );

return -1;
}

method_request = (METHOD_SELECT_REQUEST *)recv_buffer;
method_response = (METHOD_SELECT_RESPONSE *)reply_buffer;

// 鍗忓晢鐗堟湰鍜屾槸鍚﹂渶瑕佸鎴风璁よ瘉韬唤
if( -1 == ClientMethod( sock, method_request, method_response ) )
{
closesocket( sock );

return -1;
}

// 鎺ユ敹瀹㈡埛绔殑璁よ瘉淇℃伅
if( need_auth != 0 )
{
memset( recv_buffer, 0, BUFF_SIZE );
ret = recv( sock, recv_buffer, BUFF_SIZE, 0 );
if( ret < 0 )
{
printf( "recv username and password error: %d\n", GetLastError() );
closesocket( sock );

return -1;
}

auth_request = (AUTH_REQUEST *)recv_buffer;

memset( reply_buffer, 0, BUFF_SIZE );
auth_response = (AUTH_RESPONSE *)reply_buffer;

if( -1 == AuthClient( sock, auth_request, auth_response ) )
{
closesocket( sock );
return -1;
}
}

// 鎺ユ敹瀹㈡埛绔懡浠? memset( recv_buffer, 0, BUFF_SIZE );
ret = recv( sock, recv_buffer, BUFF_SIZE, 0 );
if( ret < 0 )
{
printf( "recv connect command error:%d\n", GetLastError() );

closesocket( sock );

return -1;
}

socks5_request = (SOCKS5_REQUEST *)recv_buffer;
struct sockaddr_in sin;

memset( &sin, 0, sizeof(struct sockaddr_in) );

// 鍒嗘瀽瀹㈡埛绔懡浠? if( -1 == SplitCmd( socks5_request, &sin ) )
{
closesocket( sock );
return -1;
}

memset( reply_buffer, 0, BUFF_SIZE );
socks5_response = (SOCKS5_RESPONSE *)reply_buffer;

SOCKET real_server_sock = TestRealServer( sock, sin, socks5_response );

if( SOCKET_ERROR == real_server_sock )
{
return -1;
}

TransferData( sock, real_server_sock );

return 0;
}

int main( int argc, char *argv[] )
{
if( argc != 3 && argc != 2 )
{
printf( "Socks5 proxy for test,code by YunShu\n" );
printf( "Usage: %s <proxy_port> [auth]\n", argv[0] );
printf( "Options:\n" );
printf( " <proxy_port> ---which port of this proxy server will listen.\n" );
printf( " [auth] ---if this proxy need auth,must be 0 or 1, default not.\n" );

return 1;
}

if( argc == 3 )
{
need_auth = atoi(argv[2]);
if( need_auth != 0 && need_auth != 1 )
{
printf( "need_auth must be 0 or 1.\n" );
return 1;
}
}

WSAData wsa;

if( 0 != WSAStartup( 0x0202, &wsa ) )
{
printf( "WSAStartup error: %d\n", GetLastError() );

return -1;
}

struct sockaddr_in sin;

memset( (void *)&sin, 0, sizeof( struct sockaddr_in) );

sin.sin_family = AF_INET;
sin.sin_port = htons( atoi(argv[1]) );
sin.sin_addr.s_addr = htonl(INADDR_ANY);

SOCKET listen_sock = socket( AF_INET, SOCK_STREAM, 0 );
if( listen_sock == INVALID_SOCKET )
{
printf( "Socket creation failed: %d\n", GetLastError() );
return -1;
}

if( bind( listen_sock, (struct sockaddr*)&sin, sizeof(struct sockaddr_in) ) == SOCKET_ERROR )
{
printf( "Bind error: %d\n", GetLastError() );
return -1;
}
if( listen( listen_sock, MAX_USER ) == SOCKET_ERROR )
{
printf( "Listen error: %d\n", GetLastError() );
return -1;
}

struct sockaddr_in cin;
SOCKET client_sock;
int client_len = sizeof( struct sockaddr_in );

while( client_sock = accept( listen_sock, (struct sockaddr *)&cin, (int *)&client_len ) )
{
//printf( "Connected from %s,processing......\n", inet_ntoa( cin.sin_addr ) );

HANDLE work_thread;
DWORD thread_id;

work_thread = CreateThread( NULL, 0,
(LPTHREAD_START_ROUTINE)Socks5,
(LPVOID)&client_sock,
0,
(LPDWORD)(&thread_id) );

if( NULL == work_thread )
{
printf( "Create thread error: %d\n", GetLastError() );
closesocket( client_sock );
}
else
{
CloseHandle(work_thread);
}
}

return 0;
}
yunshu 2007-05-31
  • 打赏
  • 举报
回复
涓嬮潰灏辨槸浠g爜寮€濮嬩簡锛?
[code]
#include <stdio.h>
#include <winsock2.h>
#include <windows.h>

#include "Socks5.h"

#pragma comment( lib, "ws2_32" )

#define MAX_USER 10
#define BUFF_SIZE 1024

#define AUTH_CODE 0x02

#define TIME_OUT 400000 // select瓒呮椂锛?.4绉?
#define USER_NAME "yunshu" // 浠g悊鐢ㄦ埛鍚? #define PASS_WORD "ph4nt0m" // 浠g悊瀵嗙爜

int need_auth = 0; // 榛樿涓嶉渶瑕佸瘑鐮?

// 鍗忓晢鐗堟湰鍜岃韩浠借璇佹柟娉曪紝澶辫触杩斿洖-1锛屽惁鍒欒繑鍥?.
int ClientMethod( SOCKET sock, METHOD_SELECT_REQUEST *method_request, METHOD_SELECT_RESPONSE *method_response )
{
int ret = -1;

// 鍙厑璁窼ocks5鍗忚
method_response->version = VERSION;
if( (unsigned int)method_request->version != VERSION )
{
method_response->select_method = 0xff;

ret = send( sock, (char *)method_response, sizeof(METHOD_SELECT_RESPONSE), 0 );

return -1;
}

// 鍙戦€佽璇佽姹傚埌瀹㈡埛绔湇鍔$
if( need_auth == 0 )
{
method_response->select_method = 0x00;
}
else
{
method_response->select_method = AUTH_CODE;
}

ret = send( sock, (char *)method_response, sizeof(METHOD_SELECT_RESPONSE), 0 );
if( ret != sizeof(METHOD_SELECT_RESPONSE) )
{
return -1;
}

return 1;
}

// 楠岃瘉鐢ㄦ埛韬唤锛屽け璐ヨ繑鍥?1锛屾垚鍔熻繑鍥?.
int AuthClient( SOCKET sock, AUTH_REQUEST *auth_request, AUTH_RESPONSE *auth_response )
{
auth_response->version = 0x01;

char recv_name[256] = { 0 };
char recv_pass[256] = { 0 };

int ret = -1;

strncpy( recv_name, auth_request->name, auth_request->name_len );
strncpy( recv_pass, &auth_request->name_len + sizeof(auth_request->name_len) + (int)auth_request->name_len + sizeof(auth_request->pwd_len), auth_request->pwd_len );

// 楠岃瘉甯愬彿鍜屽瘑鐮? if( (strncmp( recv_name, USER_NAME, auth_request->name_len ) == 0) &&
(strncmp( recv_pass, PASS_WORD, auth_request->pwd_len ) == 0)
)
{
auth_response->result = 0x00;
ret = send( sock, (char *)auth_response, sizeof(AUTH_RESPONSE), 0 );

if( ret != sizeof(AUTH_RESPONSE) )
{
return -1;
}
}
else
{
auth_response->result = 0x01;
send( sock, (char *)auth_response, sizeof(AUTH_RESPONSE), 0 );

return -1;
}

return 1;
}

// 瑙f瀽socks5鍛戒护锛屽彧鏀寔connect鍛戒护銆? // 澶辫触杩斿洖-1锛屾垚鍔熻繑鍥?.
int SplitCmd( SOCKS5_REQUEST *socks5_request, struct sockaddr_in *sin )
{
// 妫€娴嬪鎴风鍛戒护涓殑socks鐗堟湰
// 鍙敮鎸乧onnect鍛戒护
// 蹇呴』鏄疘PV4鍗忚

if( (socks5_request->version != VERSION) ||
(socks5_request->cmd != CONNECT) ||
(socks5_request->address_type == IPV6) )
{
printf( "connect command error.\n" );

return -1;
}

memset( (void *)sin, 0, sizeof(struct sockaddr_in) );
sin->sin_family = AF_INET;

// 濡傛灉鏄疘PV4鍦板潃
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( "Real Server: %s %d\n", inet_ntoa( sin->sin_addr ), ntohs( sin->sin_port ) );
}
else if( socks5_request->address_type == DOMAIN )
{
char domain_length = *(&socks5_request->address_type + sizeof(socks5_request->address_type));
char target_domain[ 256] = { 0 };

strncpy( target_domain, &socks5_request->address_type + 2, domain_length );

//printf( "target: %s\n", target_domain );

struct hostent *phost = gethostbyname( target_domain );
if( phost == NULL )
{
//printf( "Resolve %s error!\n" , target_domain );

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 );

}

return 1;
}


// 灏濊瘯杩炴帴鍒皉eal server锛屽鏋滃け璐ヨ繑鍥濻OCKET_ERROR锛屾垚鍔熷垯杩斿洖杩炴帴鍒皉eal server鐨剆ocket
SOCKET TestRealServer( SOCKET sock, struct sockaddr_in sin, SOCKS5_RESPONSE *socks5_response )
{
// try to connect to real server
SOCKET real_server_sock = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );
if( real_server_sock == INVALID_SOCKET )
{
printf( "Socket creation failed: %d\n", GetLastError() );

closesocket( sock );

return SOCKET_ERROR;
}

socks5_response->version = VERSION;
socks5_response->reserved = 0x00;
socks5_response->address_type = 0x01;

memset( socks5_response + 4, 0 , 6 );

int ret = connect( real_server_sock, (struct sockaddr *)&sin, sizeof(sin) );
if( ret != SOCKET_ERROR )
{
socks5_response->reply = 0x00;
ret = send( sock, (char *)socks5_response, 10, 0 );

if( ret != 10 )
{
printf( "send result of test real server toclient error: %d\n", GetLastError() );

closesocket( sock );
return SOCKET_ERROR;
}
}
else
{
printf( "Connect to real server error: %d\n", GetLastError() );
socks5_response->reply = 0x01;

send( sock, (char *)socks5_response, 10, 0 );

closesocket( sock );
return SOCKET_ERROR;
}

return real_server_sock;
}

void TransferData( SOCKET client_sock, SOCKET real_server_sock )
{
fd_set fd_read;
struct timeval time_out;

char recv_buffer[BUFF_SIZE] = { 0 };

time_out.tv_sec = 0;
time_out.tv_usec = TIME_OUT;

while( 1 )
{
FD_ZERO( &fd_read );

FD_SET( client_sock, &fd_read );
FD_SET( real_server_sock, &fd_read );

int ret = select( 0, &fd_read, NULL, NULL, &time_out );

if( -1 == ret )
{
printf( "select: socket error: %d\n", GetLastError() );
break;
}
else if( 0 == ret )
{
continue;
}
else
{
if( FD_ISSET(client_sock, &fd_read) )
{
memset( recv_buffer, 0, BUFF_SIZE );
ret = recv( client_sock, recv_buffer, BUFF_SIZE, 0 );

if( ret != 0 && ret != SOCKET_ERROR )
{
ret = send( real_server_sock, recv_buffer, (int)strlen(recv_buffer), 0 );
if( ret == SOCKET_ERROR )
{
printf( "send data to real server error: %d\n", GetLastError() );
break;
}
}
else
{
//printf( "recv from client error: %d\n", GetLastError() );
break;
}
}
else if( FD_ISSET(real_server_sock, &fd_read) )
{
memset( recv_buffer, 0, BUFF_SIZE );
ret = recv( real_server_sock, recv_buffer, BUFF_SIZE, 0 );

if( ret != 0 && ret != SOCKET_ERROR )
{
ret = send( client_sock, recv_buffer, (int)strlen(recv_buffer), 0 );
if( ret == SOCKET_ERROR )
{
perror( "send data to client error" );
break;
}
}
else
{
//printf( "recv from client error: %d\n", GetLastError() );
break;
}
}
}
}

closesocket( client_sock );
closesocket( real_server_sock );
}

69,373

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧