zapret v.46

English
-------

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

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

Автономное, без задействования сторонних серверов, средство противодействия DPI.
Может помочь обойти блокировки или замедление сайтов http(s), сигнатурный анализ tcp и udp протоколов,
например с целью блокировки VPN.

Проект нацелен прежде всего на маломощные embedded устройства - роутеры, работающие под openwrt.
Поддерживаются традиционные Linux системы, FreeBSD, OpenBSD, частично MacOS.
В некоторых случаях возможна самостоятельная прикрутка решения к различным прошивкам.


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

В самом простейшем случае вы имеете дело с пассивным 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 на пакетном уровне.

Подробнее про DPI :
 https://habr.com/ru/post/335436
 https://geneva.cs.umd.edu/papers/geneva_ccs19.pdf

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

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

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

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


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

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

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

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

Можно использовать "-j REDIRECT --to-port 988" вместо DNAT , однако в этом случае процесс transparent proxy
должен слушать на ip адресе входящего интерфейса или на всех адресах. Слушать на всех - не есть хорошо
с точки зрения безопасности. Слушать на одном (локальном) можно, но в случае автоматизированного
скрипта придется его узнавать, потом динамически вписывать в команду. В любом случае требуются дополнительные усилия.
Использование route_localnet тоже имеет потенциальные проблемы с безопасностью. Вы делаете доступным все, что висит
на 127.0.0.0/8 для локальной подсети <внутренний_интерфейс>. Службы обычно привязываются к 127.0.0.1, поэтому можно
средствами iptables запретить входящие на 127.0.0.1 не с интерфейса lo, либо повесить tpws на любой другой IP из
из 127.0.0.0/8, например на 127.0.0.127, и разрешить входящие не с lo только на этот IP.

iptables -A INPUT ! -i lo -d 127.0.0.127 -j ACCEPT
iptables -A INPUT ! -i lo -d 127.0.0.0/8 -j DROP

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

tpws может использоваться в режиме socks proxy. В этом случае iptables не нужны, а нужно прописать socks
в настройки программы (например, броузера), с которой будем обходить блокировки.
transparent proxy отличается от socks именно тем, что в варианте transparent настраивать клиентские программы не нужно.


Для перенаправления на очередь 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 1:4 -m mark ! --mark 0x40000000/0x40000000 -m set --match-set zapret dst -j NFQUEUE --queue-num 200 --queue-bypass

Фильтр по mark нужен для отсечения от очереди пакетов, сгенерированных внутри nfqws.
Если применяется фильтр по connbytes 1:4, то обязательно добавлять в iptables и фильтр по mark. Иначе возможно
перепутывание порядка следования пакетов, что приведет к неработоспособности метода.


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

