[Twisted-Python] Tunneling using conch (with application.service)

exarkun at twistedmatrix.com exarkun at twistedmatrix.com
Sat Aug 8 12:49:25 EDT 2009


On 6 Aug, 03:47 pm, smhollingsworth at gmail.com wrote:
>I 19ve got an app written that runs as a service using
>twisted.application.service that I need to tunnel through SSH. Right 
>now, I
>use a script that makes use of Paramiko (and runs separate from my app) 
>to
>set up a tunnel. That more or less works, but I 19ve had some problems 
>with
>the tunnel just going away and would like to integrate the tunneling 
>into
>the app, using conch. I 19ve found an example of tunneling via conch, at
>http://twistedmatrix.com/pipermail/twisted- 
>python/2009-February/019196.html,
>that I think I can use as a base to add the code to my app.
>
>Right now my app is basically:
>
>class DataPuller(service.Service):
>    ...Code for my app...
>    ... The app pulls data from a database and I can only connect to the
>server via SSH...
>
>application = service.Application( 18Data_puller 19)
>dpService = DataPuller()
>dpService.setServiceParent(application)
>
>My main problems are that I 19m not sure whether or not the example 
>linked to
>above is a good one for tunneling with conch and, if it is, how do I 
>merge
>the example tunneling code with my app code. From the example, where 
>the
>code is:

The example you linked to sets up the traditional port forwarding 
behavior.
A local port is opened and connections to it are tunneled over the SSH
connection, where data is then delivered to some address accessible from
the server on the other end of the SSH connection.

This is fine and should work, and probably very closely mirrors what 
you're
doing with Paramiko, so if you're happy with that, you should go for it.

However, it's also possible for you to do this tunneling without opening
the extra local port.  Since your application and the SSH client code 
are
all in the same process, you don't need the TCP connection to a local 
port
to do this IPC to interact wiht the tunnel.  You can set up the tunnel 
part
of things, but instead of binding a local port to accept connections on,
you can just open a connection over the tunnel and write bytes into it 
with
API calls.

I *don't* have an example of doing things this way, and I don't even 
know
exactly what it involves. ;)  However, the example you linked to gives a
clue about where to start on this approach: when it binds the local 
port,
it uses the forwarding.SSHListenForwardingFactory factory, so I'd start
by looking at that class and see what it does.  The rest is just 
mimicking
its behavior without actually using reactor.listenTCP.
>class Connection(connection.SSHConnection):
>        .
>        .
>        .
>        def serviceStarted(self):
>
>Do I instantiate my DataPuller class there, in serviceStarted (and not
>subclass from service.Service)? If so, how do I wrap the tunneling code 
>so
>that I can make it a service? If not, do I need put the tunneling code
>inside my DataPuller class? What would that look like?

If you want things to happen when your program starts or when it is 
about
to stop, then using service.Service is still a good idea.  That's the 
easy
way to hook into startup and shutdown events.  However, you may not want
to do anything other than set up (or tear down) the SSH connection in 
your
service.Service subclass.  Creating your new non-Service DataPuller in 
the
Connection's serviceStarted (or maybe even a little later - after you
actually set up the connection over the tunnel over the connection) then
makes sense.

Jean-Paul



More information about the Twisted-Python mailing list