如何在现有的TCP连接上运行ssh

WavesAtParticles

我希望能够在不同的NAT之后立即SSH到许多linux设备。我无法配置它们所在的网络。但是,我很难让ssh遍历现有连接。

我可以完全控制我的客户端和设备。到目前为止的过程是这样的:在我的客户上,我首先运行

socat TCP-LISTEN:5001,pktinfo,fork EXEC:./create_socket.sh,fdin=3,fdout=4,nofork

内容./create_socket.sh

ssh -N -M -S "~/sockets/${SOCAT_PEERADDR}" -o "ProxyCommand=socat - FD:3!!FD:4" "root@${SOCAT_PEERADDR}"

在设备上,我正在跑步

socat TCP:my_host:4321 TCP:localhost:22

但是,FD:3!!FD:4由于ProxyCommand是一个子进程,因此我认为没有任何结果我也尝试设置fdin=3,fdout=3并更改./create_socket.sh为:

ssh -N -M -S "~/sockets/${SOCAT_PEERADDR}" -o "ProxyUseFdpass=yes" -o "ProxyCommand=echo 3" "root@${host}"

这会显示错误:

mm_receive_fd: no message header
proxy dialer did not pass back a connection

我相信这是因为应该使用来以某种方式发送fd sendmsg,但fd并非源自子进程。我想使它尽可能简单,并且感觉可行。

知识

您想颠倒​​客户端/服务器模型,并使其成为通用服务器,以通过网络边界按需并响应对传入的未经身份验证的TCP连接生成客户端,然后告诉该新生成的客户端使用该未经身份验证的TCP会话。我认为这可能具有您未曾想到的安全注意事项。如果恶意软件向您的计算机发送垃圾邮件,您的计算机将产生大量SSH实例以进行重新连接,并且这些过程在身份验证时会占用大量本地系统资源。您实际上是在尝试设置SSH,以跨网络边界自动连接到不受信任(未经验证)的远程启动的计算机。我不能强调可能对您的客户端计算机造成危险使用错误的选项可能会暴露您拥有的所有凭据,甚至可能使恶意人员完全访问您的计算机。

还要注意的是,您要执行的方案(在多个设备之间建立隧道以在不受信任的网络边界上多路复用其他连接)正是VPN软件的目的是的,SSH可以建立隧道。VPN软件可以更好地构建隧道。这个概念就是您要在客户端计算机上运行VPN服务器。VPN服务器将创建一个代表您的设备的新(虚拟)网络接口设备将连接到VPN服务器,并被分配一个IP地址。然后,您只需从客户端计算机启动SSH到设备的VPN地址,它将通过虚拟网络接口路由并到达设备,并由其SSH守护程序服务器处理。那你不socat或用于端口转发的SSH选项。您将获得有关VPN的所有工具和教程。我强烈建议您看一下VPN软件

如果您真的想使用SSH,那么我强烈建议您学习有关保护SSH服务器的信息您已声明设备跨网络边界(NAT),并且客户端系统不受保护。我不会阻止您用脚射击自己,但是在您陈述的情况下,如此壮观地拍摄非常容易如果您处于工作环境中,则应与系统管理员联系,讨论防火墙规则,堡垒主机等类似内容。

是的,您可以按照您所说的去做。我强烈建议您谨慎。我建议,足够强烈,我不会建议任何这将与合作作为说明我将建议一个具有相同概念但更多身份验证的变体。

首先,您已经有效地设置了自己的SSH退回服务器,但是没有任何与SSH服务器兼容的常用工具。因此,这是我要解决的第一件事:使用SSH服务器软件ssh而不是通过客户端软件从设备启动连接来验证传入的隧道请求socatssh已经有足够的能力来创建隧道两个方向你捆绑了它(与认证socat,没有认证)。设备应该能够使用加密密钥进行身份验证(ssh称为这些身份)。您需要手动连接一次从设备验证并授权远程加密密钥指纹。您还需要将公共密钥文件(而不是私有密钥文件)复制到客户端计算机,并将其添加到您的authorized_keys文件中。如果需要,您可以单独寻求帮助。

