我是靠谱客的博主 无语曲奇,这篇文章主要介绍使用socks5实现简易代理服务器,现在分享给大家,希望可以做个参考。

写一个简易的socks5代理服务器,负责转发网络数据包,要能够使用它来上网。

SOCKS5 是一个代理协议,它在使用TCP/IP协议通讯的前端机器和服务器机器之间扮演一个中介角色,使得内部网中的前端机器变得能够访问Internet网中的服务器,或者使通讯更加安全。SOCKS5 服务器通过将前端发来的请求转发给真正的目标服务器, 模拟了一个前端的行为。在这里,前端和SOCKS5之间也是通过TCP/IP协议进行通讯,前端将原本要发送给真正服务器的请求发送给SOCKS5服务器,然后SOCKS5服务器将请求转发给真正的服务器。

socks5协议认证步骤:

1、客户端连接到服务器,向服务器发送一个版本标识/方法选择报文:

+-------+------------------+----------------+

|  VER | NMETHODS | METHODS |

+-------+------------------+----------------+

|     1    |          1          |     1~255     |

+-------+------------------+----------------+

VER:客户端的协议版本号(socks5:0x05 socks4:0x04)

NMETHODS:客户端所支持认证方式的长度

METHODS:客户端支持的认证方式

目前定义的METHOD有以下几种:
  0x00  无需认证
  0x01  通用安全服务应用程序
  0x02  用户名/密码
  0x03- 0x7F IANA 分配
  0x80- 0xFE 私人方法保留
  0xFF  无可接受方法

 

2、服务器从客户端报文中选择一种方式,并发送一个方式选择报文:

    +----+----------+
    |VER | METHOD |
    +----+----------+
    | 1  |   1    |
    +----+----------+

VER:服务端的协议版本号(socks5:0x05 socks4:0x04)

METHOD:服务端选择的认证方式

 

3、客户端向服务器发送连接目的服务器的请求报文:

    +----+-----+-------+------+------------+----------+
    |VER | CMD|   RSV | ATYP | DST.ADDR | DST.PORT |
    +----+-----+-------+------+------------+----------+
    | 1   |   1  |   1   |   1   | Variable |    2     |
    +----+-----+-------+------+------------+----------+

VER:客户端协议版本号(socks5:0x05 socks4:0x04)

CMD:请求类型(CONNECT:0x00 BIND:0x01 UDP:0x02)

RSV:保留位(要求为0x00)

ATYP:IP类型(IPV4:0x01 IPV6:0X04 域名:0x03)

DST.ADDR:目的服务器地址

DST.ADDR:目的服务器端口

 

4、服务器向客户端回应连接请求

    +----+-----+-------+------+-------------+-----------+
    |VER | REP |   RSV  | ATYP | BND.ADDR | BND.PORT |
    +----+-----+-------+------+-------------+-----------+
    | 1  |   1   |   1   |   1   | Variable |    2     |
    +----+-----+-------+------+----------+--------------+

VER:服务端协议版本号(socks5:0x05 socks4:0x04)

REP:应答结果

      1. 0x00        成功
      2. 0x01        一般性失败
      3. 0x02        规则不允许转发
      4. 0x03        网络不可达
      5. 0x04        主机不可达
      6. 0x05        连接拒绝
      7. 0x06        TTL超时
      8. 0x07        不支持请求包中的CMD
      9. 0x08        不支持请求包中的ATYP
      10. 0x09-0xFF   未定义

RSV:保留位(要求为0x00)

ATYP:指明后面的地址类型

BND.ADDR:客户端请求报文中CMD的回应地址(CMD为0x01时)

BND.PORT:客户端请求报文中CMD的回应端口(CMD为0x01时)

 

程序主要步骤:

第一步:建立客户端和代理服务器连接,TCP连接

第二步:socks5协议认证

第三步:代理服务器连接目的服务器

第四步:转发数据

 

