java - 如何通过 SSH 传输所有 RMI 流量

标签 java ssh rmi tunnel cajo

我正在研究通过 SSH 隧道传输 cajo rmi 流量。

为此,我有一个运行 SSH 守护程序 (apache Mina) 的服务器和一个运行 SSH 客户端 (Trilead SSH) 的客户端。

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

设置:

Activity SSH 连接(端口 22)
客户端:将本地端口 4000 转发到远程主机端口 1198(此流量实际上通过隧道) 服务器:将服务器端口 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());

使用客户端的 trilead ssh 库调用端口转发:

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

当使用 WireShark 分析两台机器之间的 IP 流量时,我发现查找正在通过隧道重定向,但响应却没有。 响应通常发送到客户端的端口 1198。

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

更新:这里的问题是 RMI 对象的端口与注册表端口不同,因此也需要转发。

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

我尝试摆弄 cajo Remote.config(ServerAddress, ServerPort, ClientAddress, ClientPort) 设置,但是当我将此方法的客户端地址设置为 10.0.0.1 或 127.0.0.1 时,我无法获得响应返回,我根本没有看到任何响应流量...

最佳答案

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

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

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,

  • 这会欺骗客户端认为从远程注册表获取的对象是本地的,然后连接到其本地转发的端口。

在客户端上,我授予与上面相同的权限,我不启动寄存器,而是绑定(bind)一个额外的套接字工厂以用于注册表查找。

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")};
}

}

这种自动端口转发可确保无论使用哪个端口来绑定(bind) RMI 对象,它都会通过 SSH 隧道并指向 localhost。

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

关于java - 如何通过 SSH 传输所有 RMI 流量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8279426/

相关文章:

java - 是否可以手动检查 LocateRegistry 是否存在?

java - IntelliJ 2019.2.2 : Unable to debug gradle unit tests

java - 无法将 getDownloadUrl() 的响应保存到变量

java - 使用 JSch 执行命令

java - 如何通过 RMI 传递输入流

java - Java RMI和高级多线程

java - cucumber AmbiguousStepDefinitionsException Java

java - JPA @UniqueConstraint 看不到列

mysql - 无法重置 MySQL 密码

开始使用 token 后,Windows 客户端中的 git pull over ssh 挂起