AntiBlock 2.0

Приблизительно два года назад я начал разрабатывать свою программу AntiBlock, о которой я писал ранее. Версия, которую я описал тогда, была далека от завершения. Но сейчас уже применятся другая архитектура, появился скрипт для сборки пакета и удобная служба, с конфигурационным файлом.

AntiBlock кратко

С помощью обработки DNS запросов, программа направляет только заблокированные сайты через VPN, а остальные идут без изменений.

DPI не спасет

В прошлой статье я писал про DPI как про один из подходов. Но со временем я понял что это не так, DPI хорошо подходит для блокировки, но совсем не подходит для разблокировки. К моменту TLS ClientHello, когда мы сможем проверить сессия идет на заблокированный сайт или нет, уже будет установлена TCP сессия, и мы не сможет эту, уже сформированную сессию, пустить через VPN. Поэтому подход с DNS самый эффективный.

Изменения в архитектуре

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

Скрытый текст

Прошлая версия добавляла IP-адреса, полученные из DNS-запросов заблокированных сайтов, в таблицу маршрутизации и удаляла их при истечении актуальности. Но такой подход имел недостаток, что если два сайта висят на одном IP-адресе и только один из них заблокированный, то оба пойдут через VPN. Новая версия лишена такого недостатка.

Новая версия использует более интересный подход:

  1. Программа создает TUN устройство и дает ему подсеть например 10.7.0.1/16.

  2. Если программа встречает 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 будет описано далее.

  3. А в DNS-запросе IP-адрес домена заменяется на 10.7.0.2.

    Domain

    IP

    example.com

    10.7.0.2

  4. Клиент обращается по адресу 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

  5. 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 настроек

WebGUI настройки https-dns-proxy

WebGUI настройки https-dns-proxy

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

WebGUI настройки https-dns-proxy

Убедиться что DoH работает можно на сайте.

Картинка что должен показать сайт

Лог проверки DoH

Лог проверки DoH

Важная проверка

Необходимо перейти в закладку DHCP and DNS

Картинка как выглядит закладка DHCP and DNS

Закладка DHCP and DNS

Закладка DHCP and DNS

Перейти в Закладка Forwards

Картинка как выглядит закладка Forwards

Закладка Forwards

Закладка Forwards

Убедиться что в поле DNS Forwards, при включенной службе AntiBlock, только listen_IP#listen_port. Если будут другие поля, то это сломает всю логику работы программы.

Картинка правильного примера поля DNS Forwards

Поле 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, помогу чем смогу.

© Habrahabr.ru