mirror of
https://github.com/bol-van/zapret.git
synced 2024-12-02 14:40:52 +03:00
295 lines
26 KiB
Plaintext
295 lines
26 KiB
Plaintext
zapret v.13
|
||
|
||
Для чего это надо
|
||
-----------------
|
||
|
||
Обойти блокировки веб сайтов http.
|
||
|
||
Как это работает
|
||
----------------
|
||
|
||
У провайдеров в DPI бывают бреши. Они случаются от того, что правила DPI пишут для
|
||
обычных пользовательских программ, опуская все возможные случаи, допустимые по стандартам.
|
||
Это делается для простоты и скорости. Нет смысла ловить хакеров, которых 0.01%,
|
||
ведь все равно эти блокировки обходятся довольно просто даже обычными пользователями.
|
||
|
||
Некоторые DPI не могут распознать http запрос, если он разделен на TCP сегменты.
|
||
Например, запрос вида "GET / HTTP/1.1\r\nHost: kinozal.tv......"
|
||
мы посылаем 2 частями : сначала идет "GET ", затем "/ HTTP/1.1\r\nHost: kinozal.tv.....".
|
||
Другие DPI спотыкаются, когда заголовок "Host:" пишется в другом регистре : например, "host:".
|
||
Кое-где работает добавление дополнительного пробела после метода : "GET /" => "GET /"
|
||
или добавление точки в конце имени хоста : "Host: kinozal.tv."
|
||
|
||
Как это реализовать на практике в системе linux
|
||
-----------------------------------------------
|
||
|
||
Как заставить систему разбивать запрос на части ? Можно прогнать всю TCP сессию
|
||
через transparent proxy, а можно подменить поле tcp window size на первом входящем TCP пакете с SYN,ACK.
|
||
Тогда клиент подумает, что сервер установил для него маленький window size и первый сегмент с данными
|
||
отошлет не более указанной длины. В последующих пакетах мы не будем менять ничего.
|
||
Дальнейшее поведение системы по выбору размера отсылаемых пакетов зависит от реализованного
|
||
в ней алгоритма. Опыт показывает, что linux первый пакет всегда отсылает не более указанной
|
||
в window size длины, остальные пакеты до некоторых пор шлет не более max(36,указанный_размер).
|
||
После некоторого количества пакетов срабатывает механизм window scaling и начинает
|
||
учитываться фактор скалинга, размер пакетов становится не более max(36,указанный_рамер << scale_factor).
|
||
Не слишком изящное поведение, но поскольку на размеры входящик пакетов мы не влияем,
|
||
а объем принимаемых по http данных обычно гораздо выше объема отсылаемых, то визуально
|
||
появятся лишь небольшие задержки.
|
||
Windows ведет себя в аналогичном случае гораздо более предсказуемо. Первый сегмент
|
||
уходит указанной длины, дальше window size меняется в зависимости от значения,
|
||
присылаемого в новых tcp пакетах. То есть скорость почти сразу же восстанавливается
|
||
до возможного максимума.
|
||
|
||
Перехватить пакет с SYN,ACK не представляет никакой сложности средствами iptables.
|
||
Однако, возможности редактирования пакетов в iptables сильно ограничены.
|
||
Просто так поменять window size стандартными модулями нельзя.
|
||
Для этого мы воспользуемся средством NFQUEUE. Это средство позволяет
|
||
передавать пакеты на обработку процессам, работающим в user mode.
|
||
Процесс, приняв пакет, может его изменить, что нам и нужно.
|
||
|
||
iptables -t raw -I PREROUTING -p tcp --sport 80 --tcp-flags SYN,ACK SYN,ACK -j NFQUEUE --queue-num 200 --queue-bypass
|
||
|
||
Будет отдавать нужные нам пакеты процессу, слушающему на очереди с номером 200.
|
||
Он подменит window size. PREROUTING поймает как пакеты, адресованные самому хосту,
|
||
так и маршрутизируемые пакеты. То есть решение одинаково работает как на клиенте,
|
||
так и на роутере. На роутере на базе PC или на базе OpenWRT.
|
||
В принципе этого достаточно.
|
||
Однако, при таком воздействии на TCP будет небольшая задержка.
|
||
Чтобы не трогать хосты, которые не блокируются провайдером, можно сделать такой ход.
|
||
Создать список заблоченых доменов или скачать его с rublacklist.
|
||
Заресолвить все домены в ipv4 адреса. Загнать их в ipset с именем "zapret".
|
||
Добавить в правило :
|
||
|
||
iptables -t raw -I PREROUTING -p tcp --sport 80 --tcp-flags SYN,ACK SYN,ACK -m set --match-set zapret src -j NFQUEUE --queue-num 200 --queue-bypass
|
||
|
||
Такии образом воздействие будет производиться только на ip адреса, относящиеся к заблокированным сайтам.
|
||
Список можно обновлять через cron раз в несколько дней.
|
||
Если обновлять через rublacklist, то это займет довольно долго. Более часа. Но ресурсов
|
||
этот процесс не отнимает, так что никаких проблем это не вызовет, особенно, если система
|
||
работает постоянно.
|
||
|
||
Если DPI не обходится через разделение запроса на сегменты, то иногда срабатывает изменение
|
||
"Host:" на "host:". В этом случае нам может не понадобится замена window size, поэтому цепочка
|
||
PREROUTING нам не нужна. Вместо нее вешаемся на исходящие пакеты в цепочке POSTROUTING :
|
||
|
||
iptables -t mangle -I POSTROUTING -p tcp --dport 80 -m set --match-set zapret dst -j NFQUEUE --queue-num 200 --queue-bypass
|
||
|
||
В этом случае так же возможны дополнительные моменты. DPI может ловить только первый http запрос, игнорируя
|
||
последующие запросы в keep-alive сессии. Тогда можем уменьшить нагрузку на проц, отказавшись от процессинга ненужных пакетов.
|
||
|
||
iptables -t mangle -I POSTROUTING -p tcp --dport 80 -m set --match-set zapret dst -m connbytes --connbytes-dir=original --connbytes-mode=packets --connbytes 1:5 -j NFQUEUE --queue-num 200 --queue-bypass
|
||
|
||
Случается так, что провайдер мониторит всю HTTP сессию с keep-alive запросами. В этом случае
|
||
недостаточно ограничивать TCP window при установлении соединения. Необходимо посылать отдельными
|
||
TCP сегментами каждый новый запрос. Эта задача решается через полное проксирование трафика через
|
||
transparent proxy (TPROXY или DNAT). TPROXY не работает с соединениями, исходящими с локальной системы,
|
||
так что это решение применимо только на роутере. DNAT работает и с локальными соединениеми,
|
||
но имеется опасность входа в бесконечную рекурсию, поэтому демон запускается под отдельным пользователем,
|
||
и для этого пользователя отключается DNAT через "-m owner". Полное проксирование требует больше ресурсов
|
||
процессора, чем манипуляция с исходящими пакетами без реконструкции TCP соединения.
|
||
|
||
iptables -t nat -I PREROUTING -p tcp --dport 80 -j DNAT --to 127.0.0.1:1188
|
||
iptables -t nat -I OUTPUT -p tcp --dport 80 -m owner ! --uid-owner tpws -j DNAT --to 127.0.0.1:1188
|
||
|
||
nfqws
|
||
-----
|
||
|
||
Эта программа - модификатор пакетов и обработчик очереди NFQUEUE.
|
||
Она берет следующие параметры :
|
||
--daemon ; демонизировать прогу
|
||
--qnum=200 ; номер очереди
|
||
--wsize=4 ; менять tcp window size на указанный размер
|
||
--hostcase ; менять регистр заголовка "Host:"
|
||
Параметры манипуляции могут сочетаться в любых комбинациях.
|
||
|
||
tpws
|
||
-----
|
||
|
||
tpws - это transparent proxy.
|
||
--bind-addr ; на каком адресе слушать. может быть ipv4 или ipv6 адрес. если не указано, то слушает на всех адресах ipv4 и ipv6
|
||
--port=<port> ; на каком порту слушать
|
||
--daemon ; демонизировать прогу
|
||
--user=<username> ; менять uid процесса
|
||
--split-http-req=method|host ; способ разделения http запросов на сегменты : около метода (GET,POST) или около заголовка Host
|
||
--split-pos=<offset> ; делить все посылы на сегменты в указанной позиции. Если отсыл длинее 8Kb (размер буфера приема), то будет разделен каждый блок по 8Kb.
|
||
--hostcase ; замена "Host:" => "host:"
|
||
--hostdot ; добавление точки после имени хоста : "Host: kinozal.tv."
|
||
--methodspace ; добавить пробел после метода : "GET /" => "GET /"
|
||
Параметры манипуляции могут сочетаться в любых комбинациях.
|
||
Есть исключение : split-pos заменяет split-http-req.
|
||
|
||
Провайдеры
|
||
----------
|
||
|
||
mns.ru : нужна замена window size на 4
|
||
beeline (corbina) : нужна замена регистра "Host:" на протяжении всей http сессии
|
||
dom.ru : нужно проксирование HTTP сессий через tpws с заменой регистра "Host:" и разделение TCP сегментов на хедере "Host:".
|
||
Ахтунг ! Домру блокирует все поддомены заблоченого домена. IP адреса всевозможных поддоменов узнать невозможно из реестра
|
||
блокировок, поэтому если вдруг на каком-то сайте вылезает блокировочный баннер, то идите в консоль firefox, вкладка network.
|
||
Загружайте сайт и смотрите куда идет редирект. Потом вносите домен в zapret-hosts-user.txt. Например, на kinozal.tv имеются
|
||
2 запрашиваемых поддомена : s.kinozal.tv и st.kinozal.tv с разными IP адресами.
|
||
sknt.ru : проверена работа с tpws с параметром "--split-http-req=method". возможно, будет работать nfqueue, пока возможности
|
||
проверить нет
|
||
tkt : помогает разделение http запроса на сегменты, настройки mns.ru подходят
|
||
ТКТ был куплен ростелекомом, используется фильтрация ростелекома.
|
||
Поскольку DPI не отбрасывает входящую сессию, а только всовывает свой пакет, который приходит раньше ответа от настоящего сервера,
|
||
блокировки так же обходятся без применения "тяжелой артиллерии" следующим правилом :
|
||
iptables -t raw -I PREROUTING -p tcp --sport 80 -m string --hex-string "|0D0A|Location: http://95.167.13.50" --algo bm -j DROP --from 40 --to 200
|
||
Ростелеком : см tkt
|
||
tiera : сама тиера до последнего ничего не банила. Похоже, что банит вышестоящий оператор, возможно telia.
|
||
Требуется сплит http запросов в течение всей сессии.
|
||
|
||
Способы получения списка заблокированных IP
|
||
-------------------------------------------
|
||
|
||
1) Внесите заблокирванные домены в ipset/zapret-hosts-user.txt и запустите ipset/get_user.sh
|
||
На выходе получите ipset/zapret-ip-user.txt с IP адресами.
|
||
|
||
2) ipset/get_reestr.sh получает список доменов от rublacklist и дальше их ресолвит в ip адреса
|
||
в файл ipset/zapret-ip.txt. В этом списке есть готовые IP адреса, но судя во всему они там в точности в том виде,
|
||
что вносит в реестр РосКомПозор. Адреса могут меняться, позор не успевает их обновлять, а провайдеры редко
|
||
банят по IP : вместо этого они банят http запросы с "нехорошим" заголовком "Host:" вне зависимости
|
||
от IP адреса. Поэтому скрипт ресолвит все сам, хотя это и занимает много времени.
|
||
Дополнительное требование - объем памяти в /tmp для сохранения туда скачанного файла, размер которого
|
||
несколько Мб и продолжает расти. На роутерах openwrt /tmp представляет собой tmpfs , то есть ramdisk.
|
||
В случае роутера с 32 мб памяти ее может не хватить, и будут проблемы. В этом случае используйте
|
||
следующий скрипт.
|
||
|
||
3) ipset/get_anizapret.sh. быстро и без нагрузки на роутер получает лист с http://antizapret.prostovpn.org.
|
||
|
||
Все варианты рассмотренных скриптов автоматически создают и заполняют ipset.
|
||
Варианты 2 и 3 дополнительно вызывают вариант 1.
|
||
|
||
На роутерах не рекомендуется вызывать эти скрипты чаще раза за 2 суток, поскольку сохранение идет
|
||
либо во внутреннюю флэш память роутера, либо в случае extroot - на флэшку.
|
||
В обоих случаях слишком частая запись может убить флэшку, но если это произойдет с внутренней
|
||
флэш памятью, то вы просто убьете роутер.
|
||
|
||
Принудительное обновление ipset выполняет скрипт ipset/create_ipset.sh
|
||
|
||
Можно внести список доменов в ipset/zapret-hosts-user-ipban.txt. Их ip адреса будут помещены
|
||
в отдельный ipset "ipban". Он может использоваться для принудительного завертывания всех
|
||
соединений на прозрачный proxy "redsocks".
|
||
|
||
|
||
Пример установки на debian 7
|
||
----------------------------
|
||
Debian 7 изначально содержит ядро 3.2. Оно не умеет делать DNAT на localhost.
|
||
Конечно, можно не привязывать tpws к 127.0.0.1 и заменить в правилах iptables "DNAT 127.0.0.1" на "REDIRECT",
|
||
но лучше установить более свежее ядро. Оно есть в стабильном репозитории :
|
||
apt-get update
|
||
apt-get install linux-image-3.16
|
||
Установить пакеты :
|
||
apt-get update
|
||
apt-get install libnetfilter-queue-dev ipset curl
|
||
Скопировать директорию "zapret" в /opt.
|
||
Собрать nfqws :
|
||
cd /opt/zapret/nfq
|
||
make
|
||
Собрать tpws :
|
||
cd /opt/zapret/tpws
|
||
make
|
||
Скопировать /opt/zapret/init.d/debian7/zapret в /etc/init.d.
|
||
В /etc/init.d/zapret выбрать пераметр "ISP". В зависимости от него будут применены нужные правила.
|
||
Там же выбрать параметр SLAVE_ETH, соответствующий названию внутреннего сетевого интерфейса.
|
||
Включить автостарт : chkconfig zapret on
|
||
(опционально) Вручную первый раз получить новый список ip адресов : /opt/zapret/ipset/get_antizapret.sh
|
||
Зашедулить задание обновления листа :
|
||
crontab -e
|
||
Создать строчку "0 12 * * */2 /opt/zapret/ipset/get_antizapret.sh". Это значит в 12:00 каждые 2 дня обновлять список.
|
||
Запустить службу : service zapret start
|
||
Попробовать зайти куда-нибудь : http://ej.ru, http://kinozal.tv, http://grani.ru.
|
||
Если не работает, то остановить службу zapret, добавить правило в iptables вручную,
|
||
запустить nfqws в терминале под рутом с нужными параметрами.
|
||
Пытаться подключаться к заблоченым сайтам, смотреть вывод программы.
|
||
Если нет никакой реакции, значит скорее всего указан неверный номер очереди или ip назначения нет в ipset.
|
||
Если реакция есть, но блокировка не обходится, значит параметры обхода подобраные неверно, или это средство
|
||
не работает в вашем случае на вашем провайдере.
|
||
Никто и не говорил, что это будет работать везде.
|
||
Попробуйте снять дамп в wireshark или "tcpdump -vvv -X host <ip>", посмотрите действительно ли первый
|
||
сегмент TCP уходит коротким и меняется ли регистр "Host:".
|
||
|
||
ubuntu 12,14
|
||
------------
|
||
|
||
Имеется готовый конфиг для upstart : zapret.conf. Его нужно скопировать в /etc/init и настроить по аналогии с debian.
|
||
Запуск службы : "start zapret"
|
||
Останов службы : "stop zapret"
|
||
Ubuntu 12 так же, как и debian 7, оснащено ядром 3.2. См замечание в разделе "debian 7".
|
||
|
||
ubuntu 16,debian 8
|
||
------------------
|
||
|
||
Процесс аналогичен debian 7, однако требуется зарегистрировать init скрипты в systemd после их копирования в /etc/init.d.
|
||
install : /usr/lib/lsb/install_initd zapret
|
||
remove : /usr/lib/lsb/remove_initd zapret
|
||
|
||
|
||
Другие linux системы
|
||
--------------------
|
||
|
||
Существует несколько основных систем запуска служб : sysvinit, upstart, systemd.
|
||
Настройка зависит от системы, используемой в вашем дистрибутиве.
|
||
Типичная стратегия - найти скрипт или конфигурацию запуска других служб и написать свой по аналогии,
|
||
при необходимости почитывая документацию по системе запуска.
|
||
Нужные команды можно взять из предложенных скриптов.
|
||
|
||
|
||
Фаерволлы
|
||
---------
|
||
|
||
Если вы используете какую-то систему управления фаерволом, то она может вступать в конфликт
|
||
с имеющимся скриптом запуска. В этом случае правила для iptables должны быть прикручены
|
||
к вашему фаерволу отдельно от скрипта запуска tpws или nfqws.
|
||
Именно так решается вопрос в случае с openwrt, поскольку там своя система управления фаерволом.
|
||
При повторном применении правил она могла бы поломать настройки iptables, сделанные скриптом из init.d.
|
||
|
||
Что делать с openwrt
|
||
--------------------
|
||
|
||
Установить дополнительные пакеты :
|
||
opkg update
|
||
opkg install iptables-mod-extra iptables-mod-nfqueue iptables-mod-filter iptables-mod-ipopt ipset curl bind-tools
|
||
|
||
Самая главная трудность - скомпилировать программы на C.
|
||
Это можно сделать средствами кросс-компиляции на любой традиционной linux системе.
|
||
Читайте compile/build_howto_openwrt.txt.
|
||
Ваша задача - получить ipk файлы для tpws и nfqws.
|
||
Скопировать директорию "zapret" в /opt на роутер.
|
||
Установить ipk. Для этого сначала копируем на роутер ipk в /tmp, потом opkg install /tmp/*.ipk.
|
||
Смотрим, что появились исполняемые файлы /opt/zapret/tpws/tpws, /opt/zapret/nfq/nfqws.
|
||
Скопировать /opt/zapret/init.d/zapret в /etc/init.d.
|
||
В /etc/init.d/zapret выбрать пераметр "ISP". В зависимости от него будут применены нужные правила.
|
||
/etc/init.d/zapret enable
|
||
/etc/init.d/zapret start
|
||
В зависимости от вашего провайдера внести нужные записи в /etc/firewall.user.
|
||
/etc/init.d/firewall restart
|
||
Посмотреть через iptables -L или через luci вкладку "firewall" появились ли нужные правила.
|
||
Зашедулить задание обновления листа :
|
||
crontab -e
|
||
Создать строчку "0 12 * * */2 /opt/zapret/ipset/get_antizapret.sh". Это значит в 12:00 каждые 2 дня обновлять список.
|
||
|
||
Если у вас linux x64, то вместо компиляции toolchain можно использовать пре-компилированный SDK от разработчиков openwrt.
|
||
https://downloads.openwrt.org/
|
||
Найдите вашу версию openwrt, найдите вашу архитектуру, скачайте файл "OpenWrt-SDK-*".
|
||
Фактически это тот же buildroot, только в нем уже подготовлен toolchain для нужной версии openwrt,
|
||
нужной target архитектуры и хост-системы linux x64.
|
||
|
||
|
||
Прекомпилированые бинарики
|
||
--------------------------
|
||
|
||
Компилировать для роутеров может быть непростой задачей, требующей изучения вопроса и гугления "глюков из коробки" в openwrt SDK.
|
||
Нет кое-каких бинариков, нет кое-каких линков, в результате из коробки SDK может выдавать ошибки.
|
||
Для самых распространенных архитектур собраны статические бинарики. См binaries.
|
||
Статическая сборка означает, что бинарик не зависит от типа libc (uclibc или musl) и наличия установленных so - его можно использовать сразу.
|
||
Лишь бы подходил тип CPU. У ARM и MIPS есть несколько версий. Если на вашей версии выдаются ошибки при запуске - придется собирать самостоятельно под вашу систему.
|
||
|
||
Обход блокировки https
|
||
----------------------
|
||
|
||
Как правило трюки с DPI не помогают для обхода блокировки https.
|
||
Приходится перенаправлять трафик через сторонний хост.
|
||
Предлагается использовать прозрачный редирект через socks5 посредством iptables+redsocks, либо iptables+iproute+openvpn.
|
||
Настройка варианта с redsocks на openwrt описана в https.txt.
|