![关于 ssh ProxyCommand 的所有信息](https://linux22.com/image/17586/%E5%85%B3%E4%BA%8E%20ssh%20ProxyCommand%20%E7%9A%84%E6%89%80%E6%9C%89%E4%BF%A1%E6%81%AF.png)
我正在寻找对以下 ProxyCommand 的深入解释,请详细了解其操作的具体细节。如果可以的话,您能帮我彻底剖析一下并改进它吗?如果没有别的,为了可读性。
ProxyCommand ssh gatewayserver 'exec 3<>/dev/tcp/targetserver/22; cat <&3 & cat >&3;kill $!'
答案1
/dev/tcp
(我的系统上没有设备;但是bash
似乎有一些内置处理,分配一个连接到以下/host/port
部分的 TCP 套接字。)
因此,您的 ssh 代理命令安全地运行一个 shell,gatewayserver
该 shell 执行以下操作:
exec 3<>/dev/tcp/targetserver/22
即在文件描述符 3 上附加一个套接字(连接到targetserver
/ port
)。然后:
cat <&3 & cat >&3; kill $!
这是一种在文件描述符0
(输入)和1
(输出)以及文件描述符3
(输入和输出)之间进行双向重定向(使用两个单独的进程)的方法。在其他进程返回后,它kill $!
会终止后台进程。cat <&3
cat >&3
所有这些只是某种更标准的等价物:
ProxyCommand ssh gatewayserver "tcpconnect targetserver port"
使用/dev/tcp
(或bash
) 功能代替tcpconnect
命令。
更多细节:
ssh 使用的代理命令用于定义如何连接到远程主机targetserver
(那里并不真正需要加密,因为将使用 ssh 协议超过这个频道)。在我们的例子中,我们希望建立与该目标主机的连接(可能是因为防火墙阻止直接gatewayserver
连接。targetserver
那么一个过程
ssh gatewayserver 'exec 3<>/dev/tcp/targetserver/22; cat <&3 & cat >&3;kill $!'
已启动并且:
- filedescriptor(fd)
1
(又名标准输出)将被 ssh 客户端用来将数据发送到目标主机。 - fd
0
(又名标准输入)将被 ssh 客户端用来从远程主机读取数据。
用于ssh gatewayserver
首先连接到作为第一跳的网关。在此主机上启动一个新的 shell,该ssh
实例将原始主机上进程的fd 0
/fd中继到网关主机上运行的 shell 的fd /fd 。这个shell执行的命令是:1
0
1
exec 3<>/dev/tcp/targetserver/22; cat <&3 & cat >&3;kill $!
没有exec
命令的不会执行任何操作,它只会应用 shell 本身的以下重定向。通常的重定向是:
n>file
将 fd 重定向n
到file
(仅打开用于写入,n
如果1
省略则为)。n<file
将 fd 重定向n
到file
(打开以供阅读,n
如果0
省略)。n<>file
将 fd 重定向n
到file
(打开以进行读写)。- 当指定为
n>&m
orn<&m
or时n<>&m
,fdn
将重定向到 fd 先前指向的文件m
。
这里使用以下内容:
exec 3<>/dev/tcp/targetserver/22
这会将新创建的 fd 重定向3
到一些非常特殊的文件/dev/tcp/targetserver/22
(这不是真正的文件,而是 bash 本身可以理解的文件)。在这里,bash 创建一个套接字(使用 tcp 协议的特殊文件)来targetserver
在端口22
(我们期望找到sshd
服务器的地方)上进行通信,并且该文件在 fd 上打开(读和写)3
。
现在我们需要将数据“泵送”到fd 0
(来自客户端的数据)上并将其发送到fd 3
(连接到目标服务器)。我们还需要通过“泵送”fd 上的数据3
并将其发送回 fd 1
(客户端的结果)来确保向后通信。这两个“泵”是使用两个cat
过程设置的:
cat <&3
(从 shell 的 fd 读取3
并写入 shell 的 fd1
。)cat >&3
(从 shell 的 fd 读取0
并写入 shell 的 fd3
。)
两个cat
都必须并行运行,因此其中一个需要后台运行。在这里,我们希望在 fd 上读取的那个0
(可能是 tty)是留在前台的那个。这给出:
cat <&3 & #run in the background
cat >&3; kill $!
是kill $!
用来终止后台进程的($!
扩展到最后一个后台进程的 pid)。这样当客户端挂起时,前台进程终止,执行kill,最后一个进程也终止。
就是这样!我们已经搭建了这座桥:
源主机—(ssh)→网关—(泵+套接字)→目标服务器(端口22)
一个ssh user@targetserver
关于起源主机将能够连接到目标主人通过这座桥!