Все описанное в статье реализовано в виде инструмента Toroxy, доступного на GitHub
В последнее время анонимность в сети является предметом горячих споров. Ни для кого не секрет, что данные о посещениях Интернет-ресурсов с локального устройства могут собираться на разных уровнях с целью построения «модели» пользователя, которая позже против него же и может быть использована (или могла бы). Поэтому не удивительно, что все большее количество активных пользователей Интернета становятся уверены в необходимости механизмов проксирования и анонимизации. В связи с этим появляется все больше новых VPN-клиентов, но, как показывает практика, далеко не всем из них по-настоящему можно доверять: то не все работает из коробки, то анонимизируется только HTTP-трафик, то качество реализации хромает, а то и вовсе разработчики грешат сливанием данных о своих пользователях.

В этой статье мы попробуем собрать из ряда программных компонентов собственный инструмент с UI, который бы позволил полностью анонимизировать трафик локальной системы и не допустить утечек по «прослушиваемым» каналам ни на одном из этапов работы.

Главной нашей целью будет «сборка» надежной утилиты из готовых инструментов. Очевидно, что идея создания с нуля качественного инструмента за разумный срок чревата ошибками, а поэтому бытрее и надежнее будет выбрать готовые компоненты, а затем правильно их связать!

Что должен уметь инструмент?

  1. Перенаправлять весь трафик целевой системы на промежуточные узлы (желательно несколько) для надежной маскировки источника
  2. Отслеживать возможные нарушения анонимности, исправлять их и сообщать о них с помощью UI уведомлений

Выбранные компоненты для создания инструмента:

  • tor
  • iptables
  • python3
  • systemd

Перемешав все компоненты в оболочке под названием «Linux» мы определенно сможем получить что-то стоящее, что поможет достигнуть итоговой цели.

Компонент №1: Tor


Именно вокруг этого компонента будет построена вся остальная инфраструктура инструмента. Tor предоставляет механизм, который находится в составе любого VPN-клиента — механизм заворачивания трафика через промежуточные анонимные для внешнего наблюдателя узлы (в с��андартной конфигурации таких узла 3).

По умолчанию клиент Tor из стандартных пакетных репозиториев после установки начинает слушать порт 9050, принимающий любого клиента, «умеющего» socks. Проблема заключается в том, что помимо socks-трафика в нашей системе может быть куча другого трафика от приложений, не работающих по этому протоколу. В связи с этим прежде всего в пределах локальной системы придется прорубить окно в сеть Tor для любого нового сетевого соединения. Делается это достаточно просто с помощью поднятия transparent proxy в конфигурации torrc:

/etc/tor/torrc
...
TransPort 9040
# а это нам еще понадобится в дальнейшем для автоматизации из python
ControlPort 9051
...

Отдельного внимания заслуживает UDP трафик. Дело в том, что в основе принципа луковой маршрутизации лежит концепция «соединения» (stream), существующего, как известно, только в TCP. Отправив через Tor UDP-пакет, целевая система не сможет получить на него ответ, так как ответный пакет не найдет обратной дороги. Но несмотря на эту особенность, у нас остается возможность анонимизировать DNS запросы, которые, как известно осуществляются по UDP, а заодно и включить .onion резолв:

/etc/tor/torrc
...
AutomapHostsOnResolve 1
DNSPort 53
...

На этом доступ в Tor открыт в пределах loopback'а.

Компонент №2: Iptables


Так как наша задача заключается в сокрытии истинного источника трафика от внешнего наблюдателя в пределах всей системы, а окно в Tor уже открыто, осталось только завернуть весь трафик в это окно. Поможет нам в этом системный файрвол, находящийся в комплекте с ядром Linux:

# заворачиваем 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

На данном этапе мы получаем рабочую утилиту, надежно маскирующую весь исходящий трафик, однако это только половина работы.

Компонент №3: python + Desktop Evironment UI


Каждый раз производить ручную конфигурацию из консоли (даже если это будет запуск bash-скрипта) будет достаточно утомительно, поэтому самое время приступить к написанию небольшой утилиты, помогающей нам конкретно в следующем:

  1. Автоматическая установка конфигурации
  2. Смена своего identity в пределах Tor в любой момент
  3. Отслеживание целостности правил iptables и их перезапись при нарушении
  4. Отслеживание текущего identity (IP)
  5. Уведомление о двух предыдущих пунктах с помощью уведомлений графическогой оболочки

При первом запуске утилита самостоятельно скачает все необходимые компоненты, а при последующих запусках будет конфигурировать Tor в связке с iptables, как описано выше.

При желании смены своего внешнего IP адреса, будет происходить взаимодействие со служебным портом Tor — 9051, открытым в самом начале для автоматизации смены IP:

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

Отслеживание целостности можно реализовать достаточно банально (делаем же на коленке) с помощью периодического чтения структуры правил iptables и проверки их SHA256-суммы:

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

Также при обнаружении несостыковок с ожидаемой контрольной суммой можно сохранить дамп правил iptables в /tmp/broken-rules-%d-%m-%Y_%I-%M-%S.log для дальнейших разбирательств. Если окажется, что
rulesOk() == False
то будет инициирована перезапись таблицы правил iptables.

Наблюдение за текущим IP будет происходить с помощью постоянного обращения на какой-нибудь внешний ресурс, предоставляющий IP-клиента — например, ident.me.

Ну, и напоследок задействуем DE UI для сообщения о проблемах с правилами либо о смене IP. Каждое графическое окружение в каком-то роде уникально, особенно когда речь идет об использовании UI из процесса-демона, но все же на большинстве Linux'ов такой bash-код, вызываемый из 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

Объединив все это в 200-строчном Python скрипте, получаем то, чего добивались. Вот, например, как будет выглядеть уведомление о том, что наш identity обновился:

image

А вот так будет выглядеть уведомление о том, что была нарушена целостность правил Iptables с указанием выгруженного дампа, содержащего нарушение:

image

Компонент №4: systemd


Ну и напоследок нам определенно хотелось бы произвести единоразовую настройку и не думать в дальнейшем о своей безопасности, а потому на помощь приходят автозапуск и сервисы. В Linux есть несколько стандартных подсистем управления демонами: systemd, sysV, init. В нашем случае выбор пал на systemd из-за гибкости его настройки.

Предположим, что написанный в предыдущем шаге python-скрипт называется «toroxy» и лежит в /usr/bin/, тогда его автозапуск и последующий мониторинг с определенной гибкостью управления демоном будет таким:

[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

Почти все готово для «промышленной» эксплуатации. Последний штрих, который хотелось бы внести в инструмент для дополнительной надежности — это автоматическая инициализация правил iptables при запуске системы (как известно, правила iptables при перезагрузке сбрасываются) с помощью iptables-persistent:

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

Заключение


Вот мы и собрали из совокупности разношерстных компонентов собственный инструмент, который с достаточно высокой степенью надежности способен обеспечивать непрерывную анонимность пользователя Linux в сети. В завершение следует сказать, что все описанное в статье реализовано в виде инструмента Toroxy, доступного на GitHub.