共计 3115 个字符,预计需要花费 8 分钟才能阅读完成。
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 | STATUS |
---|---|
1 字节 | 1 字节 |
- VERSION 认证子协商版本,与客户端 VERSION 字段一致
-
STATUS 认证结果
- 0x00 认证成功
- 大于 0x00 认证失败
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
- 0x05 SOCKS5 协议版本
- 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 协议服务器的开发。