Compare commits

..

9 Commits

Author SHA1 Message Date
bol-van
fc2d511d78 update changes.txt 2024-11-18 23:19:51 +03:00
bol-van
5207104c06 readme: fix-seg info 2024-11-18 23:19:11 +03:00
bol-van
06147836d0 tpws: segmentation failure warning and fix 2024-11-18 23:06:23 +03:00
bol-van
46eb30a897 build docs for unix and windows 2024-11-18 21:00:25 +03:00
bol-van
840617a0c3 install_easy: copy systemd units instead of linking 2024-11-18 20:42:55 +03:00
bol-van
f7ae5eaae5 doc works 2024-11-18 20:33:37 +03:00
bol-van
827a838715 doc works 2024-11-18 20:25:52 +03:00
bol-van
db5c60e19f doc works 2024-11-18 20:24:17 +03:00
bol-van
256c2d7e50 doc works 2024-11-18 16:28:22 +03:00
13 changed files with 769 additions and 518 deletions

View File

@ -143,7 +143,7 @@ $ ipfw -q -f flush
zapret, добавив в параметры `--daemon`. Например так:
```sh
$ pkill ^dvtws$
$ /opt/zapret/nfq/dvtws --port=989 --daemon --dpi-desync=split2
$ /opt/zapret/nfq/dvtws --port=989 --daemon --dpi-desync=multisplit --dpi-desync-split-pos=2
```
Для перезапуска фаервола и демонов достаточно будет сделать:
@ -209,7 +209,7 @@ $ ipfw delete 100
$ ipfw add 100 divert 989 tcp from any to any 80,443 out not diverted xmit em0
# required for autottl mode only
$ ipfw add 100 divert 989 tcp from any 80,443 to any tcpflags syn,ack in not diverted recv em0
$ /opt/zapret/nfq/dvtws --port=989 --dpi-desync=split2
$ /opt/zapret/nfq/dvtws --port=989 --dpi-desync=multisplit --dpi-desync-split-pos=2
```
#### Трафик только на таблицу zapret, за исключением таблицы nozapret
@ -220,7 +220,7 @@ $ ipfw add 100 allow tcp from me to table\(nozapret\) 80,443
$ ipfw add 100 divert 989 tcp from any to table\(zapret\) 80,443 out not diverted not sockarg xmit em0
# required for autottl mode only
$ ipfw add 100 divert 989 tcp from table\(zapret\) 80,443 to any tcpflags syn,ack in not diverted not sockarg recv em0
$ /opt/zapret/nfq/dvtws --port=989 --dpi-desync=split2
$ /opt/zapret/nfq/dvtws --port=989 --dpi-desync=multisplit --dpi-desync-split-pos=2
```
@ -317,7 +317,7 @@ sysctl net.inet6.ip6.pfil.inbound=ipfw,pf
ipfw delete 100
ipfw add 100 divert 989 tcp from any to any 80,443 out not diverted xmit em0
pkill ^dvtws$
dvtws --daemon --port 989 --dpi-desync=split2
dvtws --daemon --port 989 --dpi-desync=multisplit --dpi-desync-split-pos=2
# required for newer pfsense versions (2.6.0 tested) to return ipfw to functional state
pfctl -d ; pfctl -e
@ -357,7 +357,7 @@ rdr pass on em1 inet6 proto tcp to port {80,443} -> fe80::20c:29ff:5ae3:4821 por
```sh
$ pfctl -a zapret -f /etc/zapret.anchor
$ pkill ^tpws$
$ tpws --daemon --port=988 --enable-pf --bind-addr=127.0.0.1 --bind-iface6=em1 --bind-linklocal=force --split-http-req=method --split-pos=2
$ tpws --daemon --port=988 --enable-pf --bind-addr=127.0.0.1 --bind-iface6=em1 --bind-linklocal=force --split-pos=2
```
4. После перезагрузки проверьте, что правила создались:
@ -424,7 +424,7 @@ pass out quick on em0 proto tcp to port {80,443} divert-packet port 989 no sta
```sh
$ pfctl -f /etc/pf.conf
$ ./dvtws --port=989 --dpi-desync=split2
$ ./dvtws --port=989 --dpi-desync=multisplit --dpi-desync-split-pos=2
```
#### Трафик только на таблицу zapret, за исключением таблицы nozapret
@ -456,7 +456,7 @@ pass out quick on em0 inet6 proto tcp to <zapret6-user> port {80,443} divert-p
```sh
$ pfctl -f /etc/pf.conf
$ ./dvtws --port=989 --dpi-desync=split2
$ ./dvtws --port=989 --dpi-desync=multisplit --dpi-desync-split-pos=2
```

View File

@ -70,7 +70,7 @@ pass in quick on em0 proto tcp from port {80,443} flags SA/SA divert-packet por
pass in quick on em0 proto tcp from port {80,443} no state
pass out quick on em0 proto tcp to port {80,443} divert-packet port 989 no state
pfctl -f /etc/pf.conf
./dvtws --port=989 --dpi-desync=split2
./dvtws --port=989 --dpi-desync=multisplit --dpi-desync-split-pos=2
; dvtws with table limitations : to zapret,zapret6 but not to nozapret,nozapret6
; reload tables : pfctl -f /etc/pf.conf

View File

@ -363,3 +363,29 @@ nfqws,tpws: use alternate $ sign for $<config_file>
repo: binaries removed from repo. git actions binaries build in releases.
uninstall_easy.sh: offer to remove dependencies in openwrt
install_easy.sh: allow to download lists in autohostlist filter mode
v69:
nfqws, tpws: multisplit/multidisorder support.
nfqws: name change split->fakedsplit, disorder->fakeddisorder. compat : old names are synonyms
nfqws: --dpi-desync-split-http-req, --dpi-desync-split-tls deprecated. compat : these parameters add split point to multisplit.
nfqws: --dpi-desync=split2|disorder2 deprecated. compat: they are now synonyms for multisplit/multidisorder
nfqws: cancel seqovl if MTU is exceeded (linux only). cancel seqovl for disorder if seqovl>=first_part_size.
nfqws: fixed splits in multiple TLS segments.
tpws: --split-tls,--split-tls deprecated. compat : these parameters add split point to multisplit.
tpws: --tlsrec now takes pos markers. compat : old names are converted to pos markers
tpws: --tlsrec-pos deprecated. compat : sets absolute pos marker
nfqws,tpws: chown autohostlist, autohostlist debug log and debug log files after options parse
nfqws,tpws: set EXEDIR env var to use in @config (won't work for stadalone winws without /bin/sh)
dvtws: set random/increasing ip_id value in generated packets
mdig: fixed parsing of DNS reply in windows (stdin is opened as text, not binary)
tpws: support compile for android NDK api level >= 21 (Android 5.0)
tpws: --fix-seg segmentation fixer
repo: build for android NDK api level 21 (Android 5.0)
install_easy: support for APK package manager in openwrt
blockcheck: removed ignore CA question
blockcheck: removed IGNORE_CA, CURL_VERBOSE
blockcheck: added CURL_OPT
blockcheck: new strategies support
blockcheck: test sequence rework
blockcheck: view all working strategies in summary

View File

@ -0,0 +1,16 @@
debian,ubuntu :
apt install make gcc zlib1g-dev libcap-dev libnetfilter-queue-dev
make -C /opt/zapret
FreeBSD :
make -C /opt/zapret
OpenBSD :
make -C /opt/zapret bsd
MacOS :
make -C /opt/zapret mac

View File

@ -0,0 +1,29 @@
Windows x64
1) Download latest cygwin for windows 7
curl -O https://www.cygwin.com/setup-x86_64.exe
setup-x86_64.exe --allow-unsupported-windows --no-verify --site http://ctm.crouchingtigerhiddenfruitbat.org/pub/cygwin/circa/64bit/2024/01/30/231215
2) During setup install packages : make gcc-core zlib-devel
3) Run Cygwin.bat
4) cd to %ZAPRET_BASE%/nfq
cd C:/Users/user/Downloads/zapret/nfq
5) Compile
make cygwin64
use winws.exe
6) Take windivert.dll and windivert64.sys here : https://reqrypt.org/download
Choose version 2.2.2 for Windows 10 and 2.2.0 for Windows 7.
7) Copy cygwin1.dll, winws.exe, windivert.dll and windivert64.sys to one folder.
8) Run winws.exe from cmd.exe running as administrator.
winws will not run from cygwin shell with cygwin1.dll copy in it's folder.
winws will not run without cygwin1.dll outside of cygwin shell.

View File

@ -1,4 +1,4 @@
# zapret v.68
# zapret v.69
# SCAMMER WARNING

View File

