Network Working Group                                           M. Leech
Request for Comments: 1928                    Bell-Northern Research Ltd
Category: Standards Track                                       M. Ganis
                                         International Business Machines
                                                                  Y. Lee
                                                  NEC Systems Laboratory
                                                                R. Kuris
                                                       Unify Corporation
                                                               D. Koblas
                                                  Independent Consultant
                                                                L. Jones
                                                 Hewlett-Packard Company
                                                              March 1996

SCOKS协议5

备忘录地位

本标准为Internet网详细说明了一份架构委员会的标准轨迹协议,并且要求讨论和建议以便进一步的改进。请关注最新的用于陈述标准化协议的的文件"IAB Official Protocol Standards"(STD1)。本备忘录的发行无任何限制。

感谢

这份备忘录详细描述了一个由早先的版本(版本4[1])演化来的协议。新协议起源积极的讨论和一些早先版本的实现。关键的投稿人有:Marcus Leech: 贝尔北方研究所, David Koblas:独立研究者, Ying-Da Lee: NEC 系统实验室, LaMont Jones: Hewlett-Packard 公司, Ron Kuris: Unify 有限公司, Matt Ganis: IBM公司。

介绍

使用网络防火墙将一个组织内部的网络结构和外部网络隔开,这种方法在因特网上正变得日益流行。这些防火墙系统常常以应用层网关的形式工作在网络之间,一般提供对TELNET, FTP, 和 SMTP的访问控制。随着越来越多促进全球信息化的应用协议的出现,有必要提供一个框架使得应用协议可以透明并秘密的穿越防火墙。

而且在实际应用中还需要一种安全的认证方式用以穿越防火墙。这种要求起源于不同组织的网络间客户端/服务器关系的出现,这种关系常常需要得到控制并要求有安全的认证。

在这儿所描述的协议框架是为了让使用TCP和UDP的客户/服务器应用程序更方便安全地使用网络防火墙提供的服务而设计的。这个协议从概念上来讲是介于应用层和传输层之间的“中介层(shim-layer)”,因而不提供如ICMP信息之类由网络层网关的提供的服务。

现有的成果

当前存在一个协议SOCKS 4,它为TELNET、FTP、HTTP、WAIS和GOPHER等基于TCP协议的客户/服务器程序提供不安全的防火墙穿越策略。

新协议扩展了SCOKS4的模型使它可以用于UDP协议,扩展了一个框架使它可以提供一般意义上的强认证机制,扩展了寻址机制使它支持域名和IPV6。为了实现这个SOCKS协议,通常需要重新编译或者重新链接基于TCP的客户端应用程序以使用SOCKS库中相应的加密函数。

注意:

除非特别注明,所有出现在数据包格式图中的十进制数字均表示相应域的字节长度。如果一个给定的字节需要说明其值,则用X'hh'来表示这个字节的值。如果某域中用到单词'Variable',这表示该域的长度是可变的,且该域的长度定义在一个和这个域相关联(1–2个字节)的域中,或一个数据类型域中。

基于TCP连接的客户端程序

当一个基于TCP协议的客户端希望与一个只能通过防火墙才可以到达的目标(这是由实现所决定的)建立连接,它必须先建立一个与相应SOCKS服务器的SOCKS端口的TCP连接。通常这个TCP端口是1080。当连接建立后,客户端进入带有认证机制的“握手(negotiation)”过程,根据选中的认证方式进行认证,然后发送需要转发的请求。SOCKS服务器检查这个请求,根据结果,或建立合适的连接,或拒绝。

除非特别注明,所有出现在数据包格式图中的十进制数字均以字节表示相应域的长度。如果某域需要给定一个字节的值,用X'hh'来表示这个字节中的值。如果某域中用到单词'Variable',这表示该域的长度是可变的,且该长度定义在一个和这个域相关联(1–2个字节)的域中,或一个数据类型域中。

客户端连到服务器后,就发送一个版本标识符/方法选择消息:

+----+----------+----------+
|VER | NMETHODS | METHODS  |
+----+----------+----------+
| 1  |    1     | 1 to 255 |
+----+----------+----------+

