torxy - прозрачный HTTP/HTTPS-прокси, позволяющий перенаправлять трафик на выбранные домены через TOR-сервер.
Посылами к созданию проекта послужили три причины: блокировки некоторых сайтов, вызванные этим неудобства и полное отсутствие готовых решений. Разумеется, всегда можно завернуть вообще весь трафик в VPN, однако это имеет свои очевидные неудобства. Городить же ужасающие дикие костыли в виде резолвинга доменов в IP для их последующей хитрой маршрутизации это тоже такое себе решение. Хотелось иметь просто прозрачный HTTP/HTTPS-прокси, который можно установить на роутер и заворачивать в TOR не все сайты, а только необходимые.
Какие были пожелания, что прокси должен уметь:
- Работать в прозрачном режиме;
- Извлекать из запросов название домена и на основании заданных правил либо проксировать запрос "как есть", либо оборачивать в SOCKS и перенаправлять в TOR-сервер;
- Поддерживать Server Name Indication, чтобы обрабатывать не только HTTP/1.1, но также и TLS;
Проведённые изыскания готовых решений показали полное отсутствие таковых. Наиболее подходящим на первый взгляд показался проект python-proxy. Однако он не умеет работать в прозрачном режиме и вообще не поддерживает SNI. Идея его допатчить до состояния стояния быстро пропала после изучения исходников, в которых скрупулёзно реализована абстрактная фабрика виртуальных метаклассов c шаблонными методами.
В итоге стало ясно, что придётся засучить рукава и взяться за дело самому.
Проект предназначен для сугубо личного использования в небольшой (домашней) локальной сети. На серьёзную нагрузку не рассчитывался и вообще написан "на скорую руку" за один день как "pet-project". Однако, это не значит, что он не работает или работает плохо. Просто применять его следует по назначению.
torxy принимает запросы, извлекает из них название домена и в зависимости от заданных правил либо пропускает запрос "как есть", без изменений, либо направляет в SOCKS5-сервер, встроенный в TOR-сервер. Запросы, которые не были распознаны как HTTP или HTTPS, будут пропущены "как есть".
- Нет поддержки авторизации в SOCKS. Просто потому, что сам прокси и TOR-сервер работают на одном хосте и делать ещё и авторизацию было бы излишне параноидально;
- Поддерживаются только TLS-подключения, в которых есть SNI. TLS-подключения без SNI будут обрабатываться "как есть", поскольку название хоста при этом неизвестно;
Первым делом требуется добавить на интерфейс lo
адрес 169.254.254.254/32
.
Это необходимо потому, что нельзя просто взять и сделать DNAT на адрес из сети
127.0.0.0/8. Потому как при настройках по-умолчанию ядро воспринимает такие пакеты
как martian. Это можно отключить,
но лучше не надо.
Добавляем адрес:
ip addr add 169.254.254.254/32 dev lo
Далее, для прозрачного проксирования нужно добавить правило DNAT:
iptables \
-A PREROUTING \
-s $LAN \
-p tcp -m multiport --dports http,https \
-j DNAT --to-destination 169.254.254.254:3128
Где $LAN
- адрес локальной сети, например 10.193.68.0/24
.
Настройки TOR-сервера выходят за рамки данного мануала, лучше будет обратиться к официальной документации. Для работы прокси нужно чтобы TOR-сервер принимал подключения по протоколу SOCKS5 без авторизации на порту 9050 (или любом другом).
Вариантов настройки DNS для зоны .onion
много, один из них таков. В конфиге
dnsmasq.conf
добавляем запись:
address=/onion/$ROUTER
Где $ROUTER
- локальный адрес роутера. Тогда любой домен в зоне .onion
будет
указывать на роутер, что в итоге приведёт к попаданию запроса в прокси, который
с этим уже разберётся.
Запрос, подпадающий под правило, будет направлен в SOCKS-сервер, предоставляемый сервером TOR.
Важно! Поиск по списку правил выполняется за O(n). То есть, не стоит добавлять туда слишком много правил, иначе запросы начнут дичайше тормозить.
Конфиг с правилами по-умолчанию находится в файле /etc/torxy.rules
. По одному
правилу на строку. Строки, начинающиеся с символа #
считаются комментариями.
Сравнение производится до первого совпадения. Сравнение выполняется методом
вхождения подстроки в строку. Регулярные выражения не поддерживаются. Под сравнение
подпадают только имена хостов (заголовок Host:
в HTTP или SNI в TLS), URL не
поддерживаются.
Примеры правил:
# Вся зона .onion.
.onion
# Один отдельный сайт.
homedepot.com
Сравнение по методу вхождения подстроки в строку подразумевает, что заданное правило ищется как подстрока в имени хоста в запросе. То есть:
Правило: example.com
Хост: example.com
=> Правило сработало.
Хост: www.example.com
=> Правило сработало.
Хост: example.com.net
=> Правило сработало.
Хост: example.org
=> Правило НЕ сработало.
Метод имеет свои недостатки, например правило сработает на хост notexample.com
.
Однако, является достаточно разумным компромиссом между гибкостью и удобством.
Регулярные выражения были бы ещё более гибкими, но менее удобными, а wildcards
(*.
) потребовали бы создавать несколько записей для одного хоста (с www
и
без www
).
Пример пакетирования под archlinux.
См. torxy --help
.
Поддерживается перезагрузка правил без остановки, по сигналу SIGHUP
.
GPL.