代码

 

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
#include <unistd.h> #include <arpa/inet.h> //因特网地址结构体相关 #include <sys/socket.h> //socket相关 #include <time.h> //时间相关 #include <signal.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <pthread.h> #include <sys/epoll.h> #define BUFF_SIZE 1024 //设置转发缓冲区 #define TIME_OUT 6000000 //设置复用IO延时 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ //++++++++++++ sock5协议结构体定义 ++++++++++++++ /*++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ /* 一、客户端认证请求 +----+----------+----------+ |VER | NMETHODS | METHODS | +----+----------+----------+ | 1 | 1 | 1~255 | +----+----------+----------+ 二、服务端回应认证 +----+--------+ |VER | METHOD | +----+--------+ | 1 | 1 | +----+--------+ 三、客户端连接请求(连接目的网络) +----+-----+-------+------+----------+----------+ |VER | CMD | RSV | ATYP | DST.ADDR | DST.PORT | +----+-----+-------+------+----------+----------+ | 1 | 1 | 1 | 1 | Variable | 2 | +----+-----+-------+------+----------+----------+ 四、服务端回应连接 +----+-----+-------+------+----------+----------+ |VER | REP | RSV | ATYP | BND.ADDR | BND.PORT | +----+-----+-------+------+----------+----------+ | 1 | 1 | 1 | 1 | Variable | 2 | +----+-----+-------+------+----------+----------+ */ //以下为协议结构体定义 //一、客户端认证请求 typedef struct client_license_request{ char ver; // 客户端的协议版本号 0x05:socks5 0x04:socks4 char nmethods; // 客户端所支持认证方式的长度 char methods[255]; //客户端支持的认证方式(可以有255种) }client_license_request; //二、服务端回应认证 typedef struct server_license_response{ char ver; // 服务端的协议版本号 char method; //服务端选择的认证方式 }server_license_response; //三、客户端连接请求 typedef struct client_connect_request{ char ver; //客户端协议版本号 char cmd; //连接方式 char rsv; //保留位0x00 char type; //类型 char addr[4]; //目的服务器ip char port[2]; //目的服务器端口 }client_connect_request; //四、服务端回应连接 typedef struct server_connect_response{ char ver; //版本 char rep; //连接状态 char rsv; //保留0x00 char type; //类型 char addr[4]; //bind ip char port[2]; //bind port }server_connect_response; int socketfd_tcp; //TCP监听套接字 //转发 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; printf("线程%u-开始进行数据转发n",(int)pthread_self()); 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 ) { break; } else if( 0 == ret ) { continue; } if( FD_ISSET(sock, &fd_read) ) { memset( recv_buffer, 0, BUFF_SIZE ); ret = recv( sock, recv_buffer, BUFF_SIZE, 0 ); if( ret >0 ) { ret = send( real_server_sock, recv_buffer, ret, 0 ); if( ret == -1 ) { break; } } else if( ret == 0 ) { break; } else { 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 = send( sock, recv_buffer, ret, 0 ); if( ret == -1 ) { break; } } else if(ret==0) { break; } else { break; } } } return 0; } //创建TCP套接字 void tcp_creat() { socketfd_tcp=socket(AF_INET,SOCK_STREAM,0); if(socketfd_tcp==-1) { perror("socketfd_tcp"); exit(-1); } struct sockaddr_in addr_tcp; bzero(&addr_tcp,sizeof(addr_tcp)); addr_tcp.sin_family=AF_INET; addr_tcp.sin_port=htons(2018); addr_tcp.sin_addr.s_addr=INADDR_ANY; int re=bind(socketfd_tcp,(struct sockaddr *)&addr_tcp,sizeof(addr_tcp)); if(re==-1) { perror("bind"); exit(-1); } re=listen(socketfd_tcp,100); //队列长度设为100 if(re==-1) { perror("listen"); exit(-1); } } //代理服务器连接目的服务器 int connect_dest_server(client_connect_request * connect_request) { int fd=socket(AF_INET,SOCK_STREAM,0); if(fd==-1) { perror("socketfd_tcp"); return -1; } struct sockaddr_in sin_server; bzero(&sin_server,sizeof(sin_server)); sin_server.sin_family=AF_INET; //目的服务器ip填入结构体 memcpy(&sin_server.sin_addr,&connect_request->addr,sizeof(connect_request->addr)); //目的服务器的端口号填入结构体 memcpy(&sin_server.sin_port,&connect_request->port,sizeof(connect_request->port)); /*2 连接服务器*/ int re=connect(fd,(struct sockaddr *)&sin_server,sizeof(sin_server)); if(re==-1) { // printf("目的服务器连接失败n"); return -1; } // printf("目的服务器连接成功n"); return fd; } //socks5认证连接 int sock5_license(struct sockaddr_in *addr_client,socklen_t len,int fd) { //接收认证信息 char buffer[30]={0}; read(fd,buffer,sizeof(buffer)); client_license_request * license_request=(client_license_request *)buffer; //验证认证信息 // printf("客户端版本%dn",license_request->ver); if(license_request->ver!=0x5) { // printf("协议版本错误n"); return 0; } // printf("客户认证信息通过,回应认证请求n"); server_license_response license_response; license_response.ver=0x5; license_response.method=0x0; char buff[2]={0}; memcpy(buff,&license_response,sizeof(buff)); //回应认证信息 write(fd,buff,sizeof(buff)); // printf("已发送回应请求n"); //接收连接请求 bzero(&buffer,sizeof(buffer)); // printf("等待接收客户连接请求n"); read(fd,buffer,sizeof(buffer)); client_connect_request * connect_request=(client_connect_request *)buffer; //认证连接请求 if(connect_request->ver!=0x5) { // printf("连接请求协议版本错误n"); return 0; } if(connect_request->cmd!=0x1) { // printf("连接请求命令错误(非TCP)n"); return 0; } if(connect_request->type!=0x01) { // printf("连接请求类型错误(非IPV4)n"); return 0; } //连接客户端指定的目的地址 int dest_fd=connect_dest_server(connect_request); if(dest_fd==-1) { return -1; } //成功连接则发送回应信息 //回应连接信息 char buffer1[10]={0}; bzero(&buffer,sizeof(buffer1)); server_connect_response connect_response; bzero(&connect_response,sizeof(connect_response)); connect_response.ver=0x5; connect_response.rep=0x00; //连接成功标志 connect_response.rsv=0x00; connect_response.type=0x01; memcpy(buffer1,&connect_response,sizeof(connect_response));//服务端回应数据 设置版本号与结果位,ip与端口号未使用 write(fd,buffer1,sizeof(buffer1)); // printf("已发送回应请求n"); //全部认证连接建立完成 //执行转发程序 ForwardData(fd,dest_fd); } //等待TCP连接,每个客户端分出一条线程,跳转执行socks5认证函数↑↑↑ void * pthread_tcp(void * arg) { printf("线程%u-正在运行n",(int)pthread_self()); struct sockaddr_in addr_client; socklen_t len=sizeof(addr_client); bzero(&addr_client,sizeof(addr_client)); int fd=accept(socketfd_tcp,(struct sockaddr *)&addr_client,&len); pthread_t pid2; pthread_create(&pid2,NULL,pthread_tcp,NULL); //打印客户端信息 char ip[20]={0}; unsigned short port; inet_ntop(AF_INET,&addr_client.sin_addr,ip,len); port=ntohs(addr_client.sin_port); //转换为本机字节序 printf("%s:%hu已连接n",ip,port); //执行socks5认证 sock5_license(&addr_client,len,fd); printf("线程%u-退出n",(int)pthread_self()); return NULL; } int main(void) { //创建TCP套接字 tcp_creat(); printf("初始化完成等待连接n"); while(1) { printf("主线程%u-正在运行n",(int)pthread_self()); pthread_tcp(NULL); } }

 

 

 

 

 

 

最后

以上就是无语曲奇最近收集整理的关于使用socks5实现简易代理服务器的全部内容,更多相关使用socks5实现简易代理服务器内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(114)

评论列表共有 0 条评论

立即
投稿
返回
顶部