这个版本的SOCKS协议中,VER字段被设置成X'05'。NMETHODS字段为METHODS字节字段的长度。

服务器从这些给定的方法中选择一个并发还给客户端:

+----+--------+
|VER | METHOD |
+----+--------+
| 1  |   1    |
+----+--------+

如果选中的方法是X'FF',这表示客户端所列出的方法列表中没有一个方法被选中,客户端必须关闭连接。

当前定义的方法有:

o  X'00' 不需要认证
o  X'01' GSSAPI
o  X'02' 用户名/密码
o  X'03'-X'7F' IANA 分配
o  X'80'-X'FE' 保留用作私人方法
o  X'FF' 没有可以接受的方法

然后客户和服务器进入由选定认证方法所决定的子协商过程(sub-negotiation)。各种不同的方法的子协商过程的描述请参考各自的备忘录。

开发者如果要为自己的方法得到一个方法号,可以联系IANA。可以参考关于已经被分配号码的文档以得到当前所有方法的列表和相应的协议。

符合本文档的SOCKS V5实现必须支持GSSAPI,并且在将来支持用户名/密码认证方式。

请求

一旦子协商过程结束后,客户端就发送详细的请求信息。如果协商的方法中有以完整性检查和/或安全性为目的的封装,这些请求必须按照该方法所定义的方式进行封装。

SOCKS请求的格式如下:

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

其中:

o  VER  协议版本: X'05'
o  CMD
o  CONNECT  X'01'
o  BIND  X'02'
o  UDP  交互 X'03'
o  RSV  保留字段
o  ATYP  后面的地址类型
o  IP V4 地址: X'01'
o  域名: X'03'
o  IP V6 地址: X'04'
o  DST.ADDR  目的地址
o  DST.PORT  以网络字节顺序出现的端口号

SOCKS服务器会根据源地址和目的地址来分析请求,然后根据请求类型返回一个或多个应答。

地址

ATYP字段中描述了地址字段(DST.ADDR,BND.ADDR)所包含的地址类型:

o  X'01'

这是IPV4的IP地址,4个字节长。

o  X'03'

这是域名的地址,地址字段中的第一字节是该域名的字节长度,没有结尾的NUL字节。

o  X'04'

这是基于IPV6的IP地址,16个字节长。

应答

一旦建立了一个到SOCKS服务器的连接,并且完成了认证协商,客户机将会发送一个SOCKS请求信息给服务器。服务器将会根据请求,以如下格式返回:

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

其中:

o  VER    协议版本: X'05'
o  REP    应答字段:
o  X'00' 成功
o  X'01' 普通的SCOKS服务器请求失败
o  X'02' 现有的规则不允许连接
o  X'03' 网络不可达
o  X'04' 主机不可达
o  X'05' 连接被拒绝
o  X'06' 连接超时
o  X'07' 命令不支持
o  X'08' 地址类型不支持
o  X'09' to X'FF' 未定义
o  RSV    保留
o  ATYP   后面的地址类型
o  IP V4 地址: X'01'
o  域名: X'03'
o  IP V6 地址: X'04'
o  BND.ADDR       服务器绑定的地址
o  BND.PORT       以网络字节顺序表示的服务器绑定的段口

标识为RSV的字段必须设为X'00'。

如果选中的方法中有以完整性检查和/或安全性为目的的封装,这些应答必须按照该方法所定义的方式进行封装。

CONNECT

在对一个CONNECT命令的应答中,BND.PORT包含了服务器分配的用来连到目标机的端口号,BND.ADDR则是相应的IP地址。由于SOCKS服务器通常有多个IP,应答中的BND.ADDR常和客户端连到SOCKS服务器的那个IP不同。SOCKS服务器可以利用DST.ADDR和DST.PORT,以及客户端源地址和端口来对一个CONNECT请求进行分析。

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地址和端口号。

UDP交换

请求通常是要求建立一个UDP转发进程来控制到来的UDP数据报。DST.ADDR和DST.PORT 字段包含客户端所希望的用来发送UDP数据报的IP地址和端口号。服务器可以使用这个信息来限制进入的连接。如果客户端在发送这个请求时没有地址和端口信息,客户端必须用全0来填充。

