Michael Altfield's gravatar

pycurl through Tor without leaking DNS lookups

This article describes the correct way to use pycurl over Tor, such that both DNS lookup data and HTTP(S) traffic is sent through Tor's SOCKS5 proxy.

If you google "pycurl tor", one of the first results is a stackoverflow post that describes how to configure pycurl using the pycurl.PROXYTYPE_SOCKS5 setting. Indeed, even the tutorial To Russia With Love on the Tor Project's Official Website describes how to pass pycurl through Tor using the pycurl.PROXYTYPE_SOCKS5 setting.

However, using pycurl.PROXYTYPE_SOCKS5 will leak DNS queries associated with your HTTP requests outside of the Tor network! Instead you should use pycurl.PROXYTYPE_SOCKS5_HOSTNAME.

The --socks5-hostname argument was added to libcurl v7.26.0. The pycurl.PROXYTYPE_SOCKS5_HOSTNAME argument wasn't added to pycurl until pycurl v7.19.5.1, which (at the time of writing) was less than 2 months ago!

This article will describe how to install pycurl v7.19.5.1 onto the latest version of TAILS at the time of writing, which is TAILS v1.2.3.

Bad Code

I spent a long time scratching my head this weekend trying to find out why the code snippet provided by the stack exchange link above kept getting suck for about 2 minutes, then timing out with the following error:

amnesia@amnesia: ~$ cat checkTor.py
#!/usr/bin/env python

import pycurl

curl = pycurl.Curl()
curl.setopt( pycurl.URL, 'https://check.torproject.org/' )
curl.setopt( pycurl.PROXY, 'localhost' )
curl.setopt( pycurl.PROXYPORT, 9050 )
curl.setopt( pycurl.PROXYTYPE, pycurl.PROXYTYPE_SOCKS5 )

curl.perform()
amnesia@amnesia: ~$ time ./checkTor.py
Traceback (most recent call last):
  File "./checkTor.py", line 11, in
    curl.perform()
pycurl.error: (6, "Couldn't resolve host name")

real	2m7.311s
user	0m0.036s
sys	0m0.016s

There were few answers on the internet about this issue, but it appears that TAILS' iptables configuration is dropping the dns request (causing a timeout) as its designed to do--to prevent any non-Tor traffic from leaving the computer.

Installing pycurl-7.19.5.1

The solution in TAILS v1.2.3 is to download the latest version of pycurl, install dependencies, build & install it, and rewrite the script using pycurl.PROXYTYPE_SOCKS5_HOSTNAME instead of pycurl.PROXYTYPE_SOCKS5.

# get depends
sudo su -
apt-get update
apt-get -y install gcc python-dev libcurl4-openssl-dev

# download and build pycurl from source
wget http://pycurl.sourceforge.net/download/pycurl-7.19.5.1.tar.gz
tar -xzvf pycurl-7.19.5.1.tar.gz
cd pycurl-7.19.5.1
python setup.py install

Success!

Now that you have the latest version of pycurl in-place (supporting pycurl.PROXYTYPE_SOCKS5_HOSTNAME), you can update the script to match the one shown below.

amnesia@amnesia: ~$ cat checkTor.py
#!/usr/bin/env python

import pycurl

curl = pycurl.Curl()
curl.setopt( pycurl.URL, 'https://check.torproject.org/' )
curl.setopt( pycurl.PROXY, '127.0.0.1' )
curl.setopt( pycurl.PROXYPORT, 9050 )
curl.setopt( pycurl.PROXYTYPE, pycurl.PROXYTYPE_SOCKS5_HOSTNAME )

curl.perform()
amnesia@amnesia: ~$ time ./checkTor.py
<!doctype html>
...
Congratulations. This browser is configured to use Tor.
...
real 0m2.487s
user 0m0.060s
sys 0m0.000s

Protip: Note also that I changed 'localhost' to '127.0.0.1'. This cut over 2 minutes off the query!

Further Reading

Using TAILS is a great way to securely browse the Internet. Anonymity benefits aside, it's just an wonderful security-focused Operating System. It's the only OS I trust when using online banking, and you can even use it to browse facebook on the darknet.

Writing scripts that operate through Tor has a ton of use cases--from academic to military, nonprofit/activist organizations to journalists, and businesses too.

And Tor is designed very carefully to provide you with an anonymous internet experience. When sending DNS through Tor, for example, it not only ensures that the DNS resolver on the side of the exit node has no knowledge of where the request actually originated, it also utilizes stream isolation by default to ensure that a separate Tor Circuit is used for different protocols (IsolateClientProtocol). Moreover, you can also configure Tor to create a unique Circuit for each destination IP Address (IsolateDestAddr) that you're communicating with--or each destination port that you're communicating on (IsolateDestPort). Both of these options (IsolateDestAddr & IsolateDestPort) are enabled in the torrc file in TAILS by default.

Utilizing Host and Port stream isolation further increases your anonymity by reducing the possibility to perform identity correlation attacks from a malicious Tor exit node. For more information on the possible Stream Isolation options in Tor, see the list of possible "[isolation flags]" listed on the Tor Manual under the "SOCKSPort" option.

Related Posts

2 comments to pycurl through Tor without leaking DNS lookups

  • Tom

    Good stuff. Thank you.

  • Anon

    Thank You So Much My Friend!
    I've would spent so much time if I wouldn't found that!
    No one really describes that PROXYTYPE_SOCKS5 changed to PROXYTYPE_SOCKS5_HOSTNAME .
    And It was only issue my script doesn't worked.
    Thank you!

Leave a Reply

You can use these HTML tags

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>