В новых ядрах (и в более старых, 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.
Поэтому скрипты zapret поддерживают свою систему выборочного управления offload в openwrt.


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

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

 ip6tables -t nat -I OUTPUT -o <внешний_интерфейс> -p tcp --dport 80 -m owner ! --uid-owner tpws -j DNAT --to [::1]:988

Параметра route_localnet не существует для ipv6.
DNAT на localhost (::1) возможен только в цепочке OUTPUT.
В цепочке PREROUTING DNAT возможен на любой global address или на link local address того же интерфейса,
откуда пришел пакет.
NFQUEUE работает без изменений.


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

Более подробно преимущества и недостатки nftables применительно к данной системе описаны в docs/nftables_notes.txt
Если коротко, то в nftables невозможно работать с большими ip листами на системах с малым количеством RAM.
Остальные рассматриваемые здесь функции могут быть перенесены на nftables.


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

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


nfqws
-----

Эта программа - модификатор пакетов и обработчик очереди NFQUEUE.
Для BSD систем существует адаптированный вариант - dvtws, собираемый из тех же исходников (см. bsd.txt).

 --debug=0|1				; 1=выводить отладочные сообщения
 --daemon				; демонизировать прогу
 --pidfile=<file>			; сохранить PID в файл
 --user=<username>			; менять uid процесса
 --uid=uid[:gid]			; менять uid процесса
 --qnum=N				; номер очереди N
 --wsize=<winsize>[:<scale_factor>]	; менять tcp window size на указанный размер в SYN,ACK. если не задан scale_factor, то он не меняется (устарело !)
 --wssize=<winsize>[:<scale_factor>]	; менять tcp window size на указанный размер в исходящих пакетах. scale_factor по умолчанию 0. (см. conntrack !)
 --wssize-cutoff=[n|d|s]N               ; изменять server window size в исходящих пакетах (n), пакетах данных (d), относительных sequence (s) по номеру меньше N
 --ctrack-timeouts=S:E:F[:U]            ; таймауты внутреннего conntrack в состояниях SYN, ESTABLISHED, FIN, таймаут udp. по умолчанию 60:300:60:60
 --hostcase				; менять регистр заголовка "Host:" по умолчанию на "host:".
 --hostnospace				; убрать пробел после "Host:" и переместить его в конец значения "User-Agent:" для сохранения длины пакета
 --hostspell=HoST			; точное написание заголовка Host (можно "HOST" или "HoSt"). автоматом включает --hostcase
 --domcase				; домен после Host: сделать таким : TeSt.cOm
 --dpi-desync=[<mode0>,]<mode>[,<mode2]	; атака по десинхронизации DPI. mode : synack fake rst rstack hopbyhop destopt ipfrag1 disorder disorder2 split split2 ipfrag2
 --dpi-desync-fwmark=<int|0xHEX>        ; бит fwmark для пометки десинхронизирующих пакетов, чтобы они повторно не падали в очередь. default = 0x40000000
 --dpi-desync-ttl=<int>                 ; установить ttl для десинхронизирующих пакетов
 --dpi-desync-ttl6=<int>                ; установить ipv6 hop limit для десинхронизирующих пакетов. если не указано, используется значение ttl
 --dpi-desync-fooling=<fooling>		; дополнительные методики как сделать, чтобы фейковый пакет не дошел до сервера. none md5sig badseq badsum hopbyhop hopbyhop2
 --dpi-desync-retrans=0|1               ; (только для fake,rst,rstack) 0(default)=отправлять оригинал следом за фейком  1=дропать оригинал, заставляя ОС выполнять ретрансмиссию через 0.2 сек
 --dpi-desync-repeats=<N>               ; посылать каждый генерируемый в nfqws пакет N раз (не влияет на остальные пакеты)
 --dpi-desync-skip-nosni=0|1		; 1(default)=не применять dpi desync для запросов без hostname в SNI, в частности для ESNI
 --dpi-desync-split-pos=<1..1500>	; (только для split*, disorder*) разбивать пакет на указанной позиции
 --dpi-desync-badseq-increment=<int|0xHEX> ; инкремент sequence number для badseq. по умолчанию -10000
 --dpi-desync-badack-increment=<int|0xHEX> ; инкремент ack sequence number для badseq. по умолчанию -66000
 --dpi-desync-any-protocol=0|1		; 0(default)=работать только по http request и tls clienthello  1=по всем непустым пакетам данных
 --dpi-desync-fake-http=<filename>	; файл, содержащий фейковый http запрос для dpi-desync=fake, на замену стандартному w3.org
 --dpi-desync-fake-tls=<filename>	; файл, содержащий фейковый tls clienthello для dpi-desync=fake, на замену стандартному w3.org
 --dpi-desync-fake-unknown=<filename>	; файл, содержащий фейковый пейлоад неизвестного протокола для dpi-desync=fake, на замену стандартным нулям 256 байт
 --dpi-desync-fake-unknown-udp=<filename> ; файл, содержащий фейковый пейлоад неизвестного udp протокола для dpi-desync=fake, на замену стандартным нулям 64 байт
 --dpi-desync-cutoff=[n|d|s]N           ; применять dpi desync только в исходящих пакетах (n), пакетах данных (d), относительных sequence (s) по номеру меньше N
 --hostlist=<filename>			; применять дурение только к хостам из листа

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

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

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

* md5sig работает не на всех серверах. Пакеты с md5 обычно отбрасывают только linux.
* badsum не сработает, если ваше устройство за NAT, который не пропускает пакеты с инвалидной суммой.
  Наиболее распространенная настройка NAT роутера в Linux их не пропускает. На Linux построено большинство
  домашних роутеров. Непропускание обеспечивается так : настройка ядра sysctl по умолчанию
  net.netfilter.nf_conntrack_checksum=1 заставляет conntrack проверять tcp и udp чексуммы входящих пакетов
  и выставлять state INVALID для пакетов с инвалидной суммой.
  Обычно в правилах iptables вставляется правило для дропа пакетов с состоянием INVALID в цепочке FORWARD.
  Совместное сочетание этих факторов приводит к непрохождению badsum через такой роутер.
  В openwrt из коробки net.netfilter.nf_conntrack_checksum=0, в других роутерах часто нет,
  и не всегда это можно изменить. Чтобы nfqws мог работать через роутер, нужно на нем выставить указанное
  значение sysctl в 0. nfqws на самом роутере будет работать и без этой настройки, потому что
  чексумма локально созданных пакетов не проверяется никогда.
  Если роутер за другим NAT, например провайдерским, и он не пропускает invalid packets
  вы ничего не сможете с этим сделать. Но обычно провайдеры все же пропускают badsum.
  На некоторых адаптерах/свитчах/драйверах принудительно включен rx-checksum offload, badsum пакеты отсекаются
  еще до получения в ОС. В этом случае если что-то и можно сделать, то только модифицировать драйвер,
  что представляется задачей крайне нетривиальной. Установлено, что так себя ведут некоторые роутеры на базе mediatek.
  badsum пакеты уходят с клиентской ОС, но роутером не видятся в br-lan через tcpdump.
  При этом если nfqws выполняется на самом роутере, обход может работать. badsum нормально уходят с внешнего интерфейса.
* Пакеты с badseq будут наверняка отброшены принимающим узлом, но так же и DPI, если он ориентируется
  на sequence numbers. По умолчанию смещение seq выбирается -10000. Практика показала, что некоторые DPI
  не пропускают seq вне определенного окна. Однако, такое небольшое смещение может вызвать проблемы
  при существенной потоковой передаче и потере пакетов. Если вы используете --dpi-desync-any-protocol,
  может понадобится установить badseq increment 0x80000000. Это обеспечит надежную гарантию,
  что поддельный пакет не вклинится в tcp window на сервере. Так же было замечено, что badseq ломает логику
  некоторых DPI при анализе http, вызывая зависание соединения. Причем на тех же DPI TLS с badseq работает нормально.
* TTL казалось бы - лучший вариант, но он требует индивидуальной настройки под каждого провайдера.
  Если DPI находится дальше локальных сайтов провайдера, то вы можете отрезать себе доступ к ним.
  Необходим ip exclude list, заполняемый вручную. Вместе с ttl можно применять md5sig. Это ничего не испортит,
  зато дает неплохой шанс работы сайтов, до которых "плохой" пакет дойдет по TTL.
  Если не удается найти автоматическое решение, воспользуйтесь файлом zapret-hosts-user-exclude.txt.
  Некоторые стоковые прошивки роутеров фиксируют исходящий TTL, без отключения этой опции через них работать не будет.
  КАКИМ СТОИТ ВЫБИРАТЬ TTL : найдите минимальное значение, при котором обход еще работает.
  Это и будет номер хопа вашего DPI.
* hopbyhop относится только к ipv6. Добавляется ipv6 extenstion header "hop-by-hop options".
  В варианте hopbyhop2 добавляются 2 хедера, что является нарушением стандарта и гарантированно отбрасывается
  стеком протоколов во всех ОС. Один хедер hop-by-hop принимается всеми ОС, однако на некоторых каналах/провайдерах
  такие пакеты могут фильтроваться и не доходить. Расчет идет на то, что DPI проанализирует пакет с hop-by-hop,
  но он либо не дойдет до адресата всилу фильтров провайдера, либо будет отброшен сервером, потому что хедера два.

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

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

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

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

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

Режимы десинхронизации hopbyhop, destopt и ipfrag1 (не путать с fooling !) относятся только к ipv6 и заключается
в добавлении хедера "hop-by-hop options" , "destination options" или "fragment" во все пакеты, попадающие под десинхронизацию.
Здесь надо обязательно понимать, что добавление хедера увеличивает размер пакета, потому не может быть применено
к пакетам максимального размера. Это имеет место при передаче больших сообщений.
В случае невозможности отослать пакет дурение будет отменено, пакет будет выслан в оригинале.
Расчет идет на то, что DPI увидит 0 в поле next header основного заголовка ipv6 и не будет скакать по
extension хедерам в поисках транспортного хедера. Таким образом не поймет, что это tcp или udp, и пропустит пакет
без анализа. Возможно, какие-то DPI на это купятся.
Может сочетаться с любыми режимами 2-й фазы, кроме варианта "ipfrag1+ipfrag2".
Например, "hopbyhop,split2" означает разбить tcp пакет на 2 сегмента, в каждый из них добавить hop-by-hop.
При "hopbyhop,ipfrag2" последовательность хедеров будет : ipv6,hop-by-hop,fragment,tcp/udp.
Режим "ipfrag1" может срабатывать не всегда без специальной подготовки. См. раздел "IP фрагментация".

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

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

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

iptables -t mangle -I POSTROUTING -o <внешний_интерфейс> -p tcp -m multiport --dports 80,443 -m connbytes --connbytes-dir=original --connbytes-mode=packets --connbytes 1:4 -m mark ! --mark 0x40000000/0x40000000 -j NFQUEUE --queue-num 200 --queue-bypass

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

iptables -t mangle -I POSTROUTING -o <внешний_интерфейс> -p tcp --dport 443 -m connbytes --connbytes-dir=original --connbytes-mode=packets --connbytes 1:4 -m mark ! --mark 0x40000000/0x40000000 -j NFQUEUE --queue-num 200 --queue-bypass
iptables -t mangle -I POSTROUTING -o <внешний_интерфейс> -p tcp --dport 80 -m mark ! --mark 0x40000000/0x40000000 -j NFQUEUE --queue-num 200 --queue-bypass

mark нужен, чтобы сгенерированный поддельный пакет не попал опять к нам на обработку. nfqws выставляет fwmark при его отсылке.
хотя nfqws способен самостоятельно различать помеченные пакеты, фильтр в iptables по mark нужен при использовании connbytes,
чтобы не допустить изменения порядка следования пакетов. Процессинг очереди - процесс отложенный.
Если ядро имеет пакеты на отсылку вне очереди - оно их отправляет незамедлительно.
Изменение правильного порядка следования пакетов при десинхронизации ломает всю идею.
При отсутствии ограничения на connbytes, атака будет работать и без фильтра по mark.
Но лучше его все же оставить для увеличения скорости.

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

КОМБИНИРОВАНИЕ МЕТОДОВ ДЕСИНХРОНИЗАЦИИ
В параметре dpi-desync можно указать до 3 режимов через запятую.
0 фаза предполагает работу на этапе установления соединения. Может быть synack.
На 0 фазу не действует фильтр по hostlist.
Последующие режимы отрабатывают на пакетах с данными.
Режим 1-й фазы может быть fake,rst,rstack. Режим 2-й фазы может быть disorder,disorder2,split,split2,ipfrag2.
Может быть полезно, когда у провайдера стоит не один DPI.

РЕЖИМ SYNACK
В документации по geneva это называется "TCB turnaround". Попытка ввести DPI в заблуждение относительно
ролей клиента и сервера.
!!! Поскольку режим нарушает работу NAT, техника может сработать только если между атакующим устройством
и DPI нет NAT. Атака не сработает через NAT роутер, но может сработать с него.
Для реализации атаки в linux обязательно требуется отключить стандартное правило firewall,
дропающее инвалидные пакеты в цепочке OUTPUT. Например : -A OUTPUT -m state --state INVALID -j DROP
В openwrt можно отключить drop INVALID в OUTPUT и FORWARD через опцию в /etc/config/firewall :

config zone
	option name 'wan'
	.........
	option masq_allow_invalid '1'

К сожалению, отключить только в OUTPUT таким образом нельзя. Но можно сделать иначе. Вписать в /etc/firewall.user :

iptables -D zone_wan_output -m comment --comment '!fw3' -j zone_wan_dest_ACCEPT
ip6tables -D zone_wan_output -m comment --comment '!fw3' -j zone_wan_dest_ACCEPT

Лучше делать так, потому что отсутствие дропа INVALID в FORWARD может привести к нежелательным утечкам пакетов из LAN.
Если не принять эти меры, отсылка SYN,ACK сегмента вызовет ошибку и операция будет прервана.
Остальные режимы тоже не сработают. Если поймете, что вам synack не нужен, обязательно верните правило дропа INVALID.

ВИРТУАЛЬНЫЕ МАШИНЫ
Изнутри VM от virtualbox и vmware в режиме NAT не работают многие техники пакетной магии nfqws.
Принудительно заменяется ttl, не проходят фейк пакеты. Необходимо настроить сеть в режиме bridge.

CONNTRACK
nfqws оснащен ограниченной реализацией слежения за состоянием tcp соединений (conntrack).
Он включается для реализации некоторых методов противодействия DPI.
На текущий момент это параметры --wssize и --dpi-desync-cutoff.
conntrack способен следить за фазой соединения : SYN,ESTABLISHED,FIN , количеством пакетов в каждую сторону,
sequence numbers. conntrack способен "кормиться" пакетами в обе или только в одну сторону.
Соединение попадает в таблицу при обнаружении пакетов с выставленными флагами SYN или SYN,ACK.
Поэтому если необходим conntrack, в правилах перенаправления iptables соединение должно идти на nfqws с самого первого
пакета, хотя затем может обрываться по фильтру connbytes.
Для UDP инициатором попадания в таблицу является первый UDP пакет. Он же и определяет направление потока.
Считается, что первый UDP пакет исходит от клиента к серверу. Далее все пакеты с совпадающими
src_ip,src_port,dst_ip,dst_port считаются принадлежащими этому потоку до истечения времени неактивности.
conntrack - простенький, он не писался с учетом всевозможных атак на соединение, он не проверяет
пакеты на валидность sequence numbers или чексумму. Его задача - лишь обслуживание нужд nfqws, он обычно
кормится только исходящим трафиком, потому нечувствителен к подменам со стороны внешней сети.
Соединение удаляется из таблицы, как только отпадает нужда в слежении за ним или по таймауту неактивности.
Существуют отдельные таймауты на каждую фазу соединения. Они могут быть изменены параметром --ctrack-timeouts.

--wssize позволяет изменить с клиента размер tcp window для сервера, чтобы он послал следующие ответы разбитыми на части.
Чтобы это подействовало на все серверные ОС, необходимо менять window size в каждом исходящем с клиента пакете до отсылки сообщения,
ответ на который должен быть разбит (например, TLS ClientHello). Именно поэтому и необходим conntrack, чтобы
знать когда надо остановиться. Если не остановиться и все время устанавливать низкий wssize, скорость упадет катастрофически.
В linux это может быть купировано через connbytes, но в BSD системах такой возможности нет.
В случае http(s) останавливаемся сразу после отсылки первого http запроса или TLS ClientHello.
Если вы имеете дело с не http(s), то вам потребуется параметр --wssize-cutoff. Он устанавливает предел, с которого действие
wssize прекращается. Префикс d перед номером означает учитывать только пакеты с data payload, префикс s - relative sequence number,
проще говоря количество переданных клиентом байтов + 1.
Если проскочит пакет с http request или TLS ClientHello, действие wssize прекращается сразу же, не дожидаясь wssize-cutoff.
Если ваш протокол склонен к долгому бездействию, следует увеличить таймаут фазы ESTABLISHED через параметр --ctrack-timeouts.
Таймаут по умолчанию низкий - всего 5 минут.
Не забывайте, что nfqws кормится приходящими на него пакетами. Если вы ограничили поступление пакетов через connbytes,
то в таблице могут остаться повисшие соединения в фазе ESTABLISHED, которые отвалятся только по таймауту.
Для диагностики состояния conntrack пошлите сигнал SIGUSR1 процессу nfqws : killall -SIGUSR1 nfqws.
Текущая таблица будет выведена nfqws в stdout.

Обычно в SYN пакете клиент отсылает кроме window size еще и TCP extension "scaling factor".
scaling factor представляет из себя степень двойки, на которую умножается window size : 0=>1, 1=>2, 2=>4, ..., 8=>256, ...
В параметре wssize scaling factor указывается через двоеточие.
Scaling factor может только снижаться, увеличение заблокировано, чтобы не допустить превышение размера окна со стороны сервера.
Для принуждения сервера к фрагментации ServerHello, чтобы избежать просекание имени сервера из сертификата сервера на DPI,
лучше всего использовать --wssize=1:6 . Основное правило - делать scale_factor как можно больше, чтобы после восстановления
window size итоговый размер окна стал максимально возможным. Если вы сделаете 64:0, будет очень медленно.
С другой стороны нельзя допустить, чтобы ответ сервера стал достаточно большим, чтобы DPI нашел там искомое.

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

--dpi-desync-cutoff позволяет задать предел, при достижении которого прекращается применение dpi-desync.
Доступны префиксы n,d,s по аналогии с --wssize-cutoff.
Полезно совместно с --dpi-desync-any-protocol=1.
На склонных к бездействию соединениях следует изменить таймауты conntrack.
Если соединение выпало из conntrack и задана опция --dpi-desync-cutoff, dpi desync применяться не будет.

ПОДДЕРЖКА UDP
Атаки на udp более ограничены в возможностях. udp нельзя фрагментировать иначе, чем на уровне ip.
Для UDP действуют только режимы десинхронизации fake,hopbyhop,destopt,ipfrag1,ipfrag2.
Возможно сочетание fake,hopbyhop,destopt с ipfrag2.
Обязательно указание --dpi-desync-any-protocol, иначе десинхронизация работать не будет,
поскольку протокол неизвестен, а никакие протоколы пока не определяются.
Реализован conntrack для udp. Можно пользоваться --dpi-desync-cutoff. Таймаут conntrack для udp
можно изменить 4-м параметром в --ctrack-timeouts.
Атака fake полезна только для stateful DPI, она бесполезна для анализа на уровне отдельных пакетов.
По умолчанию fake наполнение - 64 нуля. Можно указать файл в --dpi-desync-fake-unknown-udp.

IP ФРАГМЕНТАЦИЯ
В современной сети с этом все очень плохо. Фрагментированные пакеты застревают по пути, часто отбрасываются.
Иногда доходят. Иногда то доходят, то не доходят. Может зависеть от версии ipv4/ipv6.
Роутеры на базе linux могут самопроизвольно собирать или перефрагментировать пакеты.
Позиция фрагментации задается отдельно для tcp и udp. По умолчанию 24 и 8 соответственно, должна быть кратна 8.
Смещение считается с транспортного заголовка.

Существует ряд моментов вокруг работы с фрагментами на Linux, без понимания которых может ничего не получиться.

ipv4 : Linux дает отсылать ipv4 фрагменты, но стандартные настройки iptables в цепочке OUTPUT могут вызывать ошибки отправки.

ipv6 : Нет способа для приложения гарантированно отослать фрагменты без дефрагментации в conntrack.
На разных системах получается по-разному. Где-то нормально уходят, где-то пакеты дефрагментируются.
Для ядер <4.16 похоже, что нет иного способа решить эту проблему, кроме как выгрузить модуль nf_conntrack,
который подтягивает зависимость nf_defrag_ipv6. Он то как раз и выполняет дефрагментацию.
Для ядер 4.16+ ситуация чуть лучше. Из дефрагментации исключаются пакеты в состоянии NOTRACK.
Чтобы не загромождать описание, смотрите пример решения этой проблемы в blockcheck.sh.

Иногда требуется подгружать модуль ip6table_raw с параметром raw_before_defrag=1.
В openwrt параметры модулей указываются через пробел после их названий в файлах /etc/modules.d.
В традиционных системах посмотрите используется ли iptables-legacy или iptables-nft. Если legacy, то нужно создать файл
/etc/modprobe.d/ip6table_raw.conf с содержимым :
options ip6table_raw raw_before_defrag=1
В некоторых традиционных дистрибутивах можно изменить текущий ip6tables через : update-alternatives --config ip6tables
Если вы хотите оставаться на iptables-nft, вам придется пересобрать патченную версию. Патч совсем небольшой.
В nft.c найдите фрагмент :
			{
				.name	= "PREROUTING",
				.type	= "filter",
				.prio	= -300,	/* NF_IP_PRI_RAW */
				.hook	= NF_INET_PRE_ROUTING,
			},
			{
				.name	= "OUTPUT",
				.type	= "filter",
				.prio	= -300,	/* NF_IP_PRI_RAW */
				.hook	= NF_INET_LOCAL_OUT,
			},
и замените везде -300 на -450.

Это нужно сделать вручную, никакой автоматики в blockcheck.sh нет.

Либо можно раз и навсегда избавиться от этой проблемы, используя nftables. Там можно создать netfilter hook
с любым приоритетом. Используйте приоритет -401 и ниже.

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 адрес
 			; если указан ipv6 link local, то требуется указать с какого он интерфейса : fe80::1%br-lan
 --bind-linklocal=no|unwanted|prefer|force
			; no : биндаться только на global ipv6
 			; unwanted (default) : предпочтительно global, если нет - LL
			; prefer : предпочительно LL, если нет - global
			; force : биндаться только на LL
 --bind-iface4=<iface>	; слушать на первом ipv4 интерфейса iface
 --bind-iface6=<iface>	; слушать на первом ipv6 интерфейса iface
 --bind-wait-ifup=<sec>	; ждать до N секунд появления и поднятия интерфейса
 --bind-wait-ip=<sec>	; ждать до N секунд получения IP адреса (если задан --bind-wait-ifup - время идет после поднятия интерфейса)
 --bind-wait-ip-linklocal=<sec>
			; имеет смысл только при задании --bind-wait-ip
			; --bind-linklocal=unwanted : согласиться на LL после N секунд
			; --bind-linklocal=prefer : согласиться на global address после N секунд
 --bind-wait-only	; подождать все бинды и выйти. результат 0 в случае успеха, иначе не 0.
 --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>	; делить все посылы на сегменты в указанной позиции. единственная опция, работающая на не-http. при указании split-http-req он имеет преимущество на http.
 --split-any-protocol	; применять split-pos к любым пакетам. по умолчанию - только к http и TLS ClientHello
 --hostcase             ; менять регистр заголовка "Host:". по умолчанию на "host:".
 --hostspell=HoST	; точное написание заголовка Host (можно "HOST" или "HoSt"). автоматом включает --hostcase
 --hostdot		; добавление точки после имени хоста : "Host: kinozal.tv."
 --hosttab		; добавление табуляции после имени хоста : "Host: kinozal.tv\t"
 --hostnospace		; убрать пробел после "Host:"
 --hostpad=<bytes>	; добавить паддинг-хедеров общей длиной <bytes> перед Host:
 --domcase		; домен после Host: сделать таким : TeSt.cOm
 --methodspace		; добавить пробел после метода : "GET /" => "GET  /"
 --methodeol		; добавить перевод строки перед методом  : "GET /" => "\r\nGET  /"
 --unixeol		; конвертировать 0D0A в 0A и использовать везде 0A
 --hostlist=<filename>  ; действовать только над доменами, входящими в список из filename. поддомены автоматически учитываются.
			; в файле должен быть хост на каждой строке.
			; список читается 1 раз при старте и хранится в памяти в виде иерархической структуры для быстрого поиска.
			; для списка РКН может потребоваться система с 128 Mb памяти !
			; расчитывайте требование RAM для процесса как 3-5 кратный размер файла списка.
			; по сигналу HUP список будет перечитан при следующем принятом соединении
			; список может быть запакован в gzip. формат автоматически распознается и разжимается
			; хосты извлекаются из Host: хедера обычных http запросов и из SNI в TLS ClientHello.

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

В случае http запроса split-http-req имеет преимущество над split-pos.
split-pos по умолчанию работает только на http и TLS ClientHello.
Чтобы он работал на любых пакетах, укажите --split-any-protocol.

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

tpws может биндаться на множество интерфейсов и IP адресов (до 32 шт).
Порт всегда только один.
Параметры --bind-iface* и --bind-addr создают новый бинд.
Остальные параметры --bind-* относятся к последнему бинду.
Для бинда на все ipv4 укажите --bind-addr "0.0.0.0", на все ipv6 - "::". --bind-addr="" - биндаемся на все ipv4 и ipv6.
Выбор режима использования link local ipv6 адресов (fe80::/8) :
--bind-iface6 --bind-linklocal=no : сначала приватный адрес fc00::/7, затем глобальный адрес
--bind-iface6 --bind-linklocal=unwanted : сначала приватный адрес fc00::/7, затем глобальный адрес, затем link local.
--bind-iface6 --bind-linklocal=prefer : сначала link local, затем приватный адрес fc00::/7, затем глобальный адрес.
--bind-iface6 --bind-linklocal=force : только link local
Если не указано ни одного бинда, то создается бинд по умолчанию на все адреса всех интерфейсов.
Для бинда на конкретный link-local address делаем так : --bind-iface6=fe80::aaaa:bbbb:cccc:dddd%iface-name
Параметры --bind-wait* могут помочь в ситуациях, когда нужно взять IP с интерфейса, но его еще нет, он не поднят
или не сконфигурирован.
В разных системах события ifup ловятся по-разному и не гарантируют, что интерфейс уже получил IP адрес определенного типа.
В общем случае не существует единого механизма повеситься на событие типа "на интерфейсе X появился link local address".
Для бинда на известный ip, когда еще интерфейс не сконфигурирован, нужно делать так : --bind-addr=192.168.5.3 --bind-wait-ip=20
В режиме transparent бинд возможен на любой несуществующий адрес, в режиме socks - только на существующий.

Параметры 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
-------------------------------------------

!!! nftables не могут работать с ipset-ами. Собственный аналогичный механизм требует огромного количество RAM
!!! для загрузки больших листов.  Например, для загона 100K записей в nfset не хватает даже 256 Mb.
!!! Если вам нужны большие листы на домашних роутерах, откатывайтесь на iptables+ipset.

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 (собственная разработка).
Реестр РКН уже настолько огромен, что однопоточный ресолв займет вечность, а многопоточный хоть и тоже много времени,
но хотя бы оно конечно.
На роутерах с небольшим объемом RAM может сработать только с TMPDIR на внешнем носителе

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

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

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

5) ipset/get_antifilter_ip.sh. получает лист https://antifilter.network/download/ip.lst.

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.
Это позволяет снизить их размер во много раз и сэкономить место на роутере.
Отключить сжатие листов можно параметром конфига GZIP_LISTS=0.

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

