tags:

views:

122

answers:

2

I have ran into trouble while starting SSH tunnel from HTTP RPC server written in Python.

There is a simple HTTP RPC server written in Python based on Python's BaseHTTPServer. As a part of one of the services I would like to start a SSH tunnel from the RPC server to a remote machine. I used os.system to start the SSH tunnel in the Python script invoked by the RPC call

os.system("ssh -f -n -N -L 127.0.0.1:%d:localhost:%d user@%s" % (6800, 9000, "remote.machine"))

At first sight all seems to be well as the tunnel is started and I can use it, but there is one thing I noticed. In addition to listening on the port 6800 SSH started listening on port 8001 as well (the port that the HTTP RPC server runs on).

Here is output of lsof regarding the RPC server and SSH:

rpc.py    27763   usern    5u  IPv4 102130428       TCP 127.0.0.1:8001 (LISTEN)
ssh        1951   usern   14u  IPv4 102149728       TCP 127.0.0.1:6800 (LISTEN)
ssh        1951   usern    5u  IPv4 102130428       TCP 127.0.0.1:8001 (LISTEN)

Everything works until RPC server's restart. During restart the RPC server is forced to close his connection to the listening socket but the SSH's connection remains open and RPC server can not start on the same port again.

It seems that the SSH tunnel also somehow associates itself with the fd of the RPC server's listening socket.

Could anybody give hints how to set up the SSH tunnel from the script with it only listening on the supposed port (6800 in this example).

A: 

I suspect this has something to do with forking and then telling ssh to detach from the calling process ("-f").

Also, not sure if this will help, but you should really use the subprocess module if your python is modern enough to have it.

JanC
+1  A: 

Have you considered using paramiko for your SSH? (depends on PyCrypto, but otherwise pure Python)

That'd make managing the connection simpler and, depending on how your server deals with sockets, you may just be able to set up a paramiko Channel and then let the server treat it as it would any other listening socket.

(in paramiko, Transport objects represent the basic SSH2 connections and, for each Transport, you can create multiple Channel objects, each of which acts as a drop-in replacement for a regular Python socket)

Here are some resources in case you want to take a look:

ssokolow
Any progress? We generally do better at helping people if they give status updates.
ssokolow