【问题标题】:How to run ssh reverse tunnel in background using python?如何使用 python 在后台运行 ssh 反向隧道?
【发布时间】:2020-01-08 14:56:02
【问题描述】:

我需要使用python在后台执行命令ssh -NTf -R 5000:localhost:22 server@ip。由于选项-f,我知道命令本身在后台运行。

我已经使用 python subprocess 包来做到这一点。

cm="ssh -NTf -o ExitOnForwardFailure=yes -o ConnectTimeout=10 -R 5000:localhost:22 servermc@122.174.345.9"

try:
    out=sp.check_output(cm,stderr=sp.STDOUT,shell=True)
except Exception as e:
    print "ddddd",e.output

但是发生的情况是该进程仍处于前台。当我们运行上面的python代码时,执行在check_output命令处暂停,我需要按ctrl+c退出python代码。

我还尝试了 Popen 和 poll() 函数。使用这些功能,我可以实现所需的功能,但问题是如果发生任何错误(例如端口未空闲或 IP 地址错误),我无法获取状态。

我需要做的是我想使用 python 在后台运行 ssh 反向隧道,并且我需要从服务器端获取它是否运行成功的状态?

我只能访问服务器,上面的脚本将在客户端内运行。因此我可以通过服务器访问客户端。如果客户端运行此脚本,状态将被发送到云端,以便我可以验证状态并从服务器连接到客户端。

【问题讨论】:

  • 为什么不能使用Popenpoll 获得状态?这将是正常的方法。
  • 如果轮询表明进程仍在运行以获取任何错误消息,您还可以使用 communicate 超时。
  • 如果使用communicate,也会出现同样的问题。它将在通信时暂停。
  • 这就是为什么我对communicatewith a timeout。给它一个 2 秒的超时,期望如果一切正常,那么你会得到超时异常。如果您没有收到异常,则可能出现问题。
  • 我们如何给超时通信功能?

标签: linux ssh sshd


【解决方案1】:

"Background" 纯粹是一个 shell 概念:您可能想要的是生成一个新进程。subprocess.Popen() 仅在 python 脚本中没有任何内容依赖于正在运行的命令的输出时才运行一个进程。

示例:

import subprocess
subprocess.Popen(["ls","-lha","/"])

如果您想检查某个进程的错误或信息,一种方法是检查该进程的日志。

您可以在 ssh 命令上使用-E 参数并将调试日志附加到日志文件:

ssh -NTf -o ExitOnForwardFailure=yes -o ConnectTimeout=10 -R 5000:localhost:22 servermc@x.x.x.x -E /tmp/ssh.log

使用subprocess.Popen() 执行 ssh 命令后,您可以检查日志文件是否有任何错误,而无需暂停。

Using shell=True can be a security hazard.

更新 1:我的脚本中的 result 变量完全等于脚本中的 out 变量。并且脚本不会卡在Popen

#!/usr/bin/python
import shlex
from subprocess import Popen, PIPE
import time

tmp_file = "/tmp/ssh.log"   #temp log file address 
cmd="ssh -NTf -o ExitOnForwardFailure=yes -o ConnectTimeout=10 -R 5000:localhost:22 servermc@x.x.x.x -E "+tmp_file  #command to execute

def executor(command):
    try:
        file = open(tmp_file,"w+")  #create or truncates the log file if exist
        p = Popen(shlex.split(command), stdin=PIPE, stdout=PIPE, stderr=PIPE)   #execute the command
        p.wait()
        content = file.read().strip()
        file.close()
        return content
    except Exception as e:
        return e

result = executor(cmd)

print (result)

【讨论】:

  • 不,我不能使用日志文件,因为无法访问远程客户端。基本上,客户端将从云中下载 IP 地址和端口,并使用哪个客户端运行反向隧道,以便我可以访问客户端 PC。问题是我永远不会知道反向隧道是否启动。所以我需要使用 python 获取状态。
  • 是的,它是一个调试日志,您可以通过解析日志文件发现您的客户端已连接或无法访问远程端。你需要的每一件事,你在 python 代码中的例外都将在该日志中。 -E 将标准错误日志附加到文件中。
  • 您好,先生,我只能访问服务器。所以我在客户端拥有日志文件没有任何好处。
  • 嘿先生,您必须清楚并在您的问题中指定所有内容。
【解决方案2】:

嗯,有时将基本命令粘合在一起很好,但有时会有更好的解决方案。

潜入python方式:rforward.py

这个脚本是如何使用 paramiko(python SSH 库)的一个很好的例子,它也是一个完美的工作解决方案。 您不需要生成 SSH,只需在 Python 中完成。

【讨论】:

    【解决方案3】:

    试试autossh(Windows下,可以安装cygwin的autossh)

    import subprocess as sp
    import shlex
    
    # cm = "autossh -f -M 15580 -N root@acone3 -R 5580:127.0.0.1:5580 -C -o ExitOnForwardFailure=yes -o ConnectTimeout=10"
    
    cm = "autossh -f -M 15000 -o ExitOnForwardFailure=yes -o ConnectTimeout=10 -R 5000:localhost:22 servermc@122.174.345.9"
    
    cm = shlex.split(cm)
    try:
        out=sp.check_output(cm, stderr=sp.STDOUT,shell=True)
    except Exception as e:
        print("ddddd", e.output)
    ...
    

    请注意,python 程序结束时 autossh 不会退出。如果你不想让它运行,你需要明确地杀死 autossh。另一方面,一旦建立了隧道,您就可以在不影响隧道的情况下终止 autossh —— 隧道在 ssh 会话中有效。杀死相关的 ssh 将终止隧道。

    【讨论】:

      猜你喜欢
      • 2020-01-24
      • 2012-06-06
      • 1970-01-01
      • 2010-09-27
      • 2019-02-04
      • 2015-03-09
      • 1970-01-01
      • 2016-06-10
      • 2012-01-26
      相关资源
      最近更新 更多