zapret v.31

English
-------

For english version refer to docs/readme.eng.txt

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

Автономно, без задействования сторонних серверов, обойти блокировки веб сайтов http и https на DPI.

Как это работает
----------------

В самом простейшем случае вы имеете дело с пассивным DPI. Пассивный DPI может читать трафик
из потока, может инжектить свои пакеты, но не может блокировать проходящие пакеты.
Если запрос "плохой", пассивный DPI инжектит пакет RST, опционально дополняя его пакетом http redirect.
Если фейк пакет инжектится только для клиента, в этом случае можно обойтись командами iptables
для дропа RST и/или редиректа на заглушку по определенным условиям, которые нужно подбирать
для каждого провайдера индивидуально. Так мы обходим последствия срабатывания триггера запрета.
Если пассивный DPI направляет пакет RST в том числе и серверу, то вы ничего с этим не сможете сделать.
Ваша задача - не допустить срабатывания триггера запрета. Одними iptables уже не обойдетесь.
Этот проект нацелен именно на предотвращение срабатывания запрета, а не ликвидацию его последствий.

Активный DPI ставится в разрез провода и может дропать пакеты по любым критериям,
в том числе распознавать TCP потоки и блокировать любые пакеты, принадлежащие потоку.

Как не допустить срабатывания триггера запрета ? Послать то, на что DPI не расчитывает
и что ломает ему алгоритм распознавания запросов и их блокировки.

Некоторые 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."

Существует и более продвинутая магия, направленная на преодоление DPI на пакетном уровне.


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

Если кратко, то варианты можно классифицировать по следующей схеме :

1) Пассивный DPI, не отправляющий RST серверу. Помогут индивидуально настраиваемые под провайдера команды iptables.
На rutracker в  разделе "обход блокировок - другие способы" по этому вопросу существует отдельная тема.
В данном проекте не рассматривается. Если вы не допустите срабатывание триггера запрета, то и не придется
бороться с его последствиями.
2) Модификация TCP соединения на уровне потока. Реализуется через proxy или transparent proxy.
3) Модификация TCP соединения на уровне пакетов. Реализуется через обработчик очереди NFQUEUE и raw сокеты.

Для вариантов 2 и 3 реализованы программы tpws и nfqws соответственно.
Чтобы они работали, необходимо их запустить с нужными параметрами и перенаправить на них определенный трафик
средствами iptables.


Для перенаправления tcp соединения на transparent proxy используются команды следующего вида :

проходящий трафик :
iptables -t nat -I PREROUTING -i <внутренний_интерфейс> -p tcp --dport 80 -j DNAT --to 127.0.0.1:1188
исходящий трафик :
iptables -t nat -I OUTPUT -o <внешний_интерфейс> -p tcp --dport 80 -m owner ! --uid-owner tpws -j DNAT --to 127.0.0.1:1188

DNAT на localhost работает в цепочке OUTPUT, но не работает в цепочке PREROUTING без включения параметра route_localnet :

sysctl -w net.ipv4.conf.<внутренний_интерфейс>.route_localnet=1

Можно использовать "-j REDIRECT --to-port 1188" вместо DNAT , однако в этом случае процесс transparent proxy
должен слушать на ip адресе входящего интерфейса или на всех адресах. Слушать на всех - не есть хорошо
с точки зрения безопасности. Слушать на одном (локальном) можно, но в случае автоматизированного
скрипта придется его узнавать, потом динамически вписывать в команду. В любом случае требуются дополнительные усилия.

Фильтр по owner необходим для исключения рекурсивного перенаправления соединений от самого tpws.
tpws запускается под пользователем "tpws", для него задается исключающее правило.


Для перенаправления на очередь NFQUEUE исходящего и проходящего в сторону внешнего интерфейса трафика используются
команды следующего вида :

iptables -t mangle -I POSTROUTING -o <внешний_интерфейс> -p tcp --dport 80 -j NFQUEUE --queue-num 200 --queue-bypass


Чтобы не трогать трафик на незаблокированные адреса, можно взять список заблокированных хостов, заресолвить его
в IP адреса и загнать в ipset zapret, затем добавить фильтр в команду :

iptables -t mangle -I POSTROUTING -o <внешний_интерфейс> -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 -o <внешний_интерфейс> -p tcp --dport 80 -m connbytes --connbytes-dir=original --connbytes-mode=packets --connbytes 2:4 -m set --match-set zapret dst -j NFQUEUE --queue-num 200 --queue-bypass


Если ваше устройство поддерживает аппаратное ускорение (flow offloading, hardware nat, hardware acceleration), то iptables могут не работать.
При включенном offloading пакет не проходит по обычному пути netfilter. 
Необходимо его отключить. Да, ваш хилый роутер уже не потянет гигабит, даже 200-250 может не потянуть, а на торрентах и того меньше.
Но если у вас такой линк, и вы хотите продвинутых вещей от роутера, то вам стоит задуматься о покупке mini pc с двумя или более gigabit ethernet.

В новых ядрах (и в более старых, openwrt портировал изменение на 4.14) присутствует software flow offloading (SFO).
Пакеты, проходящие через SFO, так же проходят мимо большей части механизмов iptables.
При включенном SFO работает DNAT/REDIRECT (tpws). Эти соединения исключаются из offloading.
Однако, остальные соединения идут через SFO, потому NFQUEUE будет срабатывать только до помещения
соединения в flowtable. Практически это означает, что nfqws будет работать на window size changing,
но не будут работать опции по модификации содержимого пакетов.
Offload включается через специальный target в iptables "FLOWOFFLOAD". Не обязательно пропускать весь трафик через offload.
Можно исключить из offload соединения, которые должны попасть на tpws или nfqws.
Однако, openwrt не предусматривает выборочного управления offload. Если вы хотите с этим связаться,
вам придется городить свой собственный огород вокруг этого.


Особенности применения ip6tables
--------------------------------

ip6tables работают почти точно так же, как и ipv4, но есть ряд важных нюансов.
В DNAT следует брать адрес --to в квадратные скобки. Например :

 iptables -t nat -I OUTPUT -p tcp --dport 80 -m owner ! --uid-owner tpws -j DNAT --to [::1]:1188
 
Параметра route_localnet не существует для ipv6.
DNAT на localhost (::1) возможен только в цепочке OUTPUT.
В цепочке PREROUTING DNAT возможен на любой global address или на link local address того же интерфейса,
откуда пришел пакет.
NFQUEUE работает без изменений.


Когда это работать не будет
---------------------------

* Если подменяется DNS. С этой проблемой легко справиться.
* Если блокировка осуществляется по IP.
* Если соединение проходит через фильтр, способный реконструировать TCP соединение, и который
следует всем стандартам. Например, нас заворачивают на squid. Соединение идет через полноценный стек tcpip
операционной системы, фрагментация отпадает сразу как средство обхода. Squid правильный, он все найдет
как надо, обманывать его бесполезно.
НО. Заворачивать на squid могут позволить себе лишь небольшие провайдеры, поскольку это очень ресурсоемко.
Большие компании обычно используют DPI, который расчитан на гораздо большую пропускную способность.
Может применяться комбинированный подход, когда на DPI заворачивают только IP из "плохого" списка,
и дальше уже DPI решает пропускать или нет. Так можно снизить нагрузку на DPI в десятки, если не сотни раз,
а следовательно не покупать очень дорогие решения, обойдясь чем-то существенно более дешевым.
Мелкие провайдеры могут покупать услугу фильтрации у вышестоящих, чтобы самим не морочиться, и
они уже будут применять DPI.


nfqws
-----

Эта программа - модификатор пакетов и обработчик очереди NFQUEUE.

 --debug=0|1				; 1=выводить отладочные сообщения
 --daemon				; демонизировать прогу
 --pidfile=<file>			; сохранить PID в файл
 --user=<username>			; менять uid процесса
 --uid=uid[:gid]			; менять uid процесса
 --qnum=200				; номер очереди
 --wsize=4				; менять tcp window size на указанный размер (устарело !)
 --hostcase				; менять регистр заголовка "Host:" по умолчанию на "host:".
 --hostnospace				; убрать пробел после "Host:" и переместить его в конец значения "User-Agent:" для сохранения длины пакета
 --hostspell=HoST			; точное написание заголовка Host (можно "HOST" или "HoSt"). автоматом включает --hostcase
 --dpi-desync[=<mode>]			; атака по десинхронизации DPI. mode : fake rst rstack disorder disorder2 split split2
 --dpi-desync-fwmark=<int|0xHEX>        ; бит fwmark для пометки десинхронизирующих пакетов, чтобы они повторно не падали в очередь. default = 0x40000000
 --dpi-desync-ttl=<int>                 ; установить ttl для десинхронизирующих пакетов
 --dpi-desync-fooling=none|md5sig|ts|badseq|badsum ; дополнительные методики как сделать, чтобы фейковый пакет не дошел до сервера
 --dpi-desync-retrans=0|1               ; (только для fake,rst,rstack) 0(default)=отправлять оригинал следом за фейком  1=дропать оригинал, заставляя ОС выполнять ретрансмиссию через 0.2 сек
 --dpi-desync-skip-nosni=0|1		; 1(default)=не применять dpi desync для запросов без hostname в SNI, в частности для ESNI
 --dpi-desync-split-pos=<1..1500>	; (только для disorder) разбивать пакет на указанной позиции
 --dpi-desync-any-protocol=0|1		; 0(default)=работать только по http request и tls clienthello  1=по всем непустым пакетам данных
 --hostlist=<filename>			; применять дурение только к хостам из листа