Принудительное обновление ipset выполняет скрипт ipset/create_ipset.sh.
Если передан параметр "no-update", скрипт не обновляет ipset, а только создает его при его отсутствии и заполняет.
Это полезно, когда могут случиться несколько последовательных вызовов скрипта. Нет смысла несколько раз перезаполнять
ipset, это длительная операция на больших листах. Листы можно обновлять раз в несколько суток, и только тогда
вызывать create_ipset без параметра "no-update". Во всех остальных случаях стоит применять "no-update".

Список РКН уже достиг внушительных размеров в сотни тысяч IP адресов. Поэтому для оптимизации ipset
применяется утилита ip2net. Она берет список отдельных IP адресов и пытается интеллектуально создать из него подсети для сокращения
количества адресов. ip2net отсекает неправильные записи в листах, гарантируя осутствие ошибок при их загрузке.
ip2net написан на языке C, поскольку операция ресурсоемкая. Иные способы роутер может не потянуть.

Можно внести список доменов в 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 адреса или подсети.

FreeBSD. Скрипты ipset/*.sh работают так же на FreeBSD. Вместо ipset они создают lookup таблицы ipfw с аналогичными именами.
ipfw таблицы в отличие от ipset могут содержать как ipv4, так и ipv6 адреса и подсети в одной таблице, поэтому разделения нет.

Параметр конфига LISTS_RELOAD задает произвольную команду для перезагрузки листов.
Это особенно полезно на BSD системах с PF.
LISTS_RELOAD=-  отключает перезагрузку листов.


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.
ipfw из FreeBSD понимает ip/prefix, но не понимает ip1-ip2.
ip2net фильтрует входные данные, выкидывая неправильные IP адреса.

Выбирается подсеть, в которой присутствует указанный минимум адресов.
Для 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 и исключает zapret-hosts-exclude.txt.
init скрипт будет запускать tpws с листом zapret-hosts.txt.gz.

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


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

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

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

Если 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 по нескольким заблокированным сайтам и выявить общий характер блокировок.
Разные сайты могут быть заблокированы по-разному, нужно искать такую технику, которая работает на большинстве.
Чтобы записать вывод blockcheck.sh в файл, выполните : ./blockcheck.sh | tee /tmp/blockcheck.txt

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

Имейте в виду, что у провайдеров может быть несколько DPI или запросы могут идти через разные каналы
по методу балансировки нагрузки. Балансировка может означать, что на разных ветках разные DPI или
они находятся на разных хопах. Такая ситуация может выражаться в нестабильности работы обхода.
Дернули несколько раз curl. То работает, то connection reset или редирект. blockcheck.sh выдает
странноватые результаты. То split работает на 2-м. хопе, то на 4-м. Достоверность результата вызывает сомнения.
В этом случае задайте несколько повторов одного и того же теста. Тест будет считаться успешным только,
если все попытки пройдут успешно.


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

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

На linux системах можно выбрать использовать iptables или nftables.
По умолчанию на традиционных linux выбирается nftables, если установлен nft.
На openwrt по умолчанию выбирается nftables на новых версиях с firewall4.

FWTYPE=iptables

Основной режим :
tpws - tpws в режиме transparent
tpws-socks - tpws в режиме socks
 вешается на localhost и LAN интерфейс (если задан IFACE_LAN или если система - OpenWRT). порт 988
nfqws - nfqws
filter - только заполнить ipset или загрузить hostlist
custom - нужно самому запрограммировать запуск демонов в init скрипте и правила iptables

MODE=tpws

Применять ли дурение к HTTP :

MODE_HTTP=1

Применять ли дурение к последовательным http запросам в одном tcp соединении (http keeaplive).
Относится только к nfqws. Выключение данной функции способно сэкономить загрузку процессора.
tpws всегда работает с http keepalive

MODE_HTTP_KEEPALIVE=0

Применять ли дурение к HTTPS :

MODE_HTTPS=1

Режим фильтрации хостов :
none - применять дурение ко всем хостам
ipset - ограничить дурение ipset-ом zapret/zapret6
hostlist - ограничить дурение списком хостов из файла

MODE_FILTER=none

Опции tpws :

TPWS_OPT="--hostspell=HOST --split-http-req=method --split-pos=3"

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

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

Задание раздельных опций nfqws для http и https и для версий ip протоколов 4,6 :

NFQWS_OPT_DESYNC_HTTP="--dpi-desync=split --dpi-desync-ttl=0 --dpi-desync-fooling=badsum"
NFQWS_OPT_DESYNC_HTTPS="--wssize=1:6 --dpi-desync=split --dpi-desync-ttl=0 --dpi-desync-fooling=badsum"
NFQWS_OPT_DESYNC_HTTP6="--dpi-desync=split --dpi-desync-ttl=5 --dpi-desync-fooling=none"
NFQWS_OPT_DESYNC_HTTPS6="--wssize=1:6 --dpi-desync=split --dpi-desync-ttl=5 --dpi-desync-fooling=none"

Если какая-то из переменных NFQWS_OPT_DESYNC_HTTP/NFQWS_OPT_DESYNC_HTTPS не определена,
берется значение NFQWS_OPT_DESYNC.
Если какая-то из переменных NFQWS_OPT_DESYNC_HTTP6/NFQWS_OPT_DESYNC_HTTPS6 не определена,
берется значение NFQWS_OPT_DESYNC_HTTP/NFQWS_OPT_DESYNC_HTTPS.

Настройка системы управления выборочным traffic offload (только openwrt)
donttouch : выборочное управление отключено, используется системная настройка, простой инсталятор выключает системную настройку, если она не совместима с выбранным режимом
none : выборочное управление отключено, простой инсталятор выключает системную настройку
software : выборочное управление включено в режиме software, простой инсталятор выключает системную настройку
hardware : выборочное управление включено в режиме hardware, простой инсталятор выключает системную настройку

FLOWOFFLOAD=donttouch

Параметр 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-ов и nfset-ов

SET_MAXELEM=262144
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"

Включить или выключить сжатие больших листов в скриптах ipset/*.sh. По умолчанию включено.
GZIP_LISTS=1

Команда для перезагрузки ip таблиц фаервола.
Если не указано или пустое, выбирается автоматически ipset или ipfw при их наличии.
На BSD системах с PF нет автоматической загрузки. Там нужно указать команду явно : pfctl -f /etc/pf.conf
На более новых pfctl (есть в новых FreeBSD, нет в OpenBSD 6.8) можно дать команду загрузки только таблиц : pfctl -Tl -f /etc/pf.conf
"-" означает отключение загрузки листов даже при наличии поддерживаемого backend.
#LISTS_RELOAD="pfctl -f /etc/pf.conf"
#LISTS_RELOAD=-

В openwrt существует сеть по умолчанию 'lan'. Только трафик с этой сети будет перенаправлен на tpws.
Но возможно задать другие сети или список сетей :
OPENWRT_LAN="lan lan2 lan3"

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

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

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

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

Если вы используете какую-то систему управления фаерволом, то она может вступать в конфликт
с имеющимся скриптом запуска. При повторном применении правил она могла бы поломать настройки 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 restart_fw

А так можно запустить или остановить демоны отдельно от фаервола :

 /opt/zapret/init.d/sysv/zapret start_daemons
 /opt/zapret/init.d/sysv/zapret stop_daemons
 /opt/zapret/init.d/sysv/zapret restart_daemons

nftables сводят практически на нет конфликты между разными системами управления, поскольку позволяют
использовать независимые таблицы и хуки. Используется отдельная nf-таблица "zapret".
Если ваша система ее не будет трогать, скорее всего все будет нормально.

Для nftables предусмотрено несколько дополнительных вызовов :

Посмотреть set-ы интерфейсов, относящихся к lan, wan и wan6. По ним идет завертывание трафика.
А так же таблицу flow table с именами интерфейсов ingress hook.
 /opt/zapret/init.d/sysv/zapret list_ifsets

Обновить set-ы интерфейсов, относящихся к lan, wan и wan6.
Для традиционных linux список интерфейсов берется из переменных конфига IFACE_LAN, IFACE_WAN.
Для openwrt определяется автоматически. Множество lanif может быть расширено параметром OPENWRT_LAN.
Все интерфейсы lan и wan так же добавляются в ingress hook от flow table.
 /opt/zapret/init.d/sysv/zapret reload_ifsets

Просмотр таблицы без содержимого set-ов. Вызывает nft -t list table inet zapret
 /opt/zapret/init.d/sysv/zapret list_table

Так же возможно прицепиться своим скриптом к любой стадии применения и снятия фаервола со стороны zapret скриптов :

INIT_FW_PRE_UP_HOOK="/etc/firewall.zapret.hook.pre_up"
INIT_FW_POST_UP_HOOK="/etc/firewall.zapret.hook.post_up"
INIT_FW_PRE_DOWN_HOOK="/etc/firewall.zapret.hook.pre_down"
INIT_FW_POST_DOWN_HOOK="/etc/firewall.zapret.hook.post_down"

Эти настройки доступны в config.

Вариант custom
--------------

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

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

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

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

Для фаервола кастом пишется отдельно для iptables и nftables. Все очень похоже, но отличается
написание фильтров и названия процедур хелперов. Если вам не нужны iptables или nftables -
можете не писать соответствующую функцию.

Готовый custom скрипт custom-tpws4http-nfqws4https позволяет применить дурение
tpws к http и nfqws к https. При этом поддерживаются установки из config.
Его можно использовать как стартовую точку для написания своих скриптов.

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

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

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

Если хотите использовать nftables, то нужен пакет nftables, а ipset не обязателен.

Скопировать директорию 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

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

enable auto start : systemctl enable zapret
disable auto start : systemctl disable zapret
start : systemctl 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/openrc/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


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

install_easy.sh автоматизирует описанные выше ручные варианты процедур установки.
Он поддерживает OpenWRT, linux системы на базе systemd или openrc и MacOS.

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

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

Для совсем обрезанных дистрибутивов (alpine) требуется отдельно установить iptables и ip6tables.

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

 install_easy.sh make

Под openwrt все уже сразу готово для использования системы в качестве роутера.
Имена интерфейсов WAN и LAN известны из настроек системы.
Под другими системами роутер вы настраиваете самостоятельно. Инсталятор в это не вмешивается.
Инсталятор в зависимости от выбранного режима может спросить LAN и WAN интерфейсы.
Нужно понимать, что заворот проходящего трафика на tpws в прозрачном режиме происходит до выполнения маршрутизации,
следовательно возможна фильтрация по LAN и невозможна по WAN.
Решение о завороте на tpws локального исходящего трафика принимается после выполнения маршрутизации,
следовательно ситуация обратная : LAN не имеет смысла, фильтрация по WAN возможна.
Заворот на nfqws происходит всегда после маршрутизации, поэтому к нему применима только фильтрация по WAN.
Возможность прохождения трафика в том или ином направлении настраивается вами в процессе конфигурации роутера.

Деинсталяция выполняется через uninstall_easy.sh


Ручная установка на openwrt/LEDE 15.xx-21.xx
--------------------------------------------

!!! Данная инструкция написана для систем, основанных на iptables+firewall3
!!! В новых версиях openwrt переходит на nftables+firewall4, инструкция неприменима. Пользуйтесь install_easy.sh

Установить дополнительные пакеты :
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
(опционально) opkg install coreutils-sort

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

gzip от busybox в разы медленней полноценного варианта. gzip используется скриптами получения листов.
sort от busybox медленней полноценного варианта и жрет намного больше памяти. sort используется скриптами получения листов.
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
ПРИМЕЧАНИЕ : на этапе старта системы интерфейсы еще не подняты. в некоторых случаях невозможно правильно
сформировать параметры запуска демонов, не зная имя физического интерфейса LAN.
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, common, файл config, init.d/openwrt.
Далее нужно создать подкаталоги с реально используемыми бинариками (ip2net, mdig, tpws, nfq)
и скопировать туда из binaries рабочие executables.

ЕСЛИ ВСЕ ПЛОХО С МЕСТОМ : откажитесь от работы со списком РКН. используйте только 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, ...

Ответ на вопрос куда поместить tpws на android без рута, чтобы потом его запускать из приложений.
Файл заливаем через adb shell в /data/local/tmp/, лучше всего в субфолдер.
mkdir /data/local/tmp/zapret
adb push tpws /data/local/tmp/zapret
chmod 755 /data/local/tmp/zapret /data/local/tmp/zapret/tpws
chcon u:object_r:system_file:s0 /data/local/tmp/zapret/tpws

Мобильные модемы и роутеры 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 для arm работают нормально.

Чтобы избежать проблемы с 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 отсутствует. Значит, все, что можно сделать - создать индивидуальные правила
на небольшое количество хостов.

Некоторые наброски скриптов присутствуют в files/huawei. Не готовое решение ! Смотрите, изучайте, приспосабливайте.
Здесь можно скачать готовые полезные статические бинарики для arm, включая curl : https://github.com/bol-van/bins


FreeBSD, OpenBSD, MacOS
-----------------------

Описано в docs/bsd.txt


Windows (WSL)
-------------

tpws в режиме socks можно запускать и под более-менее современными билдами windows 10 и windows server
с установленным WSL. Совсем не обязательно устанавливать дистрибутив убунту, как вам напишут почти в каждой
статье про WSL, которую вы найдете в сети. tpws - статический бинарик, ему дистрибутив не нужен.

Установить WSL : dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all
Скопировать на целевую систему binaries/x86_64/tpws_wsl.tgz.
Выполнить : wsl --import tpws "%USERPROFILE%\tpws" tpws_wsl.tgz
Запустить : wsl --exec /tpws --uid=1 --no-resolve --socks --bind-addr=127.0.0.1 --port=1080 <параметры_дурения>
Прописать socks 127.0.0.1:1080 в броузер или другую программу.

Удаление : wsl --unregister tpws

Проверено на windows 10 build 19041 (20.04).

ЗАМЕЧАНИЕ. Под Windows существует нативное решение GoodByeDPI, выполняющее дурение на пакетном уровне (по типу nfqws).


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

Для статических бинариков не имеет значения на чем они запущены : 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.
С их помощью можно компенсировать недостаток ПО основной прошивки, за исключением ядра.

Можно попытаться использовать sysv init script таким образом, как это описано в разделе
"Прикручивание к системе управления фаерволом или своей системе запуска".
В случае ругани на отсутствие каких-то базовых программ, их следует восполнить посредством entware.
Перед запуском скрипта путь к дополнительным программам должен быть помещен в PATH.

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

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, позволяющего собрать недостающее


Обход блокировки через сторонний хост
-------------------------------------

Если не работает автономный обход, приходится перенаправлять трафик через сторонний хост.
Предлагается использовать прозрачный редирект через 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 не нужны совсем.
Это вариант наименее напряжный для чайников, хотя и не самый удобный в использовании.
