How to wrap all OS traffic in Tor

CreedX

Unknown
Messages
233
Reputation
4
Reaction score
226
Points
43
Online anonymity has been hotly debated lately. It's not a secret for anyone that data on visits to Internet resources from a local device can be collected at different levels in order to build a "model" of a user, which can later be used against him (or could ). Therefore, it is not surprising that an increasing number of active Internet users are becoming convinced of the need for proxying and anonymization mechanisms. In this regard, more and more new VPN clients appear, but, as practice shows, not all of them can truly be trusted: either not everything works out of the box, then only HTTP traffic is anonymized, then the quality of implementation is lame, or and at all developers sin by merging data about their users.

In this article, we will try to assemble our own tool with a UI from a number of software components, which would allow to completely anonymize the traffic of the local system and prevent leaks through the "listening" channels at any stage of work.

Our main goal will be to "build" a reliable utility from ready-made tools. Obviously, the idea of creating a high-quality tool from scratch in a reasonable time is fraught with mistakes, and therefore it will be faster and more reliable to select ready-made components, and then connect them correctly!

What should a tool be able to do?

  1. Redirect all traffic of the target system to intermediate nodes (preferably several) to reliably mask the source
  2. Track potential breaches of anonymity, correct them and report them using UI notifications
Selected components for creating the tool:

  • tor
  • iptables
  • python3
  • systemd
By mixing all the components in a shell called "Linux" we can definitely get something worthwhile that will help achieve the final goal.

Component # 1: Tor​

It is around this component that the rest of the tool infrastructure will be built. Tor provides a mechanism that is part of any VPN client - a mechanism for wrapping traffic through intermediate anonymous nodes for an external observer (in the standard configuration there are 3 such nodes).

By default, the Tor client from the standard batch repositories after installation starts listening to port 9050, accepting any client that knows how to do socks. The problem is that in addition to socks traffic, our system may contain a bunch of other traffic from applications that do not work using this protocol. In this regard, first of all, within the local system, you will have to open a window to the Tor network for any new network connection. This is done quite simply by raising the transparent proxy in the configuration torrc :
Bash:
/etc/tor/torrc
...
TransPort 9040
# а это нам еще понадобится в дальнейшем для автоматизации из python
ControlPort 9051
...

UDP traffic deserves special attention. The point is that onion routing is based on the concept of a stream, which, as you know, exists only in TCP. Having sent a UDP packet through Tor, the target system will not be able to receive a response to it, since the response packet will not find a way back. But despite this feature, we still have the opportunity to anonymize DNS requests, which, as you know, are carried out over UDP, and at the same time enable .onion resolution:
Bash:
/etc/tor/torrc
...
AutomapHostsOnResolve 1
DNSPort 53
...

On this, access to Tor is open within the loopback.

Component №2: Iptables​

Since our task is to hide the true source of traffic from an external observer within the entire system, and the window in Tor is already open, it remains only to wrap all traffic in this window. The system firewall included with the Linux kernel will help us with this:

Bash:
# заворачиваем tcp
iptables -t nat -A OUTPUT -p tcp --syn -j REDIRECT --to-ports $TRANS_PORT
# заворачиваем частично udp (dns only)
iptables -t nat -A OUTPUT -p udp --dport 53 -j REDIRECT --to-ports 53
iptables -A OUTPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
# запрещаем всему остальному трафику покидать систему
iptables -A OUTPUT -j REJECT
ip6tables -A OUTPUT -j REJECT

At this stage, we get a working utility that reliably masks all outgoing traffic, but this is only half the work.

Component №3: python + Desktop Evironment UI​

Each time, manual configuration from the console (even if it is running a bash script) will be quite tedious, so it's time to start writing a small utility that helps us specifically in the following:

  1. Automatic configuration setting
  2. Change your identity within Tor at any time
  3. Tracking the integrity of iptables rules and rewriting them if violated
  4. Tracking the current identity (IP)
  5. Notification of the previous two items using GUI notifications
At the first start, the utility will automatically download all the necessary components , and on subsequent launches it will configure Tor in conjunction with iptables, as described above.

If you want to change your external IP address, you will interact with the service port Tor - 9051, opened at the very beginning to automate the IP change:

