SOCKS:用于穿越防火墙的TCP代理协议

Ying-Da Lee
NEC 系统实验室主要的技术负责人,CSTC
ylee@syl.dl.nec.com

SOCKS最初由David Koblas开发并且后来被我改进成当前正在运行的版本—版本4。它用于一台安装了防火墙主机上使得用户应用协议可以透明的穿过防火墙。因为这个协议决定于应用协议,所以它能够(已经)用于很多的服务,如telnet,ftp,finger,whois,gopher,WWW等等。在TCP协议的开始阶段可以使用访问控制;其后服务只能在客户端和应用服务器之间传递数据,这样就可以是传输消耗降到最小。因为SOCKS更本不需要知道任何应用协议本身,所以他可以很容易的提供加密功能,使得消息在有监控者的信道中能安全的传输。

SCOKS定义了两个操作:CONNECT和BIND。

1)  CONNECT

客户端会和SOCKS服务器建立连接并且当它想和应用服务器建立连接时会发送一个CONNECT请求。客户端的请求包中有目的主机的IP地址,端口号码,和userid(译者注:作为一个特殊的名称没有翻译)。包格式如下:

            +----+----+----+----+----+----+----+----+----+----+....+----+
             | VN | CD | DSTPORT |      DSTIP        | USERID       |NULL|
            +----+----+----+----+----+----+----+----+----+----+....+----+
各段为: 1     1              3                    4               长度可变        1

VN表示SCOKS协议的版本号码,在本版本是应该为4。CD表示SOCKS的命令码,CONNECT命令为1。NULL是所有bit都为0的一个字节。

SCOKS服务器会通过检查一个由源IP地址,目的IP地址,目的端口号码,userid,和被包含在经过商议的IDENT中的信息所组成的联合标识符(比较RFC1413)来确定请求是否被允许。如果请求通过,则SCOKS会建立一个和目的主机端口的连接。当和目的主机的链接被建立,或请求被拒绝,或操作失败时,会给客户端返回一个包。如下

            +----+----+----+----+----+----+----+----+
             | VN | CD | DSTPORT |      DSTIP        |
            +----+----+----+----+----+----+----+----+
各段为  1       1            2                       2

VN是返回的版本编码,这里为0。CD是表示下列结果之一的编码:

90: 请求被接受
91: 请求被拒绝或者失败了
92: 请求被拒绝因为不能和客户端提供的IDENT建立连接。
93: 请求被拒绝因为客户端和IDENT代表了两个不同的用户。

剩下的部分被忽略了。

在SCOKS服务器告诉客户端请求被拒绝或失败后,会马上关闭连接。对于一个成功的请求,SCOKS服务器会准备在两个方向传递信息。这样可以使客户端像直接连上了应用服务器一样进行I/O操作。

2)  BIND

当客户端准备接收来自应用服务器的连接时,它会像SCOKS服务器附送一个BIND请求。这会发生在和应用服务器的主要连接被CONNECT建立后。往往,这个部分按顺序会有以下的步骤:

-bind(): 获得一个套接字
-getsockname(): 得到套接字中的IP地址和端口号码
-listen(): 准备接受来自应用服务器的连接。
-使用主连接告诉应用服务器连接的IP地址和端口号码。
-accept(): 接收来自应用服务器的链接。

使用SCOKS的BIND操作的只要目的是为了支持这样一个顺序,套接字在SCOKS服务器上使用,而不是在客户端上。

客户端的请求包中有应用服务器的IP地址,主连接使用的目的端口号,和userid。

            +----+----+----+----+----+----+----+----+----+----+....+----+
             | VN | CD | DSTPORT |      DSTIP        | USERID       |NULL|
            +----+----+----+----+----+----+----+----+----+----+....+----+
各段为:1      1              2                       4             长度可变      1

VN是4,表示SCOKS协议的版本。CD一定是2,代表这是BIND请求。

SCOKS服务器使用客户端信息确定请求是否被接受。服务器返回给客户端的包的格式和CONNECT请求的返回包一样,如,

            +----+----+----+----+----+----+----+----+
             | VN | CD | DSTPORT |      DSTIP        |
            +----+----+----+----+----+----+----+----+
各段为:1      1               2                          4

VN是返回的版本编码,这里为0。CD是表示下列结果之一的编码:

90: 请求被接受
91: 请求被拒绝或者失败了
92: 请求被拒绝因为不能和客户端提供的IDENT建立连接。
93: 请求被拒绝因为客户端和IDENT代表了两个不同的用户。

无论如何,对于一个被接受的请求(CD是90),DSTPORT和DSTIP域是有意义的。那样的话,SCOKS服务器会等待一个进入的连接,并把套接字中的端口号和IP地址分别放到DSTPORT和DSTIP中发送给客户端。如果返回的DSIP是0(常量INADDR_ANY的值),则客户端会用连接着的SOCKS服务器的IP地址替换它。(这个仅会发生在SOCKS服务器不是多用户主机的情况) 典型的情况是,同时有两个以上的应用程序需要经由服务器而导致getsockname()的并发调用。应用协议应当提供一种将两种不同信息从客户端发送到服务器的方法,使得它可以初始化与SCOKS服务器的连接,而不是像平时一样和应用服务器的连接。

当来自应用服务器的预期连接被建立后,SCOKS服务器会返回第二个包给客户端。SOCKS服务器检查源主机的IP地址,并与客户端的BIND请求的DSIP域比较。如果双方不匹配,第二个返回包中的CD域会被设置为91并且SOCKS服务器会关闭和两边连接。如果匹配的话,返回包的CD域会被设置为90,并且SCOKS服务器将在它的两个连接间传递信息。从这以后,客户端就可以和SCOKS服务器进行I/O操作,就好象直接连上了应用服务器。

对于CONNECT和BIND操作,服务器都为建立连接设置了时间限制(当前的CSTC实现将时限设为2分钟)。如果时限到了后连接还没有建立,服务器会关闭和客户端的连接并且放弃。


SOCKS 4A:SCOKS 4协议的简单扩展

Ying-Da Lee
yingda@best.com  or  yingda@esd.sgi.com

请首先阅读描述4号协议版本的SOCKS4.protocol。这个扩展允许没有能力解析所有域名的主机使用SCOKS。

在版本4中,客户端会发送如下的包给服务器,请求CONNECT或者BIND操作。

           +----+----+----+----+----+----+----+----+----+----+....+----+
            | VN | CD | DSTPORT |      DSTIP        | USERID       |NULL|
           +----+----+----+----+----+----+----+----+----+----+....+----+
各段为   1      1               3                      4            长度可变        1

VN是SCOKS协议的版本号,在这个版本中为4.CD是请求命令的代码,1代表CONNECT命令,2代表BIND命令。NULL是所有bit都为0的一个字节。

对于版本4,如果客户端不能把目的主机的域名解析成IP地址。那么它会将DSIP的前3个字节设置为空并将最后一个字节设置成一个不为0的值。(这样的IP地址符合I0.0.0.x的形式,它被IAIN(互联网数字权威分配组织)认为是一个不被接受的目的地址,因此就不会发生客户端无法解析主机域名的情况了)紧跟着的userid后面有一个空字节作为结束,客户端必须发送目的域名并以一个空字符结束它。这个方法用于CONNECT和BIND操作。
一个使用SCOKS4协议的服务器必须检查请求包的DSIP域。如果地址是0.0.0.x,x不为0的形式,服务器必须降包中的userid域读出。如果服务器可以的话,它将解析域名并与目的主机建立连接。

服务器中继程序可以将它不能解析的域名传送给下一跳的SCOKS服务器。