Nested SSH session with Paramiko
I managed to find a solution, but it requires a little manual work. If anyone have a better solution, please tell me.
ssh = paramiko.SSHClient()ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())ssh.connect('first.com', username='luser', password='secret')chan = ssh.invoke_shell()# Ssh and wait for the password prompt.chan.send('ssh second.com\n')buff = ''while not buff.endswith('\'s password: '): resp = chan.recv(9999) buff += resp# Send the password and wait for a prompt.chan.send('secret\n')buff = ''while not buff.endswith('some-prompt$ '): resp = chan.recv(9999) buff += resp# Execute whatever command and wait for a prompt again.chan.send('ls\n')buff = ''while not buff.endswith('some-prompt$ '): resp = chan.recv(9999) buff += resp# Now buff has the data I need.print 'buff', buffssh.close()
The thing to note is that instead of this
t = ssh.get_transport()chan = t.open_session()chan.get_pty()
...you want this
chan = ssh.invoke_shell()
It reminds me of when I tried to write a TradeWars script when I was a kid and gave up coding for ten years. :)
Here is a small example using paramiko only (and port forwarding):
import paramiko as sshclass SSHTool(): def __init__(self, host, user, auth, via=None, via_user=None, via_auth=None): if via: t0 = ssh.Transport(via) t0.start_client() t0.auth_password(via_user, via_auth) # setup forwarding from 127.0.0.1:<free_random_port> to |host| channel = t0.open_channel('direct-tcpip', host, ('127.0.0.1', 0)) self.transport = ssh.Transport(channel) else: self.transport = ssh.Transport(host) self.transport.start_client() self.transport.auth_password(user, auth) def run(self, cmd): ch = self.transport.open_session() ch.set_combine_stderr(True) ch.exec_command(cmd) retcode = ch.recv_exit_status() buf = '' while ch.recv_ready(): buf += ch.recv(1024) return (buf, retcode)# The example below is equivalent to# $ ssh 10.10.10.10 ssh 192.168.1.1 uname -a# The code above works as if these 2 commands were executed:# $ ssh -L <free_random_port>:192.168.1.1:22 10.10.10.10# $ ssh 127.0.0.1:<free_random_port> uname -ahost = ('192.168.1.1', 22)via_host = ('10.10.10.10', 22)ssht = SSHTool(host, 'user1', 'pass1', via=via_host, via_user='user2', via_auth='pass2')print ssht.run('uname -a')