##// END OF EJS Templates
added basic tunneling with ssh or paramiko
added basic tunneling with ssh or paramiko

File last commit:

r3571:9b5cebba
r3571:9b5cebba
Show More
tunnel.py
123 lines | 3.3 KiB | text/x-python | PythonLexer
#-----------------------------------------
# Imports
#-----------------------------------------
from __future__ import print_function
import os,sys
from multiprocessing import Process
from getpass import getpass, getuser
try:
import paramiko
except ImportError:
paramiko = None
else:
from forward import forward_tunnel
from IPython.external import pexpect
def launch_ssh_tunnel(lport, rport, server, remoteip='127.0.0.1', keyfile=None, timeout=15):
"""Create an ssh tunnel using command-line ssh that connects port lport
on this machine to localhost:rport on server. The tunnel
will automatically close when not in use, remaining open
for a minimum of timeout seconds for an initial connection.
"""
ssh="ssh "
if keyfile:
ssh += "-i " + keyfile
cmd = ssh + " -f -L %i:127.0.0.1:%i %s sleep %i"%(lport, rport, server, timeout)
tunnel = pexpect.spawn(cmd)
failed = False
while True:
try:
tunnel.expect('[Pp]assword:', timeout=.1)
except pexpect.TIMEOUT:
continue
except pexpect.EOF:
if tunnel.exitstatus:
print (tunnel.exitstatus)
print (tunnel.before)
print (tunnel.after)
raise RuntimeError("tunnel '%s' failed to start"%(cmd))
else:
return tunnel.pid
else:
if failed:
print("Password rejected, try again")
tunnel.sendline(getpass())
failed = True
def _split_server(server):
if '@' in server:
username,server = server.split('@', 1)
else:
username = getuser()
if ':' in server:
server, port = server.split(':')
port = int(port)
else:
port = 22
return username, server, port
def launch_paramiko_tunnel(lport, rport, server, remoteip='127.0.0.1', keyfile=None):
"""launch a tunner with paramiko in a subprocess"""
if paramiko is None:
raise ImportError("Paramiko not available")
server = _split_server(server)
if keyfile is None:
passwd = getpass("%s@%s's password: "%(server[0], server[1]))
else:
passwd = None
p = Process(target=_paramiko_tunnel,
args=(lport, rport, server, remoteip),
kwargs=dict(keyfile=keyfile, password=passwd))
p.daemon=False
p.start()
return p
def _paramiko_tunnel(lport, rport, server, remoteip, keyfile=None, password=None):
"""function for actually starting a paramiko tunnel, to be passed
to multiprocessing.Process(target=this).
"""
username, server, port = server
client = paramiko.SSHClient()
client.load_system_host_keys()
client.set_missing_host_key_policy(paramiko.WarningPolicy())
try:
client.connect(server, port, username=username, key_filename=keyfile,
look_for_keys=True, password=password)
except Exception as e:
print ('*** Failed to connect to %s:%d: %r' % (server, port, e))
sys.exit(1)
print ('Now forwarding port %d to %s:%d ...' % (lport, server, rport))
try:
forward_tunnel(lport, remoteip, rport, client.get_transport())
except KeyboardInterrupt:
print ('C-c: Port forwarding stopped.')
sys.exit(0)
__all__ = ['launch_ssh_tunnel', 'launch_paramiko_tunnel']