[Python] How to run a command over an ssh tunnel?

Discussão em 'Python' iniciado por Stack, Abril 13, 2025.

  1. Stack

    Stack Membro Participativo

    I'm trying to automate launches of VNC-clients for multiple remote systems. Currently I achieve that with a LocalForward 15900 127.0.0.1:5900. VNC uses port 5900 by default, which is fine -- there should only be one VNC-server at a time on any machine. But I may some times have multiple VNC-viewers running, so the local port must be dynamic -- and cannot be hardcoded (such as to 15900).

    To make it nicer, I'd like to implement a script, which will:

    1. Find an unused local port (freePort).
    2. SSH into the specified remote computer (as the specified user).
    3. Create a tunnel from the remote 5900 to the local freePort.
    4. Invoke the x11vnc -xkb -display :0 -localhost remotely.
    5. Invoke the vncviewer localhost:freePort locally.

    The first item I do using this method. I then use SSHTunnelForwarder:

    import os
    import paramiko
    import socket
    import sys
    import sshtunnel
    import logging
    from paramiko import SSHClient

    def freePort():
    s = socket.socket()
    s.bind(('localhost', 0))
    port = s.getsockname()[1]
    s.close()
    return port

    logging.basicConfig(level = logging.DEBUG,
    format='%(asctime)s %(message)s')

    try:
    user, host = sys.argv[1].split('@')
    except ValueError:
    host = sys.argv[1]
    user = os.getlogin()

    tunnel = sshtunnel.SSHTunnelForwarder(host, ssh_username = user,
    local_bind_address = ('127.0.0.1', freePort()),
    remote_bind_address = ('127.0.0.1', 5900))
    print(tunnel)


    The above works nicely and prints the following at the end:

    <class 'sshtunnel.SSHTunnelForwarder'> object
    ssh gateway: foo.example.com:23
    proxy: no
    username: meow
    authentication: {'pkeys': [('ssh-rsa', b'081c323ca3b5bb6f157f91984b2cb7b2')]}
    hostkey: not checked
    status: not started
    keepalive messages: disabled
    tunnel connection check: disabled
    concurrent connections: allowed
    compression: not requested
    logging level: ERROR
    local binds: [('127.0.0.1', 21242)]
    remote binds: [('127.0.0.1', 5900)]


    But now I need to launch the remote command (step 4.)... Presumably, I need to use Paramiko's SSHClient() for that, but I don't see, how to do that without starting a whole new ssh-connection. There's got to be a way to issue a command over the already-created tunnel. How would I do that?

    Also: how would I insist on the remote hostkey being verified -- against the known_hosts-database?

    Continue reading...

Compartilhe esta Página