发信人: ifeelyou()
整理人: consultant(2000-09-30 14:26:31), 站内信件
|
这个问题应该分为两部分,一是如何调用防火墙外部方法(outgoing calls) ,一是如何调用防火墙内部的方法(incoming calls)。
1.通过防火墙调用外部方法。
通过防火墙调用外部方法,是指客户程序在防火墙之后的内部网上,而要调用 的远程方法在Internet上。主要有三种途径达到这个目的:HTTP隧道、SOCKS和下 载套接字代理。
HTTP隧道
这是一种比较老的方法,但是仍然比较流行,因为它几乎不需要什么设置。他 在允许通过代理服务器使用HTTP请求的环境中工作的很好,但是不支持一般的TC P连接。
如果RMI通过一般的连接(或SOCKS)到特定的服务器失败了,而且它发现已经配 置了HTTP代理服务器,那么它会通过“隧道”使RMI请求通过代理服务器。
有两种格式的HTTP隧道将会被依次尝试,首先是HTTP到端口,然后是HTTP到CG I。
在HTTP到端口的隧道方式中,RMI直接尝试到目的主机和目的端口的HTTP POST 请求,该HTTP POST请求包含单个的RMI请求。如果HTTP代理服务器接受了这个UR L,那么它会把该请求转发到正在侦听的RMI服务器,RMI服务器会识别该HTTP PO ST请求并把它解包成RMI请求。而结果会被包装成一个HTTP响应,通过代理服务器 返回。
通常代理服务器会拒绝任意的端口访问。在这种情况下,RMI会转换到HTTP到C GI隧道方式。就像上面那样,RMI请求会被先包装成HTTP POST请求,但该请求的 URL格式是form http://hostname:80/cgi-bin/java-rmi.cgi?port=n (其中hos tname和n使目的主机的名字和端口)。目的主机上必须要有一个在端口80侦听的 HTTP服务器,该服务器会运行java-rmi.cgi脚本(由JDK提供),该服务器会逐一 转发请求到RMI所侦听得端口n。RMI可以在不依靠HTTP服务器、CGI脚本或其他外 部实体的帮助下解包通过HTTP隧道传过来的RMI请求。因此,如果客户程序的代理 服务器可以直接连接到服务器端口,你就根本不需要java-rmi.cgi脚本。
为了触发对HTTP隧道的使用,标准的系统属性http.proxyHost必须被设置到本 地HTTP服务器的主机名。(据说某些Netscape用户不必设置该属性。)
HTTP隧道最大的缺点是不允许向内的请求和多元连接。第二个缺点是HTTP到CG I打开了服务器端的安全漏洞,因为不需要任何更改就可以重定向外来请求到任何 端口。
SOCKS
JDK中套接字的缺省实现是通过可用的配置过的SOCKS服务器。系统属性socksP roxyHost必须设置到本地SOCKS服务器的主机名;如果SOCKS服务器的端口号不是 1080的话,还要配置socksProxyPort属性。
这个方法看起来是最有用处的解决方案。但是至今ServerSockets仍然没有使用 SOCKS服务器,因此处理外来请求仍然需要其他的机制。
下载套接字代理(downloaded socket factoris)
这是JDK1.2Beta4的创新,允许服务器指定客户必须使用的套接字代理。客户端 必须运行在JDK1.2Beta4或更高版本下。此方法将在将来的某个时候译给大家(S orry!)。
这种方法的缺点是穿过代理服务器必须通过RMI服务器端提供的代码实现,它不 必知道穿过怎样被完成,而且它也没有自动获得足够的权限穿过防火墙。
2.通过本地防火墙接受外来RMI方法调用。
共有四种主要方法:已知端口、传输层桥、应用层代理和连接多路复用技术。
已知端口
如果输出的对象都在同一主机的同一端口输出,那么该主机和端口可以在防火 墙上明确许可。一般来说,RMI请求端口0(代表“任意端口”)。在JDK1.2中, exportObject方法用一个额外的参数指定端口号。在JDK1.1中,服务器必须子类 化RMISocketFactory并截取请求到createServerSocket(0),用指定到特定端口的 请求替换它。
这个方法的缺点是需要管理本地代理服务器的网络管理员的支持。如果输出的 对象正在别处的机器上运行(因为代码DL到该机器上),那么本地代理服务器的 管理员可能并不知道你是谁。
传输层桥
传输层桥是从一个TCP连接读取字节流并把他们写到另外的TCP连接的程序,这 个程序并不知道那些字节流代表什么。
这个想法是以这样的途径输出对象:任何想在防火墙外调用该对象的方法的客 户程序改为连接一个另外的端口(或许也是一台另外的主机),这个另外的端口 上运行着一个程序,该程序建立第二个连接到真正的服务器,然后把字节流像“ 泵”一样抽取过来。
技巧性的部分是使客户程序信任地连接到桥。可下载的套接字代理(download able socket factory)(JDK1.2)可以有效的完成这个任务;另外,可能需要设 置java.rmi.server.hostname属性来命名桥主机并同时设置端口。
应用层代理
这个方法比较费功夫,但这会是一种比较安全的做法。代理程序运行在防火墙 所在的主机上(即可在外部又可在内部访问)。当内部的服务器准备使输出的对 象可用时,它连接代理服务器并给它一个引用。然后代理服务器建立一个代理对 象(位于代理服务器上的新的远程对象),这个代理对象就像原对象一样实现相 同的远程接口。代理服务器向内部的服务器返回一个新代理对象的一个远程引用 ,内部服务器通过它和外界交流(不知何故)。
当外界调用代理时,代理立即转发该调用到内部服务器原来的对象。代理的使 用对外界来说是透明的(但对内部服务器并不透明,在和任何对象交流时它必须 决定是传送原对象的引用还是代理对象的引用)。
不用说,这需要考虑设置和与本地网管的协作。
连接多路复用技术
因为JDK1.0.2不允许非授权代码侦听TCP端口(即使该端口大于1023这些匿名端 口),所以即使JDK1.1的代码没有那些限制,JDK1.0.2代码也不能输出对象到JD K1.1。因此,传输层的代码被改变了,从而允许连接多路复用:即,连接可以是 多路复用的,每一路都可以做实际工作。连接多路复用不会超时,但它们是不可 升级的。
然而,可以使用连接多路复用绕过防火墙的特殊规则:那些允许在一个方向上 连接而不可在相反方向上连接的防火墙。
这项技术是要防止RMI侦听TCP端口,因此导致连接多路复用技术。这样做的唯 一途径是安装安全管理器,在checkListen内部抛出SecurityException异常。
如果你能这样做,你同样也可以安装一个套接字代理来替代它。
3.如何使RMI穿越两层防火墙?
首先,你需要客户端的防火墙如何合作呢?
做糟糕的情况是客户端的防火墙只有HTTP代理服务器并且不允许直接连接TCP端 口,这样防火墙后的客户只能做网上冲浪。在这种情况下,你的服务器主机会收 到在端口80的连接,这些连接包含内嵌有RMI请求的HTTP请求。你可以使用带有j ava-rmi.cgi程序的HTTP服务器,或者直接在端口80上运行RMI服务器。在任何一 种情况下,服务器都无法使用客户端输出的回调对象。
比较乐观的情况是客户端可以直接连接到服务器,但是不能接受由服务器传来 的外来连接。这种情况下,回调对象一般也是不可能的(有一种特殊情况,就是 有些环境下的applet可以触发与JDK1.0.2兼容的连接多路复用模式——这会允许 回调对象,但这是不可升级的,一般不支持这样做。)。
假设没有客户端防火墙管理员的帮助,最保守的方法是:
* 避免使用回调对象;
* 在公共端口上运行服务器,如80,81,8001,443等。
* 如果服务器没有运行在80端口上,那么:
- 在端口80上运行一个有CGI能力的HTTP服务器,它可以使用java-rm i.cgi,或者
- 在80端口上运行一个端口转向器,它可以接受连接并立即连接到真 正的服务器端口并传送数据。这会导致getClientHost()返回容易让人误解的信息 ,因此除非在不同的主机上,否则尽量不要使用这种方法使注册器(Registry) 可用。
-- 灌水的时候想想我,想我的时候来看我... 看什么看,没见过鱼吗?!
※ 来源:.月光软件站 http://www.moon-soft.com.[FROM: 202.104.86.90]
|
|