博客首页 注册 建议与交流 排行榜 加入友情链接
推荐 投诉 搜索: 帮助

好想好好爱你!

badb0y.cublog.cn


Linux平台socks5代理
这是一个非常简单的Socks5代理,,用的非常不错,也非常好用,最主要的是非常小,就两个文件!
 
 
Socks5.h,,文件头
 
 

///////////////////////////////////////////////////////////////////////////////////////////////////////////////

// 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

///////////////////////////////////////////////////////////////////////////////////////////////////////////////


#ifndef SOCKS5_H
#define SOCKS5_H

#define VERSION 0x05
#define CONNECT 0x01
#define IPV4 0x01
#define DOMAIN 0x03
#define IPV6 0x04

typedef struct _method_select_response // 协商方法服务器响应

{
 char version; // 服务器支持的Socks版本,0x04或者0x05

 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为0x01,IP V6为0x04,域名为0x03

 char address_port[1]; // 如果address_type为域名,此处第一字节为域名长度,其后为域名本身,无0字符结尾,域名后为Socks代理服务器绑定端口

}SOCKS5_RESPONSE;

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

 

Socks5.c .,,,,主文件

 

///////////////////////////////////////////////////////////////////////////////////////////////////////////////

// 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 -o socks5 -O2 Socks5.c -lpthread( RedHat AS5测试 )

///////////////////////////////////////////////////////////////////////////////////////////////////////////////


#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"

#define MAX_USER 10
#define BUFF_SIZE 1024

#define AUTH_CODE 0x02

#define TIME_OUT 6000000

#define USER_NAME "yunshu"
#define PASS_WORD "ph4nt0m"

// Select auth method, return 0 if success, -1 if failed

int SelectMethod( int sock )
{
 char recv_buffer[BUFF_SIZE] = { 0 };
 char reply_buffer[2] = { 0 };

 METHOD_SELECT_REQUEST *method_request;
 METHOD_SELECT_RESPONSE *method_response;
 
 // recv METHOD_SELECT_REQUEST

 int ret = recv( sock, recv_buffer, BUFF_SIZE, 0 );
 if( ret <= 0 )
 {
 perror( "recv error" );
 close( sock );

 return -1;
 }

 //printf( "SelectMethod: recv %d bytes\n", ret );


 // if client request a wrong version or a wrong number_method

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

 method_response->version = VERSION;
 
 // if not socks5

 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;
 }
 
 return 0;
}

// test password, return 0 for success.

int AuthPassword( int sock )
{
 char recv_buffer[BUFF_SIZE] = { 0 };
 char reply_buffer[BUFF_SIZE] = { 0 };

 AUTH_REQUEST *auth_request;
 AUTH_RESPONSE *auth_response;
 
 // 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;
 }
 //printf( "AuthPass: recv %d bytes\n", ret );


 auth_request = (AUTH_REQUEST *)recv_buffer;

 memset( reply_buffer, 0, BUFF_SIZE );
 auth_response = (AUTH_RESPONSE *)reply_buffer;
 auth_response->version = 0x01;

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

 // auth_request->name_len is a char, max number is 0xff

 char pwd_str[2] = { 0 };
 strncpy( pwd_str, auth_request->name + auth_request->name_len, 1 );
 int pwd_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 );

 // check username and password

 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
 {
 return 0;
 }
 }
 else
 {
 auth_response->result = 0x01;
 send( sock, auth_response, sizeof(AUTH_RESPONSE), 0 );

 close( sock );
 return -1;
 }
}

// parse command, and try to connect real server.

// return socket for success, -1 for failed.

