Rob*_*ino 6 bash process io-redirection openssh
我正在寻找对以下 ProxyCommand 的深入解释,包括其操作的具体细节。如果可以的话,你能否为我彻底剖析它并改进它?为了可读性,如果没有别的。
ProxyCommand ssh gatewayserver 'exec 3<>/dev/tcp/targetserver/22; cat <&3 & cat >&3;kill $!'
Run Code Online (Sandbox Code Playgroud)
(我的/dev/tcp
系统上没有设备;但是bash
似乎有一些内置的处理方法,分配一个连接到以下/host/port
部分的 tcp 套接字。)
因此,您的 ssh 代理命令安全地运行一个 shell,gatewayserver
它执行以下操作:
exec 3<>/dev/tcp/targetserver/22
Run Code Online (Sandbox Code Playgroud)
即在文件描述符 3 上附加一个套接字(连接到targetserver
/ port
)。然后:
cat <&3 & cat >&3; kill $!
Run Code Online (Sandbox Code Playgroud)
这是一种在文件描述符0
(输入)和1
(输出)和文件描述符3
(输入和输出)之间进行双向重定向(使用两个单独的进程)的方法。的kill $!
是那里杀后台进程cat <&3
的其他工艺后,cat >&3
又回来了。
所有这些只是一些更标准的等价物:
ProxyCommand ssh gatewayserver "tcpconnect targetserver port"
Run Code Online (Sandbox Code Playgroud)
使用/dev/tcp
(或bash
)功能代替tcpconnect
命令。
更多细节:
ssh 使用的代理命令用于定义如何连接到远程主机targetserver
(那里并不真正需要加密,因为将在此通道上使用 ssh 协议)。在我们的例子中,我们想建立到这个目标主机的连接槽gatewayserver
(可能是因为防火墙阻止targetserver
直接连接。
所以一个过程
ssh gatewayserver 'exec 3<>/dev/tcp/targetserver/22; cat <&3 & cat >&3;kill $!'
Run Code Online (Sandbox Code Playgroud)
已启动并且:
1
ssh 客户端将使用filedescriptor(fd) (又名标准输出)将数据发送到目标主机。0
ssh 客户端将使用fd (又名标准输入)从远程主机读取数据。将ssh gatewayserver
首先用于连接到这将是第一跳网关。在这个主机上启动一个新的 shell,这个ssh
实例将把原始主机上进程的fd 0
/fd中继1
到网关主机上运行的 shell 的fd 0
/fd 1
。这个shell执行的命令是:
exec 3<>/dev/tcp/targetserver/22; cat <&3 & cat >&3;kill $!
Run Code Online (Sandbox Code Playgroud)
在exec
没有命令将不会执行任何东西,它只是采用下列重定向shell本身。通常的重定向是:
n>file
重定向的fdn
到file
(开放仅书面方式,n
是1
如果中省略)。n<file
重定向的fdn
到file
(开放为只读,n
则0
如果中省略)。n<>file
将 fd 重定向n
到file
(打开读取和写入)。n>&m
或n<&m
或n<>&m
,将FDn
被重定向到文件先前由FD指向m
。这里使用了以下内容:
exec 3<>/dev/tcp/targetserver/22
Run Code Online (Sandbox Code Playgroud)
这会将新创建的 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
(从外壳的 fd 读取3
并写入外壳的 fd 1
。)cat >&3
(从外壳的 fd 读取0
并写入外壳的 fd 3
。)两者cat
必须并行运行,因此需要一个后台运行。在这里,我们希望读取 fd 0
(可能是 tty)的那个是留在前台的那个。这给出:
cat <&3 & #run in the background
cat >&3; kill $!
Run Code Online (Sandbox Code Playgroud)
的kill $!
是那里杀后台程序($!
扩展到最后转到后台进程的PID)。这样当客户端挂断时,前台进程终止,执行kill,最后一个进程也终止。
就是这样!我们已经建立了桥梁:
源主机?—(ssh)??网关?—(泵+套接字)??目标服务器(端口22)
源主机ssh user@targetserver
上的一个将能够通过这个网桥连接到目标主机!