Параметры манипуляции могут сочетаться в любых комбинациях.

ЗАМЕЧАНИЕ. Параметр --wsize считается устаревшим и более не поддерживается в скриптах.
Функции сплита выполняются в рамках атаки десинхронизации. Это быстрее и избавляет от целого ряда недостатков wsize.

АТАКА ДЕСИНХРОНИЗАЦИИ DPI
Суть ее в следующем. После выполнения tcp 3-way handshake идет первый пакет с данными от клиента.
Там обычно "GET / ..." или TLS ClientHello. Мы дропаем этот пакет, заменяя чем-то другим.
Это может быть поддельная версия с безобидным, но валидным запросом http или https (вариант fake),
пакет сброса соединения (варианты rst, rstack), разбитый на части оригинальный пакет с перепутанным
порядком следования сегментов + фейк-сегмент посередине (disorder).
В литературе такие атаки еще называют TCB desynchronization и TCB teardown.
Надо, чтобы фейковые пакеты дошли до DPI, но не дошли до сервера.
На вооружении есть следующие возможности : установить низкий TTL, посылать пакет с инвалидной чексуммой,
добавлять tcp option "MD5 signature", испортить sequence numbers. Все они не лишены недостатков.

* md5sig работает не на всех серверах. Пакеты с md5 обычно отбрасывают только linux.
* badsum не сработает, если ваше устройство за NAT, который не пропускает пакеты с инвалидной суммой.
  Linux NAT по умолчанию их не пропускает без особой настройки "sysctl -w net.netfilter.nf_conntrack_checksum=0".
  В openwrt она сделана из коробки, в других роутерах как правило нет, и не всегда это можно изменить.
  Если nfqws работает на роутере, то не обязательно выключать nf_conntrack_checksum. Фейковый пакет не проходит FORWARD, он идет через OUTPUT.
  Но если роутер за другим NAT, например провайдерским, и он не пропускает invalid packets, вы ничего не сможете с этим сделать.
* пакеты с badseq будут наверняка отброшены принимающим узлом, но так же и DPI, если он ориентируется на sequence numbers
* TTL казалось бы - лучший вариант, но он требует индивидуальной настройки под каждого провайдера. Если DPI находится дальше локальных
  сайтов провайдера, то вы можете отрезать себе доступ к ним. Необходим ip exclude list, заполняемый вручную.
  Вместе с ttl можно применять md5sig. Это ничего не испортит, зато дает неплохой шанс работы сайтов, до которых "плохой" пакет дойдет по TTL.
  Если не удается найти автоматическое решение, воспользуйтесь файлом zapret-hosts-user-exclude.txt.
  КАКИМ СТОИТ ВЫБИРАТЬ TTL : найдите минимальное значение, при котором обход еще работает. Это и будет номер хопа вашего DPI.

Режимы дурения могут сочетаться в любых комбинациях. --dpi-desync-fooling берет множество значений через запятую.

Для режимов fake, rst, rstack после фейка отправляем оригинальный пакет. Можно его отправить сразу следом за фейком, а можно его просто дропнуть.
Если его дропнуть, ОС выполнит ретрансмиссию. Первая ретрансмиссия случается через 0.2 сек, потом задержка увеличивается экспоненциально.
Задержка может дать надежную гарантию, что пакеты пойдут именно в нужном порядке и будут именно в нем обработаны на DPI.
По умолчанию используется первый вариант, т.к. он быстрее.

Режим disorder делит оригинальный пакет на 2 части и отправляет следующую комбинацию в указанном порядке :
1. 2-я часть пакета
2. поддельная 1-я часть пакета, поле данных заполнено нулями
3. 1-я часть пакета
4. поддельная 1-я часть пакета, поле данных заполнено нулями. отсылка 2-й раз.
Оригинальный пакет дропается всегда. Параметр --dpi-desync-split-pos позволяет указать байтовую позицию, на которой
происходит разбивка. По умолчанию - 3. Если позиция больше длины пакета, позиция выбирается 1.
Этой последовательностью для DPI максимально усложняется задача реконструкции начального сообщения,
по которому принимается решение о блокировке. Некоторым DPI хватит и tcp сегментов в неправильном порядке,
поддельные части сделаны для дополнительной надежности и более сложных алгоритмов реконструкции.
Режим disorder2 отключает отправку поддельных частей.

Режим split очень похож на disorder, только нет изменения порядка следования сегментов :
1. поддельная 1-я часть пакета, поле данных заполнено нулями
2. 1-я часть пакета
3. поддельная 1-я часть пакета, поле данных заполнено нулями. отсылка 2-й раз.
4. 2-я часть пакета
Режим split2 отключает отправку поддельных частей.
Он может быть использован как более быстрая альтернатива --wsize.

disorder2 и split2 не предполагают отсылку фейк пакетов, поэтому опции ttl и fooling неактуальны.

Есть DPI, которые анализируют ответы от сервера, в частности сертификат из ServerHello, где прописаны домены.
Подтверждением доставки ClientHello является ACK пакет от сервера с номером ACK sequence, соответствующим длине ClientHello+1.
В варианте disorder обычно приходит сперва частичное подтверждение (SACK), потом полный ACK.
Если вместо ACK или SACK идет RST пакет с минимальной задержкой, то DPI вас отсекает еще на этапе вашего запроса.
Если RST идет после полного ACK спустя задержку, равную примерно пингу до сервера,
тогда вероятно DPI реагирует на ответ сервера.
DPI может отстать от потока, если ClientHello его удовлетворил и не проверять ServerHello.
Тогда вам повезло. Вариант fake может сработать.
Если же он не отстает и упорно проверяет ServerHello, еще и выполняя реконструкцию сегментов TCP,
то сделать с этим что-либо вряд ли возможно без помощи со стороны сервера.
Лучшее решение - включить на сервере поддержку TLS 1.3. В нем сертификат сервера передается в зашифрованном виде.
Это рекомендация ко всем админам блокируемых сайтов. Включайте TLS 1.3. Так вы дадите больше возможностей преодолеть DPI.

Хосты извлекаются из Host: хедера обычных http запросов и из SNI в TLS ClientHello.
Субдомены учитываются автоматически. Поддерживаются листы gzip.

iptables для задействования атаки на первый пакет данных :

iptables -t mangle -I POSTROUTING -p tcp -m multiport --dports 80,443 -m connbytes --connbytes-dir=original --connbytes-mode=packets --connbytes 2:4 -m mark ! --mark 0x40000000/0x40000000 -j NFQUEUE --queue-num 200 --queue-bypass

Этот вариант применяем, когда DPI не следит за всеми запросами http внутри keep-alive сессии.
Если следит, направляем только первый пакет от https и все пакеты от http :

iptables -t mangle -I POSTROUTING -p tcp --dport 80 -m connbytes --connbytes-dir=original --connbytes-mode=packets --connbytes 2:4 -m mark ! --mark 0x40000000/0x40000000 -j NFQUEUE --queue-num 200 --queue-bypass
iptables -t mangle -I POSTROUTING -p tcp --dport 443 -m mark ! --mark 0x40000000/0x40000000 -j NFQUEUE --queue-num 200 --queue-bypass

mark нужен, чтобы сгенерированный поддельный пакет не попал опять к нам на обработку. nfqws выставляет fwmark при его отсылке.
nfqws способен самостоятельно различать помеченные пакеты, фильтр в iptables по mark нужен только для увеличения скорости.

Почему --connbytes 2:4 : 2 - иногда данные идут в 3-м пакете 3-way handshake. 3 - стандартная ситуация. 4 - для надежности. на случай, если выполнялась одна ретрансмиссия


tpws
-----

