开发者

Question about starting SSH tunnel using Python

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 开发者_JAVA百科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).


Instead of os.system(), try using subprocess.Popen() and set close_fds=True (available in Python 2.4 and higher).

import subprocess    
subprocess.Popen("ssh -f -n -N -L 127.0.0.1:%d:localhost:%d user@%s" % (6800, 9000, "remote.machine"), shell=True, close_fds=True)

In theory, I believe you should also be able to use fcntl to set the listening socket's file descriptor to close-on-exec (FD_CLOEXEC) prior to calling os.system().


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.


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:

  • SFTP in Python: Paramiko (Provides a simple example of getting a Transport set up)
  • API Docs: paramiko.Transport (Direct link to the docs for Transport.open_channel)
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