@ -1,4 +1,4 @@
# zapret v.68
# zapret v.69
# ВНИМАНИЕ, остерегайтесь мошенников
@ -17,12 +17,15 @@ zapret является свободным и open source.
- [Как это работает](#как-это-работает)
- [Что сейчас происходит в России](#что-сейчас-происходит-в-россии)
- [Как это реализовать на практике в системе linux](#как-это-реализовать-на-практике-в-системе-linux)
- [Особенности применения ip6tables](#особенности-применения-ip6tables)
- [Особенности применения nftables](#особенности-применения-nftables)
- [Когда это работать не будет](#когда-это-работать-не-будет)
- [nfqws](#nfqws)
- [АТАКА ДЕСИНХРОНИЗАЦИИ DPI](#атака-десинхронизации-dpi)
- [ФЕЙКИ](#фейки)
- [TCP СЕГМЕНТАЦИЯ](#tcp-сегментация)
- [ПЕРЕКРЫТИЕ SEQUENCE NUMBERS](#перекрытие-sequence-numbers)
- [СПЕЦИФИЧЕСКИЕ РЕЖИМЫ IPV6](#специфические-режимы-ipv6)
- [КОМБИНИРОВАНИЕ МЕТОДОВ ДЕСИНХРОНИЗАЦИИ](#комбинирование-методов-десинхронизации)
- [РЕАКЦИЯ DPI НА ОТВЕТ СЕРВЕРА](#реакция-dpi-на-ответ-сервера)
- [РЕЖИМ SYNACK](#режим-synack)
- [РЕЖИМ SYNDATA](#режим-syndata)
- [ВИРТУАЛЬНЫЕ МАШИНЫ](#виртуальные-машины)
@ -31,8 +34,18 @@ zapret является свободным и open source.
- [ПОДДЕРЖКА UDP](#поддержка-udp)
- [IP ФРАГМЕНТАЦИЯ](#ip-фрагментация)
- [МНОЖЕСТВЕННЫЕ СТРАТЕГИИ](#множественные-стратегии)
- [IPTABLES ДЛЯ NFQWS](#iptables-для-nfqws)
- [NFTABLES ДЛЯ NFQWS](#nftables-для-nfqws)
- [FLOW OFFLOADING](#flow-offloading)
- [tpws](#tpws)
- [TCP СЕГМЕНТАЦИЯ В TPWS](#tcp-сегментация-в-tpws)
- [TLSREC](#tlsrec)
- [MSS](#mss)
- [ДРУГИЕ ПАРАМЕТРЫ ДУРЕНИЯ](#другие-параметры-дурения)
- [МНОЖЕСТВЕННЫЕ СТРАТЕГИИ](#множественные-стратегии-1)
- [СЛУЖЕБНЫЕ ПАРАМЕТРЫ](#служебные-параметры)
- [IPTABLES ДЛЯ TPWS](#iptables-для-tpws)
- [NFTABLES ДЛЯ TPWS](#nftables-для-tpws)
- [Способы получения списка заблокированных IP](#способы-получения-списка-заблокированных-ip)
- [ip2net](#ip2net)
- [mdig](#mdig)
@ -126,107 +139,6 @@ DPI. Все больше становится внереестровых бло
Для вариантов 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:6 -m mark ! --mark 0x40000000/0x40000000 -m set --match-set zapret dst -j NFQUEUE --queue-num 200 --queue-bypass`
Фильтр по mark нужен для отсечения от очереди пакетов, сгенерированных внутри nfqws. Если применяется фильтр по
connbytes 1:6, то обязательно добавлять в iptables и фильтр по mark. Иначе возможно перепутывание порядка следования
пакетов, что приведет к неработоспособности метода. Так же возможно зависание nfqws по deadlock.
Для некоторых атак на DPI требуется перенаправлять один или несколько входящих пакетов от соединения :
`iptables -t mangle -I PREROUTING -i <внешний_интерфейс> -p tcp --sport 80 -m connbytes --connbytes-dir=reply --connbytes-mode=packets --connbytes 1:6 -m set --match-set zapret src -j NFQUEUE --queue-num 200 --queue-bypass`
Получаемые пакеты будут фильтроваться по входящему интерфейсу, порту и IP источника, то есть наоборот прямому правилу.
Некоторые техники, ломающие NAT, не всегда можно реализовать через iptables. Требуются nftables.
Если ваше устройство поддерживает аппаратное ускорение (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_notes.txt) Если
коротко, то в nftables невозможно работать с большими ip листами на системах с малым количеством RAM. Остальные
рассматриваемые здесь функции могут быть перенесены на nftables.
Рекомендуется версия nft `1.0.2` или выше. Но чем выше версия, тем лучше. В nft регулярно находят баги.
Относительно старые версии ядра и/или утилиты nft могут вызывать ошибки. В частности, на ubuntu 18.04 с ядром 4.15 будут
проблемы. В 20.04 - работает.
Некоторые техники можно полноценно использовать только с nftables. Например, в iptables невозможно перенаправить пакеты
на nfqws после NAT. Следовательно, при использовании NAT невозможно произвести атаку, не совместимую с NAT. В nftables
этой проблемы не существует, потому что приоритеты хука выставляете вы сами, а не привязаны к фиксированным значениям,
соответствующим разным таблицам iptables. В iptables нет таблицы, способной перехватить пакеты после MASQUERDADE.
## Когда это работать не будет
* Если подменяется DNS. С этой проблемой легко справиться.
@ -265,7 +177,7 @@ dvtws, собираемый из тех же исходников (см. [док
--hostnospace ; убрать пробел после "Host:" и переместить его в конец значения "User-Agent:" для сохранения длины пакета
--hostspell=HoST ; точное написание заголовка Host (можно "HOST" или "HoSt"). автоматом включает --hostcase
--domcase ; домен после Host: сделать таким : TeSt.cOm
--dpi-desync=[<mode0>,]<mode>[,<mode2] ; атака по десинхронизации DPI. mode : synack syndata fake fakeknown rst rstack hopbyhop destopt ipfrag1 disorder disorder2 split split2 ipfrag2 udplen tamper
--dpi-desync=[<mode0>,]<mode>[,<mode2] ; атака по десинхронизации DPI. mode : synack syndata fake fakeknown rst rstack hopbyhop destopt ipfrag1 multisplit multidisorder fakedsplit fakeddisorder ipfrag2 udplen tamper
--dpi-desync-fwmark=<int|0xHEX> ; бит fwmark для пометки десинхронизирующих пакетов, чтобы они повторно не падали в очередь. default = 0x40000000
--dpi-desync-ttl=<int> ; установить ttl для десинхронизирующих пакетов
--dpi-desync-ttl6=<int> ; установить ipv6 hop limit для десинхронизирующих пакетов. если не указано, используется значение ttl
@ -274,10 +186,8 @@ dvtws, собираемый из тех же исходников (см. [док
--dpi-desync-fooling=<fooling> ; дополнительные методики как сделать, чтобы фейковый пакет не дошел до сервера. none md5sig badseq badsum datanoack hopbyhop hopbyhop2
--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-split-http-req=method|host ; разбивка http request на указанном логическом месте
--dpi-desync-split-tls=sni|sniext ; разбивка tls client hello на указанном логическом месте
--dpi-desync-split-seqovl=<int> ; использовать sequence overlap перед первым отсылаемым оригинальным tcp сегментом
--dpi-desync-split-pos=N|-N|marker+N|marker-N ; список через запятую маркеров для tcp сегментации в режимах split и disorder
--dpi-desync-split-seqovl=N|-N|marker+N|marker-N ; единичный маркер, определяющий величину перекрытия sequence в режимах split и disorder. для split поддерживается только положительное число.
--dpi-desync-split-seqovl-pattern=<filename>|0xHEX ; чем заполнять фейковую часть overlap
--dpi-desync-badseq-increment=<int|0xHEX> ; инкремент sequence number для badseq. по умолчанию -10000
--dpi-desync-badack-increment=<int|0xHEX> ; инкремент ack sequence number для badseq. по умолчанию -66000
@ -315,12 +225,6 @@ dvtws, собираемый из тех же исходников (см. [док
--ipset-exclude=<filename> ; исключающий ip list. на каждой строчке ip или cidr ipv4 или ipv6. поддерживается множество листов и gzip. перечитка автоматическая.
```
Параметры манипуляции могут сочетаться в любых комбинациях.
> [!TIP]
> **ЗАМЕЧАНИЕ.** Параметр `--wsize` считается устаревшим и более не поддерживается в скриптах. Функции сплита выполняются в
> рамках атаки десинхронизации. Это быстрее и избавляет от целого ряда недостатков wsize.
`--debug` позволяет выводить подробный лог действий на консоль, в syslog или в файл. Может быть важен порядок следования
опций. `--debug` лучше всего указывать в самом начале. Опции анализируются последовательно. Если ошибка будет при
проверке опции, а до анализа `--debug` еще дело не дошло, то сообщения не будут выведены в файл или syslog. При
@ -332,18 +236,24 @@ dvtws, собираемый из тех же исходников (см. [док
### АТАКА ДЕСИНХРОНИЗАЦИИ DPI
Суть ее в следующем. После выполнения tcp 3-way handshake идет первый пакет с данными от клиента. Там обычно `GET / ...`
или TLS ClientHello. Мы дропаем этот пакет, заменяя чем-то другим. Это может быть поддельная версия с безобидным, но
валидным запросом http или https (вариант `fake`), пакет сброса соединения (варианты `rst`, `rstack`), разбитый на части
оригинальный пакет с перепутанным порядком следования сегментов + обрамление первого сегмента фейками (`disorder`), то
же самое без перепутывания порядка сегментов (`split`). fakeknown отличается от fake тем, что применяется только к
распознанному протоколу. В литературе такие атаки еще называют **TCB desynchronization** и **TCB teardown**. Надо, чтобы
фейковые пакеты дошли до DPI, но не дошли до сервера. На вооружении есть следующие возможности : установить низкий TTL,
посылать пакет с инвалидной чексуммой, добавлять tcp option **MD5 signature**, испортить sequence numbers. Все они не
лишены недостатков.
Суть ее в следующем. Берется оригинальный запрос, модифицируется, добавляется поддельная информация (фейки)
таким образом, чтобы ОС сервера передала серверному процессу оригинальный запрос в неизменном виде, а DPI увидел другое.
То, что он блокировать не станет. Сервер видит одно, DPI - другое. DPI не понимает, что передается запрещенный запрос и не блокирует его.
* `md5sig` работает не на всех серверах. Пакеты с md5 обычно отбрасывают только linux.
* `badsum` не сработает, если ваше устройство за NAT, который не пропускает пакеты с инвалидной суммой. Наиболее
Есть арсенал возможностей, чтобы достичь такого результата.
Это может быть передача фейк пакетов, чтобы они дошли до DPI, но не дошли до сервера. Может использоваться фрагментация на уровне TCP (сегментация) или на уровне IP.
Есть атаки, основанные на игре с tcp sequence numbers или с перепутыванием порядка следования tcp сегментов.
Методы могут сочетаться в различных вариантах.
### ФЕЙКИ
Фейки - это отдельные сгенерированные nfqws пакеты, несущие ложную информацию для DPI.
Они либо не должны дойти до сервера, либо могут дойти, но должны быть им отброшены.
Иначе получается слом tcp соединения или нарушение целостности передаваемого потока, что гарантированно приводит к поломке ресурса.
Есть ряд методов для решения этой задачи.
* `md5sig` добавляет TCP опцию **MD5 signature**. Работает не на всех серверах. Пакеты с md5 обычно отбрасывают только linux.
* `badsum` портит контрольную сумму TCP. Не сработает, если ваше устройство за NAT, который не пропускает пакеты с инвалидной суммой. Наиболее
распространенная настройка NAT роутера в Linux их не пропускает. На Linux построено большинство домашних роутеров.
Непропускание обеспечивается так : настройка ядра sysctl по умолчанию
`net.netfilter.nf_conntrack_checksum=1` заставляет conntrack проверять tcp и udp чексуммы входящих пакетов и
@ -359,7 +269,8 @@ dvtws, собираемый из тех же исходников (см. [док
себя ведут некоторые роутеры на базе mediatek. badsum пакеты уходят с клиентской ОС, но роутером не видятся в br-lan
через tcpdump. При этом если nfqws выполняется на самом роутере, обход может работать. badsum нормально уходят с
внешнего интерфейса.
* Пакеты с `badseq` будут наверняка отброшены принимающим узлом, но так же и DPI, если он ориентируется на sequence
* `badseq` увеличивает TCP sequence number на определенное значение, выводя его тем самым из TCP window.
Такие пакеты будут наверняка отброшены принимающим узлом, но так же и DPI, если он ориентируется на sequence
numbers. По умолчанию смещение seq выбирается -10000. Практика показала, что некоторые DPI не пропускают seq вне
определенного окна. Однако, такое небольшое смещение может вызвать проблемы при существенной потоковой передаче и
потере пакетов. Если вы используете `--dpi-desync-any-protocol`, может понадобится установить badseq increment
@ -383,7 +294,8 @@ dvtws, собираемый из тех же исходников (см. [док
может ломать NAT и не всегда работает с iptables, если используется masquerade, даже с локальной системы (почти всегда
на роутерах ipv4). На системах c iptables без masquerade и на nftables работает без ограничений. Экспериментально
выяснено, что многие провайдерские NAT не отбрасывают эти пакеты, потому работает даже с внутренним провайдерским IP.
Но linux NAT оно не пройдет, так что за домашним роутером эта техника не сработает, но может сработать с него.
Но linux NAT оно не пройдет, так что за домашним роутером эта техника скорее всего не сработает, но может сработать с него.
Может сработать и через роутер, если подключение по проводу, и на роутере включено аппаратное ускорение.
* `autottl`. Суть режима в автоматическом определении TTL, чтобы он почти наверняка прошел DPI и немного не дошел до
сервера. Берутся базовые значения TTL 64,128,255, смотрится входящий пакет
(да, требуется направить первый входящий пакет на nfqws !). Вычисляется длина пути, отнимается `delta` (1 по
@ -396,44 +308,64 @@ dvtws, собираемый из тех же исходников (см. [док
Режимы дурения могут сочетаться в любых комбинациях. `--dpi-desync-fooling` берет множество значений через запятую.
Для режимов fake, rst, rstack после фейка отправляем оригинальный пакет.
### TCP СЕГМЕНТАЦИЯ
Режим disorder делит оригинальный пакет на 2 части и отправляет следующую комбинацию в указанном порядке :
* `multisplit`. нарезаем запрос на указанных в `--dpi-desync-split-pos` позициях.
* `multidisorder`. нарезаем запрос на указанных в `--dpi-desync-split-pos` позициях и отправляем в обратном порядке.
* `fakedsplit`. нарезаем запрос на 2 части, обрамляя его фейками : фейк 1-й части, 1 часть, фейк 1-й части, 2 часть
* `fakeddisorder`. нарезаем запрос на 2 части, обрамляя его фейками : 2 часть, фейк 1-й части, 1 часть, фейк 1 части.
1. 2-я часть пакета
2. поддельная 1-я часть пакета, поле данных заполнено нулями
3. 1-я часть пакета
4. поддельная 1-я часть пакета, поле данных заполнено нулями. отсылка 2-й раз. Оригинальный пакет дропается всегда.
Для определения позиций нарезки используются маркеры.
Параметр `--dpi-desync-split-pos` позволяет указать байтовую позицию, на которой происходит разбивка. По умолчанию - 2.
Если позиция больше длины пакета, позиция выбирается 1. Этой последовательностью для DPI максимально усложняется задача
реконструкции начального сообщения, по которому принимается решение о блокировке. Некоторым DPI хватит и tcp сегментов в
неправильном порядке, поддельные части сделаны для дополнительной надежности и более сложных алгоритмов реконструкции.
Режим `disorder2` отключает отправку поддельных частей.
* **Абсолютный положительный маркер** - числовое смещение внутри пакета или группы пакетов от начала.
* **Абсолютный отрицательный маркер** - числовое смещение внутри пакета или группы пакетов от следующего за концом байта. -1 указывает на последний байт.
* **Относительный маркер** - положительное или отрицательное смещение относительно логической позиции внутри пакета или группы пакетов.
Режим `split` очень похож на disorder, только нет изменения порядка следования сегментов :
Относительные позиции :
1. поддельная 1-я часть пакета, поле данных заполнено нулями
2. 1-я часть пакета
3. поддельная 1-я часть пакета, поле данных заполнено нулями. отсылка 2-й раз.
4. 2-я часть пакета Режим split2 отключает отправку поддельных частей. Он может быть использован как более быстрая
альтернатива --wsize.
* **method** - начало метода HTTP ('GET', 'POST', 'HEAD', ...). Метод обычно всегда находится на позиции 0, но поддерживается и нахождение метода после дурение методом `--methodeol` от tpws. Тогда позиция может стать 1 или 2.
* **host** - начало имени хоста в известном протоколе (http, TLS)
* **endhost** - конец имени хоста
* **sld** - начало домена 2 уровня в имени хоста
* **endsld** - конец домена 2 уровня в имени хоста
* **midsld** - середина домена 2 уровня в имени хоста
* **sniext** - начало поля данных SNI extension в TLS. Любой extension состоит из 2-байтовых полей type и length, за ними идет поле данных.
`disorder2` и `split2` не предполагают отсылку фейк пакетов, поэтому опции ttl и fooling неактуальны.
Пример списка маркеров : `100,midsld,sniext+1,endhost-2,-10`.
`seqovl` добавляет в начало первой отсылаемой части оригинального пакета (1 часть для split и 2 часть для disorder)
`seqovl` байт со смещенным в минус sequence number на величину seqovl. В случае `split2` расчет идет на то, что предыдущий
отсыл, если он был, уже попал в сокет серверного приложения, поэтому новая пришедшая часть лишь частично находится в
При разбиении пакета первым делом происходит ресолвинг маркеров - нахождение всех указанных относительных позиций и применение смещений.
Если относительная позиция отсутствует в текущем протоколе, такие позиции не применяются и отбрасываются.
Дальше происходит нормализация позиций относительно смещения текущего пакета в группе пакетов (многопакетные запросы TLS с kyber, например).
Выкидываются все позиции, выходящие за пределы текущего пакета. Оставшиеся сортируются в порядке возрастания и удаляются дубли.
В вариантах `multisplit` и `multidisorder` если не осталось ни одной позиции, разбиение не происходит.
Варианты `fakedsplit` и `fakeddisorder` применяют только одну позицию сплита. Ее поиск среди списка `--dpi-desync-split-pos` осуществляется особым образом.
Сначала сверяются все относительные маркеры. Если среди них найден подходящий, применяется он. В противном случае сверяются все абсолютные маркеры.
Если и среди них ничего не найдено, применяется позиция 1.
Например, можно написать `--dpi-desync-split-pos=method+2,midsld,5`. Если протокол http, разбиение будет на позиции `method+2`.
Если протокол TLS - на позиции `midsld`. Если протокол неизвестен и включено `--dpi-desync-any-protocol`, разбиение будет на позиции 5.
Чтобы все было однозначнее, можно использовать разные профили для разных протоколов и указывать только одну позицию, которая точно есть в этом протоколе.
### ПЕРЕКРЫТИЕ SEQUENCE NUMBERS
`seqovl` добавляет в начало одного из TCP сегментов `seqovl` байт со смещенным в минус sequence number на величину `seqovl`.
Для `split` - в начало первого сегмента, для `disorder` - в начало предпоследнего отсылаемого сегмента (второго в оригинальном порядке следования).
В случае `split` расчет идет на то, что предыдущий отсыл, если он был, уже попал в сокет серверного приложения, поэтому новая пришедшая часть лишь частично находится в
пределах текущего окна (in-window). Спереди фейковая часть отбрасывается, а оставшаяся часть содержит оригинал и
начинается с начала window, поэтому попадает в сокет. Серверное приложение получает все, что реально отсылает клиент,
отбрасывая фейковую out-of-window часть. Но DPI не может этого понять, поэтому у него происходит sequence
десинхронизация.
отбрасывая фейковую out-of-window часть. Но DPI не может этого понять, поэтому у него происходит sequence десинхронизация.
Обязательно, чтобы первый сегмент вместе с `seqovl` не превысили длину MTU. Эта ситуация распознается автоматически в Linux, и `seqovl` отменяется.
В остальных системах ситуация не распознается, и это приведет к поломке соединения. Поэтому выбирайте первую позицию сплита и `seqovl` таким образом, чтобы MTU не был превышен в любом случае.
Иначе дурение может не работать или работать хаотично.
Для `disorder2` overlap идет на 2-ю часть пакета. Обязательно, чтобы `seqovl` был меньше `split_pos`, иначе
все отосланное будет передано в сокет сразу же, включая фейк, ломая протокол прикладного уровня.
При соблюдении этого условия 2-я часть пакета является полностью in-window,
поэтому серверная ОС принимает ее целиком, включая фейк. Но поскольку начальная часть данных из 1 пакета
еще не принята, то фейк и реальные данные остаются в памяти ядра, не отправляясь в серверное приложение.
Для `disorder` overlap идет на предпоследнюю отсылаемую часть пакета.
Для простоты будем считать, что разбиение идет на 2 части, шлются они в порядке "2 1" при оригинальном порядке "1 2".
Обязательно, чтобы `seqovl` был меньше позиции первого сплита, иначе все отосланное будет передано в сокет сразу же, включая фейк, ломая протокол прикладного уровня.
Такая ситуация легко обнаруживается программой, и `seqovl` отменяется. Увеличение размера пакета невозможно в принципе.
При соблюдении условия 2-я часть пакета является полностью in-window, поэтому серверная ОС принимает ее целиком, включая фейк.
Но поскольку начальная часть данных из 1 пакета еще не принята, то фейк и реальные данные остаются в памяти ядра, не отправляясь в серверное приложение.
Как только приходит 1-я часть пакета, она переписывает фейковую часть в памяти ядра.
Ядро получает данные из 1 и 2 части, поэтому далее идет отправка в сокет приложения.
Таково поведение всех unix ОС, кроме solaris - оставлять последние принятые данные.
@ -441,7 +373,13 @@ Windows оставляет старые данные, поэтому disorder с
при работе с Windows серверами. Solaris практически мертв, windows серверов очень немного.
Можно использовать листы при необходимости.
Метод позволяет обойтись без fooling и TTL. Фейки перемешаны с реальным данными.
`split/disorder` вместо `split2/disorder2` по-прежнему добавляют дополнительные отдельные фейки.
`fakedsplit/fakeddisorder` по-прежнему добавляют дополнительные отдельные фейки.
`seqovl` в варианте `split` может быть только абсолютным положительным значением, поскольку применяется только в первому пакету.
В варианте `disorder` допустимо применение всех вариантов маркеров.
Они автоматически нормализуются к текущему пакету в серии. Можно сплитать на `midsld` и делать seqovl на `midsld-1`.
### СПЕЦИФИЧЕСКИЕ РЕЖИМЫ IPV6
Режимы десинхронизации `hopbyhop`, `destopt` и `ipfrag1` (не путать с fooling !) относятся только к `ipv6` и заключается
в добавлении хедера `hop-by-hop options`, `destination options` или `fragment` во все пакеты, попадающие под десинхронизацию.
@ -452,10 +390,22 @@ Windows оставляет старые данные, поэтому disorder с
extension хедерам в поисках транспортного хедера. Таким образом не поймет, что это tcp или udp, и пропустит пакет
без анализа. Возможно, какие-то DPI на это купятся.
Может сочетаться с любыми режимами 2-й фазы, кроме варианта `ipfrag1+ipfrag2`.
Например, `hopbyhop,split2` означает разбить tcp пакет на 2 сегмента, в каждый из них добавить hop-by-hop.
Например, `hopbyhop,multisplit` означает разбить tcp пакет на несколько сегментов, в каждый из них добавить hop-by-hop.
При `hopbyhop,ipfrag2` последовательность хедеров будет : `ipv6,hop-by-hop`,`fragment`,`tcp/udp`.
Режим `ipfrag1` может срабатывать не всегда без специальной подготовки. См. раздел `IP фрагментация`.
### КОМБИНИРОВАНИЕ МЕТОДОВ ДЕСИНХРОНИЗАЦИИ
В параметре dpi-desync можно указать до 3 режимов через запятую.
* 0 фаза - предполагает работу на этапе установления соединения : `synack`, `syndata` `--wsize`, `--wssize`. На эту фазу не действуют фильтры по [hostlist](((#множественные-стратегии))).
* 1 фаза - отсылка чего-либо до оригинального пакета данных : `fake`, `rst`, `rstack`.
* 2 фаза - отсылка в модифицированном виде оригинального пакета данных (например, `fakedsplit` или `ipfrag2`).
Режимы требуют указания в порядке возрастания номеров фаз.
### РЕАКЦИЯ DPI НА ОТВЕТ СЕРВЕРА
Есть DPI, которые анализируют ответы от сервера, в частности сертификат из ServerHello, где прописаны домены.
Подтверждением доставки ClientHello является ACK пакет от сервера с номером ACK sequence, соответствующим длине ClientHello+1.
В варианте disorder обычно приходит сперва частичное подтверждение (SACK), потом полный ACK.
@ -470,44 +420,6 @@ DPI может отстать от потока, если ClientHello его у
Лучшее решение - включить на сервере поддержку 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:6 -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:6 -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,
чтобы не допустить изменения порядка следования пакетов. Процессинг очереди - процесс отложенный.
Если ядро имеет пакеты на отсылку вне очереди - оно их отправляет незамедлительно.
Изменение правильного порядка следования пакетов при десинхронизации ломает всю идею.
Так же были замечены дедлоки при достаточно большой отсылке пакетов из nfqws и отсутствии mark фильтра.
Процесс может зависнуть. Поэтому наличие фильтра по mark в ip/nf tables можно считать обязательным.
Почему --connbytes 1:6 :
1 - для работы методов десинхронизации 0-й фазы и wssize
2 - иногда данные идут в 3-м пакете 3-way handshake
3 - стандартная ситуация приема одного пакета запроса
4-6 - на случай ретрансмиссии или запроса длиной в несколько пакетов (TLSClientHello с kyber, например)
### КОМБИНИРОВАНИЕ МЕТОДОВ ДЕСИНХРОНИЗАЦИИ
В параметре dpi-desync можно указать до 3 режимов через запятую.
0 фаза предполагает работу на этапе установления соединения. Может быть `synack` или `syndata`.
На 0 фазу не действует фильтр по hostlist.
Последующие режимы отрабатывают на пакетах с данными.
Режим 1-й фазы может быть `fake`, `rst`, `rstack`. Режим 2-й фазы может быть `disorder`, `disorder2`, `split`, `split2`, `ipfrag2`.
Может быть полезно, когда у провайдера стоит не один DPI.
### РЕЖИМ SYNACK
В документации по geneva это называется "TCB turnaround". Попытка ввести DPI в заблуждение относительно
@ -617,10 +529,10 @@ chrome рандомизирует фингерпринт TLS. SNI может о
При любой ошибке в процессе сборки задержанные пакеты немедленно отсылаются в сеть, а десинхронизация отменяется.
Есть специальная поддержка всех вариантов tcp сплита для многосегментного TLS.
Если указать позицию сплита больше длины первого пакета или использовать --dpi-desync-split-tls,
то разбивка происходит не обязательно первого пакета, а того, на который пришлась итоговая позиция.
Если, допустим, клиент послал TLS ClientHello длиной 2000, а SNI начинается с 1700,
и заданы опции fake,split2, то перед первым пакетом идет fake, затем первый пакет в оригинале,
Если указать позицию сплита больше длины первого пакета, то разбивка происходит не обязательно первого пакета, а того,
на который пришлась итоговая позиция.
Если, допустим, клиент послал TLS ClientHello длиной 2000, SNI начинается с 1700,
и заданы опции `fake,multisplit`, то перед первым пакетом идет fake, затем первый пакет в оригинале,
а последний пакет разбивается на 2 сегмента. В итоге имеем фейк в начале и 3 реальных сегмента.
### ПОДДЕРЖКА UDP
@ -737,6 +649,115 @@ L7 протокол становится известен обычно посл
> Вариант в ядре работает гораздо эффективнее. Это создавалось для систем без подержки ipset в ядре.
> Конкретно - Windows и ядра Linux, собранные без nftables и ipset модулей ядра. Например, в android нет ipset.
### IPTABLES ДЛЯ NFQWS
iptables для задействования атаки на первые пакеты данных в tcp соединении :
```
iptables -t mangle -I POSTROUTING -o <внешний_интерфейс> -p tcp -m multiport --dports 80,443 -m connbytes --connbytes-dir=original --connbytes-mode=packets --connbytes 1:6 -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:6 -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,
чтобы не допустить изменения порядка следования пакетов. Процессинг очереди - процесс отложенный.
Если ядро имеет пакеты на отсылку вне очереди - оно их отправляет незамедлительно.
Изменение правильного порядка следования пакетов при десинхронизации ломает всю идею.
Так же были замечены дедлоки при достаточно большой отсылке пакетов из nfqws и отсутствии mark фильтра.
Процесс может зависнуть. Поэтому наличие фильтра по mark в ip/nf tables можно считать обязательным.
Почему `--connbytes 1:6` :
* 1 - для работы методов десинхронизации 0-й фазы и корректной работы conntrack
* 2 - иногда данные идут в 3-м пакете 3-way handshake
* 3 - стандартная ситуация приема одного пакета запроса
* 4-6 - на случай ретрансмиссии или запроса длиной в несколько пакетов (TLSClientHello с kyber, например)
Для режима autottl необходимо перенаправление входящего `SYN,ACK` пакета или первого пакета соединения (что обычно есть тоже самое).
Можно построить фильтр на tcp flags и модуле u32 для поиска характерных паттернов http redirect, но проще использовать connbytes.
Для режима autohostlist необходимо перенаправление нескольких входящих пакетов, чтобы засечь RST или http redirect.
Так же стоит увеличить лимит исходящих пакетов в connbytes, чтобы в него вошли все возможные ретрансмиссии, после которых идет реакция по autoostlist.
`
iptables -t mangle -I PREROUTING -i <внешний интерфейс> -p tcp -m multiport --sports 80,443 -m connbytes --connbytes-dir=reply --connbytes-mode=packets --connbytes 1:3 -m mark ! --mark 0x40000000/0x40000000 -j NFQUEUE --queue-num 200 --queue-bypass
`
Для quic :
```
iptables -t mangle -I POSTROUTING -o <внешний_интерфейс> -p udp --dport 443 -m connbytes --connbytes-dir=original --connbytes-mode=packets --connbytes 1:6 -m mark ! --mark 0x40000000/0x40000000 -j NFQUEUE --queue-num 200 --queue-bypass
```
6 пакетов берется, чтобы покрыть случаи возможных ретрансмиссий quic initial в случае плохой связи или если сервер плохо себя чувствует, а приложение настаивает именно на quic, не переходя на tcp.
А так же для работы autohostlist по quic. Однако, autohostlist для quic не рекомендуется.
### NFTABLES ДЛЯ NFQWS
Можно начать с базовой конфигурации.
```
IFACE_WAN=wan
nft create table inet ztest
nft add chain inet ztest post "{type filter hook postrouting priority mangle;}"
nft add rule inet ztest post oifname $IFACE_WAN meta mark and 0x40000000 == 0 tcp dport "{80,443}" ct original packets 1-6 queue num 200 bypass
nft add rule inet ztest post oifname $IFACE_WAN meta mark and 0x40000000 == 0 udp dport 443 ct original packets 1-6 queue num 200 bypass
# auto hostlist with avoiding wrong ACK numbers in RST,ACK packets sent by russian DPI
sysctl net.netfilter.nf_conntrack_tcp_be_liberal=1
nft add chain inet ztest pre "{type filter hook prerouting priority filter;}"
nft add rule inet ztest pre iifname $IFACE_WAN tcp sport "{80,443}" ct reply packets 1-3 queue num 200 bypass
```
Для задействования IP фрагментации и `datanoack` на проходящие пакеты требуется особая конфигурация цепочек, перенаправляющая пакеты после NAT.
В скриптах zapret эта схема называется `POSTNAT`, и она возможна только на nftables.
Сгенерированные nfqws пакеты требуется на раннем этапе помечать как **notrack**, чтобы они не были испорчены NAT.
```
IFACE_WAN=wan
nft create table inet ztest
nft add chain inet ztest postnat "{type filter hook postrouting priority srcnat+1;}"
nft add rule inet ztest postnat oifname $IFACE_WAN meta mark and 0x40000000 == 0 tcp dport "{80,443}" ct original packets 1-6 queue num 200 bypass
nft add rule inet ztest postnat oifname $IFACE_WAN meta mark and 0x40000000 == 0 udp dport 443 ct original packets 1-6 queue num 200 bypass
nft add chain inet ztest predefrag "{type filter hook output priority -401;}"
nft add rule inet ztest predefrag "mark & 0x40000000 != 0x00000000 notrack"
```
Удаление тестовой таблицы :
```
nft delete table inet ztest
```
### FLOW OFFLOADING
Если ваше устройство поддерживает аппаратное ускорение (flow offloading, hardware nat, hardware acceleration), то
iptables могут не работать. При включенном offloading пакет не проходит по обычному пути netfilter. Необходимо или его
отключить, или выборочно им управлять.
В новых ядрах присутствует software flow offloading (SFO).
Пакеты, проходящие через SFO, так же проходят мимо большей части механизмов iptables. При включенном SFO работает
DNAT/REDIRECT (tpws). Эти соединения исключаются из offloading. Однако, остальные соединения идут через SFO, потому
NFQUEUE будет срабатывать только до помещения соединения в flowtable. Практически это означает, что почти весь функционал nfqws работать не будет.
Offload включается через специальный target в iptables `FLOWOFFLOAD`. Не обязательно пропускать весь трафик через offload. Можно исключить из
offload соединения, которые должны попасть на tpws или nfqws. openwrt не предусматривает выборочного управления offload.
Поэтому скрипты zapret поддерживают свою систему выборочного управления offload в openwrt.
iptables target `FLOWOFFLOAD` - это проприетарное изобретение openwrt.
Управление offload в nftables реализовано в базовом ядре linux без патчей.
## tpws
tpws - это transparent proxy.
@ -791,10 +812,10 @@ tpws - это transparent proxy.
--skip-nodelay ; не устанавливать в исходящих соединения TCP_NODELAY. несовместимо со split.
--local-tcp-user-timeout=<seconds> ; таймаут соединений client-proxy (по умолчанию : 10 сек, 0 = оставить системное значение)
--remote-tcp-user-timeout=<seconds> ; таймаут соединений proxy-target (по умолчанию : 20 сек, 0 = оставить системное значение)
--fix-seg ; исправлять неудачи tcp сегментации ценой задержек для всех клиентов и замедления
--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
--split-pos=N|-N|marker+N|marker-N ; список через запятую маркеров для tcp сегментации
--split-any-protocol ; применять сегментацию к любым пакетам. по умолчанию - только к известным протоколам (http, TLS)
--disorder[=http|tls] ; путем манипуляций с сокетом вынуждает отправлять первым второй сегмент разделенного запроса
--oob[=http|tls] ; отправить байт out-of-band data (OOB) в конце первой части сплита
--oob-data=<char>|0xHEX ; переопределить байт OOB. по умолчанию 0x00.
@ -808,10 +829,8 @@ tpws - это transparent proxy.
--methodspace ; добавить пробел после метода : "GET /" => "GET /"
--methodeol ; добавить перевод строки перед методом : "GET /" => "\r\nGET /"
--unixeol ; конвертировать 0D0A в 0A и использовать везде 0A
--tlsrec=sni|sniext ; разбивка TLS ClientHello на 2 TLS records. режем между 1 и 2 символами hostname в SNI или между байтами длины SNI extension. Если SNI нет - отмена.
--tlsrec-pos=<pos> ; разбивка TLS ClientHello на 2 TLS records. режем на указанной позиции, если длина слишком мелкая - на позиции 1.
--tlsrec=N|-N|marker+N|marker-N ; разбивка TLS ClientHello на 2 TLS records на указанной позиции. Минимальное смещение - 6.
--mss=<int> ; установить MSS для клиента. может заставить сервер разбивать ответы, но существенно снижает скорость
--mss-pf=[~]port1[-port2] ; применять MSS только к портам назначения, подпадающим под фильтр. ~ означает инверсию
--tamper-start=[n]<pos> ; начинать дурение только с указанной байтовой позиции или номера блока исходяшего потока (считается позиция начала принятого блока)
--tamper-cutoff=[n]<pos> ; закончить дурение на указанной байтовой позиции или номере блока исходящего потока (считается позиция начала принятого блока)
--hostlist=<filename> ; действовать только над доменами, входящими в список из filename. поддомены автоматически учитываются.
@ -834,6 +853,115 @@ tpws - это transparent proxy.
--ipset-exclude=<filename> ; исключающий ip list. на каждой строчке ip или cidr ipv4 или ipv6. поддерживается множество листов и gzip. перечитка автоматическая.
```
### TCP СЕГМЕНТАЦИЯ В TPWS
tpws, как и nfqws, поддерживает множественную сегментацию запросов. Сплит позиции задаются в `--split-pos`.
Указываются маркеры через запятую. Описание маркеров см в разделе [nfqws](#tcp-сегментация).
На прикладном уровне в общем случае нет гарантированного средства заставить ядро выплюнуть
блок данных, порезанным в определенном месте. ОС держит буфер отсылки (SNDBUF) у каждого сокета.
Если у сокета включена опция TCP_NODELAY и буфер пуст, то каждый send приводит к отсылке
отдельного ip пакета или группы пакетов, если блок не вмещается в один ip пакет.
Однако, если в момент send уже имеется неотосланный буфер, то ОС присоединит данные к нему,
никакой отсылки отдельным пакетом не будет. Но в этом случае и так нет никакой гарантии,
что какой-то блок сообщения пойдет в начале пакета, на что собственно и заточены DPI.
Разбиение будет производится согласно MSS, который зависит от MTU исходящего интерфейса.
Таким образом DPI, смотрящие в начало поля данных TCP пакета, будут поломаны в любом случае.
Протокол http относится к запрос-ответным протоколам. Новое сообщение посылается только тогда,
когда сервер получил запрос и полностью вернул ответ. Значит запрос фактически был не только отослан,
но и принят другой стороной, а следовательно буфер отсылки пуст, и следующие 2 send приведут
к отсылке сегментов данных разными ip пакетами.
Таким образом tpws обеспечивает сплит только за счет раздельных вызовов send, и это обычно работает надежно,
если разбивать не на слишком много частей и не на слишком мелкие подряд следующие части.
В последнем случае Linux все же может обьединить некоторые части, что приведет к несоответствию реальной сегментации
указанным сплит позициям. Другие ОС в этом вопросе ведут себя более предсказуемо. Спонтанного обьединения замечено не было.
Поэтому не стоит злоупотреблять сплитами и в особенности мелкими соседними пакетами.
Как показывается практика, проблемы могут начаться , если количество сплит позиций превышает 8.
При неудаче сегментации будет выводиться сообщение `WARNING ! segmentation failed`.
Если вы его видите, это повод снизить количество сплит позиций.
Если это не вариант, есть параметр `--fix-seg`. Он позволяет подождать завершение отсылки перед отправкой следующей части.
Но этот вариант ломает модель асинхронной обработки событий. Пока идет ожидание, все остальные соединения не обрабатываются
и кратковременно подвисают. На практике это может быть совсем небольшое ожидание - менее 10 мс.
И производится оно только , если происходит split, и в ожидании есть реальная необходимость.
В высоконагруженных системах данный вариант не рекомендуется. Но для домашнего использования может подойти, и вы эти задержки даже не заметите.
tpws работает на уровне сокетов, поэтому длинный запрос, не вмещающийся в 1 пакет (TLS с kyber), он получает целым блоком.
На каждую сплит часть он делает отдельный вызов `send()`. Но ОС не сможет отослать данные в одном пакете, если размер превысит MTU.
В случае слишком большого сегмента ОС дополнительно его порежет на более мелкие. Результат должен быть аналогичен nfqws.
`--disorder` заставляет слать каждый 2-й пакет с TTL=1, начиная с первого.
К серверу приходят все четные пакеты сразу. На остальные ОС делает ретрансмиссию, и они приходят потом.
Это само по себе создает дополнительную задержку (200 мс в linux для первой ретрансмиссии).
Иным способом сделать disorder в сокет варианте не представляется возможным.
Итоговый порядок для 6 сегментов получается `2 4 6 1 3 5`.
`--oob` высылает 1 байт out-of-band data после первого сплит сегмента. `oob` в каждом сегменте сплита показал себя ненадежным.
Сервер получает oob в сокет.
Сочетание `oob` и `disorder` возможно только в Linux. Остальные ОС не умеют с таким справляться. Флаг URG теряется при ретрансмиссиях.
Сервер получает oob в сокет. Сочетание этих параметров в ос, кроме Linux, вызывает ошибку на этапе запуска.
### TLSREC
`--tlsrec` позволяют внутри одного tcp сегмента разрезать TLS ClientHello на 2 TLS records. Можно использовать стандартный
механизм маркеров для задания относительных позиций.
`--tlsrec` ломает значительное количество сайтов. Криптобиблиотеки (openssl, ...) на оконечных http серверах
без проблем принимают разделенные tls сегменты, но мидлбоксы - не всегда. К мидлбоксам можно отнести CDN
или системы ddos-защиты. Поэтому применение `--tlsrec` без ограничителей вряд ли целесообразно.
В РФ `--tlsrec` обычно не работает с TLS 1.2, потому что цензор парсит сертификат сервера из ServerHello.
Работает только с TLS 1.3, поскольку там эта информация шифруется.
Впрочем, сейчас сайтов, не поддерживающих TLS 1.3, осталось немного.
### MSS
`--mss` устанавливает опцию сокета TCP_MAXSEG. Клиент выдает это значение в tcp опциях SYN пакета.
Сервер в ответ в SYN,ACK выдает свой MSS. На практике сервера обычно снижают размеры отсылаемых ими пакетов, но они
все равно не вписываются в низкий MSS, указанный клиентом. Обычно чем больше указал клиент, тем больше
шлет сервер. На TLS 1.2 если сервер разбил заброс так, чтобы домен из сертификата не попал в первый пакет,
это может обмануть DPI, секущий ответ сервера.
Схема может значительно снизить скорость и сработать не на всех сайтах.
С фильтром по hostlist совместимо только в режиме socks при включенном удаленном ресолвинге хостов.
(firefox network.proxy.socks_remote_dns). Это единственный вариант, когда tpws может узнать имя хоста
еще на этапе установления соединения.
Применяя данную опцию к сайтам TLS1.3, если броузер тоже поддерживает TLS1.3, то вы делаете только хуже.
Но нет способа автоматически узнать когда надо применять, когда нет, поскольку MSS идет только в
3-way handshake еще до обмена данными, а версию TLS можно узнать только по ответу сервера, который
может привести к реакции DPI.
Использовать только когда нет ничего лучше или для отдельных ресурсов.
Для http использовать смысла нет, поэтому заводите отдельный desync profile с фильтром по порту 443.
Работает только на Linux, не работает на BSD и MacOS.
### ДРУГИЕ ПАРАМЕТРЫ ДУРЕНИЯ
Параметр `--hostpad=<bytes>` добавляет паддинг-хедеров перед `Host:` на указанное количество байтов.
Если размер `<bytes>` слишком большой, то идет разбивка на разные хедеры по 2K.
Общий буфер приема http запроса - 64K, больший паддинг не поддерживается, да и http сервера
такое уже не принимают.
Полезно против DPI, выполняющих реассемблинг TCP с ограниченным буфером.
Если техника работает, то после некоторого количества bytes http запрос начнет проходить до сайта.
Если при этом критический размер padding около MTU, значит скорее всего DPI не выполняет реассемблинг пакетов, и лучше будет использовать обычные опции TCP сегментации.
Если все же реассемблинг выполняется, то критический размер будет около размера буфера DPI. Он может быть 4K или 8K, возможны и другие значения.
### МНОЖЕСТВЕННЫЕ СТРАТЕГИИ
Работают аналогично `nfqws`, кроме некоторых моментов.
Нет параметра `--filter-udp`, поскольку `tpws` udp не поддерживает.
Методы нулевой фазы (`--mss`) могут работать по хостлисту в одном единственном случае:
если используется режим socks и удаленный ресолвинг хостов через прокси.
То есть работоспособность вашей настройки в одном и том же режиме может зависеть от того,
применяет ли клиент удаленный ресолвинг. Это может быть неочевидно.
В одной программе работает, в другой - нет.
Если вы используете профиль с хостлистом , и вам нужен mss, укажите mss в профиле с хостлистом,
создайте еще один профиль без хостлиста, если его еще нет, и в нем еще раз укажите mss.
Тогда при любом раскладе будет выполняться mss.
Используйте `curl --socks5` и `curl --socks5-hostname` для проверки вашей стратегии.
Смотрите вывод `--debug`, чтобы убедиться в правильности настроек.
### СЛУЖЕБНЫЕ ПАРАМЕТРЫ
`--debug` позволяет выводить подробный лог действий на консоль, в syslog или в файл.
Может быть важен порядок следования опций. `--debug` лучше всего указывать в самом начале.
Опции анализируются последовательно. Если ошибка будет при проверке опции, а до анализа `--debug` еще дело не дошло,
@ -850,28 +978,6 @@ tpws - это transparent proxy.
Вместо удаления лучше использовать truncate.
В шелле это можно сделать через команду ": >filename"
Параметры манипуляции могут сочетаться в любых комбинациях.
В случае 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` создают новый бинд.
@ -895,19 +1001,17 @@ tpws может биндаться на множество интерфейсо
Параметры 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.
`--skip-nodelay` может быть полезен, когда tpws используется без дурения, чтобы привести MTU к MTU системы, на которой работает tpws.
Это может быть полезно для скрытия факта использования VPN. Пониженный MTU - 1 из способов обнаружения
подозрительного подключения. С tcp proxy ваши соединения неотличимы от тех, что сделал бы сам шлюз.
`--local-tcp-user-timeout` и `--remote-tcp-user-timeout` устанавливают значение таймаута в секундах
для соединений клиент-прокси и прокси-сервер. Этот таймаут соответствует опции сокета linux
TCP_USER_TIMEOUT. Под таймаутом подразумевается время, в течение которого буферизированные данные
не переданы или на переданные данные не получено подтверждение (ACK) от другой стороны.
Этот таймаут никак не касается времени отсутствия какой-либо передачи через сокет лишь потому,
что данных для передачи нет. Полезно для сокращения время закрытия подвисших соединений.
Поддерживается только на Linux и MacOS.
Режим `--socks` не требует повышенных привилегий (кроме бинда на привилегированные порты 1..1023).
Поддерживаются версии socks 4 и 5 без авторизации. Версия протокола распознается автоматически.
@ -921,82 +1025,77 @@ tpws поддерживает эту возможность асинхронно
Если задан параметр `--no-resolve`, то подключения по именам хостов запрещаются, а пул ресолверов не создается.
Тем самым экономятся ресурсы.
Параметр `--hostpad=<bytes>` добавляет паддинг-хедеров перед Host: на указанное количество байтов.
Если размер `<bytes>` слишком большой, то идет разбивка на разные хедеры по 2K.
Общий буфер приема http запроса - 64K, больший паддинг не поддерживается, да и http сервера
такое уже не принимают.
Полезно против DPI, выполняющих реассемблинг TCP с ограниченным буфером.
Если техника работает, то после некоторого количества bytes http запрос начнет проходить до сайта.
Если при этом критический размер padding около MTU, значит скорее всего DPI не выполняет реассемблинг пакетов, и лучше будет использовать обычные опции `--split-…`
Если все же реассемблинг выполняется, то критический размер будет около размера буфера DPI. Он может быть 4K или 8K, возможны и другие значения.
### IPTABLES ДЛЯ TPWS
`--disorder` - это попытка симулировать режим `disorder2 nfqws`, используя особенности ОС по реализации stream сокетов.
Однако, в отличие от nfqws, здесь не требуются повышенные привилегии.
Реализовано это следующим образом. У сокета есть возможность выставить TTL. Все пакеты будут отправляться с ним.
Перед отправкой первого сегмента ставим TTL=1. Пакет будет дропнут на первом же роутере, он не дойдет ни до DPI, ни до сервера.
Затем возвращаем TTL в значение по умолчанию. ОС отсылает второй сегмент, и он уже доходит до сервера.
Сервер возвращает SACK, потому что не получил первый кусок, и ОС его отправляет повторно, но здесь уже мы ничего не делаем.
Этот режим работает как ожидается на Linux и MacOS. Однако, на FreeBSD и OpenBSD он работает не так хорошо.
Ядро этих ОС отсылает ретрансмиссию в виде полного пакета. Потому выходит, что до сервера идет сначала второй кусок,
а потом полный запрос без сплита. На него может отреагировать DPI штатным образом.
`--disorder` является дополнительным флагом к любому сплиту. Сам по себе он не делает ничего.
Для перенаправления tcp соединения на transparent proxy используются команды следующего вида :
`--tlsrec` и `--tlsrec-pos` позволяют внутри одного tcp сегмента разрезать TLS ClientHello на 2 TLS records.
`--tlsrec=sni` режет между 1 и 2 символами hostname в SNI, делая невозможным бинарный поиск паттерна без анализа
структуры данных. В случае отсутствия SNI разбиение отменяется.
`--tlsrec-pos` режет на указанной позиции. Если длина блока данных TLS меньше указанной позиции, режем на позиции 1.
Параметр сочетается с `--split-pos`. В этом случае происходит сначала разделение на уровне TLS record layer, потом на уровне TCP.
Самая изощрённая атака `--tlsrec`, `--split-pos` и `--disorder` вместе.
`--tlsrec` ломает значительное количество сайтов. Криптобиблиотеки (openssl, ...) на оконечных http серверах
без проблем принимают разделенные tls сегменты, но мидлбоксы - не всегда. К мидлбоксам можно отнести CDN
или системы ddos-защиты. Поэтому применение `--tlsrec` без ограничителей вряд ли целесообразно.
В РФ `--tlsrec` обычно не работает с TLS 1.2, потому что цензор парсит сертификат сервера из ServerHello.
Работает только с TLS 1.3, поскольку там эта информация шифруется.
Впрочем, сейчас сайтов, не поддерживающих TLS 1.3, осталось немного.
```
iptables -t nat -I OUTPUT -o <внешний_интерфейс> -p tcp --dport 80 -m owner ! --uid-owner tpws -j DNAT --to 127.0.0.127:988
iptables -t nat -I PREROUTING -i <внутренний_интерфейс> -p tcp --dport 80 -j DNAT --to 127.0.0.127:988
```
`--mss` устанавливает опцию сокета TCP_MAXSEG. Клиент выдает это значение в tcp опциях SYN пакета.
Сервер в ответ в SYN,ACK выдает свой MSS. На практике сервера обычно снижают размеры отсылаемых ими пакетов, но они
все равно не вписываются в низкий MSS, указанный клиентом. Обычно чем больше указал клиент, тем больше
шлет сервер. На TLS 1.2 если сервер разбил заброс так, чтобы домен из сертификата не попал в первый пакет,
это может обмануть DPI, секущий ответ сервера.
Схема может значительно снизить скорость и сработать не на всех сайтах.
С фильтром по hostlist совместимо только в режиме socks при включенном удаленном ресолвинге хостов.
(firefox network.proxy.socks_remote_dns). Это единственный вариант, когда tpws может узнать имя хоста
еще на этапе установления соединения.
Применяя данную опцию к сайтам TLS1.3, если броузер тоже поддерживает TLS1.3, то вы делаете только хуже.
Но нет способа автоматически узнать когда надо применять, когда нет, поскольку MSS идет только в
3-way handshake еще до обмена данными, а версию TLS можно узнать только по ответу сервера, который
может привести к реакции DPI.
Использовать только когда нет ничего лучше или для отдельных ресурсов.
Для http использовать смысла нет, поэтому заводите отдельный desync profile с фильтром по порту 443.
Работает только на linux, не работает на BSD и MacOS.
Первая команда для соединений с самой системы, вторая - для проходящих через роутер соединений.
`--skip-nodelay` может быть полезен, чтобы привести MTU к MTU системы, на которой работает tpws.
Это может быть полезно для скрытия факта использования VPN. Пониженный MTU - 1 из способов обнаружения
подозрительного подключения. С tcp proxy ваши соединения неотличимы от тех, что сделал бы сам шлюз.
DNAT на localhost работает в цепочке OUTPUT, но не работает в цепочке PREROUTING без включения параметра
route_localnet :
`--local-tcp-user-timeout` и `--remote-tcp-user-timeout` устанавливают значение таймаута в секундах
для соединений клиент-прокси и прокси-сервер. Этот таймаут соответствует опции сокета linux
TCP_USER_TIMEOUT. Под таймаутом подразумевается время, в течение которого буферизированные данные
не переданы или на переданные данные не получено подтверждение (ACK) от другой стороны.
Этот таймаут никак не касается времени отсутствия какой-либо передачи через сокет лишь потому,
что данных для передачи нет. Полезно для сокращения время закрытия подвисших соединений.
Поддерживается только на Linux и MacOS.
`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`, для него задается исключающее правило.
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 ДЛЯ TPWS
Базовая конфигурация :
```
IFACE_WAN=wan
IFACE_LAN=br-lan
sysctl -w net.ipv4.conf.$IFACE_LAN.route_localnet=1
nft create table inet ztest
nft create chain inet ztest localnet_protect
nft add rule inet ztest localnet_protect ip daddr 127.0.0.127 return
nft add rule inet ztest localnet_protect ip daddr 127.0.0.0/8 drop
nft create chain inet ztest input "{type filter hook input priority filter - 1;}"
nft add rule inet ztest input iif != "lo" jump localnet_protect
nft create chain inet ztest dnat_output "{type nat hook output priority dstnat;}"
nft add rule inet ztest dnat_output meta skuid != tpws oifname $IFACE_WAN tcp dport { 80, 443 } dnat ip to 127.0.0.127:988
nft create chain inet ztest dnat_pre "{type nat hook prerouting priority dstnat;}"
nft add rule inet ztest dnat_pre meta iifname $IFACE_LAN tcp dport { 80, 443 } dnat ip to 127.0.0.127:988
```
Удаление таблицы :
```
nft delete table inet ztest
```
Работают аналогично `nfqws`, кроме некоторых моментов.
Нет параметра `--filter-udp`, поскольку `tpws` udp не поддерживает.
Методы нулевой фазы (`--mss`) могут работать по хостлисту в одном единственном случае:
если используется режим socks и удаленный ресолвинг хостов через прокси.
То есть работоспособность вашей настройки в одном и том же режиме может зависеть от того,
применяет ли клиент удаленный ресолвинг. Это может быть неочевидно.
В одной программе работает, в другой - нет.
Если вы используете профиль с хостлистом , и вам нужен mss, укажите mss в профиле с хостлистом,
создайте еще один профиль без хостлиста, если его еще нет, и в нем еще раз укажите mss.
Тогда при любом раскладе будет выполняться mss.
Используйте `curl --socks5` и `curl --socks5-hostname` для проверки вашей стратегии.
Смотрите вывод `--debug`, чтобы убедиться в правильности настроек.
## Способы получения списка заблокированных IP
@ -1078,17 +1177,17 @@ Cкрипты с названием `get_antifilter_*` оперируют спи
в отдельный ipset `ipban`. Он может использоваться для принудительного завертывания всех
соединений на прозрачный proxy `redsocks` или на VPN.
IPV6 : если включен ipv6, то дополнительно создаются листы с таким же именем, но с "6" на конце перед расширением.
**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`.
**СИСТЕМА ИСКЛЮЧЕНИЯ 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 с аналогичными именами.
**FreeBSD**. Скрипты ipset/*.sh работают так же на FreeBSD. Вместо ipset они создают lookup таблицы ipfw с аналогичными именами.
ipfw таблицы в отличие от ipset могут содержать как ipv4, так и ipv6 адреса и подсети в одной таблице, поэтому разделения нет.
Параметр конфига LISTS_RELOAD задает произвольную команду для перезагрузки листов.
@ -1516,7 +1615,7 @@ nfqws начнет получать адреса пакетов из локал
```
TPWS_SOCKS_OPT="
--filter-tcp=80 --methodeol <HOSTLIST> --new
--filter-tcp=443 --split-tls=sni --disorder <HOSTLIST>"
--filter-tcp=443 --split-pos=1,midsld --disorder <HOSTLIST>"
```
***Включение стандартной опции tpws в прозрачном режиме***\
@ -1529,7 +1628,7 @@ TPWS_SOCKS_OPT="
```
TPWS_OPT="
--filter-tcp=80 --methodeol <HOSTLIST> --new
--filter-tcp=443 --split-tls=sni --disorder <HOSTLIST>"
--filter-tcp=443 --split-pos=1,midsld --disorder <HOSTLIST>"
```
***Включение стандартной опции nfqws***\
@ -1566,9 +1665,9 @@ NFQWS_PORTS_UDP_KEEPALIVE=
***Параметры nfqws***
```
NFQWS_OPT="
--filter-tcp=80 --dpi-desync=fake,split2 --dpi-desync-fooling=md5sig <HOSTLIST> --new
--filter-tcp=443 --dpi-desync=fake,disorder2 --dpi-desync-fooling=md5sig <HOSTLIST> --new
--filter-udp=443 --dpi-desync=fake --dpi-desync-repeats=6 <HOSTLIST_NOAUTO>"
--filter-tcp=80 --dpi-desync=fake,multisplit --dpi-desync-split-pos=method+2 --dpi-desync-fooling=md5sig <HOSTLIST> --new
--filter-tcp=443 --dpi-desync=fake,multidisorder --dpi-desync-split-pos=1,midsld --dpi-desync-fooling=badseq,md5sig <HOSTLIST> --new
--filter-udp=443 --dpi-desync=fake --dpi-desync-repeats=6 <HOSTLIST_NOAUTO>
```
***Режим фильтрации хостов:***
@ -1943,11 +2042,12 @@ zapret_custom_firewall_nft поднимает правила nftables.
"не просто" до "почти невозможно". Если только вы не найдете готовое собранное ядро под ваш девайс.
tpws будет работать в любом случае, он не требует чего-либо особенного.
В android нет /etc/passwd, потому опция `--user` не будет работать. Вместо нее можно
пользоваться числовыми user id и опцией `--uid`.
Хотя linux варианты под Android работают, рекомендуется использовать специально собранные под bionic бинарники.
У них не будет проблем с DNS, с локальным временем и именами юзеров и групп.\
Рекомендую использовать gid 3003 (AID_INET). Иначе можете получить permission denied на создание сокета.
Например: `--uid 1:3003`\
В iptables укажите: "! --uid-owner 1" вместо "! --uid-owner tpws".\
В iptables укажите: `! --uid-owner 1` вместо `! --uid-owner tpws`.\
Напишите шелл скрипт с iptables и tpws, запускайте его средствами вашего рут менеджера.
Скрипты автозапуска лежат тут:\
magisk : /data/adb/service.d\
@ -1956,10 +2056,6 @@ supersu: /system/su.d
`nfqws` может иметь такой глюк. При запуске с uid по умолчанию (0x7FFFFFFF) при условии работы на сотовом интерфейсе
и отключенном кабеле внешнего питания система может частично виснуть. Перестает работать тач и кнопки,
но анимация на экране может продолжаться. Если экран был погашен, то включить его кнопкой power невозможно.
Это, видимо, связано с переводом в suspend процессов с определенным UID. UID соответствует приложению или
системному сервису. По UID android определяет политику power saving.
Так же возможно, что глюк связан с кривым драйвером сотового интерфейса от китайцев, поскольку при использовании
wifi такого не наблюдается. suspend обработчика nfqueue на обычном linux не вызывает подобных фатальных последствий.
Изменение UID на низкий (--uid 1 подойдет) позволяет решить эту проблему.
Глюк был замечен на android 8.1 на девайсе, основанном на платформе mediatek.

View File

@ -549,7 +549,7 @@ service_install_systemd()
if [ -w "$SYSTEMD_SYSTEM_DIR" ] ; then
rm -f "$INIT_SCRIPT"
ln -fs "$EXEDIR/init.d/systemd/zapret.service" "$SYSTEMD_SYSTEM_DIR"
cp -f "$EXEDIR/init.d/systemd/zapret.service" "$SYSTEMD_SYSTEM_DIR"
"$SYSTEMCTL" daemon-reload
"$SYSTEMCTL" enable zapret || {
echo could not enable systemd service
@ -567,8 +567,8 @@ timer_install_systemd()
if [ -w "$SYSTEMD_SYSTEM_DIR" ] ; then
"$SYSTEMCTL" disable zapret-list-update.timer
"$SYSTEMCTL" stop zapret-list-update.timer
ln -fs "$EXEDIR/init.d/systemd/zapret-list-update.service" "$SYSTEMD_SYSTEM_DIR"
ln -fs "$EXEDIR/init.d/systemd/zapret-list-update.timer" "$SYSTEMD_SYSTEM_DIR"
cp -f "$EXEDIR/init.d/systemd/zapret-list-update.service" "$SYSTEMD_SYSTEM_DIR"
cp -f "$EXEDIR/init.d/systemd/zapret-list-update.timer" "$SYSTEMD_SYSTEM_DIR"
"$SYSTEMCTL" daemon-reload
"$SYSTEMCTL" enable zapret-list-update.timer || {
echo could not enable zapret-list-update.timer

View File

@ -11,6 +11,10 @@
#include <sys/stat.h>
#include <libgen.h>
#ifdef __linux__
#include <linux/tcp.h>
#endif
#ifdef __ANDROID__
#include "andr/ifaddrs.h"
#else
@ -461,3 +465,55 @@ bool parse_cidr6(char *s, struct cidr6 *cidr)
if (p) *p = d; // restore char
return b;
}
void msleep(unsigned int ms)
{
struct timespec time = {
.tv_nsec = (ms % 1000) * 1000000,
.tv_sec = ms / 1000
};
nanosleep(&time, 0);
}
#ifdef __linux__
bool socket_has_notsent(int sfd)
{
struct tcp_info tcpi;
socklen_t ts = sizeof(tcpi);
if (getsockopt(sfd, IPPROTO_TCP, TCP_INFO, (char *)&tcpi, &ts) < 0)
return false;
if (tcpi.tcpi_state != 1)
return false;
size_t s = (char *)&tcpi.tcpi_notsent_bytes - (char *)&tcpi.tcpi_state;
if (ts < s)
return false;
return !!tcpi.tcpi_notsent_bytes;
}
bool socket_wait_notsent(int sfd, unsigned int delay_ms, unsigned int *wasted_ms)
{
struct timespec tres;
unsigned int mtick;
if (wasted_ms) *wasted_ms=0;
if (!socket_has_notsent(sfd)) return true;
if (clock_getres(CLOCK_MONOTONIC,&tres))
{
tres.tv_nsec = 10000000;
tres.tv_sec = 0;
}
mtick = (unsigned int)(tres.tv_sec*1000) + (unsigned int)(tres.tv_nsec/1000000);
if (mtick<1) mtick=1;
for(;;)
{
msleep(mtick);
if (wasted_ms) *wasted_ms+=mtick;
if (!socket_has_notsent(sfd)) return true;
if (delay_ms<=mtick) break;
delay_ms-=mtick;
}
return false;
}
#endif

View File

@ -117,3 +117,9 @@ static inline const struct in6_addr *mask_from_preflen6(uint8_t preflen)
{
return ip6_mask+preflen;
}
void msleep(unsigned int ms);
#ifdef __linux__
bool socket_has_notsent(int sfd);
bool socket_wait_notsent(int sfd, unsigned int delay_ms, unsigned int *wasted_ms);
#endif

View File

@ -104,6 +104,7 @@ struct params_s
uint8_t proxy_type;
bool no_resolve;
bool skip_nodelay;
bool fix_seg;
bool droproot;
uid_t uid;
gid_t gid;

View File

@ -169,6 +169,9 @@ static void exithelp(void)
" --uid=uid[:gid]\t\t\t; drop root privs\n"
#if defined(__FreeBSD__)
" --enable-pf\t\t\t\t; enable PF redirector support. required in FreeBSD when used with PF firewall.\n"
#endif
#if defined(__linux__)
" --fix-seg\t\t\t\t; fix segmentation failures at the cost of possible slowdown\n"
#endif
" --debug=0|1|2|syslog|@<filename>\t; 1 and 2 means log to console and set debug level. for other targets use --debug-level.\n"
" --debug-level=0|1|2\t\t\t; specify debug level\n"
@ -635,8 +638,9 @@ void parse_params(int argc, char *argv[])
{ "local-tcp-user-timeout",required_argument,0,0 }, // optidx=62
{ "remote-tcp-user-timeout",required_argument,0,0 }, // optidx=63
{ "mss",required_argument,0,0 }, // optidx=64
{ "fix-seg",no_argument,0,0 }, // optidx=65
#ifdef SPLICE_PRESENT
{ "nosplice",no_argument,0,0 }, // optidx=65
{ "nosplice",no_argument,0,0 }, // optidx=66
#endif
#endif
{ "hostlist-auto-retrans-threshold",optional_argument,0,0}, // ignored. for nfqws command line compatibility
@ -1228,8 +1232,11 @@ void parse_params(int argc, char *argv[])
exit_clean(1);
}
break;
case 65: /* fix-seg */
params.fix_seg = true;
break;
#ifdef SPLICE_PRESENT
case 65: /* nosplice */
case 66: /* nosplice */
params.nosplice = true;
break;
#endif

View File

@ -1244,7 +1244,21 @@ static bool handle_epoll(tproxy_conn_t *conn, struct tailhead *conn_list, uint32
if (wr>0) conn->partner->twr += wr;
break;
}
#ifdef __linux__
if (params.fix_seg)
{
unsigned int wasted;
if (!socket_wait_notsent(conn->partner->fd, 20, &wasted))
DLOG_ERR("WARNING ! segmentation failed\n");
if (wasted)
VPRINT("WARNING ! wasted %u ms to fix segmenation\n", wasted);
}
else
{
if (socket_has_notsent(conn->partner->fd))
DLOG_ERR("WARNING ! segmentation failed\n");
}
#endif
from = to;
}
}