当与UDP相应的TCP连接中断时,该UDP连接也必须中断。

应答UDP 交互请求时,BND.PORT 和BND.ADDR字段指明了客户发送UDP消息至服务器的端口和地址。

应答处理

当一个应答(REP值不等于00)指明出错时,SOCKS服务器必须在发送完应答消息后一小段时间内终止TCP连接。这段时间应该在发现错误后10秒内。

如果一个应答(REP值等于00)指明成功,并且请求是一个BIND或CONNECT时,客户端就可以开始发送数据了。如果协商的认证方法中有以完整性、认证和/或安全性为目的的封装,这些请求必须按照该方法所定义的方式进行封装。类似的,当以客户端主机为目的地的数据到达SOCKS服务器时,SOCKS服务器必须用正在使用的方法对这些数据进行封装。

基于UDP连接的客户端程序

在UDP 交互应答中由BND.PORT指明了服务器所使用的UDP端口,一个基于UDP协议的客户端必须发送数据报至UDP转发服务器的该端口上。如果协商的认证方法中有以完整性、认证和/或安全性为目的的封装,这些数据报必须按照该方法所定义的方式进行封装。每个UDP数据报都有一个UDP请求头部在其首部

+----+------+------+----------+----------+----------+
|RSV | FRAG | ATYP | DST.ADDR | DST.PORT |   DATA   |
+----+------+------+----------+----------+----------+
| 2  |  1   |  1   | Variable |    2     | Variable |
+----+------+------+----------+----------+----------+

其中UDP头部为:

o  RSV  保留字段 X'0000'
o  FRAG   当前的分段号
o  ATYP    后面的地址类型:
o  IP V4 地址: X'01'
o  域名: X'03'
o  IP V6 地址: X'04'
o  DST.ADDR       目的地址
o  DST.PORT       目的端口
o  DATA     用户数据

当一个UDP转发服务器转发一个UDP数据报时,不会发送任何通知给客户端;同样,它也将丢弃任何它不能发至远端主机的数据报。当UDP转发服务器从远端服务器收到一个应答的数据报时,必须加上上述UDP请求头,并对数据报进行封装。

UDP转发服务器必须从SOCKS服务器得到期望的客户端IP地址,并将数据报发送到UDP ASSOCIATE应答中给定的端口号。如果数据报从任何IP地址到来,而该IP地址与该特定连接中指定的IP地址不同,那么该数据报会被丢弃。

FRAG字段指明数据报是否是一些分片中的一片。如果SOCKS服务器要实现这个功能,X'00'指明数据报是独立的;否则其越大越是接近数据报的尾端。介于1到127之间的值说明了该分片在分片序列里的位置。每个接收者都为这些分片提供一个重组队列和一个重组的计时器。这个重组队列必须在重组计时器超时后重新初始化,并丢弃相应的数据报。或者当一个新到达的数据报有一个比当前在处理的数据报序列中最大的FRAG值要小时,也必须重新初始化重组队列。重组计时器必须不小于5秒。只要有可能,应用程序最好不要使用分片。

分片的实现是可选的;如果某实现不支持分片,所有FRAG字段不为0的数据报都必须被丢弃。

一个SOCKS的UDP界面(The programming interface for a SOCKS-aware UDP)必须报告当前可用UDP数据报缓存空间小于操作系统提供的实际空间的情况。

o  如果 ATYP 是 X'01' - 10+method_dependent octets smaller
o  如果 ATYP 是X'03' - 262+method_dependent octets smaller
o  如果 ATYP 是X'04' - 20+method_dependent octets smaller
(译者注:这里可能会有问题)
安全性考虑

这篇文档描述了一个用来透过IP网络防火墙的应用层协议。这种传输的安全性在很大程度上依赖于特定的实现以及在SOCKS客户与SOCKS服务器之间经协商所选定的特殊的认证和封装方式。

系统管理员需要对用户认证方式的选择进行仔细考虑。

参考文献

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

作者地址:

Marcus Leech
Bell-Northern Research Ltd
P.O. Box 3511, Stn. C,
Ottawa, ON
CANADA K1Y 4H7

Phone: (613) 763-9145
EMail: mleech@bnr.ca