NGINX-DPI: обход блокировок

Этот проект является форком проекта nginxdpi. Оргинальная статья для ознакомления.

КАК ЭТО РАБОТАЕТ?

Весь трафик будет идти через интернет-провайдера, но если по пути встретится заблокированный сайт, то трафик перенаправится через прокси-сервер. Учитываются только порты 80 и 443 по протоколу http и https.

В КАКИХ СЛУЧАЯХ МОЖЕТ ПОНАДОБИТСЯ?

  1. Когда нет возможности развернуть VPN.
  2. Когда VPN значит bottleneck.
  3. Когда просто задолбался вести список заблокированных ресурсов.
  4. Когда задолбался вкл/выкл VPN для работы с банк-клиентами.

ЧТО ПОНАДОБИТСЯ?

Чтобы развернуть дома будет достаточно одноплатника вроде raspberry pi (тестировал на model B). Организации могут развернуть на машрутизаторе с некоторыми модификациями, которые не будут описаны тут поскольку это довольно индивидуально в зависимости от инфраструктуры. Или же можно развернуть на выделенном сервере.
Далее понадобится VPS за границей для перенаправления трафика туда, если встретится заблокированный ресурс. Если у вас нет ничего на примете, то посмею рекомендовать следующие:
1. Fornex
2. Melbicom
3. PQ Host
Они принимают Российские карты VISA, СБП и Yandex Pay. Лично я брал себе в PQ Host в направлении Молдова (для личного пользования) и Франкфурт (Германия - для юридического лица).
Есть юридический момент, когда хостеры запрещают устанавливать VPN и прокси, но это касается только тех случаев, когда вы намерены предоставлять коммерческие услуги (за их счет так сказать). Тоже самое относится к публичным сервисам. Так что используйте только в персональных целях. Одним из преимуществ выше перечисленных хостеров является относительная дешевизна в купе с безлимитным трафиком с шириной канала в 100 мегабит. Если хотите гигабит, то надо уже брать выделенный сервер за где-то 30К причем без гарантии того, что в вашей локации будет именно гигабит (даже looking glass как оказалось не дает гарантию).
Что могу сказать про PQ Host...не самый стабильный хостинг. Уже бывали и отвалы VPS и лаги (видимо ДУДОС).

SHADOWSOCKS

Начнем с прокси-сервера. Подключаемся к vps и собираем shadowsocks. Для сборки понадобится не менее 2 гигабайт памяти. Если нету, то лучше поставить с репозитория shadowsocks-libev (который помедленее будет) или его же и скомпилить (для компиляции хватит и гига).

git clone https://github.com/shadowsocks/shadowsocks-rust.git
dnf install gcc
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
rustup toolchain install nightly
rustup default nightly
cd shadowsocks-rust
cargo build --release
make install TARGET=release

Файлы будут установлены в директорию /usr/local/bin.
Теперь накидаем конфиг в /etc/shadowsocks/server.json.

{
        "server": "0.0.0.0",
        "server_port": 4443,
        "mode": "tcp_and_udp",
        "password": "paste_password_here",
        "timeout": 60,
        "no_delay": true,
        "fast_open": true,
        "reuse_port": true,
        "method": "chacha20-ietf-poly1305"
}

Я использовал порт 4443 поскольку у меня 443 уже занял nginx.
Для генерации стойкого пароля используйте команду "openssl rand -base64 24" и вставьте вместо paste_password_here.
Теперь накидаем скрипт systemd в /etc/systemd/system/shadowsocks-server.service.

[Unit]
Description=Shadowsocks-Libev Custom Server Service for %I
Documentation=man:ss-server(1)
After=network-online.target

[Service]
Type=simple
LimitNOFILE=32768
ExecStart=/usr/local/bin/ssserver -c /etc/shadowsocks/server.json

[Install]
WantedBy=multi-user.target

Опция LimitNOFILE увеличивает ограничение на количество файловых дескрипторов в ОС.
Стартуем сервис shadowsocks-server, открываем порт на фаерволе и на этом заканчиваем с сервером прокси.
Теперь разворачиваем клиент на raspberry pi - apt install shadowsocks-libev (для версии rust на моем одноплатнике не хватает памяти Т__Т).
Накидаем конфиг клиента в /etc/shadowsocks-libev/config.json.