Python:
with Controller.from_port(port = 9051) as controller:
    controller.authenticate()
    controller.signal(Signal.NEWNYM)

Integrity tracking can be implemented quite trivially (we do the same on the knee) by periodically reading the structure of iptables rules and checking their SHA256 sum:

Python:
def rulesOk(self):
    RULES_CHECKSUM_CMD = "{ iptables-save && ip6tables-save; } | sed s/\-\-uid\-owner\\\\s[0-9]\\\\+\\\\s//g | grep -viE '^#' | grep -viE '^\:' | sort | uniq | sha256sum | cut -d' ' -f 1"
    checkSum = getoutput(RULES_CHECKSUM_CMD).strip()
    alright = checkSum == Strings.RULES_CHECKSUM_CORRECT_HASH

    if not alright:
        rules = getoutput('iptables-save && ip6tables-save')
        self.lastSnapshotFileName = "/tmp/broken-rules-%s.log" % time.strftime("%d-%m-%Y_%I-%M-%S")
        open(self.lastSnapshotFileName, "w").write(rules)
        return False
     else:
         return True

Code:
Also if you find inconsistencies with the expected checksum you can save a dump of iptables rules to /tmp/broken-rules-%d-%m-%Y_%I-%M-%S.log for further investigation. If it turns out,чтоrulesOk() == False

this will initiate a rewrite of the iptables rule table.

Monitoring the current IP will be done by constantly accessing some external resource that provides an IP client - for example, ident.me.

Well, and finally, we will use DE UI to report problems with the rules or change the IP. Each graphical environment is in some way unique, especially when it comes to using the UI from a daemon process, but still on most Linuxes, such bash code called from Python will successfully show notifications:

Python:
# root UI
eval "export $(egrep -z DBUS_SESSION_BUS_ADDRESS /proc/$(pgrep -u $LOGNAME gnome-session)/environ)"

export DISPLAY=:0
for USR in `ls /home && echo root`
do
    # ubuntu gnome + root UI
    export XAUTHORITY=/home/$USR/.Xauthority
    notify-send -u {0} '{1}' '{2}'

    # ubuntu parallels
    for UID in `ls /run/user/`
    do
        su $USR -c "DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/$UID/bus notify-send -u {0} '{1}' '{2}'"
    done
done

Putting it all together in a 200-line Python script, we get what we wanted. For example, here's how the notification that our identity has been updated will look like:

1620006317000.png


And this is how a notification will look like that the integrity of the Iptables rules has been violated, indicating an uploaded dump containing a violation:

1620006346000.png


Component # 4: systemd​

And finally, we would definitely like to make a one-time setup and not think about our safety in the future, and therefore autorun and services come to the rescue. Linux has several standard daemon management subsystems: systemd, sysV, init. In our case, the choice fell on systemd due to the flexibility of its configuration.

Suppose that the python script written in the previous step is called "toroxy" and lies in /usr/bin/, then its autorun and subsequent monitoring with a certain flexibility of daemon control will be like this:
Code:
[Unit]
Description=Toroxy
After=network.target
StartLimitIntervalSec=0

[Service]
Type=simple
Restart=always
RestartSec=1
User=root
# service toroxy start
ExecStart=/usr/bin/toroxy service
# service toroxy stop
ExecStop=/usr/bin/toroxy stop
# service toroxy reload
ExecReload=/usr/bin/toroxy switch

[Install]
# запускаемся на init 3, чтобы с пользовательского уровня до загрузки UI трафик уже шел через Tor
WantedBy=multi-user.target

Almost everything is ready for "industrial" operation. The final touch that I would like to add to the tool for added reliability is the automatic initialization of iptables rules at system startup (as you know, iptables rules are reset on reboot) using iptables-persistent:

Bash:
iptables-save > /etc/iptables/rules.v4
ip6tables-save > /etc/iptables/rules.v6
netfilter-persistent start && netfilter-persistent save

Conclusion​

So we have assembled our own tool from a set of diverse components, which, with a sufficiently high degree of reliability, is capable of providing continuous anonymity of a Linux user on the network. In conclusion, it should be said that everything described in the article is implemented in the form of the tool Toroxy available on GitHub.
 
Top