SOCKS v5 的原理与 SOCKS v4/v4a 的原理大致相同,但增加了对 UDP 协议的支持、安全验证机制及 IPv6 的支持。客户端通过 SOCKS v5 代理服务器与外部建立连接的流程如下:
1、 客户端尝试连接代理服务器;
2、 客户端选择一种认证的方法,并发送认证信息的方法代码至代理服务器;
3、 若代理服务器不接受此认证方法,则拒绝客户端的请求;
4、 若代理服务器接受了此认证方法,则客户端可根据方法的规定与代理服务器进行一些信息通讯,如发送用户名及密码等;
5、 认证成功后,客户端将发送一个类似于 SOCKS v4 的请求数据包给代理服务器;
6、 代理服务器发送一个类似于 SOCKS v4 规定的回复数据包给客户端;
7、 若以上操作均成功进行,则此时客户端可以与目标主机通过代理服务器进行相互通讯。
客户端认证请求数据包格式
字段名 | VER | NMETHODS | 认证方式 1 | …… | 认证方式 n |
字段值 | 5 | 认证方式数目 n | 0-254 | 0-254 | 0-254 |
字段大小 (字节) | 1 | 1 | 1 | 1 | 1 |
代理服务器应答认证数据包格式
字段名 | VER | 代理接受的认证方式 |
字段值 | 5 | 0-254 (或返回 255 代表不支持此认证方式) |
字段大小(字节) | 1 | 1 |
已定义的认证方式代号:
0x00: 无验证
0x01: 通过 GSSAPI 验证
0x02: 通过常规的“用户名 / 密码”对验证
0x03-0x7F: 通过 IANA (互联网地址编码分配机构 Internet Assigned Numbers Authority )进行验证
0x80-0xFE: 可以由用户自行定义
0xFF: 不接受的认证方式
其中目前的 GSSAPI 认证方法一般有以下几种: Kerberos , NTLM , Distributed Computing Environment (DCE) , SESAME , SPKM , LIPKEY 。
“用户名 / 密码”对认证数据包格式
字段名 | VER | ULEN | USERNAME | PLEN | PASSWD |
字段值 | 1 | 用户名长度 | 用户名 | 密码长度 | 密码 |
字段大小 (字节) | 1 | 1 | 可变 | 1 | 可变 |
代理服务器应答“用户名 / 密码”对认证数据包格式
字段名 | VER | STATUS |
字段值 | 1 | 0 - 成功 非零 - 失败 |
字段大小(字节) | 1 | 1 |
注意:若认证失败,则代理服务器应马上关闭与客户端的连接。
认证成功后,客户端可向代理服务器发送连接请求,格式大致与 v4 版一样,但 v5 版增加了 UDP 和 IPv6 的支持,并且支持域名解析。
客户端“ CONNECT/BIND/UDP 关联”请求数据包格式
字段名 | VER | CMD | RSV | ATYP | DSTADDR | DSTPORT |
字段值 | 5 | 1 - CONNECT 2 - BIND 3 - UDP 关联 | 0 (保留) | 1 - IPv4 3 - 域名 4 - IPv6 | IP/ 域名 | 通讯端口 |
字段大小(字节) | 1 | 1 | 1 | 1 | 可变 | 2 |
注意:若 DSTADDR 为域名,则该字段的第一字节代表域名名称的长度,域名名称最后无 NULL 作为终止符。
代理服务器应答请求数据包格式
字段名 | VER | REP | RSV | ATYP | BNDADDR | BNDPORT |
字段值 | 5 | 应答代号 | 0 (保留) | 1 - IPv4 3 - 域名 4 - IPv6 | 绑定的 地址 | 绑定的 端口 |
字段大小(字节) | 1 | 1 | 1 | 1 | 可变 | 2 |
其中 REP 字段的值及其表示意义如下(注:RFC英文原文及本人翻译):
0x00: succeeded 成功
0x01: general SOCKS server failure 常规 SOCKS 服务器失败
0x02: connection not allowed by ruleset 规则集不允许此连接
0x03: Network unreachable 网络不可达
0x04: Host unreachable 主机不可达
0x05: Connection refused 连接被拒绝
0x06: TTL expired TTL 期限已失效
0x07: Command not supported 命令不支持
0x08: Address type not supported 地址类型不支持
0x09 - 0xFF unassigned 未定义
1、 CONNECT
在对一个 CONNECT 命令的应答中, BND.PORT 包含了服务器分配的用来连到目标机的端口号, BND.ADDR 则是相应的 IP 地址。由于 SOCKS 服务器通常有多个 IP ,应答中的 BND.ADDR 常和客户端连到 SOCKS 服务器的那个 IP 不同。
SOCKS 服务器可以利用 DST.ADDR 和 DST.PORT ,以及客户端源地址和端口来对一个 CONNECT 请求进行分析。
2、 BIND
BIND 请求通常被用在那些要求客户端接受来自服务器的连接的协议上。 FTP 是一个典型的例子。它建立一个从客户端到服务器端的连接来执行命令以及接收状态的报告,而使用另一个从服务器到客户端的连接来接收传输数据的要求 ( 如 LS , GET , PUT) 。
建议只有在一个应用协议的客户端在使用 CONNECT 命令建立主连接后才可以使用 BIND 命令建立第二个连接。建议 SOCKS 服务器使用 DST.ADDR 和 DST.PORT 来评价 BIND 请求。
在一个 BIND 请求的操作过程中, SOCKS 服务器要发送两个应答给客户端。当服务器建立并绑定一个新的套接口时发送第一个应答。 BND.PORT 字段包含 SOCKS 服务器用来监听进入的连接的端口号, BAND.ADDR 字段包含了对应的 IP 地址。客户端通常使用这些信息来告诉(通过主连接或控制连接)应用服务器连接的汇接点。第二个应答仅发生在所期望到来的连接成功或失败之后。在第二个应答中, BND.PORT 和 BND.ADDR 字段包含了连上来的主机的 IP 地址和端口号。
3、 UDP 关联
UDP 关联请求通常是要求建立一个 UDP 转发进程来控制到来的 UDP 数据报。 DST.ADDR 和 DST.PORT 字段包含客户端所希望的用来发送 UDP 数据报的 IP 地址和端口号。服务器可以使用这个信息来限制进入的连接。如果客户端在发送这个请求时没有地址和端口信息,客户端必须用全 0 来填充。
当与 UDP 相应的 TCP 连接中断时,该 UDP 连接也必须中断。
应答 UDP 关联请求时, BND.PORT 和 BND.ADDR 字段指明了客户发送 UDP 消息至服务器的端口和地址。
4、 应答处理
当一个应答 (REP 值不等于 00) 指明出错时, SOCKS 服务器必须在发送完应答消息后一小段时间内终止 TCP 连接。这段时间应该在发现错误后少于 10 秒。
如果一个应答 (REP 值等于 00) 指明成功,并且请求是一个 BIND 或 CONNECT 时,客户端就可以开始发送数据了。如果协商的认证方法中有以完整性、认证和 / 或安全性为目的的封装,这些请求必须按照该方法所定义的方式进行封装。类似的,当以客户机为目的地的数据到达 SOCKS 服务器时, SOCKS 服务器必须用正在使用的方法对这些数据进行封装。