2016-03-07 14:48:23 +00:00
zapret v.10
2016-02-25 13:43:48 +00:00
Для чего это надо
-----------------
Обойти блокировки веб сайтов 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
2016-03-07 14:48:23 +00:00
--split-pos=<offset> ; делить все посылы на сегменты в указанной позиции. Если отсыл длинее 8Kb (размер буфера приема), то будет разделен каждый блок по 8Kb.
2016-02-25 13:43:48 +00:00
--hostcase ; замена "Host:" => "host:"
--hostdot ; добавление точки после имени хоста : "Host: kinozal.tv."
--methodspace ; добавить пробел после метода : "GET /" => "GET /"
Параметры манипуляции могут сочетаться в любых комбинациях.
Провайдеры
----------
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
2016-03-05 08:04:40 +00:00
tiera : сама тиера до последнего ничего не банила. Похоже, что банит вышестоящий оператор, возможно telia.
Требуется сплит http запросов в течение всей сессии.
2016-02-25 13:43:48 +00:00
Способы получения списка заблокированных 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 мб памяти е е может не хватить, и будут проблемы. В этом случае используйте
следующий скрипт.
Скрипт автоматически вызывает ipset/get_user.sh и обновляет ipset
3) ipset/get_anizapret.sh. быстро и без нагрузки на роутер получает лист с http://antizapret.prostovpn.org.
Скрипт автоматически вызывает ipset/get_user.sh и обновляет ipset
Н а роутерах не рекомендуется вызывать эти скрипты чаще раза за 2 суток, поскольку сохранение идет
либо во внутреннюю флэш память роутера, либо в случае extroot - на флэшку.
В обоих случаях слишком частая запись может убить флэшку, но если это произойдет с внутренней
флэш памятью, то вы просто убьете роутер.
Обновление ipset выполняет скрипт ipset/create_ipset.sh
Пример установки на 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"
Другие 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
2016-02-26 08:09:31 +00:00
В зависимости от вашего провайдера внести нужные записи в /etc/firewall.user.
2016-02-25 13:43:48 +00:00
/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.