2011-11-26 79 views
1

我正在通过SSH隧道隧道传输cajo rmi流量。通过SSH隧道传输所有RMI流量

为此,我有一台运行SSH deamon(apache Mina)的服务器和一台运行SSH客户端(Trilead SSH)的客户端。

可以建立这些机器之间的shh连接,并通过应用本地和远程端口转发我可以隧道rmi流量,但是这只适用于延长(到服务器)方向。

的设置:

主动SSH连接(端口22)
客户端:转发本地端口4000,远程主机端口第1198(此流量实际上去trhough隧道) 服务器:转发服务器端口4000到客户端端口1198(隧道的这部分没有被使用cajo)

服务器出口使用对象:

Remote.config(null, 1198, null, 0); 
ItemServer.bind(new SomeObject(), "someobject"); 

客户端不会使用对象查找:

ObjectType someObject = (ObjectType)TransparentItemProxy.getItem(
          "//localhost:4000/someobject", 
          new Class[] { ObjectType.class }); 
logger.info(someObject.getName()); 

端口转发是使用在客户端的三铅SSH库调用:

conn.createLocalPortForwarder(4000, "Server-IP", 1198); 
conn.requestRemotePortForwarding("localhost" 4000, "Client-IP", 1198); 

当使用Wireshark分析两个机器之间的IP通信,我发现通过隧道将查询重定向,但回应不是。 负责人通常发送到客户端的1198端口。

如何强制服务器将远程调用的响应发送到本地端口,以便将其传回客户端?

UPDATE:这里的问题是,对RMI对象的端口不同,那么注册表端口,因此还需要进行转发。

简而言之,客户端10.0.0.1会查找到//10.0.0.1:4000,并将其转发到服务器上的RMI端口(通过隧道)。 随后,服务器响应10.0.0.1:1198,我希望服务器将其流量发送到其本地端口4000,以便使用隧道。

我试图摆弄cajo Remote.config(ServerAddress,ServerPort,ClientAddress,ClientPort)设置,但是当我将clientaddress设置为10.0.0.1或127.0.0.1这个方法时,我无法获取响应回来,我没有看到任何响应的交通...

+0

将响应发送回请求发送到的相同连接。你在谈论一个*回调*? – EJP

+0

他在这里回答了答案中的细节吗? http://stackoverflow.com/questions/1734558/java-rmi-via-ssh-v2-protocol - 好像他可能错过了至少一次转移 – Petesh

+0

谢谢Petesh和EJP,我正在重新思考我的设计。 RMI注册表可能运行在与RMI服务器不同的端口上。定制RMI服务器端口我想我需要实现一个自定义套接字facktory,如下所述:http://www.javaranch.com/journal/2003/10/rmi-ssh_p1.html –

回答

2

我找到了解决这个问题的方法,其中我从设置中省略了cajo框架并使用纯java rmi。这使事情更加透明。

在客户端和服务器上,我都放置了一个安全策略文件:C:\ server。政策

grant { 
permission java.security.AllPermission; 
}; 

然后在服务器上,设置安全权限并开始所需的端口上的注册表:

System.setProperty("java.rmi.server.hostname", "127.0.0.1");    
System.setProperty("java.security.policy","C:\\server.policy"); 
System.setSecurityManager(new RMISecurityManager()); 
new SocketPermission("*:1024-", "accept,connect,listen");  
createRMIRegistry(Property.getProperty("rmi.registry.port")); 

注意主机名127.0.0.1,这样可以确保我们始终指向localost,

  • 这招骗客户端认为从远程注册表获得的对象是本地的,然后连接到它的本地f转发端口。

在客户端上,我给出了与上面相同的权限,但我不启动注册表,但绑定了一个额外的套接字工厂用于注册表查找。

RMISocketFactory.setSocketFactory(new LocalHostSocketFactory()); 

此套接字工厂创建一个到本地主机ssh端口(到远程注册表)的SSHClientSocket。

远程对象使用自定义ClientSocketFactory导出,因此在客户端实现。 (在服务器端,它需要被禁用,否则你将ssh到你自己的机器:$)

然后它创建一个ssh套接字和端口转发器。

public class SSHClientSocketFactory implements RMIClientSocketFactory, Serializable { 

public Socket createSocket(String host, int port) throws IOException { 
    try {  
    Connection conn = new Connection(hostname, 22); 
    conn.connect(); 
    boolean isAuthenticated = conn.authenticateWithPassword(username, password); 
    LocalPortForwarder lpf1 = conn.createLocalPortForwarder(port, serverAddress, port); 
     return new Socket(host, port); 
    catch (Exception e) {System.out.println("Unable to connect")}; 
} 

}

这种自动端口formwarding确保被用于结合的RMI对象的任何端口,它通过SSH通道和点为localhost了点。

此设置不需要远程端口转发。

+0

我现在修改了上面的方法。我在服务器端需要一些额外的可配置性。所以我更改了sshd的ChannelDirectTcpip,以编程方式将我的主机地址名称解析为127.0.0.1。 –