tpws - это transparent proxy.
 --debug=0|1|2		; Количество буковок в output : 0(default)=тихо, 1=подробно, 2=отладка
 --daemon               ; демонизировать прогу
 --pidfile=<file>	; сохранить PID в файл
 --user=<username>	; менять uid процесса
 --uid=uid[:gid]	; менять uid процесса
 --bind-addr		; на каком адресе слушать. может быть ipv4 или ipv6 адрес. если не указано, то слушает на всех адресах ipv4 и ipv6
 			; если указан ipv6 link local, то требуется указать с какого он интерфейса через --bind-iface6
 --bind-linklocal=prefer|force	; если prefer, то найти link local от iface6. если не найдено - использовать первый адрес любого типа.
 				; если force и link local не найден - выход по ошибке.
 --bind-iface4=<iface>	; слушать на первом ipv4 интерфейса iface
 --bind-iface6=<iface>	; слушать на первом ipv6 интерфейса iface. при bind-linklocal определяет интерфейс, откуда брать ipv6 link local
 --bind-wait-ifup=<sec>	; ждать до N секунд появления и поднятия интерфейса
 --bind-wait-ip=<sec>	; ждать до N секунд получения IP адреса (если задан --bind-wait-ifup - время идет после поднятия интерфейса)
 --bind-wait-ip-linklocal=<sec> ; (только если заданы --bind-wait-ip и --bind-linklocal=prefer) согласиться на global address после N секунд
 --socks		; вместо прозрачного прокси реализовать socks4/5 proxy
 --no-resolve		; запретить ресолвинг имен через socks5
 --port=<port>		; на каком порту слушать
 --maxconn=<max_connections> ; максимальное количество соединений от клиентов к прокси
 --maxfiles=<max_open_files>    ; макс количество файловых дескрипторов (setrlimit). мин требование (X*connections+16), где X=6 в tcp proxy mode, X=4 в режиме тамперинга.
				; стоит сделать запас с коэффициентом как минимум 1.5. по умолчанию maxfiles (X*connections)*1.5+16
 --max-orphan-time=<sec>; если вы запускате через tpws торрент-клиент с множеством раздач, он пытается установить очень много исходящих соединений,
			; большая часть из которых отваливается по таймату (юзера сидят за NAT, firewall, ...)
			; установление соединения в linux может длиться очень долго. локальный конец отвалился, перед этим послав блок данных,
			; tpws ждет подключения удаленного конца, чтобы отослать ему этот блок, и зависает надолго.
			; настройка позволяет сбрасывать такие подключения через N секунд, теряя блок данных. по умолчанию 5 сек. 0 означает отключить функцию
			; эта функция не действует на успешно подключенные ранее соединения

 --local-rcvbuf=<bytes> ; SO_RCVBUF для соединений client-proxy
 --local-sndbuf=<bytes> ; SO_SNDBUF для соединений client-proxy
 --remote-rcvbuf=<bytes> ; SO_RCVBUF для соединений proxy-target
 --remote-sndbuf=<bytes> ; SO_SNDBUF для соединений proxy-target
 --skip-nodelay		; не устанавливать в исходящих соединения TCP_NODELAY. несовместимо со split.

 --split-http-req=method|host	; способ разделения http запросов на сегменты : около метода (GET,POST) или около заголовка Host
 --split-pos=<offset>	; делить все посылы на сегменты в указанной позиции. Если отсыл длинее 8Kb (размер буфера приема), то будет разделен каждый блок по 8Kb.
 --hostcase             ; менять регистр заголовка "Host:". по умолчанию на "host:".
 --hostspell=HoST	; точное написание заголовка Host (можно "HOST" или "HoSt"). автоматом включает --hostcase
 --hostdot		; добавление точки после имени хоста : "Host: kinozal.tv."
 --hosttab		; добавление табуляции после имени хоста : "Host: kinozal.tv\t"
 --hostnospace		; убрать пробел после "Host:"
 --hostpad=<bytes>	; добавить паддинг-хедеров общей длиной <bytes> перед Host:
 --methodspace		; добавить пробел после метода : "GET /" => "GET  /"
 --methodeol		; добавить перевод строки перед методом  : "GET /" => "\r\nGET  /"
 --unixeol		; конвертировать 0D0A в 0A и использовать везде 0A
 --hostlist=<filename>  ; действовать только над доменами, входящими в список из filename. поддомены автоматически учитываются. в файле должен быть хост на каждой строке.
			; список читается 1 раз при старте и хранится в памяти в виде иерархической структуры для быстрого поиска.
			; для списка РКН может потребоваться система с 128 Mb памяти ! расчитывайте требование RAM для процесса как 3-5 кратный размер файла списка.
			; по сигналу HUP список будет перечитан при следующем принятом соединении
			; список может быть запакован в gzip. формат автоматически распознается и разжимается

Параметры манипуляции могут сочетаться в любых комбинациях.
Есть исключения : split-pos заменяет split-http-req. hostdot и hosttab взаимоисключающи.

На прикладном уровне в общем случае нет гарантированного средства заставить ядро выплюнуть
блок данных, порезанным в определенном месте. ОС держит буфер отсылки (SNDBUF) у каждого сокета.
Если у сокета включена опция TCP_NODELAY и буфер пуст, то каждый send приводит к отсылке
отдельного ip пакета или группы пакетов, если блок не вмещается в один ip пакет.
Однако, если в момент send уже имеется неотосланный буфер, то ОС присоединит данные к нему,
никакой отсылки отдельным пакетом не будет. Но в этом случае и так нет никакой гарантии,
что какой-то блок сообщения пойдет в начале пакета, на что собственно и заточены DPI.
Разбиение будет производится согласно MSS, который зависит от MTU исходящего интерфейса.
Таким образом DPI, смотрящие в начало поля данных TCP пакета, будут поломаны в любом случае.
Протокол http относится к запрос-ответным протоколам. Новое сообщение посылается только тогда,
когда сервер получил запрос и полностью вернул ответ. Значит запрос фактически был не только отослан,
но и принят другой стороной, а следовательно буфер отсылки пуст, и следующие 2 send приведут
к отсылке сегментов данных разными ip пакетами.
Резюме : tpws гарантирует сплит только за счет раздельных вызовов send, что на практике
вполне достаточно для протоколов http(s).

tpws может биндаться только к одному ip или ко всем сразу.
Для бинда на все ipv4 укажите "0.0.0.0", на все ipv6 - "::". Без параметров биндаемся на все ipv4 и ipv6.
Параметры --bind-wait* могут помочь в ситуациях, когда нужно взять IP с интерфейса, но его еще нет, он не поднят
или не сконфигурирован.
В разных системах события ifup ловятся по-разному и не гарантируют, что интерфейс уже получил IP адрес определенного типа.
В общем случае не существует единого механизма повеситься на событие типа "на интерфейсе X появился link local address".

Параметры rcvbuf и sndbuf позволяют установить setsockopt SO_RCVBUF SO_SNDBUF для локального и удаленного соединения.

Если не указан ни один из параметров модификации содержимого, tpws работает в режиме "tcp proxy mode".
Он отличается тем, что в оба конца применяется splice для переброски данных из одного сокета в другой
без копирования в память процесса. Практически - это то же самое, но может быть чуть побыстрее.
TCP проксирование может быть полезно для обхода блокировок, когда DPI спотыкается на экзотических
хедерах IP или TCP. Вы вряд ли сможете поправить хедеры, исходящие от айфончиков и гаджетиков,
но на linux сможете влиять на них в какой-то степени через sysctl.
Когда соединение проходит через tpws, фактически прокси-сервер сам устанавливает подключение к удаленному
узлу от своего имени, и на это распространяются настройки системы, на которой работает прокси.
tpws можно использовать на мобильном устройстве, раздающем интернет на тарифе сотового оператора,
где раздача запрещена, в socks режиме даже без рута. Соединения от tpws неотличимы от соединений
с самого раздающего устройства. Отличить можно только по содержанию (типа обновлений windows).
Заодно можно и обойти блокировки. 2 зайца одним выстрелом.
Более подробную информацию по вопросу обхода ограничений операторов гуглите на 4pda.ru.

Режим "--socks" не требует повышенных привилегий (кроме бинда на привилегированные порты 1..1023).
Поддерживаются версии socks 4 и 5 без авторизации. Версия протокола распознается автоматически.
Подключения к IP того же устройства, на котором работает tpws, включая localhost, запрещены.
socks5 позволяет удаленно ресолвить хосты (curl : --socks5-hostname  firefox : socks_remote_dns=true).
tpws поддерживает эту возможность, однако используется блокирующий ресолвинг. Пока система
ресолвит хост (это может занять секунды), вся активность останавливается.
tpws полностью работает на асинхронных сокетах, но ресолвинг может попортить эту модель.
С ним возможны атаки DoS на tpws. Если tpws обслуживает множество клиентов, то из-за частого
ресолвинга качество обслуживания может существенно ухудшиться.
Если удаленный ресолвинг создает проблемы, настройте клиенты на локальный ресолвинг, включите опцию
--no-resolve на стороне tpws.

Параметр --hostpad=<bytes> добавляет паддинг-хедеров перед Host: на указанное количество байтов.
Если размер <bytes> слишком большой, то идет разбивка на разные хедеры по 2K.
Общий буфер приема http запроса - 64K, больший паддинг не поддерживается, да и http сервера
такое уже не принимают.
Полезно против DPI, выполняющих реассемблинг TCP с ограниченным буфером.
Если техника работает, то после некоторого количества bytes http запрос начнет проходить до сайта.
Если при этом критический размер padding около MTU, значит скорее всего DPI не выполняет реассемблинг пакетов, и лучше будет использовать обычные опции --split-…
Если все же реассемблинг выполняется, то критический размер будет около размера буфера DPI. Он может быть 4K или 8K, возможны и другие значения. 

