SOCKS5协议/RFC1928阅读笔记

基于TCP的连接

服务器通常开放在1080端口,协议过程如下:

  1. 客户端连接到服务端,发送**版本标识和认证方式选择(version identifier/method selection)**消息
版本(VER) 认证方法数(NMETHODS) 方法(METHODS)
1字节,=0x05 1字节 1到255字节
  1. 服务端选择一个支持的方法,并返回一个**方法选择(method selection)**消息
版本(VER) 方法(METHOD)
1字节 1字节

如果服务端返回的认证方式(METHOD)客户端不予支持,则客户端必须关闭连接。

当前定义的认证方式有:

  • 0x00:不需要认证
  • 0x01:GSSAPI
  • 0x02:用户名密码认证
  • 0x03~0x7F:由IANA分派
  • 0x80~0xFE:保留用于私有方法
  • 0xFF:没有支持的方法

当认证方式协商完毕后,客户端和服务端将根据对应的方式进入相应的子协议。

  1. 当1和2步的握手完成后,客户端向服务端发送请求的细节,**SOCKS请求(SOCKS request)**描述如下
版本(VER) 命令(CMD) 保留(RSV) 地址类型(ATYP) 目的地址(DST.ADDR) 目的端口(DST.PORT)
1字节,=0x05 1字节 1字节,=0x00 1字节 可变的 2字节,网络序

其中,**命令字(CMD)**定义如下:

  • 0x01:连接(CONNECT)
  • 0x02:绑定(BIND)
  • 0x03:UDP连接(UDP ASSOCIATE)

**地址类型(ATYP)**定义如下:

  • 0x01:IPv4地址,此时DST.ADDR长度为4字节
  • 0x03:域名,此时DST.ADDR的第一个字节用于指定字符串长度,后续一个无'\0'结尾的字符串
  • 0x04:IPv6地址,此时DST.ADDR长度为16字节

服务端会根据请求的内容返回一到多条消息。

此外,如果认证机制带有额外的封装方式,上述消息应当被封装在其中。

  1. SOCKS请求对应的服务端的回包描述如下
版本(VER) 响应(REP) 保留(RSV) 地址类型(ATYP) 绑定地址(DND.ADDR) 绑定端口(DND.PORT)
1字节,=0x05 1字节 1字节,=0x00 1字节 可变的 2字节,网络序

其中,**响应(REP)**定义如下:

  • 0x00:成功
  • 0x01:服务端常规错误
  • 0x02:连接不被规则允许
  • 0x03:网络不可达
  • 0x04:主机不可达
  • 0x05:连接被拒绝
  • 0x06:TTL超时
  • 0x07:命令不支持
  • 0x08:地址类型不支持
  • 0x09~0xFF:尚未分配

地址类型、地址和端口的定义参见SOCKS请求。

此外,如果认证机制带有额外的封装方式,上述消息应当被封装在其中。

  1. 开始数据传输

若服务端的回包不是一个错误(REP为非0值),那么服务端必须在发完回包后(保证回包正确发送)关闭连接,且连接关闭不应当超过10秒。

如果回包是一个正确状态(REP=0),那么客户端将开始发送数据,若认证方式存在相应的封装,服务端将进行解封装操作,并将数据发送到目的主机。

三种命令的解释

CONNECT命令

通知服务端连接到某个地址,回包中的BND.ADDR表明服务端用于连接到目的主机的地址(这个值可能和客户端访问socks服务的地址不同),BND.PORT用于表明服务端连接到目的主机的端口(实际编程中,在connect操作后可以用getsockname获取这一信息)。

BIND命令

BIND请求被用于那些需要服务器反向连接客户端的协议(比如FTP)。这里要求客户端首先使用CONNECT命令建立一个主连接,而后建立一个新的连接并使用BIND命令来通知SOCKS服务器绑定一个地址来接收请求。

请求中的DST.ADDR和DST.PORT将被服务器用于评估连接。

SOCKS服务端将会返回两个回包,第一个回包在服务端创建并绑定一个SOCKS端口后进行,BND.ADDR和BND.PORT填写绑定在服务端上的地址和端口。客户端将使用这些信息来映射协议中的地址。

第二个回包仅在服务端成功或失败地接受一个传入连接时发送,BND.ADDR和BND.PORT包含远端连入的地址和端口。

之后将使用这个连接发送后续的数据。

注:但是这个地方有一个问题,在这种设计下,客户端只能接受一个连接。在stackoverflow上搜索后,看到了这样的答复:

You need a separate BIND request for each connection you want to accept, as there is only 1 notification sent back by the SOCKS proxy when a client connects to the bound port. Whether or not the SOCKS5 proxy allows multiple BIND requests on the same IP/Port depends on the proxy's implementation.

换句话说,当一个连接被成功接受后,客户端可以再次发起连接进行BIND操作绑定相同的地址,从而接受更多的请求。

UDP ASSOCIATE

暂时用不到,略。

基于UDP的连接

暂时用不到,略。

参考