我有两台机器,m1 和 m2,机器 m2 可以使用 SSH 连接到 m1。有一台机器 m1bis 只能连接到 m1,还有一台机器 m2bis 只有 m2 可以连接到。我想通过连接到机器 m1 的某个端口 p,使 m1bis 能够通过某个端口 q 到达机器 m2bis。假设 p 和 q 都是非特权端口,即它们大于 1024。如图所示:
+-------+ q +----+ SSH +----+ p +-------+
| m1bis | ----> | m1 | <------ | m2 | ----> | m2bis |
+-------+ +----+ +----+ +-------+
我有 m1 和 m2 的 shell 访问权限。我通常的做法是使用 SSH 反向端口转发,在 m2 上运行以下命令:
ssh -R *:q:m2bis:p m1
这会使 m1 上的 SSH 守护进程监听所有接口上的端口 q,并将所有传入连接中继到计算机 m2bis 的端口 p。这样,当 m1bis 连接到计算机 m1 的端口 q 时,该连接将通过 SSH 从 m1 路由到 m2,并且该连接实际上发生在计算机 m2bis 的端口 p 上。到目前为止一切顺利。
问题是,这需要GatewayPorts=yes
在 m1 上的 SSH 服务器配置中启用该设置。但是,它没有启用,而且我不是 m1 上的 root 用户,因此无法启用它。
但是,在我看来,似乎没有什么可以真正阻止我解决这个问题并进行端口转发:我拥有 m1 的 shell 访问权限,我可以在 m1 和 m2 之间建立 SSH 连接,我可以在 m1 上运行一个进程,该进程在所有接口上侦听端口 q(而不是让 SSH 守护程序进行侦听),并通过 SSH 路由连接。所以基本上我拥有构建自己的端口转发所需的所有权限。
我真的可以做到这一点吗?有没有简单的方法可以做到这一点?
其他要求:
- 由于我不是 m1 上的 root 权限,我更喜欢没有复杂依赖关系的解决方案,理想情况下是一些具有常用实用程序(如
netcat
、socat
等)的 bash 脚本,或者一些独立的 C 程序。 - 如果有帮助的话,我是 m2 上的 root(但原则上我也不认为我需要这个)。
- 我不信任 m1 和 m2 之间的连接,因此 m1 和 m2 之间的转发应该加密(即,它应该真正通过 SSH 进行)。
答案1
一个可行的解决方案是在 m1 上运行您自己的 SSH 守护程序,这无需 root 即可完成。以下是如何以普通用户身份运行 SSH 守护程序。
首先生成主机密钥:
ssh-keygen -f test_host_rsa -N '' -t rsa
ssh-keygen -f test_host_dsa -N '' -t dsa
ssh-keygen -f test_host_ed25519 -N '' -t ed25519
然后为您的 sshd 编写一个配置文件,其中 2222 是一些未在 m1 上使用且 m2 可以连接的非特权端口,并且您还需要指示当前文件夹的绝对路径:
cat >sshd_config <<EOF
Port 2222
HostKey /folder/where/the/files/are/test_host_rsa
HostKey /folder/where/the/files/are/test_host_dsa
HostKey /folder/where/the/files/are/test_host_ed25519
GatewayPorts yes
现在运行你的 SSH 守护程序:
/usr/sbin/sshd -f sshd_config
现在,m2 可以连接到 m1 的端口 2222 并运行反向端口转发,因为 GatewayPorts 已在您的 SSH 守护程序上启用。换句话说,在 m2 上您可以运行:
ssh -p 2222 -R *:q:m2bis:p m1
答案2
一位朋友提出了另一种解决方案:如果socat
在 m1 上安装了该命令,则可以在某个端口 q2 上监听环回地址的同时执行 SSH 反向端口转发,即在 m2 上运行以下命令:
ssh -R q2:m2bis:p m1
并socat
在 m1 上使用如下方法,将端口 q 上的传入连接重定向到监听环回地址的端口转发:
socat tcp-listen:q,reuseaddr,fork tcp:localhost:q2