--skip-nodelay может быть полезен, чтобы привести MTU к MTU системы, на которой работает tpws.
Это может быть полезно для скрытия факта использования VPN. Пониженный MTU - 1 из способов обнаружения
подозрительного подключения. С tcp proxy ваши соединения неотличимы от тех, что сделал бы сам шлюз.


Способы получения списка заблокированных IP
-------------------------------------------

1) Внесите заблокированные домены в ipset/zapret-hosts-user.txt и запустите ipset/get_user.sh
На выходе получите ipset/zapret-ip-user.txt с IP адресами.

Cкрипты с названием get_reestr_* оперируют дампом реестра заблокированных сайтов :

2) ipset/get_reestr_resolve.sh получает список доменов от rublacklist и дальше их ресолвит в ip адреса
в файл ipset/zapret-ip.txt.gz. В этом списке есть готовые IP адреса, но судя во всему они там в точности в том виде,
что вносит в реестр РосКомПозор. Адреса могут меняться, позор не успевает их обновлять, а провайдеры редко
банят по IP : вместо этого они банят http запросы с "нехорошим" заголовком "Host:" вне зависимости
от IP адреса. Поэтому скрипт ресолвит все сам, хотя это и занимает много времени.
Используется мультипоточный ресолвер mdig (собственная разработка).
Реестр РКН уже настолько огромен, что однопоточный ресолв займет вечность, а многопоточный хоть и тоже много времени,
но хотя бы оно конечно.

3) ipset/get_reestr_ip.txt
взять все IP адреса из реестра и загнать в ipset zapret/zapret6
на роутерах с <128 Mb RAM может сработать только с TMPDIR на внешнем носителе

4) ipset/get_reestr_combined.sh. для провайдеров, которые блокируют по IP https, а остальное по DPI.
IP https и IP без домена заносятся в ipset ipban, остальные в ipset zapret.
на роутерах с <128 Mb RAM может сработать только с TMPDIR на внешнем носителе

Скрипты 3 и 4 убирают из списка мусор. На данный момент мусором считается миллион+ забаненых telegram proxy IP.
Это сокращает размер списка кардинально. Большой объем памяти требуется только для временного хранения скачанного
реестра в /tmp. Потом из списка уберется мусор, он станет значительно легче, поместится в ipset даже на 64 Mb RAM.
Поэтому поможет задание TMPDIR на флэшку.

Cкрипты с названием get_antifilter_* оперируют списками адресов и масок подсетей с сайтов antifilter.network и antifilter.download :

5) ipset/get_antifilter_ip.sh. получает лист https://antifilter.network/download/ip.lst.
лист содержит огромное количество ip (> миллиона).
на роутерах с <128 Mb RAM даже не пытайтесь

7) ipset/get_antifilter_ipsmart.sh. получает лист https://antifilter.network/download/ipsmart.lst.
это умная суммаризация отдельных адресов из ip.lst по маскам от /32 до /22
количество префиксов измеряется всего лишь десятками тысяч, потому это лучшее решение для роутера с 64 Mb RAM

7) ipset/get_antifilter_ipsum.sh. получает лист https://antifilter.network/download/ipsum.lst.
это суммаризация отдельных адресов из ip.lst по маске /24
количество префиксов измеряется всего лишь десятками тысяч, потому можно использовать на роутерах с 64 Mb RAM

Все варианты рассмотренных скриптов автоматически создают и заполняют ipset.
Варианты 2-7 дополнительно вызывают вариант 1.

8) ipset/get_config.sh. этот скрипт вызывает то, что прописано в переменной GETLIST из файла config
Если переменная не определена, то ресолвятся лишь листы для ipset nozapret/nozapret6.

Листы РКН все время изменяются. Возникают новые тенденции. Требования к RAM могут меняться.
Поэтому необходима нечастая, но все же регулярная ревизия что же вообще у вас происходит на роутере.
Или вы можете узнать о проблеме лишь когда у вас начнет постоянно пропадать wifi, и вам придется
его перезагружать каждые 2 часа (метод кувалды).

Листы zapret-ip.txt и zapret-ipban.txt сохраняются в сжатом виде в файлы .gz.
Это позволяет снизить их размер во много раз и сэкономить место на роутере.

На роутерах не рекомендуется вызывать эти скрипты чаще раза за 2 суток, поскольку сохранение идет
либо во внутреннюю флэш память роутера, либо в случае extroot - на флэшку.
В обоих случаях слишком частая запись может убить флэшку, но если это произойдет с внутренней
флэш памятью, то вы просто убьете роутер.

Принудительное обновление ipset выполняет скрипт ipset/create_ipset.sh.
Если передан параметр "no-update", скрипт не обновляет ipset, а только создает его при его отсутствии и заполняет.
Это полезно, когда могут случиться несколько последовательных вызовов скрипта. Нет смысла несколько раз перезаполнять
ipset, это длительная операция на больших листах. Листы можно обновлять раз в несколько суток, и только тогда
вызывать create_ipset без параметра "no-update". Во всех остальных случаях стоит применять "no-update".
Список РКН уже достиг внушительных размеров в сотни тысяч IP адресов. Поэтому для оптимизации ipset
применяется утилита ip2net. Она берет список отдельных IP адресов и пытается интеллектуально создать из него подсети для сокращения
количества адресов. ip2net написан на языке C, поскольку операция ресурсоемкая. Иные способы роутер может не потянуть.
Если ip2net скомпилирован или в каталог ip2net скопирован бинарик, то скрипт create_ipset.sh использует ipset типа hash:net, прогоняя список через ip2net.
В противном случае используется ipset типа hash:ip, список загружается как есть.
Соответственно, если вам не нравится ip2net, просто уберите из каталога ip2net бинарик.

Можно внести список доменов в ipset/zapret-hosts-user-ipban.txt. Их ip адреса будут помещены
в отдельный ipset "ipban". Он может использоваться для принудительного завертывания всех
соединений на прозрачный proxy "redsocks" или на VPN.

IPV6 : если включен ipv6, то дополнительно создаются листы с таким же именем, но с "6" на конце перед расширением.
zapret-ip.txt => zapret-ip6.txt
Создаются ipset-ы zapret6 и ipban6.
Листы с antifilter не содержат список ipv6 адресов.

СИСТЕМА ИСКЛЮЧЕНИЯ IP. Все скрипты ресолвят файл zapret-hosts-user-exclude.txt, создавая zapret-ip-exclude.txt и zapret-ip-exclude6.txt.
Они загоняются в ipset-ы nozapret и nozapret6. Все правила, создаваемые init скриптами, создаются с учетом этих ipset.
Помещенные в них IP не участвуют в процессе.
zapret-hosts-user-exclude.txt может содержать домены, ipv4 и ipv6 адреса или подсети.


ip2net
------

Утилита ip2net предназначена для преобразования ipv4 или ipv6 списка ip в список подсетей
с целью сокращения размера списка. Входные данные берутся из stdin, выходные выдаются в stdout.
 -4                             ; лист - ipv4 (по умолчанию)
 -6                             ; лист - ipv6
 --prefix-length=min[-max]      ; диапазон рассматриваемых длин префиксов. например : 22-30 (ipv4), 56-64 (ipv6)
 --v4-threshold=mul/div         ; ipv4 : включать подсети, в которых заполнено по крайней мере mul/div адресов. например : 3/4
 --v6-threshold=N               ; ipv6 : минимальное количество ip для создания подсети
В списке могут присутствовать записи вида ip/prefix и ip1-ip2. Такие записи выкидываются в stdout без изменений.
Они принимаются командой ipset. ipset умеет для листов hash:net из ip1-ip2 делать оптимальное покрытие ip/prefix.

Выбирается подсеть, в которой присутствует указанный минимум адресов.
Для ipv4 минимум задается как процент от размера подсети (mul/div. например, 3/4), для ipv6 минимум задается напрямую.

Размер подсети выбирается следующим алгоритмом :
Сначала в указанном диапазоне длин префиксов ищутся подсети, в которых количество адресов - максимально.
Если таких сетей найдено несколько, берется наименьшая сеть (префикс больше).
Например, заданы параметры v6_threshold=2 prefix_length=32-64, имеются следующие ipv6 :
1234:5678:aaaa::5
1234:5678:aaaa::6
1234:5678:aaac::5
Результат будет :
1234:5678:aaa8::/45
Эти адреса так же входят в подсеть /32. Однако, нет смысла проходиться ковровой бомбардировкой,
когда те же самые адреса вполне влезают в /45 и их ровно столько же.
Если изменить v6_threshold=4, то результат будет :
1234:5678:aaaa::5
1234:5678:aaaa::6
1234:5678:aaac::5
То есть ip не объединятся в подсеть, потому что их слишком мало.
Если изменить prefix_length=56-64, результат будет :
1234:5678:aaaa::/64
1234:5678:aaac::5

