AntiBlock 2.0
Приблизительно два года назад я начал разрабатывать свою программу AntiBlock, о которой я писал ранее. Версия, которую я описал тогда, была далека от завершения. Но сейчас уже применятся другая архитектура, появился скрипт для сборки пакета и удобная служба, с конфигурационным файлом.
AntiBlock кратко
С помощью обработки DNS запросов, программа направляет только заблокированные сайты через VPN, а остальные идут без изменений.
DPI не спасет
В прошлой статье я писал про DPI как про один из подходов. Но со временем я понял что это не так, DPI хорошо подходит для блокировки, но совсем не подходит для разблокировки. К моменту TLS ClientHello, когда мы сможем проверить сессия идет на заблокированный сайт или нет, уже будет установлена TCP сессия, и мы не сможет эту, уже сформированную сессию, пустить через VPN. Поэтому подход с DNS самый эффективный.
Изменения в архитектуре
Чтобы не мучать людей, которые хотели бы только установить приложение, оставлю описание архитектуры под спойлером.
Скрытый текст
Прошлая версия добавляла IP-адреса, полученные из DNS-запросов заблокированных сайтов, в таблицу маршрутизации и удаляла их при истечении актуальности. Но такой подход имел недостаток, что если два сайта висят на одном IP-адресе и только один из них заблокированный, то оба пойдут через VPN. Новая версия лишена такого недостатка.
Новая версия использует более интересный подход:
Программа создает TUN устройство и дает ему подсеть например 10.7.0.1/16.
Если программа встречает DNS-запрос с заблокированным доменом:
Domain
IP
example.com
93.184.215.14
, то она добавляет в хеш-таблицу запись:
Key
Value
10.7.0.2
93.184.215.14
10.7.0.2 — свободный IP-адрес из подсети 10.7.0.1/17, почему из подсети 10.7.0.1/17, а не 10.7.0.1/16 будет описано далее.
А в DNS-запросе IP-адрес домена заменяется на 10.7.0.2.
Domain
IP
example.com
10.7.0.2
Клиент обращается по адресу 10.7.0.2. TUN устройство принимает пакет:
Source IP
Destination IP
192.168.1.10:25090
10.7.0.2:443
Из хеш-таблицы получаем значение по ключу Destination IP:
Key
Value
10.7.0.2
93.184.215.14
TUN устройство выполняет роль NAT. У подсети 10.7.0.1/16 две 17 подсети 10.7.0.1/17 и 10.7.128.1/17. Для дальнейшей обработки Destination IP 10.7.0.2 переводим из 10.7.0.1/17 в 10.7.128.1/17, просто инверсией нужного бита и получаем 10.7.128.2. Зачем это нужно будет объяснено далее. Заменяем поля у пакета:
Source IP
Destination IP
10.7.128.2:25091
93.184.215.14:443
Source port 25090 поменялся на 25091, потому что Source port 25090 был занят, и мы нашли первый свободный порт. Запоминаем в другую хеш-таблицу:
Key
Value
10.7.128.2:25091
93.184.215.14:443
192.168.1.10:25090
Другая хеш-таблица необходима, чтобы произвести обратные преобразования, когда пакет пойдет до клиента.
Подсети 10.7.0.1/17 и 10.7.128.1/17 используются, чтобы отличать пакеты, которые должны направиться в VPN (клиент→TUN→VPN) от пакетов, которые должны направиться прямо к клиенту (VPN→TUN→клиент). Так как маршрутизация на VPN происходит по Source IP Route Rules, то если всегда использовалась бы подсеть 10.7.0.1/16 любой пакет, исходящий из TUN, направлялся бы на VPN и не попадал бы на обратном пути к клиенту.
ip rule add from 10.10.128.1/17 table 200
Схема новой архитектуры
Сборка для OpenWrt
Для сборки пакета на OpenWrt был написал скрипт:
https://github.com/karen07/openwrt-package-autobuild.git
Скачиваем репозиторий:
git clone https://github.com/karen07/openwrt-package-autobuild.git
Запускаем скрипт:
./auto_install.sh antiblock ROUTER_NAME
где ROUTER_NAME
название роутера из ssh config или например root@192.168.1.1
При запуске на Ubuntu или Arch скрипт сам поставит необходимые зависимости. А так же сам сходит на роутер узнает его архитектуру, скачает нужный SDK, соберет и установит пакет AntiBlock на роутер. Пакет так же устанавливает службу с конфигурационным файлом.
Настройка службы
Конфигурационный файл лежит по пути /etc/config/antiblock
config antiblock 'args'
option url 'https://antifilter.download/list/domains.lst'
option file '/root/my_urls.txt'
option DNS_IP '127.0.0.1'
option DNS_port '5060'
option listen_IP '127.0.0.1'
option listen_port '5053'
option TUN_name 'NAT'
option TUN_net '10.7.0.1/16'
option VPN_name 'VPN'
option route_table '100'
option output '/tmp/antiblock/'
option log '1'
option stat '1'
Обязательно хотя бы один параметр:
url — url файла, в котором лежат заблокированные домены, домены идут построчно, последний домен тоже оканчивается новой строкой
file — путь до файла, в котором лежат заблокированные домены, подходит для ручной настройки списка заблокированных доменов, домены идут построчно, последний домен тоже оканчивается новой строкой
Обязательные параметры:
DNS_IP — IP-адрес DNS сервера, на который будут отправляться запросы
DNS_port — порт DNS сервера, на который будут отправляться запросы
listen_IP — IP-адрес, на котором AntiBlock будет слушать входящие запросы
listen_port — порт, на котором AntiBlock будет слушать входящие запросы, listen_port+1 используется для исходящих запросов
TUN_name — название будущего TUN интерфейса, не должно пересекаться с другими интерфейсами
TUN_net — подсеть будущего TUN интерфейса, не должна пересекаться с остальными подсетями на устройстве
VPN_name — название интерфейса, на который будут маршрутизироваться запросы на заблокированные домены, не обязательно название VPN интерфейса, может быть любой интерфейс
route_table — номер свободной таблицы маршрутизации, через которую будут маршрутизироваться пакеты на VPN_name
Не обязательные параметры:
output — папка, в которую будут сохраняться лог и статистика
log — включить полное логирование запросов в файл log.txt, помогает когда надо выявить домен, который потом можно включить в файл с заблокированными доменами
stat — включить вывод статистики работы программы в файл stat.txt, интересно отслеживать сколько всего было запросов DNS
Проверить запустилась служба или нет, можно командой:
logread | grep antiblock
Пример удачного запуска:
Antiblock started
Get urls from url https://antifilter.download/list/domains.lst
Get urls from file /root/my_urls.txt
DNS IP 127.0.0.1
DNS port 5060
Listen IP 127.0.0.1
Listen port 5053
TUN net 10.7.0.1/16
TUN name NAT
Thread TUN started
Thread client data started
TUN dev NAT allocated 10.7.0.2-10.7.127.254
Thread DNS data started
Readed domains from file 5 from url 626345
Для добавление службы в автозапуск:
service antiblock enable
Для применения новых настроек из конфигурационного файла:
service antiblock restart
Конфигурационный файл, который описан выше, появляется при установке пакета. Программа остановится с ошибкой если не найдет /root/my_urls.txt
, поэтому или надо удалить эту строчку или создать файл /root/my_urls.txt
. Например для ютуба необходимы записи:
ytimg.com
youtube.com
googlevideo.com
youtubei.googleapis.com
А так же если не использовать DoH, который будет описан в следующей главе. Необходимо поменять параметры:
DNS IP 127.0.0.1
DNS port 5060
Listen IP 127.0.0.1
Например на :
DNS IP 1.1.1.1
DNS port 53
Listen IP 192.168.1.1
DoH — DNS over HTTPS
Чтобы совсем не переживать за DNS, я использую вместе со своей программой:
https-dns-proxy
Название пакета для установки:
luci-app-https-dns-proxy
Это DNS proxy, принимающий DNS UDP запросы и переводящий их в HTTPS. Получается такой конвейер, Dnsmasq отправляет UDP DNS в AntiBlock, AntiBlock отправляет UDP DNS в https-dns-proxy, https-dns-proxy отправляет HTTPS DNS например в CloudFlare.
Для корректной работы вместе с моей программой необходимо выставить такие настройки. Найти настройки можно в закладке Services
далее в закладке HTTPS DNS Proxy
.
Картинки WebGUI настроек
Закладка WebGUI настроек
WebGUI настройки https-dns-proxy
WebGUI настройки https-dns-proxy
Так же настройки можно сделать через файл /etc/config/https-dns-proxy
:
config main 'config'
option dnsmasq_config_update '-'
option force_dns '0'
list force_dns_port '53'
list force_dns_port '853'
option procd_trigger_wan6 '0'
config https-dns-proxy
option resolver_url 'https://cloudflare-dns.com/dns-query'
option listen_addr '127.0.0.1'
option listen_port '5060'
Так же надо убедиться что служба добавлена в автозапуск и включена:
Картинка статуса службы
WebGUI настройки https-dns-proxy
Убедиться что DoH работает можно на сайте.
Картинка что должен показать сайт
Лог проверки DoH
Важная проверка
Необходимо перейти в закладку DHCP and DNS
Картинка как выглядит закладка DHCP and DNS
Закладка DHCP and DNS
Перейти в Закладка Forwards
Картинка как выглядит закладка Forwards
Закладка Forwards
Убедиться что в поле DNS Forwards
, при включенной службе AntiBlock, только listen_IP#listen_port
. Если будут другие поля, то это сломает всю логику работы программы.
Картинка правильного примера поля DNS Forwards
Поле DNS Forwards
Запуск на не OpenWrt
Собрать AntiBlock нужно через CMake. Systemd служба еще не сделана.
Поднять VPN, настроить правила маршрутизации:
wg-quick up VPN
ip route add 0.0.0.0/0 via ..... dev VPN table 200
ip rule add from 10.10.128.1/17 table 200
iptables -t nat -I POSTROUTING -o VPN -j MASQUERADE
Запустить AntiBlock:
antiblock \
-log \
-stat \
-output ..... \
-url https://antifilter.download/list/domains.lst \
-file ..... \
-DNS_IP 1.1.1.1 \
-DNS_port 53 \
-listen_IP ..... \
-listen_port 53 \
-TUN_net 10.10.0.1/16 \
-TUN_name NAT
В другой консоли нужно задать подсеть NAT устройству:
ip address add 10.10.0.1/16 dev NAT
ip link set dev NAT up
Дисклеймер
Разработка еще не окончена, AntiBlock тестировался на двух роутерах с ARM и MIPS, но все равно сохраняется вероятность неожиданного поведения на других устройствах. AntiBlock потребляет примерно 22 мегабайта ОЗУ. Так много, потому что уже 620 000 заблокированных доменов, и они весят 11 мегабайт, хеш таблица поверх них весит еще 5 мегабайт. А так же пока не реализовано удаление их NAT таблицы, там 50000 записей, за неделю не переполнялось, но если держать включенным очень долго, то может и переполниться. Поэтому рекомендую раз в неделю перезапускать. IPv6 тоже не работает, поэтому чтобы корректно работало, надо чтобы DNS запросы были только для IPv4 адресов. Я решил эту проблему так:
service odhcpd disable
service odhcpd stop
uci delete dhcp.odhcpd
uci delete network.wan6
Если что то не взлетит, обращайтесь в комментарии или в GitHub Issues, помогу чем смогу.