{
        "server":"server_ip",
        "mode":"tcp_and_udp",
        "server_port":4443,
        "local_address":"0.0.0.0",
        "local_port":1080,
        "password":"paste_password_here",
        "timeout":60,
        "no_delay": true,
        "fast_open": true,
        "reuse_port": true,
        "method":"chacha20-ietf-poly1305"
}

Где server_ip там подставляем ip-адрес shadowsocks-server, а где paste_password_here подставляем тот же пароль, что в server.json.
Стартуем shadowsocks-libev (конфиг вроде бы он сам находит) и на этом заканчиваем с клиентом прокси и приступаем к DNS.

DNS-over-TLS

DoT позволит скрыть dns запросы от провайдера таким образом обходя некоторые виды блокировок. Шаг не обязательный, но рекомендуемый. При развертке на raspberry pi он будет принимать запросы на порту 53/UDP и пересылать на публичные dns-серверы по порту 853/TCP с шифрованием.

git clone https://github.com/LINKIWI/dotproxy.git
cd dotproxy
dnf install golang
make
mkdir /usr/local/dotproxy
mv dotproxy /usr/local/dotproxy

Накидаем конфиг в /usr/local/dotproxy/config.yaml.

metrics:
  statsd:
    addr: udp://127.0.0.1:8125
    sample_rate: 1.0
listener:
  tcp:
    addr: 0.0.0.0:53
    read_timeout: 5s
    write_timeout: 5s
  udp:
    addr: 0.0.0.0:53
    max_concurrent_connections: 64
    write_timeout: 5s
upstream:
  load_balancing_policy: Failover
  max_connection_retries: 10
  servers:
    - addr: 8.8.8.8:853
      server_name: dns.google
      connection_pool_size: 8
      connect_timeout: 100ms
      handshake_timeout: 250ms
      read_timeout: 5s
      write_timeout: 5s
      stale_timeout: 10s
    - addr: 1.1.1.1:853
      server_name: cloudflare-dns.com
      connection_pool_size: 8
      connect_timeout: 100ms
      handshake_timeout: 250ms
      read_timeout: 5s
      write_timeout: 5s
      stale_timeout: 10s

Накидаем скрипт systemd в /etc/systemd/system/dotproxy.service.

[Unit]
Description=High performance DNS-over-TLS proxy
After=network.target

[Service]
Type=simple
Restart=always
RestartSec=30
User=root
SyslogIdentifier=dotproxy
ExecStart=/usr/local/dotproxy/dotproxy --verbosity info --config /usr/local/dotproxy/config.yaml

[Install]
WantedBy=multi-user.target

Стартуем сервис dotproxy и на этом заканчиваем с dns. Переходим к NGINX-DPI, Ваше величество!

OPENRESTY

Эта штука позволит обходить блокировки, если на 80 порту провайдер навешивает баннер, если сайт не доступен по портам 80 и 443 и даже если у сайта по каким-то причинам (например из-за проксирования запросов провайдером) отсутствует ssl сертификат.