Требуемое процессорное время для вычислений сильно зависит от ширины диапазона длин префиксов, размера искомых подсетей и длины листа.
Если ip2net думает слишком долго, не используйте слишком большие подсети и уменьшите диапазон длин префиксов.
Учтите, что арифметика mul/div - целочисленная. При превышении разрядной сетки 32 bit результат непредсказуем.
Не надо делать такое :  5000000/10000000. 1/2 - гораздо лучше.


Фильтрация по именам доменов
----------------------------

Альтернативой ipset является использование tpws или nfqws со списком доменов.
Может быть только один hostlist.

Поддерживаются 2 варианта :
1) Внесите домены для дурения в ipset/zapret-hosts-users.txt. Удалите ipset/zapret-hosts.txt.gz.
Тогда init скрипт будет запускать tpws с листом zapret-hosts-users.txt.

2) Список доменов РКН может быть получен скриптом ipset/get_reestr_hostlist.sh - кладется в ipset/zapret-hosts.txt.gz.
Этот скрипт автоматически добавляет к списку РКН домены из zapret-hosts-user.txt.
init скрипт будет запускать tpws с листом zapret-hosts.txt.gz.

При фильтрации по именам доменов демон должен запускаться без фильтрации по ipset.
Весь трафик http идет через демон, и он решает нужно ли применять дурение в зависимости от поля Host: в http запросе.
Это создает повышенную нагрузку на систему.
Сам поиск по доменам работает очень быстро, нагрузка связана с прокачиванием объема данных через процесс.
При использовании больших списков, в том числе списка РКН, оцените объем RAM на роутере !
Если после запуска демона RAM под завязку или случаются oom, значит нужно отказаться от таких больших списков.


Проверка провайдера
-------------------

Перед настройкой нужно провести исследование какую бяку устроил вам ваш провайдер.

Нужно выяснить не подменяет ли он DNS и какой метод обхода DPI работает.
В этом вам поможет скрипт https://github.com/ValdikSS/blockcheck.

Если DNS подменяется, но провайдер не перехватывает обращения к сторонним DNS, поменяйте DNS на публичный.
Например : 8.8.8.8, 8.8.4.4, 1.1.1.1, 1.0.0.1, 9.9.9.9
Если DNS подменяется и провайдер перехватывает обращения к сторонним DNS, настройте dnscrypt.

Если blockcheck не определил рабочие методы обхода, попробуйте атаку десинхронизации с различными параметрами.

Проанализируйте какие методы дурения DPI работают, в соответствии с ними настройте /opt/zapret/config.


Выбор параметров
----------------

Файл /opt/zapret/config используется различными компонентами системы и содержит основные настройки.
Его нужно просмотреть и при необходимости отредактировать.
Выберите MODE :

nfqws_all_desync - использовать nfqws для атаки десинхронизации DPI на http и https для всех IP
nfqws_ipset_desync - использовать nfqws для атаки десинхронизации DPI на http и https только на IP из ipset "zapret"
nfqws_hostlist_desync - использовать nfqws для атаки десинхронизации DPI на http и https только на хосты из hostlist.
tpws_ipset - использовать tpws для модификации трафика на порт 80 только на IP из ipset "zapret"
tpws_ipset_https - использовать tpws для модификации трафика на порты 80 и 443 только на IP из ipset "zapret"
tpws_all - использовать tpws для модификации трафика на порт 80 для всех IP
tpws_all_https - использовать tpws для модификации трафика на порты 80 и 443 для всех IP
tpws_hostlist - пропускать через tpws весь трафик на порт 80. tpws применяет дурение только к хостам из hostlist.
ipset - только заполнить ipset. ipset может быть применен для заворота трафика на прокси или на VPN
custom - нужно самому запрограммировать запуск демонов в init скрипте и правила iptables

Для tpws отдельно настраиваются опции для http и https :

TPWS_OPT_HTTP="--hostspell=HOST --split-http-req=method"
TPWS_OPT_HTTPS="--split-pos=3"

Опции nfqws для атаки десинхронизации DPI :

DESYNC_MARK=0x40000000
NFQWS_OPT_DESYNC="--dpi-desync=fake --dpi-desync-ttl=0 --dpi-desync-fooling=badsum --dpi-desync-fwmark=$DESYNC_MARK"


Параметр GETLIST указывает инсталятору install_easy.sh какой скрипт дергать
для обновления списка заблокированных ip или хостов.
Он же вызывается через get_config.sh из запланированных заданий (crontab или systemd timer).
Поместите сюда название скрипта, который будете использовать для обновления листов.
Если не нужно, то параметр следует закомментировать.

Можно индивидуально отключить ipv4 или ipv6. Если параметр закомментирован или не равен "1",
использование протокола разрешено.
#DISABLE_IPV4=1
DISABLE_IPV6=1

Количество потоков для многопоточного DNS ресолвера mdig (1..100).
Чем их больше, тем быстрее, но не обидится ли на долбежку ваш DNS сервер ?
MDIG_THREADS=30

Место для хранения временных файлов. При скачивании огромных реестров в /tmp места может не хватить.
Если файловая система на нормальном носителе (не встроенная память роутера), то можно
указать место на флэшке или диске.
TMPDIR=/opt/zapret/tmp

Опции для создания ipset-ов
IPSET_OPT="hashsize 262144 maxelem 2097152"
ПРО РУГАНЬ в dmesg по поводу нехватки памяти.
Может так случиться, что памяти в системе достаточно, но при попытке заполнить огромный ipset
ядро начинает громко ругаться, ipset заполняется не полностью.
Вероятная причина в том, что превышается hashsize, заданный при создании ipset (create_ipset.sh).
Происходит переаллокация списка, не находится непрерывных фрагментов памяти нужной длины.
Это лечится увеличением hashsize. Но чем больше hashsize, тем больше занимает ipset в памяти.
Задавать слишком большой hashsize для недостаточно больших списков нецелесообразно.

Опции для вызова ip2net. Отдельно для листов ipv4 и ipv6.
IP2NET_OPT4="--prefix-length=22-30 --v4-threshold=3/4"
IP2NET_OPT6="--prefix-length=56-64 --v6-threshold=5"

Следующие настройки не актуальны для openwrt :

Если ваша система работает как роутер, то нужно вписать названия внутреннего и внешнего интерфейсов :
IFACE_LAN=eth0
IFACE_WAN=eth1
ВАЖНО : настройка маршрутизации , маскарада и т.д. не входит в задачу zapret.
Включаются только режимы, обеспечивающие перехват транзитного трафика.

Параметр INIT_APPLY_FW=1 разрешает init скрипту самостоятельно применять правила iptables.
При иных значениях или если параметр закомментирован, правила применены не будут.
Это полезно, если у вас есть система управления фаерволом, в настройки которой и следует прикрутить правила.

Прикручивание к системе управления фаерволом или своей системе запуска
----------------------------------------------------------------------

Если вы используете какую-то систему управления фаерволом, то она может вступать в конфликт
с имеющимся скриптом запуска. При повторном применении правил она могла бы поломать настройки iptables от zapret.
В этом случае правила для iptables должны быть прикручены к вашему фаерволу отдельно от запуска tpws или nfqws.

Следующие вызовы позволяют применить или убрать правила iptables отдельно :

 /opt/zapret/init.d/sysv/zapret start-fw
 /opt/zapret/init.d/sysv/zapret stop-fw
 
А так можно запустить или остановить демоны отдельно от фаервола :

 /opt/zapret/init.d/sysv/zapret start-daemons
 /opt/zapret/init.d/sysv/zapret stop-daemons
 
Вариант custom
--------------

custom код вынесен в отдельный shell include
/opt/zapret/init.d/sysv/custom
или
/opt/zapret/init.d/openwrt/custom

Нужно свой код вписать в функции :
zapret_custom_daemons
zapret_custom_firewall

В файле custom пишите ваш код, пользуясь хелперами из "functions" или "zapret".
Смотрите как там сделано добавление iptables или запуск демонов.
Используя хелпер функции, вы избавитесь от необходимости учитывать все возможные случаи
типа наличия/отсутствия ipv6, является ли система роутером, имена интерфейсов, ...
Хелперы это учитывают , вам нужно сосредоточиться лишь на фильтрах iptables и
параметрах демонов.

Код для openwrt и sysv немного отличается. В sysv нужно обрабатывать и запуск, и остановку.
Запуск это или остановка передается в параметре $1 (0 или 1).
В openwrt за остановку демонов отвечает procd, а firewall вычищается при "fw3 restart",
потому нет необходимости реализовывать логику останова.

При апгрейде нужно сохранить лишь custom, другие файлы править не надо.

Пример установки на debian-подобную систему
-------------------------------------------

На debian основано большое количество дистрибутивов linux, включая ubuntu.
Здесь рассматриваются прежде всего Debian 8+ и Ubuntu 16+.
Но с большой вероятностью может сработать и на производных от них.
Главное условие - наличие systemd, apt и нескольких стандартных пакетов в репозитории.

