Socks5代理协议
或许你没听说过socks5,但你一定听说过SS,SS内部使用的正是socks5协议。
socks5是一种网络传输协议,主要用于客户端与目标服务器之间通讯的透明传递。
该协议设计之初是为了让有权限的用户可以穿过防火墙的限制,访问外部资源。
1. RFC地址
- socks5协议规范rfc1928
- socks5账号密码鉴权规范rfc1929
2. 协议过程
- 客户端连接上代理服务器之后需要发送请求告知服务器目前的socks协议版本以及支持的认证方式
- 代理服务器收到请求后根据其设定的认证方式返回给客户端
- 如果代理服务器不需要认证,客户端将直接向代理服务器发起真实请求
- 代理服务器收到该请求之后连接客户端请求的目标服务器
- 代理服务器开始转发客户端与目标服务器之间的流量
3. 认证过程
3.1 客户端发出请求
客户端连接服务器之后将直接发出该数据包给代理服务器
VERSION | METHODS_COUNT | METHODS... |
---|
1字节 | 1字节 | 1到255字节,长度由METHODS_COUNT值决定 |
0x05 | 0x03 | 0x00 0x01 0x02 |
- VERSION SOCKS协议版本,目前固定0x05
- METHODS_COUNT 客户端支持的认证方法数量
- METHODS... 客户端支持的认证方法,每个方法占用1个字节
METHOD定义
- 0x00 不需要认证(常用)
- 0x01 GSSAPI认证
- 0x02 账号密码认证(常用)
- 0x03 - 0x7F IANA分配
- 0x80 - 0xFE 私有方法保留
- 0xFF 无支持的认证方法
3.2 服务端返回选择的认证方法
接收完客户端支持的认证方法列表后,代理服务器从中选择一个受支持的方法返回给客户端
3.2.1 无需认证
VERSION | METHOD |
---|
1字节 | 1字节 |
0x05 | 0x00 |
- VERSION SOCKS协议版本,目前固定0x05
- METHOD 本次连接所用的认证方法,上例中为无需认证
3.2.2 账号密码认证
VERSION | METHOD |
---|
1字节 | 1字节 |
0x05 | 0x02 |
3.2.3 客户端发送账号密码
服务端返回的认证方法为0x02(账号密码认证)时,客户端会发送账号密码数据给代理服务器
VERSION | USERNAME_LENGTH | USERNAME | PASSWORD_LENGTH | PASSWORD |
---|
1字节 | 1字节 | 1-255字节 | 1字节 | 1-255字节 |
0x01 | 0x01 | 0x0a | 0x01 | 0x0a |
- VERSION 认证子协商版本(与SOCKS协议版本的0x05无关系)
- USERNAME_LENGTH 用户名长度
- USERNAME 用户名字节数组,长度为USERNAME_LENGTH
- PASSWORD_LENGTH 密码长度
- PASSWORD 密码字节数组,长度为PASSWORD_LENGTH
3.2.4 服务端响应账号密码认证结果
收到客户端发来的账号密码后,代理服务器加以校验,并返回校验结果
- VERSION 认证子协商版本,与客户端VERSION字段一致
STATUS 认证结果
4. 命令过程
认证成功后,客户端会发送连接命令给代理服务器,代理服务器会连接目标服务器,并返回连接结果
4.1 客户端请求
VERSION | COMMAND | RSV | ADDRESS_TYPE | DST.ADDR | DST.PORT |
---|
1字节 | 1字节 | 1字节 | 1字节 | 1-255字节 | 2字节 |
- VERSION SOCKS协议版本,固定0x05
COMMAND 命令
- 0x01 CONNECT 连接上游服务器
- 0x02 BIND 绑定,客户端会接收来自代理服务器的链接,著名的FTP被动模式
- 0x03 UDP ASSOCIATE UDP中继
- RSV 保留字段
ADDRESS_TYPE 目标服务器地址类型
- 0x01 IP V4地址
- 0x03 域名地址(没有打错,就是没有0x02),域名地址的第1个字节为域名长度,剩下字节为域名名称字节数组
- 0x04 IP V6地址
- DST.ADDR 目标服务器地址
- DST.PORT 目标服务器端口
4.2 代理服务器响应
VERSION | RESPONSE | RSV | ADDRESS_TYPE | BND.ADDR | BND.PORT |
---|
1字节 | 1字节 | 1字节 | 1字节 | 1-255字节 | 2字节 |
- VERSION SOCKS协议版本,固定0x05
RESPONSE 响应命令
- 0x00 代理服务器连接目标服务器成功
- 0x01 代理服务器故障
- 0x02 代理服务器规则集不允许连接
- 0x03 网络无法访问
- 0x04 目标服务器无法访问(主机名无效)
- 0x05 连接目标服务器被拒绝
- 0x06 TTL已过期
- 0x07 不支持的命令
- 0x08 不支持的目标服务器地址类型
- 0x09 - 0xFF 未分配
- RSV 保留字段
- BND.ADDR 代理服务器连接目标服务器成功后的代理服务器IP
- BND.PORT 代理服务器连接目标服务器成功后的代理服务器端口
5. 通信过程
经过认证与命令过程后,客户端与代理服务器进入正常通信,客户端发送需要请求到目标服务器的数据给代理服务器,代理服务器转发这些数据,并把目标服务器的响应转发给客户端,起到一个“透明代理”的功能。
6. 实际例子
上文详细讲解了协议规范,下面来一个实例的通信过程范例。
6.2中无需认证和需要账号密码认证是互斥的,同一请求只会采取一种,本文都列在下面。
6.1 客户端发送受支持的认证方法
0x05 0x02 0x00 0x02
- 0x05 SOCKS5协议版本
- 0x02 支持的认证方法数量
- 0x00 免认证
- 0x02 账号密码认证
6.2 服务端响应选择的认证方法
6.2.1 无需认证
以下是无需认证,客户端收到该响应后直接发送需要发送给目标服务器的数据给到代理服务器,此时进入通信错过程
0x05 0x00
6.2.2 需要账号密码认证
0x05 0x02
- 0x05 SOCKS5协议版本
- 0x02 账号密码认证
6.2.3 客户端发送账号密码
0x01 0x04 0x61 0x61 0x61 0x61 0x04 0x61 0x61 0x61 0x61
- 0x01 子协商版本
- 0x04 用户名长度
- 0x61 0x61 0x61 0x61 转换为ascii字符之后为"aaaa"
- 0x04 密码长度
- 0x61 0x61 0x61 0x61 转换为ascii字符之后"aaaa"
6.2.4 代理服务器响应认证结果
0x01 0x00
- 0x01 子协商版本
- 0x00 认证成功(也就是代理服务器允许aaaa账号以aaaa密码登录)
6.3 客户端请求代理服务器连接目标服务器
以127.0.0.1和80端口为例
0x05 0x01 0x01 0x01 0x7f 0x00 0x00 0x01 0x00 0x50
- 0x05 SOCKS协议版本
- 0x01 CONNECT命令
- 0x01 RSV保留字段
- 0x01 地址类型为IPV4
- 0x7f 0x00 0x00 0x01 目标服务器IP为127.0.0.1
- 0x00 0x50 目标服务器端口为80
6.4 代理服务器连接目标主机,并返回结果给客户端
0x05 0x00 0x01 0x01 0x7f 0x00 0x00 0x01 0x00 0xaa 0xaa
- 0x05 SOCKS5协议版本
- 0x00 连接成功
- 0x01 RSV保留字段
- 0x01 地址类型为IPV4
- 0x7f 0x00 0x00 0x01 代理服务器连接目标服务器成功后的代理服务器IP, 127.0.0.1
- 0xaa 0xaa 代理服务器连接目标服务器成功后的代理服务器端口(代理服务器使用该端口与目标服务器通信),本例端口号为43690
6.5 客户端发送请求数据给代理服务器
如果客户端需要请求目标服务器的HTTP服务,就会发送HTTP协议报文给代理服务器,代理服务器将这些报文原样转发给目标服务器,并将目标服务器的响应发送给客户端,代理服务器不会对客户端或者目标服务器的报文做任何解析。
7. 结尾
SOCKS5协议的讲解到此结束,后续会使用GOLANG实现一个SOCKS5服务器来讲述TCP协议服务器的开发。