仓库源文站点原文


key: 37 title: "[翻译] RFC 1928: SOCKS 协议第 5 版"

tag: translations

socks5 是一个常用的代理协议, 它既可以用来代理 TCP, 也可以代理 UDP. socks5 的用途非常广泛, 许多网络软件都支持 socks5, 主流操作系统也支持使用 socks5 作系统代理. RFC 1928 是 socks5 协议的规范文档, 本文是对 RFC 1928 的翻译. 原文见 RFC 1928 - SOCKS Protocol Version 5. 以下是翻译正文:

文档声明

本文档为互联网社区规范了一个互联网标准跟踪的协议, 并征求讨论和改进建议. 请参阅当前版本的 "互联网官方协议标准(STD 1)" 以获取此协议的标准化的状态. 本文档的发布不受限制.

致谢

本文描述的协议是其之前版本 (第 4 版) [1] 的升级版. 该协议离不开积极的讨论和原型的实现, 这其中主要的贡献者有: Marcus Leech: 贝尔北方研究中心, David Koblas: 独立顾问, Ying-Da Lee: NEC 系统实验室, LaMont Jones: 惠普公司, Ron Kuris: Unify 公司, Matt Ganis: IBM 公司.

1. 介绍

防火墙的使用变得越来越流行, 它可以有效地将组织内部网络与外部网络 (如因特网) 隔离. 这些防火墙系统通常充当网络这间的应用层网关, 通常提供 telnet, FTP 和 SMTP 的访问控制. 随着被设计成促进全球信息发现(global information discovery)的更复杂的应用层协议的出现, 我们需要一种通用的框架, 让这些协议可以透明安全地穿越防火墙.

此外, 我们还需要一种可操作的细粒度的方式对这种穿越防火墙的行为进行强认证. 这需要意识到, 客户端-服务器关系会出现在各种组织的网络之间, 并且这种关系需要受到控制并经常经过严格的身份验证.

本文描述的协议旨在为 TCP 和 UDP 域中的客户端-服务器应用程序提供一个框架,以方便安全地使用网络防火墙的服务. 该协议在概念上是应用层和传输层之间的 "中介层", 因此无法提供网络层的网关服务, 例如转发 ICMP 消息.

2. 现有的实践

目前已有一个第 4 版的 SOCKS 协议, 可以为基于 TCP 的客户端-服务器应用提供非安全的防火墙穿透服务, 这其中包括 telnet, FTP 和一些流行的信息发现协议(information-discovery protocol)例如 HTTP, WAIS 和 GOPHER.

新协议将第 4 版 SOCKS 协议模型扩展为包括 UDP, 并扩展其框架使其包含通用强身份验证方案的规范, 此外寻址方案也扩展为包含域名和 IPv6.

SOCKS 协议的实现通常涉及到重新编译或重新链接基于 TCP 的客户端应用程序, 以使用 SOCKS 库中合适的封装例程.

注意:

除非另有说明, 出现在数据包格式图中的十进制数表示对应字段的长度, 单位为八位字节. 当一个给定的字节必须为一个特定的值时, 使用 X'hh' 的格式表示该字段中单字节的值. 当用到 "Variable" 一词时, 表示对应字段的长度是由相应的长度字段 (一到两字节) 或数据类型字段所定义的可变长度.

3. 基于 TCP 客户端的过程

当一个基于 TCP 的客户端想要与一个必须经由防火墙才能连接 (取决于实现) 的对象建立连接时, 它必须在适当的端口开启一条到 SOCKS 服务器系统的 TCP 连接. SOCKS 服务通常使用 TCP 的 1080 端口. 如果连接请求成功, 客户端会进入协商阶段以协商认证方法, 然后使用所选的方法进行认证, 接着发送相应的请求. SOCKS 服务器会评估请求, 然后建立适当的连接或拒绝它.

除非另有说明, 出现在数据包格式图中的十进制数表示对应字段的长度, 单位为八位字节. 当一个给定的字节必须为一个特定的值时, 使用 X'hh' 的格式表示该字段中单字节的值. 当用到 "Variable" 一词时, 表示对应字段的长度是由相应的长度字段 (一到两字节) 或数据类型字段所定义的可变长度.

