txtorcon icon indicating copy to clipboard operation
txtorcon copied to clipboard

Adding support for tunneling an existing TLS tunnel through tor

Open eayin2 opened this issue 9 years ago • 4 comments

I'd like to tunnel my TLS tunnel through tor, so that overall i'd have a tunnel like this: tor(TLS(my_protocol)). Not sure if this is possible, maybe a convenience method (server and client side) to start TLS later is the way to add support for it.

With txsocksx (which implements TLSWrapClientEndpoint with the help of TLSMemoryBIOFactory -> http://twistedmatrix.com/documents/current/api/twisted.protocols.tls.html ) it works like this: client.py

from __future__ import print_function

from twisted.internet.task import react
from twisted.internet.defer import inlineCallbacks
from twisted.internet.endpoints import TCP4ClientEndpoint
from twisted.python.filepath import FilePath
from twisted.internet import ssl, task, protocol, endpoints, defer
from twisted.python.modules import getModule
from txsocksx.tls import TLSWrapClientEndpoint
from txsocksx.client import SOCKS5ClientEndpoint

import other_proto


@defer.inlineCallbacks
def main(reactor):
    factory = protocol.Factory.forProtocol(other_proto.something)
    ca_data = FilePath(b'ca_cert.pem').getContent()
    client_data = FilePath(b'a.client.pem').getContent()
    ca_cert = ssl.Certificate.loadPEM(ca_data)
    client_key = ssl.PrivateCertificate.loadPEM(client_data)
    options = ssl.optionsForClientTLS(u'the-authority', ca_cert, client_key)
    torServerEndpoint = TCP4ClientEndpoint(reactor, '127.0.0.1', 9050)
    exampleEndpoint = SOCKS5ClientEndpoint("remote_ip_here", 1234, torServerEndpoint)
    tlsEndpoint = TLSWrapClientEndpoint(options, exampleEndpoint)
    deferred = yield tlsEndpoint.connect(factory)
    done = defer.Deferred()
    deferred.connectionLost = lambda reason: done.callback(None)
    yield done

task.react(main)  

server.py

import sys

from twisted.python.filepath import FilePath
from twisted.internet import ssl, protocol, task, defer, endpoints
from twisted.python import log
from twisted.python.modules import getModule
from twisted.protocols.basic import LineReceiver
from twisted.protocols.tls import TLSMemoryBIOFactory

import other_proto


def main(reactor):
    log.startLogging(sys.stdout)
    ca_data = FilePath('ca_cert.pem').getContent()
    ca_cert = ssl.Certificate.loadPEM(ca_data)
    ca_key = ssl.PrivateCertificate.loadPEM(ca_data)
    factory = protocol.Factory.forProtocol(other_proto.example)
    options = ca_key.options(ca_cert)
    tlsFactory = TLSMemoryBIOFactory(options, False, factory)
    reactor.listenTCP(1234, tlsFactory)
    return defer.Deferred()


task.react(main)

I also tried startTLS with which I inconveniently started TLS within my protocol implementation at a later time, so i guess txsocksx implementation is the way to go.

eayin2 avatar Feb 01 '16 21:02 eayin2

Did you try something like:

endpoint = txtorcon.TorClientEndpoint(server_ip, server_port)
tlsEndpoint = TLSWrapClientEndpoint(options, endpoint)

meejah avatar Feb 06 '16 20:02 meejah

p.s. this would make a good addition to the examples/ if you get it working :)

meejah avatar Feb 06 '16 20:02 meejah

Yes, that worked fine with txtorcon.TorClientEndpoint. Thanks for the hint. I had to specifically provide socks_hostname='127.0.0.1', else (i think) it'd pick automatically the ipv6 localhost ::1.

client.py

from twisted.internet.task import react
from twisted.internet.defer import inlineCallbacks
from twisted.internet.endpoints import TCP4ClientEndpoint
from twisted.python.filepath import FilePath
from twisted.internet import ssl, task, protocol, endpoints, defer
from twisted.python.modules import getModule
from txsocksx.tls import TLSWrapClientEndpoint
import txtorcon

import other_proto


@defer.inlineCallbacks
def main(reactor):
    factory = protocol.Factory.forProtocol(other_proto.DecisionProtocol)
    ca_data = FilePath(b'ca_cert.pem').getContent()
    client_data = FilePath(b'a.client.pem').getContent()
    ca_cert = ssl.Certificate.loadPEM(ca_data)
    client_key = ssl.PrivateCertificate.loadPEM(client_data)
    options = ssl.optionsForClientTLS(u'the-authority', ca_cert, client_key)
    exampleEndpoint = txtorcon.TorClientEndpoint(ip, 8966, socks_hostname="127.0.0.1")
    tlsEndpoint = TLSWrapClientEndpoint(options, exampleEndpoint)
    deferred = yield tlsEndpoint.connect(factory)
    done = defer.Deferred()
    deferred.connectionLost = lambda reason: done.callback(None)
    yield done


task.react(main)

eayin2 avatar Feb 07 '16 11:02 eayin2

@meejah is it possible to achieve this behaviour using this on client?

tor = yield txtorcon.launch() #launch fresh tor ep=tor.stream_via(host,port,tls=True,socks_endpoint=SSL4ClientEndpointTwistedInstance) #connect to server (host, port) using tls and already created twisted TLS instance ep.connect(someFactory)

From what I understand, using txsocksx is not necessary from 2017, but I couldn't find any other sources for this tls usage.

xplsek03 avatar Aug 17 '19 20:08 xplsek03