Обход DPI в linux
Go to file
2016-02-16 16:08:37 +03:00
compile first commit 2016-02-15 16:34:45 +03:00
init.d tkt/rostelekom 2016-02-16 16:07:27 +03:00
ipset first commit 2016-02-15 16:34:45 +03:00
nfq first commit 2016-02-15 16:34:45 +03:00
tpws v4 2016-02-15 19:18:33 +03:00
changes.txt tkt/rostelekom 2016-02-16 16:07:27 +03:00
iptables.txt first commit 2016-02-15 16:34:45 +03:00
readme.txt tkt/rostelekom 2016-02-16 16:08:37 +03:00

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

zapret v.4

Для чего это надо
-----------------

Обойти блокировки веб сайтов 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.....".
Как заставить систему разбивать запрос на 2 части ? Подменить поле tcp window size
на первом входящем TCP пакете с SYN,ACK. Тогда клиент подумает, что сервер установил
для него маленький window size и первый сегмент с данными отошлет не более указанной длины.
В следующем пакете мы не будем менять ничего, поэтому клиент это поймет так,
что сервер увеличил window size, и все пойдет как обычно.

Другие DPI спотыкаются, когда заголовок "Host:" пишется в другом регистре : например, "host:".
Кое-где работает добавление дополнительного пробела после метода : "GET /" => "GET  /".

Как это реализовать на практике в системе linux
-----------------------------------------------

Перехватить пакет с 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 будет небольшая задержка при установлении соединения.
От 0.5 до 1.5 сек.
Чтобы не трогать хосты, которые не блокируются провайдером, можно сделать такой ход.
Создать список заблоченых доменов или скачать его с 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.
Она берет следующие параметры :
 --qnum=200		; номер очереди
 --wsize=4		; менять tcp window size на указанный размер
 --hostcase		; менять регистр заголовка "Host:"
 --daemon		; демонизировать прогу

tpws
-----

tpws - это transparent proxy.
 --bind-addr		; на каком адресе слушать. может быть ipv4 или ipv6 адрес. если не указано, то слушает на всех адресах ipv4 и ipv6
 --port=<port>		; на каком порту слушать
 --split-http-req=method|host	; способ разделения http запросов на сегменты : около метода (GET,POST) или около заголовка Host
 --hostcase             ; замена "Host:" => "host:"
 --methodspace		; добавить пробел после метода : "GET /" => "GET  /"
 --daemon               ; демонизировать прогу
 --user=<username>	; менять uid процесса
 
Провайдеры
----------

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 "Location: http://95.167.13.50" --algo bm -j DROP --from 40 --to 300 
Ростелеком : см tkt

Пример установки на debian 7
----------------------------

Установить пакеты :
 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_reestr.sh
Зашедулить задание обновления листа :
 crontab -e
 Создать строчку  "0 12 * * */2 /opt/zapret/ipset/get_reestr.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
В зависимости от вашего провайдера либо внести нужные записи в /etc/firewall.user, либо
скопировать 99-zapret в /etc/hotplug.d/firewall (сначала нужно mkdir /etc/hotplug.d/firewall).
В /etc/hotplug.d/firewall/99-zapret выбрать нужного провайдера.
/etc/init.d/firewall restart
Посмотреть через iptables -L или через luci вкладку "firewall" появились ли нужные правила.
Зашедулить задание обновления листа :
 crontab -e
 Создать строчку  "0 12 * * */2 /opt/zapret/ipset/get_reestr.sh". Это значит в 12:00 каждые 2 дня обновлять список.

Если у вас linux x64, то вместо компиляции toolchain можно использовать пре-компилированный SDK от разработчиков openwrt.
https://downloads.openwrt.org/
Найдите вашу версию openwrt, найдите вашу архитектуру, скачайте файл "OpenWrt-SDK-*".
Фактически это тот же buildroot, только в нем уже подготовлен toolchain для нужной версии openwrt,
нужной target архитектуры и хост-системы linux x64.