第二个问题是您似乎正在使用fd3和fd4。我不知道你为什么要这么做。如果有的话,您应该使用fd0和fd1,因为它们分别是stdinstdout但是,如果您要socat用来发起连接,则甚至不需要这样做只需使用-wherestdinstdout意味着。它应该完全兼容-o ProxyCommand而不指定任何文件描述符。这个答案的末尾有一个例子。

设备端进行的调用可能看起来像这样(将其放入脚本文件中):

IDENTITY=/home/WavesAtParticles/.ssh/tunnel.id_rsa # on device
REMOTE_SOCKET=/home/WavesAtParticles/.ssh/$(hostname).sock # on client
REMOTEUSER=WavesAtParticles # on client
REMOTEHOST=remotehost # client hostname or IP address accessible from device
while true
do
  echo "$(date -Is) connecting"
  #
  # Set up your SSH tunnel. Check stderr for known issues.
  ssh \
    -i "${IDENTITY}" \
    -R "${REMOTE_SOCKET}:127.0.0.1:22" \
    -o ExitOnForwardFailure=yes \
    -o PasswordAuthentication=no \
    -o IdentitiesOnly=yes \
    -l "${REMOTEUSER}" \
    "${REMOTEHOST}" \
      "sleep inf" \
  2> >(
    read -r line
    if echo "${line}" | grep -q "Error: remote port forwarding failed"
    then
      ssh \
        -i "${IDENTITY}" \
        -o PasswordAuthentication=no \
        -o IdentitiesOnly=yes \
        -l "${REMOTEUSER}" \
        "${REMOTEHOST}" \
          "rm ${REMOTE_SOCKET}" \
      2>/dev/null # convince me this is wrong
      echo "$(date -Is) removed stale socket"
    fi
    #
    # Re-print stderr to the terminal
    >&2 echo "${line}" # the stderr line we checked
    >&2 cat - # and any unused stderr messages
  )

  echo "disconnected"
  sleep 30
done

请记住,就shell脚本而言,复制和粘贴是不好的。至少,我建议您阅读man sshman ssh_config,并对照shellcheck.net检查脚本。该脚本的目的是:

  1. 在一个循环中,让您的设备(重新)连接到客户端以维护隧道。
  2. 如果连接断开或失败,则每30秒重新连接一次。
  3. ssh使用以下参数运行
    • -i "${IDENTITY}":指定用于认证的私钥。
    • -R "${REMOTE_SOCKET}:127.0.0.1:22":指定一个连接请求转发器,它在远程端接受连接, /home/WavesAtParticles/$(hostname).sock然后通过连接到本地将它们转发到本地127.0.0.1:22
    • -o ExitOnForwardFailure=yes:如果远程端无法建立连接转发器,则本地端应发出错误并死亡(我们将在子shell中检查此错误)。
    • -o PasswordAuthentication=no:不要回退到密码请求,尤其是因为本地用户不在此处输入密码时
    • -o IdentitiesOnly=yes:请勿使用任何默认身份或任何本地代理提供的身份。仅使用由指定的一个-i
    • -l "${REMOTEUSER}":以指定用户身份登录。
    • remotehost,例如您希望设备连接到的客户端计算机。
  4. 永远睡
  5. 如果由于套接字过期而导致连接失败,请通过以下方法解决此问题:

    • 分别登录
    • 删除(陈旧的)套接字
    • 打印今天的日期,指示何时删除
    • 再次循环

    有一个选项旨在使此错误处理变得多余:StreamLocalBindUnlink但是,该选件无法正常工作,并且已打开多年错误我想那是因为确实没有多少人使用ssh来转发unix域套接字。这很烦人,但并不难解决。

使用Unix域套接字应将连接性限制为可以访问套接字文件的任何人(应该只有您并且该文件root位于${HOME}/.ssh目录中并且目录具有正确的权限)。我不知道这对您的情况是否重要。

