关于 ssh ProxyCommand 的所有信息

关于 ssh ProxyCommand 的所有信息

我正在寻找对以下 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 <&3cat >&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执行的命令是:101

exec 3<>/dev/tcp/targetserver/22; cat <&3 & cat >&3;kill $!

没有exec命令的不会执行任何操作,它只会应用 shell 本身的以下重定向。通常的重定向是:

  • n>file将 fd 重定向nfile(仅打开用于写入,n如果1省略则为)。
  • n<file将 fd 重定向nfile(打开以供阅读,n如果0省略)。
  • n<>file将 fd 重定向nfile(打开以进行读写)。
  • 当指定为n>&mor n<&mor时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 的 fd 1。)
  • cat >&3(从 shell 的 fd 读取0 并写入 shell 的 fd 3。)

两个cat都必须并行运行,因此其中一个需要后台运行。在这里,我们希望在 fd 上读取的那个0(可能是 tty)是留在前台的那个。这给出:

cat <&3 &  #run in the background
cat >&3; kill $!

kill $!用来终止后台进程的($!扩展到最后一个后台进程的 pid)。这样当客户端挂起时,前台进程终止,执行kill,最后一个进程也终止。

就是这样!我们已经搭建了这座桥:

源主机—(ssh)→网关—(泵+套接字)→目标服务器(端口22)

一个ssh user@targetserver关于起源主机将能够连接到目标主人通过这座桥!

相关内容