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)