Creating SSH tunnels from within Python

By aslakjohansen

The following script creates a secure tunnel over localhost (could be any ssh-capable host you have a login to) pointing to port 80 at google.com. The target could be any port at any host reachable from our gateway host.

We are using the pexpect module to do bidirectional communication with the ssh-command itself. The command basically translates to this one:

ssh tmp@localhost -L 4000:google.com:80 -N

This command will ask for the password of tmp@localhost and we will need to interprete the output of the command in order to figure out if it was successful (e.g. the port could be in use). Hence the need for two-way communication.

If the port turns out to be in use we scanforward through the range [4000,4050]. And the code:

#!/usr/bin/python</code>

# http://pexpect.sourceforge.net/pexpect.html
# http://www.thescripts.com/forum/thread26248.html

import pexpect
import time

thetimeout = 2
port_lower = 4000
port_upper = 4050

def create (via_host, via_user, via_pwd, to_host, to_port):
  for via_port in range(port_lower, port_upper+1):
    cmd = 'ssh '+via_user+'@'+via_host+' -L '+str(via_port)+':'+to_host+':'+str(to_port)+' -N'
    child = pexpect.spawn(cmd, timeout=thetimeout)
    r = child.expect(['.ssword:*', 'Privileged ports can only be forwarded by root.*', pexpect.EOF, pexpect.TIMEOUT])

    if r == 0:
      time.sleep(0.1)
      child.sendline(via_pwd+'\n')
      r = child.expect(['bind: Address already in use.*local forwarding', pexpect.EOF, pexpect.TIMEOUT])

      if   r == 0 or r == 1:
        pass
      elif r == 2:
        return (child, via_port)
      else:
        print "Error: Unknown result from SSH tunneling attempt."
        pass
    else:
      print "Error: You are trying to open a privileged port as an unprivileged user."
  print "Error: Unable to bring up a tunnel within port range ["+str(port_lower)+","+str(port_upper)+"]."
  return (None, -1)

child, port = create("localhost", "tmp", "tmp", "google.com", 80)
print "port = "+str(port)
while (1):
  time.sleep(2)

It seems that WordPress does an excellent job at messing up code inclusions and we are not allowed to upload anything but jpg, jpeg, png, gif, pdf, doc, ppt, odt files. Since the above is python code (where indentation matters) you will have to be creative, sorry . Found a way around this.

Leave a Reply