Doing ssh tunnel with Python script. Error: "Could not resolve hostname when trying to open ssh tunnel"

efirvida

Hello I'm working on simple python ssh tunnel scrpit but I allways receive Could not resolve hostname error, but it works if run it manually. this is my code:

#!/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}')
Marat

subprocess.call expects a list of arguments. When ssh_conection is formed, several arguments are slapped together, so e.g. this part gets quoted into a single argument:

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

Fix: properly split the arguments:

...
    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'
                ]
...

What hinted the problem: IP addresses are used directly. 'cannot be resolved' on an IP address says that it is interpreted as a symbolic name, which makes spotting this easier.

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related