git clone https://gitflic.ru/project/igroykt/nginx-dpi.git
dnf install libtool make zlib-devel openssl-devel pcre-devel bc
wget https://openresty.org/download/openresty-1.19.9.1.tar.gz
tar xvvf openresty-1.19.9.1.tar.gz
cd openresty-1.19.9.1
./configure --prefix=/usr/local/nginx-dpi --with-cc=gcc --add-module=../nginx-dpi/lua-resty-openssl-aux-module --add-module=../nginx-dpi/lua-resty-openssl-aux-module/stream --add-module=../nginx-dpi/lua-resty-getorigdest-module/src
gmake && gmake install
cd ..
yes|cp -r nginx-dpi/lua-resty-getorigdest-module/lualib/* /usr/local/nginx-dpi/lualib/
yes|cp -r nginx-dpi/lua-resty-openssl/lib/resty/* /usr/local/nginx-dpi/lualib/resty/
yes|cp -r nginx-dpi/lua-resty-openssl-aux-module/lualib/* /usr/local/nginx-dpi/lualib/
yes|cp nginx-dpi/lua-resty-socks5/socks5.lua /usr/local/nginx-dpi/lualib/resty/
yes|cp nginx-dpi/lua-struct/src/struct.lua /usr/local/nginx-dpi/lualib/
cp nginx-dpi/sapi/nginx-dpi.service /etc/systemd/system/
systemctl daemon-reload

Стартуем сервис nginx-dpi. Теперь необходимо произвести конфигурацию /usr/local/nginx-dpi/cfg/nginx.conf. Поскольку подразумеваем, что shadowsocks-libev находится на этом же железе, то оставляем proxy_addr и proxy_port как есть. В isp_block_banner указываем адрес баннера без протокола. Аналогично указываем основной домен провайдера. В массив exclude_domains указываем через запятую домены сайтов, которые не надо пускать через прокси-сервер. Сделано это на случай, если по каким-то причинам тот или иной домен все же перенаправляется через прокси и это не желательно в вашем случае. Пример ниже.

local exclude_domains = {
	"habr.com",
	"igro.tech",
	"whatismyipaddress.com"
}

При этом поиск будет производится именно по домену т.е. нет смысла вписывать it.igro.tech поскольку он уже будет идти "не через прокси".
Аналогичным образом работает массив force_domains только наоборот вместо того, чтобы исключать из перенаправления на прокси он форсирует проксирование. Таким образом можно вписать скажем netflix.com, чтобы весь трафик netflix бегал через vps.
Теперь давайте приступим к последнему шагу.

НАСТРОЙКА МАРШРУТИЗАТОРА

Все это конечно круто, но очень не хотелось настраивать каждое устройство в сети на работу с nginx-dpi. Поэтому в openresty есть скрипты start.sh и stop.sh. Если stop.sh можно оставить в покое, то start.sh лучше подогнать под реалии своей сети (например добавить VLAN'ы если есть или подправить сеть, если отличается адресация локальной сети). За IPTV можно не беспокоится поскольку там уже есть и NAT и разрешения для IGMP broadcast. Учитывая, что будет двойной NAT, то надо позаботится о пробросе портов.
Конечно никаких конфигов тут приводить не буду поскольку маршрутизаторов великое количество, но приведу основную идею, а она очень простая.
В настройках DHCP-сервера меняем маршрутизатор и DNS на IP-адрес raspberry pi или иного устройства, где развернут nginx-dpi, dotproxy и shadowsocks. Ждем или перезагружем все устройства и все должно начать работать.
Сделаю отдельную ремарку по поводу raspberry pi. Покупайте оригинальные блоки питания или совпадающие по характеристике ибо перепады напряжения и шумы в электросети сказываются на нем не самым очевидным образом. Пока не решил эту проблему были и просадки скорости и зависания связи. Удалось диагностировать засекая время и сопоставляя с временем в syslog.

Всем доброй охоты (С) Кибердед

UPD: 30.04.22

Путем замены проверки сертификата на тест подключения к порту и уменьшения таймаутов удалось увеличить производительность dpi. Оригинальный автор видимо проверял сертификаты из-за того, что его провайдер отлавливал dns запросы или же понижал протокол tls до версии 1.2 через прокси для отлова sni с последующей блокировкой. Блокировки по второму типу не обнаружил, а первый тип обходит dot. Это позволило немного снизить нагрузку на процессор.
Обход же баннеров на 80 порту производится с помощью кэширования адреса предыдущего хоста и редиректа через прокси, что немного повысило потребление памяти, но не критично (даже до свопа дело не доходит).

UPD: 01.05.22

Чтобы без проблем смотреть lampa.mx или чтоб вообще торренты работали оказывается надо добавить upnp: apt install miniupnpd-nftables miniupnpd (порядок пакетов не с проста). Настройка демона простая.

listening_ip=server_ip
system_uptime=yes
force_igd_desc_v1=no
ext_ifname=server_interface

Где вместо server_ip надо вставить ip-адрес сервера, а вместо server_interface указать интерфейс сервера на котором крутится этот ip-адрес.
Если сделали рестарт dpi, то после этого лучше перезапустить стрим lampa.mx или вовсе этого не делать во время просмотра контента.

Показать комментарии