socks5代理浅识

  在防火墙内部的客户端主机(A)想访问某个服务器(C)时,有时候是无法直接访问的;但是如果有一台服务(B),A可以直接访问,而B又可以直接访问C,那么就可以通过访问B服务达到间接访问C的目的,B称为代理服务器。这篇文章介绍下socks5的TCP代理。

一、什么是socks5代理

  socks5是socks协议中最新版本协议,前有socks4和socks4a两个版本。socks是一种网络传输协议,主要用于客户端与外网服务器之间的中间传输。socks5相较于socks4新增了连接验证、UDP包代理和IPV6的支持。今天主要简单介绍socks5协议实现tcp代理。

二、socks5代理协议"三步走"

  第一步:客户端和代理服务器建立socket-tcp代理连接后,客户端向代理服务器发送请求来确认协议版本和认证方式,协议格式(以字节为单位)如下:

--------------------------------------
| VER  | NMETHODS | METHODS |
--------------------------------------
|   1  |     1    | 1~255   |
-------------------------------------- 

    VER:socks版本号,socks5版本号:0x05,占用1字节

  NMETHODS:METHODS字段的长度,占有1字节

  METHODS:客户端支持的认证方法列表,每个方法占有一个字节。当前定义如下:

  0x00:不需要认证

  0x001:GSSAPI

  0x02:用户名、密码认证

  0x03-0x7F:由IANA分配,属于保留字段

  0X80-0XFE:为私人方法保留

  0XFF:无可接受的方法

  代理服务从客户端收到的协议中选择一个认证方法,并发送如下格式(字节为单位)给客户端:

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

  VER:socks版本号

  METHOD:认证方式,如果返回的是0XFF,客户端没有认证方式,需要与服务器关闭连接

  客户端向代理服务器发送认证信息,如果认证成功,进入第二步,否则关闭连接,重新开始。

  用户名和密码认证格式:

-------------------------------------------------
|  签订协议版本 |  用户名长度 | 用户名 | 密码长度|密码 |
|      1      |      1    |  动态  |    1   | 动态|
-------------------------------------------------
签订协议版本号目前:0x01

  代理服务器返回格式:

-------------------
|签订协议版本|认证状态|
|     1    |  1    |
-------------------
认证状态码:
0x00:成功
0x01:失败

  第二步:客户端向代理服务器发送代理请求信息,socks5请求格式(字节为单位)如下:

----------------------------------------------------------------------------
|  VER   |   CMD   |   RSV   |   ATYP   |   DST.ADDR     |  DST.PORT       |
---------------------------------------------------------------------------|
|   1    |    1    |    1    |     1    |    动态         |   2             |
----------------------------------------------------------------------------

  VER:socks版本号

  CMD:socks命令码:

  0x01:连接请求

  0x02:BIND请求

  0x03:UDP转发

  RSV:保留字段,0x00

  ATYP:目标服务器的地址类型:

  0x01:IPV4, DST.ADDR字节为4

  0x03:域名,DST.ADDR第一个字节为域名长度,后面为域名存放字节,不要\0结尾

  0x04:IPV6,DST.ADDR字节为16

  DST.ADDR:目标服务器地址

  DST.PORT:目标服务端口号

  代理服务器收到客户端请求后,回复如下请求:

----------------------------------------------------------------------------
|  VER   |   REP   |   RSV   |   ATYP   |   BND.ADDR    |  BND.PORT   |
---------------------------------------------------------------------------|
|   1      |    1      |    1      |     1      |    动态             |         2         |
----------------------------------------------------------------------------

  VER:版本号

  REP:应答字段:

  0x00:成功

  0x01:普通socks服务器连接失败

  0x02:现有规则不允许连接

  0x03:网络不可达

  0x04:主机不可达

  0x05:连接被拒

  0x06:TTL超时

  0x07:不支持的命令

  0x08:不支持的地址类型

  0x09-0xFF:未定义

  RSV:保留

  ATYP:同上

  BND.ADDR:代理服务器绑定的地址

  BND.PORT:代理服务器绑定的端口

  第三步:以上两步都成功后,客户端和 代理服务器,代理服务器和目标服务器都建立了socket连接,这个时候客户端通过与代理服务器建立的socket发送消息,代理服务器会将消息发送给目标服务器。

  

  以上是socks5代理(TCP穿透)原理的核心部分介绍,如果实现UDP代理,还需要一些其他处理才能实现,后面有机会再介绍。

三、socks5代理demo编写

  客户端如何与代理服务器建立socks5代理连接的代码实现,遵循上面所说的三部走:

  前提是客户端与代理服务器建立socket-tcp连接

 1 bool InitWSA()
 2 {
 3     WORD wVersionRequested;
 4     WSADATA wsaData;
 5     int err;
 6 
 7     wVersionRequested = MAKEWORD(1, 1);
 8     err = WSAStartup(wVersionRequested, &wsaData);
 9     if (err != 0)
10     {
11         return false;
12     }
13     if (LOBYTE(wsaData.wVersion) != 1 ||
14         HIBYTE(wsaData.wVersion) != 1)
15     {
16         WSACleanup();
17         return false;
18     }
19     return true;
20 }
1 void main()
2 {
3      InitWSA();
4      SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);  
5  }

  第一步:认证

1 TSock5Request* proxyRequest;
2 proxyRequest = (TSock5Request*)buf;
3 proxyRequest->Ver = 0x05;
4 proxyRequest->nMethods = 0x01;
5 proxyRequest->Methods = 0x00;
6 Send(socket, buf, 3);

  第二步:请求

 1 TSock5Request2* proxyRequest2
 2 proxyRequest2 = (TSock5Request2*)buf;
 3 proxyRequest2->Ver = 5;
 4 proxyRequest2->Cmd = 1;
 5 proxyRequest2->Rsv = 0;
 6 proxyRequest2->Atyp = 1;
 7 unsigned long tmpLong = inet_addr(ip);
 8 unsigned short port1 = ntohs(port);
 9 memcpy((char*)&proxyreq2->other, &tmpLong, 4);
10 memcpy((char*)(&proxyreq2->other) + 4, &port1, 2);
11 
12 Send(socket, buf, 10);

  第三步:发送数据

1  while (true){
2       Send(socket, buf, len);
3       Recive(socket, buf, len);
4  }

  代理服务器响应的数据处理省略。

四、验证

  1.准备工具:两台PC电脑;TCP/UDP socket工具;go的代理服务程序

  2.一台电脑启动go代理服务程序,并使用TCP/UDP socket工具创建服务端口监听,查看go代理服务绑定的目标ip和端口

  3.另外一台电脑启动上面编写的demo,验证另外一台代理服务器绑定的目标服务是否正常接受到数据

  验证截图如下:

  启动go的socks5代理服务器

  

  客户端与代理服务器建立tcp连接后,执行socks5协议后,向代理服务器发送消息:

        

  目标ip正常接受到消息

   

   目标服务器发送消息:

  

   客户端接受到目标服务器发送的数据

       

 

实现源码下载地址:https://files.cnblogs.com/files/smartNeo/socks5_proxy.zip

posted @ 2021-03-22 00:48  blackstar666  阅读(1855)  评论(0编辑  收藏  举报