SSH to SSH proxy in Twisted using Conch

Viewed 232

I'm trying to write an SSH proxy in Twisted, that intercepts SSH traffic and forwards it to a back-end ssh server.

On the front-end I'm using a modified Conch, with the following code subclassed as SSHSession:

def request_exec(self, data):
    cmd,data = common.getNS(data)
    log.msg('executing command "%s"' % cmd)
    prot = session.SSHSessionClient()
    prot.transport = self
    pf = _ProtocolFactory(prot)
    ep = endpoints.SSHCommandClientEndpoint.newConnection(reactor, cmd,
        USER, HOST, port=PORT, password=PASSWORD)
    ep.connect(pf)
    self.client = prot
    return 1

The _ProtocolFactory class looks like this:

class _ProtocolFactory():
    """
    Factory to return the (existing) ssh session to pass to ssh command endpoint
    It does not actually function as a factory
    """

    def __init__(self, protocol):
        self.protocol = protocol


    def buildProtocol(self, addr):
        return self.protocol

The entire thing accepts connections from users, and I can see it successfully logs in into the back-end.

The issue I'm having is with connecting the stdout/stdin channels to each other. The SSHSession on the back-end connection needs to be connected to the SSHSession on the front-end. I've tried to do that with the Protocol as an in-between, but I don't think this is correct.

Update: one-way data transfer is working by using a custom Protocol that translates client/server functions around (so dataReceived is mapped to write, and vice versa:

class InBetween(protocol.Protocol):
    """
    This is the glue between the SSH server one one side and the
    SSH client on the other side
    """
    transport = None # Transport is the back-end the ssh-server
    client = None # Client is the front-end, the ssh-client
    buf = "" # buffer to send to back-end

    def write(self, bytes):
        # This is data going from the end-user to the back-end
        if not self.transport:
            self.buf += bytes
            return
        elif len(self.buf) and self.transport != None:
            self.transport.dataReceived(self.buf)
            self.buf = None
        self.transport.dataReceived(bytes)

   def dataReceived(self, data):
        # This is data going from the back-end to the end-user
        self.client.write(data)
0 Answers
Related