【问题标题】:Doing ssh tunnel with Python script. Error: "Could not resolve hostname when trying to open ssh tunnel"用 Python 脚本做 ssh 隧道。错误:“尝试打开 ssh 隧道时无法解析主机名”
【发布时间】:2020-08-06 22:29:29
【问题描述】:

您好,我正在研究简单的 python ssh 隧道脚本,但我总是收到 Could not resolve hostname 错误,但如果手动运行它就可以了。这是我的代码:

#!/usr/bin/env python

import subprocess
import time
import tempfile

class TunnelSSH():
    def __init__(self, ssh_user: str, ssh_password: str, ssh_host: str, ssh_port: int,
                local_tunnel_port:int, remote_tunnel_host:str, remote_tunnel_port:int):
        self.ssh_user = ssh_user
        self.ssh_password = ssh_password
        self.ssh_host = ssh_host
        self.ssh_port = ssh_port
        self.local_tunnel_port = local_tunnel_port
        self.remote_tunnel_port = remote_tunnel_port
        self.remote_tunnel_host = remote_tunnel_host

        _socket_file = tempfile.NamedTemporaryFile()
        _socket_file.close()
        self.socket = _socket_file.name
        self.connected = False


    def start(self):
        ssh_conection = ['ssh', '-CN',
                        f'"{self.ssh_user}:{self.ssh_password}"@{self.ssh_host} -p {self.ssh_port}',
                        f'-L {self.local_tunnel_port}:{self.remote_tunnel_host}:{self.remote_tunnel_port}',
                        f'-S {self.socket}',
                        '-o ExitOnForwardFailure=True'
                    ]
        if not self.connected:
            status = subprocess.call(ssh_conection)
            self._check_connection(status)
            time.sleep(self.retry_sleep)
        else:
            raise Exception('Tunnel is open')

    def stop(self):
        if self.connected:
            if self._send_control_command('exit') != 0:
                raise Exception('SSH tunnel failed to exit')
            self.connected = False

    def _check_connection(self, status) -> None:
        """Check connection status and set connected to True is tunnel is open"""
        if status != 0:
            raise Exception(f'SSH tunnel failed status: {status}')
        if self._send_control_command('check'):
            raise Exception(f'SSH tunnel failed to check')
        self.connected = True

    def _send_control_command(self, ctl_cmd:str):
        call = ['ssh',f'-S {self.socket}',f'-O {self.ctl_cmd}', f'-l {self.ssh_user}', f'{self.ssh_host}']
        return subprocess.check_call(call)


if __name__ == "__main__":
    tunnel = TunnelSSH(ssh_user='...',
                        ssh_password='...',
                        ssh_host='...',
                        ssh_port=...,
                        local_tunnel_port=...,
                        remote_tunnel_host='...',
                        remote_tunnel_port=...
                    )

    retry = 10 # times
    wait_for_retry = 5 #s

    for i in range(retry):
        print(f'Connection attempt: {i}')
        try:
            tunnel.start()
        except Exception as err:
            tunnel.stop()
            print(err)
            time.sleep(wait_for_retry)

    print(f'Connected: {tunnel.connected}')

【问题讨论】:

  • 您是否偶然使用了 ssh 别名作为主机? host <ssh_host> 的输出会很有帮助
  • @Marat 我也试过ssh服务器ip,
  • 您能否确认即使使用 IP 地址,错误仍然“无法解决”?
  • @Marat,是的,即使使用 IP 地址我也有相同的答案

标签: python python-3.x ssh subprocess


【解决方案1】:

subprocess.call 需要一个参数列表。当ssh_conection 形成时,几个参数被拍打在一起,例如这部分被引用到一个参数中:

'"{self.ssh_user}:{self.ssh_password}"@{self.ssh_host} -p {self.ssh_port}'

修复:正确拆分参数:

...
    ssh_conection = ['ssh', '-CN',
                    f'{self.ssh_user}:{self.ssh_password}@{self.ssh_host}',  # will be quoted automatically
                    '-p', f'{self.ssh_port}',
                    '-L', f'{self.local_tunnel_port}:{self.remote_tunnel_host}:{self.remote_tunnel_port}',
                    '-S', f'{self.socket}',
                    '-o', 'ExitOnForwardFailure=True'
                ]
...

什么暗示了问题:直接使用IP地址。 IP 地址上的“无法解析”表示它被解释为符号名称,这使得发现这一点更容易。

【讨论】:

    猜你喜欢
    • 2017-07-10
    • 2016-03-27
    • 2015-02-17
    • 2018-07-20
    • 2011-05-20
    • 1970-01-01
    • 2019-08-10
    • 2011-11-03
    • 1970-01-01
    相关资源
    最近更新 更多