Установить пакеты :
 apt-get update
 apt-get install ipset curl dnsutils git

Скопировать директорию zapret в /opt или скачать через git :
 cd /opt
 git clone --depth 1 https://github.com/bol-van/zapret

Запустить автоинсталятор бинариков. Он сам определит рабочую архитектуру и настроит все бинарики.
 /opt/zapret/install_bin.sh
АЛЬТЕРНАТИВА : make -C /opt/zapret. Получите динамические бинарики под вашу ось.
Для сборки требуются dev пакеты : zlib1g-dev libcap-dev libnetfilter-queue-dev

Настроить параметры согласно разделу "Выбор параметров".

Создать ссылку на service unit в systemd :
 ln -fs /opt/zapret/init.d/systemd/zapret.service /lib/systemd/system

Удалить старые листы, если они были созданы ранее :
 /opt/zapret/ipset/clear_lists.sh
По желанию прописать в /opt/zapret/ipset/zapret-hosts-user.txt свои домены.
Выполнить скрипт обновления листа :
 /opt/zapret/ipset/get_config.sh
Настроить таймер systemd для обновления листа :
 ln -fs /opt/zapret/init.d/systemd/zapret-list-update.service /lib/systemd/system
 ln -fs /opt/zapret/init.d/systemd/zapret-list-update.timer /lib/systemd/system

Принять изменения в systemd :
 systemctl daemon-reload

Включить автозапуск службы :
 systemctl enable zapret

Включить таймер обновления листа :
 systemctl enable zapret-list-update.timer

Запустить службу :
 systemctl start zapret

Попробовать зайти куда-нибудь : http://ej.ru, http://kinozal.tv, http://grani.ru.
Если не работает, то остановить службу zapret, добавить правило в iptables вручную,
запустить nfqws или tpws в терминале под рутом с нужными параметрами.
Пытаться подключаться к заблоченым сайтам, смотреть вывод программы.
Если нет никакой реакции, значит скорее всего указаны неверные параметры или ip назначения нет в ipset.
Если реакция есть, но блокировка не обходится, значит параметры обхода подобраны неверно, или это средство
не работает в вашем случае на вашем провайдере.
Никто и не говорил, что это будет работать везде.
Попробуйте снять дамп в wireshark или "tcpdump -vvv -X host <ip>", посмотрите действительно ли первый
сегмент TCP уходит коротким и меняется ли регистр "Host:".

Шпаргалка по управлению службой и таймером :

enable auto start : systemctl enable zapret
disable auto start : systemctl disable zapret
start : sytemctl start zapret
stop : systemctl stop zapret
status, output messages : systemctl status zapret
timer info : systemctl list-timer
delete service : systemctl disable zapret ; rm /lib/systemd/system/zapret.service
delete timer : systemctl disable zapret-list-update.timer ; rm /lib/systemd/system/zapret-list-update.*

Centos 7+, Fedora
-----------------

Centos с 7 версии и более-менее новые федоры построены на systemd.
В качестве пакетного менеджера используется yum.

Установить пакеты :
 yum install -y curl ipset dnsutils git

Далее все аналогично debian.

OpenSUSE
--------

Новые OpenSUSE основаны на systemd и менеджере пакетов zypper.

Установить пакеты :
 zypper --non-interactive install curl ipset

Далее все аналогично debian, кроме расположения systemd.
В opensuse он находится не в /lib/systemd, а в /usr/lib/systemd.
Правильные команды будут :

 ln -fs /opt/zapret/init.d/systemd/zapret.service /usr/lib/systemd/system
 ln -fs /opt/zapret/init.d/systemd/zapret-list-update.service /usr/lib/systemd/system
 ln -fs /opt/zapret/init.d/systemd/zapret-list-update.timer /usr/lib/systemd/system

Arch linux
----------

Построен на базе systemd.

Установить пакеты :
 pacman -Syy
 pacman --noconfirm -S ipset curl

Далее все аналогично debian.

Gentoo
------

Эта система использует OpenRC - улучшенную версию sysvinit.
Установка пакетов производится командой : emerge <package_name>
Пакеты собираются из исходников.

Требуются все те же ipset, curl, git для скачивания с github.
git и curl по умолчанию могут присутствовать, ipset отсутствует.

 emerge ipset

Настроить параметры согласно разделу "Выбор параметров".

Запустить автоинсталятор бинариков. Он сам определит рабочую архитектуру и настроит все бинарики.
 /opt/zapret/install_bin.sh
АЛЬТЕРНАТИВА : make -C /opt/zapret. Получите динамические бинарики под вашу ось.

Удалить старые листы, если они были созданы ранее :
 /opt/zapret/ipset/clear_lists.sh
По желанию прописать в /opt/zapret/ipset/zapret-hosts-user.txt свои домены.
Выполнить скрипт обновления листа :
 /opt/zapret/ipset/get_config.sh
Зашедулить обновление листа :
 crontab -e
 Создать строчку  "0 12 */2 * * /opt/zapret/ipset/get_config.sh"

Подключить init скрипт :

 ln -fs /opt/zapret/init.d/sysv/zapret /etc/init.d
 rc-update add zapret

Запустить службу :

 rc-service zapret start

Шпаргалка по управлению службой :

enable auto start : rc-update add zapret
disable auto start : rc-update del zapret
start : rc-service zapret start
stop : rc-service zapret stop

Простая установка
-----------------

Ты простой юзер ? Не хочешь ни во что вникать, а хочешь нажать и чтобы сразу заработало ?
Пользуешься системой на базе systemd ? Тогда этот вариант для тебя.
Есть шансы, что оно заработает с минимумом усилий. Запусти терминал и в нем вбивай команды :

# su
<введи пароль рута>
# apt-get update
# apt-get install git
# cd /opt
# git clone --depth 1 https://github.com/bol-van/zapret
# zapret/install_easy.sh

Надоело ?

# /opt/zapret/uninstall_easy.sh
# rm -r /opt/zapret

Это самый необходимый миниум действий.
Если zapret уже куда-то был скачан, то можно запустить install_easy.sh прямо оттуда.
Инсталятор сам запросит рута, скопирует файлы куда надо.
Можно даже запускать инсталятор из "проводника" через функцию "запустить в терминале", если
"проводник" такое позволяет.

Для более гибкой настройки перед запуском инсталятора следует выполнить раздел "Выбор параметров".

Если система на базе systemd, но используется не поддерживаемый инсталятором менеджер пакетов
или названия пакетов не соответствуют прописанным в инсталятор, пакеты нужно установить вручную.
Требуется : ipset curl

ВАЖНО : Хоть инсталятор и спрашивает является ли система роутером,
настройка маршрутизации , маскарада и т.д. не входит в задачу zapret.
Роутер вдруг сам волшебно не поднимется. Предполагается, что роутер вы уже настроили сами.

В комплекте идут статические бинарики для большинства архитектур. Какой-то из них подойдет
с вероятностью 99%. Но если у вас экзотическая система, инсталятор попробует собрать бинарики сам
через make. Для этого нужны gcc, make и необходимые -dev пакеты. Можно форсировать режим
компиляции следующим вызовом :

 install_easy.sh make


openwrt/LEDE
------------

Установить дополнительные пакеты :
opkg update
opkg install iptables-mod-extra iptables-mod-nfqueue iptables-mod-filter iptables-mod-ipopt iptables-mod-conntrack-extra ipset curl
(ipv6) opkg install ip6tables-mod-nat
(опционально) opkg install gzip
(опционально) opkg install grep

ЭКОНОМИЯ МЕСТА :

gzip от busybox в разы медленней полноценного варианта. gzip используется скриптами получения листов.
grep от busybox катастрофически медленный с опцией -f. она применяется в get_reestr_combined.sh. если вы не собираетесь
пользоваться этим скриптом, gnu grep можно не устанавливать
iptables-mod-nfqueue можно выкинуть, если не будем пользоваться nfqws
curl можно выкинуть, если для получения ip листа будет использоваться только get_user.sh

Самая главная трудность - скомпилировать программы на C. Это можно сделать на linux x64 при помощи SDK, который
можно скачать с официального сайта openwrt или LEDE. Но процесс кросс компиляции - это всегда сложности.
Недостаточно запустить make как на традиционной linux системе.
Поэтому в binaries имеются готовые статические бинарики для всех самых распространенных архитектур.
Статическая сборка означает, что бинарик не зависит от типа libc (glibc, uclibc или musl) и наличия установленных so.
Его можно использовать сразу. Лишь бы подходил тип CPU. У ARM и MIPS есть несколько версий.
Скорее всего найдется рабочий вариант. Если нет - вам придется собирать самостоятельно.
Для всех поддерживаемых архитектур бинарики запакованы upx. На текущий момент все, кроме mips64.

Скопировать директорию "zapret" в /opt на роутер.

Если места достаточно, самый простой способ :
 opkg update
 opkg install git-http
 mkdir /opt
 cd /opt
 git clone --depth 1 https://github.com/bol-van/zapret