另一方面,如果您愿意为每个设备打开一个TCP端口,则也可以简化很多127.0.0.1操作。但是随后,同一系统上的任何其他用户也可以连接。您应该专门侦听127.0.0.1哪些内容将仅接受来自同一主机的连接,以防止外部计算机到达转发端口。您可以将${REMOTE_SOCKET}变量更改为例如127.0.0.1:4567侦听端口4567并仅接受本地连接。因此,您将失去命名套接字功能,并允许客户端计算机上的任何其他用户连接到您的设备,但获得了更为简单的隧道脚本(因为您可以删除解析stderr的全部内容来删除陈旧的套接字文件)。

只要您的设备处于联机状态(可以到达工作站的传入端口)并且正在运行该脚本,并且身份验证有效,则隧道也应该处于联机状态或联机状态。但是,丢失(和恢复)网络连接后,将需要一些时间来恢复。您可以使用ConnectTimeoutTCPKeepAliveServerAliveInterval选项以及sleep 30循环一部分进行调整。您可以在tmux会话中运行它以使其继续运行,即使您没有运行登录会话也是如此。您也可以在设备上将其作为系统服务运行,以使其联机,即使从电源故障中恢复后也是如此。

然后,可以从客户端反向连接:

ssh -o ProxyCommand='socat - unix-connect:/home/WavesAtParticles/remotehost.sock' -l WavesAtParticles .

在此调用中,您将开始ssh然后,它将使用来设置proxycommand socat它将使用其stdin / stdout并通过提供的路径上连接的AF_UNIX套接字将其中继。您需要更新所需的远程主机的路径。但是根本不需要指定文件描述符。如果ssh抱怨:

2019/08/26 18:09:52 socat[29914] E connect(5, AF=1 "/home/WavesAtParticles/remotehost.sock", 7): Connection refused
ssh_exchange_identification: Connection closed by remote host

那么隧道当前已关闭,您应该调查remotehost设备的连接性。

如果您将远程转发选项与TCP端口侦听而不是Unix域套接字一起使用,则通过隧道远程客户端调用将变得更加容易:ssh -p 4567 WavesAtParticles@localhost

同样,您正在尝试反转客户端/服务器模型,我认为使用SSH并不是一个好主意。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

通过SSH连接到没有运行SSH服务器的计算机,或者如何重用现有的ssh连接反向

如何使用现有的tcp连接从bash脚本访问http服务器?

如何在新安装的Ubuntu上使用现有的SSH密钥

如何在Azure中连接现有的Automation Account和Log Analytics工作区?

如何在断开连接上运行脚本(节点js)

如何在Linux中的Rails项目上运行现有的Ruby

如何在Ruby 2.2上运行现有的测试代码

如何在Sublime REPL中运行现有的Clojure程序

如何在运行时销毁现有的bean并用新的定义Spring替换

如何在Electron中集成和运行现有的ReactJS应用程序

如何在现有的Apple Watch应用程序中添加和运行Glance?

如何通过ssh(cmus)控制现有的终端程序

如何连接到现有的超级账本网络

如何逐步连接到现有的 Kafka MSK 集群?

如何运行现有的AWS放大项目

如何使用和运行现有的yeoman项目?

如何打开和运行现有的Vagrant / Homestead项目

可以连接现有的SSH密钥,但不能连接新的

如何在java中编辑现有的PDF

如何在Android下重用现有的Qt代码?

如何在Laravel中扩展现有的外墙?

如何在VirtualBox中打开现有的VM?

如何在Appium中使用现有的应用会话

如何在Datomic中用现有的UUID表示实体?

如何在现有的AspNetUsers表中添加列

如何在Eclipse中使用现有的.target文件?

如何在AWS CDK中导入现有的VPC?

如何在现有的Eclipse中安装CUDA NSight?

如何在现有的Lubuntu安装上安装grub?