
Все описанное в статье реализовано в виде инструмента Toroxy, доступного на GitHubВ последнее время анонимность в сети является предметом горячих споров. Ни для кого не секрет, что данные о посещениях Интернет-ресурсов с локального устройства могут собираться на разных уровнях с целью построения «модели» пользователя, которая позже против него же и может быть использована (или могла бы). Поэтому не удивительно, что все большее количество активных пользователей Интернета становятся уверены в необходимости механизмов проксирования и анонимизации. В связи с этим появляется все больше новых VPN-клиентов, но, как показывает практика, далеко не всем из них по-настоящему можно доверять: то не все работает из коробки, то анонимизируется только HTTP-трафик, то качество реализации хромает, а то и вовсе разработчики грешат сливанием данных о своих пользователях.
В этой статье мы попробуем собрать из ряда программных компонентов собственный инструмент с UI, который бы позволил полностью анонимизировать трафик локальной системы и не допустить утечек по «прослушиваемым» каналам ни на одном из этапов работы.
Главной нашей целью будет «сборка» надежной утилиты из готовых инструментов. Очевидно, что идея создания с нуля качественного инструмента за разумный срок чревата ошибками, а поэтому бытрее и надежнее будет выбрать готовые компоненты, а затем правильно их связать!
Что должен уметь инструмент?
- Перенаправлять весь трафик целевой системы на промежуточные узлы (желательно несколько) для надежной маскировки источника
- Отслеживать возможные нарушения анонимности, исправлять их и сообщать о них с помощью 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-скрипта) будет достаточно утомительно, поэтому самое время приступить к написанию небольшой утилиты, помогающей нам конкретно в следующем:
- Автоматическая установка конфигурации
- Смена своего identity в пределах Tor в любой момент
- Отслеживание целостности правил iptables и их перезапись при нарушении
- Отслеживание текущего identity (IP)
- Уведомление о двух предыдущих пунктах с помощью уведомлений графическогой оболочки
При первом запуске утилита самостоятельно скачает все необходимые компоненты, а при последующих запусках будет конфигурировать 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 обновился:

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

Компонент №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.
