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:
freePort
).freePort
.x11vnc -xkb -display :0 -localhost
remotely.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?
Ended up using the actual ssh-client as below. Would've liked a Python-solution...
import os
import socket
import sys
import time
def freePort():
s = socket.socket()
s.bind(('localhost', 0))
port = s.getsockname()[1]
s.close()
return port
port = freePort()
os.system("ssh -f -n -L %d:localhost:5900 %s exec x11vnc -xkb -display :0 -localhost" %
(port, sys.argv[1]))
time.sleep(2) # Remote takes a few seconds to get ready
os.system("exec env LANG=C vncviewer localhost:%d" % port)