2019-04-27
- Tor isn’t a silver bullet
- Plan #1 — Configuring SOCKS5 proxy in program
- Plan #2 — torsocks
- Plan #3 — iptables + transparent SOCKS client
- Conclusion
Last weekend I was interested in running an application over Tor to calculate some metrics regarding performance. Moreover, this program wasn’t open source yet.
I thought it wouldn’t be problematic since the Tor proxy has a SOCKS5 interface, and there was a high chance that this would be good enough to make it. As you may imagine, that wasn’t the case, and I tried different approaches, from the obvious ones to others more complex.
For a personal history reminder and to help other people who might have the same experience, here is the journey I got into making this work.
But first, the necessary caution.
Tor isn’t a silver bullet
Running a program over Tor would make sense if they only require TCP output connections to work correctly. Moreover, you should know some basics of Tor mechanics to understand that changing Tor circuits might matter depending on what kind of anonymity you try to achieve.
It isn’t a silver bullet for anonymity. With the right amount of effort, statistical analysis can be done considering that Tor exit nodes are public, there could be persistent data in the executable session that can be used to correlate traffic, or some fancy clock-time correlations to leak some information about the user.
Also, running over Tor might break some assumptions the program's author made so that you can get unexpected results or security consequences. Moreover, since exit nodes are public, you must be cautious about unencrypted traffic since you’ll be sniffed with a high chance.
Plan #1 — Configuring SOCKS5 proxy in program
This plan is the most obvious to run an executable behind a proxy: tell the executable to do it. This plan was rapidly dismissed since there wasn’t any flag to configure this.
Plan #2 — torsocks
My next approach was using a process wrapper that would do the work behind the scenes, like torsocks.
Torsocks is an interceptor between the process and the libc library. Since most of the executables use libc it works in most of the cases. Behind the scenes, it utilizes the LD_PRELOAD trick to override shared library methods.
You can install torsocks
with apt get
. This will install torsocks and tor.
$ apt-get update
$ apt-get install torsocks curl
To check that all work as expected we can check our current IP vs the Tor exit IP:
$ curl <https://ifconfig.me>
185.100.86.XXX
$ torsocks curl <https://ifconfig.me>
144.217.164.XXX
If you’re having trouble, check that the tor proxy is running and retry: sudo service tor start
.
Now run the program: torsocks yourpogram arg1 arg1 ...
Unfortunately, in my case, this didn’t work. More precisely, the program worked as if it wasn’t running within the proxy. I ran the ldd
command and checked the executable was dynamically linked to libc, so this should work.
After some minutes of research, I found out that Golang no longer depends on libc for network, for good reasons. If you can avoid that dependency, it’s a good idea to do it. You can find it here if you’re interested in the official discussion about this.
The executable is linked to libc
maybe for other reasons or dependencies. If the program makes syscalls directly, a wrapper interceptor is useless.
Plan #3 — iptables + transparent SOCKS client
In that discussion, a user mentioned that a good solution was using iptables in conjunction with a transparent proxy to tunnel the traffic into the SOCKS5 proxy. In my case, it would be the SOCKS5 of my running Tor proxy.
It’s a smart solution but has challenges. Since the transparent proxy will receive TCP packages with the destination changed by iptables
, a way of identifying the original destination is needed. However, this person is quite smart and already gives a candidate a transparent proxy to implement this solution. Here you can find his initial motivation for building it.
To configure iptables for my needs, I had to add some tricks to make this work:
sudo iptables --table nat -A OUTPUT -p tcp -j REDIRECT --to-ports 1081 -m owner --uid-owner dummytoruser-o wlo1
Some quick explanation of this configuration:
-table nat
refers to adding a rule in the nat table.A OUTPUT
add to the OUTPUT chain.j REDIRECT --to-ports <port>
is where the magic happens.m owner --uid-owner <user> -o wlo1
might seem weird for my purpose, but crucial.
What did I mean by magic? It instructs to change TCP packets destination to localhost:port
. In my case, 1081 is the port where transocks
transparent-proxy is listening. This proxy will get the original TCP packet destination, as explained by Hirotaka, by an undocumented SO_ORIGINAL_DST flag in getsockopt syscall.
The owner
and -o
flags were necessary since I was running transocks
and tor
in the same machine I was trying to run the target program over Tor. I created a dummytoruser
in the computer and set the rule only to apply in processes running in that user. This way, I ran transocks
and tor
in my current user and ran the target program as dummytoruser
. The -o
flag makes this rule in the interface with internet access since it makes no sense (and will fail!) to Torify to private addresses.
Conclusion
Claps to Hirotaka for open-sourcing his work. I had the opportunity to make a tiny PR as a sign of gratitude.
They may be other ways to solve this problem, but despite this might seem a bit complex it may save your day.