译注: 原文如此, 不知为何又重复了一段, 很奇怪.

客户端连接服务器, 然后发送一条包含版本号和方法选择的消息:

VER NMETHODS METHODS
1 1 1 至 255

VER 字段在这个版本置为 X'05'. NMETHODS 字段包含出现在 METHODS 字段中的方法标识符的字节数.

服务器从 METHODS 字段中给出的方法中选择一个, 将其放在返回给客户端消息的 METHOD 字段中:

VER METHOD
1 1

如果 METHOD 字段标识选择的方法为 X'FF', 则客户端列出的方法均不被服务器接受, 此时客户端必须关闭连接.

目前已定义的方法有:

然后客户端和服务器会进入认证方法所规定的子协商过程(sub-negotiation).

依赖于具体方法的子协商过程的描述可以在其它对应的文档中找到.

为此协议提供新方法支持的开发人员应与 IANA 联系以获取 METHOD 编号. 有关方法编号及其相应协议的最新列表, 请参考 ASSIGNED NUMBERS 文档.

符合规范的实现必须支持 GSSAPI 方法, 且应该支持 用户名/密码 认证方法.

4. 请求

一旦依赖于具体方法的子协商过程完成, 客户端就开始发送请求详情. 如果出于完整性检查或机密性的目的, 协商的方法包括封装, 则这些请求必须按照该方法所定义的方式进行封装.

SOCKS 请求的格式如下

VER CMD RSV ATYP DST.ADDR DST.PORT
1 1 X'00' 1 Variable 2

其中:

SOCKS 服务器通常会根据源地址和目标地址来评估请求, 然后根据请求类型适当地返回一个或多个应答消息.

5. 地址

对于地址字段 (DST.ADDR, BND.ADDR), 由 ATYP 字段指定其包含的地址类型:

6. 应答

客户端与 SOCKS 服务器建立连接并完成身份验证协商后, 客户端就会开始发送 SOCKS 请求信息. 服务器会评估请求, 并返回如下格式的应答消息:

VER REP RSV ATYP BND.ADDR BND.PORT
1 1 X'00' 1 Variable 2

其中:

标记为 "保留" 的字段必须置为 X'00'

如果协商的方法出于完整性或机密性的目的, 包含封装, 则应答需按照该方法所定义的方式进行封装.

CONNECT 请求

如果应答的是 CONNECT 请求, 则 BND.PORT 需包含服务器连接目标主机所用的端口号, BND.ADDR 包含相应的 IP 地址. 这里的 BND.ADDR 常常不同于客户端访问的 SOCKS 服务器的地址, 因为服务器常常是分布式部署的. 服务器通常会使用 DST.ADDRDST.PORT, 以及客户端的源地址和端口, 来评估 CONNECT 请求.

BIND 请求

BIND 请求会在需要客户端接受来自服务器连接的协议中使用. FTP 就是一个典型的例子, 它使用客户端到服务器的主连接来发送命令和状态报告, 但可以使用服务器到客户端的连接来按需传递数据 (e.g. LS, GET, PUT).

它期望客户端使用的应用层协议只有在使用 CONNECT 请求建立完主连接后, 才使用 BIND 请求建立次连接. SOCKS 服务器会使用 DST.ADDRDST.PORT 来评估 BIND 请求.

在 BIND 请求中会有两条应答消息从 SOCKS 服务器发往客户端. 第一条会在服务器创建并绑定一个套接字后发送. BND.PORT 字段包含 SOCKS 服务器为监听传入连接分配的端口号. BND.ADDR 字段则包含相应的 IP 地址. 客户端通常会将这些信息 (通过主连接或者说控制连接) 通知给目标地址的应用服务器. 第二条应答消息则只会在期待的传入连接成功或失败后发送.

在第二条应答消息中, BND.PORTBND.ADDR 字段包含连上来的主机的 IP 地址和端口号.

UDP ASSOCIATE 请求

