Socks5 协议

建立连接

客户端连接到服务端,发送一个版本标志和验证方法选择的消息

+----+----------+----------+
|VER | NMETHODS | METHODS  |
+----+----------+----------+
| 1  |    1     | 1 to 255 |
+----+----------+----------+

一般VER被设置为05,表示Socks版本5,NMETHODS表示支持的验证方法数量。METHODS则是验证方法列表。

X'00' NO AUTHENTICATION REQUIRED
X'01' GSSAPI
X'02' USERNAME/PASSWORD
X'03' to X'7F' IANA ASSIGNED
X'80' to X'FE' RESERVED FOR PRIVATE METHODS
X'FF' NO ACCEPTABLE METHODS

服务端会选择一个验证方法,返回消息

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

如果返回的是X'FF',客户端必须关闭连接。

其他情况下,客户端和服务端会进入特定验证方法的协商阶段。

请求

一旦验证协商阶段完成,客户端开始发送具体请求,请求格式如下

+----+-----+-------+------+----------+----------+
|VER | CMD |  RSV  | ATYP | DST.ADDR | DST.PORT |
+----+-----+-------+------+----------+----------+
| 1  |  1  | X'00' |  1   | Variable |    2     |
+----+-----+-------+------+----------+----------+
  • VER 版本
  • CMD 操作符

    • CONNET : X'01'
    • BIND : X'02'
    • UDP ASSOCIATE : X'03'
  • RSV 保留字段
  • ATYP 地址类型

    • IPV4 : X'01'
    • DOMAIN : X'03'
    • IPV6 : X'04'
  • DST.ADDR 目标地址

    • 如果是IPV4,4位长度
    • 如果是域名,则首位表示整个长度
    • 如果是IPV6,16位长度
  • DST.PORT 目标端口

回复

服务端返回格式如下

+----+-----+-------+------+----------+----------+
|VER | REP |  RSV  | ATYP | BND.ADDR | BND.PORT |
+----+-----+-------+------+----------+----------+
| 1  |  1  | X'00' |  1   | Variable |    2     |
+----+-----+-------+------+----------+----------+
  • VER 版本
  • REP 回复字段

    • X'00' 成功
    • X'01' 常规SOCKS服务器错误
    • X'02' 请求不被规则允许
    • X'03' 网络无法到达
    • X'04' HOST无法到达
    • X'05' 连接被拒绝
    • X'06' TTL过期
    • X'07' 命令不支持
    • X'08' 地址类型不支持
    • X'09' to X'FF' unassigned
  • RSV 保留字段
  • ATYP 地址类型,同上
  • BND.ADDR 服务绑定地址
  • BND.PORT 服务绑定端口

保留字短必须为X'00'

CONNECT

对于CONNECT的回复,BND.PORT包含了服务端连接到目标服务器的端口,BND.ADDR包含关联的IP地址,有时候BND.ADDR不同于客户端请求的服务端IP(SOCKS服务器可能有多个IP)

BIND(略过)
   The BIND request is used in protocols which require the client to
   accept connections from the server.  FTP is a well-known example,
   which uses the primary client-to-server connection for commands and
   status reports, but may use a server-to-client connection for
   transferring data on demand (e.g. LS, GET, PUT).

   It is expected that the client side of an application protocol will
   use the BIND request only to establish secondary connections after a
   primary connection is established using CONNECT.  In is expected that
   a SOCKS server will use DST.ADDR and DST.PORT in evaluating the BIND
   request.

   Two replies are sent from the SOCKS server to the client during a
   BIND operation.  The first is sent after the server creates and binds
   a new socket.  The BND.PORT field contains the port number that the
   SOCKS server assigned to listen for an incoming connection.  The
   BND.ADDR field contains the associated IP address.  The client will
   typically use these pieces of information to notify (via the primary
   or control connection) the application server of the rendezvous
   address.  The second reply occurs only after the anticipated incoming
   connection succeeds or fails.
UDP ASSOCIATE

UDP关联用来中转处理UDP数据,DST.ADDR和DST.PORT包含客户端想要把UDP数据发往的地址和端口,服务端可以用这些信息来做一些限制。如果客户端在发送这个请求时没有地址和端口信息,客户端必须用全0来填充。

当UDP ASSOCIATE相关的TCP连接中断的时候,UDP也必须停止。

应答UDP ASSOCIATE请求时,BND.PORT 和BND.ADDR字段指明了客户发送UDP消息至服务器的端口和地址。

回复处理

当服务端返回失败信息之后(REP值不是X'00'),服务端必须在十秒之内中断TCP连接。

如果返回值表明成功,请求是BIND或者CONNET,客户端应该立即开始发送数据。

基于UDP的客户端程序

UDP客户端必须发送数据到UDP ASSSOCIATE响应中的BND.PORT。每个UDP请求都带有如下的头部。

+----+------+------+----------+----------+----------+
|RSV | FRAG | ATYP | DST.ADDR | DST.PORT |   DATA   |
+----+------+------+----------+----------+----------+
| 2  |  1   |  1   | Variable |    2     | Variable |
+----+------+------+----------+----------+----------+
  • RSV 保留字段 X'0000'
  • FRAG 当前帧数
  • ATYP 同上
  • DST.ARRD
  • DST.PORT
  • DATA 用户数据

当一个UDP中转服务器决定去转发UDP数据时,无需通知请求的客户端,同样的,也可以静默的抛弃无法转发或者无法到达的数据包。当UDP中转服务端接收到远端的响应时,它必须使用上面的UDP头来封装数据。

UDP中转服务器必须获得客户端想要数据发往的地址和端口,如果数据来自的IP地址与该特定连接中指定的IP地址不同,那么该数据报会被丢弃。

FRAG字段指明数据报是否是一些分片中的一片。如果SOCKS服务器要实现这个功能,X’00’指明数据报是独立的;其他则越大越是数据报的尾端。介于1到127之间的值说明了该分片在分片序列里的位置。每个接收者都为这些分片提供一个重组队列和一个重组的计时器。这个重组队列必须在重组计时器超时后重新初始化,并丢弃相应的数据报。或者当一个新到达的数据报有一个比当前在处理的数据报序列中最大的FRAG值要小时,也必须重新初始化从组队列。重组计时器必须小于5秒。只要有可能,应用程序最好不要使用分片。

分片的实现是可选的;如果某实现不支持分片,所有FRAG字段不为0的数据报都必须被丢弃。

来源:rfc1928