2019独角兽企业重金招聘Python工程师标准>>>
介绍
网络防火墙可以将组织的内部网络与外部网络(如 Internet)中有效地隔离开。网络防火墙的使用日益广泛。防火墙通常以应用层网关的形式工作在内外网络之间,提供 TELNET、FTP、SMTP 访问。随着越来越多的应用层协议被设计出来以实现全球范围内的信息交流,有必要提供一种通用的框架来使这些协议安全透明地穿过防火墙。而且,在实际应用中,安全的认证方式也是必要的。这个要求起源于不同网络中客户/服务器关系的出现,这个关系需要得到控制并要求有安全的认证。
这个协议设计的目的是为了让使用 TCP/UDP 的应用程序更方便、安全地使用防火墙所提供的服务。从概念上讲,这个协议是介于应用层和传输层之间的中介层(shim-layer),因此不提供 ICMP 转发等由网络层网关提供的服务。
现有的协议
现有的协议为 SOCKS4 协议,它为 TELNET、FTP、HTTP、WAIS 和 GOPHER 等基于 TCP 的应用程序提供了不安全的防火墙服务。
新的协议扩展了 SOCKS4 协议,以支持 UDP、安全认证和新的地址协议(域名解析和 IPv6 地址)。
为了实现这个 SOCKS 协议,基于 TCP 的应用程序通常需要重新编译或者重新链接以使用 SOCKS 库中相应的封装函数。
注意:
除非特别注明,所有出现在数据包格式图中的十进制数字均是相应域的长度(以字节为单位)。如果一个域为一个字节,用 X'hh' 的形式来表示这个字节的值。如果某个域为“Variable”,这表示该域的长度是不定的,并且长度定义在一个和这个域相关联(1 – 2 个字节)的域中,或一个数据类型域中。
基于 TCP 协议的客户端
当一个基于 TCP 协议的客户端希望通过防火墙来和一个目标建立连接,它必须与 SOCKS 服务器上的 SOCKS 端口建立一个 TCP 连接。SOCKS 服务通常使用的 TCP 端口号是 1080。连接成功后,客户端进入协议的“协商(negotiation)”阶段:选择认证方式,根据所选的方式进行认证,然后发送请求。SOCKS 服务器检查这个请求,或建立合适的连接,或拒绝这个请求。
客户端连接到服务器后,发送请求来协商协议版本和认证方法:
VER | NMETHODS | METHODS |
---|---|---|
1 | 1 | 1 - 255 |
在这个版本的 SOCKS 协议中,VER 字段被设置为 X'05'。NMETHODS 字段包含了 METHODS 字段中认证方法的个数(以字节为单位)。
服务器从 METHODS 中给定的认证方法中选择一个,然后发送一个 METHOD 选择响应:
VER | NMETHODS |
---|---|
1 | 1 |
如果选中的 METHOD 是 X'FF',表示客户端提供的所有认证方法都不支持,客户端必须断开连接。
当前定义 METHOD 如下:
- X'00' 不需要认证
- X'01' GSSAPI
- X'02' 用户名/密码
- X'03' - X'7F' 由IANA分配
- X'80' to X'FE' 为私人方法所保留的
- X'FF' 没有可以接受的方法
然后客户和服务器进入由选定认证方法所决定的子协商过程(sub-negotiation)。不同认证方法的子协商过程请参考各自的备忘录。
开发者如果要为自己的新认证方法得到一个方法号,可以联系 IANA。可以参考关于已经被分配号码的文档以得到当前所有方法的列表和相应的协议。
符合本文档的 SOCKS5 实现必须支持 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'
-
- UPD ASSOCIATE X'03'
- RSV 保留
- ATYP 地址类型
-
- IPv4 地址 X'01'
-
- 域名 X'03'
-
- IPv6 地址 X'04'
- DST.ADDR 目的地址
- DST.PORT 目的端口号(网络字节序)
SOCKS 服务器根据源地址和目的地址来分析请求,然后根据请求类型返回一个或多个应答。
地址
ATYP 字段描述了地址字段(DST.ADDR,BND.ADDR)所包含的地址类型:
- X'01' IPv4 地址,4 个字节
- X'03' 域名,地址字段中的第 1 个字节是该域名的长度(以字节为单位),结尾没有 NUL 字符
- X'04' IPv6 地址,16 个字节
应答
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 地址类型
-
- IPv4 地址 X'01'
-
- 域名 X'03'
-
- IPv6 地址 X'04'
- BND.ADDR 服务器绑定的地址
- 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 ASSOCIATE
UDP ASSOCIATE 请求通常是要求建立一个 UDP 中继来处理到来的 UDP 数据包。DST.ADDR 和 DST.PORT 字段包含客户端所希望用来发送 UDP 数据包的 IP 地址和端口号。服务器可以使用这个信息来限制进入的连接。如果客户端在发送这个请求时没有地址和端口信息,客户端必须用全 0 来填充。
当与 UDP 相对应的 TCP 连接中断时,该 UDP 连接也必须中断。
应答 UDP ASSOCIATE 请求时,BND.PORT 和 BND.ADDR 字段指明了客户端发送 UDP 数据包时的目的端口和目的地址。
应答处理
当一个应答(REP 值不等于 X'00')表明有错误发生时,SOCKS 服务器必须在发送完应答消息后一小段时间内终止 TCP 连接。这段时间应该在发现错误后少于 10 秒。
如果一个应答(REP 值等于 X'00')表明成功,并且请求是 BIND 或 CONNECT 时,客户端就可以开始发送数据了。如果协商的认证方法中有以完整性、认证、安全为目的的封装,这些数据必须按照该方法所定义的方式进行封装。类似的,当以客户机为目的地的数据到达 SOCKS 服务器时,SOCKS 服务器必须用正在使用的方法对这些数据进行封装。
基于UDP协议的客户
UDP ASSOCIATE 应答中 BND.PORT 指明了服务器所使用的 UDP 端口,一个基于 UDP 协议的客户必须发送数据报到服务器的该端口上。如果协商的认证方法中有以完整性、认证、安全为目的的封装,这些数据报必须按照该方法所定义的方式进行封装。每个UDP数据报都有一个 UDP 请求头在其首部:
RSV | FRAG | ATYP | DST.ADDR | DST.PORT | DATA |
---|---|---|---|---|---|
2 | 1 | 1 | Variable | 2 | Variable |
其中:
- RSV 保留
- FRAG 当前的分段号
- ATYP 地址类型
-
- IPv4 地址 X'01'
-
- 域名 X'03'
-
- IPv6 地址 X'04'
- DST.ADDR 目的地址
- DST.PORT 目的端口号(网络字节序)
- DATA 用户数据
当 UDP 中继服务器转发一个 UDP 数据报时,不会向客户端发送任何通知。同样,不能转发的数据报将被直接丢弃。当 UDP 中继服务器从远程主机收到一个响应数据报时,也必须加上上述 UDP 请求头,并对数据报进行封装。
客户端向 UDP ASSOCIATE 应答中给定的端口号发送数据报时,所用的 IP 地址必须由 SOCKS 服务器告知 UDP 中继服务器。来自其他 IP 地址的数据报将会被丢弃。
FRAG 字段指明数据报是否是一组分片中的一片。如果 SOCKS 服务器要实现这个功能,X'00' 表示数据报是独立的,其他的值则越大越是数据报组的尾端。介于 1 到 127 之间的值说明了该分片在分片序列里的位置。每个接收者都为这些分片提供一个重组队列和一个重组的计时器。这个重组队列必须在重组计时器超时后重新初始化,并丢弃相应的数据报。或者当一个新到达的数据报有一个比当前在处理的数据报序列中最大的 FRAG 值要小时,也必须重新初始化从组队列。重组计时器必须小于5秒。只要有可能,应用程序最好不要使用分片。
分片的实现是可选的,如果某实现不支持分片,所有 FRAG 字段不为 0 的数据报都必须被丢弃。
支持 SOCKS 的 UDP 编程接口必须报告当前可用 UDP 数据报缓存空间小于操作系统提供的实际空间:
- ATYP 为 X'01' 比实际空间小 10 + 认证方法相关的字节数
- ATYP 为 X'03' 比实际空间小 262 + 认证方法相关字节数
- ATYP 为 X'04' 比实际空间小 20 + 认证方法相关字节数
安全性考虑
这篇文档描述了一个用来透过 IP 网络防火墙的应用层协议。这种传输的安全性在很大程度上依赖于特定实现所拥有以及在 SOCKS 客户端与 SOCKS 服务器之间经协商所选定的特殊的认证和封装方式。
系统管理员需要对用户认证方式的选择进行仔细考虑。
参考书目
[1] Koblas, D., “SOCKS”, Proceedings: 1992 Usenix Security Symposium.