python - 用 Python 脚本做 ssh 隧道。错误:“尝试打开 ssh 隧道时无法解析主机名”
问题描述
您好,我正在研究简单的 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}')
解决方案
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 地址上的“无法解析”表示它被解释为符号名称,这使得发现这一点更容易。
推荐阅读
- python - 带有按钮的 PyQt 中的 VTK 集成
- ruby - Mac OS X 批量重命名文件(2 种模式)
- qt - 如何延迟 qml 中 Loader 元素内容的可见性?
- javascript - Vue类与字符串绑定?
- php - adobe muse 表单不发送电子邮件
- jpa - 我们如何从 spring data jpa 中获取选定的列列表?
- ios - 目标 C 函数未在 swift 类中调用
- c# - 如何获取 app.config 中所有连接字符串的列表
- python-3.x - 我如何在 tkinter 中单独控制每个按钮
- javascript - 使用jquery动画角度5动画方式(平滑滚动)