UDP ASSOCIATE 请求用于在 UDP 中继进程内建立关联以处理 UDP 数据报. 其中的 DST.ADDRDST.PORT 字段包含客户端用于在关联上发送 UDP 数据报的地址和端口号. 服务器可能根据这些信息限制关联的访问. 如果客户端在 UDP ASSOCIATE 时还没有这些信息,则客户端必须将端口号和地址字段置为零.

当发送 UDP ASSOCIATE 请求的 TCP 连接终止时, UDP 关联终止.

在 UDP ASSOCIATE 请求的应答中, BND.PORTBND.ADDR 字段指示客户端发送 UDP 请求到中继服务器的端口和地址.

应答的处理

当一个应答消息指示出错 (REP 字段不为 X'00') 时, SOCKS 服务器应在发送完这条应答消息后的一小段时间内关闭连接. 这不应该超过检测到错误发生后的 10 秒.

如果应答码指示成功 (REP 字段为 X'00'), 且请求为 BIND 或 CONNECT, 那么客户端就可以开始传送数据了. 如果使用的认证方法出于完整性, 身份验证或机密性的目的支持封装, 则应使用认证方法要求的封装方式封装数据. 同样地, 当需要发给客户端的数据到达服务器时, 服务器也必须使用相应的封装方式封装数据.

7. 基于 UDP 客户端的过程

基于 UDP 的客户端必须把数据报发送到 UDP 中继服务器的某个 UDP 端口中, 端口由 UDP ASSOCIATE 请求的应答中的 BND.PORT 字段指定. 如果使用的认证方法出于真实性, 完整性或机密性的目的提供了封装, 则必须使用相应的封装方式封装数据. 每个 UDP 数据报都带有一个如下的 UDP 请求头:

RSV FRAG ATYP DST.ADDR DST.PORT DATA
2 1 1 Variable 2 Variable

UDP 请求头中的字段分别为:

当 UDP 中继服务器要转发 UDP 数据报时, 它会静默转发, 不会给请求的客户端发送任何通知. 同样地, 它会丢弃无法或不会中继的数据报. 当 UDP 中继服务器接收到来自远程主机的应答数据报时, 它必须将数据报封装在上述的 UDP 请求头以及认证方法依赖的封装中.

UDP 中继服务器必须从 SOCKS 服务器获取预期的客户端 IP, 客户端则会给 UDP ASSOCIATE 请求答复中的 BND.PORT 字段给出的端口发送数据报. 中继服务器必须丢弃所有来自非特定关联的 IP 地址的数据报.

FRAG 字段表示该数据报是否是一组分段中的一个. 如果实现 (了分段功能), 则高位比特指示分段序列的结尾, 而值 X'00' 表示数据报是独立的. 1 至 127 之间的值表示该分段在分段序列中的位置. 接收方会使用重组队列重组计时器关联这些分段. 每当重组计时器超时, 或者一个新到达的数据报的 FRAG 字段的值小于该重组序列中出现过的最大的 FRAG 值时, 重组队列都必须重新初始化并丢弃相应的分段. 重组计时器不得小于 5 秒. 建议应用尽可能地避免使用分段.

分段的实现是可选的; 不支持分段的实现必须丢弃任何 FRAG 字段不为 X'00' 的数据报.

能够识别 SOCKS 的 UDP 的编程接口必须报告 UDP 数据报的可用缓冲区空间,该缓冲区空间小于操作系统提供的实际空间:

8. 安全考虑

本文档描述了一个让应用层穿越 IP 网络防火墙的协议. 这种穿越的安全性高度依赖于特定实现中提供的特定认证方法和封装, 它们是在 SOCKS 客户端和 SOCKS 服务器在协商过程中选择的.

管理员应当仔细考虑身份验证方法的选择.

9. 参考

[1] Koblas, D., "SOCKS", Proceedings: 1992 Usenix Security Symposium.

作者的地址

Marcus Leech<br> 贝尔北方研究有限公司<br> P.O. Box 3511, Stn. C,<br> 安大略省, 渥太华<br> 加拿大 K1Y 4H7<br>

电话: (613) 763-9145<br> 邮箱: mleech@bnr.ca