Если места немного :
 opkg update
 opkg install openssh-sftp-server unzip
 ifconfig br-lan
Скачать на комп с github zip архив кнопкой "Clone or download"->Download ZIP
Скопировать средствами sftp zip архив на роутер в /tmp.
 mkdir /opt
 cd /opt
 unzip /tmp/zapret-master.zip
 mv zapret-master zapret
 rm /tmp/zapret-master.zip

Если места совсем мало :
 cd /tmp
 nc -l -p 1111 >zapret.tar.gz
На linux системе скачать и распаковать zapret. Оставить необходимый минимум файлов.
Запаковать в архив zapret.tar.gz.
 md5sum zapret.tar.gz
 nc <router_ip> 1111 <zapret.tar.gz
На роутере
 md5sum zapret.tar.gz
Проверить соответствие hash.

Не стоит работать с распакованной версией zapret на windows. Потеряются ссылки и chmod.

Запустить автоинсталятор бинариков. Он сам определит рабочую архитектуру и настроит все бинарики.
 /opt/zapret/install_bin.sh

Создать ссылку на скрипт запуска :
 ln -fs /opt/zapret/init.d/openwrt/zapret /etc/init.d
Создать ссылку на скрипт события поднятия интерфейса :
 ln -fs /opt/zapret/init.d/openwrt/90-zapret /etc/hotplug.d/iface

Настроить параметры согласно разделу "Выбор параметров".

Удалить старые листы, если они были созданы ранее :
 /opt/zapret/ipset/clear_lists.sh
По желанию прописать в /opt/zapret/ipset/zapret-hosts-user.txt свои домены.
Выполнить скрипт обновления листа :
 /opt/zapret/ipset/get_config.sh
Зашедулить обновление листа :
 crontab -e
 Создать строчку  "0 12 */2 * * /opt/zapret/ipset/get_config.sh"

Включить автозапуск и службы и запустить ее :
 /etc/init.d/zapret enable
 /etc/init.d/zapret start
ПРИМЕЧАНИЕ : на этапе старта системы интерфейсы еще не подняты. Для некоторых демонов это
может быть критично, они не запустятся после перезагрузки.
Cкрипт из /etc/hotplug.d/iface запустит недостающие службы при поднятии интерфейса lan.

Создать ссылку на firewall include :
 ln -fs /opt/zapret/init.d/openwrt/firewall.zapret /etc/firewall.zapret
Проверить была ли создана ранее запись о firewall include :
 uci show firewall | grep firewall.zapret
Если firewall.zapret нет, значит добавить :
 uci add firewall include
 uci set firewall.@include[-1].path="/etc/firewall.zapret"
 uci set firewall.@include[-1].reload="1"
 uci commit firewall
Проверить не включен ли flow offload :
 uci show firewall.@defaults[0]
Если flow_offloading=1 или flow_offloading_hw=1 ,
 uci set firewall.@defaults[0].flow_offloading=0
 uci set firewall.@defaults[0].flow_offloading_hw=0
 uci commit firewall
Перезапустить фаервол :
 fw3 restart

Посмотреть через iptables -nL, ip6tables -nL или через luci вкладку "firewall" появились ли нужные правила.

ЭКОНОМИЯ МЕСТА : если его мало, то можно оставить в директории zapret лишь подкаталог ipset, файл config и init.d/openwrt.
Далее нужно создать подкаталоги с реально используемыми бинариками (ip2net, mdig, tpws, nfq)
и скопировать туда из binaries рабочие executables.
Рекомендуется оставить ip2net и mdig. Из tpws и nfq оставить лишь тот, что был выбран в config.

ЕСЛИ ВСЕ ПЛОХО С МЕСТОМ : откажитесь от работы со списком РКН. используйте только get_user.sh

ЕСЛИ СОВСЕМ ВСЕ УЖАСНО С МЕСТОМ : берете tpws и делаете все своими руками. поднятие iptables, автостарт бинарика.
С некоторых версий скрипты запуска zapret без ipset не работают (он требуется для ip exclude)

СОВЕТ : Покупайте только роутеры с USB. В USB можно воткнуть флэшку и вынести на нее корневую файловую систему
или использовать ее в качестве оверлея. Не надо мучать себя, запихивая незапихиваемое в 8 мб встроенной флэшки.
Для комфортной работы с zapret нужен роутер с 16 Mb встроенной памяти или USB разъемом и 128+ Mb RAM.
На 64 Mb без swap будут проблемы с листами РКН. Если у вас только 64 Mb, и вы хотите листы РКН, подключите swap.
32 Mb для современных версий openwrt - конфигурация на грани живучести. Возможны хаотические падения процессов в oom.
Работа с листами РКН невозможна в принципе.

Простая установка на openwrt
----------------------------

Работает только если у вас на роутере достаточно места.

Копируем zapret на роутер в /tmp.

Запускаем установщик :
 /tmp/zapret_install_easy.sh
