SOCKS 协议版本 5 (RFC 1928)
这份文档描述了 SOCKS 协议版本 5 (SOCKSv5),这是一个标准跟踪协议,旨在为 TCP 和 UDP 领域的客户端-服务器应用程序提供一个通用框架,以便它们能够透明且安全地穿越网络防火墙。
简介
随着网络防火墙的普及,SOCKSv5 应运而生,以解决传统防火墙仅提供有限服务(如 TELNET、FTP、SMTP)的问题。它旨在提供一个通用的框架,使更复杂的应用层协议也能安全地穿越防火墙。此外,SOCKSv5 还强调了对穿越行为进行细粒度强认证的需求,以满足不同组织间客户端-服务器关系的安全控制要求。
SOCKSv5 协议充当应用程序层和传输层之间的“垫片层”,因此它不提供网络层网关服务(例如,转发 ICMP 消息)。
现有实践与 SOCKSv5 的改进
SOCKSv5 是 SOCKS 版本 4 (SOCKSv4) 的演进。SOCKSv4 提供了基于 TCP 的客户端-服务器应用程序(包括 TELNET、FTP 和流行的信息发现协议如 HTTP、WAIS、GOPHER)的非安全防火墙穿越功能。
SOCKSv5 在 SOCKSv4 的基础上进行了以下扩展:
- 支持 UDP: 扩展了对 UDP 协议的支持。
- 通用强认证机制: 引入了通用强认证方案的规定。
- 扩展寻址方案: 支持域名和 IPv6 地址。
SOCKS 协议的实现通常涉及重新编译或重新链接基于 TCP 的客户端应用程序,以使用 SOCKS 库中适当的封装例程。
注意: 除非另有说明,数据包格式图中出现的十进制数字表示相应字段的长度(以八位字节为单位)。当某个八位字节必须取特定值时,使用 X'hh'
语法表示该字段中单个八位字节的值。当使用“Variable”一词时,表示相应字段的长度可变,由关联的(一个或两个八位字节)长度字段或数据类型字段定义。
基于 TCP 客户端的流程
当基于 TCP 的客户端需要建立与只能通过防火墙访问的对象的连接时,它必须打开一个到 SOCKS 服务器系统上相应 SOCKS 端口的 TCP 连接。SOCKS 服务通常位于 TCP 端口 1080。如果连接请求成功,客户端将进入认证方法的协商阶段,使用所选方法进行认证,然后发送中继请求。SOCKS 服务器评估请求,并建立相应的连接或拒绝连接。
1. 版本标识符/方法选择消息:
客户端连接到服务器后,发送以下消息:
+----+----------+----------+
|VER | NMETHODS | METHODS |
+----+----------+----------+
| 1 | 1 | 1 to 255 |
+----+----------+----------+
- VER: 对于 SOCKSv5,此字段设置为
X'05'
。 - NMETHODS: 包含 METHODS 字段中方法标识符八位字节的数量。
2. 方法选择消息:
服务器从 METHODS 字段中给出的方法中选择一个,并发送以下消息:
+----+--------+
|VER | METHOD |
+----+--------+
| 1 | 1 |
+----+--------+
如果选择的 METHOD 是 X'FF'
,则客户端列出的所有方法都不可接受,客户端必须关闭连接。
目前定义的 METHOD 值包括:
X'00'
:无需认证X'01'
:GSSAPIX'02'
:用户名/密码X'03'
到X'7F'
:IANA 分配X'80'
到X'FE'
:保留用于私有方法X'FF'
:没有可接受的方法
客户端和服务器随后进入方法特定的子协商阶段。方法依赖子协商的描述出现在单独的备忘录中。符合规范的实现必须支持 GSSAPI,并且应该支持用户名/密码认证方法。
请求
方法依赖子协商完成后,客户端发送请求详情。如果协商的方法包含用于完整性检查和/或保密性的封装,则这些请求必须在方法依赖的封装中进行封装。
SOCKS 请求格式如下:
+----+-----+-------+------+----------+----------+
|VER | CMD | RSV | ATYP | DST.ADDR | DST.PORT |
+----+-----+-------+------+----------+----------+
| 1 | 1 | X'00' | 1 | Variable | 2 |
+----+-----+-------+------+----------+----------+
其中:
- VER: 协议版本:
X'05'
- CMD: 命令
- CONNECT:
X'01'
- BIND:
X'02'
- UDP ASSOCIATE:
X'03'
- CONNECT:
- RSV: 保留字段 (
X'00'
) - ATYP: 后续地址的地址类型
- IP V4 地址:
X'01'
- 域名:
X'03'
- IP V6 地址:
X'04'
- IP V4 地址:
- DST.ADDR: 目标地址
- DST.PORT: 目标端口(网络字节序)
SOCKS 服务器通常根据源地址和目标地址评估请求,并根据请求类型返回一个或多个回复消息。
寻址
在地址字段(DST.ADDR,BND.ADDR)中,ATYP 字段指定了字段中包含的地址类型:
X'01'
: 地址是 IPv4 地址,长度为 4 个八位字节。X'03'
: 地址字段包含一个完全限定域名。地址字段的第一个八位字节包含后续名称的八位字节数,没有终止的 NUL 八位字节。X'04'
: 地址是 IPv6 地址,长度为 16 个八位字节。
回复
SOCKS 请求信息在客户端与 SOCKS 服务器建立连接并完成认证协商后立即发送。服务器评估请求并返回以下格式的回复:
+----+-----+-------+------+----------+----------+
|VER | REP | RSV | ATYP | BND.ADDR | BND.PORT |
+----+-----+-------+------+----------+----------+
| 1 | 1 | X'00' | 1 | Variable | 2 |
+----+-----+-------+------+----------+----------+
其中:
- VER: 协议版本:
X'05'
- REP: 回复字段:
X'00'
:成功X'01'
:SOCKS 服务器通用故障X'02'
:规则集不允许连接X'03'
:网络不可达X'04'
:主机不可达X'05'
:连接被拒绝X'06'
:TTL 过期X'07'
:不支持的命令X'08'
:不支持的地址类型X'09'
到X'FF'
:未分配
- RSV: 保留字段
- ATYP: 后续地址的地址类型(与请求中的 ATYP 相同)
- BND.ADDR: 服务器绑定的地址
- BND.PORT: 服务器绑定的端口(网络字节序)
标记为 RESERVED (RSV) 的字段必须设置为 X'00'
。如果选择的方法包含用于认证、完整性和/或保密性的封装,则回复将封装在方法依赖的封装中。
CONNECT 回复
在 CONNECT 的回复中,BND.PORT 包含服务器分配的用于连接到目标主机的端口号,而 BND.ADDR 包含关联的 IP 地址。提供的 BND.ADDR 通常与客户端用于访问 SOCKS 服务器的 IP 地址不同,因为此类服务器通常是多宿主的。SOCKS 服务器预期会使用 DST.ADDR 和 DST.PORT 以及客户端源地址和端口来评估 CONNECT 请求。
BIND 回复
BIND 请求用于需要客户端接受来自服务器连接的协议(例如 FTP)。在 BIND 操作期间,SOCKS 服务器会向客户端发送两次回复。第一次回复在服务器创建并绑定新套接字后发送,包含 SOCKS 服务器分配给监听传入连接的端口号 (BND.PORT) 和关联的 IP 地址 (BND.ADDR)。客户端通常会使用这些信息来通知(通过主连接或控制连接)应用程序服务器会合地址。第二次回复仅在预期的传入连接成功或失败后发生,包含连接主机的地址和端口号。
UDP ASSOCIATE 回复
UDP ASSOCIATE 请求用于在 UDP 中继进程中建立关联,以处理 UDP 数据报。DST.ADDR 和 DST.PORT 字段包含客户端预期用于发送 UDP 数据报的地址和端口。服务器可以使用此信息限制对关联的访问。如果在 UDP ASSOCIATE 时客户端没有这些信息,则客户端必须使用全零的端口号和地址。
当发送 UDP ASSOCIATE 请求的 TCP 连接终止时,UDP 关联也终止。在 UDP ASSOCIATE 请求的回复中,BND.PORT 和 BND.ADDR 字段指示客户端必须将 UDP 请求消息发送到哪个端口号/地址才能进行中继。
回复处理
当回复(REP 值不是 X'00'
)表示失败时,SOCKS 服务器必须在发送回复后不久终止 TCP 连接。这必须在检测到导致失败的条件后不超过 10 秒内完成。
如果回复码(REP 值为 X'00'
)表示成功,并且请求是 BIND 或 CONNECT,客户端现在可以开始传输数据。如果选择的认证方法支持用于完整性、认证和/或保密性的封装,则数据将使用方法依赖的封装进行封装。类似地,当数据到达 SOCKS 服务器以供客户端使用时,服务器必须根据正在使用的认证方法对数据进行封装。
基于 UDP 客户端的流程
基于 UDP 的客户端必须将其数据报发送到 UDP 中继服务器,端口由 UDP ASSOCIATE 请求的回复中的 BND.PORT 指示。如果选择的认证方法提供用于认证、完整性和/或保密性的封装,则数据报必须使用适当的封装进行封装。每个 UDP 数据报都带有以下 UDP 请求头:
+----+------+------+----------+----------+----------+
|RSV | FRAG | ATYP | DST.ADDR | DST.PORT | DATA |
+----+------+------+----------+----------+----------+
| 2 | 1 | 1 | Variable | 2 | Variable |
+----+------+------+----------+----------+----------+
UDP 请求头中的字段是:
- RSV: 保留
X'0000'
- FRAG: 当前分片号。如果实现,高位表示分片序列的结束,而
X'00'
值表示此数据报是独立的。1 到 127 之间的值表示分片序列中的分片位置。 - ATYP: 后续地址的地址类型(与请求中的 ATYP 相同)
- DST.ADDR: 目标地址
- DST.PORT: 目标端口
- DATA: 用户数据
当 UDP 中继服务器决定中继 UDP 数据报时,它会静默进行,不会向请求客户端发送任何通知。同样,它将丢弃无法或不愿中继的数据报。当 UDP 中继服务器从远程主机收到回复数据报时,它必须使用上述 UDP 请求头和任何认证方法依赖的封装来封装该数据报。
UDP 中继服务器必须从 SOCKS 服务器获取将向 UDP ASSOCIATE 回复中给出的 BND.PORT 发送数据报的客户端的预期 IP 地址。它必须丢弃来自与该特定关联记录的源 IP 地址不同的任何源 IP 地址的数据报。
FRAG 字段表示此数据报是否是多个分片中的一个。每个接收器将有一个关联的重组队列和重组计时器。当重组计时器到期,或者收到一个 FRAG 字段值小于此分片序列已处理的最高 FRAG 值的新数据报时,必须重新初始化重组队列并放弃关联的分片。重组计时器必须不小于 5 秒。建议应用程序尽可能避免分片。
分片的实现是可选的;不支持分片的实现必须丢弃任何 FRAG 字段不是 X'00'
的数据报。
SOCKS-aware UDP 的编程接口必须报告一个小于操作系统提供的实际空间的 UDP 数据报可用缓冲区空间:
- 如果 ATYP 是
X'01'
:小 10 + 方法依赖八位字节 - 如果 ATYP 是
X'03'
:小 262 + 方法依赖八位字节 - 如果 ATYP 是
X'04'
:小 20 + 方法依赖八位字节
安全考虑
本文件描述了 IP 网络防火墙应用层穿越的协议。这种穿越的安全性高度依赖于特定实现中提供的、以及 SOCKS 客户端和 SOCKS 服务器之间协商选择的特定认证和封装方法。管理员应仔细考虑认证方法的选择。