txsocksx
is SOCKS4/4a and SOCKS5 client endpoints for Twisted 10.1 or
greater. The code is available on github: https://github.com/habnabit/txsocksx
These examples assume familiarity with how to use Twisted endpoints. For simplicity, most of the examples will use SOCKS5.
One specifies authentication methods to a SOCKS5ClientEndpoint
via the
methods parameter. For example, to connect using the username spam
and
password eggs
:
exampleEndpoint = SOCKS5ClientEndpoint( 'example.com', 6667, proxyEndpoint, methods={'login': ('spam', 'eggs')})
However, this will disable anonymous authentication. To use either login or anonymous authentication, specify both methods:
exampleEndpoint = SOCKS5ClientEndpoint( 'example.com', 6667, proxyEndpoint, methods={'login': ('spam', 'eggs'), 'anonymous': ()})
The methods
dict must always map from a string to a tuple.
SOCKS4 has no authentication, but does have a configurable "user ID" which defaults to an empty string:
exampleEndpoint = SOCKS4ClientEndpoint( 'example.com', 6667, proxyEndpoint, user='spam')
To connect to example.com
on port 6667 over tor, one creates a
SOCKS5ClientEndpoint
wrapping the endpoint of the tor server:
torServerEndpoint = TCP4ClientEndpoint(reactor, '127.0.0.1', 9050) exampleEndpoint = SOCKS5ClientEndpoint('example.com', 6667, torServerEndpoint)
Establishing the connection from there proceeds like usual:
deferred = exampleEndpoint.connect(someFactory)
txsocksx
will not do any DNS resolution, so the hostname example.com
will not leak; tor will receive the hostname directly and do the DNS lookup
itself.
Tor allows connections by SOCKS4 or SOCKS5, and does not expect a user ID to be sent when using the SOCKS4 client.
Sometimes one tires of waiting and wants to abort the connection attempt. For example, to abort the whole connection attempt after ten seconds:
torServerEndpoint = TCP4ClientEndpoint(reactor, '127.0.0.1', 9050) exampleEndpoint = SOCKS5ClientEndpoint('example.com', 6667, torServerEndpoint) deferred = exampleEndpoint.connect(someFactory) reactor.callLater(10, deferred.cancel)
This is a trivial example; real code should cancel the IDelayedCall returned
by reactor.callLater
when the deferred fires. The code would then look like
this:
torServerEndpoint = TCP4ClientEndpoint(reactor, '127.0.0.1', 9050) exampleEndpoint = SOCKS5ClientEndpoint('example.com', 6667, torServerEndpoint) deferred = exampleEndpoint.connect(someFactory) canceler = reactor.callLater(10, deferred.cancel) def cancelCanceler(result): if canceler.active(): canceler.cancel() return result deferred.addBoth(cancelCanceler)
Twisted's builtin Agent HTTP client did not support being handed an
arbitrary endpoint before 15.0, so txsocksx
provides an Agent
for maximum
compatibility.
While txsocksx
requires only Twisted 10.1, txsocksx.http
requires Twisted
12.1 or greater. Its usage is almost identical to normal Agent
usage:
torServerEndpoint = TCP4ClientEndpoint(reactor, '127.0.0.1', 9050) agent = SOCKS5Agent(reactor, proxyEndpoint=torServerEndpoint) deferred = agent.request('GET', 'http://example.com/')
Note that the proxyEndpoint
parameter must be passed as a keyword
argument. There is a second, optional, keyword-only argument for passing
additional arguments to the SOCKS5ClientEndpoint
as SOCKS5Agent
constructs it:
torServerEndpoint = TCP4ClientEndpoint(reactor, '127.0.0.1', 9050) agent = SOCKS5Agent(reactor, proxyEndpoint=torServerEndpoint, endpointArgs=dict(methods={'login': ('spam', 'eggs')})) deferred = agent.request('GET', 'http://example.com/')
SOCKS5Agent
transparently supports HTTPS via TLSWrapClientEndpoint
.
For users with Twisted 15.0 or greater, SOCKS5Agent
also implements
IAgentEndpointFactory.
Sometimes one wants to switch to speaking TLS as soon as the proxy negotiation
is finished. For that, there is txsocksx.tls
. After wrapping an endpoint with
TLSWrapClientEndpoint
, the connection will be upgraded to using TLS
immediately after proxy negotiation finishes:
torServerEndpoint = TCP4ClientEndpoint(reactor, '127.0.0.1', 9050) exampleEndpoint = SOCKS5ClientEndpoint('example.com', 6667, torServerEndpoint) tlsEndpoint = TLSWrapClientEndpoint(exampleEndpoint) deferred = tlsEndpoint.connect(someFactory)
Because of txsocksx
's composable design, it's trivial to connect from one SOCKS
proxy to another:
torServerEndpoint = TCP4ClientEndpoint(reactor, '127.0.0.1', 9050) firstProxyEndpoint = SOCKS5ClientEndpoint( 'first-proxy.example.com', 1080, torServerEndpoint) secondProxyEndpoint = SOCKS4ClientEndpoint( 'second-proxy.example.com', 1080, firstProxyEndpoint) finalHop = SOCKS5ClientEndpoint( 'example.com', 113, secondProxyEndpoint) deferred = finalHop.connect(someFactory)