Он скопирует в /opt/zapret только необходимый минимум файлов :
 config
 install_easy.sh
 uninstall_easy.sh
 install_bin.sh
 init.d/openwrt/*
 ipset/*
 binaries/<ваша архитектура>/{tpws,nfqws,ip2net,mdig}

После успешной установки можно удалить zapret из tmp для освобождения RAM :
 rm -r /tmp/zapret

Для более гибкой настройки перед запуском инсталятора следует выполнить раздел "Выбор параметров".

Android
-------

Без рута забудьте про nfqws и tpws в режиме transparent proxy. tpws будет работать только в режиме --socks.

Статистики наличия NFQUEUE в стоковых ядрах android у меня нет, но на первом попавшемся устройстве на базе MTK он есть.
Если NFQUEUE есть, то nfqws проверен - он работает.

В стоковых ядрах нет поддержки ipset. В общем случае сложность задачи по поднятию ipset варьируется от
"не просто" до "почти невозможно". Если только вы не найдете готовое собранное ядро под ваш девайс.

tpws будет работать в любом случае, он не требует чего-либо особенного.
В android нет /etc/passwd, потому опция --user не будет работать. Вместо нее можно
пользоваться числовыми user id и опцией --uid.
Рекомендую использовать gid 3003 (AID_INET). Иначе можете получить permission denied на создание сокета.
Например : --uid 1:3003
В iptables укажите : "! --uid-owner 1" вместо "! --uid-owner tpws".
Напишите шелл скрипт с iptables и tpws, запускайте его средствами вашего рут менеджера.
Скрипты автозапуска лежат тут :
magisk  : /data/adb/service.d
supersu : /system/su.d

Я не проверял не прибивают ли новые андроиды iptables по своей прихоти в процессе работы
или при подключении/отключении wifi, mobile data, ...

Мобильные модемы и роутеры huawei
---------------------------------

Устройства типа E3372, E8372, E5770 разделяют общую идеологию построения системы.
Имеются 2 вычислительных ядра. Одно ядро выполняет vxworks, другое - linux.
На 4pda имеются модицифированные прошивки с telnet и adb. Их и нужно использовать.

Дальнейшие утверждения проверены на E8372. На других может быть аналогично или похоже.
Присутствуют дополнительные аппаратные блоки для offload-а сетевых функций.
Не весь трафик идет через linux. Исходящий трафик с самого модема проходит
цепочку OUTPUT нормально, на FORWARD =>wan часть пакетов выпадает из tcpdump.

tpws работает обычным образом.

nfqueue поломан. можно собрать фиксящий модуль https://github.com/im-0/unfuck-nfqueue-on-e3372h,
используя исходники с huawei open source. Исходники содержат тулчейн и полусобирающееся,
неактуальное ядро. Конфиг можно взять с рабочего модема из /proc/config.gz.
С помощью этих исходников умельцы могут собрать модуль unfuck_nfqueue.ko.
После его применения NFQUEUE и nfqws для armhf работают нормально. 

Чтобы избежать проблемы с offload-ом при использвании nfqws, следует комбинировать tpws в режиме tcp proxy и nfqws.
Правила NFQUEUE пишутся для цепочки OUTPUT.
connbytes придется опускать, поскольку модуля в ядре нет. Но это не смертельно.

Скрипт автозапуска - /system/etc/autorun.sh. Создайте свой скрипт настройки zapret,
запускайте из конца autorun.sh через "&". Скрипт должен в начале делать sleep 5, чтобы дождаться
поднятия сети и iptables от huawei.

ПРЕДУПРЕЖДЕНИЕ.
На этом модеме происходят хаотические сбросы соединений tcp по непонятным причинам.
Выглядит это так, если запускать curl с самого модема :
 curl www.ru                                                                                                                                                                                    
 curl: (7) Failed to connect to www.ru port 80: Host is unreachable
Возникает ошибка сокета EHOSTUNREACH (errno -113). То же самое видно в tpws.
В броузере не подгружаются части веб страниц, картинки, стили.
В tcpdump на внешнем интерфейсе eth_x виден только единственный и безответный SYN пакет, без сообщений ICMP.
ОС каким-то образом узнает о невозможности установить TCP соединение и выдает ошибку.
Если выполнять подключение с клиента, то SYN пропадают, соединение не устанавливается.
ОС клиента проводит ретрансмиссию, и с какого-то раза подключение удается.
Поэтому без tcp проксирования в этой ситуации сайты тупят, но загружаются, а с проксированием
подключение выполняется, но вскоре сбрасывается без каких-либо данных, и броузеры не пытаются установить
его заново. Поэтому качество броузинга с tpws может быть хуже, но дело не в tpws.
Частота сбросов заметно возрастает, если запущен торент клиент, имеется много tcp соединений.
Однако, причина не в переполнении таблицы conntrack. Увеличение лимитов и очистка conntrack не помогают.
Предположительно эта особенность связана с обработкой пакетов сброса соединения в hardware offload.
Точного ответа на вопрос у меня нет. Если вы знаете - поделитесь, пожалуйста.
Чтобы не ухудшать качество броузинга, можно фильтровать заворот на tpws по ip фильтру.
Поддержка ipset отсутствует. Значит, все, что можно сделать - создать индивидуальные правила
на небольшое количество хостов.

Другие прошивки
---------------

Для статических бинариков не имеет значения на чем они запущены : PC, android, приставка, роутер, любой другой девайс.
Подойдет любая прошивка, дистрибутив linux. Статические бинарики запустятся на всем.
Им нужно только ядро с необходимыми опциями сборки или модулями.
Но кроме бинариков в проекте используются еще и скрипты, в которых задействуются некоторые
стандартные программы.

ЗАМЕЧАНИЕ. Как показала практика, на некоторых ядрах бинарики с upx падают в segfault.
Если это ваш случай, скачайте upx и распакуйте бинарики. Распаковать можно на любой системе и любой архитектуре.

Основные причины почему нельзя просто так взять и установить эту систему на что угодно :
 * отсутствие доступа к девайсу через shell
 * отсутствие рута
 * отсутствие раздела r/w для записи и энергонезависимого хранения файлов
 * отсутствие возможности поставить что-то в автозапуск
 * отсутствие cron
 * недостаток модулей ядра или опций его сборки
 * недостаток модулей iptables (/usr/lib/iptables/lib*.so)
 * недостаток стандартных программ (типа ipset, curl) или их кастрированность (облегченная замена)
 * кастрированный или нестандартный шелл sh

Если в вашей прошивке есть все необходимое, то вы можете адаптировать zapret под ваш девайс в той или иной степени.
Может быть у вас не получится поднять все части системы, однако вы можете хотя бы попытаться
поднять tpws и завернуть на него через -j REDIRECT весь трафик на порт 80.
Если вам есть куда записать tpws, есть возможность выполнять команды при старте, то как минимум
это вы сделать сможете. Скорее всего поддержка REDIRECT в ядре есть. Она точно есть на любом роутере,
на других устройствах под вопросом. NFQUEUE, ipset на большинстве прошивок отсутствуют из-за ненужности.

Пересобрать ядро или модули для него будет скорее всего достаточно трудно.
Для этого вам необходимо будет по крайней мере получить исходники вашей прошивки.
User mode компоненты могут быть привнесены относительно безболезненно, если есть место куда их записать.
Специально для девайсов, имеющих область r/w, существует проект entware.
Некоторые прошивки даже имеют возможность его облегченной установки через веб интерфейс.
entware содержит репозиторий user-mode компонент, которые устанавливаются в /opt.
С их помощью можно компенсировать недостаток ПО основной прошивки, за исключением ядра.

Подробное описание настроек для других прошивок выходит за рамки данного проекта.

Openwrt является одной из немногих относительно полноценных linux систем для embedded devices.
Она характеризуется следующими вещами, которые и послужили основой выбора именно этой прошивки :
 * полный root доступ к девайсу через shell. на заводских прошивках чаще всего отсутствует, на многих альтернативных есть
 * корень r/w. это практически уникальная особенность openwrt. заводские и большинство альтернативных прошивок
   построены на базе squashfs root (r/o), а конфигурация хранится в специально отформатированной области
   встроенной памяти, называемой nvram.  не имеющие r/w корня системы сильно кастрированы. они не имеют
   возможности доустановки ПО из репозитория без специальных вывертов и заточены в основном
   на чуть более продвинутого, чем обычно, пользователя и управление имеющимся функционалом через веб интерфейс,
   но функционал фиксированно ограничен. альтернативные прошивки как правило могут монтировать r/w раздел
   в какую-то область файловой системы, заводские обычно могут монтировать лишь флэшки, подключенные к USB,
   и не факт, что есть поддержка unix файловых системы. может быть поддержка только fat и ntfs.
 * возможность выноса корневой файловой системы на внешний носитель (extroot) или создания на нем оверлея (overlay)
 * наличие менеджера пакетов opkg и репозитория софта
 * в репозитории есть все модули ядра, их можно доустановить через opkg. ядро пересобирать не нужно.
 * в репозитории есть все модули iptables, их можно доустановить через opkg
 * в репозитории есть огромное количество стандартных программ и дополнительного софта
 * наличие SDK, позволяющего собрать недостающее

Обход блокировки https
----------------------

ИНОГДА (но нечасто) работает трюк со сплитом tls handshake на 2 части.
Это можно сделать все теми же средствами. nfqws --dpi-desync=split2 или tpws --split-pos.
У tpws --split-pos - единственный параметр, который работает на не-HTTP трафике, все остальное работать не будет.

ЧАЩЕ на https работает атака DPI desync, но у нее есть свои нюансы настройки.

Если ничего не работает, приходится перенаправлять трафик через сторонний хост.
Предлагается использовать прозрачный редирект через socks5 посредством iptables+redsocks, либо iptables+iproute+vpn.
Настройка варианта с redsocks на openwrt описана в https.txt.
Настройка варианта с iproute+wireguard - в wireguard_iproute_openwrt.txt.

Почему стоит вложиться в покупку VPS
------------------------------------

VPS - это виртуальный сервер. Существует огромное множество датацентров, предлагающих данную услугу.
На VPS могут выполняться какие угодно задачи. От простого веб сайта до навороченной системы собственной разработки.
Можно использовать VPS и для поднятия собственного vpn или прокси.
Сама широта возможных способов применения , распространенность услуги сводят к минимуму возможности
регуляторов по бану сервисов такого типа. Да, если введут белые списки, то решение загнется, но это будет уже другая
реальность, в которой придется изобретать иные решения.
Пока этого не сделали, никто не будет банить хостинги просто потому , что они предоставляют хостинг услуги.
Вы как индивидуум скорее всего никому не нужны. Подумайте чем вы отличаетесь от известного VPN провайдера.
VPN провайдер предоставляет _простую_ и _доступную_ услугу по обходу блокировок для масс.
Этот факт делает его первоочередной целью блокировки. РКН направит уведомление, после отказа сотрудничать
заблокирует VPN. Предоплаченная сумма пропадет.
У регуляторов нет и никогда не будет ресурсов для тотальной проверки каждого сервера в сети.
Возможен китайский расклад, при котором DPI выявляет vpn протоколы и динамически банит IP серверов,
предоставляющих нелицензированный VPN. Но имея знания, голову, вы всегда можете обфусцировать
vpn трафик или применить другие типы VPN, более устойчивые к анализу на DPI или просто менее широкоизвестные,
а следовательно с меньшей вероятностью обнаруживамые регулятором.
У вас есть свобода делать на вашем VPS все что вы захотите, адаптируясь к новым условиям.
Да, это потребует знаний. Вам выбирать учиться и держать ситуацию под контролем, когда вам ничего запретить
не могут, или покориться системе.

VPS можно прибрести в множестве мест. Существуют специализированные на поиске предложений VPS порталы.
Например, вот этот : https://vps.today/
Для персонального VPN сервера обычно достаточно самой минимальной конфигурации, но с безлимитным трафиком или
с большим лимитом по трафику (терабайты). Важен и тип VPS. Openvz подойдет для openvpn, но
вы не поднимете на нем wireguard, ipsec, то есть все, что требует kernel mode.
Для kernel mode требуется тип виртуализации, предполагающий запуск полноценного экземпляра ОС linux
вместе с ядром. Подойдут kvm, xen, hyper-v, vmware. 

По цене можно найти предложения, которые будут дешевле готовой VPN услуги, но при этом вы сам хозяин в своей лавке
и не рискуете попасть под бан регулятора, разве что "заодно" под ковровую бомбардировку с баном миллионов IP.
Кроме того, если вам совсем все кажется сложным, прочитанное вызывает ступор, и вы точно знаете, что ничего
из описанного сделать не сможете, то вы сможете хотя бы использовать динамическое перенаправление портов ssh
для получения шифрованного socks proxy и прописать его в броузер. Знания linux не нужны совсем.
Это вариант наименее напряжный для чайников, хотя и не самый удобный в использовании.