int ParseCommand( int sock )
{
 char recv_buffer[BUFF_SIZE] = { 0 };
 char reply_buffer[BUFF_SIZE] = { 0 };
 
 SOCKS5_REQUEST *socks5_request;
 SOCKS5_RESPONSE *socks5_response;

 // recv command

 int ret = recv( sock, recv_buffer, BUFF_SIZE, 0 );
 if( ret <= 0 )
 {
 perror( "recv connect command error" );

 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( "connect command error.\n" );

 close( sock );
 return -1;
 }

 // begain process connect request

 struct sockaddr_in sin;

 memset( (void *)&sin, 0, sizeof(struct sockaddr_in) );
 sin.sin_family = AF_INET;

 // get real server's ip address

 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, (unsigned int)domain_length );

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


 struct hostent *phost = gethostbyname( target_domain );
 if( phost == NULL )
 {
 //printf( "Resolve %s error!\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 );
 }

 // try to connect to real server

 int real_server_sock = socket( AF_INET, SOCK_STREAM, 0 );
 if( real_server_sock < 0 )
 {
 perror( "Socket creation failed\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, (struct sockaddr *)&sin, sizeof(struct sockaddr_in) );
 if( ret == 0 )
 {
 socks5_response->reply = 0x00;
 if( -1 == send( sock, socks5_response, 10, 0 ) )
 {
 close( sock );
 
 return -1;
 }
 }
 else
 {
 perror( "Connect to real server error" );
 socks5_response->reply = 0x01;
 send( sock, socks5_response, 10, 0 );
 
 close( sock );
 return -1;
 }
 
 return real_server_sock;
}

int ForwardData( int sock, int real_server_sock )
{
 char recv_buffer[BUFF_SIZE] = { 0 };
 
 fd_set fd_read;
 struct timeval time_out;

 time_out.tv_sec = 0;
 time_out.tv_usec = TIME_OUT;
 
 int ret = 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( "select socket error" );
 break;
 }
 else if( 0 == ret )
 {
 //perror( "select time out" );

 continue;
 }
 
 //printf( "[DEBUG] testing readable!\n" );

 if( FD_ISSET(sock, &fd_read) )
 {
 //printf( "client can read!\n" );

 memset( recv_buffer, 0, BUFF_SIZE );
 ret = recv( sock, recv_buffer, BUFF_SIZE, 0 );
 if( ret > 0 )
 {
 //printf( "%s", recv_buffer );

 //printf( "recv %d bytes from client.\n", ret );

 ret = send( real_server_sock, recv_buffer, ret, 0 );
 if( ret == -1 )
 {
 perror( "send data to real server error" );
 break;
 }
 //printf( "send %d bytes to client!\n", ret );

 }
 else if( ret == 0 )
 {
 //printf( "client close socket.\n" );

 break;
 }
 else
 {
 //perror( "recv from client error" );

 break;
 }
 }
 
 else if( FD_ISSET(real_server_sock, &fd_read) )
 {
 //printf( "real server can read!\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 %d bytes from real server.\n", ret );

 ret = send( sock, recv_buffer, ret, 0 );
 if( ret == -1 )
 {
 perror( "send data to client error" );
 break;
 }
 }
 else if( ret == 0 )
 {
 //printf( "real server close socket.\n" );

 break;
 }
 else
 {
 perror( "recv from real server error" );
 break;
 }
 }
 }
 
 return 0;
}

int Socks5( void *client_sock )
{
 int sock = *(int *)client_sock;

 if( SelectMethod( sock ) == -1 )
 {
 //printf( "socks version error\n" );

 return -1;
 }
 
 if( AuthPassword( sock ) == -1 )
 {
 //printf( "auth password error\n" );

 return -1;
 }
 
 int real_server_sock = ParseCommand( sock );
 if( real_server_sock == -1 )
 {
 //printf( "parse command error.\n" );

 return -1;
 }
 
 ForwardData( sock, real_server_sock );

 close( sock );
 close( real_server_sock );
 
 return 0;
}

int main( int argc, char *argv[] )
{
 if( argc != 2 )
 {
 printf( "Socks5 proxy for test,code by YunShu\n" );
 printf( "Usage: %s <proxy_port>\n", argv[0] );
 printf( "Options:\n" );
 printf( " <proxy_port> ---which port of this proxy server will listen.\n" );
 
 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);

 int listen_sock = socket( AF_INET, SOCK_STREAM, 0 );
 if( listen_sock < 0 )
 {
 perror( "Socket creation failed\n");
 return -1;
 }

 int opt = SO_REUSEADDR;
 setsockopt( listen_sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt) );

 if( bind( listen_sock, (struct sockaddr*)&sin, sizeof(struct sockaddr_in) ) < 0 )
 {
 perror( "Bind error" );
 return -1;
 }

 if( listen( listen_sock, MAX_USER ) < 0 )
 {
 perror( "Listen error" );
 return -1;
 }

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

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

 pthread_t work_thread;
 if( pthread_create( &work_thread, NULL, (void *)Socks5, (void *)&client_sock ) )
 {
 perror( "Create thread error..." );
 close( client_sock );
 }
 else
 {
 pthread_detach( work_thread );
 }
 }
}

 

就这么两个文件,我的系统是centos5.0

编译:

gcc -o socks5 -O2 Socks5.c -lpthread

运行:

[root@localhost socks5]# ./socks5 8888
Connected from 192.168.1.114, processing......
Connected from 192.168.1.114, processing......
Connected from 192.168.1.114, processing......
Connected from 192.168.1.114, processing......
recv error: Bad file descriptor
Connected from 192.168.1.114, processing......
Connected from 192.168.1.114, processing......
Connected from 192.168.1.114, processing......

已经OK了,,这个是SOCKS5代理,,密码在程序里面,大家可以自己修改

#define USER_NAME "yunshu"
#define PASS_WORD "ph4nt0m"

现在我运行了几天,,还不错,发出来给大家分享!

 

 

 原文地址 http://www.ph4nt0m.org
发表于: 2008-04-18 ,修改于: 2008-04-18 09:15,已浏览199次,有评论0条 推荐 投诉


网友评论

发表评论