代理协议实现源代码解析
文章转自王牌软件
站长推荐:NSetup一键部署软件
一键式完成美化安装包制作,自动增量升级,数据统计,数字签名。应对各种复杂场景,脚本模块化拆分,常规复杂的脚本代码,图形化设置。无需专业的研发经验,轻松完成项目部署。(www.nsetup.cn)
只回答业务咨询
站长推荐:NSetup一键部署软件
一键式完成美化安装包制作,自动增量升级,数据统计,数字签名。应对各种复杂场景,脚本模块化拆分,常规复杂的脚本代码,图形化设置。无需专业的研发经验,轻松完成项目部署。(www.nsetup.cn)
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 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 |
能够支持Socks4,Socks5代理协议;Socks5支持所有的三种方法(CONNECT,BIND,UDP),支持身份认证;支持HTTP代理协议,包括GET和CONNECT方法,还支持FTP的WEB下载请求。仅供参考,欢迎讨论。 头文件 //========================================================================= /* 文件: Socks.h */ /* 说明: 代理协议类头文件 */ /* 工程: SecretAgent Proxy */ /* 作者: 朱 科 (HUST) */ /* 时间: 2005.7 */ ////////////////////////////////////////////////////////////////////////// //========================================================================= #if !defined(AFX_SOCKS_H__415E34F7_32C4_4FE0_A85B_875649D59352__INCLUDED_) #define AFX_SOCKS_H__415E34F7_32C4_4FE0_A85B_875649D59352__INCLUDED_ #if _MSC_VER > 1000 #pragma once #endif // _MSC_VER > 1000 #define SOCKSPORT 1080 /* SOCKS 服务端口 */ #define HTTPPORT 80 /* HTTP 服务端口 */ /**********************************************/ /*** socksv5 定义 ****/ /**********************************************/ /* 认证方法类型 */ #define NO_AUTH_REQUIRE 0x00 #define GSSAPI 0x01 #define USER_AND_PASS 0x02 #define NO_ACCEPT_METHOD 0xff /* 命令类型 */ #define CONNECT 0x01 #define BIND 0x02 #define UDP_ACCOCIATE 0x03 /* 回应类型 */ #define SUCCESS 0x00 #define GENERAL_FAILURE 0x01 #define CNNT_NOT_ALLOWED 0x02 #define NET_UNREACHABLE 0x03 #define HOST_UNREACHABLE 0x04 #define CNNT_REFUSED 0x05 #define TTL_EXPIRED 0x06 #define CMD_NOT_SUPPORT 0x07 #define ADDR_NOT_SUPPORT 0x08 /* 地址类型 */ #define IPV4 0x01 #define DOMAINNAME 0x03 #define IPV6 0x04 /**********************************************/ /*** socksv4 定义 ****/ /**********************************************/ /* 回应类型 */ #define REQ_GRANTED 90 #define REQ_FAILED 91 #define REQ_REJECT_CNNT 92 #define REQ_REJECT_DIFF 93 /**********************************************/ /*** 代理服务器服务结构体 ****/ /**********************************************/ #include <WINSOCK2.H> #include <stdio.h> #pragma comment(lib,"ws2_32.lib") typedef struct _ProxyStruct { SOCKET Socket; /* 客户端与服务器联系的套接字 */ SOCKET relay_sock ; /* 服务器与目的主机联系的套接字 */ SOCKET new_svr_sock ; /* 用于BIND命令的监听套接字 */ SOCKET udp_sock; /* 客户端,服务器,目的主机三者交换UDP的套接字 */ sockaddr_in clientaddr; /* 用于UDP,记录下客户端的地址结构*/ char domainname[_MAX_PATH]; /* 用于UDP,记录下客户端的域名(如果用域名表示地址的话)*/ char ver; /* 版本号 */ char cmd; /* 命令类型,用到一次 */ DWORD comein_ip; /* 用于BIND命令,记录下指定连接者地址 */ WORD comein_port; /* 用于BIND命令,记录下指定连接者端口 */ } ProxyStruct,* LPProxyStruct; class CSocks { public: /*引导函数*/ int StartHTTPServer(BOOL start); int StartSOCKSServer(BOOL start); ////////////////////////////////////////////////////////////////////////// /*HTTP代理函数*/ int receive_ftp_respond(ProxyStruct &proxy); BOOL send_ftp_command(ProxyStruct &proxy,CString command); BOOL handle_methods_http(ProxyStruct &proxy); ////////////////////////////////////////////////////////////////////////// /*Sock4函数*/ BOOL handle_command_v4(ProxyStruct &proxy); void reply_command_v4( ProxyStruct &proxy, char cmd, WORD dst_port, DWORD l_dst_ip); ////////////////////////////////////////////////////////////////////////// /*Sock5函数*/ void IPtoChar(struct in_addr ip,char *buff); void relay_udp_data(ProxyStruct &proxy); BOOL creat_udp_sock(ProxyStruct &proxy,DWORD *l_dst_ip, WORD *dst_port); BOOL handle_command_v5(ProxyStruct &proxy); void reply_command_v5( ProxyStruct &proxy, char cmd, char atyp,char addr_len,char *bnd_addr, WORD bnd_port ); BOOL handle_methods_v5(ProxyStruct &proxy); BOOL handle_auth_v5(ProxyStruct &proxy); BOOL get_valid_method(char *methods, int nmethods); ////////////////////////////////////////////////////////////////////////// /*基本功能函数*/ void relay_tcp_data(ProxyStruct &proxy); BOOL wait_connect_in(ProxyStruct &proxy,DWORD * l_dst_ip, WORD * dst_port); BOOL creat_bind_sock(ProxyStruct &proxy,DWORD * l_dst_ip, WORD * dst_port); BOOL creat_connect_sock(ProxyStruct &proxy,DWORD l_dst_ip, WORD dst_port); void get_version(ProxyStruct &proxy); void close_and_exit(ProxyStruct &proxy); int write_chars(ProxyStruct &proxy,int choosesocket, char *buf, int len); int read_chars(ProxyStruct &proxy, int choosesocket, char *buf, int len); ////////////////////////////////////////////////////////////////////////// CSocks(); virtual ~CSocks(); }; #endif // !defined(AFX_SOCKS_H__415E34F7_32C4_4FE0_A85B_875649D59352__INCLUDED_) 对头文件的说明 主要是宏定义,另外定义了一个代理服务器服务结构体用于保存一个代理请求的全部信息,其他的是函数声明 发现贴在网页上的代码没有了漂亮的颜色和规范的格式,如需要详细分析,下载该类更好。 基本功能函数(实现基本功能) char cur_method; // 服务器当前使用的认证方法,分要和不要身份认证两种 CSocks sock5; extern char Account; // 服务器设置的帐号,为空表示认证方法为无需认证 extern char Password; // 服务器设置的密码 ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// CSocks::CSocks() { } CSocks::~CSocks() { WSACleanup(); } ////////////////////////////////////////////////////////////////////////// /* 基本功能函数 */ /* 工程: SecretAgent Proxy */ /* 作者: 朱 科 (HUST) */ /* 时间: 2005.7 */ ////////////////////////////////////////////////////////////////////////// /*************************************************************/ /*功能 选定服务结构体中指定的套接字接收数据 参数 ProxyStruct &proxy 服务结构体 int choosesocket 选择接收数据的套接字 char *buf 接收缓存区 int len 希望接收到的字符个数 返回 实际接收数据 -1结束套接字结构 /*************************************************************/ int CSocks::read_chars(ProxyStruct &proxy, int choosesocket,char *buf, int len) { int n; switch(choosesocket) { case 0: if ((n = recv(proxy.Socket,buf,len,0)) <= 0) { close_and_exit(proxy); } break; case 1: if ((n = recv(proxy.relay_sock,buf,len,0)) <= 0) { close_and_exit(proxy); } break; case 2: if ((n = recv(proxy.new_svr_sock,buf,len,0)) <= 0) { close_and_exit(proxy); } break; default: n=-1; break; } return(n); } /*************************************************************/ /*功能 选定服务结构体中指定的套接字发送数据 参数 ProxyStruct &proxy 服务结构体 int choosesocket 选择发送数据的套接字 char *buf 发送缓存区 int len 希望发送的字符个数 返回 实际发送数据 -1结束套接字结构 /*************************************************************/ int CSocks::write_chars(ProxyStruct &proxy,int choosesocket, char *buf, int len) { int n; switch(choosesocket) { case 0: if ((n = send(proxy.Socket, buf, len,0)) < 0) { close_and_exit(proxy); } break; case 1: if ((n = send(proxy.relay_sock, buf, len,0)) < 0) { close_and_exit(proxy); } break; case 2: if ((n = send(proxy.new_svr_sock, buf, len,0)) < 0) { close_and_exit(proxy); } break; default: n=-1; break; } return(n); } /*************************************************************/ /*功能 结束服务结构体中所有活动的套接字 参数 ProxyStruct &proxy 服务结构体 /*************************************************************/ void CSocks::close_and_exit(ProxyStruct &proxy) { if (proxy.Socket != -1) closesocket(proxy.Socket); if (proxy.new_svr_sock != -1) closesocket(proxy.new_svr_sock); if (proxy.relay_sock != -1) closesocket(proxy.relay_sock); if (proxy.udp_sock != -1) closesocket(proxy.udp_sock); } /*************************************************************/ /*功能 用于SOCKS代理,获得SOCKS的版本号 参数 ProxyStruct &proxy 服务结构体 /*************************************************************/ void CSocks::get_version(ProxyStruct &proxy) { read_chars(proxy, 0, &proxy.ver, 1); } /*************************************************************/ /*功能 用于SOCKS4/5代理,获得CONNECT命令后,用它来连接目的主机 参数 ProxyStruct &proxy 服务结构体 DWORD l_dst_ip 目的主机IP,网络字节顺序 WORD dst_port 目的端口,网络字节顺序 返回 TRUE 目的主机连通 FLASE 目的主机不通 /*************************************************************/ BOOL CSocks::creat_connect_sock(ProxyStruct &proxy,DWORD l_dst_ip, WORD dst_port) { struct sockaddr_in dst_addr; memset(&dst_addr,0x00,sizeof(sockaddr_in)); dst_addr.sin_family = AF_INET; dst_addr.sin_addr.s_addr = l_dst_ip; dst_addr.sin_port = dst_port; if ((proxy.relay_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { return FALSE; } // 连接目的主机 if (connect(proxy.relay_sock,(struct sockaddr *)&dst_addr, sizeof(dst_addr)) < 0) { return FALSE; } return TRUE; } /*************************************************************/ /*功能 用于SOCKS5代理,获得UDP_ACCOCIATE命令后,创建UDP套接字 参数 ProxyStruct &proxy 服务结构体 DWORD l_dst_ip 目的主机IP,一般客户端发送的都是0,不必要 WORD dst_port 客户端发送的表明自己将来会用于UDP接收的端口号 返回 TRUE 创建UDP套接字成功 FLASE 创建UDP套接字失败 说明 函数中附带将“服务结构体”的clientaddr赋值,记录下客户 端的地址信息(将来客户端用于UDP接收的地址),并改变 *dst_port值为服务器分配的连接到目的主机的端口 /*************************************************************/ BOOL CSocks::creat_udp_sock(ProxyStruct &proxy, DWORD *l_dst_ip, WORD *dst_port) { struct sockaddr_in me_addr; int addr_len; WORD port = 1024; memset(&proxy.clientaddr,0x00,sizeof(sockaddr_in)); //获取客户端的地址结构: addr_len = sizeof(struct sockaddr_in); if (getpeername(proxy.Socket, (struct sockaddr *)&me_addr,&addr_len) < 0) { closesocket(proxy.Socket); proxy.Socket = -1; return 0; } else proxy.clientaddr.sin_addr.s_addr=me_addr.sin_addr.s_addr; proxy.clientaddr.sin_port=*dst_port; // 赋值,见说明 proxy.clientaddr.sin_family=AF_INET; if ((proxy.udp_sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { return FALSE; } // 从1024开始,任选1024至5000的端口号绑定udp_sock for (port = 1024;port <= 5000;port ++) { memset(&me_addr,0x00,sizeof(sockaddr_in)); me_addr.sin_family = AF_INET; me_addr.sin_addr.s_addr = INADDR_ANY; me_addr.sin_port = htons(port); if (bind(proxy.udp_sock, (struct sockaddr *)&me_addr, sizeof(me_addr)) < 0) { continue; } else { break; } } if (port > 5000) return FALSE; // 获取套接字的本地地址结构 if (getsockname(proxy.udp_sock,(struct sockaddr *)&me_addr, &addr_len) < 0) { closesocket(proxy.udp_sock); proxy.udp_sock = -1; return FALSE; } // 返回值,应答客户端,分别为本机IP和服务器分配给udp_sock套接字的端口 else { *l_dst_ip = me_addr.sin_addr.s_addr; *dst_port = me_addr.sin_port; } return TRUE; } /*************************************************************/ /*功能 用于SOCKS4/5代理,获得BIND命令后,创建new_svr_sock套接字 代替客户端在服务器上监听连接。 参数 ProxyStruct &proxy 服务结构体 DWORD l_dst_ip SOCKS服务器用来监听进入的连接的IP WORD dst_port SOCKS服务器用来监听进入的连接的端口号 返回 TRUE 创建UDP套接字成功 FLASE 创建UDP套接字失败 说明 函数中将“服务结构体”的comein_ip和comein_port赋值,即 记录下客户端希望连入者的的地址信息,以判断连接者是否合法 /*************************************************************/ BOOL CSocks::creat_bind_sock(ProxyStruct &proxy,DWORD *l_dst_ip, WORD *dst_port) { struct sockaddr_in me_addr; int addr_len; WORD port = 1024; // 记录客户端要求的合法连接者信息 proxy.comein_ip = *l_dst_ip; proxy.comein_port = *dst_port; if ((proxy.new_svr_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { return FALSE; } // 任选1024至5000的端口号绑定new_svr_sock for (port = 1024;port <= 5000;port ++) { memset(&me_addr,0x00,sizeof(sockaddr_in)); me_addr.sin_family = AF_INET; me_addr.sin_addr.s_addr = INADDR_ANY; me_addr.sin_port = htons(port); // 此处改正一个错误 // 给ProxyStruct的new_svr_sock赋值 if (bind(proxy.new_svr_sock, (struct sockaddr *)&me_addr, sizeof(me_addr)) < 0) { continue; } else { break; } } if (port > 5000) return FALSE; addr_len = sizeof(struct sockaddr_in); // 获取套接字的本地地址结构 if (getsockname(proxy.new_svr_sock,(struct sockaddr *)&me_addr, &addr_len) < 0) { closesocket(proxy.new_svr_sock); proxy.new_svr_sock = -1; return FALSE; } // 返回值,应答客户端,分别为本机IP和服务器分配给new_svr_sock套接字的端口 else { *l_dst_ip = me_addr.sin_addr.s_addr; *dst_port = me_addr.sin_port; } return TRUE; } /*************************************************************/ /*功能 用于SOCKS4/5代理,创建new_svr_sock套接字监听(上一函数) 后,如果有连接者,判断是否合法,合法则赋值relay_sock套 接字,交换数据。 参数 ProxyStruct &proxy 服务结构体 DWORD l_dst_ip 实际相当于返回值,赋值后将应答回客户端 WORD dst_port 实际相当于返回值,赋值后将应答回客户端 返回 TRUE 等待连接成功,可交换数据 FLASE 等待连接失败,关闭 /*************************************************************/ BOOL CSocks::wait_connect_in(ProxyStruct &proxy,DWORD *l_dst_ip, WORD *dst_port) { struct sockaddr_in dst_addr; int addr_len; listen(proxy.new_svr_sock, 5); // 监听来访者,给ProxyStruct的relay_sock赋值 if ((proxy.relay_sock = accept(proxy.new_svr_sock,(struct sockaddr *)&dst_addr, &addr_len)) < 0) { return FALSE; } addr_len = sizeof(struct sockaddr_in); //获取与套接字相连的端地址结构dst_addr if (getpeername(proxy.relay_sock, (struct sockaddr *)&dst_addr,&addr_len) < 0) { closesocket(proxy.relay_sock); proxy.relay_sock = -1; return FALSE; } // 比较是否为合法的连接者 if (dst_addr.sin_addr.s_addr != proxy.comein_ip || dst_addr.sin_port != proxy.comein_port ) { closesocket(proxy.relay_sock); proxy.relay_sock = -1; return FALSE; } //获取套接字的本地地址结构: if (getsockname(proxy.relay_sock, (struct sockaddr *)&dst_addr,&addr_len) < 0) { closesocket(proxy.relay_sock); proxy.relay_sock = -1; return FALSE; } // 返回值,用于应答客户端 else { *l_dst_ip = dst_addr.sin_addr.s_addr; *dst_port = dst_addr.sin_port; } return TRUE; } /*************************************************************/ /*功能 用于SOCKS代理和HTTP代理的TCP数据交换,交换在“服务结构体” 的两个套接字Socket和relay_sock之间进行,Socket代表客户端 到代理之间的连接,relay_sock代表代理到目的主机的连接 参数 ProxyStruct &proxy 服务结构体 返回 直到因为两个套接字中的某个被关闭才返回。 /*************************************************************/ void CSocks::relay_tcp_data(ProxyStruct &proxy) { int n; int fdNum; char buf[4096]; fd_set fdR; for(;;) { FD_ZERO( &fdR ); FD_SET(proxy.Socket, &fdR); FD_SET(proxy.relay_sock, &fdR); fdNum = max(proxy.Socket, proxy.relay_sock) + 1; switch(select(0, &fdR, NULL, NULL, NULL)) // 非阻塞式 { case -1: // 出错退出 return; case 0: // 超时退出 closesocket(proxy.relay_sock); proxy.relay_sock = -1; return; default: // 客户端->服务器->目的 if (FD_ISSET(proxy.Socket, &fdR)) { n = read_chars(proxy,0, buf, 1024); if (n>0) write_chars(proxy,1, buf, n); else return; } // 客户端<-服务器<-目的 if (FD_ISSET(proxy.relay_sock, &fdR)) { n = read_chars(proxy,1, buf , 1024); if (n>0) write_chars(proxy,0, buf, n); else return; } } } } 基本功能函数说明 最前面定义了几个全局变量,意义可看注释。 |
学习日记,兼职软件设计,软件修改,毕业设计。
本文出自 学习日记,转载时请注明出处及相应链接。
本文永久链接: https://www.softwareace.cn/?p=597